Merge pull request #109 from nicowilliams/no_mutable_globals-rebased

Remove globals/make jq_init/next/teardown() an API
This commit is contained in:
Stephen Dolan committed 2013-05-05 12:29:07 -07:00
commit ab1a97472c
5 files changed
+198 -151

No files matched your search

+39 -2
View File
@@ -37,6 +37,7 @@ jq: $(JQ_SRC) main.c
test: jq_test test: jq_test
valgrind --error-exitcode=1 -q --leak-check=full ./jq_test >/dev/null valgrind --error-exitcode=1 -q --leak-check=full ./jq_test >/dev/null
LIBRARIES=libjq
BINARIES=jq jq_test BINARIES=jq jq_test
PLATFORMS=linux32 linux64 osx32 osx64 win32 win64 PLATFORMS=linux32 linux64 osx32 osx64 win32 win64
@@ -55,6 +56,14 @@ build/win64%: CC='x86_64-w64-mingw32-gcc -m64' EXTRA_CFLAGS=-DJQ_DEFAULT_ENABL
BIN_SUFFIX_win32 = .exe BIN_SUFFIX_win32 = .exe
BIN_SUFFIX_win64 = .exe BIN_SUFFIX_win64 = .exe
LIB_SUFFIX_win32 = .dll
LIB_SUFFIX_win64 = .dll
LIB_SUFFIX_linux32 = .so
LIB_SUFFIX_linux64 = .so
LIB_SUFFIX_osx32 = .so
LIB_SUFFIX_osx64 = .so
ALL_BINARIES=\ ALL_BINARIES=\
$(foreach platform, $(PLATFORMS), \ $(foreach platform, $(PLATFORMS), \
@@ -67,11 +76,27 @@ $(ALL_BINARIES): build/%:
make -B $(BINARIES) CC=$(CC) make -B $(BINARIES) CC=$(CC)
$(foreach binary, $(BINARIES), cp $(binary) $(@D)/$(binary)$(suffix $*);) $(foreach binary, $(BINARIES), cp $(binary) $(@D)/$(binary)$(suffix $*);)
libjq: CFLAGS += -fPIC
libjq: $(JQ_SRC)
$(CC) -shared -Wl,-soname,libjq.so.1 $(CFLAGS) $(CFLAGS_OPT) -o $@ $^
ALL_LIBRARIES=\
$(foreach platform, $(PLATFORMS), \
$(foreach library, $(LIBRARIES), \
build/$(platform)/$(library)$(LIB_SUFFIX_$(platform))))
$(ALL_LIBRARIES): build/%:
mkdir -p $(@D)
echo $(dir $*)
make -B $(LIBRARIES) CC=$(CC)
$(foreach library, $(LIBRARIES), cp $(library) $(@D)/$(library)$(suffix $*);)
binaries: $(ALL_BINARIES) binaries: $(ALL_BINARIES)
libraries: $(ALL_LIBRARIES)
clean: clean:
rm -rf build rm -rf build
rm -f $(BINARIES) *.gen.* rm -f $(LIBRARIES) $(BINARIES) *.gen.*
releasedep: lexer.gen.c parser.gen.c jv_utf8_tables.gen.h releasedep: lexer.gen.c parser.gen.c jv_utf8_tables.gen.h
@@ -87,14 +112,26 @@ tarball: docs/content/2.download/source/jq.tgz
jq.1: docs/content/3.manual/manual.yml jq.1: docs/content/3.manual/manual.yml
( cd docs; bundle exec rake manpage; ) > $@ ( cd docs; bundle exec rake manpage; ) > $@
install: jq jq.1 install: jq jq.1 libjq
install -d -m 0755 $(prefix)/bin install -d -m 0755 $(prefix)/bin
install -d -m 0755 $(prefix)/lib
install -d -m 0755 $(prefix)/include
install -d -m 0755 $(prefix)/include/jq
install -m 0755 jq $(prefix)/bin install -m 0755 jq $(prefix)/bin
ln libjq libjq.so.1
install -m 0755 execute.h $(prefix)/include/jq
install -m 0755 compile.h $(prefix)/include/jq
install -m 0755 jv.h $(prefix)/include/jq
install -m 0755 jv_parse.h $(prefix)/include/jq
install -m 0755 jv_alloc.h $(prefix)/include/jq
install -m 0755 libjq.so.1 $(prefix)/bin
install -m 0644 execute.h $(prefix)/bin
install -d -m 0755 $(mandir)/man1 install -d -m 0755 $(mandir)/man1
install -m 0644 jq.1 $(mandir)/man1 install -m 0644 jq.1 $(mandir)/man1
uninstall: uninstall:
rm -vf $(prefix)/bin/jq rm -vf $(prefix)/bin/jq
rm -vf $(prefix)/lib/libjq.so.1
rm -vf $(mandir)/man1/jq.1 rm -vf $(mandir)/man1/jq.1
+145 -136
View File
@@ -23,24 +23,28 @@ typedef struct {
int pathidx; int pathidx;
} stackval; } stackval;
struct jq_state {
struct forkable_stack data_stk;
struct forkable_stack frame_stk;
struct forkable_stack fork_stk;
jv* pathbuf;
int pathsize; // number of allocated elements
};
jv* pathbuf; int path_push(jq_state *jq, stackval sv, jv val) {
int pathsize; // number of allocated elements
int path_push(stackval sv, jv val) {
int pos = sv.pathidx; int pos = sv.pathidx;
assert(pos <= pathsize); assert(pos <= jq->pathsize);
assert(pos >= 0); assert(pos >= 0);
if (pos == pathsize) { if (pos == jq->pathsize) {
int oldpathsize = pathsize; int oldpathsize = jq->pathsize;
pathsize = oldpathsize ? oldpathsize * 2 : 100; jq->pathsize = oldpathsize ? oldpathsize * 2 : 100;
pathbuf = jv_mem_realloc(pathbuf, sizeof(pathbuf[0]) * pathsize); jq->pathbuf = jv_mem_realloc(jq->pathbuf, sizeof(jq->pathbuf[0]) * jq->pathsize);
for (int i=oldpathsize; i<pathsize; i++) { for (int i=oldpathsize; i<jq->pathsize; i++) {
pathbuf[i] = jv_invalid(); jq->pathbuf[i] = jv_invalid();
} }
} }
jv_free(pathbuf[pos]); jv_free(jq->pathbuf[pos]);
pathbuf[pos] = val; jq->pathbuf[pos] = val;
return pos + 1; return pos + 1;
} }
@@ -57,30 +61,28 @@ stackval stackval_root(jv v) {
return s; return s;
} }
struct forkable_stack data_stk;
typedef struct { typedef struct {
FORKABLE_STACK_HEADER; FORKABLE_STACK_HEADER;
stackval sv; stackval sv;
} data_stk_elem; } data_stk_elem;
void stack_push(stackval val) { void stack_push(jq_state *jq, stackval val) {
assert(jv_is_valid(val.value)); assert(jv_is_valid(val.value));
data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem)); data_stk_elem* s = forkable_stack_push(&jq->data_stk, sizeof(data_stk_elem));
s->sv = val; s->sv = val;
} }
stackval stack_pop() { stackval stack_pop(jq_state *jq) {
data_stk_elem* s = forkable_stack_peek(&data_stk); data_stk_elem* s = forkable_stack_peek(&jq->data_stk);
stackval sv = s->sv; stackval sv = s->sv;
if (!forkable_stack_pop_will_free(&data_stk)) { if (!forkable_stack_pop_will_free(&jq->data_stk)) {
sv.value = jv_copy(sv.value); sv.value = jv_copy(sv.value);
} }
forkable_stack_pop(&data_stk); forkable_stack_pop(&jq->data_stk);
assert(jv_is_valid(sv.value)); assert(jv_is_valid(sv.value));
return sv; return sv;
} }
struct forkable_stack frame_stk;
struct forkpoint { struct forkpoint {
@@ -89,36 +91,35 @@ struct forkpoint {
struct forkable_stack_state saved_call_stack; struct forkable_stack_state saved_call_stack;
}; };
struct forkable_stack fork_stk;
void stack_save(){ void stack_save(jq_state *jq){
struct forkpoint* fork = forkable_stack_push(&fork_stk, sizeof(struct forkpoint)); struct forkpoint* fork = forkable_stack_push(&jq->fork_stk, sizeof(struct forkpoint));
forkable_stack_save(&data_stk, &fork->saved_data_stack); forkable_stack_save(&jq->data_stk, &fork->saved_data_stack);
forkable_stack_save(&frame_stk, &fork->saved_call_stack); forkable_stack_save(&jq->frame_stk, &fork->saved_call_stack);
} }
void stack_switch() { void stack_switch(jq_state *jq) {
struct forkpoint* fork = forkable_stack_peek(&fork_stk); struct forkpoint* fork = forkable_stack_peek(&jq->fork_stk);
forkable_stack_switch(&data_stk, &fork->saved_data_stack); forkable_stack_switch(&jq->data_stk, &fork->saved_data_stack);
forkable_stack_switch(&frame_stk, &fork->saved_call_stack); forkable_stack_switch(&jq->frame_stk, &fork->saved_call_stack);
} }
int stack_restore(){ int stack_restore(jq_state *jq){
while (!forkable_stack_empty(&data_stk) && while (!forkable_stack_empty(&jq->data_stk) &&
forkable_stack_pop_will_free(&data_stk)) { forkable_stack_pop_will_free(&jq->data_stk)) {
jv_free(stack_pop().value); jv_free(stack_pop(jq).value);
} }
while (!forkable_stack_empty(&frame_stk) && while (!forkable_stack_empty(&jq->frame_stk) &&
forkable_stack_pop_will_free(&frame_stk)) { forkable_stack_pop_will_free(&jq->frame_stk)) {
frame_pop(&frame_stk); frame_pop(&jq->frame_stk);
} }
if (forkable_stack_empty(&fork_stk)) { if (forkable_stack_empty(&jq->fork_stk)) {
return 0; return 0;
} else { } else {
struct forkpoint* fork = forkable_stack_peek(&fork_stk); struct forkpoint* fork = forkable_stack_peek(&jq->fork_stk);
forkable_stack_restore(&data_stk, &fork->saved_data_stack); forkable_stack_restore(&jq->data_stk, &fork->saved_data_stack);
forkable_stack_restore(&frame_stk, &fork->saved_call_stack); forkable_stack_restore(&jq->frame_stk, &fork->saved_call_stack);
forkable_stack_pop(&fork_stk); forkable_stack_pop(&jq->fork_stk);
return 1; return 1;
} }
} }
@@ -148,21 +149,21 @@ void print_error(jv value) {
} }
#define ON_BACKTRACK(op) ((op)+NUM_OPCODES) #define ON_BACKTRACK(op) ((op)+NUM_OPCODES)
jv jq_next() { jv jq_next(jq_state *jq) {
jv cfunc_input[MAX_CFUNCTION_ARGS]; jv cfunc_input[MAX_CFUNCTION_ARGS];
assert(!forkable_stack_empty(&frame_stk)); assert(!forkable_stack_empty(&jq->frame_stk));
uint16_t* pc = *frame_current_retaddr(&frame_stk); uint16_t* pc = *frame_current_retaddr(&jq->frame_stk);
frame_pop(&frame_stk); frame_pop(&jq->frame_stk);
assert(!forkable_stack_empty(&frame_stk)); assert(!forkable_stack_empty(&jq->frame_stk));
int backtracking = 0; int backtracking = 0;
while (1) { while (1) {
uint16_t opcode = *pc; uint16_t opcode = *pc;
#if JQ_DEBUG #if JQ_DEBUG
dump_operation(frame_current_bytecode(&frame_stk), pc); dump_operation(frame_current_bytecode(&jq->frame_stk), pc);
printf("\t"); printf("\t");
const struct opcode_description* opdesc = opcode_describe(opcode); const struct opcode_description* opdesc = opcode_describe(opcode);
data_stk_elem* param; data_stk_elem* param;
@@ -170,10 +171,10 @@ jv jq_next() {
if (stack_in == -1) stack_in = pc[1]; if (stack_in == -1) stack_in = pc[1];
for (int i=0; i<stack_in; i++) { for (int i=0; i<stack_in; i++) {
if (i == 0) { if (i == 0) {
param = forkable_stack_peek(&data_stk); param = forkable_stack_peek(&jq->data_stk);
} else { } else {
printf(" | "); printf(" | ");
param = forkable_stack_peek_next(&data_stk, param); param = forkable_stack_peek_next(&jq->data_stk, param);
} }
if (!param) break; if (!param) break;
jv_dump(jv_copy(param->sv.value), 0); jv_dump(jv_copy(param->sv.value), 0);
@@ -194,51 +195,51 @@ jv jq_next() {
default: assert(0 && "invalid instruction"); default: assert(0 && "invalid instruction");
case LOADK: { case LOADK: {
jv v = jv_array_get(jv_copy(frame_current_bytecode(&frame_stk)->constants), *pc++); jv v = jv_array_get(jv_copy(frame_current_bytecode(&jq->frame_stk)->constants), *pc++);
assert(jv_is_valid(v)); assert(jv_is_valid(v));
stack_push(stackval_replace(stack_pop(), v)); stack_push(jq, stackval_replace(stack_pop(jq), v));
break; break;
} }
case DUP: { case DUP: {
stackval v = stack_pop(); stackval v = stack_pop(jq);
stackval v2 = v; stackval v2 = v;
v2.value = jv_copy(v.value); v2.value = jv_copy(v.value);
stack_push(v); stack_push(jq, v);
stack_push(v2); stack_push(jq, v2);
break; break;
} }
case DUP2: { case DUP2: {
stackval keep = stack_pop(); stackval keep = stack_pop(jq);
stackval v = stack_pop(); stackval v = stack_pop(jq);
stackval v2 = v; stackval v2 = v;
v2.value = jv_copy(v.value); v2.value = jv_copy(v.value);
stack_push(v); stack_push(jq, v);
stack_push(keep); stack_push(jq, keep);
stack_push(v2); stack_push(jq, v2);
break; break;
} }
case SWAP: { case SWAP: {
stackval a = stack_pop(); stackval a = stack_pop(jq);
stackval b = stack_pop(); stackval b = stack_pop(jq);
stack_push(a); stack_push(jq, a);
stack_push(b); stack_push(jq, b);
break; break;
} }
case POP: { case POP: {
jv_free(stack_pop().value); jv_free(stack_pop(jq).value);
break; break;
} }
case APPEND: { case APPEND: {
// FIXME paths // FIXME paths
jv v = stack_pop().value; jv v = stack_pop(jq).value;
uint16_t level = *pc++; uint16_t level = *pc++;
uint16_t vidx = *pc++; uint16_t vidx = *pc++;
frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, vidx); jv* var = frame_local_var(fp, vidx);
assert(jv_get_kind(*var) == JV_KIND_ARRAY); assert(jv_get_kind(*var) == JV_KIND_ARRAY);
*var = jv_array_append(*var, v); *var = jv_array_append(*var, v);
@@ -246,15 +247,15 @@ jv jq_next() {
} }
case INSERT: { case INSERT: {
stackval stktop = stack_pop(); stackval stktop = stack_pop(jq);
jv v = stack_pop().value; jv v = stack_pop(jq).value;
jv k = stack_pop().value; jv k = stack_pop(jq).value;
stackval objv = stack_pop(); stackval objv = stack_pop(jq);
assert(jv_get_kind(k) == JV_KIND_STRING); assert(jv_get_kind(k) == JV_KIND_STRING);
assert(jv_get_kind(objv.value) == JV_KIND_OBJECT); assert(jv_get_kind(objv.value) == JV_KIND_OBJECT);
objv.value = jv_object_set(objv.value, k, v); objv.value = jv_object_set(objv.value, k, v);
stack_push(objv); stack_push(jq, objv);
stack_push(stktop); stack_push(jq, stktop);
break; break;
} }
@@ -262,23 +263,23 @@ jv jq_next() {
case LOADV: { case LOADV: {
uint16_t level = *pc++; uint16_t level = *pc++;
uint16_t v = *pc++; uint16_t v = *pc++;
frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, v); jv* var = frame_local_var(fp, v);
#if JQ_DEBUG #if JQ_DEBUG
printf("V%d = ", v); printf("V%d = ", v);
jv_dump(jv_copy(*var), 0); jv_dump(jv_copy(*var), 0);
printf("\n"); printf("\n");
#endif #endif
stack_push(stackval_replace(stack_pop(), jv_copy(*var))); stack_push(jq, stackval_replace(stack_pop(jq), jv_copy(*var)));
break; break;
} }
case STOREV: { case STOREV: {
uint16_t level = *pc++; uint16_t level = *pc++;
uint16_t v = *pc++; uint16_t v = *pc++;
frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
jv* var = frame_local_var(fp, v); jv* var = frame_local_var(fp, v);
stackval val = stack_pop(); stackval val = stack_pop(jq);
#if JQ_DEBUG #if JQ_DEBUG
printf("V%d = ", v); printf("V%d = ", v);
jv_dump(jv_copy(val.value), 0); jv_dump(jv_copy(val.value), 0);
@@ -290,27 +291,27 @@ jv jq_next() {
} }
case GETPATH: { case GETPATH: {
stackval path_end = stack_pop(); stackval path_end = stack_pop(jq);
stackval path_start = stack_pop(); stackval path_start = stack_pop(jq);
jv_free(path_end.value); jv_free(path_end.value);
jv path = jv_array(); jv path = jv_array();
for (int i=path_start.pathidx; i<path_end.pathidx; i++) { for (int i=path_start.pathidx; i<path_end.pathidx; i++) {
path = jv_array_set(path, i, jv_copy(pathbuf[i])); path = jv_array_set(path, i, jv_copy(jq->pathbuf[i]));
} }
stack_push(stackval_replace(path_start, path)); stack_push(jq, stackval_replace(path_start, path));
break; break;
} }
case INDEX: { case INDEX: {
stackval t = stack_pop(); stackval t = stack_pop(jq);
jv k = stack_pop().value; jv k = stack_pop(jq).value;
int pathidx = path_push(t, jv_copy(k)); int pathidx = path_push(jq, t, jv_copy(k));
jv v = jv_get(t.value, k); jv v = jv_get(t.value, k);
if (jv_is_valid(v)) { if (jv_is_valid(v)) {
stackval sv; stackval sv;
sv.value = v; sv.value = v;
sv.pathidx = pathidx; sv.pathidx = pathidx;
stack_push(sv); stack_push(jq, sv);
} else { } else {
print_error(v); print_error(v);
goto do_backtrack; goto do_backtrack;
@@ -327,21 +328,21 @@ jv jq_next() {
case JUMP_F: { case JUMP_F: {
uint16_t offset = *pc++; uint16_t offset = *pc++;
stackval t = stack_pop(); stackval t = stack_pop(jq);
jv_kind kind = jv_get_kind(t.value); jv_kind kind = jv_get_kind(t.value);
if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) { if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) {
pc += offset; pc += offset;
} }
stack_push(t); // FIXME do this better stack_push(jq, t); // FIXME do this better
break; break;
} }
case EACH: case EACH:
stack_push(stackval_root(jv_number(-1))); stack_push(jq, stackval_root(jv_number(-1)));
// fallthrough // fallthrough
case ON_BACKTRACK(EACH): { case ON_BACKTRACK(EACH): {
int idx = jv_number_value(stack_pop().value); int idx = jv_number_value(stack_pop(jq).value);
stackval container = stack_pop(); stackval container = stack_pop(jq);
int keep_going; int keep_going;
jv key, value; jv key, value;
@@ -372,34 +373,34 @@ jv jq_next() {
jv_free(container.value); jv_free(container.value);
goto do_backtrack; goto do_backtrack;
} else { } else {
stack_save(); stack_save(jq);
stack_push(container); stack_push(jq, container);
stack_push(stackval_root(jv_number(idx))); stack_push(jq, stackval_root(jv_number(idx)));
frame_push_backtrack(&frame_stk, pc - 1); frame_push_backtrack(&jq->frame_stk, pc - 1);
stack_switch(); stack_switch(jq);
stackval sv = {value, stackval sv = {value,
path_push(container, key)}; path_push(jq, container, key)};
stack_push(sv); stack_push(jq, sv);
} }
break; break;
} }
do_backtrack: do_backtrack:
case BACKTRACK: { case BACKTRACK: {
if (!stack_restore()) { if (!stack_restore(jq)) {
return jv_invalid(); return jv_invalid();
} }
pc = *frame_current_retaddr(&frame_stk); pc = *frame_current_retaddr(&jq->frame_stk);
frame_pop(&frame_stk); frame_pop(&jq->frame_stk);
backtracking = 1; backtracking = 1;
break; break;
} }
case FORK: { case FORK: {
stack_save(); stack_save(jq);
frame_push_backtrack(&frame_stk, pc - 1); frame_push_backtrack(&jq->frame_stk, pc - 1);
stack_switch(); stack_switch(jq);
pc++; // skip offset this time pc++; // skip offset this time
break; break;
} }
@@ -411,22 +412,22 @@ jv jq_next() {
} }
case YIELD: { case YIELD: {
jv value = stack_pop().value; jv value = stack_pop(jq).value;
frame_push_backtrack(&frame_stk, pc); frame_push_backtrack(&jq->frame_stk, pc);
return value; return value;
} }
case CALL_BUILTIN: { case CALL_BUILTIN: {
int nargs = *pc++; int nargs = *pc++;
stackval top = stack_pop(); stackval top = stack_pop(jq);
cfunc_input[0] = top.value; cfunc_input[0] = top.value;
for (int i = 1; i < nargs; i++) { for (int i = 1; i < nargs; i++) {
cfunc_input[i] = stack_pop().value; cfunc_input[i] = stack_pop(jq).value;
} }
struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; struct cfunction* func = &frame_current_bytecode(&jq->frame_stk)->globals->cfunctions[*pc++];
top.value = cfunction_invoke(func, cfunc_input); top.value = cfunction_invoke(func, cfunc_input);
if (jv_is_valid(top.value)) { if (jv_is_valid(top.value)) {
stack_push(top); stack_push(jq, top);
} else { } else {
print_error(top.value); print_error(top.value);
goto do_backtrack; goto do_backtrack;
@@ -437,24 +438,24 @@ jv jq_next() {
case CALL_JQ: { case CALL_JQ: {
uint16_t nclosures = *pc++; uint16_t nclosures = *pc++;
uint16_t* retaddr = pc + 2 + nclosures*2; uint16_t* retaddr = pc + 2 + nclosures*2;
frame_ptr new_frame = frame_push(&frame_stk, frame_ptr new_frame = frame_push(&jq->frame_stk,
make_closure(&frame_stk, frame_current(&frame_stk), pc), make_closure(&jq->frame_stk, frame_current(&jq->frame_stk), pc),
retaddr); retaddr);
pc += 2; pc += 2;
frame_ptr old_frame = forkable_stack_peek_next(&frame_stk, new_frame); frame_ptr old_frame = forkable_stack_peek_next(&jq->frame_stk, new_frame);
assert(nclosures == frame_self(new_frame)->bc->nclosures); assert(nclosures == frame_self(new_frame)->bc->nclosures);
for (int i=0; i<nclosures; i++) { for (int i=0; i<nclosures; i++) {
*frame_closure_arg(new_frame, i) = make_closure(&frame_stk, old_frame, pc); *frame_closure_arg(new_frame, i) = make_closure(&jq->frame_stk, old_frame, pc);
pc += 2; pc += 2;
} }
pc = frame_current_bytecode(&frame_stk)->code; pc = frame_current_bytecode(&jq->frame_stk)->code;
break; break;
} }
case RET: { case RET: {
pc = *frame_current_retaddr(&frame_stk); pc = *frame_current_retaddr(&jq->frame_stk);
frame_pop(&frame_stk); frame_pop(&jq->frame_stk);
break; break;
} }
} }
@@ -462,33 +463,41 @@ jv jq_next() {
} }
void jq_init(struct bytecode* bc, jv input) { void jq_init(struct bytecode* bc, jv input, jq_state **jq) {
forkable_stack_init(&data_stk, sizeof(stackval) * 100); jq_state *new_jq;
forkable_stack_init(&frame_stk, 1024); new_jq = jv_mem_alloc(sizeof(*new_jq));
forkable_stack_init(&fork_stk, 1024); memset(new_jq, 0, sizeof(*new_jq));
forkable_stack_init(&new_jq->data_stk, sizeof(stackval) * 100);
forkable_stack_init(&new_jq->frame_stk, 1024);
forkable_stack_init(&new_jq->fork_stk, 1024);
stack_push(stackval_root(input)); stack_push(new_jq, stackval_root(input));
struct closure top = {bc, -1}; struct closure top = {bc, -1};
frame_push(&frame_stk, top, 0); frame_push(&new_jq->frame_stk, top, 0);
frame_push_backtrack(&frame_stk, bc->code); frame_push_backtrack(&new_jq->frame_stk, bc->code);
*jq = new_jq;
} }
void jq_teardown() { void jq_teardown(jq_state **jq) {
while (stack_restore()) {} jq_state *old_jq = *jq;
if (old_jq == NULL)
return;
*jq = NULL;
assert(forkable_stack_empty(&fork_stk)); while (stack_restore(old_jq)) {}
assert(forkable_stack_empty(&data_stk));
assert(forkable_stack_empty(&frame_stk));
forkable_stack_free(&fork_stk);
forkable_stack_free(&data_stk);
forkable_stack_free(&frame_stk);
for (int i=0; i<pathsize; i++) { assert(forkable_stack_empty(&old_jq->fork_stk));
jv_free(pathbuf[i]); assert(forkable_stack_empty(&old_jq->data_stk));
assert(forkable_stack_empty(&old_jq->frame_stk));
forkable_stack_free(&old_jq->fork_stk);
forkable_stack_free(&old_jq->data_stk);
forkable_stack_free(&old_jq->frame_stk);
for (int i=0; i<old_jq->pathsize; i++) {
jv_free(old_jq->pathbuf[i]);
} }
jv_mem_free(pathbuf); jv_mem_free(old_jq->pathbuf);
pathbuf = 0; jv_mem_free(old_jq);
pathsize = 0;
} }
struct bytecode* jq_compile(const char* str) { struct bytecode* jq_compile(const char* str) {
+5 -3
View File
@@ -5,9 +5,11 @@
struct bytecode* jq_compile(const char* str); struct bytecode* jq_compile(const char* str);
void jq_init(struct bytecode* bc, jv value); typedef struct jq_state jq_state;
jv jq_next();
void jq_teardown(); void jq_init(struct bytecode* bc, jv value, jq_state **);
jv jq_next(jq_state *);
void jq_teardown(jq_state **);
#endif #endif
+5 -4
View File
@@ -41,6 +41,7 @@ static int skipline(const char* buf) {
static void run_jq_tests() { static void run_jq_tests() {
char buf[4096]; char buf[4096];
int tests = 0, passed = 0, invalid = 0; int tests = 0, passed = 0, invalid = 0;
jq_state *jq = NULL;
while (1) { while (1) {
if (!fgets(buf, sizeof(buf), testdata)) break; if (!fgets(buf, sizeof(buf), testdata)) break;
@@ -59,13 +60,13 @@ static void run_jq_tests() {
fgets(buf, sizeof(buf), testdata); fgets(buf, sizeof(buf), testdata);
jv input = jv_parse(buf); jv input = jv_parse(buf);
if (!jv_is_valid(input)){ invalid++; continue; } if (!jv_is_valid(input)){ invalid++; continue; }
jq_init(bc, input); jq_init(bc, input, &jq);
while (fgets(buf, sizeof(buf), testdata)) { while (fgets(buf, sizeof(buf), testdata)) {
if (skipline(buf)) break; if (skipline(buf)) break;
jv expected = jv_parse(buf); jv expected = jv_parse(buf);
if (!jv_is_valid(expected)){ invalid++; continue; } if (!jv_is_valid(expected)){ invalid++; continue; }
jv actual = jq_next(); jv actual = jq_next(jq);
if (!jv_is_valid(actual)) { if (!jv_is_valid(actual)) {
jv_free(actual); jv_free(actual);
printf("*** Insufficient results\n"); printf("*** Insufficient results\n");
@@ -88,7 +89,7 @@ static void run_jq_tests() {
jv_free(actual); jv_free(actual);
} }
if (pass) { if (pass) {
jv extra = jq_next(); jv extra = jq_next(jq);
if (jv_is_valid(extra)) { if (jv_is_valid(extra)) {
printf("*** Superfluous result: "); printf("*** Superfluous result: ");
jv_dump(extra, 0); jv_dump(extra, 0);
@@ -98,7 +99,7 @@ static void run_jq_tests() {
jv_free(extra); jv_free(extra);
} }
} }
jq_teardown(); jq_teardown(&jq);
bytecode_free(bc); bytecode_free(bc);
passed+=pass; passed+=pass;
} }
+4 -6
View File
@@ -5,11 +5,8 @@
#include <ctype.h> #include <ctype.h>
#include <unistd.h> #include <unistd.h>
#include "compile.h" #include "compile.h"
#include "builtin.h"
#include "jv.h" #include "jv.h"
#include "jv_parse.h" #include "jv_parse.h"
#include "locfile.h"
#include "parser.h"
#include "execute.h" #include "execute.h"
#include "jv_alloc.h" #include "jv_alloc.h"
#include "version.gen.h" #include "version.gen.h"
@@ -63,9 +60,10 @@ static int options = 0;
static struct bytecode* bc; static struct bytecode* bc;
static void process(jv value) { static void process(jv value) {
jq_init(bc, value); jq_state *jq = NULL;
jq_init(bc, value, &jq);
jv result; jv result;
while (jv_is_valid(result = jq_next())) { while (jv_is_valid(result = jq_next(jq))) {
if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) { if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) {
fwrite(jv_string_value(result), 1, jv_string_length(jv_copy(result)), stdout); fwrite(jv_string_value(result), 1, jv_string_length(jv_copy(result)), stdout);
jv_free(result); jv_free(result);
@@ -85,7 +83,7 @@ static void process(jv value) {
printf("\n"); printf("\n");
} }
jv_free(result); jv_free(result);
jq_teardown(); jq_teardown(&jq);
} }
static jv slurp_file(const char* filename) { static jv slurp_file(const char* filename) {