]> granicus.if.org Git - jq/commitdiff
fixup
authorNicolas Williams <nico@cryptonector.com>
Sun, 26 Feb 2017 22:12:57 +0000 (16:12 -0600)
committerNicolas Williams <nico@cryptonector.com>
Sun, 26 Feb 2017 22:12:57 +0000 (16:12 -0600)
src/compile.c
src/compile.h
src/execute.c

index 8e2d09f27ec4b74d4957e10cc317d70a92b2c4fe..3b18babde41cd3dee412ac9e7064f4156134ad9c 100644 (file)
@@ -1002,16 +1002,8 @@ static int count_cfunctions(block b) {
 extern const char **environ;
 #endif
 
-static jv env = {JV_KIND_INVALID, 0, 0, 0, {0}};
-
-static void
-free_env(void)
-{
-  jv_free(env);
-}
-
 static jv
-make_env(void)
+make_env(jv env)
 {
   if (jv_is_valid(env))
     return jv_copy(env);
@@ -1026,19 +1018,21 @@ make_env(void)
     else
       r = jv_object_set(r, jv_string_sized(environ[i], eq - environ[i]), jv_string(eq + 1));
   }
-  atexit(free_env);
-  return (env = jv_copy(r));
+  return jv_copy(r);
 }
 
 // Expands call instructions into a calling sequence
-static int expand_call_arglist(block* b) {
+static int expand_call_arglist(block* b, jv args, jv *env) {
   int errors = 0;
   block ret = gen_noop();
   for (inst* curr; (curr = block_take(b));) {
     if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) {
       if (!curr->bound_by && curr->op == LOADV && strcmp(curr->symbol, "ENV") == 0) {
         curr->op = LOADK;
-        curr->imm.constant = make_env();
+        *env = curr->imm.constant = make_env(*env);
+      } else if (!curr->bound_by && curr->op == LOADV && jv_object_has(jv_copy(args), jv_string(curr->symbol))) {
+        curr->op = LOADK;
+        curr->imm.constant = jv_object_get(jv_copy(args), jv_string(curr->symbol));
       } else if (!curr->bound_by) {
         if (curr->symbol[0] == '*' && curr->symbol[1] >= '1' && curr->symbol[1] <= '3' && curr->symbol[2] == '\0')
           locfile_locate(curr->locfile, curr->source, "jq: error: break used outside labeled control structure");
@@ -1096,7 +1090,7 @@ static int expand_call_arglist(block* b) {
           i->subfn = gen_noop();
           inst_free(i);
           // arguments should be pushed in reverse order, prepend them to prelude
-          errors += expand_call_arglist(&body);
+          errors += expand_call_arglist(&body, args, env);
           prelude = BLOCK(gen_subexp(body), prelude);
           actual_args++;
         }
@@ -1118,12 +1112,12 @@ static int expand_call_arglist(block* b) {
   return errors;
 }
 
-static int compile(struct bytecode* bc, block b, struct locfile* lf) {
+static int compile(struct bytecode* bc, block b, struct locfile* lf, jv args, jv *env) {
   int errors = 0;
   int pos = 0;
   int var_frame_idx = 0;
   bc->nsubfunctions = 0;
-  errors += expand_call_arglist(&b);
+  errors += expand_call_arglist(&b, args, env);
   b = BLOCK(b, gen_op_simple(RET));
   jv localnames = jv_array();
   for (inst* curr = b.first; curr; curr = curr->next) {
@@ -1186,7 +1180,7 @@ static int compile(struct bytecode* bc, block b, struct locfile* lf) {
           params = jv_array_append(params, jv_string(param->symbol));
         }
         subfn->debuginfo = jv_object_set(subfn->debuginfo, jv_string("params"), params);
-        errors += compile(subfn, curr->subfn, lf);
+        errors += compile(subfn, curr->subfn, lf, args, env);
         curr->subfn = gen_noop();
       }
     }
@@ -1251,7 +1245,7 @@ static int compile(struct bytecode* bc, block b, struct locfile* lf) {
   return errors;
 }
 
-int block_compile(block b, struct bytecode** out, struct locfile* lf) {
+int block_compile(block b, struct bytecode** out, struct locfile* lf, jv args) {
   struct bytecode* bc = jv_mem_alloc(sizeof(struct bytecode));
   bc->parent = 0;
   bc->nclosures = 0;
@@ -1261,7 +1255,10 @@ int block_compile(block b, struct bytecode** out, struct locfile* lf) {
   bc->globals->cfunctions = jv_mem_alloc(sizeof(struct cfunction) * ncfunc);
   bc->globals->cfunc_names = jv_array();
   bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null());
-  int nerrors = compile(bc, b, lf);
+  jv env = jv_invalid();
+  int nerrors = compile(bc, b, lf, args, &env);
+  jv_free(args);
+  jv_free(env);
   assert(bc->globals->ncfunctions == ncfunc);
   if (nerrors > 0) {
     bytecode_free(bc);
index 60765515d691df6a0d3623938e6f1669e5908ad0..b341ccf70353633d6259a9abad55ffee156273ad 100644 (file)
@@ -77,7 +77,7 @@ block block_drop_unreferenced(block body);
 jv block_take_imports(block* body);
 jv block_list_funcs(block body, int omit_underscores);
 
-int block_compile(block, struct bytecode**, struct locfile*);
+int block_compile(block, struct bytecode**, struct locfile*, jv);
 
 void block_free(block);
 
index e364da4639ecc062912c0a4760855461aee37f48..bc39c0c9ee80eaada0911469d67b396c762a5e03 100644 (file)
@@ -1066,6 +1066,23 @@ static struct bytecode *optimize(struct bytecode *bc) {
   return optimize_code(bc);
 }
 
+static jv
+args2obj(jv args)
+{
+  if (jv_get_kind(args) == JV_KIND_OBJECT)
+    return args;
+  assert(jv_get_kind(args) == JV_KIND_ARRAY);
+  jv r = jv_object();
+  jv kk = jv_string("name");
+  jv vk = jv_string("value");
+  jv_array_foreach(args, i, v)
+    r = jv_object_set(r, jv_object_get(jv_copy(v), kk), jv_object_get(v, vk));
+  jv_free(args);
+  jv_free(kk);
+  jv_free(vk);
+  return r;
+}
+
 int jq_compile_args(jq_state *jq, const char* str, jv args) {
   jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
   assert(jv_get_kind(args) == JV_KIND_ARRAY || jv_get_kind(args) == JV_KIND_OBJECT);
@@ -1079,49 +1096,21 @@ int jq_compile_args(jq_state *jq, const char* str, jv args) {
   }
   int nerrors = load_program(jq, locations, &program);
   if (nerrors == 0) {
-    /*
-     * jq_compile_args() is a public function.  It should always have
-     * been the case that args was an object, but originally it was an
-     * array.
-     *
-     * We have to do an O(N) binding operation for each argument given.
-     *
-     * The best way to address this might be to have a bind function
-     * that takes an object instead of a const block and a varname.
-     *
-     * However, with `--args` this can be avoided, as one can have a
-     * single such binding then: $ARGS.
-     */
-    if (jv_get_kind(args) == JV_KIND_ARRAY) {
-      jv_array_foreach(args, i, arg) {
-        jv name = jv_object_get(jv_copy(arg), jv_string("name"));
-        jv value = jv_object_get(arg, jv_string("value"));
-        program = gen_var_binding(gen_const(value), jv_string_value(name), program);
-        jv_free(name);
-      }
-    } else if (jv_get_kind(args) == JV_KIND_OBJECT) {
-      jv_object_foreach(args, name, value) {
-        program = gen_var_binding(gen_const(value), jv_string_value(name), program);
-        jv_free(name);
-      }
-    }
-
     nerrors = builtins_bind(jq, &program);
     if (nerrors == 0) {
-      nerrors = block_compile(program, &jq->bc, locations);
+      nerrors = block_compile(program, &jq->bc, locations, args = args2obj(args));
     }
   }
   if (nerrors)
     jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error"));
   if (jq->bc)
     jq->bc = optimize(jq->bc);
-  jv_free(args);
   locfile_free(locations);
   return jq->bc != NULL;
 }
 
 int jq_compile(jq_state *jq, const char* str) {
-  return jq_compile_args(jq, str, jv_array());
+  return jq_compile_args(jq, str, jv_object());
 }
 
 jv jq_get_jq_origin(jq_state *jq) {