diff options
author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-18 15:07:52 +0100 |
---|---|---|
committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-18 15:07:52 +0100 |
commit | ffd1b73b4f3294d9f3aa2ed600da3ba053aeb47c (patch) | |
tree | ac3075e8ea26190838e0e6df3f5e6af65909ca51 /subex/subexstate.go | |
parent | febdc5dcd5b25a090b90c920914775265da98d39 (diff) | |
download | stred-go-ffd1b73b4f3294d9f3aa2ed600da3ba053aeb47c.tar |
Adds the sum operator
Currently doesn't parse strings as each atom is considered independantly. Instead individual characters in strings can be cast
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 +} |