summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Dolan <mu@netsoc.tcd.ie>2012-09-04 20:38:59 +0100
committerStephen Dolan <mu@netsoc.tcd.ie>2012-09-04 20:38:59 +0100
commit6e6ea507630eceafd2cb2eb8e25bae231ee6f8a6 (patch)
treeb232529af9c4ec919f1a165e44a9164d912b816a
parentc5ab3b2336a3ad14844bd91beae5b4dbca2c2926 (diff)
Short-circuiting Boolean "and" and "or" operators.
-rw-r--r--c/compile.c45
-rw-r--r--c/compile.h2
-rw-r--r--c/lexer.l2
-rw-r--r--c/parser.y12
-rw-r--r--c/testdata6
5 files changed, 62 insertions, 5 deletions
diff --git a/c/compile.c b/c/compile.c
index c83a5583..c4782f1d 100644
--- a/c/compile.c
+++ b/c/compile.c
@@ -348,14 +348,49 @@ block gen_definedor(block a, block b) {
return c;
}
+static block gen_condbranch(block iftrue, block iffalse) {
+ block b = gen_noop();
+ block_append(&iftrue, gen_op_target(JUMP, iffalse));
+ block_append(&b, gen_op_target(JUMP_F, iftrue));
+ block_append(&b, iftrue);
+ block_append(&b, iffalse);
+ return b;
+}
+
+block gen_and(block a, block b) {
+ // a and b = if a then (if b then true else false) else false
+ block code = gen_op_simple(DUP);
+ block_append(&code, a);
+
+ block if_a_true = gen_op_simple(POP);
+ block_append(&if_a_true, b);
+ block_append(&if_a_true, gen_condbranch(gen_op_const(LOADK, jv_true()),
+ gen_op_const(LOADK, jv_false())));
+ block_append(&code, gen_condbranch(if_a_true,
+ block_join(gen_op_simple(POP), gen_op_const(LOADK, jv_false()))));
+ return code;
+}
+
+block gen_or(block a, block b) {
+ // a or b = if a then true else (if b then true else false)
+ block code = gen_op_simple(DUP);
+ block_append(&code, a);
+
+ block if_a_false = gen_op_simple(POP);
+ block_append(&if_a_false, b);
+ block_append(&if_a_false, gen_condbranch(gen_op_const(LOADK, jv_true()),
+ gen_op_const(LOADK, jv_false())));
+ block_append(&code, gen_condbranch(block_join(gen_op_simple(POP), gen_op_const(LOADK, jv_true())),
+ if_a_false));
+ return code;
+
+}
+
block gen_cond(block cond, block iftrue, block iffalse) {
block b = gen_op_simple(DUP);
block_append(&b, cond);
-
- block_append(&iftrue, gen_op_target(JUMP, iffalse));
- block_append(&b, gen_op_target(JUMP_F, iftrue));
- block_append(&b, block_join(gen_op_simple(POP), iftrue));
- block_append(&b, block_join(gen_op_simple(POP), iffalse));
+ block_append(&b, gen_condbranch(block_join(gen_op_simple(POP), iftrue),
+ block_join(gen_op_simple(POP), iffalse)));
return b;
}
diff --git a/c/compile.h b/c/compile.h
index 5a2faf7b..1a7c62c6 100644
--- a/c/compile.h
+++ b/c/compile.h
@@ -27,6 +27,8 @@ block gen_both(block a, block b);
block gen_collect(block expr);
block gen_assign(block expr);
block gen_definedor(block a, block b);
+block gen_and(block a, block b);
+block gen_or(block a, block b);
block gen_cond(block cond, block iftrue, block iffalse);
diff --git a/c/lexer.l b/c/lexer.l
index 98365f1f..47789d29 100644
--- a/c/lexer.l
+++ b/c/lexer.l
@@ -17,6 +17,8 @@
"then" { return THEN; }
"else" { return ELSE; }
"elif" { return ELSE_IF; }
+"and" { return AND; }
+"or" { return OR; }
"end" { return END; }
"//" { return DEFINEDOR; }
"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];}
diff --git a/c/parser.y b/c/parser.y
index 165cdb42..5b997e62 100644
--- a/c/parser.y
+++ b/c/parser.y
@@ -34,9 +34,13 @@
%token ELSE "else"
%token ELSE_IF "elif"
%token END "end"
+%token AND "and"
+%token OR "or"
%right "//"
%nonassoc '=' SETPIPE
%nonassoc EQ
+%left OR
+%left AND
%left '+'
@@ -99,6 +103,14 @@ Exp '=' Exp {
$$ = gen_assign(assign);
} |
+Exp "or" Exp {
+ $$ = gen_or($1, $3);
+} |
+
+Exp "and" Exp {
+ $$ = gen_and($1, $3);
+} |
+
Exp "//" Exp {
$$ = gen_definedor($1, $3);
} |
diff --git a/c/testdata b/c/testdata
index 3fe231f5..4241c6cd 100644
--- a/c/testdata
+++ b/c/testdata
@@ -254,3 +254,9 @@ def inc(x): x |= .+1; inc(.[].a)
[{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}]
[[1,2], [1], [3], [42], [41]]
+.[] | [.[0] and .[1], .[0] or .[1]]
+[[true,[]], [false,1], [42,null], [null,false]]
+[true,true]
+[false,true]
+[false,true]
+[false,false]