<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2024-03-31 21:23:17 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2024-03-31 21:23:17 +0100
commit81925b6ad5212512d27365b8224b76095191431f (patch)
treef625a8eddb556a58c45c7e16a205df1ed6b92d3a /subex
parent256450cc3dcdd9a9b92a33642739f7143526e9b9 (diff)
downloadstred-go-81925b6ad5212512d27365b8224b76095191431f.tar
Add " shorthand for string destructure
Diffstat (limited to 'subex')
-rw-r--r--subex/main.go29
-rw-r--r--subex/main_test.go77
-rw-r--r--subex/parse.go20
-rw-r--r--subex/subexstate.go5
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,