diff --git a/c/compile.c b/c/compile.c index 93f71888..f9f738d8 100644 --- a/c/compile.c +++ b/c/compile.c @@ -14,6 +14,7 @@ struct inst { uint16_t intval; struct inst* target; json_t* constant; + struct cfunction* cfunc; } imm; // Binding @@ -311,6 +312,16 @@ block gen_else(block a, block b) { assert(0); } +block gen_cbinding(struct symbol_table* t, block code) { + for (int cfunc=0; cfuncncfunctions; cfunc++) { + inst* i = inst_new(CLOSURE_CREATE_C); + i->imm.cfunc = &t->cfunctions[cfunc]; + i->symbol = strdup(i->imm.cfunc->name); + code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO); + } + return code; +} + static uint16_t nesting_level(struct bytecode* bc, inst* target) { uint16_t level = 0; assert(bc && target->compiled); @@ -322,6 +333,16 @@ static uint16_t nesting_level(struct bytecode* bc, inst* target) { return level; } +static int count_cfunctions(block b) { + int n = 0; + for (inst* i = b.first; i; i = i->next) { + if (i->op == CLOSURE_CREATE_C) n++; + if (opcode_describe(i->op)->flags & OP_HAS_BLOCK) + n += count_cfunctions(i->subfn); + } + return n; +} + static void compile(struct bytecode* bc, block b) { int pos = 0; int var_frame_idx = 0; @@ -349,6 +370,12 @@ static void compile(struct bytecode* bc, block b) { assert(curr->bound_by == curr); curr->imm.intval = bc->nclosures++; } + if (curr->op == CLOSURE_CREATE_C) { + assert(curr->bound_by == curr); + int idx = bc->globals->ncfunctions++; + bc->globals->cfunctions[idx] = *curr->imm.cfunc; + curr->imm.intval = idx; + } } if (bc->nsubfunctions) { bc->subfunctions = malloc(sizeof(struct bytecode*) * bc->nsubfunctions); @@ -374,6 +401,7 @@ static void compile(struct bytecode* bc, block b) { const struct opcode_description* op = opcode_describe(curr->op); if (op->length == 0) continue; + uint16_t* opcode_rewrite = &code[pos]; code[pos++] = curr->op; int opflags = op->flags; assert(!(op->flags & OP_IS_CALL_PSEUDO)); @@ -381,6 +409,7 @@ static void compile(struct bytecode* bc, block b) { int nargs = curr->imm.intval; assert(nargs > 0); code[pos++] = (uint16_t)nargs; + int desired_params; for (int i=0; inext; assert(curr && opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO); @@ -389,12 +418,20 @@ static void compile(struct bytecode* bc, block b) { default: assert(0 && "Unknown type of argument"); case CLOSURE_CREATE: code[pos++] = curr->bound_by->imm.intval | ARG_NEWCLOSURE; + if (i == 0) desired_params = bc->subfunctions[curr->bound_by->imm.intval]->nclosures; break; case CLOSURE_PARAM: code[pos++] = curr->bound_by->imm.intval; + if (i == 0) desired_params = 0; + break; + case CLOSURE_CREATE_C: + code[pos++] = curr->bound_by->imm.intval; + *opcode_rewrite = bc->globals->cfunctions[curr->bound_by->imm.intval].callop; + if (i == 0) desired_params = 0; break; } } + assert(nargs - 1 == desired_params); } else if (opflags & OP_HAS_CONSTANT) { code[pos++] = json_array_size(constant_pool); json_array_append(constant_pool, curr->imm.constant); @@ -427,11 +464,15 @@ static void compile(struct bytecode* bc, block b) { bc->nlocals = maxvar + 2; // FIXME: frames of size zero? } -struct bytecode* block_compile(struct symbol_table* syms, block b) { +struct bytecode* block_compile(block b) { struct bytecode* bc = malloc(sizeof(struct bytecode)); bc->parent = 0; - bc->globals = syms; + bc->globals = malloc(sizeof(struct symbol_table)); + int ncfunc = count_cfunctions(b); + bc->globals->ncfunctions = 0; + bc->globals->cfunctions = malloc(sizeof(struct cfunction) * ncfunc); compile(bc, b); + assert(bc->globals->ncfunctions == ncfunc); return bc; } diff --git a/c/compile.h b/c/compile.h index 2ce02c0e..4c0a3a17 100644 --- a/c/compile.h +++ b/c/compile.h @@ -28,11 +28,14 @@ block gen_collect(block expr); block gen_assign(block expr); block gen_else(block a, block b); +block gen_cbinding(struct symbol_table* functions, block b); void block_append(block* b, block b2); block block_join(block a, block b); block block_bind(block binder, block body, int bindflags); -struct bytecode* block_compile(struct symbol_table*, block); +struct bytecode* block_compile(block); void block_free(block); + + diff --git a/c/execute.c b/c/execute.c index f9e2570c..75aaec09 100644 --- a/c/execute.c +++ b/c/execute.c @@ -349,6 +349,9 @@ json_t* jq_next() { } case CALL_BUILTIN_1_1: { + assert(*pc == 1); // no closure args allowed + pc++; // skip nclosures + pc++; // skip level stackval top = stack_pop(); cfunc_input[0] = top.value; struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; @@ -359,6 +362,9 @@ json_t* jq_next() { } case CALL_BUILTIN_3_1: { + assert(*pc == 1); // no closure args allowed + pc++; // skip nclosures + pc++; // skip level stackval top = stack_pop(); json_t* a = stack_pop().value; json_t* b = stack_pop().value; diff --git a/c/main.c b/c/main.c index 66984842..c03b5a99 100644 --- a/c/main.c +++ b/c/main.c @@ -30,7 +30,7 @@ void run_tests() { block program = compile(buf); block_append(&program, gen_op_simple(YIELD)); block_append(&program, gen_op_simple(BACKTRACK)); - struct bytecode* bc = block_compile(&builtins, program); + struct bytecode* bc = block_compile(gen_cbinding(&builtins, program)); block_free(program); printf("Disassembly:\n"); dump_disassembly(2, bc); @@ -76,7 +76,7 @@ int main(int argc, char* argv[]) { if (argc == 1) { run_tests(); return 0; } block blk = compile(argv[1]); block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); - struct bytecode* bc = block_compile(&builtins, blk); + struct bytecode* bc = block_compile(gen_cbinding(&builtins, blk)); block_free(blk); dump_disassembly(0, bc); printf("\n"); diff --git a/c/opcode.c b/c/opcode.c index 62624c92..bc259c22 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -5,10 +5,11 @@ #define CONSTANT OP_HAS_CONSTANT, 2 #define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3 #define BRANCH OP_HAS_BRANCH, 2 -#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC), 2 +#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2 #define UFUNC (OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2 #define CLOSURE_PARAM_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 #define CLOSURE_CREATE_IMM (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 +#define CLOSURE_CREATE_C_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 #define CLOSURE_REF_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 #define OP(name, imm, in, out) \ diff --git a/c/opcode_list.h b/c/opcode_list.h index dde07226..268025e8 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -26,3 +26,4 @@ OP(RET, NONE, 1, 1) OP(CLOSURE_PARAM, CLOSURE_PARAM_IMM, 0, 0) OP(CLOSURE_REF, CLOSURE_REF_IMM, 0, 0) OP(CLOSURE_CREATE, CLOSURE_CREATE_IMM, 0, 0) +OP(CLOSURE_CREATE_C, CLOSURE_CREATE_C_IMM, 0, 0) diff --git a/c/parser.y b/c/parser.y index 31c70865..5ec03892 100644 --- a/c/parser.y +++ b/c/parser.y @@ -106,7 +106,7 @@ Exp '+' Exp { $$ = gen_noop(); block_append(&$$, gen_subexp($1)); block_append(&$$, gen_subexp($3)); - block_append(&$$, gen_op_symbol(CALL_BUILTIN_3_1, "_plus")); + block_append(&$$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, "_plus"))); } | Term { @@ -158,21 +158,18 @@ NUMBER { block_append(&$$, $2); block_append(&$$, gen_op_simple(POP)); } | -IDENT { - $$ = gen_op_symbol(CALL_BUILTIN_1_1, $1); -} | '$' IDENT { $$ = gen_op_var_unbound(LOADV, $2); } | -'$' '$' IDENT { - $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, $3)); +IDENT { + $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, $1)); } | -'$' '$' IDENT '(' Exp ')' { +IDENT '(' Exp ')' { $$ = gen_op_call(CALL_1_1, - block_join(gen_op_block_unbound(CLOSURE_REF, $3), + block_join(gen_op_block_unbound(CLOSURE_REF, $1), block_bind(gen_op_block_defn(CLOSURE_CREATE, "lambda", - block_join($5, gen_op_simple(RET))), + block_join($3, gen_op_simple(RET))), gen_noop(), OP_IS_CALL_PSEUDO))); } diff --git a/c/testdata b/c/testdata index 1d8420d6..6e40b9ae 100644 --- a/c/testdata +++ b/c/testdata @@ -133,21 +133,21 @@ null # Oh god. # -def f: . + 1; def g: def g: . + 100; $$f | $$g | $$f; ($$f | $$g), $$g +def f: . + 1; def g: def g: . + 100; f | g | f; (f | g), g 3.0 106.0 105.0 -def f: (1000,2000); $$f +def f: (1000,2000); f 123412345 1000 2000 -[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | $$g; $$f[0] | [$$f][0][1] | $$f] +[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] "woo, testing!" [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] -def f(x): $$x | $$x; $$f([.], . + [42]) +def f(x): x | x; f([.], . + [42]) [1,2,3] [[[1,2,3]]] [[1,2,3],42]