From 1aa08f927c7043a643e847c434399fc76d053df0 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 26 Apr 2023 14:41:25 +0100 Subject: Store stred programs as a flat list of commands with no nesting, using a new jump command to simulate command blocks --- main/command.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++---------- main/main.go | 6 ++-- main/parse.go | 64 +++++++++++++++--------------------- 3 files changed, 114 insertions(+), 56 deletions(-) diff --git a/main/command.go b/main/command.go index 296ad69..44fd9eb 100644 --- a/main/command.go +++ b/main/command.go @@ -3,10 +3,12 @@ package main import ( "main/walk" "main/subex" + "fmt" ) type Command interface { exec(*ProgramState) + String() string } type PrintValueCommand struct {} @@ -17,15 +19,10 @@ func (cmd PrintValueCommand) exec(state *ProgramState) { } path := walk.PathFromWalkValues(pathValues) state.out.Print(path, state.value) + state.pc++ } - -type SequenceCommand struct { - commands []Command -} -func (cmd SequenceCommand) exec(state *ProgramState) { - for _, command := range cmd.commands { - command.exec(state) - } +func (cmd PrintValueCommand) String() string { + return "p" } type NextCommand struct {} @@ -36,6 +33,10 @@ func (cmd NextCommand) exec(state *ProgramState) { } state.value = nextItem.Value state.path = nextItem.Path + state.pc++ +} +func (cmd NextCommand) String() string { + return "n" } type AppendNextCommand struct {} @@ -46,16 +47,28 @@ func (cmd AppendNextCommand) exec(state *ProgramState) { } 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) { @@ -68,43 +81,62 @@ func runSubex(state subex.Transducer, in []walk.Atom) (out []walk.Atom, error bo type SubstituteValueCommand struct { subex subex.Transducer - next Command } func (cmd SubstituteValueCommand) exec(state *ProgramState) { newValue, err := runSubex(cmd.subex, state.value) if err { - return + state.pc++ + } else { + state.pc += 2 + state.value = newValue } - state.value = newValue - cmd.next.exec(state) +} +func (cmd SubstituteValueCommand) String() string { + return "s/.../" } type SubstitutePathCommand struct { subex subex.Transducer - next Command } func (cmd SubstitutePathCommand) exec(state *ProgramState) { newPath, err := runSubex(cmd.subex, state.path) if err { - return + state.pc++ + } else { + state.pc += 2 + state.path = newPath } - state.path = newPath - cmd.next.exec(state) +} +func (cmd SubstitutePathCommand) String() string { + return "S/.../" } type NoopCommand struct {} -func (cmd NoopCommand) exec(state *ProgramState) {} +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 {} @@ -112,11 +144,19 @@ 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 {} @@ -124,11 +164,19 @@ 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 {} @@ -136,9 +184,27 @@ 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) } \ No newline at end of file diff --git a/main/main.go b/main/main.go index 2067920..55ed5b5 100644 --- a/main/main.go +++ b/main/main.go @@ -13,6 +13,7 @@ type ProgramState struct { in walk.JSONIn out walk.JSONOut program []Command + pc int } func main() { @@ -55,8 +56,9 @@ func main() { } state.value = walkItem.Value state.path = walkItem.Path - for _, cmd := range state.program { - cmd.exec(&state) + state.pc = 0 + for state.pc < len(state.program) { + state.program[state.pc].exec(&state) } if !quiet { pathValues, err := walk.Compound(state.path) diff --git a/main/parse.go b/main/parse.go index 1972b66..ef50e81 100644 --- a/main/parse.go +++ b/main/parse.go @@ -57,18 +57,18 @@ func (p *parser) parseSubex() subex.SubexAST { return subexAST } -func (p *parser) parseBasicCommand(commandChar rune) Command { +func (p *parser) parseBasicCommand(commands []Command, commandChar rune) []Command { switch commandChar { case 'p': - return PrintValueCommand{} + return append(commands, PrintValueCommand{}) case 'd': - return DeleteValueCommand{} + return append(commands, DeleteValueCommand{}) case 'D': - return DeletePathCommand{} + return append(commands, DeletePathCommand{}) case 'n': - return NextCommand{} + return append(commands, NextCommand{}) case 'N': - return AppendNextCommand{} + return append(commands, AppendNextCommand{}) case 's', 'S', 'f', 'F', 'l', 'L', 'a', 'A': ast := p.parseSubex() switch commandChar { @@ -120,77 +120,67 @@ func (p *parser) parseBasicCommand(commandChar rune) Command { } } subex := subex.CompileTransducer(ast) - var next Command - token := p.peek() - switch token.typ { - case TokenEOF, TokenRBrace: - next = NoopCommand{} - default: - next = p.parseCommand() - } switch commandChar { case 's', 'a': - return SubstituteValueCommand {subex, next} + return append(commands, SubstituteValueCommand {subex}, JumpCommand {len(commands) + 3}) case 'S', 'f', 'F', 'l', 'L', 'A': - return SubstitutePathCommand {subex, next} + return append(commands, SubstitutePathCommand {subex}, JumpCommand {len(commands) + 3}) default: panic("Unreachable!?!?") } case 'o': - return NoopCommand{} + return append(commands, NoopCommand{}) case 'x': - return SwapXRegCommand{} + return append(commands, SwapXRegCommand{}) case 'X': - return AppendXRegCommand{} + return append(commands, AppendXRegCommand{}) case 'y': - return SwapYRegCommand{} + return append(commands, SwapYRegCommand{}) case 'Y': - return AppendYRegCommand{} + return append(commands, AppendYRegCommand{}) case 'z': - return SwapZRegCommand{} + return append(commands, SwapZRegCommand{}) case 'Z': - return AppendZRegCommand{} + return append(commands, AppendZRegCommand{}) case 'k': - return SwapPathCommand{} + return append(commands, SwapPathCommand{}) case 'K': - return AppendPathCommand{} + return append(commands, AppendPathCommand{}) default: panic("Invalid command") } } -func (p *parser) parseCommand() Command { +func (p *parser) parseCommand(commands []Command) []Command { token := p.next() switch token.typ { case TokenLBrace: - commands := p.parseCommands() + jumpToBlockCommand := &JumpCommand{0} + commands = append(commands, JumpCommand {len(commands) + 2}, jumpToBlockCommand) + commands = p.parseCommands(commands) if p.next().typ != TokenRBrace { panic("Missing matching }") } - return SequenceCommand {commands} + jumpToBlockCommand.destination = len(commands) + return commands case TokenCommand: commandChar, _, err := strings.NewReader(token.val).ReadRune() if err != nil { panic("Error reading a command character!?") } - return p.parseBasicCommand(commandChar) + return p.parseBasicCommand(commands, commandChar) default: panic("Invalid token, expected command") } } -func (p *parser) parseCommands() []Command { - var commands []Command +func (p *parser) parseCommands(commands []Command) []Command { for { nextToken := p.peek() if nextToken.typ == TokenEOF || nextToken.typ == TokenRBrace { return commands } - commands = append(commands, p.parseCommand()) - endToken := p.peek() - if endToken.typ == TokenEOF || endToken.typ == TokenRBrace { - return commands - } + commands = p.parseCommand(commands) } } @@ -198,5 +188,5 @@ func Parse(tokens chan Token) []Command { p := parser { tokenStream: tokens, } - return p.parseCommands() + return p.parseCommands(nil) } -- cgit v1.2.3