js-slang
Version:
Javascript-based implementations of Source, written in Typescript
82 lines • 4.34 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StepperArrowFunctionExpression = void 0;
const generator_1 = require("../../generator");
const utils_1 = require("../../utils");
class StepperArrowFunctionExpression {
constructor(params, body, name, expression = true, generator = false, async = false, leadingComments, trailingComments, loc, range) {
this.type = 'ArrowFunctionExpression';
this.params = params;
this.expression = expression;
this.generator = generator;
this.async = async;
this.name = name;
this.leadingComments = leadingComments;
this.trailingComments = trailingComments;
this.loc = loc;
this.range = range;
this.body = body;
}
static create(node) {
return new StepperArrowFunctionExpression(node.params.map(param => (0, generator_1.convert)(param)), (0, generator_1.convert)(node.body), undefined, node.expression, node.generator, node.async, node.leadingComments, node.trailingComments, node.loc, node.range);
}
isContractible() {
return false;
}
isOneStepPossible() {
return false;
}
contract() {
throw new Error('Cannot contract an arrow function expression');
}
oneStep() {
throw new Error('Cannot step an arrow function expression');
}
assignName(name) {
return new StepperArrowFunctionExpression(this.params, this.body, name, this.expression, this.generator, this.async, this.leadingComments, this.trailingComments, this.loc, this.range);
}
scanAllDeclarationNames() {
const paramNames = this.params.map(param => param.name);
let bodyDeclarations = [];
// @ts-expect-error gracefully handle block statement as block expression
if (this.body.type === 'BlockStatement') {
const body = this.body;
bodyDeclarations = body.body
.filter(stmt => stmt.type === 'VariableDeclaration')
.flatMap(decl => decl.declarations.map((d) => d.id.name));
}
return [...paramNames, ...bodyDeclarations];
}
// TODO: Fix name handling for lambda
substitute(id, value, upperBoundName) {
const valueFreeNames = value.freeNames();
const scopeNames = this.scanAllDeclarationNames();
const repeatedNames = valueFreeNames.filter(name => scopeNames.includes(name));
let protectedNamesSet = new Set([this.allNames(), upperBoundName ?? []].flat());
repeatedNames.forEach(name => protectedNamesSet.delete(name));
const protectedNames = Array.from(protectedNamesSet);
const newNames = (0, utils_1.getFreshName)(repeatedNames, protectedNames);
const currentArrowFunction = newNames.reduce((current, name, index) => current.rename(repeatedNames[index], name), this);
if (currentArrowFunction.scanAllDeclarationNames().includes(id.name)) {
return currentArrowFunction;
}
return new StepperArrowFunctionExpression(currentArrowFunction.params, currentArrowFunction.body.substitute(id, value, currentArrowFunction.params.flatMap(p => p.allNames())), currentArrowFunction.name, currentArrowFunction.expression, currentArrowFunction.generator, currentArrowFunction.async, currentArrowFunction.leadingComments, currentArrowFunction.trailingComments, currentArrowFunction.loc, currentArrowFunction.range);
}
freeNames() {
const paramNames = this.params
.filter(param => param.type === 'Identifier')
.map(param => param.name);
return this.body.freeNames().filter(name => !paramNames.includes(name));
}
allNames() {
const paramNames = this.params
.filter(param => param.type === 'Identifier')
.map(param => param.name);
return Array.from(new Set([paramNames, this.body.allNames()].flat()));
}
rename(before, after) {
return new StepperArrowFunctionExpression(this.params.map(param => param.rename(before, after)), this.body.rename(before, after), this.name, this.expression, this.generator, this.async, this.leadingComments, this.trailingComments, this.loc, this.range);
}
}
exports.StepperArrowFunctionExpression = StepperArrowFunctionExpression;
//# sourceMappingURL=ArrowFunctionExpression.js.map