<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/arithmetic.go
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-07-19 11:57:59 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-07-19 11:57:59 +0100
commit8cf10efe3b5a1bcc70bc6e5590ee63fd5eb00c5b (patch)
tree7a16883c17c2bdcc49b2f9d4f333dfc76c66248f /subex/arithmetic.go
parent3c34366bdd5d817a184d6b1c901d03a16b6faa4b (diff)
downloadstred-go-8cf10efe3b5a1bcc70bc6e5590ee63fd5eb00c5b.tar
Huge refactor to a more value based system, doing away with terminals. Also introduces unit testing
Diffstat (limited to 'subex/arithmetic.go')
-rw-r--r--subex/arithmetic.go114
1 files changed, 47 insertions, 67 deletions
diff --git a/subex/arithmetic.go b/subex/arithmetic.go
index 1ebd1a6..9e5e530 100644
--- a/subex/arithmetic.go
+++ b/subex/arithmetic.go
@@ -6,27 +6,23 @@ import (
"strconv"
)
-func sumValues(atoms []walk.Atom) ([]walk.Atom, error) {
+func sumValues(values walk.ValueList) (walk.ValueList, error) {
allBools := true
var sum float64 = 0
var any bool = false
- values, err := walk.Compound(atoms)
- if err != nil {
- return nil, err
- }
for _, value := range values {
switch v := value.(type) {
- case walk.ValueNull:
+ case walk.NullScalar:
allBools = false
- case walk.ValueBool:
- if bool(v) {
+ case walk.BoolScalar:
+ if v {
sum += 1
any = true
}
- case walk.ValueNumber:
+ case walk.NumberScalar:
allBools = false
sum += float64(v)
- case walk.ValueString:
+ case walk.StringStructure:
allBools = false
num, err := strconv.ParseFloat(string(v), 64)
if err == nil {
@@ -39,35 +35,31 @@ func sumValues(atoms []walk.Atom) ([]walk.Atom, error) {
}
}
if allBools {
- return []walk.Atom{walk.NewAtomBool(any)}, nil
+ return walk.ValueList{walk.BoolScalar(any)}, nil
} else {
- return []walk.Atom{walk.NewAtomNumber(sum)}, nil
+ return walk.ValueList{walk.NumberScalar(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) {
+func multiplyValues(values walk.ValueList) (walk.ValueList, error) {
allBools := true
var product float64 = 1
var all bool = false
- values, err := walk.Compound(atoms)
- if err != nil {
- return nil, err
- }
for _, value := range values {
switch v := value.(type) {
- case walk.ValueNull:
+ case walk.NullScalar:
allBools = false
product *= 0
- case walk.ValueBool:
- if !bool(v) {
+ case walk.BoolScalar:
+ if !v {
product *= 0
all = false
}
- case walk.ValueNumber:
+ case walk.NumberScalar:
allBools = false
product *= float64(v)
- case walk.ValueString:
+ case walk.StringStructure:
allBools = false
num, err := strconv.ParseFloat(string(v), 64)
if err == nil {
@@ -80,35 +72,31 @@ func multiplyValues(atoms []walk.Atom) ([]walk.Atom, error) {
}
}
if allBools {
- return []walk.Atom{walk.NewAtomBool(all)}, nil
+ return walk.ValueList{walk.BoolScalar(all)}, nil
} else {
- return []walk.Atom{walk.NewAtomNumber(product)}, nil
+ return walk.ValueList{walk.NumberScalar(product)}, nil
}
}
// Does tries to cast all to numbers and negates them
-func negateValues(atoms []walk.Atom) ([]walk.Atom, error) {
- var negatedNumbers []walk.Atom
- values, err := walk.Compound(atoms)
- if err != nil {
- return nil, err
- }
+func negateValues(values walk.ValueList) (walk.ValueList, error) {
+ var negatedNumbers walk.ValueList
for _, value := range values {
switch v := value.(type) {
- case walk.ValueNull:
- negatedNumbers = append(negatedNumbers, walk.NewAtomNumber(0))
- case walk.ValueBool:
- if bool(v) {
- negatedNumbers = append(negatedNumbers, walk.NewAtomNumber(-1))
+ case walk.NullScalar:
+ negatedNumbers = append(negatedNumbers, walk.NumberScalar(0))
+ case walk.BoolScalar:
+ if v {
+ negatedNumbers = append(negatedNumbers, walk.NumberScalar(-1))
} else {
- negatedNumbers = append(negatedNumbers, walk.NewAtomNumber(0))
+ negatedNumbers = append(negatedNumbers, walk.NumberScalar(0))
}
- case walk.ValueNumber:
- negatedNumbers = append(negatedNumbers, walk.NewAtomNumber(-float64(v)))
- case walk.ValueString:
+ case walk.NumberScalar:
+ negatedNumbers = append(negatedNumbers, walk.NumberScalar(-float64(v)))
+ case walk.StringStructure:
num, err := strconv.ParseFloat(string(v), 64)
if err == nil {
- negatedNumbers = append(negatedNumbers, walk.NewAtomNumber(-num))
+ negatedNumbers = append(negatedNumbers, walk.NumberScalar(-num))
} else {
return nil, errors.New("Tried to negate non-castable string")
}
@@ -121,28 +109,24 @@ func negateValues(atoms []walk.Atom) ([]walk.Atom, error) {
// If all are castable to numbers, takes reciprocals of all and returns them
// Else errors
-func reciprocalValues(atoms []walk.Atom) ([]walk.Atom, error) {
- var reciprocals []walk.Atom
- values, err := walk.Compound(atoms)
- if err != nil {
- return nil, err
- }
+func reciprocalValues(values walk.ValueList) (walk.ValueList, error) {
+ var reciprocals walk.ValueList
for _, value := range values {
switch v := value.(type) {
- case walk.ValueNull:
+ case walk.NullScalar:
return nil, errors.New("Tried to take reciprocal of null")
- case walk.ValueBool:
- if bool(v) {
- reciprocals = append(reciprocals, walk.NewAtomNumber(1))
+ case walk.BoolScalar:
+ if v {
+ reciprocals = append(reciprocals, walk.NumberScalar(1))
} else {
return nil, errors.New("Tried to take reciprocal of false")
}
- case walk.ValueNumber:
- reciprocals = append(reciprocals, walk.NewAtomNumber(1 / float64(v)))
- case walk.ValueString:
+ case walk.NumberScalar:
+ reciprocals = append(reciprocals, walk.NumberScalar(1 / float64(v)))
+ case walk.StringStructure:
num, err := strconv.ParseFloat(string(v), 64)
if err == nil {
- reciprocals = append(reciprocals, walk.NewAtomNumber(1 / num))
+ reciprocals = append(reciprocals, walk.NumberScalar(1 / num))
} else {
return nil, errors.New("Tried to take reciprocal of non-castable string")
}
@@ -155,21 +139,17 @@ func reciprocalValues(atoms []walk.Atom) ([]walk.Atom, error) {
// If all are castable to booleans, NOTs all and returns them
// Else errors
-func notValues(atoms []walk.Atom) (notted []walk.Atom, err error) {
- values, err := walk.Compound(atoms)
- if err != nil {
- return nil, err
- }
+func notValues(values walk.ValueList) (notted walk.ValueList, err error) {
for _, value := range values {
switch v := value.(type) {
- case walk.ValueNull:
- notted = append(notted, walk.NewAtomBool(true))
- case walk.ValueBool:
- notted = append(notted, walk.NewAtomBool(!bool(v)))
- case walk.ValueNumber:
- notted = append(notted, walk.NewAtomBool(v == 0))
- case walk.ValueString:
- notted = append(notted, walk.NewAtomBool(len(v) == 0))
+ case walk.NullScalar:
+ notted = append(notted, walk.BoolScalar(true))
+ case walk.BoolScalar:
+ notted = append(notted, walk.BoolScalar(!bool(v)))
+ case walk.NumberScalar:
+ notted = append(notted, walk.BoolScalar(v == 0))
+ case walk.StringStructure:
+ notted = append(notted, walk.BoolScalar(len(v) == 0))
default:
return nil, errors.New("Tried to NOT non-boolean")
}