<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-04-19 13:10:24 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-04-19 13:10:24 +0100
commitb48dcb0d37bd3db854927df25e6ff41d07501026 (patch)
treeae2059a0f9a66d48c9bdf3cf41c367e5c0848ad6 /subex
parent0072e6aad2f9969348d5315a692f1f5e2ebc075d (diff)
downloadstred-go-b48dcb0d37bd3db854927df25e6ff41d07501026.tar
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
Diffstat (limited to 'subex')
-rw-r--r--subex/arithmetic.go87
-rw-r--r--subex/subexast.go6
-rw-r--r--subex/subexstate.go123
3 files changed, 101 insertions, 115 deletions
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))
}