From 0072e6aad2f9969348d5315a692f1f5e2ebc075d Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 19 Apr 2023 12:59:22 +0100 Subject: Adds product/and operator --- subex/subexstate.go | 87 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 18 deletions(-) (limited to 'subex/subexstate.go') diff --git a/subex/subexstate.go b/subex/subexstate.go index 0a4f1bb..6a80eff 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -26,15 +26,15 @@ func (state SubexGroupState) accepting(store Store, outputStack OutputStack) []O return append(state.first.accepting(store, outputStack), state.second.accepting(store, outputStack)...) } -// Push an empty value onto the OutputStack and epsilon transition to next -// This value will be added to until SubexStoreEndState is reached when it will be stored -type SubexStoreBeginState struct { +// Just pushes to the OutputStack and hands over to the next state +// Used to capture the output of the state being handed over to +type SubexCaptureBeginState struct { next SubexState } -func (state SubexStoreBeginState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { +func (state SubexCaptureBeginState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { return state.next.eat(store, outputStack.push(nil), char) } -func (state SubexStoreBeginState) accepting(store Store, outputStack OutputStack) []OutputStack { +func (state SubexCaptureBeginState) accepting(store Store, outputStack OutputStack) []OutputStack { return state.next.accepting(store, outputStack.push(nil)) } @@ -187,7 +187,7 @@ func sumValues(atoms []walk.Atom) (walk.WalkValue, error) { case walk.ValueNull: allBools = false case walk.ValueBool: - if (bool(v)) { + if bool(v) { sum += 1 any = true } @@ -213,19 +213,8 @@ func sumValues(atoms []walk.Atom) (walk.WalkValue, error) { } } -// At the start of a sum, just pushes to the OutputStack allowing the end to capture what was output in the middle -// Tries to cast values to numbers to sum them and rejects if values are not castable -type SubexSumBeginState struct { - next SubexState -} -func (state SubexSumBeginState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { - return state.next.eat(store, outputStack.push(nil), char) -} -func (state SubexSumBeginState) accepting(store Store, outputStack OutputStack) []OutputStack { - return state.next.accepting(store, outputStack.push(nil)) -} - // At the end of a sum, pops what has been output since the start, sums and outputs it +// If all values are booleans does OR, if not tries to cast values to numbers to sum them and rejects if values are not castable type SubexSumEndState struct { next SubexState } @@ -245,3 +234,65 @@ func (state SubexSumEndState) accepting(store Store, outputStack OutputStack) [] } return state.next.accepting(store, topAppend(newStack, []walk.Atom{sum})) } + +// Compounds atoms into values, if all values are booleans, does AND, if not, tries to cast to numbers and multiply +func multiplyValues(atoms []walk.Atom) (walk.WalkValue, error) { + allBools := true + var product float64 = 1 + var all bool = false + values, err := walk.MemoryCompound(atoms) + if err != nil { + return walk.ValueNull{}, err + } + for _, value := range values { + switch v := value.(type) { + case walk.ValueNull: + allBools = false + product *= 0 + case walk.ValueBool: + if !bool(v) { + product *= 0 + all = false + } + case walk.ValueNumber: + allBools = false + product *= float64(v) + case walk.ValueString: + allBools = false + num, err := strconv.ParseFloat(string(v), 64) + if err == nil { + product *= num + } else { + return walk.ValueNull{}, errors.New("Tried to sum non-castable string") + } + default: + return walk.ValueNull{}, errors.New("Tried to sum non-number") + } + } + if allBools { + return walk.ValueBool(all), nil + } else { + return walk.ValueNumber(product), nil + } +} + +// Does AND or product +type SubexProductEndState struct { + next SubexState +} +func (state SubexProductEndState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { + toMultiply, newStack := outputStack.pop() + product, err := multiplyValues(toMultiply) + if err != nil { + return nil + } + return state.next.eat(store, topAppend(newStack, []walk.Atom{product}), char) +} +func (state SubexProductEndState) accepting(store Store, outputStack OutputStack) []OutputStack { + toMultiply, newStack := outputStack.pop() + product, err := multiplyValues(toMultiply) + if err != nil { + return nil + } + return state.next.accepting(store, topAppend(newStack, []walk.Atom{product})) +} -- cgit v1.2.3