block gen_definedor(block a, block b) { // var found := false block found_var = gen_op_var_fresh(STOREV, "found"); block init = BLOCK(gen_op_simple(DUP), gen_const(jv_false()), found_var); // if found, backtrack. Otherwise execute b block backtrack = gen_op_simple(BACKTRACK); block tail = BLOCK(gen_op_simple(DUP), gen_op_bound(LOADV, found_var), gen_op_target(JUMP_F, backtrack), backtrack, gen_op_simple(POP), b); // try again block if_notfound = gen_op_simple(BACKTRACK); // found := true, produce result block if_found = BLOCK(gen_op_simple(DUP), gen_const(jv_true()), gen_op_bound(STOREV, found_var), gen_op_target(JUMP, tail)); return BLOCK(init, gen_op_target(FORK, if_notfound), a, gen_op_target(JUMP_F, if_found), if_found, if_notfound, tail); }
block gen_or(block a, block b) { // a or b = if a then true else (if b then true else false) return BLOCK(gen_op_simple(DUP), a, gen_condbranch(BLOCK(gen_op_simple(POP), gen_const(jv_true())), BLOCK(gen_op_simple(POP), b, gen_condbranch(gen_const(jv_true()), gen_const(jv_false()))))); }
struct bytecode* jq_compile_args(const char* str, jv args) { assert(jv_get_kind(args) == JV_KIND_ARRAY); struct locfile locations; locfile_init(&locations, str, strlen(str)); block program; struct bytecode* bc = 0; int nerrors = jq_parse(&locations, &program); if (nerrors == 0) { for (int i=0; i<jv_array_length(jv_copy(args)); i++) { jv arg = jv_array_get(jv_copy(args), i); jv name = jv_object_get(jv_copy(arg), jv_string("name")); jv value = jv_object_get(arg, jv_string("value")); program = gen_var_binding(gen_const(value), jv_string_value(name), program); jv_free(name); } jv_free(args); program = builtins_bind(program); nerrors = block_compile(program, &locations, &bc); } if (nerrors) { fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error"); } locfile_free(&locations); return bc; }
block gen_collect(block expr) { block array_var = gen_op_var_fresh(STOREV, "collect"); block c = BLOCK(gen_op_simple(DUP), gen_const(jv_array()), array_var); block tail = BLOCK(gen_op_bound(APPEND, array_var), gen_op_simple(BACKTRACK)); return BLOCK(c, gen_op_target(FORK, tail), expr, tail, gen_op_bound(LOADVN, array_var)); }
int jq_compile_args(jq_state *jq, const char* str, jv args) { jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); assert(jv_get_kind(args) == JV_KIND_ARRAY); struct locfile locations; locfile_init(&locations, jq, str, strlen(str)); block program; jq_reset(jq); if (jq->bc) { bytecode_free(jq->bc); jq->bc = 0; } int nerrors = jq_parse(&locations, &program); if (nerrors == 0) { int i; for (i=0; i<jv_array_length(jv_copy(args)); i++) { jv arg = jv_array_get(jv_copy(args), i); jv name = jv_object_get(jv_copy(arg), jv_string("name")); jv value = jv_object_get(arg, jv_string("value")); program = gen_var_binding(gen_const(value), jv_string_value(name), program); jv_free(name); } nerrors = builtins_bind(jq, &program); if (nerrors == 0) { nerrors = block_compile(program, &locations, &jq->bc); } } jv_free(args); if (nerrors) { jv s = jv_string_fmt("%d compile %s", nerrors, nerrors > 1 ? "errors" : "error"); if (jq->err_cb != NULL) jq->err_cb(jq->err_cb_data, s); else if (!jv_is_valid(s)) fprintf(stderr, "Error formatting jq compilation errors: %s\n", strerror(errno)); else fprintf(stderr, "%s\n", jv_string_value(s)); jv_free(s); } locfile_free(&locations); return jq->bc != NULL; }