UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

144 lines 6.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StepperProgram = void 0; const generator_1 = require("../generator"); const __1 = require(".."); const utils_1 = require("../utils"); const _1 = require("."); class StepperProgram { isContractible() { return false; } isOneStepPossible() { return this.body.length === 0 ? false // unlike BlockStatement : this.body[0].isOneStepPossible() || this.body.length >= 2 || (this.body.length == 1 && (this.body[0].type == 'VariableDeclaration' || this.body[0].type == 'FunctionDeclaration')); } contract() { throw new Error('not implemented'); } oneStep() { // reduce the first statement if (this.body[0].isOneStepPossible()) { const firstStatementOneStep = this.body[0].oneStep(); const afterSubstitutedScope = this.body.slice(1); if (firstStatementOneStep === _1.undefinedNode) { return new StepperProgram([afterSubstitutedScope].flat()); } return new StepperProgram([firstStatementOneStep, afterSubstitutedScope].flat()); } // If the first statement is constant declaration, gracefully handle it! if (this.body[0].type == 'VariableDeclaration') { const declarations = (0, utils_1.assignMuTerms)(this.body[0].declarations); // for arrow function expression const afterSubstitutedScope = this.body .slice(1) .map(current => declarations .filter(declarator => declarator.init) .reduce((statement, declarator) => statement.substitute(declarator.id, declarator.init), current)); const substitutedProgram = new StepperProgram(afterSubstitutedScope); __1.redex.preRedex = [this.body[0]]; __1.redex.postRedex = afterSubstitutedScope; return substitutedProgram; } // If the first statement is function declaration, also gracefully handle it! if (this.body[0].type == 'FunctionDeclaration') { const arrowFunction = this.body[0].getArrowFunctionExpression(); const functionIdentifier = this.body[0].id; const afterSubstitutedScope = this.body .slice(1) .map(statement => statement.substitute(functionIdentifier, arrowFunction)); const substitutedProgram = new StepperProgram(afterSubstitutedScope); __1.redex.preRedex = [this.body[0]]; __1.redex.postRedex = afterSubstitutedScope; return substitutedProgram; } const firstValueStatement = this.body[0]; // After this stage, the first statement is a value statement. Now, proceed until getting the second value statement. if (this.body.length >= 2 && this.body[1].isOneStepPossible()) { const secondStatementOneStep = this.body[1].oneStep(); const afterSubstitutedScope = this.body.slice(2); if (secondStatementOneStep === _1.undefinedNode) { return new StepperProgram([firstValueStatement, afterSubstitutedScope].flat()); } return new StepperProgram([ firstValueStatement, secondStatementOneStep, afterSubstitutedScope ].flat()); } // If the second statement is constant declaration, gracefully handle it! if (this.body.length >= 2 && this.body[1].type == 'VariableDeclaration') { const declarations = (0, utils_1.assignMuTerms)(this.body[1].declarations); const afterSubstitutedScope = this.body .slice(2) .map(current => declarations .filter(declarator => declarator.init) .reduce((statement, declarator) => statement.substitute(declarator.id, declarator.init), current)); const substitutedProgram = new StepperProgram([firstValueStatement, afterSubstitutedScope].flat()); __1.redex.preRedex = [this.body[1]]; __1.redex.postRedex = declarations.map(x => x.id); return substitutedProgram; } // If the second statement is function declaration, also gracefully handle it! if (this.body.length >= 2 && this.body[1].type == 'FunctionDeclaration') { const arrowFunction = this.body[1].getArrowFunctionExpression(); const functionIdentifier = this.body[1].id; const afterSubstitutedScope = this.body .slice(2) .map(statement => statement.substitute(functionIdentifier, arrowFunction)); const substitutedProgram = new StepperProgram([firstValueStatement, afterSubstitutedScope].flat()); __1.redex.preRedex = [this.body[1]]; __1.redex.postRedex = afterSubstitutedScope; return substitutedProgram; } this.body[0].contractEmpty(); // update the contracted statement onto redex return new StepperProgram(this.body.slice(1)); } static create(node) { return new StepperProgram(node.body.map(ast => (0, generator_1.convert)(ast)), node.comments, node.leadingComments, node.trailingComments, node.loc, node.range); } constructor(body, // TODO: Add support for variable declaration comments, leadingComments, trailingComments, loc, range) { this.type = 'Program'; this.sourceType = 'module'; this.body = body; this.comments = comments; this.leadingComments = leadingComments; this.trailingComments = trailingComments; this.loc = loc; this.range = range; } substitute(id, value) { return new StepperProgram(this.body.map(statement => statement.substitute(id, value))); } scanAllDeclarationNames() { return this.body .filter(ast => ast.type === 'VariableDeclaration' || ast.type === 'FunctionDeclaration') .flatMap((ast) => { if (ast.type === 'VariableDeclaration') { return ast.declarations.map(ast => ast.id.name); } else { // Function Declaration return [ast.id.name]; } }); } freeNames() { const names = new Set(this.body.flatMap(ast => ast.freeNames())); this.scanAllDeclarationNames().forEach(name => names.delete(name)); return Array.from(names); } allNames() { return Array.from(new Set(this.body.flatMap(ast => ast.allNames()))); } rename(before, after) { return new StepperProgram(this.body.map(statement => statement.rename(before, after))); } } exports.StepperProgram = StepperProgram; //# sourceMappingURL=Program.js.map