From 0e4179fabbd0a66826f1375dae86ca7f681fb29d Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Thu, 28 Dec 2023 09:31:29 +0000 Subject: Rewrite json/read.go to no longer use a path --- json/read.go | 207 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 159 insertions(+), 48 deletions(-) (limited to 'json') 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 } -- cgit v1.2.3