<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/walk/walk.go
diff options
context:
space:
mode:
Diffstat (limited to 'walk/walk.go')
-rw-r--r--walk/walk.go134
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")
+ }
+}