diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-19 13:48:15 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-19 13:48:15 +0100 | 
| commit | d3d17484012dc603ae326bec419cff990898e6a0 (patch) | |
| tree | 44aa5b05b6aa3f9b988e6cd59ddacec04660ff32 /subex | |
| parent | 58d50737702adc48604f0a709080dcc587d7145f (diff) | |
| download | stred-go-d3d17484012dc603ae326bec419cff990898e6a0.tar | |
Adds the reciprocal operator
Diffstat (limited to 'subex')
| -rw-r--r-- | subex/arithmetic.go | 34 | ||||
| -rw-r--r-- | subex/parse.go | 2 | ||||
| -rw-r--r-- | subex/subexast.go | 15 | 
3 files changed, 51 insertions, 0 deletions
| diff --git a/subex/arithmetic.go b/subex/arithmetic.go index ff30a58..4404a1c 100644 --- a/subex/arithmetic.go +++ b/subex/arithmetic.go @@ -118,3 +118,37 @@ func negateValues(atoms []walk.Atom) ([]walk.Atom, error) {  	}  	return negatedNumbers, nil  } + +// 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.MemoryCompound(atoms) +	if err != nil { +		return nil, err +	} +	for _, value := range values { +		switch v := value.(type) { +			case walk.ValueNull: +				return nil, errors.New("Tried to take reciprocal of null") +			case walk.ValueBool: +				if bool(v) { +					reciprocals = append(reciprocals, walk.ValueNumber(1)) +				} else { +					return nil, errors.New("Tried to take reciprocal of false") +				} +			case walk.ValueNumber: +				reciprocals = append(reciprocals, walk.ValueNumber(1 / v)) +			case walk.ValueString: +				num, err := strconv.ParseFloat(string(v), 64) +				if err == nil { +					reciprocals = append(reciprocals, walk.ValueNumber(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") +		} +	} +	return reciprocals, nil +} diff --git a/subex/parse.go b/subex/parse.go index 8635186..f5316c9 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -240,6 +240,8 @@ func parseSubex(l *RuneReader, minPower int) SubexAST {  				lhs = SubexASTProduct {lhs}  			case r == '-' && minPower <= 8:  				lhs = SubexASTNegate {lhs} +			case r == '/' && minPower <= 8: +				lhs = SubexASTReciprocal {lhs}  			case r == '$' && minPower <= 8:  				slot := l.next()  				if slot == eof { diff --git a/subex/subexast.go b/subex/subexast.go index 3c807ee..78c9aff 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -223,3 +223,18 @@ func (ast SubexASTNegate) compileWith(next SubexState) SubexState {  		}),  	}  } + +// Runs the content Subex and collects the output +// If it is a list of atoms castable to numbers, it takes the reciprocal of them all and outputs them +// Else it rejects +type SubexASTReciprocal struct { +	content SubexAST +} +func (ast SubexASTReciprocal) compileWith(next SubexState) SubexState { +	return &SubexCaptureBeginState { +		next: ast.content.compileWith(&SubexArithmeticEndState { +			next: next, +			calculate: reciprocalValues, +		}), +	} +} | 
