<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-12-28 09:31:29 +0000
committerCharlie Stanton <charlie@shtanton.xyz>2023-12-28 09:31:29 +0000
commit0e4179fabbd0a66826f1375dae86ca7f681fb29d (patch)
tree147d6937440da55323ac348fb33d314e4b06e59b
parentd9bba774bfe4910b01ece1c7d657ba1b429c7636 (diff)
downloadstred-go-0e4179fabbd0a66826f1375dae86ca7f681fb29d.tar
Rewrite json/read.go to no longer use a path
-rw-r--r--json/read.go207
1 files changed, 159 insertions, 48 deletions
diff --git a/json/read.go b/json/read.go
index 6a68467..8ed7e96 100644
--- a/json/read.go
+++ b/json/read.go
@@ -42,67 +42,77 @@ func NewJSONReader(reader *bufio.Reader) *JSONReader {
}
}
+type PathSegment interface {}
+
type JSONReader struct {
- path []walk.Value
+ path []PathSegment
structure []JSONReaderStructure
state JSONReaderState
reader *bufio.Reader
+ prevStart bool
}
func (reader *JSONReader) Read() (walk.WalkItem, error) {
switch reader.state {
case JSONReaderStateValue:
if len(reader.structure) == 0 {
- path := reader.clonePath()
- value, err := reader.readValue()
- if err != nil {
- panic("Missing JSON input")
- }
- return walk.WalkItem {
- Path: path,
- Value: []walk.Value{value},
- }, nil
+ // Before the start of a root JSON value
+ return reader.readValue()
}
switch reader.structure[len(reader.structure) - 1] {
case JSONReaderStructureArray:
+ // Before a value inside an array
r, err := reader.nextNonWsRune()
if err != nil {
panic("Missing rest of array")
}
if r == ']' {
+ // End of an array
reader.structure = reader.structure[:len(reader.structure) - 1]
reader.path = reader.path[:len(reader.path) - 1]
reader.state = JSONReaderStateValueEnd
- return reader.Read()
+ item := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.ArrayValue([]walk.ArrayElement{})),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: true,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return item, nil
}
+ // Element in array
reader.reader.UnreadRune()
- prevIndex := reader.path[len(reader.path) - 1].(walk.NumberScalar)
+ prevIndex := reader.path[len(reader.path) - 1].(int)
reader.path[len(reader.path) - 1] = prevIndex + 1
- path := reader.clonePath()
- value, err := reader.readValue()
- if err != nil {
- panic("Missing value in array")
- }
- return walk.WalkItem {
- Path: path,
- Value: []walk.Value{value},
- }, nil
+ return reader.readValue()
case JSONReaderStructureMap:
+ // Before a value inside a map
r, err := reader.nextNonWsRune()
if err != nil {
panic("Reached EOF inside JSON map")
}
if r == '}' {
+ // End of a map
reader.structure = reader.structure[:len(reader.structure) - 1]
reader.path = reader.path[:len(reader.path) - 1]
reader.state = JSONReaderStateValueEnd
- return reader.Read()
+ item := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.MapValue([]walk.MapElement{})),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: true,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return item, nil
}
+ // Element in map
if r != '"' {
panic("Expected key in map, found something else")
}
key := reader.readString()
- reader.path[len(reader.path) - 1] = walk.StringStructure(key)
+ reader.path[len(reader.path) - 1] = key
r, err = reader.nextNonWsRune()
if err != nil {
panic("Reached EOF after map key")
@@ -110,15 +120,7 @@ func (reader *JSONReader) Read() (walk.WalkItem, error) {
if r != ':' {
panic("Expected : after map key, found something else")
}
- path := reader.clonePath()
- value, err := reader.readValue()
- if err != nil {
- panic("Missing value in map")
- }
- return walk.WalkItem {
- Path: path,
- Value: []walk.Value{value},
- }, nil
+ return reader.readValue()
default:
panic("Invalid JSONReaderStructure")
}
@@ -140,7 +142,15 @@ func (reader *JSONReader) Read() (walk.WalkItem, error) {
reader.path = reader.path[:len(reader.path) - 1]
reader.structure = reader.structure[:len(reader.structure) - 1]
reader.state = JSONReaderStateValueEnd
- return reader.Read()
+ item := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.ArrayValue([]walk.ArrayElement{})),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: true,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return item, nil
}
if r != ',' {
panic("Missing , after array value")
@@ -156,7 +166,15 @@ func (reader *JSONReader) Read() (walk.WalkItem, error) {
reader.path = reader.path[:len(reader.path) - 1]
reader.structure = reader.structure[:len(reader.structure) - 1]
reader.state = JSONReaderStateValueEnd
- return reader.Read()
+ item := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.MapValue([]walk.MapElement{})),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: true,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return item, nil
}
if r != ',' {
panic("Missing , after map value")
@@ -171,7 +189,7 @@ func (reader *JSONReader) Read() (walk.WalkItem, error) {
}
}
-func (reader *JSONReader) readValue() (walk.Value, error) {
+func (reader *JSONReader) readValue() (walk.WalkItem, error) {
r, err := reader.nextNonWsRune()
if err != nil {
panic("Missing value in JSON")
@@ -180,29 +198,77 @@ func (reader *JSONReader) readValue() (walk.Value, error) {
case 'n':
reader.requireString("ull")
reader.state = JSONReaderStateValueEnd
- return walk.NullScalar{}, nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.NullValue{}),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return value, nil
case 'f':
reader.requireString("alse")
reader.state = JSONReaderStateValueEnd
- return walk.BoolScalar(false), nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.BoolValue(false)),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return value, nil
case 't':
reader.requireString("rue")
reader.state = JSONReaderStateValueEnd
- return walk.BoolScalar(true), nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.BoolValue(true)),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return value, nil
case '"':
v := reader.readString()
reader.state = JSONReaderStateValueEnd
- return walk.StringStructure(v), nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.StringValue(v)),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return value, nil
case '{':
reader.state = JSONReaderStateValue
reader.structure = append(reader.structure, JSONReaderStructureMap)
- reader.path = append(reader.path, walk.StringStructure(""))
- return walk.MapStructure(make(map[string]walk.Value)), nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.MapValue([]walk.MapElement{})),
+ Start: true,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = true
+ reader.path = append(reader.path, walk.StringValue(""))
+ return value, nil
case '[':
reader.state = JSONReaderStateValue
reader.structure = append(reader.structure, JSONReaderStructureArray)
- reader.path = append(reader.path, walk.NumberScalar(-1))
- return walk.ArrayStructure{}, nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.ArrayValue([]walk.ArrayElement{})),
+ Start: true,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = true
+ reader.path = append(reader.path, -1)
+ return value, nil
}
if isNumberRune(r) {
var builder strings.Builder
@@ -223,11 +289,43 @@ func (reader *JSONReader) readValue() (walk.Value, error) {
panic("Invalid number")
}
reader.state = JSONReaderStateValueEnd
- return walk.NumberScalar(number), nil
+ value := walk.WalkItem {
+ Value: reader.buildWalkItemValue(walk.NumberValue(number)),
+ Start: false,
+ PrevStart: reader.prevStart,
+ End: false,
+ NextEnd: reader.isNextEnd(),
+ }
+ reader.prevStart = false
+ return value, nil
}
panic("Invalid JSON value starting with: " + string(r))
}
+func (reader *JSONReader) buildWalkItemValue(value walk.Value) walk.Value {
+ for i := len(reader.path) - 1; i >= 0; i -= 1 {
+ switch segment := reader.path[i].(type) {
+ case int:
+ value = walk.ArrayValue {
+ walk.ArrayElement {
+ Index: segment,
+ Value: value,
+ },
+ }
+ case string:
+ value = walk.MapValue {
+ walk.MapElement {
+ Key: segment,
+ Value: value,
+ },
+ }
+ default:
+ panic("Invalid segment type")
+ }
+ }
+ return value
+}
+
func (reader *JSONReader) readString() string {
var builder strings.Builder
for {
@@ -251,6 +349,23 @@ func (reader *JSONReader) readString() string {
return builder.String()
}
+func (reader *JSONReader) isNextEnd() bool {
+ r, err := reader.peekNonWsRune()
+ if err != nil {
+ return false
+ }
+ return r == ']' || r == '}'
+}
+
+func (reader *JSONReader) peekNonWsRune() (rune, error) {
+ r, err := reader.nextNonWsRune()
+ if err != nil {
+ return 0, err
+ }
+ reader.reader.UnreadRune()
+ return r, nil
+}
+
func (reader *JSONReader) nextNonWsRune() (rune, error) {
for {
r, _, err := reader.reader.ReadRune()
@@ -279,10 +394,6 @@ func (reader *JSONReader) require(criterion rune) {
}
}
-func (reader *JSONReader) clonePath() []walk.Value {
- return append([]walk.Value{}, reader.path...)
-}
-
func (reader *JSONReader) AssertDone() {
// TODO
}