diff options
author | Charlie Stanton <charlie@shtanton.xyz> | 2024-03-31 21:23:17 +0100 |
---|---|---|
committer | Charlie Stanton <charlie@shtanton.xyz> | 2024-03-31 21:23:17 +0100 |
commit | 81925b6ad5212512d27365b8224b76095191431f (patch) | |
tree | f625a8eddb556a58c45c7e16a205df1ed6b92d3a | |
parent | 256450cc3dcdd9a9b92a33642739f7143526e9b9 (diff) | |
download | stred-go-81925b6ad5212512d27365b8224b76095191431f.tar |
Add " shorthand for string destructure
-rw-r--r-- | subex/main.go | 29 | ||||
-rw-r--r-- | subex/main_test.go | 77 | ||||
-rw-r--r-- | subex/parse.go | 20 | ||||
-rw-r--r-- | subex/subexstate.go | 5 |
4 files changed, 114 insertions, 17 deletions
diff --git a/subex/main.go b/subex/main.go index 982b585..32a5cf3 100644 --- a/subex/main.go +++ b/subex/main.go @@ -150,8 +150,7 @@ type auxiliaryState struct { outputStack OutputStack // How deeply nested the current execution is inside of the overall value // i.e. starts at zero, is incremented to one when entering an array - nestingLen int - nestingValue bool + nesting []bool } func (aux auxiliaryState) cloneStore() auxiliaryState { @@ -227,8 +226,15 @@ func (pair SubexEatBranch) accepting() []OutputStack { } func equalStates(left SubexEatBranch, right SubexEatBranch) bool { - // Only care about if they are the same pointer - return left.state == right.state && left.aux.nestingLen == right.aux.nestingLen && left.aux.nestingValue == right.aux.nestingValue + if left.state != right.state || len(left.aux.nesting) != len(right.aux.nesting) { + return false + } + for i, l := range left.aux.nesting { + if l != right.aux.nesting[i] { + return false + } + } + return true } // If two branches have the same state, only the first has a chance of being successful @@ -254,9 +260,6 @@ func addStates(curStates []SubexEatBranch, newStates []SubexBranch, nesting []bo case SubexEpsilonState: curStates = addStates(curStates, s.epsilon(state.aux), nesting) case SubexEatState: - if state.aux.nestingLen < len(nesting) && state.aux.nestingLen > 0 { - state.aux.nestingValue = nesting[state.aux.nestingLen - 1] - } curStates = append(curStates, SubexEatBranch{ state: s, aux: state.aux, @@ -270,12 +273,13 @@ func processInput(states []SubexEatBranch, input walk.Edible, nesting []bool) [] newStates := make([]SubexEatBranch, 0, 2) for _, state := range states { - if state.aux.nestingLen > len(nesting) { + if len(state.aux.nesting) > len(nesting) { continue } - if (state.aux.nestingLen == len(nesting) && - (len(nesting) == 0 || state.aux.nestingValue || nesting[len(nesting) - 1])) { + if (len(state.aux.nesting) == len(nesting) && + (len(state.aux.nesting) == 0 || len(nesting) == 0 || + state.aux.nesting[len(nesting) - 1] || nesting[len(nesting) - 1])) { newStates = addStates(newStates, state.eat(input), nesting) } else { newStates = append(newStates, state) @@ -320,8 +324,7 @@ func RunTransducer(transducer Transducer, input []walk.Value) (output []walk.Val values: make([][]walk.Value, transducer.storeSize.values), runes: make([][]rune, transducer.storeSize.runes), }, - nestingLen: 0, - nestingValue: true, + nesting: nil, }, }}, nil) @@ -334,7 +337,7 @@ func RunTransducer(transducer Transducer, input []walk.Value) (output []walk.Val } for _, state := range states { - if state.aux.nestingLen > 0 { + if len(state.aux.nesting) > 0 { continue } acceptingStacks := state.accepting() diff --git a/subex/main_test.go b/subex/main_test.go index 9c1819a..8e98798 100644 --- a/subex/main_test.go +++ b/subex/main_test.go @@ -79,6 +79,21 @@ func TestSubexMain(t *testing.T) { }, }, { + subex: `#(".".{-0})-`, + input: []walk.Value { + walk.MapValue { + { + Key: "a", + Value: walk.NullValue{}, + }, + }, + }, + expected: []walk.Value { + walk.StringValue("a"), + walk.NullValue{}, + }, + }, + { subex: "@(..$a`$a$a`{-0})@", input: []walk.Value { walk.ArrayValue { @@ -328,6 +343,68 @@ func TestSubexMain(t *testing.T) { }, }, }, + { + subex: ":(.`null`{-0})#", + input: []walk.Value { + walk.ArrayValue { + { + Index: 0, + Value: walk.StringValue("a"), + }, + { + Index: 1, + Value: walk.StringValue("b"), + }, + { + Index: 2, + Value: walk.StringValue("c"), + }, + }, + }, + expected: []walk.Value { + walk.MapValue { + { + Key: "a", + Value: walk.NullValue{}, + }, + { + Key: "b", + Value: walk.NullValue{}, + }, + { + Key: "c", + Value: walk.NullValue{}, + }, + }, + }, + }, + { + subex: `#(".$_(.{-0})".{-0})#`, + input: []walk.Value { + walk.MapValue { + { + Key: "hello", + Value: walk.NullValue{}, + }, + { + Key: "world", + Value: walk.NullValue{}, + }, + }, + }, + expected: []walk.Value { + walk.MapValue { + { + Key: "ello", + Value: walk.NullValue{}, + }, + { + Key: "orld", + Value: walk.NullValue{}, + }, + }, + }, + }, } for i, test := range tests { diff --git a/subex/parse.go b/subex/parse.go index 1e17bb3..d7fe243 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -413,11 +413,29 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType lhs, outType = parseDestructure(l, ArrayValuesStructure, inType) case '#': lhs, outType = parseDestructure(l, MapStructure, inType) + case '"': + if inType == ValueType { + var innerOutType Type + lhs, innerOutType = parseSubex(l, 0, RuneType) + if !accept(l, "\"") { + panic("Missing matching \"") + } + resolveTypes(innerOutType, RuneType) + lhs = SubexASTDestructure { + Destructure: StringStructure, + Structure: StringStructure, + Content: lhs, + } + outType = ValueType + } else { + l.Rewind() + return SubexASTEmpty{}, inType + } // TODO // case '[': // rangeParts := parseRangeSubex(l) // lhs = SubexASTRange {rangeParts} - case ')', ']', '"', '|', ';', '{', '+', '*', '/', '!', '=', '$': + case ')', ']', '|', ';', '{', '+', '*', '/', '!', '=', '$': l.Rewind() return SubexASTEmpty{}, inType // case '=': diff --git a/subex/subexstate.go b/subex/subexstate.go index 26d7347..4f5dc19 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -424,8 +424,7 @@ type SubexIncrementNestState struct { next SubexState } func (state SubexIncrementNestState) epsilon(aux auxiliaryState) []SubexBranch { - aux.nestingLen += 1 - aux.nestingValue = state.keys + aux.nesting = append(aux.nesting, state.keys) return []SubexBranch {{ state: state.next, aux: aux, @@ -439,7 +438,7 @@ type SubexDecrementNestState struct { next SubexState } func (state SubexDecrementNestState) epsilon(aux auxiliaryState) []SubexBranch { - aux.nestingLen -= 1 + aux.nesting = aux.nesting[:len(aux.nesting) - 1] // aux.nestingValue will be set in addStates return []SubexBranch {{ state: state.next, |