return BLOCK(c,
gen_op_target(FORK, tail),
- expr,
+ expr,
tail,
gen_op_bound(LOADVN, array_var));
}
block gen_reduce(const char* varname, block source, block init, block body) {
block res_var = gen_op_var_fresh(STOREV, "reduce");
- block loop = BLOCK(gen_op_simple(DUP),
+ block loop = BLOCK(gen_op_simple(DUPN),
source,
block_bind(gen_op_unbound(STOREV, varname),
BLOCK(gen_op_bound(LOADVN, res_var),
block gen_foreach(const char* varname, block source, block init, block update, block extract) {
block output = gen_op_targetlater(JUMP);
block state_var = gen_op_var_fresh(STOREV, "foreach");
- block loop = BLOCK(gen_op_simple(DUP),
+ block loop = BLOCK(gen_op_simple(DUPN),
// get a value from the source expression:
source,
// bind the $varname to that value for all the code in
return val;
}
+// Like stack_pop(), but assert !stack_pop_will_free() and replace with
+// jv_null() on the stack.
+jv stack_popn(jq_state *jq) {
+ jv* sval = stack_block(&jq->stk, jq->stk_top);
+ jv val = *sval;
+ if (!stack_pop_will_free(&jq->stk, jq->stk_top)) {
+ *sval = jv_null();
+ }
+ jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv));
+ assert(jv_is_valid(val));
+ return val;
+}
+
struct forkpoint {
stack_ptr saved_data_stack;
break;
}
+ case DUPN: {
+ jv v = stack_popn(jq);
+ stack_push(jq, jv_copy(v));
+ stack_push(jq, v);
+ break;
+ }
+
case DUP2: {
jv keep = stack_pop(jq);
jv v = stack_pop(jq);
jv_dump(jv_copy(*var), 0);
printf(" (%d)\n", jv_get_refcnt(*var));
}
- jv_free(stack_pop(jq));
+ jv_free(stack_popn(jq));
stack_push(jq, *var);
*var = jv_null();
break;
OP(LOADK, CONSTANT, 1, 1)
OP(DUP, NONE, 1, 2)
+OP(DUPN, NONE, 1, 2)
OP(DUP2, NONE, 2, 3)
OP(POP, NONE, 1, 0)
OP(LOADV, VARIABLE, 1, 1)