mirror of
https://github.com/stedolan/jq.git
synced 2024-05-11 05:55:39 +00:00
Merge pull request #36 from stroan/contains-operator
Implemented contains operator
This commit is contained in:
16
builtin.c
16
builtin.c
@@ -161,6 +161,21 @@ static void f_greatereq(jv input[], jv output[]) {
|
||||
order_cmp(input, output, CMP_OP_GREATEREQ);
|
||||
}
|
||||
|
||||
static void f_contains(jv input[], jv output[]) {
|
||||
jv_free(input[0]);
|
||||
jv a = input[2];
|
||||
jv b = input[1];
|
||||
jv_kind akind = jv_get_kind(a);
|
||||
|
||||
if (akind == jv_get_kind(b)) {
|
||||
output[0] = jv_bool(jv_contains(a, b));
|
||||
} else {
|
||||
output[0] = jv_invalid_with_msg(jv_string_fmt("Can only check containment of values of the same type."));
|
||||
jv_free(a);
|
||||
jv_free(b);
|
||||
}
|
||||
}
|
||||
|
||||
static void f_tonumber(jv input[], jv output[]) {
|
||||
if (jv_get_kind(input[0]) == JV_KIND_NUMBER) {
|
||||
output[0] = input[0];
|
||||
@@ -294,6 +309,7 @@ static struct cfunction function_list[] = {
|
||||
{f_greater, "_greater", CALL_BUILTIN_3_1},
|
||||
{f_lesseq, "_lesseq", CALL_BUILTIN_3_1},
|
||||
{f_greatereq, "_greatereq", CALL_BUILTIN_3_1},
|
||||
{f_contains, "_contains", CALL_BUILTIN_3_1},
|
||||
{f_length, "length", CALL_BUILTIN_1_1},
|
||||
{f_type, "type", CALL_BUILTIN_1_1},
|
||||
{f_add, "add", CALL_BUILTIN_1_1},
|
||||
|
@@ -522,7 +522,33 @@ 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: |
|
||||
|
||||
|
61
jv.c
61
jv.c
@@ -329,6 +329,28 @@ jv jv_array_slice(jv a, int start, int end) {
|
||||
return a;
|
||||
}
|
||||
|
||||
int jv_array_contains(jv a, jv b) {
|
||||
int r = 1;
|
||||
int a_length = jv_array_length(jv_copy(a));
|
||||
int b_length = jv_array_length(jv_copy(b));
|
||||
for (int bi = 0; bi < b_length; bi++) {
|
||||
int ri = 0;
|
||||
for (int ai = 0; ai < a_length; ai++) {
|
||||
if (jv_contains(jv_array_get(jv_copy(a), ai), jv_array_get(jv_copy(b), bi))) {
|
||||
ri = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ri) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
jv_free(a);
|
||||
jv_free(b);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Strings (internal helpers)
|
||||
@@ -863,6 +885,27 @@ jv jv_object_merge(jv a, jv b) {
|
||||
return a;
|
||||
}
|
||||
|
||||
int jv_object_contains(jv a, jv b) {
|
||||
assert(jv_get_kind(a) == JV_KIND_OBJECT);
|
||||
assert(jv_get_kind(b) == JV_KIND_OBJECT);
|
||||
int r = 1;
|
||||
|
||||
jv_object_foreach(i, b) {
|
||||
jv key = jv_object_iter_key(b, i);
|
||||
jv a_val = jv_object_get(jv_copy(a), jv_copy(key));
|
||||
jv b_val = jv_object_get(jv_copy(b), jv_copy(key));
|
||||
|
||||
r = jv_contains(a_val, b_val);
|
||||
jv_free(key);
|
||||
|
||||
if (!r) break;
|
||||
}
|
||||
|
||||
jv_free(a);
|
||||
jv_free(b);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Object iteration (internal helpers)
|
||||
*/
|
||||
@@ -977,3 +1020,21 @@ int jv_equal(jv a, jv b) {
|
||||
jv_free(b);
|
||||
return r;
|
||||
}
|
||||
|
||||
int jv_contains(jv a, jv b) {
|
||||
int r = 1;
|
||||
if (jv_get_kind(a) != jv_get_kind(b)) {
|
||||
r = 0;
|
||||
} else if (jv_get_kind(a) == JV_KIND_OBJECT) {
|
||||
r = jv_object_contains(jv_copy(a), jv_copy(b));
|
||||
} else if (jv_get_kind(a) == JV_KIND_ARRAY) {
|
||||
r = jv_array_contains(jv_copy(a), jv_copy(b));
|
||||
} else if (jv_get_kind(a) == JV_KIND_STRING) {
|
||||
r = strstr(jv_string_value(a), jv_string_value(b)) != 0;
|
||||
} else {
|
||||
r = jv_equal(jv_copy(a), jv_copy(b));
|
||||
}
|
||||
jv_free(a);
|
||||
jv_free(b);
|
||||
return r;
|
||||
}
|
1
jv.h
1
jv.h
@@ -48,6 +48,7 @@ jv jv_copy(jv);
|
||||
void jv_free(jv);
|
||||
|
||||
int jv_equal(jv, jv);
|
||||
int jv_contains(jv, jv);
|
||||
|
||||
jv jv_invalid();
|
||||
jv jv_invalid_with_msg(jv);
|
||||
|
235
lexer.gen.c
235
lexer.gen.c
@@ -358,8 +358,8 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
|
||||
*yy_cp = '\0'; \
|
||||
yyg->yy_c_buf_p = yy_cp;
|
||||
|
||||
#define YY_NUM_RULES 35
|
||||
#define YY_END_OF_BUFFER 36
|
||||
#define YY_NUM_RULES 36
|
||||
#define YY_END_OF_BUFFER 37
|
||||
/* This struct is not used in this scanner,
|
||||
but its presence is necessary. */
|
||||
struct yy_trans_info
|
||||
@@ -367,17 +367,19 @@ struct yy_trans_info
|
||||
flex_int32_t yy_verify;
|
||||
flex_int32_t yy_nxt;
|
||||
};
|
||||
static yyconst flex_int16_t yy_accept[88] =
|
||||
static yyconst flex_int16_t yy_accept[96] =
|
||||
{ 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 36, 34, 33, 33, 34, 26, 1, 22,
|
||||
23, 24, 22, 22, 22, 22, 22, 25, 22, 22,
|
||||
22, 32, 32, 32, 32, 32, 32, 32, 22, 30,
|
||||
30, 28, 31, 33, 2, 1, 17, 15, 25, 16,
|
||||
0, 13, 18, 20, 3, 21, 32, 32, 4, 32,
|
||||
32, 32, 6, 11, 32, 14, 30, 29, 27, 29,
|
||||
0, 25, 19, 10, 5, 32, 32, 12, 32, 0,
|
||||
29, 9, 8, 7, 29, 29, 0
|
||||
0, 0, 37, 35, 34, 34, 35, 27, 1, 23,
|
||||
24, 25, 23, 23, 23, 23, 23, 26, 23, 23,
|
||||
23, 33, 33, 33, 33, 33, 33, 33, 33, 23,
|
||||
31, 31, 29, 32, 34, 2, 1, 17, 15, 26,
|
||||
16, 0, 13, 18, 20, 3, 21, 33, 33, 4,
|
||||
33, 33, 33, 33, 6, 11, 33, 14, 31, 30,
|
||||
28, 30, 0, 26, 19, 10, 33, 5, 33, 33,
|
||||
12, 33, 0, 30, 33, 9, 8, 7, 30, 33,
|
||||
30, 33, 33, 22, 0
|
||||
|
||||
} ;
|
||||
|
||||
static yyconst flex_int32_t yy_ec[256] =
|
||||
@@ -391,11 +393,11 @@ static yyconst flex_int32_t yy_ec[256] =
|
||||
21, 22, 1, 1, 23, 23, 23, 23, 24, 23,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
25, 26, 27, 1, 28, 1, 29, 23, 23, 30,
|
||||
25, 26, 27, 1, 28, 1, 29, 23, 30, 31,
|
||||
|
||||
31, 32, 23, 33, 34, 23, 23, 35, 23, 36,
|
||||
37, 23, 23, 38, 39, 40, 41, 23, 23, 23,
|
||||
23, 23, 42, 43, 44, 1, 1, 1, 1, 1,
|
||||
32, 33, 23, 34, 35, 23, 23, 36, 23, 37,
|
||||
38, 23, 23, 39, 40, 41, 42, 23, 23, 23,
|
||||
23, 23, 43, 44, 45, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
@@ -412,91 +414,97 @@ static yyconst flex_int32_t yy_ec[256] =
|
||||
1, 1, 1, 1, 1
|
||||
} ;
|
||||
|
||||
static yyconst flex_int32_t yy_meta[45] =
|
||||
static yyconst flex_int32_t yy_meta[46] =
|
||||
{ 0,
|
||||
1, 1, 2, 2, 1, 3, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 4, 1, 1, 1,
|
||||
1, 1, 4, 4, 1, 5, 1, 6, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 1, 1, 1
|
||||
4, 4, 1, 1, 1
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_base[97] =
|
||||
static yyconst flex_int16_t yy_base[105] =
|
||||
{ 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
42, 43, 144, 145, 48, 50, 122, 145, 0, 145,
|
||||
145, 145, 121, 120, 39, 40, 42, 50, 119, 118,
|
||||
117, 0, 23, 91, 37, 88, 78, 77, 80, 0,
|
||||
0, 145, 38, 73, 145, 0, 145, 145, 63, 145,
|
||||
71, 79, 145, 145, 145, 145, 0, 69, 0, 66,
|
||||
27, 67, 0, 0, 65, 145, 0, 69, 145, 67,
|
||||
75, 74, 145, 0, 0, 58, 58, 0, 50, 61,
|
||||
58, 0, 0, 0, 56, 51, 145, 102, 108, 111,
|
||||
117, 123, 126, 128, 130, 132
|
||||
43, 44, 152, 153, 49, 51, 130, 153, 0, 153,
|
||||
153, 153, 129, 128, 40, 41, 43, 51, 127, 126,
|
||||
125, 0, 23, 107, 112, 35, 110, 88, 91, 100,
|
||||
0, 0, 153, 39, 74, 153, 0, 153, 153, 63,
|
||||
153, 72, 94, 153, 153, 153, 153, 0, 75, 0,
|
||||
68, 71, 27, 72, 0, 0, 70, 153, 0, 75,
|
||||
153, 74, 82, 81, 153, 0, 56, 0, 63, 62,
|
||||
0, 56, 65, 66, 62, 0, 0, 0, 64, 53,
|
||||
59, 45, 39, 0, 153, 107, 113, 116, 122, 128,
|
||||
|
||||
131, 133, 135, 137
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_def[97] =
|
||||
static yyconst flex_int16_t yy_def[105] =
|
||||
{ 0,
|
||||
87, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
88, 88, 87, 87, 87, 87, 87, 87, 89, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 90, 90, 90, 90, 90, 90, 90, 87, 91,
|
||||
91, 87, 92, 87, 87, 89, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 90, 90, 90, 90,
|
||||
90, 90, 90, 90, 90, 87, 91, 87, 87, 93,
|
||||
87, 87, 87, 90, 90, 90, 90, 90, 90, 92,
|
||||
94, 90, 90, 90, 95, 96, 0, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87
|
||||
95, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
96, 96, 95, 95, 95, 95, 95, 95, 97, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 98, 98, 98, 98, 98, 98, 98, 98, 95,
|
||||
99, 99, 95, 100, 95, 95, 97, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 98, 98, 98,
|
||||
98, 98, 98, 98, 98, 98, 98, 95, 99, 95,
|
||||
95, 101, 95, 95, 95, 98, 98, 98, 98, 98,
|
||||
98, 98, 100, 102, 98, 98, 98, 98, 103, 98,
|
||||
104, 98, 98, 98, 0, 95, 95, 95, 95, 95,
|
||||
|
||||
95, 95, 95, 95
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_nxt[190] =
|
||||
static yyconst flex_int16_t yy_nxt[199] =
|
||||
{ 0,
|
||||
14, 15, 16, 14, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 20, 25, 26, 27, 28, 20, 20, 29,
|
||||
30, 31, 32, 32, 21, 14, 22, 32, 33, 34,
|
||||
35, 32, 32, 36, 32, 32, 37, 32, 32, 38,
|
||||
32, 21, 39, 22, 41, 41, 69, 42, 42, 44,
|
||||
44, 44, 44, 49, 49, 49, 49, 52, 58, 50,
|
||||
76, 59, 53, 51, 49, 77, 49, 43, 43, 87,
|
||||
51, 61, 62, 51, 44, 44, 80, 49, 70, 49,
|
||||
51, 80, 71, 80, 71, 84, 51, 72, 83, 82,
|
||||
72, 72, 80, 51, 80, 79, 78, 75, 74, 73,
|
||||
35, 36, 32, 32, 37, 32, 32, 38, 32, 32,
|
||||
39, 32, 21, 40, 22, 42, 42, 71, 43, 43,
|
||||
45, 45, 45, 45, 50, 50, 50, 50, 53, 59,
|
||||
51, 79, 60, 54, 52, 50, 80, 50, 44, 44,
|
||||
63, 64, 52, 95, 52, 45, 45, 50, 94, 50,
|
||||
72, 93, 52, 73, 83, 73, 52, 92, 74, 83,
|
||||
90, 83, 88, 87, 52, 86, 85, 74, 74, 83,
|
||||
|
||||
83, 82, 81, 78, 77, 76, 72, 41, 41, 41,
|
||||
41, 41, 41, 47, 75, 47, 47, 47, 47, 58,
|
||||
68, 58, 69, 69, 67, 69, 66, 69, 70, 70,
|
||||
70, 70, 70, 70, 84, 84, 89, 89, 91, 91,
|
||||
70, 70, 65, 62, 61, 57, 56, 55, 49, 48,
|
||||
46, 95, 13, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95
|
||||
|
||||
66, 70, 40, 40, 40, 40, 40, 40, 46, 65,
|
||||
46, 46, 46, 46, 57, 64, 57, 67, 67, 63,
|
||||
67, 60, 67, 68, 68, 68, 68, 68, 68, 81,
|
||||
81, 85, 85, 86, 86, 68, 68, 56, 55, 54,
|
||||
48, 47, 45, 87, 13, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_chk[190] =
|
||||
static yyconst flex_int16_t yy_chk[199] =
|
||||
{ 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 11, 12, 43, 11, 12, 15,
|
||||
15, 16, 16, 25, 26, 25, 26, 27, 33, 25,
|
||||
61, 33, 27, 26, 28, 61, 28, 11, 12, 80,
|
||||
26, 35, 35, 28, 44, 44, 86, 49, 43, 49,
|
||||
28, 85, 51, 81, 51, 79, 49, 51, 77, 76,
|
||||
72, 71, 70, 49, 68, 65, 62, 60, 58, 52,
|
||||
1, 1, 1, 1, 1, 11, 12, 44, 11, 12,
|
||||
15, 15, 16, 16, 25, 26, 25, 26, 27, 33,
|
||||
25, 63, 33, 27, 26, 28, 63, 28, 11, 12,
|
||||
36, 36, 26, 83, 28, 45, 45, 50, 93, 50,
|
||||
44, 92, 28, 52, 91, 52, 50, 90, 52, 89,
|
||||
85, 84, 82, 80, 50, 79, 77, 74, 73, 72,
|
||||
|
||||
70, 67, 64, 62, 61, 59, 83, 96, 96, 96,
|
||||
96, 96, 96, 97, 53, 97, 97, 97, 97, 98,
|
||||
40, 98, 99, 99, 39, 99, 38, 99, 100, 100,
|
||||
100, 100, 100, 100, 101, 101, 102, 102, 103, 103,
|
||||
104, 104, 37, 35, 34, 31, 30, 29, 24, 23,
|
||||
17, 13, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95
|
||||
|
||||
39, 80, 88, 88, 88, 88, 88, 88, 89, 38,
|
||||
89, 89, 89, 89, 90, 37, 90, 91, 91, 36,
|
||||
91, 34, 91, 92, 92, 92, 92, 92, 92, 93,
|
||||
93, 94, 94, 95, 95, 96, 96, 31, 30, 29,
|
||||
24, 23, 17, 13, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
|
||||
87, 87, 87, 87, 87, 87, 87, 87, 87
|
||||
} ;
|
||||
|
||||
/* The intent behind this definition is that it'll catch
|
||||
@@ -530,7 +538,7 @@ struct lexer_param;
|
||||
static int enter(int opening, int state, yyscan_t yyscanner);
|
||||
static int try_exit(int closing, int state, yyscan_t yyscanner);
|
||||
#define YY_NO_INPUT 1
|
||||
#line 534 "lexer.gen.c"
|
||||
#line 542 "lexer.gen.c"
|
||||
|
||||
#define INITIAL 0
|
||||
#define IN_PAREN 1
|
||||
@@ -786,7 +794,7 @@ YY_DECL
|
||||
#line 35 "lexer.l"
|
||||
|
||||
|
||||
#line 790 "lexer.gen.c"
|
||||
#line 798 "lexer.gen.c"
|
||||
|
||||
yylval = yylval_param;
|
||||
|
||||
@@ -843,13 +851,13 @@ yy_match:
|
||||
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
|
||||
{
|
||||
yy_current_state = (int) yy_def[yy_current_state];
|
||||
if ( yy_current_state >= 88 )
|
||||
if ( yy_current_state >= 96 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
++yy_cp;
|
||||
}
|
||||
while ( yy_base[yy_current_state] != 145 );
|
||||
while ( yy_base[yy_current_state] != 153 );
|
||||
|
||||
yy_find_action:
|
||||
yy_act = yy_accept[yy_current_state];
|
||||
@@ -981,57 +989,62 @@ YY_RULE_SETUP
|
||||
case 22:
|
||||
YY_RULE_SETUP
|
||||
#line 59 "lexer.l"
|
||||
{ return yytext[0];}
|
||||
{ return CONTAINS; }
|
||||
YY_BREAK
|
||||
case 23:
|
||||
YY_RULE_SETUP
|
||||
#line 61 "lexer.l"
|
||||
#line 60 "lexer.l"
|
||||
{ return yytext[0];}
|
||||
YY_BREAK
|
||||
case 24:
|
||||
YY_RULE_SETUP
|
||||
#line 62 "lexer.l"
|
||||
{
|
||||
return enter(yytext[0], YY_START, yyscanner);
|
||||
}
|
||||
YY_BREAK
|
||||
case 24:
|
||||
case 25:
|
||||
YY_RULE_SETUP
|
||||
#line 65 "lexer.l"
|
||||
#line 66 "lexer.l"
|
||||
{
|
||||
return try_exit(yytext[0], YY_START, yyscanner);
|
||||
}
|
||||
YY_BREAK
|
||||
case 25:
|
||||
case 26:
|
||||
YY_RULE_SETUP
|
||||
#line 70 "lexer.l"
|
||||
#line 71 "lexer.l"
|
||||
{
|
||||
yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL;
|
||||
}
|
||||
YY_BREAK
|
||||
case 26:
|
||||
case 27:
|
||||
YY_RULE_SETUP
|
||||
#line 74 "lexer.l"
|
||||
#line 75 "lexer.l"
|
||||
{
|
||||
yy_push_state(IN_QQSTRING, yyscanner);
|
||||
return QQSTRING_START;
|
||||
}
|
||||
YY_BREAK
|
||||
|
||||
case 27:
|
||||
case 28:
|
||||
YY_RULE_SETUP
|
||||
#line 80 "lexer.l"
|
||||
#line 81 "lexer.l"
|
||||
{
|
||||
return enter(QQSTRING_INTERP_START, YY_START, yyscanner);
|
||||
}
|
||||
YY_BREAK
|
||||
case 28:
|
||||
case 29:
|
||||
YY_RULE_SETUP
|
||||
#line 83 "lexer.l"
|
||||
#line 84 "lexer.l"
|
||||
{
|
||||
yy_pop_state(yyscanner);
|
||||
return QQSTRING_END;
|
||||
}
|
||||
YY_BREAK
|
||||
case 29:
|
||||
/* rule 29 can match eol */
|
||||
case 30:
|
||||
/* rule 30 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 87 "lexer.l"
|
||||
#line 88 "lexer.l"
|
||||
{
|
||||
/* pass escapes to the json parser */
|
||||
jv escapes = jv_string_fmt("\"%.*s\"", yyleng, yytext);
|
||||
@@ -1040,45 +1053,45 @@ YY_RULE_SETUP
|
||||
return QQSTRING_TEXT;
|
||||
}
|
||||
YY_BREAK
|
||||
case 30:
|
||||
/* rule 30 can match eol */
|
||||
case 31:
|
||||
/* rule 31 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 94 "lexer.l"
|
||||
#line 95 "lexer.l"
|
||||
{
|
||||
yylval->literal = jv_string_sized(yytext, yyleng);
|
||||
return QQSTRING_TEXT;
|
||||
}
|
||||
YY_BREAK
|
||||
case 31:
|
||||
case 32:
|
||||
YY_RULE_SETUP
|
||||
#line 98 "lexer.l"
|
||||
#line 99 "lexer.l"
|
||||
{
|
||||
return INVALID_CHARACTER;
|
||||
}
|
||||
YY_BREAK
|
||||
|
||||
case 32:
|
||||
case 33:
|
||||
YY_RULE_SETUP
|
||||
#line 104 "lexer.l"
|
||||
#line 105 "lexer.l"
|
||||
{ yylval->literal = jv_string(yytext); return IDENT;}
|
||||
YY_BREAK
|
||||
case 33:
|
||||
/* rule 33 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 106 "lexer.l"
|
||||
{}
|
||||
YY_BREAK
|
||||
case 34:
|
||||
/* rule 34 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 108 "lexer.l"
|
||||
{ return INVALID_CHARACTER; }
|
||||
#line 107 "lexer.l"
|
||||
{}
|
||||
YY_BREAK
|
||||
case 35:
|
||||
YY_RULE_SETUP
|
||||
#line 110 "lexer.l"
|
||||
#line 109 "lexer.l"
|
||||
{ return INVALID_CHARACTER; }
|
||||
YY_BREAK
|
||||
case 36:
|
||||
YY_RULE_SETUP
|
||||
#line 111 "lexer.l"
|
||||
YY_FATAL_ERROR( "flex scanner jammed" );
|
||||
YY_BREAK
|
||||
#line 1082 "lexer.gen.c"
|
||||
#line 1095 "lexer.gen.c"
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
case YY_STATE_EOF(IN_PAREN):
|
||||
case YY_STATE_EOF(IN_BRACKET):
|
||||
@@ -1377,7 +1390,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
||||
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
|
||||
{
|
||||
yy_current_state = (int) yy_def[yy_current_state];
|
||||
if ( yy_current_state >= 88 )
|
||||
if ( yy_current_state >= 96 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
@@ -1406,11 +1419,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
|
||||
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
|
||||
{
|
||||
yy_current_state = (int) yy_def[yy_current_state];
|
||||
if ( yy_current_state >= 88 )
|
||||
if ( yy_current_state >= 96 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
yy_is_jam = (yy_current_state == 87);
|
||||
yy_is_jam = (yy_current_state == 95);
|
||||
|
||||
return yy_is_jam ? 0 : yy_current_state;
|
||||
}
|
||||
@@ -2264,7 +2277,7 @@ void jq_yyfree (void * ptr , yyscan_t yyscanner)
|
||||
|
||||
#define YYTABLES_NAME "yytables"
|
||||
|
||||
#line 110 "lexer.l"
|
||||
#line 111 "lexer.l"
|
||||
|
||||
|
||||
/* perhaps these should be calls... */
|
||||
|
@@ -354,7 +354,7 @@ extern int jq_yylex \
|
||||
#undef YY_DECL
|
||||
#endif
|
||||
|
||||
#line 110 "lexer.l"
|
||||
#line 111 "lexer.l"
|
||||
|
||||
|
||||
#line 361 "lexer.gen.h"
|
||||
|
1
lexer.l
1
lexer.l
@@ -56,6 +56,7 @@ struct lexer_param;
|
||||
"//=" { return SETDEFINEDOR; }
|
||||
"<=" { return LESSEQ; }
|
||||
">=" { return GREATEREQ; }
|
||||
"contains" { return CONTAINS; }
|
||||
"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$"|"<"|">" { return yytext[0];}
|
||||
|
||||
"["|"{"|"(" {
|
||||
|
907
parser.gen.c
907
parser.gen.c
File diff suppressed because it is too large
Load Diff
13
parser.gen.h
13
parser.gen.h
@@ -82,11 +82,12 @@
|
||||
SETDEFINEDOR = 278,
|
||||
LESSEQ = 279,
|
||||
GREATEREQ = 280,
|
||||
QQSTRING_START = 281,
|
||||
QQSTRING_TEXT = 282,
|
||||
QQSTRING_INTERP_START = 283,
|
||||
QQSTRING_INTERP_END = 284,
|
||||
QQSTRING_END = 285
|
||||
CONTAINS = 281,
|
||||
QQSTRING_START = 282,
|
||||
QQSTRING_TEXT = 283,
|
||||
QQSTRING_INTERP_START = 284,
|
||||
QQSTRING_INTERP_END = 285,
|
||||
QQSTRING_END = 286
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -105,7 +106,7 @@ typedef union YYSTYPE
|
||||
|
||||
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 109 "parser.gen.h"
|
||||
#line 110 "parser.gen.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
|
2628
parser.gen.info
2628
parser.gen.info
File diff suppressed because it is too large
Load Diff
8
parser.y
8
parser.y
@@ -65,6 +65,7 @@ struct lexer_param;
|
||||
%token SETDEFINEDOR "//="
|
||||
%token LESSEQ "<="
|
||||
%token GREATEREQ ">="
|
||||
%token CONTAINS "contains"
|
||||
|
||||
%token QQSTRING_START
|
||||
%token <literal> QQSTRING_TEXT
|
||||
@@ -80,7 +81,7 @@ struct lexer_param;
|
||||
%nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETDEFINEDOR
|
||||
%left OR
|
||||
%left AND
|
||||
%nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ
|
||||
%nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ CONTAINS
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
|
||||
@@ -152,6 +153,7 @@ 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);
|
||||
|
||||
@@ -308,6 +310,10 @@ Exp ">=" Exp {
|
||||
$$ = gen_binop($1, $3, GREATEREQ);
|
||||
} |
|
||||
|
||||
Exp "contains" Exp {
|
||||
$$ = gen_binop($1, $3, CONTAINS);
|
||||
} |
|
||||
|
||||
Term {
|
||||
$$ = $1;
|
||||
}
|
||||
|
25
testdata
25
testdata
@@ -395,3 +395,28 @@ def inc(x): x |= .+1; inc(.[].a)
|
||||
[{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":18},"world"]},{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":19},"world"]}]
|
||||
{}
|
||||
[true,false]
|
||||
|
||||
# containment operator
|
||||
["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]]
|
||||
{}
|
||||
[true, true, true, false, false]
|
||||
|
||||
[["foobar", "foobaz"] contains ["baz", "bar"], ["foobar", "foobaz"] contains ["foo"], ["foobar", "foobaz"] contains ["blap"]]
|
||||
{}
|
||||
[true, true, false]
|
||||
|
||||
[{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: {}}}
|
||||
{}
|
||||
true
|
||||
|
||||
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} contains {bar: 14, foo: {blap: {bar: 14}}}
|
||||
{}
|
||||
false
|
Reference in New Issue
Block a user