]> granicus.if.org Git - jq/commitdiff
Demote "contains" to a built-in function rather than an operator.
authorStephen Dolan <mu@netsoc.tcd.ie>
Sun, 2 Dec 2012 22:24:02 +0000 (22:24 +0000)
committerStephen Dolan <mu@netsoc.tcd.ie>
Sun, 2 Dec 2012 22:52:38 +0000 (22:52 +0000)
builtin.c
docs/content/3.manual/manual.yml
lexer.l
parser.y
testdata

index f432bea58a0d5c4af267e0bda894a880b24fff32..ab13a2bb105fea7b684b0388805f761a9a737414 100644 (file)
--- a/builtin.c
+++ b/builtin.c
@@ -161,8 +161,7 @@ static jv f_greatereq(jv input, jv a, jv b) {
   return order_cmp(input, a, b, CMP_OP_GREATEREQ);
 }
 
-static jv f_contains(jv input, jv a, jv b) {
-  jv_free(input);
+static jv f_contains(jv a, jv b) {
   jv_kind akind = jv_get_kind(a);
 
   if (akind == jv_get_kind(b)) {
@@ -242,7 +241,7 @@ static struct cfunction function_list[] = {
   {(cfunction_ptr)f_greater, "_greater", 3},
   {(cfunction_ptr)f_lesseq, "_lesseq", 3},
   {(cfunction_ptr)f_greatereq, "_greatereq", 3},
-  {(cfunction_ptr)f_contains, "_contains", 3},
+  {(cfunction_ptr)f_contains, "contains", 2},
   {(cfunction_ptr)f_length, "length", 1},
   {(cfunction_ptr)f_type, "type", 1},
   {(cfunction_ptr)f_add, "add", 1},
index 437afdffada4294f71e7c59cffb607e4af6a2de4..60679ba29410e95dbf2447363e36801ac3a61648 100644 (file)
@@ -487,6 +487,35 @@ sections:
             input: '[1, "1", [1]]'
             output: ['"1"', '"1"', '"[1]"']
 
+      - title: `contains`
+        body: |
+
+          The filter `contains(b)` will produce true if b is
+          completely contained within the input. A string B is
+          contained in a string A if B is a substring of A. An array B
+          is contained in an array A is all elements in B are
+          contained in any element in A. An object B is contained in
+          object A if all of the values in B are contained in the
+          value in A with the same key. All other types are assumed to
+          be contained in each other if they are equal.
+
+        examples:
+          - program: 'contains("bar")'
+            input: '"foobar"'
+            output: ['true']
+          - program: 'contains(["baz", "bar"])'
+            input: '["foobar", "foobaz", "blarp"]'
+            output: ['true']
+          - program: 'contains(["bazzzzz", "bar"])'
+            input: '["foobar", "foobaz", "blarp"]'
+            output: ['false']
+          - program: 'contains({foo: 12, bar: [{barp: 12}]})'
+            input: '{foo: 12, bar:[1,2,{barp:12, blip:13}]}'
+            output: ['true']
+          - program: 'contains({foo: 12, bar: [{barp: 15}]})'
+            input: '{foo: 12, bar:[1,2,{barp:12, blip:13}]}'
+            output: ['false']
+
       - title: "String interpolation - `\(foo)`"
         body: |
 
@@ -522,33 +551,6 @@ sections:
           - program: '.[] == 1'
             input: '[1, 1.0, "1", "banana"]'
             output: ['[true, true, false, false]']
-      - title: `contains`
-        body: |
-
-          The expression 'a contains b' will produce true if b is completely
-          contained within a. A string B is contained in a string A if B is a
-          substring of A. An array B is contained in an array A is all elements
-          in B are contained in any element in A. An object B is contained in
-          object A if all of the values in B are contained in the value in A with
-          the same key. All other types are assumed to be contained in each other
-          if they are equal.
-
-        examples:
-          - program: '. == contains "bar"'
-            input: '"foobar"'
-            output: ['true']
-          - program: '. contains ["baz", "bar"]'
-            input: '["foobar", "foobaz", "blarp"]'
-            output: ['true']
-          - program: '. contains ["bazzzzz", "bar"]'
-            input: '["foobar", "foobaz", "blarp"]'
-            output: ['false']
-          - program: '. contains {foo: 12, bar: [{barp: 12}]}'
-            input: '{foo: 12, bar:[1,2,{barp:12, blip:13}]}'
-            output: ['true']
-          - program: '. contains {foo: 12, bar: [{barp: 15}]}'
-            input: '{foo: 12, bar:[1,2,{barp:12, blip:13}]}'
-            output: ['false']
       - title: if-then-else
         body: |
 
diff --git a/lexer.l b/lexer.l
index 4f2830114ca10014c8b1c5b22cafdf8e435d7279..b09ccce47634a4e1f06c26d627cb62133ab6d698 100644 (file)
--- a/lexer.l
+++ b/lexer.l
@@ -56,7 +56,6 @@ struct lexer_param;
 "//=" { return SETDEFINEDOR; }
 "<=" { return LESSEQ; }
 ">=" { return GREATEREQ; }
-"contains" { return CONTAINS; }
 "."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$"|"<"|">" { return yytext[0];}
 
 "["|"{"|"(" {
index 9c23450605522dec87184aa117f133f95b194bfb..bdee008b122f0d6bd3082a645577b584cc3d7f0c 100644 (file)
--- a/parser.y
+++ b/parser.y
@@ -65,7 +65,6 @@ struct lexer_param;
 %token SETDEFINEDOR "//="
 %token LESSEQ "<="
 %token GREATEREQ ">="
-%token CONTAINS "contains"
 
 %token QQSTRING_START
 %token <literal> QQSTRING_TEXT
@@ -81,7 +80,7 @@ struct lexer_param;
 %nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETDEFINEDOR
 %left OR
 %left AND
-%nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ CONTAINS
+%nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ
 %left '+' '-'
 %left '*' '/'
 
@@ -150,7 +149,6 @@ static block gen_binop(block a, block b, int op) {
   case '>': funcname = "_greater"; break;
   case LESSEQ: funcname = "_lesseq"; break;
   case GREATEREQ: funcname = "_greatereq"; break;
-  case CONTAINS: funcname = "_contains"; break;
   }
   assert(funcname);
 
@@ -295,10 +293,6 @@ Exp ">=" Exp {
   $$ = gen_binop($1, $3, GREATEREQ);
 } |
 
-Exp "contains" Exp {
-  $$ = gen_binop($1, $3, CONTAINS);
-} |
-
 Term { 
   $$ = $1; 
 }
index e6fcaaf7d3641f7766d3515f3cec4859c403cea6..30df927bb4155570596afd66fade71f45c8c7924 100644 (file)
--- a/testdata
+++ b/testdata
@@ -406,27 +406,27 @@ def inc(x): x |= .+1; inc(.[].a)
 [true,false]
 
 # containment operator
-["foo" contains "foo", "foobar" contains "foo", "foo" contains "foobar"]
+[("foo" | contains("foo")), ("foobar" | contains("foo")), ("foo" | contains("foobar"))]
 {}
 [true, true, false]
 
-[[] contains [], [1,2,3] contains [1,2], [1,2,3] contains [3,1], [1,2,3] contains [4], [1,2,3] contains [1,4]]
-{}
+map(.[1] as $needle | .[0] | contains($needle))
+[[[],[]], [[1,2,3], [1,2]], [[1,2,3], [3,1]], [[1,2,3], [4]], [[1,2,3], [1,4]]]
 [true, true, true, false, false]
 
-[["foobar", "foobaz"] contains ["baz", "bar"], ["foobar", "foobaz"] contains ["foo"], ["foobar", "foobaz"] contains ["blap"]]
-{}
+map(.[1] as $needle | .[0] | contains($needle))
+[[["foobar", "foobaz"], ["baz", "bar"]], [["foobar", "foobaz"], ["foo"]], [["foobar", "foobaz"], ["blap"]]]
 [true, true, false]
 
-[{foo: 12, bar:13} contains {foo: 12}, {foo: 12} contains {}, {foo: 12, bar:13} contains {baz:14}]
+[({foo: 12, bar:13} | contains({foo: 12})), ({foo: 12} | contains({})), ({foo: 12, bar:13} | contains({baz:14}))]
 {}
 [true, true, false]
 
-{foo: {baz: 12, blap: {bar: 13}}, bar: 14} contains {bar: 14, foo: {blap: {}}}
+{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {}}})
 {}
 true
 
-{foo: {baz: 12, blap: {bar: 13}}, bar: 14} contains {bar: 14, foo: {blap: {bar: 14}}}
+{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {bar: 14}}})
 {}
 false