diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-26 15:02:03 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-26 15:02:03 +0100 | 
| commit | 39f767aef901694eef14b1004b13756410f19f66 (patch) | |
| tree | c26adf90b296c1e0f4029b9867fc7b71a7de20fd | |
| parent | 1aa08f927c7043a643e847c434399fc76d053df0 (diff) | |
| download | stred-go-39f767aef901694eef14b1004b13756410f19f66.tar | |
Add labels and branches with the : and b commands
| -rw-r--r-- | main/command.go | 12 | ||||
| -rw-r--r-- | main/lex.go | 10 | ||||
| -rw-r--r-- | main/parse.go | 34 | 
3 files changed, 54 insertions, 2 deletions
| diff --git a/main/command.go b/main/command.go index 44fd9eb..63cc3b8 100644 --- a/main/command.go +++ b/main/command.go @@ -207,4 +207,16 @@ func (cmd JumpCommand) exec(state *ProgramState) {  }  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)  }
\ No newline at end of file diff --git a/main/lex.go b/main/lex.go index f28244d..198c346 100644 --- a/main/lex.go +++ b/main/lex.go @@ -118,6 +118,7 @@ const (  	TokenCommand // A command character  	TokenSubstituteDelimiter // usually / but could be something else  	TokenSubex // A subex +	TokenLabel // A label  )  type Token struct { @@ -182,6 +183,9 @@ func lexCommand(l *lexer) stateFunc {  		case 's', 'S', 'f', 'F', 'l', 'L', 'a', 'A':  			l.emit(TokenCommand)  			return lexSubstitution +		case ':', 'b': +			l.emit(TokenCommand) +			return lexLabel  	}  	if isAlpha(r) {  		l.emit(TokenCommand) @@ -212,3 +216,9 @@ func lexSubstitution(l *lexer) stateFunc {  	}  	return lexCommand  } + +func lexLabel(l *lexer) stateFunc { +	l.next() +	l.emit(TokenLabel) +	return lexCommand +} diff --git a/main/parse.go b/main/parse.go index ef50e81..cbbfb9a 100644 --- a/main/parse.go +++ b/main/parse.go @@ -1,14 +1,16 @@  package main  import ( -	"strings"  	"fmt"  	"main/subex" +	"strings" +	"unicode/utf8"  )  type parser struct {  	tokenStream chan Token  	rewinds []Token +	labels map[rune]int  }  func (p *parser) next() Token {  	var token Token @@ -146,6 +148,21 @@ func (p *parser) parseBasicCommand(commands []Command, commandChar rune) []Comma  			return append(commands, SwapPathCommand{})  		case 'K':  			return append(commands, AppendPathCommand{}) +		case ':': +			labelToken := p.next() +			if labelToken.typ != TokenLabel { +				panic("Missing branch label") +			} +			label, _ := utf8.DecodeRuneInString(labelToken.val) +			p.labels[label] = len(commands) +			return commands +		case 'b': +			labelToken := p.next() +			if labelToken.typ != TokenLabel { +				panic("Missing branch label") +			} +			label, _ := utf8.DecodeRuneInString(labelToken.val) +			return append(commands, BranchPlaceholderCommand {label})  		default:  			panic("Invalid command")  	} @@ -187,6 +204,19 @@ func (p *parser) parseCommands(commands []Command) []Command {  func Parse(tokens chan Token) []Command {  	p := parser {  		tokenStream: tokens, +		rewinds: nil, +		labels: make(map[rune]int), +	} +	program := p.parseCommands(nil) +	for i, command := range program { +		switch branch := command.(type) { +			case BranchPlaceholderCommand: +				destination, exists := p.labels[branch.label] +				if !exists { +					panic("Tried to branch to a label that doesn't exist") +				} +				program[i] = JumpCommand {destination} +		}  	} -	return p.parseCommands(nil) +	return program  } | 
