///|
/// The interpreter is downstream application logic, not a semantic-action engine.
fn evaluate(tree : @moonearley.Tree) -> Int32 raise {
  match tree {
    TokenNode(leaf) => @string.parse_int(leaf.token.text[:])
    RuleNode(node) =>
      match node.label {
        "number" => evaluate(node.children[0])
        "add" => evaluate(node.children[0]) + evaluate(node.children[2])
        "mul" => evaluate(node.children[0]) * evaluate(node.children[2])
        _ => abort("unexpected production in this example")
      }
  }
}

///|
fn main raise {
  let grammar = @moonearley.parse_grammar(
    "E -> ['add'] E '+' E | ['mul'] E '*' E | ['number'] 'n';",
  ).unwrap()
  let report = @moonearley.parse(grammar, [
    @moonearley.token("n", "1", 0, 1),
    @moonearley.token("+", "+", 1, 2),
    @moonearley.token("n", "2", 2, 3),
    @moonearley.token("*", "*", 3, 4),
    @moonearley.token("n", "3", 4, 5),
  ]).unwrap()
  assert_true(report.accepted())
  assert_eq(report.forest().count().unwrap(), @moonearley.Finite(2))
  let extraction = report.forest().extract_trees().unwrap()
  assert_true(!extraction.truncated())
  let values = extraction.trees().map(evaluate)
  values.sort()
  assert_eq(values, [7, 9])
  for value in values {
    println("a valid interpretation of 1+2*3: \{value}")
  }
  println(
    "The application can select precedence; the library did not discard alternatives.",
  )
}