From ff9a61ead2127fc849ff3a77b63658b8fce8c5c9 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 2 Jul 2014 21:22:53 -0500 Subject: [PATCH] Add `range(init;upto;by)` (fix #317) --- builtin.c | 7 ++++++- docs/content/3.manual/manual.yml | 22 +++++++++++++++++++--- tests/all.test | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/builtin.c b/builtin.c index 6a1d7961..f42b4c94 100644 --- a/builtin.c +++ b/builtin.c @@ -885,6 +885,7 @@ static block bind_bytecoded_builtins(block b) { } } { + // Note that we can now define `range` as a jq-coded function block rangevar = gen_op_var_fresh(STOREV, "rangevar"); block init = BLOCK(gen_op_simple(DUP), gen_call("start", gen_noop()), rangevar); block range = BLOCK(init, @@ -952,7 +953,11 @@ static const char* const jq_builtins[] = { "def test(re; mode): _match_impl(re; mode; true);", "def test(val): if val |type == \"string\" then test(val; null) elif val | type == \"array\" and (val | length) > 1 then test(val[0]; val[1]) elif val | type == \"array\" and (val | length > 0) then test(val[0]; null) else error((val | type) + \" not a string or array\") end;", // "def test(re): _match(re; null; 1);", - + // range/3, with a `by` expression argument + "def range(init; upto; by): " + " def _range: " + " if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; " + " if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto));", }; #undef LIBM_DD diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index 0be5e4b7..aa71bf66 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -815,7 +815,7 @@ sections: input: '[{"foo": "bar"}, [{"foo": "baz"}]]' output: ['[{"foo": "bar"}, {"foo": "baz"}]'] - - title: "`range(upto)`, `range(from;upto)`" + - title: "`range(upto)`, `range(from;upto)` `range(from;upto;by)`" body: | The `range` function produces a range of numbers. `range(4;10)` @@ -823,7 +823,14 @@ sections: are produced as separate outputs. Use `[range(4;10)]` to get a range as an array. - Its first argument can be omitted; it defaults to zero. + The one argument form generates numbers from 0 to the given + number, with an increment of 1. + + The two argument form generates numbers from `from` to `upto` + with an increment of 1. + + The three argument form generates numbers `from` to `upto` + with an increment of `by`. examples: - program: 'range(2;4)' @@ -835,6 +842,15 @@ sections: - program: '[range(4)]' input: 'null' output: ['[0,1,2,3]'] + - program: '[range(0;10;3)]' + input: 'null' + output: ['[0,3,6,9]'] + - program: '[range(0;10;-1)]' + input: 'null' + output: ['[]'] + - program: '[range(0;-5;-1)]' + input: 'null' + output: ['[0,-1,-2,-3,-4]'] - title: "`floor`" body: | @@ -1739,7 +1755,7 @@ sections: then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | - select(. < upto); + select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)' input: 'null' output: ['0,3,6,9'] diff --git a/tests/all.test b/tests/all.test index 3b52ec90..c9dc900c 100644 --- a/tests/all.test +++ b/tests/all.test @@ -202,6 +202,22 @@ null 2 3 +[range(0;10)] +null +[0,1,2,3,4,5,6,7,8,9] + +[range(0;10;3)] +null +[0,3,6,9] + +[range(0;10;-1)] +null +[] + +[range(0;-5;-1)] +null +[0,-1,-2,-3,-4] + # # Slices #