diff options
author | Nicolas Williams <nico@cryptonector.com> | 2014-02-17 12:28:26 -0600 |
---|---|---|
committer | Nicolas Williams <nico@cryptonector.com> | 2014-02-20 15:33:07 -0600 |
commit | fe29d3d3fa4a147a5103f314bc09287c4c32a81d (patch) | |
tree | 0f4d4c5625016c2631cf6b101436bb8d11bb8501 /execute.c | |
parent | 3d33412e9a88f86510b2dc8afe6ac4e82b1a44df (diff) |
Add `?`, `.[]?`, and `..` operators
Make XPath-like `//a/b` recursive structure traversal easier in jq,
which then becomes:
..|.a?.b?
The `?` operator suppresses errors about . not being an array or object.
The `..` operator is equivalent to calling the new `recurse_down`
built-in, which in turn is equivalent to
recurse(.[]?)
Note that `..a` is not supported; neither is `...a`. That could be add
added, but it doesn't seem worth the trouble of saving the need to type
a '|'.
Diffstat (limited to 'execute.c')
-rw-r--r-- | execute.c | 25 |
1 files changed, 17 insertions, 8 deletions
@@ -503,7 +503,8 @@ jv jq_next(jq_state *jq) { goto do_backtrack; } - case INDEX: { + case INDEX: + case INDEX_OPT: { jv t = stack_pop(jq); jv k = stack_pop(jq); path_append(jq, jv_copy(k)); @@ -511,7 +512,10 @@ jv jq_next(jq_state *jq) { if (jv_is_valid(v)) { stack_push(jq, v); } else { - print_error(jq, v); + if (opcode == INDEX) + print_error(jq, v); + else + jv_free(v); goto do_backtrack; } break; @@ -536,16 +540,18 @@ jv jq_next(jq_state *jq) { } case EACH: + case EACH_OPT: stack_push(jq, jv_number(-1)); // fallthrough - case ON_BACKTRACK(EACH): { + case ON_BACKTRACK(EACH): + case ON_BACKTRACK(EACH_OPT): { int idx = jv_number_value(stack_pop(jq)); jv container = stack_pop(jq); int keep_going, is_last = 0; jv key, value; if (jv_get_kind(container) == JV_KIND_ARRAY) { - if (opcode == EACH) idx = 0; + if (opcode == EACH || opcode == EACH_OPT) idx = 0; else idx = idx + 1; int len = jv_array_length(jv_copy(container)); keep_going = idx < len; @@ -555,7 +561,7 @@ jv jq_next(jq_state *jq) { value = jv_array_get(jv_copy(container), idx); } } else if (jv_get_kind(container) == JV_KIND_OBJECT) { - if (opcode == EACH) idx = jv_object_iter(container); + if (opcode == EACH || opcode == EACH_OPT) idx = jv_object_iter(container); else idx = jv_object_iter_next(container, idx); keep_going = jv_object_iter_valid(container, idx); if (keep_going) { @@ -563,9 +569,12 @@ jv jq_next(jq_state *jq) { value = jv_object_iter_value(container, idx); } } else { - assert(opcode == EACH); - print_error(jq, jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s", - jv_kind_name(jv_get_kind(container))))); + assert(opcode == EACH || opcode == EACH_OPT); + if (opcode == EACH) { + print_error(jq, + jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s", + jv_kind_name(jv_get_kind(container))))); + } keep_going = 0; } |