"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "compile.c" between
jq-1.5.tar.gz and jq-1.6.tar.gz

About: jq is a lightweight and flexible command-line JSON processor.

compile.c  (jq-1.5):compile.c  (jq-1.6)
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE // for strdup #define _GNU_SOURCE // for strdup
#endif #endif
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include "compile.h" #include "compile.h"
#include "bytecode.h" #include "bytecode.h"
#include "locfile.h" #include "locfile.h"
#include "jv_alloc.h" #include "jv_alloc.h"
#include "linker.h" #include "linker.h"
/* /*
The intermediate representation for jq filters is as a sequence of The intermediate representation for jq filters is as a sequence of
struct inst, which form a doubly-linked list via the next and prev struct inst, which form a doubly-linked list via the next and prev
pointers. pointers.
skipping to change at line 160 skipping to change at line 161
block gen_const_global(jv constant, const char *name) { block gen_const_global(jv constant, const char *name) {
assert((opcode_describe(STORE_GLOBAL)->flags & (OP_HAS_CONSTANT | OP_HAS_VARIA BLE | OP_HAS_BINDING)) == assert((opcode_describe(STORE_GLOBAL)->flags & (OP_HAS_CONSTANT | OP_HAS_VARIA BLE | OP_HAS_BINDING)) ==
(OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING)); (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING));
inst* i = inst_new(STORE_GLOBAL); inst* i = inst_new(STORE_GLOBAL);
i->imm.constant = constant; i->imm.constant = constant;
i->symbol = strdup(name); i->symbol = strdup(name);
return inst_block(i); return inst_block(i);
} }
block gen_op_pushk_under(jv constant) {
assert(opcode_describe(PUSHK_UNDER)->flags & OP_HAS_CONSTANT);
inst* i = inst_new(PUSHK_UNDER);
i->imm.constant = constant;
return inst_block(i);
}
int block_is_const(block b) { int block_is_const(block b) {
return (block_is_single(b) && b.first->op == LOADK); return (block_is_single(b) && (b.first->op == LOADK || b.first->op == PUSHK_UN DER));
} }
int block_is_const_inf(block b) { int block_is_const_inf(block b) {
return (block_is_single(b) && b.first->op == LOADK && return (block_is_single(b) && b.first->op == LOADK &&
jv_get_kind(b.first->imm.constant) == JV_KIND_NUMBER && jv_get_kind(b.first->imm.constant) == JV_KIND_NUMBER &&
isinf(jv_number_value(b.first->imm.constant))); isinf(jv_number_value(b.first->imm.constant)));
} }
jv_kind block_const_kind(block b) { jv_kind block_const_kind(block b) {
assert(block_is_const(b)); assert(block_is_const(b));
skipping to change at line 221 skipping to change at line 229
gen_noop(), OP_HAS_VARIABLE); gen_noop(), OP_HAS_VARIABLE);
} }
block gen_op_bound(opcode op, block binder) { block gen_op_bound(opcode op, block binder) {
assert(block_is_single(binder)); assert(block_is_single(binder));
block b = gen_op_unbound(op, binder.first->symbol); block b = gen_op_unbound(op, binder.first->symbol);
b.first->bound_by = binder.first; b.first->bound_by = binder.first;
return b; return b;
} }
block gen_dictpair(block k, block v) {
return BLOCK(gen_subexp(k), gen_subexp(v), gen_op_simple(INSERT));
}
static void inst_join(inst* a, inst* b) { static void inst_join(inst* a, inst* b) {
assert(a && b); assert(a && b);
assert(!a->next); assert(!a->next);
assert(!b->prev); assert(!b->prev);
a->next = b; a->next = b;
b->prev = a; b->prev = a;
} }
void block_append(block* b, block b2) { void block_append(block* b, block b2) {
if (b2.first) { if (b2.first) {
skipping to change at line 481 skipping to change at line 493
imports = jv_array_append(imports, jv_copy(dep->imm.constant)); imports = jv_array_append(imports, jv_copy(dep->imm.constant));
} }
inst_free(dep); inst_free(dep);
} }
if (top) { if (top) {
*body = block_join(inst_block(top),*body); *body = block_join(inst_block(top),*body);
} }
return imports; return imports;
} }
jv block_list_funcs(block body, int omit_underscores) {
jv funcs = jv_object(); // Use the keys for set semantics.
for (inst *pos = body.first; pos != NULL; pos = pos->next) {
if (pos->op == CLOSURE_CREATE || pos->op == CLOSURE_CREATE_C) {
if (pos->symbol != NULL && (!omit_underscores || pos->symbol[0] != '_')) {
funcs = jv_object_set(funcs, jv_string_fmt("%s/%i", pos->symbol, pos->nf
ormals), jv_null());
}
}
}
return jv_keys_unsorted(funcs);
}
block gen_module(block metadata) { block gen_module(block metadata) {
inst* i = inst_new(MODULEMETA); inst* i = inst_new(MODULEMETA);
i->imm.constant = block_const(metadata); i->imm.constant = block_const(metadata);
if (jv_get_kind(i->imm.constant) != JV_KIND_OBJECT) if (jv_get_kind(i->imm.constant) != JV_KIND_OBJECT)
i->imm.constant = jv_object_set(jv_object(), jv_string("metadata"), i->imm.c onstant); i->imm.constant = jv_object_set(jv_object(), jv_string("metadata"), i->imm.c onstant);
block_free(metadata); block_free(metadata);
return inst_block(i); return inst_block(i);
} }
jv block_module_meta(block b) { jv block_module_meta(block b) {
if (b.first != NULL && b.first->op == MODULEMETA) if (b.first != NULL && b.first->op == MODULEMETA)
return jv_copy(b.first->imm.constant); return jv_copy(b.first->imm.constant);
return jv_null(); return jv_null();
} }
block gen_import(const char* name, block metadata, const char* as, int is_data) block gen_import(const char* name, const char* as, int is_data) {
{
assert(metadata.first == NULL || block_is_const(metadata));
inst* i = inst_new(DEPS); inst* i = inst_new(DEPS);
jv meta; jv meta = jv_object();
if (block_is_const(metadata))
meta = block_const(metadata);
else
meta = jv_object();
if (as != NULL) if (as != NULL)
meta = jv_object_set(meta, jv_string("as"), jv_string(as)); meta = jv_object_set(meta, jv_string("as"), jv_string(as));
meta = jv_object_set(meta, jv_string("is_data"), is_data ? jv_true() : jv_fals e()); meta = jv_object_set(meta, jv_string("is_data"), is_data ? jv_true() : jv_fals e());
meta = jv_object_set(meta, jv_string("relpath"), jv_string(name)); meta = jv_object_set(meta, jv_string("relpath"), jv_string(name));
i->imm.constant = meta; i->imm.constant = meta;
block_free(metadata);
return inst_block(i); return inst_block(i);
} }
block gen_import_meta(block import, block metadata) {
assert(block_is_single(import) && import.first->op == DEPS);
assert(block_is_const(metadata) && block_const_kind(metadata) == JV_KIND_OBJEC
T);
inst *i = import.first;
i->imm.constant = jv_object_merge(block_const(metadata), i->imm.constant);
block_free(metadata);
return import;
}
block gen_function(const char* name, block formals, block body) { block gen_function(const char* name, block formals, block body) {
inst* i = inst_new(CLOSURE_CREATE); inst* i = inst_new(CLOSURE_CREATE);
for (inst* i = formals.last; i; i = i->prev) { for (inst* i = formals.last; i; i = i->prev) {
if (i->op == CLOSURE_PARAM_REGULAR) { if (i->op == CLOSURE_PARAM_REGULAR) {
i->op = CLOSURE_PARAM; i->op = CLOSURE_PARAM;
body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body); body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body);
} }
block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0); block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0);
} }
i->subfn = body; i->subfn = body;
skipping to change at line 549 skipping to change at line 576
return gen_function("@lambda", gen_noop(), body); return gen_function("@lambda", gen_noop(), body);
} }
block gen_call(const char* name, block args) { block gen_call(const char* name, block args) {
block b = gen_op_unbound(CALL_JQ, name); block b = gen_op_unbound(CALL_JQ, name);
b.first->arglist = args; b.first->arglist = args;
return b; return b;
} }
block gen_subexp(block a) { block gen_subexp(block a) {
if (block_is_noop(a)) {
return gen_op_simple(DUP);
}
if (block_is_single(a) && a.first->op == LOADK) {
jv c = block_const(a);
block_free(a);
return gen_op_pushk_under(c);
}
return BLOCK(gen_op_simple(SUBEXP_BEGIN), a, gen_op_simple(SUBEXP_END)); return BLOCK(gen_op_simple(SUBEXP_BEGIN), a, gen_op_simple(SUBEXP_END));
} }
block gen_both(block a, block b) { block gen_both(block a, block b) {
block jump = gen_op_targetlater(JUMP); block jump = gen_op_targetlater(JUMP);
block fork = gen_op_target(FORK, jump); block fork = gen_op_target(FORK, jump);
block c = BLOCK(fork, a, jump, b); block c = BLOCK(fork, a, jump, b);
inst_set_target(jump, c); inst_set_target(jump, c);
return c; return c;
} }
block gen_const_object(block expr) { block gen_const_object(block expr) {
int is_const = 1; int is_const = 1;
jv o = jv_object(); jv o = jv_object();
jv k = jv_null(); jv k = jv_null();
jv v = jv_null(); jv v = jv_null();
for (inst *i = expr.first; i; i = i->next) { for (inst *i = expr.first; i; i = i->next) {
if (i->op != SUBEXP_BEGIN || if (i->op == PUSHK_UNDER) {
k = jv_copy(i->imm.constant);
i = i->next;
} else if (i->op != SUBEXP_BEGIN ||
i->next == NULL || i->next == NULL ||
i->next->op != LOADK || i->next->op != LOADK ||
i->next->next == NULL || i->next->next == NULL ||
i->next->next->op != SUBEXP_END) { i->next->next->op != SUBEXP_END) {
is_const = 0; is_const = 0;
break; break;
} else {
k = jv_copy(i->next->imm.constant);
i = i->next->next->next;
} }
k = jv_copy(i->next->imm.constant); if (i != NULL && i->op == PUSHK_UNDER) {
i = i->next->next->next; v = jv_copy(i->imm.constant);
if (i == NULL || i = i->next;
} else if (i == NULL ||
i->op != SUBEXP_BEGIN || i->op != SUBEXP_BEGIN ||
i->next == NULL || i->next == NULL ||
i->next->op != LOADK || i->next->op != LOADK ||
i->next->next == NULL || i->next->next == NULL ||
i->next->next->op != SUBEXP_END) { i->next->next->op != SUBEXP_END) {
is_const = 0; is_const = 0;
break; break;
} else {
v = jv_copy(i->next->imm.constant);
i = i->next->next->next;
} }
v = jv_copy(i->next->imm.constant);
i = i->next->next->next;
if (i == NULL || i->op != INSERT) { if (i == NULL || i->op != INSERT) {
is_const = 0; is_const = 0;
break; break;
} }
if (jv_get_kind(k) != JV_KIND_STRING) {
is_const = 0;
break;
}
o = jv_object_set(o, k, v); o = jv_object_set(o, k, v);
k = jv_null(); k = jv_null();
v = jv_null(); v = jv_null();
} }
if (!is_const) { if (!is_const) {
jv_free(o); jv_free(o);
jv_free(k); jv_free(k);
jv_free(v); jv_free(v);
block b = {0,0}; block b = {0,0};
return b; return b;
skipping to change at line 688 skipping to change at line 735
expr, expr,
tail, tail,
gen_op_bound(LOADVN, array_var)); gen_op_bound(LOADVN, array_var));
} }
static block bind_matcher(block matcher, block body) { static block bind_matcher(block matcher, block body) {
// cannot call block_bind(matcher, body) because that requires // cannot call block_bind(matcher, body) because that requires
// block_has_only_binders(matcher), which is not true here as matchers // block_has_only_binders(matcher), which is not true here as matchers
// may also contain code to extract the correct elements // may also contain code to extract the correct elements
for (inst* i = matcher.first; i; i = i->next) { for (inst* i = matcher.first; i; i = i->next) {
if (i->op == STOREV && !i->bound_by) if ((i->op == STOREV || i->op == STOREVN) && !i->bound_by)
block_bind_subblock(inst_block(i), body, OP_HAS_VARIABLE, 0); block_bind_subblock(inst_block(i), body, OP_HAS_VARIABLE, 0);
} }
return BLOCK(matcher, body); return BLOCK(matcher, body);
} }
// Extract destructuring var names from the block
// *vars should be a jv_object (for set semantics)
static void block_get_unbound_vars(block b, jv *vars) {
assert(vars != NULL);
assert(jv_get_kind(*vars) == JV_KIND_OBJECT);
for (inst* i = b.first; i; i = i->next) {
if (i->subfn.first) {
block_get_unbound_vars(i->subfn, vars);
continue;
}
if ((i->op == STOREV || i->op == STOREVN) && i->bound_by == NULL) {
*vars = jv_object_set(*vars, jv_string(i->symbol), jv_true());
}
}
}
/* Build wrappers around destructuring matchers so that we can chain them
* when we have errors. The approach is as follows:
* DESTRUCTURE_ALT NEXT_MATCHER (unless last matcher)
* existing_matcher_block
* JUMP BODY
*/
static block bind_alternation_matchers(block matchers, block body) {
block preamble = {0};
block altmatchers = {0};
block mb = {0};
block final_matcher = matchers;
// Pass through the matchers to find all destructured names.
while (final_matcher.first && final_matcher.first->op == DESTRUCTURE_ALT) {
block_append(&altmatchers, inst_block(block_take(&final_matcher)));
}
// We don't have any alternations here, so we can use the simplest case.
if (altmatchers.first == NULL) {
return bind_matcher(final_matcher, body);
}
// Collect var names
jv all_vars = jv_object();
block_get_unbound_vars(altmatchers, &all_vars);
block_get_unbound_vars(final_matcher, &all_vars);
// We need a preamble of STOREVs to which to bind the matchers and the body.
jv_object_keys_foreach(all_vars, key) {
preamble = BLOCK(preamble,
gen_op_simple(DUP),
gen_const(jv_null()),
gen_op_unbound(STOREV, jv_string_value(key)));
jv_free(key);
}
jv_free(all_vars);
// Now we build each matcher in turn
for (inst *i = altmatchers.first; i; i = i->next) {
block submatcher = i->subfn;
// If we're successful, jump to the end of the matchers
submatcher = BLOCK(submatcher, gen_op_target(JUMP, final_matcher));
// DESTRUCTURE_ALT to the end of this submatcher so we can skip to the next
one on error
mb = BLOCK(mb, gen_op_target(DESTRUCTURE_ALT, submatcher), submatcher);
// We're done with this inst and we don't want it anymore
// But we can't let it free the submatcher block.
i->subfn.first = i->subfn.last = NULL;
}
// We're done with these insts now.
block_free(altmatchers);
return bind_matcher(preamble, BLOCK(mb, final_matcher, body));
}
block gen_reduce(block source, block matcher, block init, block body) { block gen_reduce(block source, block matcher, block init, block body) {
block res_var = gen_op_var_fresh(STOREV, "reduce"); block res_var = gen_op_var_fresh(STOREV, "reduce");
block loop = BLOCK(gen_op_simple(DUPN), block loop = BLOCK(gen_op_simple(DUPN),
source, source,
bind_matcher(matcher, bind_alternation_matchers(matcher,
BLOCK(gen_op_bound(LOADVN, res_var), BLOCK(gen_op_bound(LOADVN, res_var),
body, body,
gen_op_bound(STOREV, res_var))), gen_op_bound(STOREV, res_var))),
gen_op_simple(BACKTRACK)); gen_op_simple(BACKTRACK));
return BLOCK(gen_op_simple(DUP), return BLOCK(gen_op_simple(DUP),
init, init,
res_var, res_var,
gen_op_target(FORK, loop), gen_op_target(FORK, loop),
loop, loop,
gen_op_bound(LOADVN, res_var)); gen_op_bound(LOADVN, res_var));
} }
block gen_foreach(block source, block matcher, block init, block update, block e xtract) { block gen_foreach(block source, block matcher, block init, block update, block e xtract) {
block output = gen_op_targetlater(JUMP); block output = gen_op_targetlater(JUMP);
block state_var = gen_op_var_fresh(STOREV, "foreach"); block state_var = gen_op_var_fresh(STOREV, "foreach");
block loop = BLOCK(gen_op_simple(DUPN), block loop = BLOCK(gen_op_simple(DUPN),
// get a value from the source expression: // get a value from the source expression:
source, source,
// destructure the value into variable(s) for all the code // destructure the value into variable(s) for all the code
// in the body to see // in the body to see
bind_matcher(matcher, bind_alternation_matchers(matcher,
// load the loop state variable // load the loop state variable
BLOCK(gen_op_bound(LOADVN, state_var), BLOCK(gen_op_bound(LOADVN, state_var),
// generate updated state // generate updated state
update, update,
// save the updated state for value extr action // save the updated state for value extr action
gen_op_simple(DUP), gen_op_simple(DUP),
// save new state // save new state
gen_op_bound(STOREV, state_var), gen_op_bound(STOREV, state_var),
// extract an output... // extract an output...
extract, extract,
skipping to change at line 825 skipping to change at line 945
block gen_or(block a, block b) { block gen_or(block a, block b) {
// a or b = if a then true else (if b then true else false) // a or b = if a then true else (if b then true else false)
return BLOCK(gen_op_simple(DUP), a, return BLOCK(gen_op_simple(DUP), a,
gen_condbranch(BLOCK(gen_op_simple(POP), gen_const(jv_true())), gen_condbranch(BLOCK(gen_op_simple(POP), gen_const(jv_true())),
BLOCK(gen_op_simple(POP), BLOCK(gen_op_simple(POP),
b, b,
gen_condbranch(gen_const(jv_true()), gen_condbranch(gen_const(jv_true()),
gen_const(jv_false()))))); gen_const(jv_false())))));
} }
block gen_destructure_alt(block matcher) {
for (inst *i = matcher.first; i; i = i->next) {
if (i->op == STOREV) {
i->op = STOREVN;
}
}
inst* i = inst_new(DESTRUCTURE_ALT);
i->subfn = matcher;
return inst_block(i);
}
block gen_var_binding(block var, const char* name, block body) { block gen_var_binding(block var, const char* name, block body) {
return gen_destructure(var, gen_op_unbound(STOREV, name), body); return gen_destructure(var, gen_op_unbound(STOREV, name), body);
} }
block gen_array_matcher(block left, block curr) { block gen_array_matcher(block left, block curr) {
int index; int index;
if (block_is_noop(left)) if (block_is_noop(left))
index = 0; index = 0;
else { else {
// `left` was returned by this function, so the third inst is the // `left` was returned by this function, so the third inst is the
// constant containing the previously used index // constant containing the previously used index
assert(left.first->op == DUP); assert(left.first->op == DUP);
assert(left.first->next->op == SUBEXP_BEGIN); assert(left.first->next != NULL);
assert(left.first->next->next->op == LOADK); inst *i = NULL;
index = 1 + (int) jv_number_value(left.first->next->next->imm.constant); if (left.first->next->op == PUSHK_UNDER) {
i = left.first->next;
} else {
assert(left.first->next->op == SUBEXP_BEGIN);
assert(left.first->next->next->op == LOADK);
i = left.first->next->next;
}
index = 1 + (int) jv_number_value(i->imm.constant);
} }
// `left` goes at the end so that the const index is in a predictable place // `left` goes at the end so that the const index is in a predictable place
return BLOCK(gen_op_simple(DUP), gen_subexp(gen_const(jv_number(index))), return BLOCK(gen_op_simple(DUP), gen_subexp(gen_const(jv_number(index))),
gen_op_simple(INDEX), curr, left); gen_op_simple(INDEX), curr, left);
} }
block gen_object_matcher(block name, block curr) { block gen_object_matcher(block name, block curr) {
return BLOCK(gen_op_simple(DUP), gen_subexp(name), gen_op_simple(INDEX), return BLOCK(gen_op_simple(DUP), gen_subexp(name), gen_op_simple(INDEX),
curr); curr);
} }
block gen_destructure(block var, block matcher, block body) { block gen_destructure(block var, block matchers, block body) {
// var bindings can be added after coding the program; leave the TOP first. // var bindings can be added after coding the program; leave the TOP first.
block top = gen_noop(); block top = gen_noop();
if (body.first && body.first->op == TOP) if (body.first && body.first->op == TOP)
top = inst_block(block_take(&body)); top = inst_block(block_take(&body));
return BLOCK(top, gen_op_simple(DUP), var, bind_matcher(matcher, body)); if (matchers.first && matchers.first->op == DESTRUCTURE_ALT) {
block_append(&var, gen_op_simple(DUP));
} else {
top = BLOCK(top, gen_op_simple(DUP));
}
return BLOCK(top, gen_subexp(var), gen_op_simple(POP), bind_alternation_matche
rs(matchers, body));
} }
// Like gen_var_binding(), but bind `break`'s wildcard unbound variable // Like gen_var_binding(), but bind `break`'s wildcard unbound variable
static block gen_wildvar_binding(block var, const char* name, block body) { static block gen_wildvar_binding(block var, const char* name, block body) {
return BLOCK(gen_op_simple(DUP), var, return BLOCK(gen_op_simple(DUP), var,
block_bind(gen_op_unbound(STOREV, name), block_bind(gen_op_unbound(STOREV, name),
body, OP_HAS_VARIABLE | OP_BIND_WILDCARD)); body, OP_HAS_VARIABLE | OP_BIND_WILDCARD));
} }
block gen_cond(block cond, block iftrue, block iffalse) { block gen_cond(block cond, block iftrue, block iffalse) {
return BLOCK(gen_op_simple(DUP), cond, return BLOCK(gen_op_simple(DUP), BLOCK(gen_subexp(cond), gen_op_simple(POP)),
gen_condbranch(BLOCK(gen_op_simple(POP), iftrue), gen_condbranch(BLOCK(gen_op_simple(POP), iftrue),
BLOCK(gen_op_simple(POP), iffalse))); BLOCK(gen_op_simple(POP), iffalse)));
} }
block gen_try_handler(block handler) { block gen_try_handler(block handler) {
// Quite a pain just to hide jq's internal errors. // Quite a pain just to hide jq's internal errors.
return gen_cond(// `if type=="object" and .__jq return gen_cond(// `if type=="object" and .__jq
gen_and(gen_call("_equal", gen_and(gen_call("_equal",
BLOCK(gen_lambda(gen_const(jv_string("object" ))), BLOCK(gen_lambda(gen_const(jv_string("object" ))),
gen_lambda(gen_noop()))), gen_lambda(gen_noop()))),
skipping to change at line 962 skipping to change at line 1106
static int count_cfunctions(block b) { static int count_cfunctions(block b) {
int n = 0; int n = 0;
for (inst* i = b.first; i; i = i->next) { for (inst* i = b.first; i; i = i->next) {
if (i->op == CLOSURE_CREATE_C) n++; if (i->op == CLOSURE_CREATE_C) n++;
n += count_cfunctions(i->subfn); n += count_cfunctions(i->subfn);
} }
return n; return n;
} }
#ifndef WIN32
extern char **environ;
#endif
static jv
make_env(jv env)
{
if (jv_is_valid(env))
return jv_copy(env);
jv r = jv_object();
if (environ == NULL)
return r;
for (size_t i = 0; environ[i] != NULL; i++) {
const char *eq;
if ((eq = strchr(environ[i], '=')) == NULL)
r = jv_object_delete(r, jv_string(environ[i]));
else
r = jv_object_set(r, jv_string_sized(environ[i], eq - environ[i]), jv_stri
ng(eq + 1));
}
return jv_copy(r);
}
// Expands call instructions into a calling sequence // 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; int errors = 0;
block ret = gen_noop(); block ret = gen_noop();
for (inst* curr; (curr = block_take(b));) { for (inst* curr; (curr = block_take(b));) {
if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) { if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) {
if (!curr->bound_by) { if (!curr->bound_by && curr->op == LOADV && strcmp(curr->symbol, "ENV") ==
0) {
curr->op = LOADK;
*env = curr->imm.constant = make_env(*env);
} else if (!curr->bound_by && curr->op == LOADV && jv_object_has(jv_copy(a
rgs), 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') 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 out side labeled control structure"); locfile_locate(curr->locfile, curr->source, "jq: error: break used out side labeled control structure");
else if (curr->op == LOADV)
locfile_locate(curr->locfile, curr->source, "jq: error: $%s is not def
ined", curr->symbol);
else else
locfile_locate(curr->locfile, curr->source, "jq: error: %s/%d is not d efined", curr->symbol, block_count_actuals(curr->arglist)); locfile_locate(curr->locfile, curr->source, "jq: error: %s/%d is not d efined", curr->symbol, block_count_actuals(curr->arglist));
errors++; errors++;
// don't process this instruction if it's not well-defined // don't process this instruction if it's not well-defined
ret = BLOCK(ret, inst_block(curr)); ret = BLOCK(ret, inst_block(curr));
continue; continue;
} }
} }
block prelude = gen_noop(); block prelude = gen_noop();
skipping to change at line 1023 skipping to change at line 1198
break; break;
} }
case CLOSURE_CREATE_C: { case CLOSURE_CREATE_C: {
for (inst* i; (i = block_take(&curr->arglist)); ) { for (inst* i; (i = block_take(&curr->arglist)); ) {
assert(i->op == CLOSURE_CREATE); // FIXME assert(i->op == CLOSURE_CREATE); // FIXME
block body = i->subfn; block body = i->subfn;
i->subfn = gen_noop(); i->subfn = gen_noop();
inst_free(i); inst_free(i);
// arguments should be pushed in reverse order, prepend them to prelud e // arguments should be pushed in reverse order, prepend them to prelud e
errors += expand_call_arglist(&body); errors += expand_call_arglist(&body, args, env);
prelude = BLOCK(gen_subexp(body), prelude); prelude = BLOCK(gen_subexp(body), prelude);
actual_args++; actual_args++;
} }
assert(curr->op == CALL_JQ); assert(curr->op == CALL_JQ);
curr->op = CALL_BUILTIN; curr->op = CALL_BUILTIN;
curr->imm.intval = actual_args + 1 /* include the implicit input in arg count */; curr->imm.intval = actual_args + 1 /* include the implicit input in arg count */;
assert(curr->bound_by->op == CLOSURE_CREATE_C); assert(curr->bound_by->op == CLOSURE_CREATE_C);
desired_args = curr->bound_by->imm.cfunc->nargs - 1; desired_args = curr->bound_by->imm.cfunc->nargs - 1;
assert(!curr->arglist.first); assert(!curr->arglist.first);
break; break;
skipping to change at line 1045 skipping to change at line 1220
} }
assert(actual_args == desired_args); // because now handle this above assert(actual_args == desired_args); // because now handle this above
} }
ret = BLOCK(ret, prelude, inst_block(curr)); ret = BLOCK(ret, prelude, inst_block(curr));
} }
*b = ret; *b = ret;
return errors; 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 errors = 0;
int pos = 0; int pos = 0;
int var_frame_idx = 0; int var_frame_idx = 0;
bc->nsubfunctions = 0; bc->nsubfunctions = 0;
errors += expand_call_arglist(&b); errors += expand_call_arglist(&b, args, env);
b = BLOCK(b, gen_op_simple(RET)); b = BLOCK(b, gen_op_simple(RET));
jv localnames = jv_array(); jv localnames = jv_array();
for (inst* curr = b.first; curr; curr = curr->next) { for (inst* curr = b.first; curr; curr = curr->next) {
if (!curr->next) assert(curr == b.last); if (!curr->next) assert(curr == b.last);
int length = opcode_describe(curr->op)->length; int length = opcode_describe(curr->op)->length;
if (curr->op == CALL_JQ) { if (curr->op == CALL_JQ) {
for (inst* arg = curr->arglist.first; arg; arg = arg->next) { for (inst* arg = curr->arglist.first; arg; arg = arg->next) {
length += 2; length += 2;
} }
} }
skipping to change at line 1095 skipping to change at line 1270
} }
if (pos > 0xFFFF) { if (pos > 0xFFFF) {
// too long for program counter to fit in uint16_t // too long for program counter to fit in uint16_t
locfile_locate(lf, UNKNOWN_LOCATION, locfile_locate(lf, UNKNOWN_LOCATION,
"function compiled to %d bytes which is too long", pos); "function compiled to %d bytes which is too long", pos);
errors++; errors++;
} }
bc->codelen = pos; bc->codelen = pos;
bc->debuginfo = jv_object_set(bc->debuginfo, jv_string("locals"), localnames); bc->debuginfo = jv_object_set(bc->debuginfo, jv_string("locals"), localnames);
if (bc->nsubfunctions) { if (bc->nsubfunctions) {
bc->subfunctions = jv_mem_alloc(sizeof(struct bytecode*) * bc->nsubfunctions ); bc->subfunctions = jv_mem_calloc(sizeof(struct bytecode*), bc->nsubfunctions );
for (inst* curr = b.first; curr; curr = curr->next) { for (inst* curr = b.first; curr; curr = curr->next) {
if (curr->op == CLOSURE_CREATE) { if (curr->op == CLOSURE_CREATE) {
struct bytecode* subfn = jv_mem_alloc(sizeof(struct bytecode)); struct bytecode* subfn = jv_mem_alloc(sizeof(struct bytecode));
bc->subfunctions[curr->imm.intval] = subfn; bc->subfunctions[curr->imm.intval] = subfn;
subfn->globals = bc->globals; subfn->globals = bc->globals;
subfn->parent = bc; subfn->parent = bc;
subfn->nclosures = 0; subfn->nclosures = 0;
subfn->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_stri ng(curr->symbol)); subfn->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_stri ng(curr->symbol));
jv params = jv_array(); jv params = jv_array();
for (inst* param = curr->arglist.first; param; param = param->next) { for (inst* param = curr->arglist.first; param; param = param->next) {
assert(param->op == CLOSURE_PARAM); assert(param->op == CLOSURE_PARAM);
assert(param->bound_by == param); assert(param->bound_by == param);
param->imm.intval = subfn->nclosures++; param->imm.intval = subfn->nclosures++;
param->compiled = subfn; param->compiled = subfn;
params = jv_array_append(params, jv_string(param->symbol)); params = jv_array_append(params, jv_string(param->symbol));
} }
subfn->debuginfo = jv_object_set(subfn->debuginfo, jv_string("params"), params); 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(); curr->subfn = gen_noop();
} }
} }
} else { } else {
bc->subfunctions = 0; bc->subfunctions = 0;
} }
uint16_t* code = jv_mem_alloc(sizeof(uint16_t) * bc->codelen); uint16_t* code = jv_mem_calloc(sizeof(uint16_t), bc->codelen);
bc->code = code; bc->code = code;
pos = 0; pos = 0;
jv constant_pool = jv_array(); jv constant_pool = jv_array();
int maxvar = -1; int maxvar = -1;
if (!errors) for (inst* curr = b.first; curr; curr = curr->next) { if (!errors) for (inst* curr = b.first; curr; curr = curr->next) {
const struct opcode_description* op = opcode_describe(curr->op); const struct opcode_description* op = opcode_describe(curr->op);
if (op->length == 0) if (op->length == 0)
continue; continue;
code[pos++] = curr->op; code[pos++] = curr->op;
assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM); assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM);
skipping to change at line 1178 skipping to change at line 1353
} else if (op->length > 1) { } else if (op->length > 1) {
assert(0 && "codegen not implemented for this operation"); assert(0 && "codegen not implemented for this operation");
} }
} }
bc->constants = constant_pool; bc->constants = constant_pool;
bc->nlocals = maxvar + 2; // FIXME: frames of size zero? bc->nlocals = maxvar + 2; // FIXME: frames of size zero?
block_free(b); block_free(b);
return errors; 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)); struct bytecode* bc = jv_mem_alloc(sizeof(struct bytecode));
bc->parent = 0; bc->parent = 0;
bc->nclosures = 0; bc->nclosures = 0;
bc->globals = jv_mem_alloc(sizeof(struct symbol_table)); bc->globals = jv_mem_alloc(sizeof(struct symbol_table));
int ncfunc = count_cfunctions(b); int ncfunc = count_cfunctions(b);
bc->globals->ncfunctions = 0; bc->globals->ncfunctions = 0;
bc->globals->cfunctions = jv_mem_alloc(sizeof(struct cfunction) * ncfunc); bc->globals->cfunctions = jv_mem_calloc(sizeof(struct cfunction), ncfunc);
bc->globals->cfunc_names = jv_array(); bc->globals->cfunc_names = jv_array();
bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null()); 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); assert(bc->globals->ncfunctions == ncfunc);
if (nerrors > 0) { if (nerrors > 0) {
bytecode_free(bc); bytecode_free(bc);
*out = 0; *out = 0;
} else { } else {
*out = bc; *out = bc;
} }
return nerrors; return nerrors;
} }
 End of changes. 38 change blocks. 
36 lines changed or deleted 222 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)