# Interpreter Pattern

## Problem

You need to evaluate simple arithmetic expressions like `"(3 + 5) * 2"`. Writing a monolithic parser that handles every combination of operators and parentheses becomes a tangled mess. Adding new operators or changing precedence requires modifying the core evaluation logic.

## Solution

Define a **grammar** for the expression language and represent each rule as a class. Build an **abstract syntax tree (AST)** where each node is an expression object with an `interpret()` method. Composite expressions delegate to their children, and terminal expressions return literal values.

**Key participants:**
- **AbstractExpression** — declares `interpret()`
- **TerminalExpression** — represents literals (numbers)
- **NonTerminalExpression** — represents operations (Add, Multiply, etc.)
- **Context** — holds global information (variable bindings, if any)
- **Client** — builds the AST and calls `interpret()`

## When to Use

- The grammar is simple and relatively stable
- Efficiency is not the primary concern (the language is small)
- You want an extensible way to evaluate domain-specific expressions
- Each grammar rule maps naturally to a class

## When to Avoid

- The grammar is complex — use a parser generator (ANTLR, yacc) instead
- Performance is critical — tree-walking interpreters are slow for large inputs
- The grammar changes frequently in ways that break the class hierarchy

## Pseudocode

```
INTERFACE Expression:
    method interpret() -> number

CLASS NumberExpr IMPLEMENTS Expression:
    value: number
    method interpret():
        RETURN value

CLASS AddExpr IMPLEMENTS Expression:
    left: Expression
    right: Expression
    method interpret():
        RETURN left.interpret() + right.interpret()

CLASS MulExpr IMPLEMENTS Expression:
    left: Expression
    right: Expression
    method interpret():
        RETURN left.interpret() * right.interpret()

// Parse "(3 + 5) * 2" into AST:
// MulExpr(AddExpr(NumberExpr(3), NumberExpr(5)), NumberExpr(2))
ast = parse(tokens)
result = ast.interpret()
```

## Python

```python
from __future__ import annotations
from abc import ABC, abstractmethod


class Expression(ABC):
    @abstractmethod
    def interpret(self) -> float:
        pass

    @abstractmethod
    def __repr__(self) -> str:
        pass


class Number(Expression):
    def __init__(self, value: float) -> None:
        self.value = value

    def interpret(self) -> float:
        return self.value

    def __repr__(self) -> str:
        return str(self.value)


class Add(Expression):
    def __init__(self, left: Expression, right: Expression) -> None:
        self.left = left
        self.right = right

    def interpret(self) -> float:
        return self.left.interpret() + self.right.interpret()

    def __repr__(self) -> str:
        return f"({self.left} + {self.right})"


class Subtract(Expression):
    def __init__(self, left: Expression, right: Expression) -> None:
        self.left = left
        self.right = right

    def interpret(self) -> float:
        return self.left.interpret() - self.right.interpret()

    def __repr__(self) -> str:
        return f"({self.left} - {self.right})"


class Multiply(Expression):
    def __init__(self, left: Expression, right: Expression) -> None:
        self.left = left
        self.right = right

    def interpret(self) -> float:
        return self.left.interpret() * self.right.interpret()

    def __repr__(self) -> str:
        return f"({self.left} * {self.right})"


class Divide(Expression):
    def __init__(self, left: Expression, right: Expression) -> None:
        self.left = left
        self.right = right

    def interpret(self) -> float:
        right_val = self.right.interpret()
        if right_val == 0:
            raise ZeroDivisionError("Division by zero")
        return self.left.interpret() / right_val

    def __repr__(self) -> str:
        return f"({self.left} / {self.right})"


def tokenize(expr: str) -> list[str]:
    tokens: list[str] = []
    i = 0
    while i < len(expr):
        if expr[i].isspace():
            i += 1
        elif expr[i] in "+-*/()":
            tokens.append(expr[i])
            i += 1
        elif expr[i].isdigit() or expr[i] == ".":
            j = i
            while j < len(expr) and (expr[j].isdigit() or expr[j] == "."):
                j += 1
            tokens.append(expr[i:j])
            i = j
        else:
            raise ValueError(f"Unexpected character: {expr[i]}")
    return tokens


class Parser:
    """Recursive descent parser with proper operator precedence."""

    def __init__(self, tokens: list[str]) -> None:
        self.tokens = tokens
        self.pos = 0

    def parse(self) -> Expression:
        result = self._add_sub()
        if self.pos < len(self.tokens):
            raise ValueError(f"Unexpected token: {self.tokens[self.pos]}")
        return result

    def _add_sub(self) -> Expression:
        left = self._mul_div()
        while self.pos < len(self.tokens) and self.tokens[self.pos] in ("+", "-"):
            op = self.tokens[self.pos]
            self.pos += 1
            right = self._mul_div()
            left = Add(left, right) if op == "+" else Subtract(left, right)
        return left

    def _mul_div(self) -> Expression:
        left = self._primary()
        while self.pos < len(self.tokens) and self.tokens[self.pos] in ("*", "/"):
            op = self.tokens[self.pos]
            self.pos += 1
            right = self._primary()
            left = Multiply(left, right) if op == "*" else Divide(left, right)
        return left

    def _primary(self) -> Expression:
        token = self.tokens[self.pos]
        if token == "(":
            self.pos += 1
            expr = self._add_sub()
            if self.pos >= len(self.tokens) or self.tokens[self.pos] != ")":
                raise ValueError("Missing closing parenthesis")
            self.pos += 1
            return expr
        else:
            self.pos += 1
            return Number(float(token))


def evaluate(expr_str: str) -> float:
    tokens = tokenize(expr_str)
    parser = Parser(tokens)
    ast = parser.parse()
    result = ast.interpret()
    print(f"  Expression: {expr_str}")
    print(f"  AST:        {ast}")
    print(f"  Result:     {result}")
    return result


def main() -> None:
    expressions = [
        "3 + 5",
        "(3 + 5) * 2",
        "10 - 2 * 3",
        "(10 - 2) * (3 + 1)",
        "100 / 4 / 5",
    ]
    for expr in expressions:
        evaluate(expr)
        print()


if __name__ == "__main__":
    main()
```

**Output:**
```
  Expression: 3 + 5
  AST:        (3.0 + 5.0)
  Result:     8.0

  Expression: (3 + 5) * 2
  AST:        ((3.0 + 5.0) * 2.0)
  Result:     16.0

  Expression: 10 - 2 * 3
  AST:        (10.0 - (2.0 * 3.0))
  Result:     4.0

  Expression: (10 - 2) * (3 + 1)
  AST:        ((10.0 - 2.0) * (3.0 + 1.0))
  Result:     32.0

  Expression: 100 / 4 / 5
  AST:        ((100.0 / 4.0) / 5.0)
  Result:     5.0
```

## Go

```go
package main

import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

type Expression interface {
	Interpret() float64
	String() string
}

type Number struct{ Value float64 }

func (n *Number) Interpret() float64 { return n.Value }
func (n *Number) String() string     { return fmt.Sprintf("%g", n.Value) }

type Add struct{ Left, Right Expression }

func (a *Add) Interpret() float64 { return a.Left.Interpret() + a.Right.Interpret() }
func (a *Add) String() string     { return fmt.Sprintf("(%s + %s)", a.Left, a.Right) }

type Subtract struct{ Left, Right Expression }

func (s *Subtract) Interpret() float64 { return s.Left.Interpret() - s.Right.Interpret() }
func (s *Subtract) String() string     { return fmt.Sprintf("(%s - %s)", s.Left, s.Right) }

type Multiply struct{ Left, Right Expression }

func (m *Multiply) Interpret() float64 { return m.Left.Interpret() * m.Right.Interpret() }
func (m *Multiply) String() string     { return fmt.Sprintf("(%s * %s)", m.Left, m.Right) }

type Divide struct{ Left, Right Expression }

func (d *Divide) Interpret() float64 { return d.Left.Interpret() / d.Right.Interpret() }
func (d *Divide) String() string     { return fmt.Sprintf("(%s / %s)", d.Left, d.Right) }

func tokenize(expr string) []string {
	var tokens []string
	runes := []rune(expr)
	for i := 0; i < len(runes); {
		if unicode.IsSpace(runes[i]) {
			i++
		} else if strings.ContainsRune("+-*/()", runes[i]) {
			tokens = append(tokens, string(runes[i]))
			i++
		} else if unicode.IsDigit(runes[i]) || runes[i] == '.' {
			j := i
			for j < len(runes) && (unicode.IsDigit(runes[j]) || runes[j] == '.') {
				j++
			}
			tokens = append(tokens, string(runes[i:j]))
			i = j
		} else {
			panic(fmt.Sprintf("unexpected character: %c", runes[i]))
		}
	}
	return tokens
}

type Parser struct {
	tokens []string
	pos    int
}

func (p *Parser) Parse() Expression {
	result := p.addSub()
	return result
}

func (p *Parser) addSub() Expression {
	left := p.mulDiv()
	for p.pos < len(p.tokens) && (p.tokens[p.pos] == "+" || p.tokens[p.pos] == "-") {
		op := p.tokens[p.pos]
		p.pos++
		right := p.mulDiv()
		if op == "+" {
			left = &Add{left, right}
		} else {
			left = &Subtract{left, right}
		}
	}
	return left
}

func (p *Parser) mulDiv() Expression {
	left := p.primary()
	for p.pos < len(p.tokens) && (p.tokens[p.pos] == "*" || p.tokens[p.pos] == "/") {
		op := p.tokens[p.pos]
		p.pos++
		right := p.primary()
		if op == "*" {
			left = &Multiply{left, right}
		} else {
			left = &Divide{left, right}
		}
	}
	return left
}

func (p *Parser) primary() Expression {
	token := p.tokens[p.pos]
	if token == "(" {
		p.pos++
		expr := p.addSub()
		p.pos++ // skip ")"
		return expr
	}
	p.pos++
	val, _ := strconv.ParseFloat(token, 64)
	return &Number{val}
}

func evaluate(expr string) {
	tokens := tokenize(expr)
	parser := &Parser{tokens: tokens}
	ast := parser.Parse()
	result := ast.Interpret()
	fmt.Printf("  Expression: %s\n", expr)
	fmt.Printf("  AST:        %s\n", ast)
	fmt.Printf("  Result:     %g\n\n", result)
}

func main() {
	expressions := []string{
		"3 + 5",
		"(3 + 5) * 2",
		"10 - 2 * 3",
		"(10 - 2) * (3 + 1)",
		"100 / 4 / 5",
	}
	for _, expr := range expressions {
		evaluate(expr)
	}
}
```

**Output:**
```
  Expression: 3 + 5
  AST:        (3 + 5)
  Result:     8

  Expression: (3 + 5) * 2
  AST:        ((3 + 5) * 2)
  Result:     16

  Expression: 10 - 2 * 3
  AST:        (10 - (2 * 3))
  Result:     4

  Expression: (10 - 2) * (3 + 1)
  AST:        ((10 - 2) * (3 + 1))
  Result:     32

  Expression: 100 / 4 / 5
  AST:        ((100 / 4) / 5)
  Result:     5
```

## JavaScript

```javascript
class Num {
  constructor(value) {
    this.value = value;
  }
  interpret() {
    return this.value;
  }
  toString() {
    return `${this.value}`;
  }
}

class Add {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }
  interpret() {
    return this.left.interpret() + this.right.interpret();
  }
  toString() {
    return `(${this.left} + ${this.right})`;
  }
}

class Subtract {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }
  interpret() {
    return this.left.interpret() - this.right.interpret();
  }
  toString() {
    return `(${this.left} - ${this.right})`;
  }
}

class Multiply {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }
  interpret() {
    return this.left.interpret() * this.right.interpret();
  }
  toString() {
    return `(${this.left} * ${this.right})`;
  }
}

class Divide {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }
  interpret() {
    return this.left.interpret() / this.right.interpret();
  }
  toString() {
    return `(${this.left} / ${this.right})`;
  }
}

function tokenize(expr) {
  const tokens = [];
  let i = 0;
  while (i < expr.length) {
    if (expr[i] === " ") {
      i++;
    } else if ("+-*/()".includes(expr[i])) {
      tokens.push(expr[i]);
      i++;
    } else if (/[\d.]/.test(expr[i])) {
      let j = i;
      while (j < expr.length && /[\d.]/.test(expr[j])) j++;
      tokens.push(expr.slice(i, j));
      i = j;
    }
  }
  return tokens;
}

class Parser {
  constructor(tokens) {
    this.tokens = tokens;
    this.pos = 0;
  }

  parse() {
    return this.addSub();
  }

  addSub() {
    let left = this.mulDiv();
    while (this.pos < this.tokens.length && (this.tokens[this.pos] === "+" || this.tokens[this.pos] === "-")) {
      const op = this.tokens[this.pos++];
      const right = this.mulDiv();
      left = op === "+" ? new Add(left, right) : new Subtract(left, right);
    }
    return left;
  }

  mulDiv() {
    let left = this.primary();
    while (this.pos < this.tokens.length && (this.tokens[this.pos] === "*" || this.tokens[this.pos] === "/")) {
      const op = this.tokens[this.pos++];
      const right = this.primary();
      left = op === "*" ? new Multiply(left, right) : new Divide(left, right);
    }
    return left;
  }

  primary() {
    const token = this.tokens[this.pos];
    if (token === "(") {
      this.pos++;
      const expr = this.addSub();
      this.pos++; // skip ")"
      return expr;
    }
    this.pos++;
    return new Num(parseFloat(token));
  }
}

function evaluate(exprStr) {
  const tokens = tokenize(exprStr);
  const parser = new Parser(tokens);
  const ast = parser.parse();
  const result = ast.interpret();
  console.log(`  Expression: ${exprStr}`);
  console.log(`  AST:        ${ast}`);
  console.log(`  Result:     ${result}`);
  console.log();
}

const expressions = [
  "3 + 5",
  "(3 + 5) * 2",
  "10 - 2 * 3",
  "(10 - 2) * (3 + 1)",
  "100 / 4 / 5",
];

for (const expr of expressions) {
  evaluate(expr);
}
```

**Output:**
```
  Expression: 3 + 5
  AST:        (3 + 5)
  Result:     8

  Expression: (3 + 5) * 2
  AST:        ((3 + 5) * 2)
  Result:     16

  Expression: 10 - 2 * 3
  AST:        (10 - (2 * 3))
  Result:     4

  Expression: (10 - 2) * (3 + 1)
  AST:        ((10 - 2) * (3 + 1))
  Result:     32

  Expression: 100 / 4 / 5
  AST:        ((100 / 4) / 5)
  Result:     5
```

## Related Patterns

- **Composite** — the AST built by an interpreter is a composite tree; terminal expressions are leaves, non-terminal expressions are composites.
- **Visitor** — add new operations to the interpreter (e.g., pretty-print, optimize) without changing AST classes by using visitors.
- **Flyweight** — share terminal node instances (e.g., common number literals) across the AST to reduce memory when the grammar has many repeated leaves.
