if-then-else and defined-or operators

This commit is contained in:
Stephen Dolan committed 2012-09-04 15:34:34 +01:00
1 parent 520c7bb15e
commit 5add2c2ceb
7 files changed
+97 -3

No files matched your search

+45 -2
View File
@@ -312,8 +312,51 @@ block gen_assign(block expr) {
return c; return c;
} }
block gen_else(block a, block b) { block gen_definedor(block a, block b) {
assert(0); // var found := false
block c = gen_op_simple(DUP);
block_append(&c, gen_op_const(LOADK, jv_false()));
block found_var = block_bind(gen_op_var_unbound(STOREV, "found"),
gen_noop(), OP_HAS_VARIABLE);
block_append(&c, found_var);
// if found, backtrack. Otherwise execute b
block tail = gen_op_simple(DUP);
block_append(&tail, gen_op_var_bound(LOADV, found_var));
block backtrack = gen_op_simple(BACKTRACK);
block_append(&tail, gen_op_target(JUMP_F, backtrack));
block_append(&tail, backtrack);
block_append(&tail, gen_op_simple(POP));
block_append(&tail, b);
// try again
block if_notfound = gen_op_simple(BACKTRACK);
// found := true, produce result
block if_found = gen_op_simple(DUP);
block_append(&if_found, gen_op_const(LOADK, jv_true()));
block_append(&if_found, gen_op_var_bound(STOREV, found_var));
block_append(&if_found, gen_op_target(JUMP, tail));
block_append(&c, gen_op_target(FORK, if_notfound));
block_append(&c, a);
block_append(&c, gen_op_target(JUMP_F, if_found));
block_append(&c, if_found);
block_append(&c, if_notfound);
block_append(&c, tail);
return c;
}
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));
return b;
} }
block gen_cbinding(struct symbol_table* t, block code) { block gen_cbinding(struct symbol_table* t, block code) {
+3 -1
View File
@@ -26,7 +26,9 @@ block gen_subexp(block a);
block gen_both(block a, block b); block gen_both(block a, block b);
block gen_collect(block expr); block gen_collect(block expr);
block gen_assign(block expr); block gen_assign(block expr);
block gen_else(block a, block b); block gen_definedor(block a, block b);
block gen_cond(block cond, block iftrue, block iffalse);
block gen_cbinding(struct symbol_table* functions, block b); block gen_cbinding(struct symbol_table* functions, block b);
+13
View File
@@ -59,6 +59,7 @@ typedef struct {
} data_stk_elem; } data_stk_elem;
void stack_push(stackval val) { void stack_push(stackval val) {
assert(jv_is_valid(val.value));
data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem)); data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem));
s->sv = val; s->sv = val;
} }
@@ -70,6 +71,7 @@ stackval stack_pop() {
sv.value = jv_copy(sv.value); sv.value = jv_copy(sv.value);
} }
forkable_stack_pop(&data_stk); forkable_stack_pop(&data_stk);
assert(jv_is_valid(sv.value));
return sv; return sv;
} }
@@ -292,6 +294,17 @@ jv jq_next() {
break; break;
} }
case JUMP_F: {
uint16_t offset = *pc++;
stackval t = stack_pop();
jv_kind kind = jv_get_kind(t.value);
if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) {
pc += offset;
}
stack_push(t); // FIXME do this better
break;
}
case EACH: case EACH:
stack_push(stackval_root(jv_number(0))); stack_push(stackval_root(jv_number(0)));
// fallthrough // fallthrough
+5
View File
@@ -13,6 +13,11 @@
"as" { return AS; } "as" { return AS; }
"def" { return DEF; } "def" { return DEF; }
"|=" { return SETPIPE; } "|=" { return SETPIPE; }
"if" { return IF; }
"then" { return THEN; }
"else" { return ELSE; }
"end" { return END; }
"//" { return DEFINEDOR; }
"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];}
\"(\\.|[^\\"])*\" | \"(\\.|[^\\"])*\" |
+1
View File
@@ -10,6 +10,7 @@ OP(YIELD, NONE, 1, 0)
OP(EACH, NONE, 1, 1) OP(EACH, NONE, 1, 1)
OP(FORK, BRANCH, 0, 0) OP(FORK, BRANCH, 0, 0)
OP(JUMP, BRANCH, 0, 0) OP(JUMP, BRANCH, 0, 0)
OP(JUMP_F,BRANCH, 1, 0)
OP(BACKTRACK, NONE, 0, 0) OP(BACKTRACK, NONE, 0, 0)
OP(APPEND, NONE, 2, 1) OP(APPEND, NONE, 2, 1)
OP(INSERT, NONE, 4, 2) OP(INSERT, NONE, 4, 2)
+15
View File
@@ -25,13 +25,20 @@
%left '|' %left '|'
%left ',' %left ','
%token EQ "==" %token EQ "=="
%token DEFINEDOR "//"
%token AS "as" %token AS "as"
%token DEF "def" %token DEF "def"
%token SETPIPE "|=" %token SETPIPE "|="
%token IF "if"
%token THEN "then"
%token ELSE "else"
%token END "end"
%right "//"
%nonassoc '=' SETPIPE %nonassoc '=' SETPIPE
%nonassoc EQ %nonassoc EQ
%left '+' %left '+'
%type <blk> Exp Term MkDict MkDictPair ExpD %type <blk> Exp Term MkDict MkDictPair ExpD
%{ %{
@@ -78,6 +85,10 @@ Term "as" '$' IDENT '|' Exp {
jv_free($4); jv_free($4);
} | } |
"if" Exp "then" Exp "else" Exp "end" {
$$ = gen_cond($2, $4, $6);
} |
Exp '=' Exp { Exp '=' Exp {
block assign = gen_op_simple(DUP); block assign = gen_op_simple(DUP);
block_append(&assign, $3); block_append(&assign, $3);
@@ -87,6 +98,10 @@ Exp '=' Exp {
$$ = gen_assign(assign); $$ = gen_assign(assign);
} | } |
Exp "//" Exp {
$$ = gen_definedor($1, $3);
} |
Exp "|=" Exp { Exp "|=" Exp {
block assign = $1; block assign = $1;
block_append(&assign, gen_op_simple(DUP)); block_append(&assign, gen_op_simple(DUP));
+15
View File
@@ -234,3 +234,18 @@ def inc(x): x |= .+1; inc(.[].a)
.foo[2].bar = 1 .foo[2].bar = 1
{"foo":[11], "bar":42} {"foo":[11], "bar":42}
{"foo":[11,null,{"bar":1}], "bar":42} {"foo":[11,null,{"bar":1}], "bar":42}
#
# Conditionals
#
[.[] | if .foo then "yep" else "nope" end]
[{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}]
["yep","yep","yep","yep","nope","nope","yep","nope"]
# FIXME: define/test behaviour of 'if (.foo,.bar) then A else B end'
[.[] | [.foo[] // .bar]]
[{"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]]