package main import ( "main/subex" "main/walk" "fmt" ) type Command interface { exec(*ProgramState) String() string } type PrintValueCommand struct {} func (cmd PrintValueCommand) exec(state *ProgramState) { for _, value := range state.value { err := state.out.Write(value) if err != nil { panic("Error while outputting") } } state.pc++ } func (cmd PrintValueCommand) String() string { return "p" } type NextCommand struct {} func (cmd NextCommand) exec(state *ProgramState) { nextItem, err := state.Read() if err != nil { panic("Missing next value") } state.prevStart = nextItem.PrevStart state.start = nextItem.Start state.end = nextItem.End state.nextEnd = nextItem.NextEnd state.value = []walk.Value{nextItem.Value} state.pc++ } func (cmd NextCommand) String() string { return "n" } type AppendNextCommand struct {} func (cmd AppendNextCommand) exec(state *ProgramState) { nextItem, err := state.Read() if err != nil { panic("Missing next value") } state.prevStart = nextItem.PrevStart state.start = nextItem.Start state.end = nextItem.End state.nextEnd = nextItem.NextEnd state.value = append(state.value, nextItem.Value) state.pc++ } func (cmd AppendNextCommand) String() string { return "N" } type SubstituteNextCommand struct { subex subex.Transducer } func (cmd SubstituteNextCommand) exec(state *ProgramState) { item, err := state.Peek() if err != nil { panic("Missing next value") } newValue, notOk := runSubex(cmd.subex, []walk.Value{item.Value}) if notOk { state.pc++ } else { state.Read() state.prevStart = item.PrevStart state.start = item.Start state.end = item.End state.nextEnd = item.NextEnd state.pc += 2 state.value = newValue } } func (cmd SubstituteNextCommand) String() string { return "n/.../" } type SubstituteAppendNextCommand struct { subex subex.Transducer } func (cmd SubstituteAppendNextCommand) exec(state *ProgramState) { item, err := state.Peek() if err != nil { panic("Missing next value") } newValue, notOk := runSubex(cmd.subex, []walk.Value{item.Value}) if notOk { state.pc++ } else { state.Read() state.prevStart = item.PrevStart state.start = item.Start state.end = item.End state.nextEnd = item.NextEnd state.pc += 2 state.value = append(state.value, newValue...) } } func (cmd SubstituteAppendNextCommand) String() string { return "N/.../" } type MergeCommand struct {} func (cmd MergeCommand) exec(state *ProgramState) { if len(state.value) <= 1 { state.pc++ return } newVals := walk.Merge(state.value[len(state.value) - 2], state.value[len(state.value) - 1]) state.value = append( state.value[:len(state.value) - 2], newVals... ) state.pc++ } func (cmd MergeCommand) String() string { return "m" } type FullMergeCommand struct { subex subex.Transducer } func (cmd FullMergeCommand) exec(state *ProgramState) { _, notOk := runSubex(cmd.subex, state.value) if notOk { state.pc++ return } if !state.start { state.pc += 2 return } for { item, err := state.Read() if err != nil { panic("Missing next value") } _, nonTerminal := runSubex(cmd.subex, []walk.Value{item.Value}) state.value = append( state.value[:len(state.value) - 1], walk.Merge(state.value[len(state.value) - 1], item.Value)... ) if !nonTerminal && item.End { state.prevStart = item.PrevStart state.start = item.Start state.end = item.End state.nextEnd = item.NextEnd state.pc += 2 return } } } func (cmd FullMergeCommand) String() string { return "M" } type DeleteValueCommand struct {} func (cmd DeleteValueCommand) exec(state *ProgramState) { state.value = nil state.pc++ } func (cmd DeleteValueCommand) String() string { return "d" } func runSubex(state subex.Transducer, in []walk.Value) ([]walk.Value, bool) { out, error := subex.RunTransducer(state, in) if error { return nil, true } return out, false } type SubstituteValueCommand struct { subex subex.Transducer } func (cmd SubstituteValueCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.value = newValue } } func (cmd SubstituteValueCommand) String() string { return "s/.../" } type IsStartCommand struct {} func (cmd IsStartCommand) exec(state *ProgramState) { if state.start { state.pc += 2 } else { state.pc += 1 } } func (cmd IsStartCommand) String() string { return "a" } type IsPrevStartCommand struct {} func (cmd IsPrevStartCommand) exec(state *ProgramState) { if state.prevStart { state.pc += 2 } else { state.pc += 1 } } func (cmd IsPrevStartCommand) String() string { return "A" } type IsEndCommand struct {} func (cmd IsEndCommand) exec(state *ProgramState) { if state.end { state.pc += 2 } else { state.pc += 1 } } func (cmd IsEndCommand) String() string { return "e" } type IsNextEndCommand struct {} func (cmd IsNextEndCommand) exec(state *ProgramState) { if state.nextEnd { state.pc += 2 } else { state.pc += 1 } } func (cmd IsNextEndCommand) String() string { return "E" } type NoopCommand struct {} func (cmd NoopCommand) exec(state *ProgramState) { state.pc++ } func (cmd NoopCommand) String() string { return "o" } type SwapXRegCommand struct {} func (cmd SwapXRegCommand) exec(state *ProgramState) { v := state.value state.value = state.xreg state.xreg = v state.pc++ } func (cmd SwapXRegCommand) String() string { return "x" } type AppendXRegCommand struct {} func (cmd AppendXRegCommand) exec(state *ProgramState) { state.xreg = append(state.xreg, state.value...) state.pc++ } func (cmd AppendXRegCommand) String() string { return "X" } type SubstituteToXRegCommand struct { subex subex.Transducer } func (cmd SubstituteToXRegCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.xreg = newValue } } func (cmd SubstituteToXRegCommand) String() string { return "x/.../" } type SubstituteAppendXRegCommand struct { subex subex.Transducer } func (cmd SubstituteAppendXRegCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.xreg = append(state.xreg, newValue...) } } func (cmd SubstituteAppendXRegCommand) String() string { return "X/.../" } type SwapYRegCommand struct {} func (cmd SwapYRegCommand) exec(state *ProgramState) { v := state.value state.value = state.yreg state.yreg = v state.pc++ } func (cmd SwapYRegCommand) String() string { return "y" } type AppendYRegCommand struct {} func (cmd AppendYRegCommand) exec(state *ProgramState) { state.yreg = append(state.yreg, state.value...) state.pc++ } func (cmd AppendYRegCommand) String() string { return "Y" } type SubstituteToYRegCommand struct { subex subex.Transducer } func (cmd SubstituteToYRegCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.yreg = newValue } } func (cmd SubstituteToYRegCommand) String() string { return "y/.../" } type SubstituteAppendYRegCommand struct { subex subex.Transducer } func (cmd SubstituteAppendYRegCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.yreg = append(state.xreg, newValue...) } } func (cmd SubstituteAppendYRegCommand) String() string { return "Y/.../" } type SwapZRegCommand struct {} func (cmd SwapZRegCommand) exec(state *ProgramState) { v := state.value state.value = state.zreg state.zreg = v state.pc++ } func (cmd SwapZRegCommand) String() string { return "z" } type AppendZRegCommand struct {} func (cmd AppendZRegCommand) exec(state *ProgramState) { state.zreg = append(state.zreg, state.value...) state.pc++ } func (cmd AppendZRegCommand) String() string { return "Z" } type SubstituteToZRegCommand struct { subex subex.Transducer } func (cmd SubstituteToZRegCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.zreg = newValue } } func (cmd SubstituteToZRegCommand) String() string { return "z/.../" } type SubstituteAppendZRegCommand struct { subex subex.Transducer } func (cmd SubstituteAppendZRegCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { state.pc++ } else { state.pc += 2 state.zreg = append(state.xreg, newValue...) } } func (cmd SubstituteAppendZRegCommand) String() string { return "Z/.../" } type JumpCommand struct { destination int } func (cmd JumpCommand) exec(state *ProgramState) { state.pc = cmd.destination } func (cmd JumpCommand) String() string { return fmt.Sprintf("b%v", cmd.destination) } // Placeholder as the branch destination may not have been parsed when the branch command is // Should never appear in a program to actually be run type BranchPlaceholderCommand struct { label rune } func (cmd BranchPlaceholderCommand) exec(state *ProgramState) { panic("Tried to execute a BranchPlaceholderCommand!!!") } func (cmd BranchPlaceholderCommand) String() string { return fmt.Sprintf("b%c", cmd.label) }