js-slang
Version:
Javascript-based implementations of Source, written in Typescript
122 lines • 5.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StepperBinaryExpression = void 0;
const __1 = require("../..");
const generator_1 = require("../../generator");
const Literal_1 = require("./Literal");
class StepperBinaryExpression {
constructor(operator, left, right, leadingComments, trailingComments, loc, range) {
this.type = 'BinaryExpression';
this.operator = operator;
this.left = left;
this.right = right;
this.leadingComments = leadingComments;
this.trailingComments = trailingComments;
this.loc = loc;
this.range = range;
}
static create(node) {
return new StepperBinaryExpression(node.operator, (0, generator_1.convert)(node.left), (0, generator_1.convert)(node.right), node.leadingComments, node.trailingComments, node.loc, node.range);
}
isContractible() {
if (this.left.type !== 'Literal' || this.right.type !== 'Literal') {
return false;
}
const leftType = typeof this.left.value;
const rightType = typeof this.right.value;
const markContractible = () => {
__1.redex.preRedex = [this];
return true;
};
if (leftType === 'boolean') {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected number or string on left hand side of operation, got ${leftType}.`);
}
if (leftType === 'string' && rightType === 'string') {
if (['+', '===', '!==', '<', '>', '<=', '>='].includes(this.operator)) {
return markContractible();
}
else {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected number on left hand side of operation, got ${leftType}.`);
}
}
if (leftType === 'string') {
if (['+', '===', '!==', '<', '>', '<=', '>='].includes(this.operator)) {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected string on right hand side of operation, got ${rightType}.`);
}
else {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected number on left hand side of operation, got ${leftType}.`);
}
}
if (leftType === 'number' && rightType === 'number') {
if (['*', '+', '/', '-', '===', '!==', '<', '>', '<=', '>=', '%'].includes(this.operator)) {
return markContractible();
}
}
if (leftType === 'number') {
throw new Error(`Line ${this.loc?.start.line || 0}: Expected number on right hand side of operation, got ${rightType}.`);
}
return false;
}
isOneStepPossible() {
return this.isContractible() || this.left.isOneStepPossible() || this.right.isOneStepPossible();
}
contract() {
__1.redex.preRedex = [this];
if (this.left.type !== 'Literal' || this.right.type !== 'Literal')
throw new Error();
const left = this.left.value;
const right = this.right.value;
const op = this.operator;
const value = this.operator === '&&'
? left && right
: op === '||'
? left || right
: op === '+' && typeof left === 'number' && typeof right === 'number'
? left + right
: op === '+' && typeof left === 'string' && typeof right === 'string'
? left + right
: op === '-'
? left - right
: op === '*'
? left * right
: op === '%'
? left % right
: op === '/'
? left / right
: op === '==='
? left === right
: op === '!=='
? left !== right
: op === '<'
? left < right
: op === '<='
? left <= right
: op === '>='
? left >= right
: left > right;
let ret = new Literal_1.StepperLiteral(value, value !== null ? value.toString() : 'null', undefined, undefined, this.loc, this.range);
__1.redex.postRedex = [ret];
return ret;
}
oneStep() {
return this.isContractible()
? this.contract()
: this.left.isOneStepPossible()
? new StepperBinaryExpression(this.operator, this.left.oneStep(), this.right)
: new StepperBinaryExpression(this.operator, this.left, this.right.oneStep());
}
substitute(id, value) {
return new StepperBinaryExpression(this.operator, this.left.substitute(id, value), this.right.substitute(id, value), this.leadingComments, this.trailingComments, this.loc, this.range);
}
freeNames() {
return Array.from(new Set([this.left.freeNames(), this.right.freeNames()].flat()));
}
allNames() {
return Array.from(new Set([this.left.allNames(), this.right.allNames()].flat()));
}
rename(before, after) {
return new StepperBinaryExpression(this.operator, this.left.rename(before, after), this.right.rename(before, after), this.leadingComments, this.trailingComments, this.loc, this.range);
}
}
exports.StepperBinaryExpression = StepperBinaryExpression;
//# sourceMappingURL=BinaryExpression.js.map