package main import ( "main/walk" "main/subex" "fmt" ) type Command interface { exec(*ProgramState) String() string } type PrintValueCommand struct {} func (cmd PrintValueCommand) exec(state *ProgramState) { err := state.out.Write(walk.WalkItem { Path: state.path, Value: state.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 = nextItem.Value state.path = nextItem.Path 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 = walk.ConcatData(state.value, nextItem.Value) state.path = nextItem.Path 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" } type DeletePathCommand struct {} func (cmd DeletePathCommand) exec(state *ProgramState) { state.path = nil state.pc++ } func (cmd DeletePathCommand) String() string { return "D" } func runSubex(state subex.Transducer, in []walk.Atom) (out []walk.Atom, error bool) { atomsOut, error := subex.RunTransducer(state, in) if error { return nil, true } return atomsOut, 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 SubstitutePathCommand struct { subex subex.Transducer } func (cmd SubstitutePathCommand) exec(state *ProgramState) { newPath, err := runSubex(cmd.subex, state.path) if err { state.pc++ } else { state.pc += 2 state.path = newPath } } func (cmd SubstitutePathCommand) 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 SwapPathCommand struct {} func (cmd SwapPathCommand) exec(state *ProgramState) { v := state.value state.value = state.path state.path = v state.pc++ } func (cmd SwapPathCommand) String() string { return "k" } type AppendPathCommand struct {} func (cmd AppendPathCommand) exec(state *ProgramState) { state.path = walk.ConcatData(state.path, state.value) state.pc++ } func (cmd AppendPathCommand) String() string { return "K" } 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) }