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.in.Read() if err != nil { panic("Missing next value") } 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.in.Read() if err != nil { panic("Missing next value") } state.value = append(state.value, nextItem.Value) state.pc++ } func (cmd AppendNextCommand) String() string { return "N" } 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 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 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 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 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) }