}
static block j_empty() {
- return gen_op_block_defn(CLOSURE_CREATE, "empty", gen_op_simple(BACKTRACK));
+ return gen_function("empty", gen_op_simple(BACKTRACK));
}
static block j_false() {
- return gen_op_block_defn(CLOSURE_CREATE, "false",
- block_join(gen_op_const(LOADK, jv_false()),
- gen_op_simple(RET)));
+ return gen_function("false", gen_op_const(LOADK, jv_false()));
}
static block j_true() {
- return gen_op_block_defn(CLOSURE_CREATE, "true",
- block_join(gen_op_const(LOADK, jv_true()),
- gen_op_simple(RET)));
+ return gen_function("true", gen_op_const(LOADK, jv_true()));
}
static block j_null() {
- return gen_op_block_defn(CLOSURE_CREATE, "null",
- block_join(gen_op_const(LOADK, jv_null()),
- gen_op_simple(RET)));
+ return gen_function("null", gen_op_const(LOADK, jv_null()));
}
static block j_not() {
- return gen_op_block_defn(CLOSURE_CREATE, "not",
- block_join(gen_condbranch(gen_op_const(LOADK, jv_false()),
- gen_op_const(LOADK, jv_true())),
- gen_op_simple(RET)));
+ return gen_function("not", gen_condbranch(gen_op_const(LOADK, jv_false()),
+ gen_op_const(LOADK, jv_true())));
}
static struct cfunction function_list[] = {
return inst_block(i);
}
-block gen_op_block_defn(opcode op, const char* name, block block) {
- assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO);
- assert(opcode_describe(op)->flags & OP_HAS_BLOCK);
- inst* i = inst_new(op);
- i->subfn = block;
- i->symbol = strdup(name);
- return inst_block(i);
-}
-
-static void block_bind_subblock(block binder, block body, int bindflags);
-block gen_op_block_defn_rec(opcode op, const char* name, block blk) {
- block b = gen_op_block_defn(op, name, blk);
- block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING);
- return b;
-}
-
block gen_op_block_unbound(opcode op, const char* name) {
assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO);
inst* i = inst_new(op);
}
+block gen_function(const char* name, block body) {
+ inst* i = inst_new(CLOSURE_CREATE);
+ i->subfn = body;
+ i->symbol = strdup(name);
+ block b = inst_block(i);
+ block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING);
+ return b;
+}
+
+
block gen_subexp(block a) {
return BLOCK(gen_op_simple(DUP), a, gen_op_simple(SWAP));
}
// Expands call instructions into a calling sequence
// Checking for argument count compatibility happens later
-static void expand_call_arglist(struct bytecode* bc, block b) {
- for (inst* curr = b.first; curr; curr = curr->next) {
+static block expand_call_arglist(struct bytecode* bc, block b) {
+ block ret = gen_noop();
+ for (inst* curr; (curr = block_take(&b));) {
if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
assert(curr->op == CALL_1_1);
- assert(curr->next && curr->next->op == CALLSEQ_END);
+ inst* seq_end = block_take(&b);
+ assert(seq_end && seq_end->op == CALLSEQ_END);
// We expand the argument list as a series of instructions
block arglist = curr->arglist;
curr->arglist = gen_noop();
}
assert(!arglist.first);
- block_insert_before(curr, prelude);
- block_insert_after(curr, callargs);
curr->imm.intval = nargs;
+ ret = BLOCK(ret, prelude, inst_block(curr), callargs, inst_block(seq_end));
break;
}
// Arguments to C functions not yet supported
assert(block_is_single(arglist));
assert(arglist.first->op == CLOSURE_REF);
- block_insert_after(curr, arglist);
curr->imm.intval = 1;
+ ret = BLOCK(ret, inst_block(curr), arglist, inst_block(seq_end));
break;
}
+ } else {
+ ret = BLOCK(ret, inst_block(curr));
}
}
+ if (bc->parent) {
+ // functions should end in a return
+ return BLOCK(ret, gen_op_simple(RET));
+ } else {
+ // the toplevel should YIELD;BACKTRACK; when it finds an answer
+ return BLOCK(ret, gen_op_simple(YIELD), gen_op_simple(BACKTRACK));
+ }
}
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
int var_frame_idx = 0;
bc->nsubfunctions = 0;
bc->nclosures = 0;
- expand_call_arglist(bc, b);
+ b = expand_call_arglist(bc, b);
for (inst* curr = b.first; curr; curr = curr->next) {
if (!curr->next) assert(curr == b.last);
pos += opcode_length(curr->op);
block gen_op_target(opcode op, block target);
block gen_op_var_unbound(opcode op, const char* name);
block gen_op_var_bound(opcode op, block binder);
-block gen_op_block_defn(opcode op, const char* name, block block);
-block gen_op_block_defn_rec(opcode op, const char* name, block block);
block gen_op_block_unbound(opcode op, const char* name);
block gen_op_call(opcode op, block arglist);
block gen_op_symbol(opcode op, const char* name);
+block gen_function(const char* name, block body);
block gen_subexp(block a);
block gen_both(block a, block b);
block gen_collect(block expr);
struct bytecode* bc = 0;
int nerrors = jq_parse(&locations, &program);
if (nerrors == 0) {
- block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
program = builtins_bind(program);
nerrors = block_compile(program, &locations, &bc);
block_free(program);
FuncDef:
"def" IDENT ':' Exp ';' {
- block body = block_join($4, gen_op_simple(RET));
- $$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body);
+ $$ = gen_function(jv_string_value($2), $4);
jv_free($2);
} |
"def" IDENT '(' IDENT ')' ':' Exp ';' {
- block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO);
- $$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body);
+ block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), $7, OP_IS_CALL_PSEUDO);
+ $$ = gen_function(jv_string_value($2), body);
jv_free($2);
jv_free($4);
}
IDENT '(' Exp ')' {
$$ = gen_op_call(CALL_1_1,
block_join(gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)),
- block_bind(gen_op_block_defn(CLOSURE_CREATE,
- "lambda",
- block_join($3, gen_op_simple(RET))),
+ block_bind(gen_function("@lambda", $3),
gen_noop(), OP_IS_CALL_PSEUDO)));
$$ = gen_location(@1, $$);
jv_free($1);