diff options
Diffstat (limited to 'subex/arithmetic.go')
-rw-r--r-- | subex/arithmetic.go | 203 |
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 } |