diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-07-19 12:01:38 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-07-19 12:01:38 +0100 | 
| commit | 7d53110f2773ba758dea2f5c00483d879d378870 (patch) | |
| tree | 018e4c2f04557b0e2fb0024ba389e2e5a4d7fbda | |
| parent | 8cf10efe3b5a1bcc70bc6e5590ee63fd5eb00c5b (diff) | |
| download | stred-go-7d53110f2773ba758dea2f5c00483d879d378870.tar | |
Removes redundant json readers and writers
| -rw-r--r-- | json_array/read.go | 118 | ||||
| -rw-r--r-- | json_array/write.go | 151 | ||||
| -rw-r--r-- | json_tokens/read.go | 490 | ||||
| -rw-r--r-- | json_tokens/write.go | 151 | 
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, -	} -} | 
