<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/json/write.go
diff options
context:
space:
mode:
Diffstat (limited to 'json/write.go')
-rw-r--r--json/write.go303
1 files changed, 259 insertions, 44 deletions
diff --git a/json/write.go b/json/write.go
index 9e349be..97b3f4e 100644
--- a/json/write.go
+++ b/json/write.go
@@ -4,25 +4,26 @@ import (
"bufio"
"fmt"
"main/walk"
+ // "text/scanner"
)
-func isNumber(value walk.Value) bool {
- _, isFloat := value.(walk.NumberScalar)
- return isFloat
+func isInt(segment walk.PathSegment) bool {
+ _, isInt := segment.(int)
+ return isInt
}
-func isString(value walk.Value) bool {
- _, isString := value.(walk.StringStructure)
+func isString(segment walk.PathSegment) bool {
+ _, isString := segment.(string)
return isString
}
-func segmentEqual(left walk.Value, right walk.Value) bool {
+func segmentEqual(left walk.PathSegment, right walk.PathSegment) bool {
switch left := left.(type) {
- case walk.NumberScalar:
- _, isNumber := right.(walk.NumberScalar)
- return isNumber
- case walk.StringStructure:
- right, isString := right.(walk.StringStructure)
+ case int:
+ _, isInt := right.(int)
+ return isInt
+ case string:
+ right, isString := right.(string)
return isString && left == right
default:
panic("Invalid path segment type")
@@ -32,7 +33,7 @@ func segmentEqual(left walk.Value, right walk.Value) bool {
type JSONWriterState int
const (
JSONWriterStateBeforeValue JSONWriterState = iota
- JSONWriterStateAfterValue JSONWriterState = iota
+ JSONWriterStateAfterValue
JSONWriterStateInArray
JSONWriterStateInMap
)
@@ -46,29 +47,243 @@ func NewJSONWriter(writer *bufio.Writer) *JSONWriter {
}
type JSONWriter struct {
- path []walk.Value
+ path []walk.PathSegment
writer *bufio.Writer
state JSONWriterState
}
-func (writer *JSONWriter) Write(item walk.WalkItem) error {
- path := item.Path
- for _, value := range item.Value {
- err := writer.write(path, value)
- if err != nil {
- return err
+func (writer *JSONWriter) navigateTo(keepLen int, path []walk.PathSegment, state JSONWriterState) {
+ for {
+ if keepLen > len(writer.path) {
+ panic("keepLen > len(writer.path)")
+ } else if len(writer.path) == keepLen {
+ if len(path) == 0 {
+ switch writer.state {
+ case JSONWriterStateBeforeValue:
+ switch state {
+ case JSONWriterStateBeforeValue:
+ return
+ case JSONWriterStateAfterValue:
+ panic("Cannot go from BeforeValue to AfterValue in navigateTo")
+ case JSONWriterStateInArray:
+ writer.writer.WriteRune('[')
+ writer.state = JSONWriterStateInArray
+ case JSONWriterStateInMap:
+ writer.writer.WriteRune('{')
+ writer.state = JSONWriterStateInMap
+ }
+ case JSONWriterStateAfterValue:
+ if state == JSONWriterStateAfterValue {
+ return
+ } else {
+ if keepLen == 0 {
+ writer.writer.WriteRune('\n')
+ writer.state = JSONWriterStateBeforeValue
+ } else {
+ writer.writer.WriteRune(',')
+ path = writer.path[len(writer.path) - 1:]
+ writer.path = writer.path[:len(writer.path) - 1]
+ keepLen -= 1
+ switch path[0].(type) {
+ case string:
+ writer.state = JSONWriterStateInMap
+ case int:
+ writer.state = JSONWriterStateInArray
+ }
+ }
+ }
+ case JSONWriterStateInArray:
+ if state == JSONWriterStateInArray {
+ return
+ } else {
+ writer.writer.WriteRune(']')
+ writer.state = JSONWriterStateAfterValue
+ }
+ case JSONWriterStateInMap:
+ if state == JSONWriterStateInMap {
+ return
+ } else {
+ writer.writer.WriteRune('}')
+ writer.state = JSONWriterStateAfterValue
+ }
+ }
+ } else {
+ // len(path) > 0
+ switch writer.state {
+ case JSONWriterStateBeforeValue:
+ switch path[0].(type) {
+ case string:
+ writer.writer.WriteRune('{')
+ writer.state = JSONWriterStateInMap
+ case int:
+ writer.writer.WriteRune('[')
+ writer.state = JSONWriterStateInArray
+ }
+ case JSONWriterStateAfterValue:
+ if keepLen == 0 {
+ writer.writer.WriteRune('\n')
+ writer.state = JSONWriterStateBeforeValue
+ } else {
+ writer.writer.WriteRune(',')
+ path = append(writer.path[len(writer.path) - 1:], path...)
+ writer.path = writer.path[:len(writer.path) - 1]
+ keepLen -= 1
+ switch path[0].(type) {
+ case string:
+ writer.state = JSONWriterStateInMap
+ case int:
+ writer.state = JSONWriterStateInArray
+ }
+ }
+ case JSONWriterStateInArray:
+ switch path[0].(type) {
+ case string:
+ writer.writer.WriteRune(']')
+ writer.state = JSONWriterStateAfterValue
+ case int:
+ writer.path = append(writer.path, path[0])
+ path = path[1:]
+ keepLen += 1
+ writer.state = JSONWriterStateBeforeValue
+ }
+ case JSONWriterStateInMap:
+ switch p := path[0].(type) {
+ case string:
+ fmt.Fprintf(writer.writer, "%q:", p)
+ writer.path = append(writer.path, p)
+ path = path[1:]
+ keepLen += 1
+ writer.state = JSONWriterStateBeforeValue
+ case int:
+ writer.writer.WriteRune('}')
+ writer.state = JSONWriterStateAfterValue
+ }
+ }
+ }
+ } else {
+ switch writer.state {
+ case JSONWriterStateBeforeValue:
+ panic("Cannot close structures from BeforeValue in navigateTo")
+ case JSONWriterStateAfterValue:
+ if len(writer.path) == keepLen + 1 {
+ if len(path) == 0 {
+ switch writer.path[len(writer.path) - 1].(type) {
+ case string:
+ if state == JSONWriterStateInMap {
+ writer.writer.WriteRune(',')
+ writer.path = writer.path[:len(writer.path) - 1]
+ writer.state = JSONWriterStateInMap
+ } else {
+ writer.writer.WriteRune('}')
+ writer.path = writer.path[:len(writer.path) - 1]
+ }
+ case int:
+ if state == JSONWriterStateInArray {
+ writer.writer.WriteRune(',')
+ writer.path = writer.path[:len(writer.path) - 1]
+ writer.state = JSONWriterStateInArray
+ } else {
+ writer.writer.WriteRune(']')
+ writer.path = writer.path[:len(writer.path) - 1]
+ }
+ }
+ } else {
+ switch writer.path[len(writer.path) - 1].(type) {
+ case string:
+ switch path[0].(type) {
+ case string:
+ writer.writer.WriteRune(',')
+ writer.path = writer.path[:len(writer.path) - 1]
+ writer.state = JSONWriterStateInMap
+ case int:
+ writer.writer.WriteRune('}')
+ writer.path = writer.path[:len(writer.path) - 1]
+ }
+ case int:
+ switch path[0].(type) {
+ case string:
+ writer.writer.WriteRune(']')
+ writer.path = writer.path[:len(writer.path) - 1]
+ case int:
+ writer.writer.WriteRune(',')
+ writer.path = writer.path[:len(writer.path) - 1]
+ writer.state = JSONWriterStateInArray
+ }
+ }
+ }
+ } else {
+ switch writer.path[len(writer.path) - 1].(type) {
+ case string:
+ writer.writer.WriteRune('}')
+ writer.path = writer.path[:len(writer.path) - 1]
+ case int:
+ writer.writer.WriteRune(']')
+ writer.path = writer.path[:len(writer.path) - 1]
+ }
+ }
+ case JSONWriterStateInArray:
+ writer.writer.WriteRune(']')
+ writer.state = JSONWriterStateAfterValue
+ case JSONWriterStateInMap:
+ writer.writer.WriteRune('}')
+ writer.state = JSONWriterStateAfterValue
+ }
}
}
+}
+
+func (writer *JSONWriter) Write(value walk.Value) error {
return nil
}
+func (writer *JSONWriter) pathWrite(value walk.Value, path []walk.PathSegment) error {
+ switch value := value.(type) {
+ case walk.NullValue:
+ return writer.write(path, value)
+ case walk.BoolValue:
+ return writer.write(path, value)
+ case walk.NumberValue:
+ return writer.write(path, value)
+ case walk.StringValue:
+ return writer.write(path, value)
+ case walk.ArrayValue:
+ if len(value) == 0 {
+ return writer.write(path, value)
+ } else {
+ for _, element := range value {
+ err := writer.pathWrite(element.Value, append(path, element.Index))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ case walk.MapValue:
+ if len(value) == 0 {
+ return writer.write(path, value)
+ } else {
+ for _, element := range value {
+ err := writer.pathWrite(element.Value, append(path, element.Key))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ case walk.RuneValue:
+ panic("Cannot write rune value")
+ default:
+ panic("Unrecognised value type")
+ }
+}
+
func (writer *JSONWriter) indent(level int) {
for i := 0; i < level; i += 1 {
writer.writer.WriteRune('\t')
}
}
-func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error {
+func (writer *JSONWriter) write(targetPath []walk.PathSegment, value walk.Value) error {
diversionPoint := 0
for diversionPoint < len(writer.path) && diversionPoint < len(targetPath) && segmentEqual(writer.path[diversionPoint], targetPath[diversionPoint]) {
diversionPoint += 1
@@ -92,10 +307,10 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
if diversionPoint < len(targetPath) {
segment := targetPath[diversionPoint]
switch segment.(type) {
- case walk.NumberScalar:
+ case int:
writer.writer.WriteString("[\n")
goto inArray
- case walk.StringStructure:
+ case string:
writer.writer.WriteString("{\n")
goto inMap
default:
@@ -104,11 +319,11 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
}
switch value := value.(type) {
- case walk.NullScalar:
+ case walk.NullValue:
writer.writer.WriteString("null")
writer.state = JSONWriterStateAfterValue
return nil
- case walk.BoolScalar:
+ case walk.BoolValue:
if value {
writer.writer.WriteString("true")
} else {
@@ -116,20 +331,20 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
}
writer.state = JSONWriterStateAfterValue
return nil
- case walk.NumberScalar:
+ case walk.NumberValue:
writer.writer.WriteString(fmt.Sprintf("%v", value))
writer.state = JSONWriterStateAfterValue
return nil
- case walk.StringStructure:
+ case walk.StringValue:
writer.writer.WriteString(fmt.Sprintf("%q", value))
writer.state = JSONWriterStateAfterValue
return nil
- case walk.ArrayStructure:
+ case walk.ArrayValue:
// TODO: write the contents of the structures
writer.writer.WriteString("[\n")
writer.state = JSONWriterStateInArray
return nil
- case walk.MapStructure:
+ case walk.MapValue:
writer.writer.WriteString("{\n")
writer.state = JSONWriterStateInMap
return nil
@@ -143,15 +358,15 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
if diversionPoint == len(writer.path) - 1 && diversionPoint < len(targetPath) {
segment := writer.path[diversionPoint]
switch segment.(type) {
- case walk.NumberScalar:
- _, isNumber := targetPath[diversionPoint].(walk.NumberScalar)
+ case int:
+ _, isNumber := targetPath[diversionPoint].(walk.NumberValue)
if isNumber {
writer.writer.WriteString(",\n")
writer.path = writer.path[:diversionPoint]
goto inArray
}
- case walk.StringStructure:
- _, isString := targetPath[diversionPoint].(walk.StringStructure)
+ case string:
+ _, isString := targetPath[diversionPoint].(walk.StringValue)
if isString {
writer.writer.WriteString(",\n")
writer.path = writer.path[:diversionPoint]
@@ -164,10 +379,10 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
writer.writer.WriteString("\n")
switch writer.path[len(writer.path) - 1].(type) {
- case walk.NumberScalar:
+ case int:
writer.path = writer.path[:len(writer.path) - 1]
goto inArray
- case walk.StringStructure:
+ case string:
writer.path = writer.path[:len(writer.path) - 1]
goto inMap
default:
@@ -186,9 +401,9 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
diversionPoint--
writer.path = writer.path[:diversionPoint]
switch segment.(type) {
- case walk.NumberScalar:
+ case int:
goto inArray
- case walk.StringStructure:
+ case string:
goto inMap
default:
panic("Invalid segment type")
@@ -204,9 +419,9 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
diversionPoint--
writer.path = writer.path[:diversionPoint]
switch segment.(type) {
- case walk.NumberScalar:
+ case int:
goto inArray
- case walk.StringStructure:
+ case string:
goto inMap
default:
panic("Invalid segment type")
@@ -222,12 +437,12 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
if diversionPoint < len(targetPath) {
switch s := targetPath[diversionPoint].(type) {
- case walk.NumberScalar:
+ case int:
writer.path = append(writer.path, s)
diversionPoint++
writer.indent(len(writer.path))
goto beforeValue
- case walk.StringStructure:
+ case string:
writer.indent(len(writer.path))
writer.writer.WriteString("]")
goto afterValue
@@ -250,11 +465,11 @@ func (writer *JSONWriter) write(targetPath []walk.Value, value walk.Value) error
if diversionPoint < len(targetPath) {
switch s := targetPath[diversionPoint].(type) {
- case walk.NumberScalar:
+ case int:
writer.indent(len(writer.path))
writer.writer.WriteString("}")
goto afterValue
- case walk.StringStructure:
+ case string:
writer.path = append(writer.path, s)
diversionPoint++
writer.indent(len(writer.path))
@@ -278,11 +493,11 @@ func (writer *JSONWriter) AssertDone() {
}
for i := len(writer.path) - 1; i >= 0; i -= 1 {
switch writer.path[i].(type) {
- case walk.NumberScalar:
+ case int:
writer.writer.WriteString("\n")
writer.indent(i)
writer.writer.WriteString("]")
- case walk.StringStructure:
+ case string:
writer.writer.WriteString("\n")
writer.indent(i)
writer.writer.WriteString("}")