package walk import ( "fmt" "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() {} type WalkItem struct { 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() }