From cce21232cc83060a53ecb3a7c30d7f6fbfd7a529 Mon Sep 17 00:00:00 2001
From: Charlie Stanton <charlie@shtanton.xyz>
Date: Tue, 25 Apr 2023 09:56:00 +0100
Subject: Now uses a buffered output for writing to improve performance

---
 main/main.go |  3 ++-
 walk/walk.go | 41 ++++++++++++++++++++++-------------------
 2 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/main/main.go b/main/main.go
index e6730de..0c7324b 100644
--- a/main/main.go
+++ b/main/main.go
@@ -40,10 +40,11 @@ func main() {
 	program := Parse(tokens)
 
 	stdin := bufio.NewReader(os.Stdin)
+	stdout := bufio.NewWriter(os.Stdout)
 
 	state := ProgramState {
 		in: walk.NewJSONIn(stdin),
-		out: walk.NewJSONOut(),
+		out: walk.NewJSONOut(stdout),
 		program: program,
 	}
 
diff --git a/walk/walk.go b/walk/walk.go
index 0719d1c..f9bac2a 100644
--- a/walk/walk.go
+++ b/walk/walk.go
@@ -511,10 +511,11 @@ const (
 
 type JSONOut struct {
 	structure []JSONOutStructure
+	writer *bufio.Writer
 }
 
 func (out *JSONOut) indent(adjust int) {
-	fmt.Print(strings.Repeat("\t", len(out.structure) - 1 + adjust))
+	fmt.Fprint(out.writer, strings.Repeat("\t", len(out.structure) - 1 + adjust))
 }
 
 func (out *JSONOut) atomOut(key string, atom Atom) {
@@ -525,46 +526,46 @@ func (out *JSONOut) atomOut(key string, atom Atom) {
 				case AtomNull, AtomBool, AtomNumber:
 					out.indent(0)
 					if state == JSONOutMap {
-						fmt.Printf("%q: ", key)
+						fmt.Fprintf(out.writer, "%q: ", key)
 					}
-					fmt.Print(atom.String())
+					fmt.Fprint(out.writer, atom.String())
 					out.structure = append(out.structure, JSONOutValueEnd)
 				case AtomStringTerminal:
 					out.indent(0)
 					if state == JSONOutMap {
-						fmt.Printf("%q: ", key)
+						fmt.Fprintf(out.writer, "%q: ", key)
 					}
-					fmt.Print("\"")
+					fmt.Fprint(out.writer, "\"")
 					out.structure = append(out.structure, JSONOutString)
 				case AtomTerminal:
 					switch TerminalValue(atom.data) {
 						case MapBegin:
 							out.indent(0)
 							if state == JSONOutMap {
-								fmt.Printf("%q: ", key)
+								fmt.Fprintf(out.writer, "%q: ", key)
 							}
-							fmt.Print("{\n")
+							fmt.Fprint(out.writer, "{\n")
 							out.structure = append(out.structure, JSONOutMap)
 						case ArrayBegin:
 							out.indent(0)
 							if state == JSONOutMap {
-								fmt.Printf("%q: ", key)
+								fmt.Fprintf(out.writer, "%q: ", key)
 							}
-							fmt.Print("[\n")
+							fmt.Fprint(out.writer, "[\n")
 							out.structure = append(out.structure, JSONOutArray)
 						case MapEnd:
 							out.indent(-1)
 							if state != JSONOutMap {
 								panic("Map ended while not inside a map")
 							}
-							fmt.Print("}")
+							fmt.Fprint(out.writer, "}")
 							out.structure[len(out.structure) - 1] = JSONOutValueEnd
 						case ArrayEnd:
 							out.indent(-1)
 							if state != JSONOutArray {
 								panic("Array ended while not inside a array")
 							}
-							fmt.Print("]")
+							fmt.Fprint(out.writer, "]")
 							out.structure[len(out.structure) - 1] = JSONOutValueEnd
 						default:
 							panic("Invalid TerminalValue")
@@ -576,27 +577,27 @@ func (out *JSONOut) atomOut(key string, atom Atom) {
 			out.structure = out.structure[:len(out.structure) - 1]
 			underState := out.structure[len(out.structure) - 1]
 			if underState == JSONOutMap && atom.Typ == AtomTerminal && TerminalValue(atom.data) == MapEnd {
-				fmt.Print("\n")
+				fmt.Fprint(out.writer, "\n")
 				out.indent(-1)
-				fmt.Print("}")
+				fmt.Fprint(out.writer, "}")
 				out.structure[len(out.structure) - 1] = JSONOutValueEnd
 			} else if underState == JSONOutArray && atom.Typ == AtomTerminal && TerminalValue(atom.data) == ArrayEnd {
-				fmt.Print("\n")
+				fmt.Fprint(out.writer, "\n")
 				out.indent(-1)
-				fmt.Print("]")
+				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.Print(",\n")
+				fmt.Fprint(out.writer, ",\n")
 				out.atomOut(key, atom)
 			}
 		case JSONOutString:
 			if atom.Typ == AtomStringTerminal {
-				fmt.Print("\"")
+				fmt.Fprint(out.writer, "\"")
 				out.structure[len(out.structure) - 1] = JSONOutValueEnd
 			} else {
-				fmt.Print(atom.String())
+				fmt.Fprint(out.writer, atom.String())
 			}
 		default:
 			panic("Invalid JSONOutState")
@@ -615,14 +616,16 @@ func (out *JSONOut) Print(path Path, values []Atom) {
 }
 
 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() JSONOut {
+func NewJSONOut(writer *bufio.Writer) JSONOut {
 	return JSONOut {
 		structure: []JSONOutStructure{JSONOutRoot},
+		writer: writer,
 	}
 }
 
-- 
cgit v1.2.3