With tokens in hand, the parser's job is to build a tree of values. Today you define that value type and parse the four scalar tokens - null, boolean, number, string - into it, giving the library its public Parse entry point.
Define the Value type and parse a single scalar token into the matching value.
The scanner produced a flat stream of tokens; the parser turns that stream into
a tree. The tree’s node type is Value - a tagged union whose Kind says which of
the six JSON types it holds, with a field for each payload: a bool, a number, a
string, a slice of child values for arrays, and a slice of key/value members for
objects. Every JSON document parses into exactly one Value.
Start at the leaves. The four scalar tokens each map straight to a value: a Null
token to a Null value, True/False to a Bool, a Number token to a Number value
carrying its Num, a String token to a String value carrying its Str. This is
also where the public Parse function is born: it scans the input, reads one value,
and returns it. Give it a ParseError type carrying a position now, even though the
scalars all succeed - the error chapter will lean on it, and arrays and objects,
which recurse back into this same value-reading step, come next.
// name the value's kind apart from the scanner's token Kind// (same package), or the two collidetype ValueKind intconst ( KindNull ValueKind = iota; KindBool; KindNumberKindString; KindArray; KindObject )type Member struct { Key string; Value Value }type Value struct {Kind ValueKindBool bool; Num float64; Str stringArr []Value; Obj []Member}// ParseError carries position; Parse scans then reads one valuetype ParseError struct { Offset, Line, Col int; Msg string }func Parse(input string) (Value, error) { /* scan, parseValue */ }