diff options
author | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-09-04 20:38:59 +0100 |
---|---|---|
committer | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-09-04 20:38:59 +0100 |
commit | 6e6ea507630eceafd2cb2eb8e25bae231ee6f8a6 (patch) | |
tree | b232529af9c4ec919f1a165e44a9164d912b816a | |
parent | c5ab3b2336a3ad14844bd91beae5b4dbca2c2926 (diff) |
Short-circuiting Boolean "and" and "or" operators.
-rw-r--r-- | c/compile.c | 45 | ||||
-rw-r--r-- | c/compile.h | 2 | ||||
-rw-r--r-- | c/lexer.l | 2 | ||||
-rw-r--r-- | c/parser.y | 12 | ||||
-rw-r--r-- | c/testdata | 6 |
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); @@ -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];} @@ -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); } | @@ -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] |