diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-12-28 09:31:29 +0000 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-12-28 09:31:29 +0000 | 
| commit | 0e4179fabbd0a66826f1375dae86ca7f681fb29d (patch) | |
| tree | 147d6937440da55323ac348fb33d314e4b06e59b /json | |
| parent | d9bba774bfe4910b01ece1c7d657ba1b429c7636 (diff) | |
| download | stred-go-0e4179fabbd0a66826f1375dae86ca7f681fb29d.tar | |
Rewrite json/read.go to no longer use a path
Diffstat (limited to 'json')
| -rw-r--r-- | json/read.go | 207 | 
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  } | 
