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);
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");
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++;
}
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) {
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();
}
}
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;
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);
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);
}
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) {