Behavioral · DWG NO. 018

Interpreter

Represent a small language's grammar as a tree of objects that know how to evaluate themselves.

TypeBehavioral
ScopeGrammar / expression tree
ComplexityMedium–High
Common inSearch filters, rule engines, config expressions

A tiny expression language keeps getting reimplemented as string parsing

A filter like `price > 100 AND inStock` could be handled with ad-hoc string splitting, but that gets fragile fast once nested conditions and multiple operators show up. What's needed is a real, if small, grammar with a defined way to evaluate it.

One class per grammar rule

Each kind of expression (a number, a comparison, an AND) is its own class implementing `interpret(context)`. Complex expressions are built by nesting simple ones — an AND expression holds two child expressions and evaluates both.

AndExpressionGreaterThan(price,100)Equals(inStock,true)

A tiny boolean expression evaluator

Each expression type knows only how to evaluate itself; combining them builds arbitrarily complex conditions without a custom parser for each shape.

filter-interpreter.js
class GreaterThan {
  constructor(field, value) { this.field = field; this.value = value; }
  interpret(ctx) { return ctx[this.field] > this.value; }
}

class Equals {
  constructor(field, value) { this.field = field; this.value = value; }
  interpret(ctx) { return ctx[this.field] === this.value; }
}

class And {
  constructor(left, right) { this.left = left; this.right = right; }
  interpret(ctx) { return this.left.interpret(ctx) && this.right.interpret(ctx); }
}

const expr = new And(
  new GreaterThan("price", 100),
  new Equals("inStock", true)
);

console.log(expr.interpret({ price: 150, inStock: true }));  // true
console.log(expr.interpret({ price: 50, inStock: true }));   // false

Trade-offs