summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2014-12-12 17:35:59 -0600
committerNicolas Williams <nico@cryptonector.com>2014-12-12 17:35:59 -0600
commitbe11b2768f9bbeb12f9d849e1e3d07edab3ca652 (patch)
tree894031839b8d6485885e4920d89eb28ad017ea1e
parent2075bec60fd57169b7bf6a440bcf05fbf290ffe9 (diff)
Add until(cond; next); fix #639
-rw-r--r--builtin.c4
-rw-r--r--docs/content/3.manual/manual.yml18
-rw-r--r--tests/all.test4
3 files changed, 26 insertions, 0 deletions
diff --git a/builtin.c b/builtin.c
index 0629ca99..dc355353 100644
--- a/builtin.c
+++ b/builtin.c
@@ -1090,6 +1090,10 @@ static const char* const jq_builtins[] = {
" def _while: "
" if cond then ., (update | _while) else empty end; "
" try _while catch if .==\"break\" then empty else . end;",
+ "def until(cond; next): "
+ " def _until: "
+ " if cond then . else (next|_until) end;"
+ " _until;",
"def limit($n; exp): if $n < 0 then exp else foreach exp as $item ([$n, null]; if .[0] < 1 then break else [.[0] -1, $item] end; .[1]) end;",
"def first(g): foreach g as $item ([false, null]; if .[0]==true then break else [true, $item] end; .[1]);",
"def last(g): reduce g as $item (null; $item);",
diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml
index ea0514ed..42c6c98c 100644
--- a/docs/content/3.manual/manual.yml
+++ b/docs/content/3.manual/manual.yml
@@ -1270,6 +1270,24 @@ sections:
input: '1'
output: ['[1,2,4,8,16,32,64]']
+ - title: "`until(cond; next)`"
+ body: |
+
+ The `until(cond; next)` function allows you to repeatedly
+ apply the expression `next`, initially to `.` then to its own
+ output, until `cond` is true. For example, this can be used
+ to implement a factorial function (see below).
+
+ Note that `until(cond; next)` is internally defined as a
+ recursive jq function. Recursive calls within `until()` will
+ not consume additional memory if `next` produces at most one
+ output for each input. See advanced topics below.
+
+ examples:
+ - program: '[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]'
+ input: '4'
+ output: ['24']
+
- title: "`recurse(f)`, `recurse`, `recurse(f; condition)`, `recurse_down`"
body: |
diff --git a/tests/all.test b/tests/all.test
index c4c3b0df..8d27d331 100644
--- a/tests/all.test
+++ b/tests/all.test
@@ -250,6 +250,10 @@ null
1
[1,2,4,8]
+[.[]|[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]]
+[1,2,3,4,5]
+[1,2,6,24,120]
+
[foreach .[] as $item ([3, null]; if .[0] < 1 then break else [.[0] -1, $item] end; .[1])]
[11,22,33,44,55,66,77,88,99]
[11,22,33]