diff options
author | Charlie Stanton <charlie@shtanton.xyz> | 2024-03-30 21:09:32 +0000 |
---|---|---|
committer | Charlie Stanton <charlie@shtanton.xyz> | 2024-03-30 21:09:32 +0000 |
commit | fd79fd18c6c32884e757e91b8629c87af4cbf34e (patch) | |
tree | 50e6b49c64b1c6cf230c80ce83a925ec98fd2387 | |
parent | 976d96af62945178f3a3ab572620026df75003cf (diff) | |
download | stred-go-fd79fd18c6c32884e757e91b8629c87af4cbf34e.tar |
Add map destructure
-rw-r--r-- | subex/filter.go | 6 | ||||
-rw-r--r-- | subex/main_test.go | 35 | ||||
-rw-r--r-- | subex/parse.go | 13 | ||||
-rw-r--r-- | subex/subexast.go | 29 | ||||
-rw-r--r-- | subex/subexstate.go | 25 |
5 files changed, 108 insertions, 0 deletions
diff --git a/subex/filter.go b/subex/filter.go index dce0f0e..ae4b8ab 100644 --- a/subex/filter.go +++ b/subex/filter.go @@ -38,6 +38,12 @@ func (_ anyArrayFilter) valueFilter(value walk.Value) bool { return isArray } +type anyMapFilter struct {} +func (_ anyMapFilter) valueFilter(value walk.Value) bool { + _, isMap := value.(walk.MapValue) + return isMap +} + type anyStringFilter struct {} func (_ anyStringFilter) valueFilter(value walk.Value) bool { _, isString := value.(walk.StringValue) diff --git a/subex/main_test.go b/subex/main_test.go index 673b807..9c1819a 100644 --- a/subex/main_test.go +++ b/subex/main_test.go @@ -293,6 +293,41 @@ func TestSubexMain(t *testing.T) { }, }, }, + { + subex: "#(.(.$_){-0}):", + input: []walk.Value { + walk.MapValue { + { + Key: "a", + Value: walk.NullValue{}, + }, + { + Key: "b", + Value: walk.NumberValue(4), + }, + { + Key: "c", + Value: walk.StringValue("hello"), + }, + }, + }, + expected: []walk.Value { + walk.ArrayValue { + { + Index: 0, + Value: walk.StringValue("a"), + }, + { + Index: 0, + Value: walk.StringValue("b"), + }, + { + Index: 0, + Value: walk.StringValue("c"), + }, + }, + }, + }, } for i, test := range tests { diff --git a/subex/parse.go b/subex/parse.go index 98821fd..1e17bb3 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -35,6 +35,7 @@ const ( StringStructure ArrayStructure ArrayValuesStructure + MapStructure ) func (s Structure) String() string { switch s { @@ -46,6 +47,8 @@ func (s Structure) String() string { return "@" case ArrayValuesStructure: return ":" + case MapStructure: + return "#" default: panic("Invalid structure") } @@ -329,6 +332,9 @@ func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs Sub case ArrayValuesStructure: innerInType = ValueType expectedInType = ValueType + case MapStructure: + innerInType = ValueType + expectedInType = ValueType default: panic("Invalid structure") } @@ -356,6 +362,9 @@ func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs Sub case ':': structure = ArrayValuesStructure expectedInnerOutType = ValueType + case '#': + structure = MapStructure + expectedInnerOutType = ValueType default: panic("Missing matching destructure") } @@ -371,6 +380,8 @@ func parseDestructure(l RuneReader, destructure Structure, inType Type) (lhs Sub outType = ValueType case ArrayValuesStructure: outType = ValueType + case MapStructure: + outType = ValueType } lhs = SubexASTDestructure { @@ -400,6 +411,8 @@ func parseSubex(l RuneReader, minPower int, inType Type) (lhs SubexAST, outType lhs, outType = parseDestructure(l, ArrayStructure, inType) case ':': lhs, outType = parseDestructure(l, ArrayValuesStructure, inType) + case '#': + lhs, outType = parseDestructure(l, MapStructure, inType) // TODO // case '[': // rangeParts := parseRangeSubex(l) diff --git a/subex/subexast.go b/subex/subexast.go index a2c3675..2685925 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -489,6 +489,11 @@ func (ast SubexASTDestructure) compileWith(next SubexState, slotMap *SlotMap, in construct = &SubexConstructArrayValuesState { next: next, } + case MapStructure: + innerOutType = ValueType + construct = &SubexConstructMapState { + next: next, + } default: panic("Invalid ast structure") } @@ -523,6 +528,14 @@ func (ast SubexASTDestructure) compileWith(next SubexState, slotMap *SlotMap, in next: construct, }, } + case MapStructure: + innerInType = ValueType + destructFooter = &SubexDiscardTerminalState { + terminal: walk.MapEnd, + next: &SubexDecrementNestState { + next: construct, + }, + } default: panic("Invalid ast destructure") } @@ -550,6 +563,10 @@ func (ast SubexASTDestructure) compileWith(next SubexState, slotMap *SlotMap, in beginConstruct = &SubexCaptureBeginState { next: inner, } + case MapStructure: + beginConstruct = &SubexCaptureBeginState { + next: inner, + } default: panic("Invalid ast structure") } @@ -593,6 +610,18 @@ func (ast SubexASTDestructure) compileWith(next SubexState, slotMap *SlotMap, in }, }, } + case MapStructure: + return &SubexCaptureBeginState { + next: &SubexCopyState { + filter: anyMapFilter{}, + next: &SubexDiscardState { + next: &SubexIncrementNestState { + keys: true, + next: beginConstruct, + }, + }, + }, + } default: panic("Invalid destructure in ast") } diff --git a/subex/subexstate.go b/subex/subexstate.go index 45b5d00..26d7347 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -373,6 +373,31 @@ func (state SubexConstructArrayValuesState) epsilon(aux auxiliaryState) []SubexB }} } +type SubexConstructMapState struct { + next SubexState +} +func (state SubexConstructMapState) epsilon(aux auxiliaryState) []SubexBranch { + values, aux := aux.popOutput() + var m walk.MapValue + if len(values) % 2 != 0 { + panic("Tried to construct array with odd length input") + } + for i := 0; i < len(values); i += 2 { + key, isNum := values[i].(walk.StringValue) + if !isNum { + panic("Tried to construct array with non-numeric index") + } + m = append(m, walk.MapElement { + Key: string(key), + Value: values[i + 1], + }) + } + return []SubexBranch {{ + state: state.next, + aux: aux.topAppend([]walk.Value {m}), + }} +} + type SubexConstructStringState struct { next SubexState } |