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  } | 
