diff options
Diffstat (limited to 'walk/walk.go')
-rw-r--r-- | walk/walk.go | 134 |
1 files changed, 128 insertions, 6 deletions
diff --git a/walk/walk.go b/walk/walk.go index fc9e9de..e66feff 100644 --- a/walk/walk.go +++ b/walk/walk.go @@ -7,7 +7,41 @@ import ( type PathSegment interface {} +type OutputList interface { + outputList() +} + +type OutputValueList []Value +func (_ OutputValueList) outputList() {} + +type OutputRuneList []rune +func (_ OutputRuneList) outputList() {} + +// Can be passed to .eat on a state +type Edible interface { + edible() +} + +type RuneEdible rune +func (_ RuneEdible) edible() {} + +type Terminal int +const ( + ArrayEnd Terminal = iota + MapEnd + StringEnd +) +func (_ Terminal) edible() {} + +// Simple value +// Has a literal +type Scalar interface { + Value + scalar() +} + type Value interface { + Edible value() Debug() string } @@ -17,6 +51,8 @@ func (_ NullValue) value() {} func (_ NullValue) Debug() string { return "null" } +func (_ NullValue) edible() {} +func (_ NullValue) scalar() {} type BoolValue bool func (_ BoolValue) value() {} @@ -26,24 +62,23 @@ func (b BoolValue) Debug() string { } return "false" } +func (_ BoolValue) edible() {} +func (_ BoolValue) scalar() {} type NumberValue float64 func (_ NumberValue) value() {} func (n NumberValue) Debug() string { return fmt.Sprintf("%v", float64(n)) } - -type RuneValue rune -func (_ RuneValue) value() {} -func (r RuneValue) Debug() string { - return string(r) -} +func (_ NumberValue) edible() {} +func (_ NumberValue) scalar() {} type StringValue string func (_ StringValue) value() {} func (s StringValue) Debug() string { return fmt.Sprintf("%q", string(s)) } +func (_ StringValue) edible() {} type ArrayElement struct { Index int @@ -66,6 +101,7 @@ func (array ArrayValue) Debug() string { builder.WriteRune(']') return builder.String() } +func (_ ArrayValue) edible() {} type MapElement struct { Key string @@ -88,6 +124,7 @@ func (m MapValue) Debug() string { builder.WriteRune('}') return builder.String() } +func (_ MapValue) edible() {} type WalkItem struct { Value Value @@ -111,3 +148,88 @@ func (item WalkItem) Debug() string { builder.WriteString(item.Value.Debug()) return builder.String() } + +func Merge(first Value, second Value) []Value { + switch first := first.(type) { + case NullValue: + return []Value {first, second} + case BoolValue: + return []Value {first, second} + case NumberValue: + return []Value {first, second} + case StringValue: + return []Value {first, second} + case ArrayValue: + secondArr, isArr := second.(ArrayValue) + if !isArr { + return []Value {first, second} + } + + if len(first) == 0 { + return []Value {second} + } + + if len(secondArr) == 0 { + return []Value {first} + } + + var res ArrayValue + for _, el := range first[:len(first) - 1] { + res = append(res, el) + } + midFirst := first[len(first) - 1] + midSecond := secondArr[0] + if midFirst.Index == midSecond.Index { + for _, el := range Merge(midFirst.Value, midSecond.Value) { + res = append(res, ArrayElement { + Index: midFirst.Index, + Value: el, + }) + } + } else { + res = append(res, midFirst, midSecond) + } + for _, el := range secondArr[1:] { + res = append(res, el) + } + + return []Value {res} + case MapValue: + secondMap, isMap := second.(MapValue) + if !isMap { + return []Value {first, second} + } + + if len(first) == 0 { + return []Value {second} + } + + if len(secondMap) == 0 { + return []Value {first} + } + + var res MapValue + for _, el := range first[:len(first) - 1] { + res = append(res, el) + } + midFirst := first[len(first) - 1] + midSecond := secondMap[0] + if midFirst.Key == midSecond.Key { + for _, el := range Merge(midFirst.Value, midSecond.Value) { + res = append(res, MapElement { + Key: midFirst.Key, + Value: el, + }) + } + } else { + res = append(res, midFirst, midSecond) + } + for _, el := range secondMap[1:] { + res = append(res, el) + } + + return []Value {res} + default: + panic("first is invalid value type") + } +} |