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/arithmetic.go | 87 +++++++++++++++++++++++++++++++++++++ subex/subexast.go | 6 ++- subex/subexstate.go | 123 +++++----------------------------------------------- 3 files changed, 101 insertions(+), 115 deletions(-) create mode 100644 subex/arithmetic.go diff --git a/subex/arithmetic.go b/subex/arithmetic.go new file mode 100644 index 0000000..7200ac7 --- /dev/null +++ b/subex/arithmetic.go @@ -0,0 +1,87 @@ +package subex + +import ( + "main/walk" + "errors" + "strconv" +) + +func sumValues(atoms []walk.Atom) ([]walk.Atom, error) { + allBools := true + var sum float64 = 0 + var any bool = false + values, err := walk.MemoryCompound(atoms) + if err != nil { + return nil, 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 nil, errors.New("Tried to sum non-castable string") + } + default: + return nil, errors.New("Tried to sum non-number") + } + } + if allBools { + return []walk.Atom{walk.ValueBool(any)}, nil + } else { + return []walk.Atom{walk.ValueNumber(sum)}, nil + } +} + +// 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.Atom, error) { + allBools := true + var product float64 = 1 + var all bool = false + values, err := walk.MemoryCompound(atoms) + if err != nil { + return nil, 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 nil, errors.New("Tried to sum non-castable string") + } + default: + return nil, errors.New("Tried to sum non-number") + } + } + if allBools { + return []walk.Atom{walk.ValueBool(all)}, nil + } else { + return []walk.Atom{walk.ValueNumber(product)}, nil + } +} diff --git a/subex/subexast.go b/subex/subexast.go index 431ea26..abf0ca6 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -190,8 +190,9 @@ type SubexASTSum struct { } func (ast SubexASTSum) compileWith(next SubexState) SubexState { return &SubexCaptureBeginState { - next: ast.content.compileWith(&SubexSumEndState { + next: ast.content.compileWith(&SubexArithmeticEndState { next: next, + calculate: sumValues, }), } } @@ -202,8 +203,9 @@ type SubexASTProduct struct { } func (ast SubexASTProduct) compileWith(next SubexState) SubexState { return &SubexCaptureBeginState { - next: ast.content.compileWith(&SubexProductEndState { + next: ast.content.compileWith(&SubexArithmeticEndState { next: next, + calculate: multiplyValues, }), } } 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