diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2025-10-29 18:14:52 +0000 |
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2025-10-29 18:14:52 +0000 |
| commit | e4e454665bf7e21db21763c65bf35d23665b17cf (patch) | |
| tree | 121d749fe4487739ebfb239dc40d5cc88e0097dd /main/parse.go | |
| parent | b2ce005d227a10a9b8a6f5362c87a0e34ee07acc (diff) | |
| download | stred-go-e4e454665bf7e21db21763c65bf35d23665b17cf.tar | |
Diffstat (limited to 'main/parse.go')
| -rw-r--r-- | main/parse.go | 243 |
1 files changed, 195 insertions, 48 deletions
diff --git a/main/parse.go b/main/parse.go index 36bd3ee..d0a0255 100644 --- a/main/parse.go +++ b/main/parse.go @@ -10,7 +10,6 @@ import ( type parser struct { tokenStream chan Token rewinds []Token - labels map[rune]int } func (p *parser) next() Token { var token Token @@ -53,146 +52,288 @@ func (p *parser) parseSubex() subex.SubexAST { return subexAST } -func (p *parser) parseBasicCommand(commands []Command, commandChar rune) []Command { +func (p *parser) parseBasicCommand(commandChar rune) []Command { switch commandChar { case 'p': - return append(commands, PrintValueCommand{}) + return []Command {PrintValueCommand{}} case 'd': - return append(commands, DeleteValueCommand{}) + return []Command {DeleteValueCommand{}} case 'n': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, NextCommand{}) + return []Command {NextCommand{}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteNextCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteNextCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'N': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, AppendNextCommand{}) + return []Command {AppendNextCommand{}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteAppendNextCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteAppendNextCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'm': - return append(commands, MergeCommand{}) + return []Command {MergeCommand {}} case 'M': ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, FullMergeCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + FullMergeCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 's': ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteValueCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteValueCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) + case 'r': + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return []Command { + SubstituteValueCommand { + subex: subex, + elseJump: 2, + }, + RelativeJumpCommand { + destination: -1, + }, + } case 'o': - return append(commands, NoopCommand{}) + return []Command {NoopCommand {}} case 'x': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, SwapXRegCommand{}) + return []Command {SwapXRegCommand {}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteToXRegCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteToXRegCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'X': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, AppendXRegCommand{}) + return []Command {AppendXRegCommand {}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteAppendXRegCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteAppendXRegCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'y': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, SwapYRegCommand{}) + return []Command {SwapYRegCommand {}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteToYRegCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteToYRegCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'Y': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, AppendYRegCommand{}) + return []Command {AppendYRegCommand {}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteAppendYRegCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteAppendYRegCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'z': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, SwapZRegCommand{}) + return []Command {SwapZRegCommand {}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteToZRegCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteToZRegCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'Z': delim := p.peek() if delim.typ != TokenSubstituteDelimiter { - return append(commands, AppendZRegCommand{}) + return []Command {AppendZRegCommand {}} } ast := p.parseSubex() subex := subex.CompileTransducer(ast) - return append(commands, SubstituteAppendZRegCommand {subex}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + SubstituteAppendZRegCommand { + subex: subex, + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'a': - return append(commands, IsStartCommand{}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + IsStartCommand { + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'A': - return append(commands, IsPrevStartCommand{}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + IsPrevStartCommand { + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'e': - return append(commands, IsEndCommand{}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + IsEndCommand { + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case 'E': - return append(commands, IsNextEndCommand{}, JumpCommand {len(commands) + 3}) + elseBranch := p.parseCommand() + return append( + []Command { + IsNextEndCommand { + elseJump: len(elseBranch) + 1, + }, + }, + elseBranch..., + ) case ':': labelToken := p.next() if labelToken.typ != TokenLabel { panic("Missing branch label") } label, _ := utf8.DecodeRuneInString(labelToken.val) - p.labels[label] = len(commands) - return commands + return []Command { + LabelCommand { + label: label, + }, + } case 'b': labelToken := p.next() if labelToken.typ != TokenLabel { panic("Missing branch label") } label, _ := utf8.DecodeRuneInString(labelToken.val) - return append(commands, BranchPlaceholderCommand {label}) + return []Command { + BranchPlaceholderCommand { + label: label, + }, + } default: panic("Invalid command") } } -func (p *parser) parseCommand(commands []Command) []Command { +func (p *parser) parseCommand() []Command { token := p.next() switch token.typ { case TokenLBrace: - jumpToBlockCommand := &JumpCommand{0} - commands = append(commands, JumpCommand {len(commands) + 2}, jumpToBlockCommand) - commands = p.parseCommands(commands) + children := p.parseCommandSequence() if p.next().typ != TokenRBrace { panic("Missing matching }") } - jumpToBlockCommand.destination = len(commands) - return commands + return children + case TokenRBrace, TokenEOF: + p.rewind(token) + return nil case TokenCommand: commandChar, _, err := strings.NewReader(token.val).ReadRune() if err != nil { panic("Error reading a command character!?") } - return p.parseBasicCommand(commands, commandChar) + return p.parseBasicCommand(commandChar) default: panic("Invalid token, expected command") } } -func (p *parser) parseCommands(commands []Command) []Command { +func (p *parser) parseCommandSequence() []Command { + var commands []Command for { nextToken := p.peek() if nextToken.typ == TokenEOF || nextToken.typ == TokenRBrace { return commands } - commands = p.parseCommand(commands) + commands = append(commands, p.parseCommand()...) } } @@ -200,17 +341,23 @@ func Parse(tokens chan Token) []Command { p := parser { tokenStream: tokens, rewinds: nil, - labels: make(map[rune]int), } - program := p.parseCommands(nil) + program := p.parseCommandSequence() + labels := make(map[rune]int) + for i, command := range program { + switch label := command.(type) { + case LabelCommand: + labels[label.label] = i + } + } 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} + case BranchPlaceholderCommand: + destination, exists := labels[branch.label] + if !exists { + panic("Tried to branch to a label that doesn't exist") + } + program[i] = JumpCommand {destination} } } return program |
