<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-04-26 14:41:25 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-04-26 14:41:25 +0100
commit1aa08f927c7043a643e847c434399fc76d053df0 (patch)
tree3a6d5872a87395f44fced57d0aa0bf73564bf2f4
parent58bbf68238e7711da1dda53d9656444ed6ccbd4d (diff)
downloadstred-go-1aa08f927c7043a643e847c434399fc76d053df0.tar
Store stred programs as a flat list of commands with no nesting, using a new jump command to simulate command blocks
-rw-r--r--main/command.go100
-rw-r--r--main/main.go6
-rw-r--r--main/parse.go64
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)
}