]> granicus.if.org Git - jq/commitdiff
Remove syntax distinction between builtin and user calls
authorStephen Dolan <mu@netsoc.tcd.ie>
Mon, 27 Aug 2012 10:19:42 +0000 (11:19 +0100)
committerStephen Dolan <mu@netsoc.tcd.ie>
Mon, 27 Aug 2012 10:19:42 +0000 (11:19 +0100)
c/compile.c
c/compile.h
c/execute.c
c/main.c
c/opcode.c
c/opcode_list.h
c/parser.y
c/testdata

index 93f7188809d272da3652ef322050386949502bde..f9f738d8f7832139eac4bc3e66c51cfecca3695b 100644 (file)
@@ -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; cfunc<t->ncfunctions; 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; i<nargs; i++) {
         curr = curr->next;
         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;
 }
 
index 2ce02c0ea11a67373332264296338b816ecf5ac9..4c0a3a17aefebb1da1bf3c7e9473473ee22f505c 100644 (file)
@@ -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);
+
+
index f9e2570c24a9f2f246ee3c0735ab6b5f5cf8e9cc..75aaec09c6dafd387bfb1cdf950e0705e6a0d6f7 100644 (file)
@@ -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;
index 66984842d6923cd59a43c200e09dc706ab44fe08..c03b5a99378a8c0acaef6b5c33e4a72d4a3ff7ed 100644 (file)
--- 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");
index 62624c92eab530d7e191e825d328c1f52a0d22db..bc259c2285215e30b81ea87f4d9fe135878c9278 100644 (file)
@@ -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) \
index dde072262dd2958800fbc7838b80348343bd1d58..268025e8490085934c3edbb541becb2f974f76d0 100644 (file)
@@ -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)
index 31c708653d672ca88cbf82ee9b9431b6872b5634..5ec03892b04ff6b307b2442f310623d66e07980f 100644 (file)
@@ -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)));
 }
 
index 1d8420d6c9adc54d5a6f3eeb9087eaad38ff7796..6e40b9ae1fa00c6f51d9b2b8b1bb43d983eea193 100644 (file)
@@ -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]