diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-19 13:10:24 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-19 13:10:24 +0100 | 
| commit | b48dcb0d37bd3db854927df25e6ff41d07501026 (patch) | |
| tree | ae2059a0f9a66d48c9bdf3cf41c367e5c0848ad6 /subex | |
| parent | 0072e6aad2f9969348d5315a692f1f5e2ebc075d (diff) | |
| download | stred-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.go | 87 | ||||
| -rw-r--r-- | subex/subexast.go | 6 | ||||
| -rw-r--r-- | subex/subexstate.go | 123 | 
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))  } | 
