UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

80 lines 3.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isBuiltinFunction = exports.getBuiltinFunction = exports.prelude = void 0; const Identifier_1 = require("../nodes/Expression/Identifier"); const Literal_1 = require("../nodes/Expression/Literal"); const generator_1 = require("../generator"); const lists_1 = require("./lists"); const misc_1 = require("./misc"); const auxiliary_1 = require("./auxiliary"); const builtinFunctions = { ...lists_1.listBuiltinFunctions, ...misc_1.miscBuiltinFunctions, ...auxiliary_1.auxiliaryBuiltinFunctions }; function prelude(node) { node = node.type === 'Program' ? removeDebuggerStatements(node) : node; // check program for undefined variables // checkProgramForUndefinedVariables(node as es.Program, createContext()); let inputNode = (0, generator_1.convert)(node); // Substitute math constant Object.getOwnPropertyNames(Math) .filter(name => name in Math && typeof Math[name] !== 'function') .forEach(name => { inputNode = inputNode.substitute(new Identifier_1.StepperIdentifier('math_' + name), new Literal_1.StepperLiteral(Math[name])); }); return inputNode; } exports.prelude = prelude; function removeDebuggerStatements(program) { // recursively detect and remove debugger statements function remove(removee) { if (removee.type === 'BlockStatement' || removee.type === 'Program') { removee.body = removee.body.filter(s => s.type !== 'DebuggerStatement'); removee.body.forEach(s => remove(s)); } else if (removee.type === 'VariableDeclaration') { removee.declarations.forEach(s => remove(s.init)); } else if (removee.type === 'FunctionDeclaration') { remove(removee.body); } else if (removee.type === 'IfStatement') { remove(removee.consequent); remove(removee.alternate); } else if (removee.type === 'ArrowFunctionExpression') { remove(removee.body); } } remove(program); return program; } function getBuiltinFunction(name, args) { if (name.startsWith('math_')) { const mathFnName = name.split('_')[1]; if (mathFnName in Math) { const fn = Math[mathFnName]; const argVal = args.map(arg => arg.value); argVal.forEach(arg => { if (typeof arg !== 'number' || typeof arg !== 'bigint') { throw new Error('Math functions must be called with number arguments'); } }); const result = fn(...argVal); return new Literal_1.StepperLiteral(result, result); } } const calledFunction = builtinFunctions[name]; if (calledFunction.arity != args.length && name !== 'list') { // brute force way to fix this issue throw new Error(`Expected ${calledFunction.arity} arguments, but got ${args.length}.`); } return calledFunction.definition(args); } exports.getBuiltinFunction = getBuiltinFunction; function isBuiltinFunction(name) { return name.startsWith('math_') || Object.keys(builtinFunctions).includes(name); } exports.isBuiltinFunction = isBuiltinFunction; //# sourceMappingURL=index.js.map