UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

113 lines 4.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.nonDetCommand = void 0; const repl = require("repl"); // 'repl' here refers to the module named 'repl' in index.d.ts const util_1 = require("util"); const extra_typings_1 = require("@commander-js/extra-typings"); const __1 = require(".."); const constants_1 = require("../constants"); const closure_1 = require("../interpreter/closure"); const types_1 = require("../types"); const NO_MORE_VALUES_MESSAGE = 'There are no more values of: '; let previousInput; // stores the input which is then shown when there are no more values for the program let previousResult; // stores the result obtained when execution is suspended function _handleResult(result, context, callback) { if (result.status === 'finished' || result.status === 'suspended-non-det') { previousResult = result; if (result.value === constants_1.CUT) result.value = undefined; callback(null, result.value); } else { const error = new Error((0, __1.parseError)(context.errors)); // we do not display the stack trace, because the stack trace points to code within this REPL // program, rather than the erroneous line in the user's program. Such a trace is too low level // to be helpful. error.stack = undefined; callback(error, undefined); return; } } function _try_again_message() { if (previousInput) { const message = NO_MORE_VALUES_MESSAGE + previousInput; previousInput = undefined; return message; } else { return undefined; } } function _resume(toResume, context, callback) { Promise.resolve((0, __1.resume)(toResume)).then((result) => { if (result.status === 'finished') result.value = _try_again_message(); _handleResult(result, context, callback); }); } function _try_again(context, callback) { if (previousResult && previousResult.status === 'suspended-non-det') { _resume(previousResult, context, callback); } else { callback(null, _try_again_message()); } } function _run(cmd, context, options, callback) { if (cmd.trim() === constants_1.TRY_AGAIN) { _try_again(context, callback); } else { previousInput = cmd.trim(); (0, __1.runInContext)(cmd, context, options).then(result => { _handleResult(result, context, callback); }); } } function _startRepl(chapter = types_1.Chapter.SOURCE_1, useSubst, prelude = '') { // use defaults for everything const context = (0, __1.createContext)(chapter, types_1.Variant.NON_DET); const options = { executionMethod: 'interpreter', useSubst }; (0, __1.runInContext)(prelude, context, options).then(preludeResult => { if (preludeResult.status === 'finished' || preludeResult.status === 'suspended-non-det') { console.dir(preludeResult.value, { depth: null }); repl.start( // the object being passed as argument fits the interface ReplOptions in the repl module. { eval: (cmd, unusedContext, unusedFilename, callback) => { _run(cmd, context, options, callback); }, // set depth to a large number so that `parse()` output will not be folded, // setting to null also solves the problem, however a reference loop might crash writer: output => { return output instanceof closure_1.default || typeof output === 'function' ? output.toString() : (0, util_1.inspect)(output, { depth: 1000, colors: true }); } }); } else { throw new Error((0, __1.parseError)(context.errors)); } }); } exports.nonDetCommand = new extra_typings_1.Command('non-det') .option('--useSubst') .argument('<filename>') .action(async (fileName, { useSubst }) => { if (fileName !== undefined) { const fs = require('fs/promises'); const data = await fs.readFile(fileName, 'utf-8'); _startRepl(types_1.Chapter.SOURCE_3, false, data); } else { _startRepl(types_1.Chapter.SOURCE_3, !!useSubst); } }); //# sourceMappingURL=repl-non-det.js.map