UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

130 lines 6.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolvedErrorPromise = exports.htmlRunner = exports.runCodeInSource = exports.sourceFilesRunner = exports.DEFAULT_SOURCE_OPTIONS = void 0; const _ = require("lodash"); const mapper_1 = require("../alt-langs/mapper"); const preprocessor_1 = require("../modules/preprocessor"); const types_1 = require("../types"); const validator_1 = require("../validator/validator"); const parser_1 = require("../parser/parser"); const assert_1 = require("../utils/assert"); const analyzer_1 = require("../modules/preprocessor/analyzer"); const linker_1 = require("../modules/preprocessor/linker"); const utils_1 = require("./utils"); Object.defineProperty(exports, "resolvedErrorPromise", { enumerable: true, get: function () { return utils_1.resolvedErrorPromise; } }); const sourceRunner_1 = require("./sourceRunner"); let previousCode = null; exports.DEFAULT_SOURCE_OPTIONS = { steps: 1000, stepLimit: -1, executionMethod: 'auto', variant: types_1.Variant.DEFAULT, originalMaxExecTime: 1000, useSubst: false, isPrelude: false, throwInfiniteLoops: true, envSteps: -1, importOptions: { ...analyzer_1.defaultAnalysisOptions, ...linker_1.defaultLinkerOptions, loadTabs: true }, shouldAddFileName: null }; async function sourceRunner(program, context, isVerboseErrorsEnabled, options = {}) { // It is necessary to make a copy of the DEFAULT_SOURCE_OPTIONS object because merge() // will modify it rather than create a new object const theOptions = _.merge({ ...exports.DEFAULT_SOURCE_OPTIONS }, options); context.variant = (0, utils_1.determineVariant)(context, options); if (context.chapter === types_1.Chapter.FULL_JS || context.chapter === types_1.Chapter.FULL_TS || context.chapter === types_1.Chapter.PYTHON_1) { return sourceRunner_1.default.fulljs(program, context, theOptions); } (0, validator_1.validateAndAnnotate)(program, context); if (context.errors.length > 0) { return utils_1.resolvedErrorPromise; } if (theOptions.useSubst) { return sourceRunner_1.default.substitution(program, context, theOptions); } (0, utils_1.determineExecutionMethod)(theOptions, context, program, isVerboseErrorsEnabled); // native, don't evaluate prelude if (context.executionMethod === 'native' && context.variant === types_1.Variant.NATIVE) { return sourceRunner_1.default.fulljs(program, context, theOptions); } // All runners after this point evaluate the prelude. if (context.prelude !== null && !options.isPrelude) { context.unTypecheckedCode.push(context.prelude); const prelude = (0, parser_1.parse)(context.prelude, context); if (prelude === null) return utils_1.resolvedErrorPromise; await sourceRunner(prelude, context, isVerboseErrorsEnabled, { ...options, isPrelude: true }); } if (context.variant === types_1.Variant.EXPLICIT_CONTROL || context.executionMethod === 'cse-machine') { if (options.isPrelude) { const preludeContext = { ...context, runtime: { ...context.runtime, debuggerOn: false } }; const result = await sourceRunner_1.default['cse-machine'](program, preludeContext, theOptions); // Update object count in main program context after prelude is run context.runtime.objectCount = preludeContext.runtime.objectCount; return result; } return sourceRunner_1.default['cse-machine'](program, context, theOptions); } (0, assert_1.default)(context.executionMethod !== 'auto', 'Execution method should have been properly determined!'); return sourceRunner_1.default.native(program, context, theOptions); } /** * Returns both the Result of the evaluated program, as well as * `verboseErrors`. */ async function sourceFilesRunner(filesInput, entrypointFilePath, context, options = {}) { const preprocessResult = await (0, preprocessor_1.default)(filesInput, entrypointFilePath, context, options); if (!preprocessResult.ok) { return { result: { status: 'error' }, verboseErrors: preprocessResult.verboseErrors }; } const { files, verboseErrors, program: preprocessedProgram } = preprocessResult; context.variant = (0, utils_1.determineVariant)(context, options); // FIXME: The type checker does not support the typing of multiple files, so // we only push the code in the entrypoint file. Ideally, all files // involved in the program evaluation should be type-checked. Either way, // the type checker is currently not used at all so this is not very // urgent. context.unTypecheckedCode.push(files[entrypointFilePath]); const currentCode = { files, entrypointFilePath }; context.shouldIncreaseEvaluationTimeout = _.isEqual(previousCode, currentCode); previousCode = currentCode; context.previousPrograms.unshift(preprocessedProgram); const result = await sourceRunner(preprocessedProgram, context, verboseErrors, options); const resultMapper = (0, mapper_1.mapResult)(context); return { result: resultMapper(result), verboseErrors }; } exports.sourceFilesRunner = sourceFilesRunner; /** * Useful for just running a single line of code with the given context * However, if this single line of code is an import statement, * then the FileGetter is necessary, otherwise all local imports will * fail with ModuleNotFoundError */ function runCodeInSource(code, context, options = {}, defaultFilePath = '/default.js', fileGetter) { return sourceFilesRunner(path => { if (path === defaultFilePath) return Promise.resolve(code); if (!fileGetter) return Promise.resolve(undefined); return fileGetter(path); }, defaultFilePath, context, options); } exports.runCodeInSource = runCodeInSource; var htmlRunner_1 = require("./htmlRunner"); Object.defineProperty(exports, "htmlRunner", { enumerable: true, get: function () { return htmlRunner_1.htmlRunner; } }); //# sourceMappingURL=index.js.map