diff options
Diffstat (limited to 'subex/subexstate.go')
-rw-r--r-- | subex/subexstate.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/subex/subexstate.go b/subex/subexstate.go index 3c554a2..cbcd210 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -188,3 +188,65 @@ func (state SubexRangeState) eat(store Store, char walk.Atom) []SubexBranch { func (state SubexRangeState) accepting(store Store) [][]walk.Atom { return nil } + +func sumValues(values []walk.Atom) walk.ValueNumber { + var sum float64 = 0 + for _, value := range values { + switch v := value.(type) { + case walk.ValueBool: + if (bool(v)) { + sum += 1 + } + case walk.ValueNumber: + sum += float64(v) + case rune: + if '0' <= v && v <= '9' { + sum += float64(v - '0') + } + default: + } + } + return walk.ValueNumber(sum) +} + +// Run the inputState machine and sum any values output, output the sum +// Cast non numbers into numbers, ignore anything uncastable +type SubexSumState struct { + inputState SubexState + next SubexState + sum walk.ValueNumber +} +func (state SubexSumState) eat(store Store, char walk.Atom) (nextStates []SubexBranch) { + acceptedOutputs := state.inputState.accepting(store) + for _, acceptedOutput := range acceptedOutputs { + nextNextStates := state.next.eat(store.clone(), char) + for i := range nextNextStates { + nextNextStates[i].output = walk.ConcatData([]walk.Atom{sumValues(append(acceptedOutput, state.sum))}, nextNextStates[i].output) + } + nextStates = append(nextStates, nextNextStates...) + } + nextInputStates := state.inputState.eat(store.clone(), char) + for _, inputState := range nextInputStates { + nextStates = append(nextStates, SubexBranch { + state: &SubexSumState { + inputState: inputState.state, + next: state.next, + sum: sumValues(append(inputState.output, state.sum)), + }, + output: nil, + store: inputState.store, + }) + } + return nextStates +} +func (state SubexSumState) accepting(store Store) (outputs [][]walk.Atom) { + acceptedOutputs := state.inputState.accepting(store) + for _, acceptedOutput := range acceptedOutputs { + nextOutputs := state.next.accepting(store.clone()) + for i := range nextOutputs { + nextOutputs[i] = walk.ConcatData([]walk.Atom{sumValues(append(acceptedOutput, state.sum))}, nextOutputs[i]) + } + outputs = append(outputs, nextOutputs...) + } + return outputs +} |