Merge pull request #109 from nicowilliams/no_mutable_globals-rebased
Remove globals/make jq_init/next/teardown() an API
This commit is contained in:
commit
ab1a97472c
5 files changed
+198
-151
No files matched your search
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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,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
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in new issue
Block a user