diff options
author | Nicolas Williams <nico@cryptonector.com> | 2017-02-28 21:39:54 -0600 |
---|---|---|
committer | Nicolas Williams <nico@cryptonector.com> | 2017-02-28 21:54:30 -0600 |
commit | 2fcb25716827d92f3056e05a6e0db123e07b64f2 (patch) | |
tree | 4c0005d65f1f6eb278abc836839a3621a4a7d2ee | |
parent | 63791b795a984e977e6a45471731a28af252097e (diff) |
getpath/1 should be a path expression (fix #1358)
It needs to be possible to do something like
getpath($paths[]) += 1
meaning: increment all the paths in . that are listed in $paths[].
In order to do this getpath() needs to update the jq->path and
jq->value_at_path as necessary.
-rw-r--r-- | src/builtin.c | 5 | ||||
-rw-r--r-- | src/execute.c | 22 | ||||
-rw-r--r-- | tests/jq.test | 12 |
3 files changed, 38 insertions, 1 deletions
diff --git a/src/builtin.c b/src/builtin.c index b5140539..578c4417 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1089,7 +1089,10 @@ static jv f_string_implode(jq_state *jq, jv a) { } static jv f_setpath(jq_state *jq, jv a, jv b, jv c) { return jv_setpath(a, b, c); } -static jv f_getpath(jq_state *jq, jv a, jv b) { return jv_getpath(a, b); } +extern jv _jq_path_append(jq_state *, jv, jv, jv); +static jv f_getpath(jq_state *jq, jv a, jv b) { + return _jq_path_append(jq, a, b, jv_getpath(jv_copy(a), jv_copy(b))); +} static jv f_delpaths(jq_state *jq, jv a, jv b) { return jv_delpaths(a, b); } static jv f_has(jq_state *jq, jv a, jv b) { return jv_has(a, b); } diff --git a/src/execute.c b/src/execute.c index d4702103..75dfa012 100644 --- a/src/execute.c +++ b/src/execute.c @@ -246,6 +246,28 @@ static void path_append(jq_state* jq, jv component, jv value_at_path) { } } +/* For f_getpath() */ +jv +_jq_path_append(jq_state *jq, jv v, jv p, jv value_at_path) { + if (jq->subexp_nest != 0 || + jv_get_kind(jq->path) != JV_KIND_ARRAY || + !jv_is_valid(value_at_path)) { + jv_free(v); + jv_free(p); + return value_at_path; + } + if (!jv_identical(v, jv_copy(jq->value_at_path))) { + jv_free(p); + return value_at_path; + } + if (jv_get_kind(p) == JV_KIND_ARRAY) + jq->path = jv_array_concat(jq->path, p); + else + jq->path = jv_array_append(jq->path, p); + jv_free(jq->value_at_path); + return jv_copy(jq->value_at_path = value_at_path); +} + uint16_t* stack_restore(jq_state *jq){ while (!stack_pop_will_free(&jq->stk, jq->fork_top)) { if (stack_pop_will_free(&jq->stk, jq->stk_top)) { diff --git a/tests/jq.test b/tests/jq.test index 2c9cc889..4dad2308 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -842,6 +842,18 @@ def inc(x): x |= .+1; inc(.[].a) [{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}] [{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}] +# #1358, getpath/1 should work in path expressions +.[] | try (getpath(["a",0,"b"]) |= 5) catch . +[null,{"b":0},{"a":0},{"a":null},{"a":[0,1]},{"a":{"b":1}},{"a":[{}]},{"a":[{"c":3}]}] +{"a":[{"b":5}]} +{"b":0,"a":[{"b":5}]} +"Cannot index number with number" +{"a":[{"b":5}]} +"Cannot index number with string \"b\"" +"Cannot index object with number" +{"a":[{"b":5}]} +{"a":[{"c":3,"b":5}]} + .[2][3] = 1 [4] [4, null, [null, null, null, 1]] |