diff options
| -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  } | 
