UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

87 lines 3.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* tslint:disable:max-classes-per-file */ const astring_1 = require("astring"); const utils_1 = require("../cse-machine/utils"); const astCreator_1 = require("../utils/ast/astCreator"); const interpreter_1 = require("./interpreter"); const closureToJS = (value, context, klass) => { function DummyClass() { const args = Array.prototype.slice.call(arguments); const gen = (0, interpreter_1.apply)(context, value, args, (0, astCreator_1.callExpression)((0, astCreator_1.identifier)(klass), args), this); let it = gen.next(); while (!it.done) { it = gen.next(); } return it.value; } Object.defineProperty(DummyClass, 'name', { value: klass }); Object.setPrototypeOf(DummyClass, () => undefined); Object.defineProperty(DummyClass, 'Inherits', { value: (Parent) => { DummyClass.prototype = Object.create(Parent.prototype); DummyClass.prototype.constructor = DummyClass; } }); DummyClass.toString = () => (0, astring_1.generate)(value.originalNode); DummyClass.call = (thisArg, ...args) => { return DummyClass.apply(thisArg, args); }; return DummyClass; }; class Callable extends Function { constructor(f) { super(); return Object.setPrototypeOf(f, new.target.prototype); } } /** * Models function value in the interpreter environment. */ class Closure extends Callable { static makeFromArrowFunction(node, environment, context, dummyReturn, predefined) { const functionBody = !(0, utils_1.isBlockStatement)(node.body) && !(0, utils_1.isStatementSequence)(node.body) ? (0, astCreator_1.blockStatement)([(0, astCreator_1.returnStatement)(node.body, node.body.loc)], node.body.loc) : dummyReturn && !(0, utils_1.hasReturnStatement)(node.body) ? (0, astCreator_1.blockStatement)([ ...node.body.body, (0, astCreator_1.returnStatement)((0, astCreator_1.identifier)('undefined', node.body.loc), node.body.loc) ], node.body.loc) : node.body; const closure = new Closure((0, astCreator_1.blockArrowFunction)(node.params, functionBody, node.loc), environment, context, predefined); // Set the closure's node to point back at the original one closure.originalNode = node; return closure; } constructor(node, environment, context, isPredefined) { super(function (...args) { return funJS.apply(this, args); }); this.node = node; this.environment = environment; this.originalNode = node; this.id = (0, utils_1.uniqueId)(context); if (this.node.type === 'FunctionDeclaration' && this.node.id !== null) { this.functionName = this.node.id.name; } else { this.functionName = (this.node.params.length === 1 ? '' : '(') + this.node.params.map((o) => o.name).join(', ') + (this.node.params.length === 1 ? '' : ')') + ' => ...'; } // TODO: Investigate how relevant this really is. // .fun seems to only be used in interpreter's NewExpression handler, which uses .fun.prototype. const funJS = closureToJS(this, context, this.functionName); this.fun = funJS; this.preDefined = isPredefined == undefined ? undefined : isPredefined; } toString() { return (0, astring_1.generate)(this.originalNode); } } exports.default = Closure; //# sourceMappingURL=closure.js.map