From 12c1d179f32c38a929fcc9adb326a9f44c8288ae Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Fri, 21 Apr 2023 16:22:16 +0100 Subject: Replaces the interfaces implementation of Atom with a tagged union based implementation --- walk/walk.go | 150 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 35 deletions(-) (limited to 'walk/walk.go') diff --git a/walk/walk.go b/walk/walk.go index 490a6f2..949b6a2 100644 --- a/walk/walk.go +++ b/walk/walk.go @@ -50,7 +50,7 @@ const ( MapEnd ) func (value TerminalValue) Atomise(in []Atom) []Atom { - return append(in, value) + return append(in, NewAtomTerminal(value)) } func (value TerminalValue) String() string { switch value { @@ -69,7 +69,7 @@ func (value TerminalValue) String() string { type ValueNull struct {} func (value ValueNull) Atomise(in []Atom) []Atom { - return append(in, value) + return append(in, NewAtomNull()) } func (value ValueNull) String() string { return "null" @@ -77,7 +77,7 @@ func (value ValueNull) String() string { type ValueBool bool func (value ValueBool) Atomise(in []Atom) []Atom { - return append(in, value) + return append(in, NewAtomBool(bool(value))) } func (value ValueBool) String() string { if value { @@ -89,38 +89,113 @@ func (value ValueBool) String() string { type ValueNumber float64 func (value ValueNumber) Atomise(in []Atom) []Atom { - return append(in, value) + return append(in, NewAtomNumber(float64(value))) } func (value ValueNumber) String() string { v := float64(value) return fmt.Sprintf("%f", v) } -type StringTerminal struct {} -func (value StringTerminal) String() string { - return "\"" -} - -type StringAtom rune -func (value StringAtom) String() string { - return string(value) -} - type ValueString string func (value ValueString) Atomise(in []Atom) []Atom { - in = append(in, StringTerminal{}) + in = append(in, NewAtomStringTerminal()) for _, char := range value { - in = append(in, StringAtom(char)) + in = append(in, NewAtomStringRune(char)) } - in = append(in, StringTerminal{}) + in = append(in, NewAtomStringTerminal()) return in } func (value ValueString) String() string { return fmt.Sprintf("\"%s\"", string(value)) } -type Atom interface { - String() string +type AtomType int64 +const ( + AtomNull AtomType = iota + AtomBool + AtomNumber + AtomTerminal + AtomStringTerminal + AtomStringRune +) +type Atom struct { + Typ AtomType + data uint64 +} +func NewAtomNull() Atom { + return Atom { + Typ: AtomNull, + data: 0, + } +} +func NewAtomBool(v bool) Atom { + if v { + return Atom { + Typ: AtomBool, + data: 1, + } + } else { + return Atom { + Typ: AtomBool, + data: 0, + } + } +} +func NewAtomNumber(v float64) Atom { + return Atom { + Typ: AtomNumber, + data: math.Float64bits(v), + } +} +func NewAtomTerminal(v TerminalValue) Atom { + return Atom { + Typ: AtomTerminal, + data: uint64(v), + } +} +func NewAtomStringTerminal() Atom { + return Atom { + Typ: AtomStringTerminal, + data: 0, + } +} +func NewAtomStringRune(v rune) Atom { + return Atom { + Typ: AtomStringRune, + data: uint64(v), + } +} +func (v Atom) String() string { + switch v.Typ { + case AtomNull: + return "null" + case AtomBool: + if v.data == 0 { + return "false" + } + return "true" + case AtomNumber: + return fmt.Sprintf("%v", math.Float64frombits(v.data)) + case AtomTerminal: + switch TerminalValue(v.data) { + case MapBegin: + return "{" + case MapEnd: + return "}" + case ArrayBegin: + return "[" + case ArrayEnd: + return "]" + default: + panic("Invalid terminal atom") + } + case AtomStringTerminal: + return "\"" + case AtomStringRune: + return string(rune(v.data)) + default: + panic("Invalid atom type") + } } type WalkValue interface { @@ -481,12 +556,12 @@ func Compound(in []Atom) (out []WalkValue, error error) { i := 0 inString := false for _, atom := range in { - switch atom.(type) { - case TerminalValue, ValueNull, ValueBool, ValueNumber: + switch atom.Typ { + case AtomNull, AtomBool, AtomNumber, AtomTerminal: if !inString { numValues++ } - case StringTerminal: + case AtomStringTerminal: if inString { numValues++ } @@ -501,32 +576,37 @@ func Compound(in []Atom) (out []WalkValue, error error) { } atom := in[i] i++ - switch v := atom.(type) { - case TerminalValue, ValueNull, ValueBool, ValueNumber: - out = append(out, v.(WalkValue)) + switch atom.Typ { + case AtomNull: + out = append(out, ValueNull{}) continue - case StringAtom: + case AtomBool: + out = append(out, ValueBool(atom.data != 0)) + continue + case AtomNumber: + out = append(out, ValueNumber(math.Float64frombits(atom.data))) + continue + case AtomTerminal: + out = append(out, TerminalValue(atom.data)) + continue + case AtomStringRune: return nil, CompoundRuneOutsideString - case StringTerminal: + case AtomStringTerminal: default: return nil, CompoundUnknownAtom } // Handle string start var builder strings.Builder - loop: for { + for { if i >= len(in) { return nil, CompoundMissingEnd } atom := in[i] i++ - switch v := atom.(type) { - case StringTerminal: - break loop - case StringAtom, ValueNull, ValueBool, ValueNumber, TerminalValue: - builder.WriteString(v.String()) - default: - return nil, CompoundInvalidStringAtom + if atom.Typ == AtomStringTerminal { + break } + builder.WriteString(atom.String()) } out = append(out, ValueString(builder.String())) } -- cgit v1.2.3