Represent a small language's grammar as a tree of objects that know how to evaluate themselves.
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.
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.
Each expression type knows only how to evaluate itself; combining them builds arbitrarily complex conditions without a custom parser for each shape.
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