From 8cf10efe3b5a1bcc70bc6e5590ee63fd5eb00c5b Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 19 Jul 2023 11:57:59 +0100 Subject: Huge refactor to a more value based system, doing away with terminals. Also introduces unit testing --- walk/walk.go | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 246 insertions(+), 13 deletions(-) (limited to 'walk/walk.go') diff --git a/walk/walk.go b/walk/walk.go index 1073c67..65fac6e 100644 --- a/walk/walk.go +++ b/walk/walk.go @@ -1,17 +1,232 @@ package walk import ( - "strings" + "fmt" "math" + "strings" "unicode/utf8" ) +type valueIter struct { + values []Value + index int +} +func (iter *valueIter) Next() Edible { + if iter.index >= len(iter.values) { + return nil + } + iter.index += 1 + return iter.values[iter.index - 1] +} + +func NewValueIter(values []Value) StructureIter { + return &valueIter { + values: values, + index: 0, + } +} + +type OutputList interface { + outputList() +} + +type StructureIter interface { + Next() Edible +} + +type Edible interface { + edible() +} + +type Atom interface { + Edible + atom() +} + +type Scalar interface { + Atom + Value +} + +type Structure interface { + Value + structure() + Iter() StructureIter +} + +type Value interface { + Edible + value() + Debug() string +} + +type Terminal interface { + Atom + terminal() +} + +type ValueList []Value +func (_ ValueList) outputList() {} + +type RuneList []StringRuneAtom +func (_ RuneList) outputList() {} + +type NullScalar struct{} +func (_ NullScalar) edible() {} +func (_ NullScalar) atom() {} +func (_ NullScalar) value() {} +func (_ NullScalar) Debug() string { + return "null" +} + +type BoolScalar bool +func (_ BoolScalar) edible() {} +func (_ BoolScalar) atom() {} +func (_ BoolScalar) value() {} +func (b BoolScalar) Debug() string { + if b { + return "true" + } + return "false" +} + +type NumberScalar float64 +func (_ NumberScalar) edible() {} +func (_ NumberScalar) atom() {} +func (_ NumberScalar) value() {} +func (n NumberScalar) Debug() string { + return fmt.Sprintf("%v", float64(n)) +} + +type StringStructure string +func (_ StringStructure) edible() {} +func (_ StringStructure) value() {} +func (_ StringStructure) structure() {} +func (s StringStructure) Iter() StructureIter { + return &stringStructureIter { + string: string(s), + position: 0, + } +} +func (s StringStructure) Debug() string { + return fmt.Sprintf("%q", string(s)) +} + +type stringStructureIter struct { + string string + position int +} +func (iter *stringStructureIter) Next() Edible { + if iter.position == -1 { + return nil + } + r, width := utf8.DecodeRuneInString(iter.string[iter.position:]) + if width == 0 { + iter.position = -1 + return StringEndTerminal{} + } + iter.position += width + return StringRuneAtom(r) +} + +type StringBeginTerminal struct{} +func (_ StringBeginTerminal) edible() {} +func (_ StringBeginTerminal) atom() {} +func (_ StringBeginTerminal) terminal() {} + +type StringEndTerminal struct{} +func (_ StringEndTerminal) edible() {} +func (_ StringEndTerminal) atom() {} +func (_ StringEndTerminal) terminal() {} + +type StringRuneAtom rune +func (_ StringRuneAtom) edible() {} +func (_ StringRuneAtom) atom() {} + +type ArrayStructure []Value +func (_ ArrayStructure) edible() {} +func (_ ArrayStructure) value() {} +func (_ ArrayStructure) structure() {} +func (array ArrayStructure) Iter() StructureIter { + return &arrayStructureIter { + array: []Value(array), + index: 0, + } +} +func (array ArrayStructure) Debug() string { + builder := strings.Builder{} + builder.WriteRune('[') + var sep string + for _, element := range array { + builder.WriteString(sep) + builder.WriteString(fmt.Sprintf("%v", element)) + sep = ", " + } + builder.WriteRune(']') + return builder.String() +} + +type arrayStructureIter struct { + array []Value + index int +} +func (iter *arrayStructureIter) Next() Edible { + if iter.index > len(iter.array) { + return nil + } + if iter.index == len(iter.array) { + iter.index += 1 + return ArrayEndTerminal{} + } + iter.index += 1 + return iter.array[iter.index - 1] +} + +type ArrayBeginTerminal struct{} +func (_ ArrayBeginTerminal) edible() {} +func (_ ArrayBeginTerminal) atom() {} +func (_ ArrayBeginTerminal) terminal() {} + +type ArrayEndTerminal struct{} +func (_ ArrayEndTerminal) edible() {} +func (_ ArrayEndTerminal) atom() {} +func (_ ArrayEndTerminal) terminal() {} + +type MapStructure map[string]Value +func (_ MapStructure) edible() {} +func (_ MapStructure) value() {} +func (_ MapStructure) structure() {} +func (m MapStructure) Debug() string { + builder := strings.Builder{} + builder.WriteRune('{') + var sep string + for key, value := range m { + builder.WriteString(sep) + builder.WriteString(fmt.Sprintf("%q", key)) + builder.WriteString(": ") + builder.WriteString(fmt.Sprintf("%q", value)) + sep = ", " + } + builder.WriteRune('}') + return builder.String() +} + +type MapBeginTerminal struct{} +func (_ MapBeginTerminal) edible() {} +func (_ MapBeginTerminal) atom() {} +func (_ MapBeginTerminal) terminal() {} + +type MapEndTerminal struct{} +func (_ MapEndTerminal) edible() {} +func (_ MapEndTerminal) atom() {} +func (_ MapEndTerminal) terminal() {} + // int or string type PathSegment interface {} type Path []PathSegment -func (path Path) ToWalkValues() []Value { - var values []Value +func (path Path) ToWalkValues() []ValueOLD { + var values []ValueOLD for _, segment := range path { switch s := segment.(type) { case int: @@ -25,7 +240,7 @@ func (path Path) ToWalkValues() []Value { return values } -func PathFromWalkValues(values []Value) Path { +func PathFromWalkValues(values []ValueOLD) Path { var segments []PathSegment for _, value := range values { switch v := value.(type) { @@ -41,18 +256,36 @@ func PathFromWalkValues(values []Value) Path { } type WalkItem struct { - Value []Atom - Path []Atom + Value ValueList + Path ValueList +} + +func (item WalkItem) Debug() string { + builder := strings.Builder{} + var sep string + for _, pathSegment := range item.Path { + builder.WriteString(sep) + builder.WriteString(fmt.Sprintf("%s", pathSegment.Debug())) + sep = "." + } + builder.WriteString(": ") + sep = "" + for _, value := range item.Value { + builder.WriteString(sep) + builder.WriteString(fmt.Sprintf("%s", value.Debug())) + sep = ", " + } + return builder.String() } -func ConcatData(first []Atom, second []Atom) []Atom { - res := make([]Atom, 0, len(first) + len(second)) +func ConcatData(first []AtomOLD, second []AtomOLD) []AtomOLD { + res := make([]AtomOLD, 0, len(first) + len(second)) res = append(res, first...) res = append(res, second...) return res } -func Atomise(in []Value) (out []Atom) { +func Atomise(in []ValueOLD) (out []AtomOLD) { numAtoms := 0 for _, value := range in { switch v := value.(type) { @@ -64,7 +297,7 @@ func Atomise(in []Value) (out []Atom) { panic("Invalid WalkValue") } } - out = make([]Atom, 0, numAtoms) + out = make([]AtomOLD, 0, numAtoms) for _, value := range in { out = value.Atomise(out) } @@ -96,11 +329,11 @@ func (err CompoundError) Error() string { } type CompoundResult struct { - value Value + value ValueOLD error error } -func Compound(in []Atom) (out []Value, error error) { +func Compound(in []AtomOLD) (out []ValueOLD, error error) { numValues := 0 i := 0 inString := false @@ -118,7 +351,7 @@ func Compound(in []Atom) (out []Value, error error) { } } i = 0 - out = make([]Value, 0, numValues) + out = make([]ValueOLD, 0, numValues) for { if i >= len(in) { break -- cgit v1.2.3