js-slang
Version:
Javascript-based implementations of Source, written in Typescript
106 lines • 4.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StepperUnaryExpression = void 0;
const __1 = require("../..");
const generator_1 = require("../../generator");
const Literal_1 = require("./Literal");
class StepperUnaryExpression {
constructor(operator, argument, leadingComments, trailingComments, loc, range) {
this.type = 'UnaryExpression';
this.operator = operator;
this.prefix = true;
this.argument = argument;
this.leadingComments = leadingComments;
this.trailingComments = trailingComments;
this.loc = loc;
this.range = range;
}
static createLiteral(node) {
// if node argument is positive literal(x) and node operator is "-", we replace them with literal(-x) instead.
if (node.operator === '-' &&
node.argument.type === 'Literal' &&
typeof node.argument.value === 'number' &&
node.argument.value > 0) {
return new Literal_1.StepperLiteral(-node.argument.value, (-node.argument.value).toString(), node.leadingComments, node.trailingComments, node.loc, node.range);
}
return undefined;
}
static create(node) {
const literal = StepperUnaryExpression.createLiteral(node);
if (literal) {
return literal;
}
return new StepperUnaryExpression(node.operator, (0, generator_1.convert)(node.argument), node.leadingComments, node.trailingComments, node.loc, node.range);
}
isContractible() {
if (this.argument.type !== 'Literal')
return false;
const valueType = typeof this.argument.value;
const markContractible = () => {
__1.redex.preRedex = [this];
return true;
};
switch (this.operator) {
case '!':
if (valueType === 'boolean') {
return markContractible();
}
else {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected boolean, got ${valueType}.`);
}
case '-':
if (valueType === 'number') {
return markContractible();
}
else {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected number, got ${valueType}.`);
}
default:
return false;
}
}
isOneStepPossible() {
return this.isContractible() || this.argument.isOneStepPossible();
}
contract() {
__1.redex.preRedex = [this];
if (this.argument.type !== 'Literal')
throw new Error();
const operand = this.argument.value;
if (this.operator === '!') {
const ret = new Literal_1.StepperLiteral(!operand, undefined, this.leadingComments, this.trailingComments, this.loc, this.range);
__1.redex.postRedex = [ret];
return ret;
}
else if (this.operator === '-') {
const ret = new Literal_1.StepperLiteral(-operand, (-operand).toString(), this.leadingComments, this.trailingComments, this.loc, this.range);
__1.redex.postRedex = [ret];
return ret;
}
throw new Error();
}
oneStep() {
if (this.isContractible()) {
return this.contract();
}
const res = new StepperUnaryExpression(this.operator, this.argument.oneStep(), this.leadingComments, this.trailingComments, this.loc, this.range);
const literal = StepperUnaryExpression.createLiteral(res);
return literal ? literal : res;
}
substitute(id, value) {
const res = new StepperUnaryExpression(this.operator, this.argument.substitute(id, value), this.leadingComments, this.trailingComments, this.loc, this.range);
const literal = StepperUnaryExpression.createLiteral(res);
return literal ? literal : res;
}
freeNames() {
return this.argument.freeNames();
}
allNames() {
return this.argument.allNames();
}
rename(before, after) {
return new StepperUnaryExpression(this.operator, this.argument.rename(before, after), this.leadingComments, this.trailingComments, this.loc, this.range);
}
}
exports.StepperUnaryExpression = StepperUnaryExpression;
//# sourceMappingURL=UnaryExpression.js.map