diff options
| -rw-r--r-- | main/command.go | 144 | ||||
| -rw-r--r-- | main/lex.go | 35 | ||||
| -rw-r--r-- | main/main.go | 5 | ||||
| -rw-r--r-- | main/main_test.go | 46 | ||||
| -rw-r--r-- | main/parse.go | 56 | ||||
| -rw-r--r-- | subex/main_test.go | 12 | ||||
| -rw-r--r-- | subex/parse.go | 82 | ||||
| -rw-r--r-- | subex/subexast.go | 117 | ||||
| -rw-r--r-- | 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 | 
