<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Stanton <charlie@shtanton.xyz>2023-04-19 13:58:13 +0100
committerCharlie Stanton <charlie@shtanton.xyz>2023-04-19 13:58:13 +0100
commitca161b26e9b6a253837e5ec4e0cf318bd0ee7903 (patch)
treec3863c145024fd1124943e1eab525230c3236aaa
parentd3d17484012dc603ae326bec419cff990898e6a0 (diff)
downloadstred-go-ca161b26e9b6a253837e5ec4e0cf318bd0ee7903.tar
Adds the NOT operator
-rw-r--r--subex/arithmetic.go24
-rw-r--r--subex/parse.go2
-rw-r--r--subex/subexast.go15
3 files changed, 41 insertions, 0 deletions
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,
+ }),
+ }
+}