From aea1a08d6a9d378137d467d3e1f1ccc40232b725 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 19 Apr 2023 13:23:47 +0100 Subject: Adds the negate operator Negates all of the numbers produced by its content subex --- subex/arithmetic.go | 33 +++++++++++++++++++++++++++++++++ subex/parse.go | 2 ++ subex/subexast.go | 14 ++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'subex') diff --git a/subex/arithmetic.go b/subex/arithmetic.go index 7200ac7..5497a68 100644 --- a/subex/arithmetic.go +++ b/subex/arithmetic.go @@ -85,3 +85,36 @@ func multiplyValues(atoms []walk.Atom) ([]walk.Atom, error) { return []walk.Atom{walk.ValueNumber(product)}, nil } } + +// Does tries to cast all to numbers and negates them +func negateValues(atoms []walk.Atom) ([]walk.Atom, error) { + var negatedNumbers []walk.Atom + values, err := walk.MemoryCompound(atoms) + if err != nil { + return nil, err + } + for _, value := range values { + switch v := value.(type) { + case walk.ValueNull: + negatedNumbers = append(negatedNumbers, walk.ValueNumber(0)) + case walk.ValueBool: + if bool(v) { + negatedNumbers = append(negatedNumbers, walk.ValueNumber(-1)) + } else { + negatedNumbers = append(negatedNumbers, walk.ValueNumber(0)) + } + case walk.ValueNumber: + negatedNumbers = append(negatedNumbers, walk.ValueNumber(-v)) + case walk.ValueString: + num, err := strconv.ParseFloat(string(v), 64) + if err == nil { + negatedNumbers = append(negatedNumbers, walk.ValueNumber(-num)) + } else { + return nil, errors.New("Tried to sum non-castable string") + } + default: + return nil, errors.New("Tried to sum non-number") + } + } + return negatedNumbers, nil +} diff --git a/subex/parse.go b/subex/parse.go index f73d060..8635186 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -238,6 +238,8 @@ func parseSubex(l *RuneReader, minPower int) SubexAST { lhs = SubexASTSum {lhs} case r == '*' && minPower <= 8: lhs = SubexASTProduct {lhs} + case r == '-' && minPower <= 8: + lhs = SubexASTNegate {lhs} case r == '$' && minPower <= 8: slot := l.next() if slot == eof { diff --git a/subex/subexast.go b/subex/subexast.go index abf0ca6..3c807ee 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -209,3 +209,17 @@ func (ast SubexASTProduct) compileWith(next SubexState) SubexState { }), } } + +// Runs the content Subex, if all outputted atoms can be cast to numbers, outputs them all negated +// Rejects if this fails +type SubexASTNegate struct { + content SubexAST +} +func (ast SubexASTNegate) compileWith(next SubexState) SubexState { + return &SubexCaptureBeginState { + next: ast.content.compileWith(&SubexArithmeticEndState { + next: next, + calculate: negateValues, + }), + } +} -- cgit v1.2.3