From ca161b26e9b6a253837e5ec4e0cf318bd0ee7903 Mon Sep 17 00:00:00 2001 From: Charlie Stanton Date: Wed, 19 Apr 2023 13:58:13 +0100 Subject: Adds the NOT operator --- subex/arithmetic.go | 24 ++++++++++++++++++++++++ subex/parse.go | 2 ++ subex/subexast.go | 15 +++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/subex/arithmetic.go b/subex/arithmetic.go index 4404a1c..52f576d 100644 --- a/subex/arithmetic.go +++ b/subex/arithmetic.go @@ -152,3 +152,27 @@ func reciprocalValues(atoms []walk.Atom) ([]walk.Atom, error) { } return reciprocals, nil } + +// If all are castable to booleans, NOTs all and returns them +// Else errors +func notValues(atoms []walk.Atom) (notted []walk.Atom, err error) { + values, err := walk.MemoryCompound(atoms) + if err != nil { + return nil, err + } + for _, value := range values { + switch v := value.(type) { + case walk.ValueNull: + notted = append(notted, walk.ValueBool(true)) + case walk.ValueBool: + notted = append(notted, walk.ValueBool(!v)) + case walk.ValueNumber: + notted = append(notted, walk.ValueBool(v == 0)) + case walk.ValueString: + notted = append(notted, walk.ValueBool(len(v) == 0)) + default: + return nil, errors.New("Tried to NOT non-boolean") + } + } + return notted, nil +} diff --git a/subex/parse.go b/subex/parse.go index f5316c9..8b3a553 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -242,6 +242,8 @@ func parseSubex(l *RuneReader, minPower int) SubexAST { lhs = SubexASTNegate {lhs} case r == '/' && minPower <= 8: lhs = SubexASTReciprocal {lhs} + case r == '!' && minPower <= 8: + lhs = SubexASTNot {lhs} case r == '$' && minPower <= 8: slot := l.next() if slot == eof { diff --git a/subex/subexast.go b/subex/subexast.go index 78c9aff..fb16658 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -238,3 +238,18 @@ func (ast SubexASTReciprocal) compileWith(next SubexState) SubexState { }), } } + +// Runs the content Subex and collects the output +// Maps over the values in the output, casting each to a boolean, notting each and then outputs them +// Rejects if it cannot cast to boolean +type SubexASTNot struct { + content SubexAST +} +func (ast SubexASTNot) compileWith(next SubexState) SubexState { + return &SubexCaptureBeginState { + next: ast.content.compileWith(&SubexArithmeticEndState { + next: next, + calculate: notValues, + }), + } +} -- cgit v1.2.3