]> granicus.if.org Git - jq/commitdiff
Add `range(init;upto;by)` (fix #317)
authorNicolas Williams <nico@cryptonector.com>
Thu, 3 Jul 2014 02:22:53 +0000 (21:22 -0500)
committerNicolas Williams <nico@cryptonector.com>
Thu, 3 Jul 2014 03:05:33 +0000 (22:05 -0500)
builtin.c
docs/content/3.manual/manual.yml
tests/all.test

index 6a1d7961c240792d1fe19810aac833dfb1d6f9d7..f42b4c949552bc182cf0069679fadc4ba25a5e48 100644 (file)
--- 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
 
index 0be5e4b75435fa51e41ae6e15df1654e14e4fc4c..aa71bf66ceecbe71d0e90c1583ef617eec3acf4a 100644 (file)
@@ -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']
index 3b52ec904d650eb37d1a7e1ec8c11c09f4cbb200..c9dc900c9836716b36de056c26c0b375279450de 100644 (file)
@@ -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
 #