From 4747f8681b3442af8b7916ac5bdfec712662c49b Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 26 Nov 2012 01:36:55 +0000 Subject: [PATCH] Transparent handling for CBV arguments to C functions. C function arguments closures are inlined before the call. --- compile.c | 63 +++++++++++++++++++++++++++++++++++-------------------- compile.h | 3 ++- execute.c | 1 - parser.y | 12 ++++------- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/compile.c b/compile.c index b2878b1..46e5dd8 100644 --- a/compile.c +++ b/compile.c @@ -175,14 +175,6 @@ block gen_op_block_bound(opcode op, block binder) { return b; } -block gen_op_call(opcode op, block arglist) { - assert(op == CALL_1_1); - assert(opcode_describe(op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST); - inst* i = inst_new(op); - i->arglist = arglist; - return block_join(inst_block(i), inst_block(inst_new(CALLSEQ_END))); -} - static void inst_join(inst* a, inst* b) { assert(a && b); assert(!a->next); @@ -289,6 +281,17 @@ block gen_function(const char* name, block body) { return b; } +block gen_lambda(block body) { + return gen_function("@lambda", body); +} + +block gen_call(const char* name, block args) { + inst* i = inst_new(CALL_1_1); + i->arglist = BLOCK(gen_op_block_unbound(CLOSURE_REF, name), args); + return BLOCK(inst_block(i), inst_block(inst_new(CALLSEQ_END))); +} + + block gen_subexp(block a) { return BLOCK(gen_op_simple(DUP), a, gen_op_simple(SWAP)); @@ -436,7 +439,7 @@ static int count_cfunctions(block b) { // Expands call instructions into a calling sequence // Checking for argument count compatibility happens later -static block expand_call_arglist(struct bytecode* bc, block b) { +static block expand_call_arglist(block b) { block ret = gen_noop(); for (inst* curr; (curr = block_take(&b));) { if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { @@ -448,7 +451,7 @@ static block expand_call_arglist(struct bytecode* bc, block b) { curr->arglist = gen_noop(); assert(arglist.first && "zeroth argument (function to call) must be present"); inst* function = arglist.first->bound_by; - assert(function); + assert(function); // FIXME better errors switch (function->op) { default: assert(0 && "Unknown parameter type"); break; @@ -479,25 +482,30 @@ static block expand_call_arglist(struct bytecode* bc, block b) { break; } - case CLOSURE_CREATE_C: + case CLOSURE_CREATE_C: { // Arguments to C functions not yet supported - assert(block_is_single(arglist)); - assert(arglist.first->op == CLOSURE_REF); + inst* cfunction_ref = block_take(&arglist); + block prelude = gen_noop(); + int nargs = 0; + for (inst* i; (i = block_take(&arglist)); ) { + assert(i->op == CLOSURE_CREATE); // FIXME + block body = i->subfn; + i->subfn = gen_noop(); + inst_free(i); + prelude = BLOCK(prelude, gen_subexp(expand_call_arglist(body))); + nargs++; + } + assert(curr->op == CALL_1_1); curr->imm.intval = 1; - ret = BLOCK(ret, inst_block(curr), arglist, inst_block(seq_end)); + ret = BLOCK(ret, prelude, inst_block(curr), inst_block(cfunction_ref), 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)); - } + return ret; } static int compile(struct locfile* locations, struct bytecode* bc, block b) { @@ -506,7 +514,14 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) { int var_frame_idx = 0; bc->nsubfunctions = 0; bc->nclosures = 0; - b = expand_call_arglist(bc, b); + b = expand_call_arglist(b); + if (bc->parent) { + // functions should end in a return + b = BLOCK(b, gen_op_simple(RET)); + } else { + // the toplevel should YIELD;BACKTRACK; when it finds an answer + b = BLOCK(b, gen_op_simple(YIELD), gen_op_simple(BACKTRACK)); + } for (inst* curr = b.first; curr; curr = curr->next) { if (!curr->next) assert(curr == b.last); pos += opcode_length(curr->op); @@ -550,6 +565,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) { subfn->globals = bc->globals; subfn->parent = bc; errors += compile(locations, subfn, curr->subfn); + curr->subfn = gen_noop(); } } else { bc->subfunctions = 0; @@ -571,7 +587,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) { if (opflags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { assert(curr->op == CALL_1_1); int nargs = curr->imm.intval; - assert(nargs > 0); + assert(nargs > 0 && nargs < 100); //FIXME code[pos++] = (uint16_t)nargs; int desired_params = 0; @@ -630,6 +646,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) { } bc->constants = constant_pool; bc->nlocals = maxvar + 2; // FIXME: frames of size zero? + block_free(b); return errors; } diff --git a/compile.h b/compile.h index d9ed654..c8a326d 100644 --- a/compile.h +++ b/compile.h @@ -23,10 +23,11 @@ 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_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_lambda(block body); +block gen_call(const char* name, block body); block gen_subexp(block a); block gen_both(block a, block b); block gen_collect(block expr); diff --git a/execute.c b/execute.c index 605db55..e1e9b51 100644 --- a/execute.c +++ b/execute.c @@ -514,7 +514,6 @@ struct bytecode* jq_compile(const char* str) { if (nerrors == 0) { program = builtins_bind(program); nerrors = block_compile(program, &locations, &bc); - block_free(program); } if (nerrors) { fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error"); diff --git a/parser.y b/parser.y index e8cbf6d..92d6f7c 100644 --- a/parser.y +++ b/parser.y @@ -152,12 +152,11 @@ static block gen_binop(block a, block b, int op) { } assert(funcname); - return BLOCK(gen_subexp(a), gen_subexp(b), - gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, funcname))); + return gen_call(funcname, BLOCK(gen_lambda(a), gen_lambda(b))); } static block gen_format(block a) { - return BLOCK(a, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, "tostring"))); + return BLOCK(a, gen_call("tostring", gen_noop())); } static block gen_update(block a, block op, int optype) { @@ -386,14 +385,11 @@ String { jv_free($2); } | IDENT { - $$ = gen_location(@$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)))); + $$ = gen_location(@$, gen_call(jv_string_value($1), gen_noop())); jv_free($1); } | IDENT '(' Exp ')' { - $$ = gen_op_call(CALL_1_1, - block_join(gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)), - block_bind(gen_function("@lambda", $3), - gen_noop(), OP_IS_CALL_PSEUDO))); + $$ = gen_call(jv_string_value($1), gen_lambda($3)); $$ = gen_location(@1, $$); jv_free($1); } | -- 2.40.0