UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

125 lines 6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StepperFunctionApplication = void 0; const astring = require("astring"); const __1 = require("../.."); const generator_1 = require("../../generator"); const BlockStatement_1 = require("../Statement/BlockStatement"); const builtins_1 = require("../../builtins"); const BlockExpression_1 = require("./BlockExpression"); class StepperFunctionApplication { constructor(callee, args, optional = false, leadingComments, trailingComments, loc, range) { this.type = 'CallExpression'; this.callee = callee; this.arguments = args; this.optional = optional; this.leadingComments = leadingComments; this.trailingComments = trailingComments; this.loc = loc; this.range = range; } static create(node) { return new StepperFunctionApplication((0, generator_1.convert)(node.callee), node.arguments.map(arg => (0, generator_1.convert)(arg)), node.optional, node.leadingComments, node.trailingComments, node.loc, node.range); } isContractible() { const isValidCallee = this.callee.type === 'ArrowFunctionExpression' || (this.callee.type === 'Identifier' && (0, builtins_1.isBuiltinFunction)(this.callee.name)); if (!isValidCallee) { // Since the callee can not be proceed further, calling non callables should result to an error. if (!this.callee.isOneStepPossible() && this.arguments.every(arg => !arg.isOneStepPossible())) { throw new Error(`Line ${this.loc?.start.line || 0}: Calling non-function value ${astring.generate(this.callee)}`); } return false; } if (this.callee.type === 'ArrowFunctionExpression') { const arrowFunction = this.callee; if (arrowFunction.params.length !== this.arguments.length) { throw new Error(`Line ${this.loc?.start.line || 0}: Expected ${arrowFunction.params.length} arguments, but got ${this.arguments.length}.`); } } return this.arguments.every(arg => !arg.isOneStepPossible()); } isOneStepPossible() { if (this.isContractible()) return true; if (this.callee.isOneStepPossible()) return true; return this.arguments.some(arg => arg.isOneStepPossible()); } contract() { __1.redex.preRedex = [this]; if (!this.isContractible()) throw new Error(); if (this.callee.type === 'Identifier') { const functionName = this.callee.name; if ((0, builtins_1.isBuiltinFunction)(functionName)) { const result = (0, builtins_1.getBuiltinFunction)(functionName, this.arguments); __1.redex.postRedex = [result]; return result; } throw new Error(`Unknown builtin function: ${functionName}`); } if (this.callee.type !== 'ArrowFunctionExpression') { throw new Error(); } const lambda = this.callee; const args = this.arguments; let result = lambda.body; if (result instanceof BlockStatement_1.StepperBlockStatement) { const blockStatement = lambda.body; if (blockStatement.body.length === 0) { result = new BlockExpression_1.StepperBlockExpression([]); } else if (blockStatement.body[0].type === 'ReturnStatement') { // (x => {return 2 + 3;})(3) -> 2 + 3; result = blockStatement.body[0].argument; } else { result = new BlockExpression_1.StepperBlockExpression(blockStatement.body); } } else { result = lambda.body; } if (lambda.name && !this.callee.scanAllDeclarationNames().includes(lambda.name)) { result = result.substitute({ type: 'Identifier', name: lambda.name }, lambda); } lambda.params.forEach((param, i) => { result = result.substitute(param, args[i]); }); __1.redex.postRedex = [result]; return result; } oneStep() { if (this.isContractible()) { // @ts-expect-error: contract can return StepperBlockExpression but it's handled at runtime return this.contract(); } if (this.callee.isOneStepPossible()) { return new StepperFunctionApplication(this.callee.oneStep(), this.arguments, this.optional, this.leadingComments, this.trailingComments, this.loc, this.range); } for (let i = 0; i < this.arguments.length; i++) { if (this.arguments[i].isOneStepPossible()) { const newArgs = [...this.arguments]; newArgs[i] = this.arguments[i].oneStep(); return new StepperFunctionApplication(this.callee, newArgs, this.optional, this.leadingComments, this.trailingComments, this.loc, this.range); } } throw new Error('No one step possible'); } substitute(id, value) { return new StepperFunctionApplication(this.callee.substitute(id, value), this.arguments.map(arg => arg.substitute(id, value)), this.optional, this.leadingComments, this.trailingComments, this.loc, this.range); } freeNames() { return Array.from(new Set([...this.callee.freeNames(), ...this.arguments.flatMap(arg => arg.freeNames())])); } allNames() { return Array.from(new Set([...this.callee.allNames(), ...this.arguments.flatMap(arg => arg.allNames())])); } rename(before, after) { return new StepperFunctionApplication(this.callee.rename(before, after), this.arguments.map(arg => arg.rename(before, after)), this.optional, this.leadingComments, this.trailingComments, this.loc, this.range); } } exports.StepperFunctionApplication = StepperFunctionApplication; //# sourceMappingURL=FunctionApplication.js.map