From b48dcb0d37bd3db854927df25e6ff41d07501026 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 19 Apr 2023 13:10:24 +0100 Subject: Combines sum and product into an arithmetic state that contains a function for it's operation Creates arithmetic.go which will house all of these functions --- subex/subexstate.go | 123 +++++----------------------------------------------- 1 file changed, 10 insertions(+), 113 deletions(-) (limited to 'subex/subexstate.go') diff --git a/subex/subexstate.go b/subex/subexstate.go index 6a80eff..cca7a88 100644 --- a/subex/subexstate.go +++ b/subex/subexstate.go @@ -2,8 +2,6 @@ package subex import ( "main/walk" - "strconv" - "errors" ) // A state of execution for the transducer @@ -174,125 +172,24 @@ func (state SubexRangeState) accepting(store Store, outputStack OutputStack) []O return nil } -func sumValues(atoms []walk.Atom) (walk.WalkValue, error) { - allBools := true - var sum float64 = 0 - var any 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 - case walk.ValueBool: - if bool(v) { - sum += 1 - any = true - } - case walk.ValueNumber: - allBools = false - sum += float64(v) - case walk.ValueString: - allBools = false - num, err := strconv.ParseFloat(string(v), 64) - if err == nil { - sum += 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(any), nil - } else { - return walk.ValueNumber(sum), 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 -} -func (state SubexSumEndState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { - toSum, newStack := outputStack.pop() - sum, err := sumValues(toSum) - if err != nil { - return nil - } - return state.next.eat(store, topAppend(newStack, []walk.Atom{sum}), char) -} -func (state SubexSumEndState) accepting(store Store, outputStack OutputStack) []OutputStack { - toSum, newStack := outputStack.pop() - sum, err := sumValues(toSum) - if err != nil { - return nil - } - 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 { +type SubexArithmeticEndState struct { next SubexState + calculate func([]walk.Atom) ([]walk.Atom, error) } -func (state SubexProductEndState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { - toMultiply, newStack := outputStack.pop() - product, err := multiplyValues(toMultiply) +func (state SubexArithmeticEndState) eat(store Store, outputStack OutputStack, char walk.Atom) []SubexBranch { + toCompute, newStack := outputStack.pop() + result, err := state.calculate(toCompute) if err != nil { return nil } - return state.next.eat(store, topAppend(newStack, []walk.Atom{product}), char) + return state.next.eat(store, topAppend(newStack, result), char) } -func (state SubexProductEndState) accepting(store Store, outputStack OutputStack) []OutputStack { - toMultiply, newStack := outputStack.pop() - product, err := multiplyValues(toMultiply) +func (state SubexArithmeticEndState) accepting(store Store, outputStack OutputStack) []OutputStack { + toCompute, newStack := outputStack.pop() + result, err := state.calculate(toCompute) if err != nil { return nil } - return state.next.accepting(store, topAppend(newStack, []walk.Atom{product})) + return state.next.accepting(store, topAppend(newStack, result)) } -- cgit v1.2.3