Select Git revision
expressions.js
Brady James Garvin authored
expressions.js 1.85 KiB
export class Operator {
constructor(symbol, arity, semantics, precedence) {
this.symbol = symbol;
this.arity = arity;
this.apply = semantics;
this.precedence = precedence;
}
toString() {
return this.symbol;
}
}
export class Variable {
constructor(name) {
this.name = name;
}
get precedence() { // eslint-disable-line class-methods-use-this
return Infinity;
}
evaluate(assignments) {
return assignments.get(this.name);
}
toString() {
return this.name;
}
}
export class Environment {
constructor(variables, unaryOperators, binaryOperators) {
console.assert(unaryOperators.every((operator) => operator.arity === 1));
console.assert(binaryOperators.every((operator) => operator.arity === 2));
this.variables = variables;
this.unaryOperators = unaryOperators;
this.binaryOperators = binaryOperators;
}
}
export class Expression {
constructor(operator, operands) {
console.assert(operator.arity === operands.length, `Tried to apply the operator ${operator} to ${operands.length} operands.`);
this.operator = operator;
this.operands = operands;
}
get precedence() {
return this.operator.precedence;
}
evaluate(assignments) {
return this.operator.apply(...this.operands.map((operand) => operand.evaluate(assignments)));
}
toString() {
const operands = this.operands.map((operand) => operand.precedence <= this.precedence ? `(${operand})` : `${operand}`);
if (this.operator.arity === 1) {
return `${this.operator.symbol}${operands[0]}`;
}
if (this.operator.arity === 2) {
return `${operands[0]} ${this.operator.symbol} ${operands[1]}`;
}
console.assert(false, `Tried to print an expression with the unsupported operator arity ${this.operator.arity} for ${this.operator}.`);
return `${this.operator}(${operands.join(', ')})`;
}
}