From 88b60b7e1e43f88701c2ad0dafdcd2aa4f5fc454 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 26 Apr 2023 10:30:40 +0100 Subject: Improve the way state is tracked in fillReadBuffer --- walk/read.go | 177 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 74 deletions(-) (limited to 'walk/read.go') diff --git a/walk/read.go b/walk/read.go index 00be010..f123369 100644 --- a/walk/read.go +++ b/walk/read.go @@ -22,16 +22,22 @@ const ( JSONInRoot JSONInStructure = iota JSONInMap JSONInArray +) + +type JSONInState int +const ( + JSONInValueEnd JSONInState = iota + JSONInValue + JSONInValueStart JSONInString - JSONInValueEnd JSONInKey - JSONInKeyEnd ) type JSONIn struct { path []Atom reader *bufio.Reader structure []JSONInStructure + state JSONInState readBuffer []Atom readIndex int readBufferCapacity int @@ -44,6 +50,7 @@ func NewJSONIn(reader *bufio.Reader) JSONIn { path: make([]Atom, 0, 256), reader: reader, structure: []JSONInStructure{JSONInRoot}, + state: JSONInValueStart, readBuffer: make([]Atom, 0, 256), readIndex: 0, readBufferCapacity: 256, @@ -142,8 +149,7 @@ func (in *JSONIn) Read() (WalkItem, error) { in.readIndex = 0 in.actionBuffer = in.actionBuffer[:0] in.readBuffer = in.readBuffer[:0] - structure, err := in.fillReadBuffer(in.structure) - in.structure = structure + err := in.fillReadBuffer() if len(in.actionBuffer) == 0 { return WalkItem{}, err } @@ -158,8 +164,7 @@ func (in *JSONIn) Read() (WalkItem, error) { in.readBufferCapacity *= 2 copy(newReadBuffer, in.readBuffer) in.readBuffer = newReadBuffer - structure, _ := in.fillReadBuffer(in.structure) - in.structure = structure + in.fillReadBuffer() continue actionLoop } copy(in.readBuffer, in.readBuffer[in.readIndex:]) @@ -168,8 +173,7 @@ func (in *JSONIn) Read() (WalkItem, error) { copy(in.actionBuffer, in.actionBuffer[in.actionIndex:]) in.actionBuffer = in.actionBuffer[:len(in.actionBuffer) - in.actionIndex] in.actionIndex = 0 - structure, _ := in.fillReadBuffer(in.structure) - in.structure = structure + in.fillReadBuffer() continue actionLoop } in.readIndex += len(value) @@ -186,8 +190,7 @@ func (in *JSONIn) Read() (WalkItem, error) { in.readBufferCapacity *= 2 copy(newReadBuffer, in.readBuffer) in.readBuffer = newReadBuffer - structure, _ := in.fillReadBuffer(in.structure) - in.structure = structure + in.fillReadBuffer() continue actionLoop } copy(in.readBuffer, in.readBuffer[in.readIndex:]) @@ -196,8 +199,7 @@ func (in *JSONIn) Read() (WalkItem, error) { copy(in.actionBuffer, in.actionBuffer[in.actionIndex:]) in.actionBuffer = in.actionBuffer[:len(in.actionBuffer) - in.actionIndex] in.actionIndex = 0 - structure, _ := in.fillReadBuffer(in.structure) - in.structure = structure + in.fillReadBuffer() continue actionLoop } in.readIndex += len(value) @@ -239,28 +241,34 @@ func (in *JSONIn) pushActionBuffer(action ReadAction) { in.actionBuffer = append(in.actionBuffer, action) } -func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure, error) { +// Appends to the readBuffer until it has reached capacity +// Also appends to the actionBuffer as needed +func (in *JSONIn) fillReadBuffer() error { + switch in.state { + case JSONInValueStart: + goto valueStart + case JSONInValue: + goto value + case JSONInValueEnd: + goto valueEnd + case JSONInString: + goto string + case JSONInKey: + goto key + default: + panic("Invalid JSONInState") + } valueStart: { - state := structure[len(structure) - 1] - switch state { - case JSONInString: - structure = structure[:len(structure) - 1] - goto string - case JSONInValueEnd: - structure = structure[:len(structure) - 1] - goto valueEnd - case JSONInKey: - structure = structure[:len(structure) - 1] - goto key - case JSONInKeyEnd: - structure = structure[:len(structure) - 1] - goto keyEnd + innermost := in.structure[len(in.structure) - 1] + switch innermost { case JSONInMap: goto mapValue case JSONInArray: goto arrayValue case JSONInRoot: goto value + default: + panic("Invalid JSONInStructure") } } value: { @@ -273,43 +281,49 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure in.requireString("ull") in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomNull()) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd case 'f': in.requireString("alse") in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomBool(false)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd case 't': in.requireString("rue") in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomBool(true)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd case '"': in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomStringTerminal()) { - return append(structure, JSONInString), nil + in.state = JSONInString + return nil } goto string case '{': - structure = append(structure, JSONInMap) + in.structure = append(in.structure, JSONInMap) in.pushActionBuffer(ActionReadValue) in.pushActionBuffer(ActionAppendPathNull) if in.pushReadBuffer(NewAtomTerminal(MapBegin)) { - return structure, nil + in.state = JSONInValueStart + return nil } goto mapValue case '[': - structure = append(structure, JSONInArray) + in.structure = append(in.structure, JSONInArray) in.pushActionBuffer(ActionReadValue) in.pushActionBuffer(ActionAppendPathNull) if in.pushReadBuffer(NewAtomTerminal(ArrayBegin)) { - return structure, nil + in.state = JSONInValueStart + return nil } goto arrayValue } @@ -333,7 +347,8 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure } in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomNumber(number)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd } @@ -346,7 +361,8 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure } if r == '"' { if in.pushReadBuffer(NewAtomStringTerminal()) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd } @@ -356,42 +372,45 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure panic("Missing rune after \\") } if in.pushReadBuffer(NewAtomStringRune(r)) { - return append(structure, JSONInString), nil + in.state = JSONInString + return nil } goto string } if in.pushReadBuffer(NewAtomStringRune(r)) { - return append(structure, JSONInString), nil + in.state = JSONInString + return nil } goto string } key: { - r, _, err := in.reader.ReadRune() - if err != nil { - panic("Missing closing terminal in string input: " + err.Error()) - } - if r == '"' { - if in.pushReadBuffer(NewAtomStringTerminal()) { - return append(structure, JSONInKeyEnd), nil - } - goto keyEnd - } - if r == '\\' { - r, _, err = in.reader.ReadRune() + var full bool + for { + r, _, err := in.reader.ReadRune() if err != nil { - panic("Missing rune after \\") + panic("Missing closing terminal in string input: " + err.Error()) + } + if r == '"' { + full = in.pushReadBuffer(NewAtomStringTerminal()) + break + } + if r == '\\' { + r, _, err = in.reader.ReadRune() + if err != nil { + panic("Missing rune after \\") + } + if in.pushReadBuffer(NewAtomStringRune(r)) { + in.state = JSONInKey + return nil + } + continue } if in.pushReadBuffer(NewAtomStringRune(r)) { - return append(structure, JSONInKey), nil + in.state = JSONInKey + return nil } - goto key - } - if in.pushReadBuffer(NewAtomStringRune(r)) { - return append(structure, JSONInKey), nil + continue } - goto key - } - keyEnd: { r, err := in.nextNonWsRune() if err != nil { panic("Expected : got: " + err.Error()) @@ -399,30 +418,37 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure if r != ':' { panic("Expected : after key") } + if full { + in.state = JSONInValue + return nil + } goto value } valueEnd: { r, err := in.nextNonWsRune() if err != nil { - return append(structure, JSONInValueEnd), err + in.state = JSONInValueEnd + return err } - underState := structure[len(structure) - 1] - if underState == JSONInRoot { + innermost := in.structure[len(in.structure) - 1] + if innermost == JSONInRoot { panic("More input after root JSON object ends") - } else if underState == JSONInMap && r == '}' { - structure = structure[:len(structure) - 1] + } else if innermost == JSONInMap && r == '}' { + in.structure = in.structure[:len(in.structure) - 1] in.pushActionBuffer(ActionPopPath) in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomTerminal(MapEnd)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd - } else if underState == JSONInArray && r == ']' { - structure = structure[:len(structure) - 1] + } else if innermost == JSONInArray && r == ']' { + in.structure = in.structure[:len(in.structure) - 1] in.pushActionBuffer(ActionPopPath) in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomTerminal(ArrayEnd)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd } @@ -438,10 +464,11 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure panic("Missing value inside object") } if r == '}' { - structure = structure[:len(structure) - 1] + in.structure = in.structure[:len(in.structure) - 1] in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomTerminal(MapEnd)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd } @@ -450,7 +477,8 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure } in.pushActionBuffer(ActionAppendPath) if in.pushReadBuffer(NewAtomStringTerminal()) { - return append(structure, JSONInKey), nil + in.state = JSONInKey + return nil } goto key } @@ -460,11 +488,12 @@ func (in *JSONIn) fillReadBuffer(structure []JSONInStructure) ([]JSONInStructure panic("Missing value inside array") } if r == ']' { - structure = structure[:len(structure) - 1] + in.structure = in.structure[:len(in.structure) - 1] in.pushActionBuffer(ActionPopPath) in.pushActionBuffer(ActionReadValue) if in.pushReadBuffer(NewAtomTerminal(ArrayEnd)) { - return append(structure, JSONInValueEnd), nil + in.state = JSONInValueEnd + return nil } goto valueEnd } -- cgit v1.2.3