]> granicus.if.org Git - jq/commitdiff
Clean up function creation API and epilogue generation.
authorStephen Dolan <mu@netsoc.tcd.ie>
Mon, 26 Nov 2012 00:39:01 +0000 (00:39 +0000)
committerStephen Dolan <mu@netsoc.tcd.ie>
Mon, 26 Nov 2012 00:39:01 +0000 (00:39 +0000)
builtin.c
compile.c
compile.h
execute.c
parser.y

index 3d726854a188304e0f5fc5630e9967c12da66483..e1144e3ded339a59b74e5bbe9704bf773331765c 100644 (file)
--- a/builtin.c
+++ b/builtin.c
@@ -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[] = {
index 68d3fb926ece886499915ca901252858ac67d791..b2878b1a7639a92da71b9423f8c69e590836b532 100644 (file)
--- a/compile.c
+++ b/compile.c
@@ -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);
index 9a5f92e5082a9401dd785af03a00af2a186fcd96..d9ed654ebadcd2f72cdfc902bcee9d1352860915 100644 (file)
--- a/compile.h
+++ b/compile.h
@@ -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);
index 93aefc0eb6277bf735ff5334a5d13ced3f3ae1aa..605db552ea9d947032ba9ea7ef4aeeba7ab2dc61 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -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);
index 73943c3811045ab11c2d10ddc9f87397aaaad8ff..e8cbf6d8261b4a94283260cdfba1a1ca1fb07bdd 100644 (file)
--- a/parser.y
+++ b/parser.y
@@ -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);