<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/arithmetic.go
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2024-12-15 17:54:45 +0000
committerCharlie Stanton <charlie@shtanton.xyz>2024-12-15 17:54:45 +0000
commit62aa738be03845f96c40edde087ea39693b27e4e (patch)
tree81a86faa96db42d9da5e7014f53974468229d3e6 /subex/arithmetic.go
parentb434fe4e14f6dcc8d1d7433a29351b8e8ea77d37 (diff)
downloadstred-go-numbers.tar
Implement new number systemnumbers
Diffstat (limited to 'subex/arithmetic.go')
-rw-r--r--subex/arithmetic.go203
1 files changed, 58 insertions, 145 deletions
diff --git a/subex/arithmetic.go b/subex/arithmetic.go
index 4c87d5f..5e0eb44 100644
--- a/subex/arithmetic.go
+++ b/subex/arithmetic.go
@@ -3,171 +3,84 @@ package subex
import (
"main/walk"
"errors"
- "strconv"
)
-func sumValues(values []walk.Value) ([]walk.Value, error) {
- allBools := true
- var sum float64 = 0
- var any bool = false
- for _, value := range values {
- switch v := value.(type) {
- case walk.NullValue:
- allBools = false
- case walk.BoolValue:
- if v {
- sum += 1
- any = true
- }
- case walk.NumberValue:
- allBools = false
- sum += float64(v)
- case walk.StringValue:
- 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")
- }
+func binopAdd(values []walk.Value) ([]walk.Value, error) {
+ if len(values) != 2 {
+ return nil, errors.New("Tried to sum a weird number of values")
+ }
+
+ lhs, lhsIsNumber := values[0].(walk.NumberValue)
+ if !lhsIsNumber {
+ return nil, errors.New("Tried to sum a lhs that is not a number")
}
- if allBools {
- return []walk.Value{walk.BoolValue(any)}, nil
- } else {
- return []walk.Value{walk.NumberValue(sum)}, nil
+
+ rhs, rhsIsNumber := values[1].(walk.NumberValue)
+ if !rhsIsNumber {
+ return nil, errors.New("Tried to sum a rhs that is not a number")
}
+
+ return []walk.Value{walk.NumberValue(float64(lhs) + float64(rhs))}, nil
}
-// Compounds atoms into values, if all values are booleans, does AND, if not, tries to cast to numbers and multiply
-func multiplyValues(values []walk.Value) ([]walk.Value, error) {
- allBools := true
- var product float64 = 1
- var all bool = false
- for _, value := range values {
- switch v := value.(type) {
- case walk.NullValue:
- allBools = false
- product *= 0
- case walk.BoolValue:
- if !v {
- product *= 0
- all = false
- }
- case walk.NumberValue:
- allBools = false
- product *= float64(v)
- case walk.StringValue:
- allBools = false
- num, err := strconv.ParseFloat(string(v), 64)
- if err == nil {
- product *= num
- } else {
- return nil, errors.New("Tried to multiply non-castable string")
- }
- default:
- return nil, errors.New("Tried to multiply non-number")
- }
+func binopMultiply(values []walk.Value) ([]walk.Value, error) {
+ if len(values) != 2 {
+ return nil, errors.New("Tried to multiply a weird number of values")
}
- if allBools {
- return []walk.Value{walk.BoolValue(all)}, nil
- } else {
- return []walk.Value{walk.NumberValue(product)}, nil
+
+ lhs, lhsIsNumber := values[0].(walk.NumberValue)
+ if !lhsIsNumber {
+ return nil, errors.New("Tried to multiply a lhs that is not a number")
}
-}
-// Does tries to cast all to numbers and negates them
-func negateValues(values []walk.Value) ([]walk.Value, error) {
- var negatedNumbers []walk.Value
- for _, value := range values {
- switch v := value.(type) {
- case walk.NullValue:
- negatedNumbers = append(negatedNumbers, walk.NumberValue(0))
- case walk.BoolValue:
- if v {
- negatedNumbers = append(negatedNumbers, walk.NumberValue(-1))
- } else {
- negatedNumbers = append(negatedNumbers, walk.NumberValue(0))
- }
- case walk.NumberValue:
- negatedNumbers = append(negatedNumbers, walk.NumberValue(-float64(v)))
- case walk.StringValue:
- num, err := strconv.ParseFloat(string(v), 64)
- if err == nil {
- negatedNumbers = append(negatedNumbers, walk.NumberValue(-num))
- } else {
- return nil, errors.New("Tried to negate non-castable string")
- }
- default:
- return nil, errors.New("Tried to negate non-number")
- }
+ rhs, rhsIsNumber := values[1].(walk.NumberValue)
+ if !rhsIsNumber {
+ return nil, errors.New("Tried to multiply a rhs that is not a number")
}
- return negatedNumbers, nil
+
+ return []walk.Value{walk.NumberValue(float64(lhs) * float64(rhs))}, nil
}
-// If all are castable to numbers, takes reciprocals of all and returns them
-// Else errors
-func reciprocalValues(values []walk.Value) ([]walk.Value, error) {
- var reciprocals []walk.Value
- for _, value := range values {
- switch v := value.(type) {
- case walk.NullValue:
- return nil, errors.New("Tried to take reciprocal of null")
- case walk.BoolValue:
- if v {
- reciprocals = append(reciprocals, walk.NumberValue(1))
- } else {
- return nil, errors.New("Tried to take reciprocal of false")
- }
- case walk.NumberValue:
- reciprocals = append(reciprocals, walk.NumberValue(1 / float64(v)))
- case walk.StringValue:
- num, err := strconv.ParseFloat(string(v), 64)
- if err == nil {
- reciprocals = append(reciprocals, walk.NumberValue(1 / num))
- } else {
- return nil, errors.New("Tried to take reciprocal of non-castable string")
- }
- default:
- return nil, errors.New("Tried to take reciprocal of non-number")
- }
+func binopDivide(values []walk.Value) ([]walk.Value, error) {
+ if len(values) != 2 {
+ return nil, errors.New("Tried to divide a weird number of values")
+ }
+
+ lhs, lhsIsNumber := values[0].(walk.NumberValue)
+ if !lhsIsNumber {
+ return nil, errors.New("Tried to divide a lhs that is not a number")
+ }
+
+ rhs, rhsIsNumber := values[1].(walk.NumberValue)
+ if !rhsIsNumber {
+ return nil, errors.New("Tried to divide a rhs that is not a number")
}
- return reciprocals, nil
+
+ return []walk.Value{walk.NumberValue(float64(lhs) / float64(rhs))}, nil
}
-// If all are castable to booleans, NOTs all and returns them
-// Else errors
-func notValues(values []walk.Value) (notted []walk.Value, err error) {
+func arithmeticSum(values []walk.Value) ([]walk.Value, error) {
+ var total float64 = 0
for _, value := range values {
- switch v := value.(type) {
- case walk.NullValue:
- notted = append(notted, walk.BoolValue(true))
- case walk.BoolValue:
- notted = append(notted, walk.BoolValue(!bool(v)))
- case walk.NumberValue:
- notted = append(notted, walk.BoolValue(v == 0))
- case walk.StringValue:
- notted = append(notted, walk.BoolValue(len(v) == 0))
- default:
- return nil, errors.New("Tried to NOT non-boolean")
+ n, isNumber := value.(walk.NumberValue)
+ if !isNumber {
+ return nil, errors.New("Tried to sum non-number value")
}
+ total += float64(n)
}
- return notted, nil
+
+ return []walk.Value{walk.NumberValue(total)}, nil
}
-// Returns true if all values are equal, false if not
-func equalValues(values []walk.Value) ([]walk.Value, error) {
- if len(values) == 0 {
- return []walk.Value{walk.BoolValue(true)}, nil
- }
- first := values[0]
- for _, value := range values[1:] {
- // TODO: Refine the equality check
- if value != first {
- return []walk.Value{walk.BoolValue(false)}, nil
+func arithmeticProduct(values []walk.Value) ([]walk.Value, error) {
+ var product float64 = 0
+ for _, value := range values {
+ n, isNumber := value.(walk.NumberValue)
+ if !isNumber {
+ return nil, errors.New("Tried to sum non-number value")
}
+ product *= float64(n)
}
- return []walk.Value{walk.BoolValue(true)}, nil
+
+ return []walk.Value{walk.NumberValue(product)}, nil
}