diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-26 14:41:25 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-26 14:41:25 +0100 | 
| commit | 1aa08f927c7043a643e847c434399fc76d053df0 (patch) | |
| tree | 3a6d5872a87395f44fced57d0aa0bf73564bf2f4 /main | |
| parent | 58bbf68238e7711da1dda53d9656444ed6ccbd4d (diff) | |
| download | stred-go-1aa08f927c7043a643e847c434399fc76d053df0.tar | |
Store stred programs as a flat list of commands with no nesting, using a new jump command to simulate command blocks
Diffstat (limited to 'main')
| -rw-r--r-- | main/command.go | 100 | ||||
| -rw-r--r-- | main/main.go | 6 | ||||
| -rw-r--r-- | 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)  } | 
