package main import ( "bufio" "io" "main/json" "main/walk" "os" ) type ProgramState struct { value, xreg, yreg, zreg []walk.Value start, prevStart, end, nextEnd bool // TODO: This will only ever have 0 or 1 values, it is a slice out of laziness peekStack []walk.WalkItem in walk.StredReader out walk.StredWriter program []Command pc int } func (state *ProgramState) Read() (walk.WalkItem, error) { if len(state.peekStack) > 0 { item := state.peekStack[len(state.peekStack) - 1] state.peekStack = state.peekStack[:len(state.peekStack) - 1] return item, nil } return state.in.Read() } func (state *ProgramState) Peek() (walk.WalkItem, error) { item, err := state.Read() if err != nil { return walk.WalkItem{}, err } state.peekStack = append(state.peekStack, item) return item, nil } type config struct { quiet bool program string in io.Reader out io.Writer } func run(config config) { tokens := Lex(config.program) program := Parse(tokens) stdin := bufio.NewReader(config.in) stdout := bufio.NewWriter(config.out) state := ProgramState { in: json.NewJSONReader(stdin), out: json.NewJSONWriter(stdout), program: program, } for { walkItem, err := state.Read() if err != nil { break } state.value = []walk.Value{walkItem.Value} state.start = walkItem.Start state.prevStart = walkItem.PrevStart state.end = walkItem.End state.nextEnd = walkItem.NextEnd state.pc = 0 for state.pc < len(state.program) { state.program[state.pc].exec(&state) } if !config.quiet { for _, value := range state.value { err := state.out.Write(value) if err != nil { panic("Error while outputting") } } } } state.in.AssertDone() state.out.AssertDone() } func main() { config := config { quiet: false, in: os.Stdin, out: os.Stdout, } hasInput := false for i := 1; i < len(os.Args); i += 1 { switch os.Args[i] { case "-n": config.quiet = true continue } if i < len(os.Args) - 1 { panic("Unexpected arguments after program") } config.program = os.Args[i] hasInput = true } if !hasInput { panic("Missing program") } run(config) }