]> granicus.if.org Git - jq/commitdiff
Short-circuiting Boolean "and" and "or" operators.
authorStephen Dolan <mu@netsoc.tcd.ie>
Tue, 4 Sep 2012 19:38:59 +0000 (20:38 +0100)
committerStephen Dolan <mu@netsoc.tcd.ie>
Tue, 4 Sep 2012 19:38:59 +0000 (20:38 +0100)
c/compile.c
c/compile.h
c/lexer.l
c/parser.y
c/testdata

index c83a5583dd5a96f11ad39b814d5c3f0e8949e724..c4782f1d168e2e0b11d135c5d221c0796c0c0aac 100644 (file)
@@ -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;
 }
 
index 5a2faf7b85569924319b71fdc921ae9e6cf7da41..1a7c62c6bca48bd751d5259db814861bd8ce5ac9 100644 (file)
@@ -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);
 
index 98365f1f78ead0f675c138428baebe16ccbadb13..47789d29fde1c13b81f31c240ce14b0a16855c77 100644 (file)
--- 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];}
index 165cdb428e745323483c8ae5ef9c1718ed046277..5b997e620e4be4b08b615574a7d4c6fec4e6b097 100644 (file)
 %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);
 } |
index 3fe231f58fc614188d3e7d929b0626da93b0d9f8..4241c6cd5f0e245405a8133b6de248bc1c308ff4 100644 (file)
@@ -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]