js-slang
Version:
Javascript-based implementations of Source, written in Typescript
130 lines • 6.24 kB
JavaScript
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
;