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