The evaluator walks the syntax tree and produces values. Today you define what a runtime value is - the object system - and evaluate the simplest node, an integer literal, then wire eval into the REPL so it finally computes.
Evaluate an integer literal node into an integer object and print its value at the REPL.
Parsing gave you a tree; evaluation turns that tree into values. First you
need to say what a runtime value is: an Object interface with a Type (for
error messages and comparisons) and an Inspect (how it prints). Define the
Integer object now - it is the first of several object kinds, all sharing this
interface.
Eval is a function that takes a node and returns an object, switching on the
node’s kind. Today it handles exactly one case - an integer literal becomes an
integer object - but that switch is the spine of the whole evaluator, growing one
case per node type. Wire Eval into the REPL after the parser, print the
result’s Inspect, and your loop finally computes instead of just echoing.
type Object interface { Type() string; Inspect() string }type Integer struct { Value int64 }func (i *Integer) Type() string { return "INTEGER" }func (i *Integer) Inspect() string { return fmt.Sprint(i.Value) }func Eval(node Node) Object { /* switch on node type; IntegerLiteral -> &Integer{...} */ }