<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-07-19 12:01:38 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-07-19 12:01:38 +0100
commit7d53110f2773ba758dea2f5c00483d879d378870 (patch)
tree018e4c2f04557b0e2fb0024ba389e2e5a4d7fbda
parent8cf10efe3b5a1bcc70bc6e5590ee63fd5eb00c5b (diff)
downloadstred-go-7d53110f2773ba758dea2f5c00483d879d378870.tar
Removes redundant json readers and writers
-rw-r--r--json_array/read.go118
-rw-r--r--json_array/write.go151
-rw-r--r--json_tokens/read.go490
-rw-r--r--json_tokens/write.go151
4 files changed, 0 insertions, 910 deletions
diff --git a/json_array/read.go b/json_array/read.go
deleted file mode 100644
index 786bc2c..0000000
--- a/json_array/read.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package json_array
-
-import (
- "main/walk"
- "encoding/json"
- "errors"
- "bufio"
-)
-
-type state int
-const (
- stateStart state = iota
- stateValueStart
- stateEnd
- stateDead
-)
-
-func atomiseValue(value interface{}) []walk.AtomOLD {
- switch v := value.(type) {
- case nil:
- return []walk.AtomOLD{walk.NewAtomNull()}
- case bool:
- return []walk.AtomOLD{walk.NewAtomBool(v)}
- case float64:
- return []walk.AtomOLD{walk.NewAtomNumber(v)}
- case string:
- atoms := []walk.AtomOLD{walk.NewAtomStringTerminal()}
- for _, r := range v {
- atoms = append(atoms, walk.NewAtomStringRune(r))
- }
- atoms = append(atoms, walk.NewAtomStringTerminal())
- return atoms
- case []interface{}:
- atoms := []walk.AtomOLD{walk.NewAtomTerminal(walk.ArrayBegin)}
- for _, element := range v {
- atoms = append(atoms, atomiseValue(element)...)
- }
- atoms = append(atoms, walk.NewAtomTerminal(walk.ArrayEnd))
- return atoms
- case map[string]interface{}:
- atoms := []walk.AtomOLD{walk.NewAtomTerminal(walk.MapBegin)}
- for key, element := range v {
- atoms = append(atoms, atomiseValue(key)...)
- atoms = append(atoms, atomiseValue(element)...)
- }
- atoms = append(atoms, walk.NewAtomTerminal(walk.MapEnd))
- return atoms
- default:
- panic("Invalid JSON value type")
- }
-}
-
-func NewJSONArrayReader(reader *bufio.Reader) *JSONArrayReader {
- return &JSONArrayReader {
- decoder: json.NewDecoder(reader),
- state: stateStart,
- index: 0,
- }
-}
-
-type JSONArrayReader struct {
- decoder *json.Decoder
- state state
- index int
-}
-
-func (in *JSONArrayReader) Read() (walk.WalkItem, error) {
- restart:
- switch in.state {
- case stateStart:
- arrayStart, err := in.decoder.Token()
- if err != nil {
- panic("Error reading start of JSON array")
- }
- delim, isDelim := arrayStart.(json.Delim)
- if !isDelim || delim != '[' {
- panic("JSON input is not an array!")
- }
- in.state = stateValueStart
- goto restart
- case stateValueStart:
- if !in.decoder.More() {
- in.state = stateEnd
- goto restart
- }
- var m interface{}
- err := in.decoder.Decode(&m)
- if err != nil {
- panic("Error decoding array value")
- }
- in.index += 1
- return walk.WalkItem {
- Path: []interface{}{float64(in.index - 1)},
- Value: []interface{}{m},
- }, nil
- case stateEnd:
- arrayEnd, err := in.decoder.Token()
- if err != nil {
- panic("Error reading end of JSON array")
- }
- delim, isDelim := arrayEnd.(json.Delim)
- if !isDelim || delim != ']' {
- panic("JSON array wasn't ended")
- }
- in.state = stateDead
- return walk.WalkItem{}, errors.New("eof")
- case stateDead:
- return walk.WalkItem{}, errors.New("eof")
- default:
- panic("Unreachable!!!")
- }
-}
-
-func (in *JSONArrayReader) AssertDone() {
- if in.state != stateDead || in.decoder.More() {
- panic("More JSON after array value")
- }
-}
diff --git a/json_array/write.go b/json_array/write.go
deleted file mode 100644
index aaa2851..0000000
--- a/json_array/write.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package json_array
-
-import (
- "bufio"
- "strings"
- "main/walk"
- "encoding/json"
-)
-
-func assembleValue(atoms []walk.AtomOLD) (interface{}, []walk.AtomOLD) {
- if len(atoms) == 0 {
- panic("Missing JSON value in output")
- }
- switch atoms[0].Typ {
- case walk.AtomNull:
- return nil, atoms[1:]
- case walk.AtomBool:
- return atoms[0].Bool(), atoms[1:]
- case walk.AtomNumber:
- return atoms[0].Number(), atoms[1:]
- case walk.AtomStringTerminal:
- var builder strings.Builder
- atoms = atoms[1:]
- for {
- if len(atoms) == 0 {
- panic("Missing closing string terminal")
- }
- if atoms[0].Typ == walk.AtomStringTerminal {
- break
- }
- if atoms[0].Typ != walk.AtomStringRune {
- panic("Non string rune atom inside string")
- }
- builder.WriteRune(atoms[0].StringRune())
- atoms = atoms[1:]
- }
- atoms = atoms[1:]
- return builder.String(), atoms
- case walk.AtomStringRune:
- panic("String rune used outside of string terminals")
- case walk.AtomTerminal:
- terminal := atoms[0].Terminal()
- switch terminal {
- case walk.ArrayEnd, walk.MapEnd:
- panic("Tried to extract value from end terminal")
- case walk.ArrayBegin:
- var arr []interface{}
- var element interface{}
- atoms = atoms[1:]
- for {
- if len(atoms) == 0 {
- panic("Missing array end terminal")
- }
- if atoms[0].Typ == walk.AtomTerminal && atoms[0].Terminal() == walk.ArrayEnd {
- atoms = atoms[1:]
- break
- }
- element, atoms = assembleValue(atoms)
- arr = append(arr, element)
- }
- return arr, atoms
- case walk.MapBegin:
- obj := make(map[string]interface{})
- var key interface{}
- var element interface{}
- atoms = atoms[1:]
- for {
- if len(atoms) == 0 {
- panic("Missing map end terminal")
- }
- if atoms[0].Typ == walk.AtomTerminal && atoms[0].Terminal() == walk.MapEnd {
- atoms = atoms[1:]
- break
- }
- key, atoms = assembleValue(atoms)
- element, atoms = assembleValue(atoms)
- keyString, keyIsString := key.(string)
- if !keyIsString {
- panic("Key is not string")
- }
- obj[keyString] = element
- }
- return obj, atoms
- default:
- panic("Invalid terminal")
- }
- default:
- panic("Invalid atom")
- }
-}
-
-func outputValue(values []interface{}, writer *bufio.Writer) {
- for _, value := range values {
- bytes, err := json.MarshalIndent(value, "\t", "\t")
- if err != nil {
- panic("Error marshalling json into bytes")
- }
- _, err = writer.Write(bytes)
- if err != nil {
- panic("Error writing value")
- }
- }
-}
-
-type writerState int
-const (
- writerStateStart writerState = iota
- writerStateValue
-)
-
-func NewJSONArrayWriter(writer *bufio.Writer) *JSONArrayWriter {
- return &JSONArrayWriter {
- writer: writer,
- state: writerStateStart,
- }
-}
-
-type JSONArrayWriter struct {
- writer *bufio.Writer
- state writerState
-}
-
-func (out *JSONArrayWriter) Write(item walk.WalkItem) error {
- switch out.state {
- case writerStateStart:
- _, err := out.writer.WriteString("[\n\t")
- if err != nil {
- panic("Error outputting [ at beginning of array")
- }
- outputValue(item.Value, out.writer)
- out.state = writerStateValue
- return nil
- case writerStateValue:
- _, err := out.writer.WriteString(",\n\t")
- if err != nil {
- panic("Error outputting comma at the end of a value")
- }
- outputValue(item.Value, out.writer)
- return nil
- default:
- panic("Invalid writer state")
- }
-}
-
-func (out *JSONArrayWriter) AssertDone() {
- if out.state == writerStateStart {
- out.writer.WriteString("[")
- }
- out.writer.WriteString("\n]")
- out.writer.Flush()
-}
diff --git a/json_tokens/read.go b/json_tokens/read.go
deleted file mode 100644
index b0acf71..0000000
--- a/json_tokens/read.go
+++ /dev/null
@@ -1,490 +0,0 @@
-package json_tokens
-
-import (
- "main/walk"
- "bufio"
- "strings"
- "strconv"
- "fmt"
-)
-
-type ReadAction int
-const (
- ActionReadValue ReadAction = iota
- ActionAppendPath
- ActionPopPath
- ActionIncrementPath
- ActionAppendPathNull
-)
-
-type JSONInStructure int
-const (
- JSONInMap JSONInStructure = iota
- JSONInArray
-)
-
-type JSONInState int
-const (
- JSONInValueEnd JSONInState = iota
- JSONInValue
- JSONInValueStart
- JSONInString
- JSONInKey
-)
-
-type JSONIn struct {
- path []walk.AtomOLD
- reader *bufio.Reader
- structure []JSONInStructure
- state JSONInState
- readBuffer []walk.AtomOLD
- readIndex int
- readBufferCapacity int
- actionBuffer []ReadAction
- actionIndex int
-}
-
-func NewJSONIn(reader *bufio.Reader) *JSONIn {
- return &JSONIn {
- path: make([]walk.AtomOLD, 0, 256),
- reader: reader,
- structure: []JSONInStructure{},
- state: JSONInValueStart,
- readBuffer: make([]walk.AtomOLD, 0, 256),
- readIndex: 0,
- readBufferCapacity: 256,
- actionBuffer: make([]ReadAction, 0, 256),
- actionIndex: 0,
- }
-}
-
-func isWhitespace(r rune) bool {
- for _, ws := range " \t\r\n" {
- if r == ws {
- return true
- }
- }
- return false
-}
-
-func isNumberRune(r rune) bool {
- return '0' <= r && r <= '9' || r == '.'
-}
-
-func (in *JSONIn) popPath() {
- if len(in.path) == 0 {
- panic("Tried to pop from empty path")
- }
- finalAtom := in.path[len(in.path) - 1]
- if finalAtom.Typ != walk.AtomStringTerminal {
- in.path = in.path[:len(in.path) - 1]
- return
- }
- i := len(in.path) - 2
- for {
- if i < 0 {
- panic("Missing string begin in path")
- }
- if in.path[i].Typ == walk.AtomStringTerminal {
- break
- }
- i--
- }
- in.path = in.path[:i]
-}
-
-func (in *JSONIn) nextNonWsRune() (rune, error) {
- for {
- r, _, err := in.reader.ReadRune()
- if err != nil {
- return 0, err
- }
- if !isWhitespace(r) {
- return r, nil
- }
- }
-}
-
-func (in *JSONIn) requireString(criteria string) {
- for _, r := range criteria {
- in.require(r)
- }
-}
-
-func (in *JSONIn) require(criterion rune) {
- r, _, err := in.reader.ReadRune()
- if err != nil {
- panic("Error while reading required rune: " + err.Error())
- }
- if r != criterion {
- panic("Required rune not read")
- }
-}
-
-// Returns the first full value of a list of atoms and also a boolean to indicate if there isn't a value at the beginning
-func firstValue(atoms []walk.AtomOLD) ([]walk.AtomOLD, bool) {
- if len(atoms) == 0 {
- return nil, true
- }
- if atoms[0].Typ != walk.AtomStringTerminal {
- return atoms[0:1], false
- }
- i := 1
- for {
- if i == len(atoms) {
- return nil, true
- }
- if atoms[i].Typ == walk.AtomStringTerminal {
- return atoms[0:i+1], false
- }
- i++
- }
-}
-
-func (in *JSONIn) readValue() []walk.AtomOLD {
- try:
- value, incomplete := firstValue(in.readBuffer[in.readIndex:])
- if incomplete {
- if in.readIndex == 0 {
- newReadBuffer := make([]walk.AtomOLD, len(in.readBuffer), in.readBufferCapacity * 2)
- in.readBufferCapacity *= 2
- copy(newReadBuffer, in.readBuffer)
- in.readBuffer = newReadBuffer
- in.fillReadBuffer()
- goto try
- }
- copy(in.readBuffer, in.readBuffer[in.readIndex:])
- in.readBuffer = in.readBuffer[:len(in.readBuffer) - in.readIndex]
- in.readIndex = 0
- copy(in.actionBuffer, in.actionBuffer[in.actionIndex:])
- in.actionBuffer = in.actionBuffer[:len(in.actionBuffer) - in.actionIndex]
- in.actionIndex = 0
- in.fillReadBuffer()
- goto try
- }
- in.readIndex += len(value)
- return value
-}
-
-func (in *JSONIn) Read() (walk.WalkItem, error) {
- for {
- if in.actionIndex == len(in.actionBuffer) {
- in.actionIndex = 0
- in.readIndex = 0
- in.actionBuffer = in.actionBuffer[:0]
- in.readBuffer = in.readBuffer[:0]
- err := in.fillReadBuffer()
- if len(in.actionBuffer) == 0 {
- return walk.WalkItem{}, err
- }
- }
- action := in.actionBuffer[in.actionIndex]
- in.actionIndex++
- switch action {
- case ActionReadValue:
- value := in.readValue()
- return walk.WalkItem {
- Value: value,
- Path: in.path,
- }, nil
- case ActionAppendPath:
- value := in.readValue()
- in.path = append(in.path, value...)
- case ActionAppendPathNull:
- in.path = append(in.path, walk.NewAtomNull())
- case ActionPopPath:
- in.popPath()
- case ActionIncrementPath:
- prevIndex := in.path[len(in.path) - 1]
- if prevIndex.Typ == walk.AtomNull {
- prevIndex = walk.NewAtomNumber(0)
- } else if prevIndex.Typ == walk.AtomNumber {
- prevIndex = walk.NewAtomNumber(prevIndex.Number() + 1)
- } else {
- panic("Invalid index in array input. Type: " + fmt.Sprintf("%v", prevIndex.Typ))
- }
- in.path[len(in.path) - 1] = prevIndex
- default:
- panic("Invalid ReadAction")
- }
- }
-}
-
-func (in *JSONIn) AssertDone() {
- if len(in.structure) != 0 || in.state != JSONInValueEnd || in.readIndex < len(in.readBuffer) {
- panic("Input ended on incomplete JSON root")
- }
-}
-
-func (in *JSONIn) pushReadBuffer(atom walk.AtomOLD) bool {
- in.readBuffer = append(in.readBuffer, atom)
- return len(in.readBuffer) == in.readBufferCapacity
-}
-
-func (in *JSONIn) pushActionBuffer(action ReadAction) {
- in.actionBuffer = append(in.actionBuffer, action)
-}
-
-// 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: {
- if len(in.structure) == 0 {
- goto value
- }
- innermost := in.structure[len(in.structure) - 1]
- switch innermost {
- case JSONInMap:
- goto mapValue
- case JSONInArray:
- goto arrayValue
- default:
- panic("Invalid JSONInStructure")
- }
- }
- value: {
- r, err := in.nextNonWsRune()
- if err != nil {
- panic("Missing value in JSON")
- }
- switch r {
- case 'n':
- in.requireString("ull")
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomNull()) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- case 'f':
- in.requireString("alse")
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomBool(false)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- case 't':
- in.requireString("rue")
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomBool(true)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- case '"':
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomStringTerminal()) {
- in.state = JSONInString
- return nil
- }
- goto string
- case '{':
- in.structure = append(in.structure, JSONInMap)
- in.pushActionBuffer(ActionReadValue)
- in.pushActionBuffer(ActionAppendPathNull)
- if in.pushReadBuffer(walk.NewAtomTerminal(walk.MapBegin)) {
- in.state = JSONInValueStart
- return nil
- }
- goto mapValue
- case '[':
- in.structure = append(in.structure, JSONInArray)
- in.pushActionBuffer(ActionReadValue)
- in.pushActionBuffer(ActionAppendPathNull)
- if in.pushReadBuffer(walk.NewAtomTerminal(walk.ArrayBegin)) {
- in.state = JSONInValueStart
- return nil
- }
- goto arrayValue
- }
- if isNumberRune(r) {
- var builder strings.Builder
- builder.WriteRune(r)
- for {
- r, _, err = in.reader.ReadRune()
- if err != nil {
- break
- }
- if !isNumberRune(r) {
- in.reader.UnreadRune()
- break
- }
- builder.WriteRune(r)
- }
- number, parseError := strconv.ParseFloat(builder.String(), 64)
- if parseError != nil {
- panic("Invalid number")
- }
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomNumber(number)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- }
- panic("Invalid JSON value starting with: " + string(r))
- }
- string: {
- r, _, err := in.reader.ReadRune()
- if err != nil {
- panic("Missing closing terminal in string input: " + err.Error())
- }
- if r == '"' {
- if in.pushReadBuffer(walk.NewAtomStringTerminal()) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- }
- if r == '\\' {
- r, _, err = in.reader.ReadRune()
- if err != nil {
- panic("Missing rune after \\")
- }
- if in.pushReadBuffer(walk.NewAtomStringRune(r)) {
- in.state = JSONInString
- return nil
- }
- goto string
- }
- if in.pushReadBuffer(walk.NewAtomStringRune(r)) {
- in.state = JSONInString
- return nil
- }
- goto string
- }
- key: {
- var full bool
- for {
- r, _, err := in.reader.ReadRune()
- if err != nil {
- panic("Missing closing terminal in string input: " + err.Error())
- }
- if r == '"' {
- full = in.pushReadBuffer(walk.NewAtomStringTerminal())
- break
- }
- if r == '\\' {
- r, _, err = in.reader.ReadRune()
- if err != nil {
- panic("Missing rune after \\")
- }
- if in.pushReadBuffer(walk.NewAtomStringRune(r)) {
- in.state = JSONInKey
- return nil
- }
- continue
- }
- if in.pushReadBuffer(walk.NewAtomStringRune(r)) {
- in.state = JSONInKey
- return nil
- }
- continue
- }
- r, err := in.nextNonWsRune()
- if err != nil {
- panic("Expected : got: " + err.Error())
- }
- if r != ':' {
- panic("Expected : after key")
- }
- if full {
- in.state = JSONInValue
- return nil
- }
- goto value
- }
- valueEnd: {
- r, err := in.nextNonWsRune()
- if err != nil {
- in.state = JSONInValueEnd
- return err
- }
- if len(in.structure) == 0 {
- panic("More input after root JSON object ends")
- }
- innermost := in.structure[len(in.structure) - 1]
- if innermost == JSONInMap && r == '}' {
- in.structure = in.structure[:len(in.structure) - 1]
- in.pushActionBuffer(ActionPopPath)
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomTerminal(walk.MapEnd)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- } else if innermost == JSONInArray && r == ']' {
- in.structure = in.structure[:len(in.structure) - 1]
- in.pushActionBuffer(ActionPopPath)
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomTerminal(walk.ArrayEnd)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- }
- if r != ',' {
- panic("Expected , after JSON value, found: \"" + string(r) + "\"")
- }
- goto valueStart
- }
- mapValue: {
- in.pushActionBuffer(ActionPopPath)
- r, err := in.nextNonWsRune()
- if err != nil {
- panic("Missing value inside object")
- }
- if r == '}' {
- in.structure = in.structure[:len(in.structure) - 1]
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomTerminal(walk.MapEnd)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- }
- if r != '"' {
- panic("Expected key found something else")
- }
- in.pushActionBuffer(ActionAppendPath)
- if in.pushReadBuffer(walk.NewAtomStringTerminal()) {
- in.state = JSONInKey
- return nil
- }
- goto key
- }
- arrayValue: {
- r, err := in.nextNonWsRune()
- if err != nil {
- panic("Missing value inside array")
- }
- if r == ']' {
- in.structure = in.structure[:len(in.structure) - 1]
- in.pushActionBuffer(ActionPopPath)
- in.pushActionBuffer(ActionReadValue)
- if in.pushReadBuffer(walk.NewAtomTerminal(walk.ArrayEnd)) {
- in.state = JSONInValueEnd
- return nil
- }
- goto valueEnd
- }
- in.reader.UnreadRune()
- in.pushActionBuffer(ActionIncrementPath)
- goto value
- }
-}
diff --git a/json_tokens/write.go b/json_tokens/write.go
deleted file mode 100644
index 78ed186..0000000
--- a/json_tokens/write.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package json_tokens
-
-import (
- "fmt"
- "strings"
- "bufio"
- "main/walk"
-)
-
-func stringPathSegment(segment walk.PathSegment) string {
- return fmt.Sprintf("%v", segment)
-}
-
-type JSONOutStructure int
-const (
- JSONOutRoot JSONOutStructure = iota
- JSONOutMap
- JSONOutArray
- JSONOutString
- JSONOutValueEnd
-)
-
-type JSONOut struct {
- structure []JSONOutStructure
- writer *bufio.Writer
-}
-
-func (out *JSONOut) indent(adjust int) {
- fmt.Fprint(out.writer, strings.Repeat("\t", len(out.structure) - 1 + adjust))
-}
-
-func (out *JSONOut) atomOut(key string, atom walk.AtomOLD) {
- state := out.structure[len(out.structure) - 1]
- switch state {
- case JSONOutRoot, JSONOutMap, JSONOutArray:
- switch atom.Typ {
- case walk.AtomNull, walk.AtomBool, walk.AtomNumber:
- out.indent(0)
- if state == JSONOutMap {
- fmt.Fprintf(out.writer, "%q: ", key)
- }
- fmt.Fprint(out.writer, atom.String())
- out.structure = append(out.structure, JSONOutValueEnd)
- case walk.AtomStringTerminal:
- out.indent(0)
- if state == JSONOutMap {
- fmt.Fprintf(out.writer, "%q: ", key)
- }
- fmt.Fprint(out.writer, "\"")
- out.structure = append(out.structure, JSONOutString)
- case walk.AtomTerminal:
- switch atom.Terminal() {
- case walk.MapBegin:
- out.indent(0)
- if state == JSONOutMap {
- fmt.Fprintf(out.writer, "%q: ", key)
- }
- fmt.Fprint(out.writer, "{\n")
- out.structure = append(out.structure, JSONOutMap)
- case walk.ArrayBegin:
- out.indent(0)
- if state == JSONOutMap {
- fmt.Fprintf(out.writer, "%q: ", key)
- }
- fmt.Fprint(out.writer, "[\n")
- out.structure = append(out.structure, JSONOutArray)
- case walk.MapEnd:
- out.indent(-1)
- if state != JSONOutMap {
- panic("Map ended while not inside a map")
- }
- fmt.Fprint(out.writer, "}")
- out.structure[len(out.structure) - 1] = JSONOutValueEnd
- case walk.ArrayEnd:
- out.indent(-1)
- if state != JSONOutArray {
- panic("Array ended while not inside a array")
- }
- fmt.Fprint(out.writer, "]")
- out.structure[len(out.structure) - 1] = JSONOutValueEnd
- default:
- panic("Invalid TerminalValue")
- }
- default:
- panic("Invalid AtomType in root value")
- }
- case JSONOutValueEnd:
- out.structure = out.structure[:len(out.structure) - 1]
- underState := out.structure[len(out.structure) - 1]
- if underState == JSONOutMap && atom.Typ == walk.AtomTerminal && atom.Terminal() == walk.MapEnd {
- fmt.Fprint(out.writer, "\n")
- out.indent(-1)
- fmt.Fprint(out.writer, "}")
- out.structure[len(out.structure) - 1] = JSONOutValueEnd
- } else if underState == JSONOutArray && atom.Typ == walk.AtomTerminal && atom.Terminal() == walk.ArrayEnd {
- fmt.Fprint(out.writer, "\n")
- out.indent(-1)
- fmt.Fprint(out.writer, "]")
- out.structure[len(out.structure) - 1] = JSONOutValueEnd
- } else if underState == JSONOutRoot {
- panic("Tried to output JSON after root value has concluded")
- } else {
- fmt.Fprint(out.writer, ",\n")
- out.atomOut(key, atom)
- }
- case JSONOutString:
- if atom.Typ == walk.AtomStringTerminal {
- fmt.Fprint(out.writer, "\"")
- out.structure[len(out.structure) - 1] = JSONOutValueEnd
- } else {
- fmt.Fprint(out.writer, atom.String())
- }
- default:
- panic("Invalid JSONOutState")
- }
-}
-
-func (out *JSONOut) Print(path walk.Path, values []walk.AtomOLD) {
- var segment walk.PathSegment
- if len(path) > 0 {
- segment = path[len(path) - 1]
- }
- segmentString := stringPathSegment(segment)
- for _, atom := range values {
- out.atomOut(segmentString, atom)
- }
-}
-
-func (out *JSONOut) Write(item walk.WalkItem) error {
- pathValues, err := walk.Compound(item.Path)
- if err != nil {
- return err
- }
- path := walk.PathFromWalkValues(pathValues)
- out.Print(path, item.Value)
- return nil
-}
-
-func (out *JSONOut) AssertDone() {
- out.writer.Flush()
- if len(out.structure) != 2 || out.structure[0] != JSONOutRoot || out.structure[1] != JSONOutValueEnd {
- panic("Program ended with incomplete JSON output")
- }
-}
-
-func NewJSONOut(writer *bufio.Writer) *JSONOut {
- return &JSONOut {
- structure: []JSONOutStructure{JSONOutRoot},
- writer: writer,
- }
-}