From 658900fcae610caace83a112ac0ee865108ebc92 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Sun, 7 Apr 2024 15:27:36 +0100 Subject: Change output subex internals to allow structures Also add substitute register syntactic sugar --- main/command.go | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main/lex.go | 35 ++++++++----- main/main.go | 5 ++ main/main_test.go | 46 ++++++++++++++++- main/parse.go | 56 +++++++++++++++++--- subex/main_test.go | 12 +++++ subex/parse.go | 82 ++++++++++++++++++++++-------- subex/subexast.go | 117 +++++++++++++++++++++++------------------- subex/subexstate.go | 67 ++++++++++++++---------- 9 files changed, 442 insertions(+), 122 deletions(-) diff --git a/main/command.go b/main/command.go index 1d089ee..3f22821 100644 --- a/main/command.go +++ b/main/command.go @@ -84,6 +84,54 @@ func (cmd SubstituteValueCommand) String() string { return "s/.../" } +type IsStartCommand struct {} +func (cmd IsStartCommand) exec(state *ProgramState) { + if state.start { + state.pc += 2 + } else { + state.pc += 1 + } +} +func (cmd IsStartCommand) String() string { + return "a" +} + +type IsPrevStartCommand struct {} +func (cmd IsPrevStartCommand) exec(state *ProgramState) { + if state.prevStart { + state.pc += 2 + } else { + state.pc += 1 + } +} +func (cmd IsPrevStartCommand) String() string { + return "A" +} + +type IsEndCommand struct {} +func (cmd IsEndCommand) exec(state *ProgramState) { + if state.end { + state.pc += 2 + } else { + state.pc += 1 + } +} +func (cmd IsEndCommand) String() string { + return "e" +} + +type IsNextEndCommand struct {} +func (cmd IsNextEndCommand) exec(state *ProgramState) { + if state.nextEnd { + state.pc += 2 + } else { + state.pc += 1 + } +} +func (cmd IsNextEndCommand) String() string { + return "E" +} + type NoopCommand struct {} func (cmd NoopCommand) exec(state *ProgramState) { state.pc++ @@ -112,6 +160,38 @@ func (cmd AppendXRegCommand) String() string { return "X" } +type SubstituteToXRegCommand struct { + subex subex.Transducer +} +func (cmd SubstituteToXRegCommand) exec(state *ProgramState) { + newValue, err := runSubex(cmd.subex, state.value) + if err { + state.pc++ + } else { + state.pc += 2 + state.xreg = newValue + } +} +func (cmd SubstituteToXRegCommand) String() string { + return "x/.../" +} + +type SubstituteAppendXRegCommand struct { + subex subex.Transducer +} +func (cmd SubstituteAppendXRegCommand) exec(state *ProgramState) { + newValue, err := runSubex(cmd.subex, state.value) + if err { + state.pc++ + } else { + state.pc += 2 + state.xreg = append(state.xreg, newValue...) + } +} +func (cmd SubstituteAppendXRegCommand) String() string { + return "X/.../" +} + type SwapYRegCommand struct {} func (cmd SwapYRegCommand) exec(state *ProgramState) { v := state.value @@ -132,6 +212,38 @@ func (cmd AppendYRegCommand) String() string { return "Y" } +type SubstituteToYRegCommand struct { + subex subex.Transducer +} +func (cmd SubstituteToYRegCommand) exec(state *ProgramState) { + newValue, err := runSubex(cmd.subex, state.value) + if err { + state.pc++ + } else { + state.pc += 2 + state.yreg = newValue + } +} +func (cmd SubstituteToYRegCommand) String() string { + return "y/.../" +} + +type SubstituteAppendYRegCommand struct { + subex subex.Transducer +} +func (cmd SubstituteAppendYRegCommand) exec(state *ProgramState) { + newValue, err := runSubex(cmd.subex, state.value) + if err { + state.pc++ + } else { + state.pc += 2 + state.yreg = append(state.xreg, newValue...) + } +} +func (cmd SubstituteAppendYRegCommand) String() string { + return "Y/.../" +} + type SwapZRegCommand struct {} func (cmd SwapZRegCommand) exec(state *ProgramState) { v := state.value @@ -152,6 +264,38 @@ func (cmd AppendZRegCommand) String() string { return "Z" } +type SubstituteToZRegCommand struct { + subex subex.Transducer +} +func (cmd SubstituteToZRegCommand) exec(state *ProgramState) { + newValue, err := runSubex(cmd.subex, state.value) + if err { + state.pc++ + } else { + state.pc += 2 + state.zreg = newValue + } +} +func (cmd SubstituteToZRegCommand) String() string { + return "z/.../" +} + +type SubstituteAppendZRegCommand struct { + subex subex.Transducer +} +func (cmd SubstituteAppendZRegCommand) exec(state *ProgramState) { + newValue, err := runSubex(cmd.subex, state.value) + if err { + state.pc++ + } else { + state.pc += 2 + state.zreg = append(state.xreg, newValue...) + } +} +func (cmd SubstituteAppendZRegCommand) String() string { + return "Z/.../" +} + type JumpCommand struct { destination int } diff --git a/main/lex.go b/main/lex.go index 496abd0..a28975f 100644 --- a/main/lex.go +++ b/main/lex.go @@ -171,21 +171,28 @@ func lexCommand(l *lexer) stateFunc { l.ignore() r := l.next() switch r { - case eof: - l.emit(TokenEOF) - return nil - case '{': - l.emit(TokenLBrace) - return lexCommand - case '}': - l.emit(TokenRBrace) - return lexCommand - case 's', 'S': - l.emit(TokenCommand) + case eof: + l.emit(TokenEOF) + return nil + case '{': + l.emit(TokenLBrace) + return lexCommand + case '}': + l.emit(TokenRBrace) + return lexCommand + case 's', 'S': + l.emit(TokenCommand) + return lexSubstitution + case 'x', 'X', 'y', 'Y', 'z', 'Z': + l.emit(TokenCommand) + if l.peek() == '/' { return lexSubstitution - case ':', 'b': - l.emit(TokenCommand) - return lexLabel + } else { + return lexCommand + } + case ':', 'b': + l.emit(TokenCommand) + return lexLabel } if isAlpha(r) { l.emit(TokenCommand) diff --git a/main/main.go b/main/main.go index 3a864ad..3fb1cbf 100644 --- a/main/main.go +++ b/main/main.go @@ -10,6 +10,7 @@ import ( type ProgramState struct { value, xreg, yreg, zreg []walk.Value + start, prevStart, end, nextEnd bool in walk.StredReader out walk.StredWriter program []Command @@ -42,6 +43,10 @@ func run(config config) { break } state.value = []walk.Value{walkItem.Value} + state.start = walkItem.Start + state.prevStart = walkItem.PrevStart + state.end = walkItem.End + state.nextEnd = walkItem.NextEnd state.pc = 0 for state.pc < len(state.program) { state.program[state.pc].exec(&state) diff --git a/main/main_test.go b/main/main_test.go index a7a7795..7aa90aa 100644 --- a/main/main_test.go +++ b/main/main_test.go @@ -5,6 +5,8 @@ import ( "testing" ) +var miscInput string = `{"something":{"nested":"Here is my test value"},"array":["Hello","world","these","are","values"],"people":[{"first_name":"Charlie","last_name":"Johnson","age":22},{"first_name":"Tom","last_name":"Johnson","age":18},{"first_name":"Charlie","last_name":"Chaplin","age":122},{"first_name":"John","last_name":"Johnson","age":48}]}` + func TestMain(t *testing.T) { type test struct { program string @@ -17,9 +19,51 @@ func TestMain(t *testing.T) { { program: `s/#(~(people)~$_@(1$_#(~(first_name)~$_.|(..$_){-0})-|(..$_){-0})-|(..$_){-0})-/p`, quiet: true, - input: `{"something":{"nested":"Here is my test value"},"array":["Hello","world","these","are","values"],"people":[{"first_name":"Charlie","last_name":"Johnson","age":22},{"first_name":"Tom","last_name":"Johnson","age":18},{"first_name":"Charlie","last_name":"Chaplin","age":122},{"first_name":"John","last_name":"Johnson","age":48}]}`, + input: miscInput, + expected: `"Tom"`, + }, + { + program: `s/#("people"$_ @(1 $_#("first_name"$_ .)-)-)-/p`, + quiet: true, + input: miscInput, + expected: `"Tom"`, + }, + { + program: "s/#(\"people\" @(1 #(\"first_name\" (.$a))-)-)-$_ `$a`/p", + quiet: true, + input: miscInput, expected: `"Tom"`, }, + { + program: "s/#(\"people\" @(2 (.$a))-)-$_ `$a`/p", + quiet: true, + input: miscInput, + expected: `{"first_name":"Charlie","last_name":"Chaplin","age":122}`, + }, + { + program: "s/#(\"people\"$_ :(#(\"age\"$_ .)-):)-/p", + quiet: true, + input: miscInput, + expected: `[22,18,122,48]`, + }, + { + program: "aX/#(\"people\" :(#()#):)#$_ `1`/o es/#()#/{ xs/.{-0}+/p }", + quiet: true, + input: miscInput, + expected: "4", + }, + { + program: "s/#(\"people\"$_ .)-/{ s/:():/p as/:(#()#):/{ xdx } s/:(#((\"first_name\" | \"last_name\") .)#)-/X es/@(.#()-)-/{ xs/(#(\"first_name\" \".{-0}$a\")# | #(\"last_name\" \".{-0}$b\")# | .){-0}$_ `\"$a $b\"`/Xxs/-(..)@/p } }", + quiet: true, + input: miscInput, + expected: `["Charlie Johnson","Tom Johnson","Charlie Chaplin","John Johnson"]`, + }, + { + program: "s/#(\"people\"$_ .)-/{ s/:():/p as/:(#()#):/{ xdx } X/:(#((\"first_name\" | \"last_name\") .)#)-/o es/@(.#()-)-/{ xX/(#(\"first_name\" \".{-0}$a\")# | #(\"last_name\" \".{-0}$b\")# | .){-0}$_ `\"$a $b\"`/xs/-(..)@/p } }", + quiet: true, + input: miscInput, + expected: `["Charlie Johnson","Tom Johnson","Charlie Chaplin","John Johnson"]`, + }, } for i, test := range tests { diff --git a/main/parse.go b/main/parse.go index 9c7a437..3e0e80b 100644 --- a/main/parse.go +++ b/main/parse.go @@ -76,17 +76,61 @@ func (p *parser) parseBasicCommand(commands []Command, commandChar rune) []Comma case 'o': return append(commands, NoopCommand{}) case 'x': - return append(commands, SwapXRegCommand{}) + delim := p.peek() + if delim.typ != TokenSubstituteDelimiter { + return append(commands, SwapXRegCommand{}) + } + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return append(commands, SubstituteToXRegCommand {subex}, JumpCommand {len(commands) + 3}) case 'X': - return append(commands, AppendXRegCommand{}) + delim := p.peek() + if delim.typ != TokenSubstituteDelimiter { + return append(commands, AppendXRegCommand{}) + } + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return append(commands, SubstituteAppendXRegCommand {subex}, JumpCommand {len(commands) + 3}) case 'y': - return append(commands, SwapYRegCommand{}) + delim := p.peek() + if delim.typ != TokenSubstituteDelimiter { + return append(commands, SwapYRegCommand{}) + } + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return append(commands, SubstituteToYRegCommand {subex}, JumpCommand {len(commands) + 3}) case 'Y': - return append(commands, AppendYRegCommand{}) + delim := p.peek() + if delim.typ != TokenSubstituteDelimiter { + return append(commands, AppendYRegCommand{}) + } + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return append(commands, SubstituteAppendYRegCommand {subex}, JumpCommand {len(commands) + 3}) case 'z': - return append(commands, SwapZRegCommand{}) + delim := p.peek() + if delim.typ != TokenSubstituteDelimiter { + return append(commands, SwapZRegCommand{}) + } + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return append(commands, SubstituteToZRegCommand {subex}, JumpCommand {len(commands) + 3}) case 'Z': - return append(commands, AppendZRegCommand{}) + delim := p.peek() + if delim.typ != TokenSubstituteDelimiter { + return append(commands, AppendZRegCommand{}) + } + ast := p.parseSubex() + subex := subex.CompileTransducer(ast) + return append(commands, SubstituteAppendZRegCommand {subex}, JumpCommand {len(commands) + 3}) + case 'a': + return append(commands, IsStartCommand{}, JumpCommand {len(commands) + 3}) + case 'A': + return append(commands, IsPrevStartCommand{}, JumpCommand {len(commands) + 3}) + case 'e': + return append(commands, IsEndCommand{}, JumpCommand {len(commands) + 3}) + case 'E': + return append(commands, IsNextEndCommand{}, JumpCommand {len(commands) + 3}) case ':': labelToken := p.next() if labelToken.typ != TokenLabel { diff --git a/subex/main_test.go b/subex/main_test.go index 8e98798..fb6f152 100644 --- a/subex/main_test.go +++ b/subex/main_test.go @@ -405,6 +405,18 @@ func TestSubexMain(t *testing.T) { }, }, }, + { + subex: ".{-0}`\"hello\"`", + input: []walk.Value { + walk.NumberValue(1), + walk.NumberValue(2), + }, + expected: []walk.Value { + walk.NumberValue(1), + walk.NumberValue(2), + walk.StringValue("hello"), + }, + }, } for i, test := range tests { diff --git a/subex/parse.go b/subex/parse.go index d7fe243..619c1c3 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -1,6 +1,7 @@ package subex import ( + "fmt" "main/walk" "strconv" "strings" @@ -115,6 +116,7 @@ func parseScalarLiteral(l RuneReader) (walk.Scalar, bool) { panic("Invalid literal") } default: + fmt.Printf("%c\n", r) panic("Invalid literal") } } @@ -181,7 +183,8 @@ func parseRepeatRange(l RuneReader) (output []ConvexRange) { return output } -func parseValueReplacement(l RuneReader) (output []OutputValueAST) { +func parseValueReplacement(l RuneReader) (output SubexAST) { + output = SubexASTEmpty{} // TODO escaping // TODO add arrays, maps and strings loop: for { @@ -197,37 +200,67 @@ func parseValueReplacement(l RuneReader) (output []OutputValueAST) { if slot == eof { panic("Missing slot character") } - output = append(output, OutputValueLoadAST {slot: slot}) + output = SubexASTConcat { + First: output, + Second: SubexASTOutputValueLoad { + slot: slot, + }, + } + // TODO: destructures + case '"': + output = SubexASTConcat { + First: output, + Second: SubexASTDestructure { + Destructure: NoneStructure, + Structure: StringStructure, + Content: parseRuneReplacement(l, '"'), + }, + } default: l.Rewind() scalar, ok := parseScalarLiteral(l) if !ok { panic("Invalid scalar literal") } - output = append(output, OutputValueLiteralAST {scalar}) + output = SubexASTConcat { + First: output, + Second: SubexASTOutputValueLiteral { + literal: scalar, + }, + } } } return output } -func parseRuneReplacement(l RuneReader) (output []OutputRuneAST) { +func parseRuneReplacement(l RuneReader, end rune) (output SubexAST) { + output = SubexASTEmpty{} // TODO escaping - // TODO add arrays, maps and strings loop: for { r := l.Next() switch r { case eof: panic("Missing closing `") - case '`': + case end: break loop case '$': slot := l.Next() if slot == eof { panic("Missing slot character") } - output = append(output, OutputRuneLoadAST {slot: slot}) + output = SubexASTConcat { + First: output, + Second: SubexASTOutputRuneLoad { + slot: slot, + }, + } default: - output = append(output, OutputRuneLiteralAST {r}) + output = SubexASTConcat { + First: output, + Second: SubexASTOutputRuneLiteral { + literal: r, + }, + } } } return output @@ -394,6 +427,7 @@ func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs Sub } func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType Type) { + start: r := l.Next() switch r { case eof: @@ -467,16 +501,14 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType lhs = SubexASTCopyNumber{} case '`': outType = inType - lhs = SubexASTOutputValues {parseValueReplacement(l)} - // TODO - // case '_': - // lhs = SubexASTCopyStringAtom{} - // case '#': - // lhs = SubexASTCopyString{} - // case ',': - // lhs = SubexASTCopyValue{} - // case '"': - // lhs = SubexASTCopyScalar {walk.NewAtomStringTerminal()} + lhs = parseValueReplacement(l) + case ' ': + if inType == RuneType { + outType = RuneType + lhs = SubexASTCopyRune {' '} + } else { + goto start + } default: outType = inType if inType == RuneType { @@ -533,10 +565,16 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType InnerOutType: outType, } } else { - resolveTypes(inType, ValueType) - lhs = SubexASTStoreValues { - Match: lhs, - Slot: slot, + if inType == ValueType { + lhs = SubexASTStoreValues { + Match: lhs, + Slot: slot, + } + } else { + lhs = SubexASTStoreRunes { + Match: lhs, + Slot: slot, + } } } outType = AnyType diff --git a/subex/subexast.go b/subex/subexast.go index 2685925..d08ddac 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -46,6 +46,25 @@ func (ast SubexASTStoreValues) String() string { return fmt.Sprintf("$%c(%v)", ast.Slot, ast.Match) } +type SubexASTStoreRunes struct { + Match SubexAST + Slot rune +} +func (ast SubexASTStoreRunes) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { + id := slotMap.getRuneId(ast.Slot) + newNext := ast.Match.compileWith(&SubexStoreRunesEndState { + slot: id, + next: next, + }, slotMap, inType, RuneType) + + return &SubexCaptureRunesBeginState { + next: newNext, + } +} +func (ast SubexASTStoreRunes) String() string { + return fmt.Sprintf("(%v)$%c", ast.Match, ast.Slot) +} + // Try to run the first subex, if it fails then backtrack and use the second type SubexASTOr struct { First, Second SubexAST @@ -148,7 +167,7 @@ type SubexASTCopyScalar struct { } func (ast SubexASTCopyScalar) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTCopyScalar") } return &SubexCopyState{ filter: selectScalarFilter {ast.Scalar}, @@ -162,7 +181,7 @@ func (ast SubexASTCopyScalar) String() string { type SubexASTCopyAnyRune struct {} func (ast SubexASTCopyAnyRune) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != RuneType || outType != RuneType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTCopyAnyRune") } return &SubexCopyRuneState { next: next, @@ -170,7 +189,7 @@ func (ast SubexASTCopyAnyRune) compileWith(next SubexState, slotMap *SlotMap, in } } func (ast SubexASTCopyAnyRune) String() string { - return "." + return ".RUNE" } type SubexASTCopyRune struct { @@ -178,19 +197,22 @@ type SubexASTCopyRune struct { } func (ast SubexASTCopyRune) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != RuneType || outType != RuneType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTCopyRune") } return &SubexCopyRuneState { next: next, filter: selectRuneFilter {ast.rune}, } } +func (ast SubexASTCopyRune) String() string { + return string(ast.rune) +} // Read in a single atom that must be a boolean and output it unchanged type SubexASTCopyBool struct {} func (ast SubexASTCopyBool) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTCopyBool") } return &SubexCopyState { next: next, @@ -205,7 +227,7 @@ func (ast SubexASTCopyBool) String() string { type SubexASTCopyNumber struct {} func (ast SubexASTCopyNumber) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTCopyNumber") } return &SubexCopyState { next: next, @@ -220,7 +242,6 @@ func (ast SubexASTCopyNumber) String() string { type SubexASTCopyAnyValue struct {} func (ast SubexASTCopyAnyValue) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - fmt.Printf("%v, %v", inType, outType) panic("Invalid types for SubexASTCopyAnyValue") } return &SubexCopyState { @@ -277,64 +298,56 @@ func (ast SubexASTOutput) String() string { } */ -type OutputValueAST interface { - compile(slotMap *SlotMap) OutputValue +type SubexASTOutputValueLiteral struct { + literal walk.Scalar } - -type OutputValueLoadAST struct { - slot rune -} -func (ast OutputValueLoadAST) compile(slotMap *SlotMap) OutputValue { - return OutputValueLoad { - slotMap.getId(ast.slot), +func (ast SubexASTOutputValueLiteral) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { + if outType != ValueType { + panic("Invalid outType for SubexASTOutputValueLiteral") } -} - -type OutputValueLiteralAST struct { - scalar walk.Scalar -} -func (ast OutputValueLiteralAST) compile(slotMap *SlotMap) OutputValue { - return OutputValueLiteral { - ast.scalar, + return &SubexOutputValueLiteralState { + literal: ast.literal, + next: next, } } -type SubexASTOutputValues struct { - Replacement []OutputValueAST +type SubexASTOutputValueLoad struct { + slot rune } -func (ast SubexASTOutputValues) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { +func (ast SubexASTOutputValueLoad) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if outType != ValueType { - panic("Invalid outType") - } - var content []OutputValue - for _, el := range ast.Replacement { - content = append(content, el.compile(slotMap)) + panic("Invalid outType for SubexASTOutputValueLoad") } - return &SubexOutputValuesState { - content: content, + return &SubexOutputValueLoadState { + slot: slotMap.getId(ast.slot), next: next, } } -type OutputRuneAST interface { - compile(slotMap *SlotMap) OutputRune -} - -type OutputRuneLoadAST struct { - slot rune +type SubexASTOutputRuneLiteral struct { + literal rune } -func (ast OutputRuneLoadAST) compile(slotMap *SlotMap) OutputRune { - return OutputRuneLoad {slotMap.getRuneId(ast.slot)} +func (ast SubexASTOutputRuneLiteral) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { + if outType != RuneType { + panic("Invalid outType for SubexASTOutputRuneLiteral") + } + return &SubexOutputRuneLiteralState { + literal: ast.literal, + next: next, + } } -type OutputRuneLiteralAST struct { - r rune -} -func (ast OutputRuneLiteralAST) compile (slotMap *SlotMap) OutputRune { - return OutputRuneLiteral {ast.r} +type SubexASTOutputRuneLoad struct { + slot rune } - -type SubexASTOutputRunes struct { +func (ast SubexASTOutputRuneLoad) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { + if outType != RuneType { + panic("Invalid outType for SubexASTOutputRuneLoad") + } + return &SubexOutputRuneLoadState { + slot: slotMap.getRuneId(ast.slot), + next: next, + } } // Run each input Atom through a map to produce an output Atom @@ -359,7 +372,7 @@ type SubexASTSum struct { } func (ast SubexASTSum) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTSum") } return &SubexCaptureBeginState { next: ast.Content.compileWith(&SubexArithmeticEndState { @@ -378,7 +391,7 @@ type SubexASTProduct struct { } func (ast SubexASTProduct) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTProduct") } return &SubexCaptureBeginState { next: ast.Content.compileWith(&SubexArithmeticEndState { @@ -398,7 +411,7 @@ type SubexASTNegate struct { } func (ast SubexASTNegate) compileWith(next SubexState, slotMap *SlotMap, inType Type, outType Type) SubexState { if inType != ValueType || outType != ValueType { - panic("Invalid types for SubexASTNot") + panic("Invalid types for SubexASTNegate") } return &SubexCaptureBeginState { next: ast.Content.compileWith(&SubexArithmeticEndState { diff --git a/subex/subexstate.go b/subex/subexstate.go index 4f5dc19..1e1e94e 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -133,6 +133,19 @@ func (state SubexStoreEndState) epsilon(aux auxiliaryState) []SubexBranch { }} } +type SubexStoreRunesEndState struct { + slot int + next SubexState +} +func (state SubexStoreRunesEndState) epsilon(aux auxiliaryState) []SubexBranch { + toStore, aux := aux.popOutputRunes() + aux.store = aux.store.withRunes(state.slot, toStore) + return []SubexBranch {{ + state: state.next, + aux: aux, + }} +} + /* // A part of an output literal, either an Atom or a slot from which to load type OutputContent interface { @@ -211,48 +224,48 @@ func (state SubexOutputState) accepting(aux auxiliaryState) []OutputStack { } */ -type OutputValue interface { - build(store Store) []walk.Value -} - -type OutputValueLoad struct { - slot int +type SubexOutputValueLiteralState struct { + literal walk.Scalar + next SubexState } -func (ov OutputValueLoad) build(store Store) []walk.Value { - return store.values[ov.slot] +func (state SubexOutputValueLiteralState) epsilon(aux auxiliaryState) []SubexBranch { + return []SubexBranch {{ + state: state.next, + aux: aux.topAppend([]walk.Value {state.literal}), + }} } -type OutputValueLiteral struct { - scalar walk.Scalar +type SubexOutputValueLoadState struct { + slot int + next SubexState } -func (ov OutputValueLiteral) build(store Store) []walk.Value { - return []walk.Value{ov.scalar} +func (state SubexOutputValueLoadState) epsilon(aux auxiliaryState) []SubexBranch { + return []SubexBranch {{ + state: state.next, + aux: aux.topAppend(aux.store.values[state.slot]), + }} } -type SubexOutputValuesState struct { - content []OutputValue +type SubexOutputRuneLiteralState struct { + literal rune next SubexState } -func (state SubexOutputValuesState) epsilon(aux auxiliaryState) []SubexBranch { - var content []walk.Value - for _, el := range state.content { - content = append(content, el.build(aux.store)...) - } +func (state SubexOutputRuneLiteralState) epsilon(aux auxiliaryState) []SubexBranch { return []SubexBranch {{ state: state.next, - aux: aux.topAppend(content), + aux: aux.topAppendRune([]rune {state.literal}), }} } -type OutputRune interface { -} - -type OutputRuneLoad struct { +type SubexOutputRuneLoadState struct { slot int + next SubexState } - -type OutputRuneLiteral struct { - r rune +func (state SubexOutputRuneLoadState) epsilon(aux auxiliaryState) []SubexBranch { + return []SubexBranch {{ + state: state.next, + aux: aux.topAppendRune(aux.store.runes[state.slot]), + }} } // A final state, transitions to nothing but is accepting -- cgit v1.2.3