diff --git a/c/execute.c b/c/execute.c index 62984ca4..c8505bf6 100644 --- a/c/execute.c +++ b/c/execute.c @@ -466,6 +466,7 @@ void run_program(struct bytecode* bc) { jv_dump(result); printf("\n"); } + jv_free(result); #if JQ_DEBUG printf("end of results\n"); #endif diff --git a/c/jv.c b/c/jv.c index 35ade789..be50c6f6 100644 --- a/c/jv.c +++ b/c/jv.c @@ -37,15 +37,10 @@ jv_kind jv_get_kind(jv x) { return x.kind; } -static const jv JV_INVALID = {JV_KIND_INVALID, {0}}; static const jv JV_NULL = {JV_KIND_NULL, {0}}; static const jv JV_FALSE = {JV_KIND_FALSE, {0}}; static const jv JV_TRUE = {JV_KIND_TRUE, {0}}; -jv jv_invalid() { - return JV_INVALID; -} - jv jv_true() { return JV_TRUE; } @@ -62,6 +57,43 @@ jv jv_bool(int x) { return x ? JV_TRUE : JV_FALSE; } +/* + * Invalid objects, with optional error messages + */ + +typedef struct { + jv_refcnt refcnt; + jv errmsg; +} jvp_invalid; + +jv jv_invalid_with_msg(jv err) { + jv x; + x.kind = JV_KIND_INVALID; + x.val.complex.i[0] = x.val.complex.i[1] = 0; + jvp_invalid* i = malloc(sizeof(jvp_invalid)); + x.val.complex.ptr = &i->refcnt; + i->refcnt.count = 1; + i->errmsg = err; + return x; +} + +jv jv_invalid() { + return jv_invalid_with_msg(jv_null()); +} + +jv jv_invalid_get_message(jv inv) { + jv x = ((jvp_invalid*)inv.val.complex.ptr)->errmsg; + jv_free(inv); + return x; +} + +static void jvp_invalid_free(jv_complex* x) { + if (jvp_refcnt_dec(x)) { + jv_free(((jvp_invalid*)x->ptr)->errmsg); + free(x->ptr); + } +} + /* * Numbers */ @@ -789,7 +821,8 @@ jv jv_object_iter_value(jv object, int iter) { jv jv_copy(jv j) { if (jv_get_kind(j) == JV_KIND_ARRAY || jv_get_kind(j) == JV_KIND_STRING || - jv_get_kind(j) == JV_KIND_OBJECT) { + jv_get_kind(j) == JV_KIND_OBJECT || + jv_get_kind(j) == JV_KIND_INVALID) { jvp_refcnt_inc(&j.val.complex); } return j; @@ -802,6 +835,8 @@ void jv_free(jv j) { jvp_string_free(&j.val.complex); } else if (jv_get_kind(j) == JV_KIND_OBJECT) { jvp_object_free(&j.val.complex); + } else if (jv_get_kind(j) == JV_KIND_INVALID) { + jvp_invalid_free(&j.val.complex); } } diff --git a/c/jv.h b/c/jv.h index 2ec18629..a3a5e794 100644 --- a/c/jv.h +++ b/c/jv.h @@ -14,8 +14,8 @@ typedef enum { JV_KIND_TRUE, JV_KIND_NUMBER, JV_KIND_STRING, - JV_KIND_OBJECT, - JV_KIND_ARRAY + JV_KIND_ARRAY, + JV_KIND_OBJECT } jv_kind; typedef struct { @@ -49,6 +49,9 @@ void jv_free(jv); int jv_equal(jv, jv); jv jv_invalid(); +jv jv_invalid_with_msg(jv); +jv jv_invalid_get_msg(jv); + jv jv_null(); jv jv_true(); jv jv_false(); @@ -99,19 +102,19 @@ jv jv_parse(const char* string); jv jv_parse_sized(const char* string, int length); - - static jv jv_lookup(jv t, jv k) { jv v; if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { v = jv_object_get(t, k); if (!jv_is_valid(v)) { + jv_free(v); v = jv_null(); } } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { // FIXME: don't do lookup for noninteger index v = jv_array_get(t, (int)jv_number_value(k)); if (!jv_is_valid(v)) { + jv_free(v); v = jv_null(); } } else if (jv_get_kind(t) == JV_KIND_NULL && diff --git a/c/jv_parse.c b/c/jv_parse.c index 7a8c811e..9300f311 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -18,8 +18,7 @@ typedef const char* presult; void jv_parser_init(struct jv_parser* p) { p->stack = 0; p->stacklen = p->stackpos = 0; - p->hasnext = 0; - p->next = jv_invalid(); //FIXME: jv_invalid + p->next = jv_invalid(); p->tokenbuf = 0; p->tokenlen = p->tokenpos = 0; p->st = JV_PARSER_NORMAL; @@ -27,15 +26,15 @@ void jv_parser_init(struct jv_parser* p) { } void jv_parser_free(struct jv_parser* p) { - if (p->hasnext) jv_free(p->next); + jv_free(p->next); free(p->stack); free(p->tokenbuf); jvp_dtoa_context_free(&p->dtoa); } static pfunc value(struct jv_parser* p, jv val) { - if (p->hasnext) return "Expected separator between values"; - p->hasnext = 1; + if (jv_is_valid(p->next)) return "Expected separator between values"; + jv_free(p->next); p->next = val; return 0; } @@ -53,40 +52,40 @@ static void push(struct jv_parser* p, jv v) { static pfunc token(struct jv_parser* p, char ch) { switch (ch) { case '[': - if (p->hasnext) return "Expected separator between values"; + if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_array()); break; case '{': - if (p->hasnext) return "Expected separator between values"; + if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_object()); break; case ':': - if (!p->hasnext) + if (!jv_is_valid(p->next)) return "Expected string key before ':'"; if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "':' not as part of an object"; if (jv_get_kind(p->next) != JV_KIND_STRING) return "Object keys must be strings"; push(p, p->next); - p->hasnext = 0; + p->next = jv_invalid(); break; case ',': - if (!p->hasnext) + if (!jv_is_valid(p->next)) return "Expected value before ','"; if (p->stackpos == 0) return "',' not as part of an object or array"; if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); - p->hasnext = 0; + p->next = jv_invalid(); } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; - p->hasnext = 0; + p->next = jv_invalid(); } else { // this case hits on input like {"a", "b"} return "Objects must consist of key:value pairs"; @@ -96,37 +95,37 @@ static pfunc token(struct jv_parser* p, char ch) { case ']': if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) return "Unmatched ']'"; - if (p->hasnext) { + if (jv_is_valid(p->next)) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); - p->hasnext = 0; + p->next = jv_invalid(); } else { if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { // this case hits on input like [1,2,3,] return "Expected another array element"; } } - p->hasnext = 1; + jv_free(p->next); p->next = p->stack[--p->stackpos]; break; case '}': if (p->stackpos == 0) return "Unmatched '}'"; - if (p->hasnext) { + if (jv_is_valid(p->next)) { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) return "Objects must consist of key:value pairs"; assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; - p->hasnext = 0; + p->next = jv_invalid(); } else { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "Unmatched '}'"; if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) return "Expected another key-value pair"; } - p->hasnext = 1; + jv_free(p->next); p->next = p->stack[--p->stackpos]; break; } @@ -320,7 +319,7 @@ static pfunc finish(struct jv_parser* p) { return "Unfinished JSON term"; // this will happen on the empty string - if (!p->hasnext) + if (!jv_is_valid(p->next)) return "Expected JSON value"; return 0; diff --git a/c/jv_parse.h b/c/jv_parse.h index 4dddcf6f..10270766 100644 --- a/c/jv_parse.h +++ b/c/jv_parse.h @@ -4,7 +4,6 @@ struct jv_parser { int stackpos; int stacklen; jv next; - int hasnext; char* tokenbuf; int tokenpos; diff --git a/c/main.c b/c/main.c index 7e274c4a..7c341d8d 100644 --- a/c/main.c +++ b/c/main.c @@ -49,6 +49,7 @@ void run_tests() { assert(jv_is_valid(expected)); jv actual = jq_next(); if (!jv_is_valid(actual)) { + jv_free(actual); printf("Insufficient results\n"); pass = 0; break; @@ -70,6 +71,8 @@ void run_tests() { jv_dump(extra); printf("\n"); pass = 0; + } else { + jv_free(extra); } } jq_teardown();