diff options
author | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-11-26 00:39:01 +0000 |
---|---|---|
committer | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-11-26 00:39:01 +0000 |
commit | 3e3fe5195947a0af711959e2dedc9c84a697c5fb (patch) | |
tree | 99877aeed9644c4a4c25ff1ef187d52f0947e16f | |
parent | 924aeda5043d76296c651d20025881a60161b7d3 (diff) |
Clean up function creation API and epilogue generation.
-rw-r--r-- | builtin.c | 20 | ||||
-rw-r--r-- | compile.c | 50 | ||||
-rw-r--r-- | compile.h | 3 | ||||
-rw-r--r-- | execute.c | 1 | ||||
-rw-r--r-- | parser.y | 11 |
5 files changed, 38 insertions, 47 deletions
@@ -252,32 +252,24 @@ static void f_type(jv input[], jv output[]) { } 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[] = { @@ -161,22 +161,6 @@ block gen_op_symbol(opcode op, const char* sym) { 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); @@ -296,6 +280,16 @@ block block_bind(block binder, block body, int bindflags) { } +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)); } @@ -442,11 +436,13 @@ static int count_cfunctions(block b) { // 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(); @@ -478,9 +474,8 @@ static void expand_call_arglist(struct bytecode* bc, block b) { } 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; } @@ -488,12 +483,21 @@ static void expand_call_arglist(struct bytecode* bc, block b) { // 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) { @@ -502,7 +506,7 @@ 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); @@ -22,12 +22,11 @@ block gen_op_const(opcode op, jv constant); 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); @@ -512,7 +512,6 @@ struct bytecode* jq_compile(const char* str) { 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); @@ -305,14 +305,13 @@ QQSTRING_START QQString QQSTRING_END { 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); } @@ -393,9 +392,7 @@ IDENT { 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); |