Skip to content
Snippets Groups Projects
Select Git revision
  • 4e41cf3002917a2d15a27615759251eaf37f69b0
  • master default protected
2 results

expressions.js

Blame
  • 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(', ')})`;
      }
    }