diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2024-04-27 09:29:46 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2024-04-27 09:29:46 +0100 | 
| commit | 8ac12c99fc59b01da40c2939cb4a7b72d32d2153 (patch) | |
| tree | a60859e7614f35a8158fdd7614b2e3c196460b61 | |
| parent | 7084f5e1ceb61eab199512410048ad53e3ea08d7 (diff) | |
| download | stred-go-8ac12c99fc59b01da40c2939cb4a7b72d32d2153.tar | |
Add iterating destructures
| -rw-r--r-- | main/main_test.go | 7 | ||||
| -rw-r--r-- | subex/parse.go | 61 | ||||
| -rw-r--r-- | subex/subexstate.go | 78 | 
3 files changed, 37 insertions, 109 deletions
| diff --git a/main/main_test.go b/main/main_test.go index b745202..8512b62 100644 --- a/main/main_test.go +++ b/main/main_test.go @@ -87,6 +87,13 @@ func TestMain(t *testing.T) {  			expected: `["Charlie Johnson","Tom Johnson","Charlie Chaplin","John Johnson"]`,  		},  		{ +			name: "Get full names with merge full command", +			program: "s/#(\"people\"$_ :(): )-/p M/#( \"people\" @( . #()# )@ )#/{ s/#( \"people\"$_ @( . #[ \"first_name\" \".{-0}$a\" | \"last_name\" \".{-0}$b\" | .. $_]- `\"$a $b\"` )@ )-/p }", +			quiet: true, +			input: miscInput, +			expected: `["Charlie Johnson","Tom Johnson","Charlie Chaplin","John Johnson"]`, +		}, +		{  			name: "Verbose concat array values",  			program: "as/#( \"array\"$_ :(): )-/{ :s N/#( .$_ . )-/{ es/.{-0}:():/be mbs } :em s/:( -( ~(.{-0}` `)-{-0} ~(.{-0})- )~ )-/p }",  			quiet: true, diff --git a/subex/parse.go b/subex/parse.go index b6bf2f6..9a7a75c 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -55,6 +55,12 @@ func (s Structure) String() string {  	}  } +type DestructureMethod int +const ( +	Normal DestructureMethod = iota +	Iterate +) +  type RuneReader interface {  	Next() rune  	Rewind() @@ -361,8 +367,14 @@ func parseRuneReplacement(l RuneReader, end rune) (output SubexAST) {  // }  func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs SubexAST, outType Type) { -	if !accept(l, "(") { -		panic("Missing ( after destructure start") +	var method rune +	switch l.Next() { +	case '(': +		method = ')' +	case '[': +		method = ']' +	default: +		panic("Missing ( or [ after destructure start")  	}  	var innerInType Type @@ -390,8 +402,22 @@ func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs Sub  	resolveTypes(inType, expectedInType)  	lhs, innerOutType := parseSubex(l, 0, innerInType) -	if !accept(l, ")") { -		panic("Missing matching )") +	if !accept(l, string(method)) { +		panic("Missing matching ) or ]") +	} + +	switch method { +	case ')': +	case ']': +		lhs = SubexASTRepeat { +			Content: lhs, +			Acceptable: []ConvexRange{{ +				Start: -1, +				End: 0, +			}}, +		} +	default: +		panic("Invalid method")  	}  	var structure Structure @@ -487,20 +513,6 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType  		case ')', ']', '|', ';', '{', '+', '*', '/', '!', '=', '$':  			l.Rewind()  			return SubexASTEmpty{}, inType -		// case '=': -		// 	replacement := parseReplacement(l) -		// 	lhs = SubexASTOutput{replacement} -		// case '^': -		// 	replacement := parseReplacement(l) -		// 	replacement = append( -		// 		[]OutputContentAST{OutputValueLiteralAST {walk.NewAtomStringTerminal()}}, -		// 		replacement... -		// 	) -		// 	replacement = append( -		// 		replacement, -		// 		OutputValueLiteralAST {walk.NewAtomStringTerminal()}, -		// 	) -		// 	lhs = SubexASTOutput {replacement}  		case '.':  			outType = inType  			if inType == RuneType { @@ -569,14 +581,10 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType  				lhs = SubexASTProduct {lhs}  				resolveTypes(inType, ValueType)  				outType = resolveTypes(outType, ValueType) -			// case r == '/' && minPower <= 4: -				// lhs = SubexASTReciprocal {lhs}  			case r == '!' && minPower <= 4:  				lhs = SubexASTNot {lhs}  				resolveTypes(inType, ValueType)  				outType = resolveTypes(outType, ValueType) -			// case r == '=' && minPower <= 4: -				// lhs = SubexASTEqual {lhs}  			case r == '$' && minPower <= 4:  				slot := l.Next()  				if slot == eof { @@ -608,15 +616,6 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType  					panic("Missing subex after |")  				}  				lhs = SubexASTOr{lhs, rhs} -			/*case r == ';' && minPower <= 10: -				rhs := parseSubex(l, 11, inType, outType) -				if rhs == nil { -					panic("Missing subex after ;") -				} -				lhs = SubexASTJoin { -					Content: lhs, -					Delimiter: rhs, -				}*/  			default:  				l.Rewind()  				break loop diff --git a/subex/subexstate.go b/subex/subexstate.go index 1e1e94e..8f27a10 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -146,84 +146,6 @@ func (state SubexStoreRunesEndState) epsilon(aux auxiliaryState) []SubexBranch {  	}}  } -/* -// A part of an output literal, either an Atom or a slot from which to load -type OutputContent interface { -	// Given the current store, return the ValueList produced by the TransducerOutput -	buildValues(Store) walk.ValueList -	// Given the current store, return the RuneList produced by the TransducerOutput -	buildRunes(Store) walk.RuneList -} - -// An OutputContent which is just a Value literal -type OutputValueLiteral struct { -	value walk.Value -} -func (replacement OutputValueLiteral) buildValues(store Store) walk.ValueList { -	return walk.ValueList{replacement.value} -} -func (replacement OutputValueLiteral) buildRunes(store Store) walk.RuneList { -	// TODO: serialise to JSON -	panic("Unimplemented!") -} - -// An OutputContent which is just a rune literal -type OutputRuneLiteral struct { -	rune walk.StringRuneAtom -} -func (replacement OutputRuneLiteral) buildValues(store Store) walk.ValueList { -	// TODO: Try to deserialise -	panic("Unimplemented!") -} -func (replacement OutputRuneLiteral) buildRunes(store Store) walk.RuneList { -	return walk.RuneList {replacement.rune} -} - -// An OutputContent which is a slot that is loaded from -type OutputLoad struct { -	slot int -} -func (replacement OutputLoad) buildValues(store Store) walk.ValueList { -	values, isValues := store[replacement.slot].(walk.ValueList) -	if !isValues { -		panic("Tried to output non-values list") -	} -	return values -} -func (replacement OutputLoad) buildRunes(store Store) walk.RuneList { -	runes, isRunes := store[replacement.slot].(walk.RuneList) -	if !isRunes { -		panic("Tried to output non-runes as runes") -	} -	return runes -} - -// Don't read in anything, just output the series of data and slots specified -type SubexOutputState struct { -	content []OutputContent -	next SubexState -} -// Given a store, return what is outputted by an epsilon transition from this state -// TODO: separate into buildValues and buildRunes -func (state SubexOutputState) build(store Store) walk.ValueList { -	var result walk.ValueList -	for _, part := range state.content { -		result = append(result, part.buildValues(store)...) -	} -	return result -} -func (state SubexOutputState) eat(aux auxiliaryState, char walk.Value) []SubexBranch { -	content := state.build(aux.store) -	nextStates := state.next.eat(aux.topAppend(content), char) -	return nextStates -} -func (state SubexOutputState) accepting(aux auxiliaryState) []OutputStack { -	content := state.build(aux.store) -	outputStacks := state.next.accepting(aux.topAppend(content)) -	return outputStacks -} -*/ -  type SubexOutputValueLiteralState struct {  	literal walk.Scalar  	next SubexState | 
