mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[master] Merged trac4233 (new concat string function to classification expression)
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
1080. [func] fdupont
|
||||
Added a concat function in classification which concatenates two
|
||||
strings.
|
||||
(Trac #4233, git ...)
|
||||
|
||||
1079. [func] fdupont
|
||||
Added Not, And and Or logical operators, parentheses around
|
||||
logical expressions and option[code].exist logical predicate
|
||||
(to check the presence of an empty option).
|
||||
(Trac #4231, git xxx)
|
||||
(Trac #4231, git 8e01dbe2fe2d8c97f89c20f5bb1d03748a2432e0)
|
||||
|
||||
1078. [func] tomek
|
||||
Client classification in DHCPv4 has been enhanced. It is now
|
||||
|
@@ -224,6 +224,7 @@ sub-option with code "code" from the Relay Agent Information option
|
||||
<row><entry>And</entry> <entry>('foo' == 'bar') and ('bar' == 'foo')</entry><entry>Logical and</entry></row>
|
||||
<row><entry>Or</entry> <entry>('foo' == 'bar') or ('bar' == 'foo')</entry><entry>Logical or</entry></row>
|
||||
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
|
||||
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the concatenation of the strings</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@@ -261,6 +262,14 @@ sub-option with code "code" from the Relay Agent Information option
|
||||
substring('foobar', 10, 2) == ''
|
||||
</screen>
|
||||
</section>
|
||||
<section>
|
||||
<title>Concat</title>
|
||||
The concat function "concat(string1, string2)" returns the
|
||||
concatenation of its two arguments. For instance:
|
||||
<screen>
|
||||
concat('foo', 'bar') == 'foobar'
|
||||
</screen>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<note>
|
||||
|
@@ -460,8 +460,8 @@ static void yy_fatal_error (yyconst char msg[] );
|
||||
(yy_c_buf_p) = yy_cp;
|
||||
|
||||
/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
|
||||
#define YY_NUM_RULES 25
|
||||
#define YY_END_OF_BUFFER 26
|
||||
#define YY_NUM_RULES 26
|
||||
#define YY_END_OF_BUFFER 27
|
||||
/* This struct is not used in this scanner,
|
||||
but its presence is necessary. */
|
||||
struct yy_trans_info
|
||||
@@ -469,33 +469,35 @@ struct yy_trans_info
|
||||
flex_int32_t yy_verify;
|
||||
flex_int32_t yy_nxt;
|
||||
};
|
||||
static yyconst flex_int16_t yy_acclist[119] =
|
||||
static yyconst flex_int16_t yy_acclist[128] =
|
||||
{ 0,
|
||||
26, 24, 25, 1, 24, 25, 2, 25, 24, 25,
|
||||
19, 24, 25, 20, 24, 25, 23, 24, 25, 24,
|
||||
25, 18, 24, 25, 5, 24, 25, 5, 24, 25,
|
||||
24, 25, 24, 25,16390, 21, 24, 25, 22, 24,
|
||||
25, 24, 25,16390, 24, 25,16390, 24, 25,16390,
|
||||
24, 25,16390, 24, 25,16390, 24, 25,16390, 24,
|
||||
25,16390, 24, 25,16390, 1, 2, 3, 5, 7,
|
||||
16390, 8198,16390,16390,16390,16390,16390,16390, 17,16390,
|
||||
16390,16390,16390, 4, 14,16390, 16,16390,16390, 10,
|
||||
16390, 15,16390,16390,16390,16390,16390,16390,16390,16390,
|
||||
27, 25, 26, 1, 25, 26, 2, 26, 25, 26,
|
||||
20, 25, 26, 21, 25, 26, 24, 25, 26, 25,
|
||||
26, 19, 25, 26, 5, 25, 26, 5, 25, 26,
|
||||
25, 26, 25, 26,16390, 22, 25, 26, 23, 25,
|
||||
26, 25, 26,16390, 25, 26,16390, 25, 26,16390,
|
||||
25, 26,16390, 25, 26,16390, 25, 26,16390, 25,
|
||||
26,16390, 25, 26,16390, 25, 26,16390, 1, 2,
|
||||
3, 5, 7,16390, 8198,16390,16390,16390,16390,16390,
|
||||
16390,16390, 18,16390,16390,16390,16390, 4, 14,16390,
|
||||
17,16390,16390,16390, 10,16390, 16,16390,16390,16390,
|
||||
|
||||
16390, 9,16390,16390,16390,16390,16390, 11,16390, 8,
|
||||
16390, 13,16390,16390,16390,16390, 12,16390
|
||||
16390,16390,16390,16390,16390,16390,16390, 9,16390,16390,
|
||||
16390,16390,16390,16390, 15,16390, 11,16390, 8,16390,
|
||||
12,16390,16390,16390,16390, 13,16390
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_accept[76] =
|
||||
static yyconst flex_int16_t yy_accept[82] =
|
||||
{ 0,
|
||||
1, 1, 1, 2, 4, 7, 9, 11, 14, 17,
|
||||
20, 22, 25, 28, 31, 33, 36, 39, 42, 45,
|
||||
48, 51, 54, 57, 60, 63, 66, 67, 68, 68,
|
||||
69, 70, 70, 71, 71, 71, 72, 73, 74, 75,
|
||||
76, 77, 78, 79, 81, 82, 83, 84, 85, 87,
|
||||
89, 90, 92, 94, 95, 96, 97, 98, 99, 100,
|
||||
101, 102, 104, 105, 106, 107, 108, 110, 112, 114,
|
||||
115, 116, 117, 119, 119
|
||||
48, 51, 54, 57, 60, 63, 66, 69, 70, 71,
|
||||
71, 72, 73, 73, 74, 74, 74, 75, 76, 77,
|
||||
78, 79, 80, 81, 82, 83, 85, 86, 87, 88,
|
||||
89, 91, 93, 94, 95, 97, 99, 100, 101, 102,
|
||||
103, 104, 105, 106, 107, 108, 110, 111, 112, 113,
|
||||
114, 115, 117, 119, 121, 123, 124, 125, 126, 128,
|
||||
128
|
||||
} ;
|
||||
|
||||
static yyconst flex_int32_t yy_ec[256] =
|
||||
@@ -509,11 +511,11 @@ static yyconst flex_int32_t yy_ec[256] =
|
||||
13, 1, 1, 1, 14, 14, 14, 14, 14, 14,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 16, 15, 15,
|
||||
17, 1, 18, 1, 19, 1, 20, 21, 14, 22,
|
||||
17, 1, 18, 1, 19, 1, 20, 21, 22, 23,
|
||||
|
||||
23, 14, 24, 25, 26, 15, 15, 27, 15, 28,
|
||||
29, 30, 15, 31, 32, 33, 34, 15, 15, 35,
|
||||
36, 15, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
24, 14, 25, 26, 27, 15, 15, 28, 15, 29,
|
||||
30, 31, 15, 32, 33, 34, 35, 15, 15, 36,
|
||||
37, 15, 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,
|
||||
@@ -530,114 +532,118 @@ static yyconst flex_int32_t yy_ec[256] =
|
||||
1, 1, 1, 1, 1
|
||||
} ;
|
||||
|
||||
static yyconst flex_int32_t yy_meta[37] =
|
||||
static yyconst flex_int32_t yy_meta[38] =
|
||||
{ 0,
|
||||
1, 2, 3, 1, 1, 1, 1, 2, 1, 4,
|
||||
4, 4, 1, 4, 2, 2, 1, 2, 2, 4,
|
||||
4, 4, 4, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2
|
||||
4, 4, 4, 4, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_base[78] =
|
||||
static yyconst flex_int16_t yy_base[84] =
|
||||
{ 0,
|
||||
0, 0, 113, 205, 108, 101, 98, 205, 205, 205,
|
||||
27, 205, 30, 33, 87, 45, 205, 205, 64, 22,
|
||||
28, 31, 43, 52, 34, 58, 82, 66, 50, 205,
|
||||
66, 0, 205, 85, 87, 66, 205, 68, 79, 71,
|
||||
81, 84, 91, 93, 95, 104, 99, 0, 101, 108,
|
||||
110, 112, 116, 119, 121, 123, 125, 129, 132, 136,
|
||||
138, 140, 142, 148, 161, 150, 152, 155, 157, 164,
|
||||
159, 169, 167, 205, 197, 200, 48
|
||||
0, 0, 202, 219, 167, 155, 138, 219, 219, 219,
|
||||
28, 219, 31, 34, 94, 46, 219, 219, 66, 22,
|
||||
27, 29, 31, 44, 42, 51, 53, 103, 80, 74,
|
||||
219, 77, 0, 219, 88, 90, 68, 219, 70, 81,
|
||||
72, 84, 86, 92, 95, 74, 88, 104, 99, 0,
|
||||
102, 108, 112, 110, 116, 118, 121, 131, 124, 127,
|
||||
134, 136, 138, 143, 145, 147, 149, 153, 156, 175,
|
||||
160, 162, 165, 167, 169, 172, 177, 182, 180, 219,
|
||||
211, 214, 58
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_def[78] =
|
||||
static yyconst flex_int16_t yy_def[84] =
|
||||
{ 0,
|
||||
74, 1, 74, 74, 74, 74, 75, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 76, 74, 74, 76, 19,
|
||||
19, 19, 19, 19, 19, 19, 74, 74, 75, 74,
|
||||
74, 77, 74, 74, 19, 19, 74, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 77, 19, 19,
|
||||
80, 1, 80, 80, 80, 80, 81, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 82, 80, 80, 82, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 80, 80, 81,
|
||||
80, 80, 83, 80, 80, 19, 19, 80, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 83,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 0, 74, 74, 74
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 0,
|
||||
80, 80, 80
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_nxt[242] =
|
||||
static yyconst flex_int16_t yy_nxt[257] =
|
||||
{ 0,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 14, 15, 16, 16, 16, 17, 18, 4, 19,
|
||||
16, 16, 20, 16, 21, 16, 16, 22, 23, 16,
|
||||
24, 25, 26, 16, 16, 16, 31, 31, 31, 31,
|
||||
31, 31, 31, 31, 31, 32, 34, 34, 36, 36,
|
||||
41, 48, 35, 30, 36, 36, 40, 36, 36, 42,
|
||||
36, 36, 37, 35, 32, 34, 34, 46, 28, 36,
|
||||
36, 35, 43, 44, 45, 31, 31, 31, 36, 36,
|
||||
47, 37, 35, 27, 36, 36, 34, 34, 74, 74,
|
||||
38, 39, 36, 36, 49, 36, 51, 36, 36, 33,
|
||||
16, 20, 16, 21, 16, 22, 16, 16, 23, 24,
|
||||
16, 25, 26, 27, 16, 16, 16, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 33, 35, 35, 37,
|
||||
37, 41, 43, 36, 37, 37, 37, 37, 37, 37,
|
||||
44, 50, 42, 38, 36, 47, 33, 35, 35, 37,
|
||||
37, 37, 37, 36, 45, 46, 49, 31, 37, 37,
|
||||
37, 37, 29, 38, 36, 48, 32, 32, 32, 35,
|
||||
35, 80, 80, 39, 40, 37, 37, 51, 37, 37,
|
||||
|
||||
50, 30, 37, 28, 74, 36, 36, 36, 36, 27,
|
||||
36, 36, 74, 36, 36, 52, 53, 36, 36, 36,
|
||||
36, 55, 36, 54, 56, 36, 36, 36, 36, 74,
|
||||
36, 36, 74, 57, 36, 36, 36, 36, 36, 36,
|
||||
60, 58, 36, 36, 59, 36, 36, 36, 36, 36,
|
||||
36, 36, 36, 74, 61, 36, 36, 62, 36, 36,
|
||||
64, 63, 36, 36, 36, 36, 36, 36, 36, 36,
|
||||
66, 65, 69, 67, 36, 68, 36, 36, 36, 36,
|
||||
70, 36, 36, 36, 36, 36, 72, 36, 36, 71,
|
||||
36, 36, 73, 36, 36, 36, 36, 29, 29, 74,
|
||||
53, 37, 37, 52, 28, 38, 34, 80, 37, 37,
|
||||
54, 37, 37, 37, 37, 58, 37, 37, 37, 37,
|
||||
37, 55, 37, 37, 59, 56, 37, 37, 57, 37,
|
||||
37, 37, 37, 61, 60, 37, 37, 37, 37, 37,
|
||||
37, 31, 62, 37, 37, 37, 37, 63, 37, 37,
|
||||
64, 37, 37, 67, 37, 37, 65, 29, 37, 37,
|
||||
66, 37, 37, 37, 37, 37, 37, 69, 28, 68,
|
||||
37, 37, 37, 37, 37, 37, 37, 37, 71, 70,
|
||||
37, 37, 72, 37, 74, 73, 75, 37, 37, 37,
|
||||
37, 76, 37, 37, 37, 37, 37, 37, 77, 37,
|
||||
|
||||
29, 36, 36, 36, 3, 74, 74, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
|
||||
74
|
||||
37, 80, 37, 37, 37, 78, 79, 37, 37, 37,
|
||||
37, 30, 30, 80, 30, 37, 37, 37, 3, 80,
|
||||
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 80
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_chk[242] =
|
||||
static yyconst flex_int16_t yy_chk[257] =
|
||||
{ 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, 11, 11, 11, 13,
|
||||
13, 13, 14, 14, 14, 13, 16, 16, 20, 20,
|
||||
21, 77, 16, 29, 21, 21, 20, 22, 22, 22,
|
||||
25, 25, 16, 16, 13, 19, 19, 25, 28, 23,
|
||||
23, 19, 23, 23, 24, 31, 31, 31, 24, 24,
|
||||
26, 19, 19, 27, 26, 26, 34, 34, 35, 35,
|
||||
19, 19, 36, 36, 38, 38, 40, 40, 40, 15,
|
||||
1, 1, 1, 1, 1, 1, 1, 11, 11, 11,
|
||||
13, 13, 13, 14, 14, 14, 13, 16, 16, 20,
|
||||
20, 20, 22, 16, 21, 21, 22, 22, 23, 23,
|
||||
23, 83, 21, 16, 16, 25, 13, 19, 19, 25,
|
||||
25, 24, 24, 19, 24, 24, 27, 30, 26, 26,
|
||||
27, 27, 29, 19, 19, 26, 32, 32, 32, 35,
|
||||
35, 36, 36, 19, 19, 37, 37, 39, 39, 41,
|
||||
|
||||
39, 7, 34, 6, 35, 39, 39, 41, 41, 5,
|
||||
42, 42, 3, 35, 35, 41, 42, 43, 43, 44,
|
||||
44, 45, 45, 43, 46, 47, 47, 49, 49, 0,
|
||||
46, 46, 0, 47, 50, 50, 51, 51, 52, 52,
|
||||
55, 51, 53, 53, 54, 54, 54, 55, 55, 56,
|
||||
56, 57, 57, 0, 56, 58, 58, 57, 59, 59,
|
||||
59, 58, 60, 60, 61, 61, 62, 62, 63, 63,
|
||||
61, 60, 65, 63, 64, 64, 66, 66, 67, 67,
|
||||
66, 68, 68, 69, 69, 71, 71, 65, 65, 70,
|
||||
70, 70, 72, 73, 73, 72, 72, 75, 75, 0,
|
||||
41, 46, 46, 40, 28, 35, 15, 36, 40, 40,
|
||||
42, 42, 42, 43, 43, 47, 47, 36, 36, 44,
|
||||
44, 43, 45, 45, 48, 44, 49, 49, 45, 51,
|
||||
51, 48, 48, 53, 49, 52, 52, 54, 54, 53,
|
||||
53, 7, 54, 55, 55, 56, 56, 57, 57, 57,
|
||||
58, 59, 59, 61, 60, 60, 59, 6, 58, 58,
|
||||
60, 61, 61, 62, 62, 63, 63, 63, 5, 62,
|
||||
64, 64, 65, 65, 66, 66, 67, 67, 65, 64,
|
||||
68, 68, 67, 69, 69, 68, 70, 71, 71, 72,
|
||||
72, 71, 73, 73, 74, 74, 75, 75, 76, 76,
|
||||
|
||||
75, 76, 76, 76, 74, 74, 74, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
|
||||
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
|
||||
74
|
||||
76, 3, 70, 70, 77, 77, 78, 79, 79, 78,
|
||||
78, 81, 81, 0, 81, 82, 82, 82, 80, 80,
|
||||
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 80
|
||||
} ;
|
||||
|
||||
/* Table of booleans, true if rule could match eol. */
|
||||
static yyconst flex_int32_t yy_rule_can_match_eol[26] =
|
||||
static yyconst flex_int32_t yy_rule_can_match_eol[27] =
|
||||
{ 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, };
|
||||
0, 0, 0, 0, 0, 0, 0, };
|
||||
|
||||
extern int yy_flex_debug;
|
||||
int yy_flex_debug = 1;
|
||||
|
||||
static yyconst flex_int16_t yy_rule_linenum[25] =
|
||||
static yyconst flex_int16_t yy_rule_linenum[26] =
|
||||
{ 0,
|
||||
78, 82, 88, 98, 104, 118, 125, 126, 127, 128,
|
||||
129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
|
||||
139, 140, 141, 143
|
||||
139, 140, 141, 142, 144
|
||||
} ;
|
||||
|
||||
static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
|
||||
@@ -714,7 +720,7 @@ static isc::eval::location loc;
|
||||
// by moving it ahead by yyleng bytes. yyleng specifies the length of the
|
||||
// currently matched token.
|
||||
#define YY_USER_ACTION loc.columns(yyleng);
|
||||
#line 718 "lexer.cc"
|
||||
#line 724 "lexer.cc"
|
||||
|
||||
#define INITIAL 0
|
||||
|
||||
@@ -962,7 +968,7 @@ YY_DECL
|
||||
loc.step();
|
||||
|
||||
|
||||
#line 966 "lexer.cc"
|
||||
#line 972 "lexer.cc"
|
||||
|
||||
if ( !(yy_init) )
|
||||
{
|
||||
@@ -1030,14 +1036,14 @@ 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 >= 75 )
|
||||
if ( yy_current_state >= 81 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
++yy_cp;
|
||||
}
|
||||
while ( yy_current_state != 74 );
|
||||
while ( yy_current_state != 80 );
|
||||
|
||||
yy_find_action:
|
||||
/* %% [10.0] code to find the action number goes here */
|
||||
@@ -1101,13 +1107,13 @@ do_action: /* This label is used only to access EOF actions. */
|
||||
{
|
||||
if ( yy_act == 0 )
|
||||
fprintf( stderr, "--scanner backing up\n" );
|
||||
else if ( yy_act < 25 )
|
||||
else if ( yy_act < 26 )
|
||||
fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
|
||||
(long)yy_rule_linenum[yy_act], yytext );
|
||||
else if ( yy_act == 25 )
|
||||
else if ( yy_act == 26 )
|
||||
fprintf( stderr, "--accepting default rule (\"%s\")\n",
|
||||
yytext );
|
||||
else if ( yy_act == 26 )
|
||||
else if ( yy_act == 27 )
|
||||
fprintf( stderr, "--(end of buffer or a NUL)\n" );
|
||||
else
|
||||
fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
|
||||
@@ -1212,12 +1218,12 @@ return isc::eval::EvalParser::make_EXISTS(loc);
|
||||
case 12:
|
||||
YY_RULE_SETUP
|
||||
#line 130 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_SUBSTRING(loc);
|
||||
return isc::eval::EvalParser::make_RELAY4(loc);
|
||||
YY_BREAK
|
||||
case 13:
|
||||
YY_RULE_SETUP
|
||||
#line 131 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_RELAY4(loc);
|
||||
return isc::eval::EvalParser::make_SUBSTRING(loc);
|
||||
YY_BREAK
|
||||
case 14:
|
||||
YY_RULE_SETUP
|
||||
@@ -1227,63 +1233,68 @@ return isc::eval::EvalParser::make_ALL(loc);
|
||||
case 15:
|
||||
YY_RULE_SETUP
|
||||
#line 133 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_NOT(loc);
|
||||
return isc::eval::EvalParser::make_CONCAT(loc);
|
||||
YY_BREAK
|
||||
case 16:
|
||||
YY_RULE_SETUP
|
||||
#line 134 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_AND(loc);
|
||||
return isc::eval::EvalParser::make_NOT(loc);
|
||||
YY_BREAK
|
||||
case 17:
|
||||
YY_RULE_SETUP
|
||||
#line 135 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_OR(loc);
|
||||
return isc::eval::EvalParser::make_AND(loc);
|
||||
YY_BREAK
|
||||
case 18:
|
||||
YY_RULE_SETUP
|
||||
#line 136 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_DOT(loc);
|
||||
return isc::eval::EvalParser::make_OR(loc);
|
||||
YY_BREAK
|
||||
case 19:
|
||||
YY_RULE_SETUP
|
||||
#line 137 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_LPAREN(loc);
|
||||
return isc::eval::EvalParser::make_DOT(loc);
|
||||
YY_BREAK
|
||||
case 20:
|
||||
YY_RULE_SETUP
|
||||
#line 138 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_RPAREN(loc);
|
||||
return isc::eval::EvalParser::make_LPAREN(loc);
|
||||
YY_BREAK
|
||||
case 21:
|
||||
YY_RULE_SETUP
|
||||
#line 139 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_LBRACKET(loc);
|
||||
return isc::eval::EvalParser::make_RPAREN(loc);
|
||||
YY_BREAK
|
||||
case 22:
|
||||
YY_RULE_SETUP
|
||||
#line 140 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_RBRACKET(loc);
|
||||
return isc::eval::EvalParser::make_LBRACKET(loc);
|
||||
YY_BREAK
|
||||
case 23:
|
||||
YY_RULE_SETUP
|
||||
#line 141 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_COMA(loc);
|
||||
return isc::eval::EvalParser::make_RBRACKET(loc);
|
||||
YY_BREAK
|
||||
case 24:
|
||||
YY_RULE_SETUP
|
||||
#line 143 "lexer.ll"
|
||||
driver.error (loc, "Invalid character: " + std::string(yytext));
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 144 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_END(loc);
|
||||
#line 142 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_COMA(loc);
|
||||
YY_BREAK
|
||||
case 25:
|
||||
YY_RULE_SETUP
|
||||
#line 144 "lexer.ll"
|
||||
driver.error (loc, "Invalid character: " + std::string(yytext));
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 145 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_END(loc);
|
||||
YY_BREAK
|
||||
case 26:
|
||||
YY_RULE_SETUP
|
||||
#line 146 "lexer.ll"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 1287 "lexer.cc"
|
||||
#line 1298 "lexer.cc"
|
||||
|
||||
case YY_END_OF_BUFFER:
|
||||
{
|
||||
@@ -1563,7 +1574,7 @@ static int yy_get_next_buffer (void)
|
||||
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 >= 75 )
|
||||
if ( yy_current_state >= 81 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
@@ -1591,11 +1602,11 @@ static int yy_get_next_buffer (void)
|
||||
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 >= 75 )
|
||||
if ( yy_current_state >= 81 )
|
||||
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 == 74);
|
||||
yy_is_jam = (yy_current_state == 80);
|
||||
if ( ! yy_is_jam )
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
|
||||
@@ -2353,7 +2364,7 @@ void yyfree (void * ptr )
|
||||
|
||||
/* %ok-for-header */
|
||||
|
||||
#line 145 "lexer.ll"
|
||||
#line 146 "lexer.ll"
|
||||
|
||||
|
||||
|
||||
|
@@ -127,9 +127,10 @@ blank [ \t]
|
||||
"text" return isc::eval::EvalParser::make_TEXT(loc);
|
||||
"hex" return isc::eval::EvalParser::make_HEX(loc);
|
||||
"exists" return isc::eval::EvalParser::make_EXISTS(loc);
|
||||
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
|
||||
"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
|
||||
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
|
||||
"all" return isc::eval::EvalParser::make_ALL(loc);
|
||||
"concat" return isc::eval::EvalParser::make_CONCAT(loc);
|
||||
"not" return isc::eval::EvalParser::make_NOT(loc);
|
||||
"and" return isc::eval::EvalParser::make_AND(loc);
|
||||
"or" return isc::eval::EvalParser::make_OR(loc);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Generated 20160219
|
||||
// Generated at 20160219
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Locations for Bison parsers in C++
|
||||
|
@@ -255,11 +255,10 @@ namespace isc { namespace eval {
|
||||
value.move< TokenOption::RepresentationType > (that.value);
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
value.move< std::string > (that.value);
|
||||
break;
|
||||
|
||||
@@ -286,11 +285,10 @@ namespace isc { namespace eval {
|
||||
value.copy< TokenOption::RepresentationType > (that.value);
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
value.copy< std::string > (that.value);
|
||||
break;
|
||||
|
||||
@@ -334,53 +332,46 @@ namespace isc { namespace eval {
|
||||
<< yysym.location << ": ";
|
||||
switch (yytype)
|
||||
{
|
||||
case 20: // "constant string"
|
||||
case 21: // "constant string"
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 342 "parser.cc" // lalr1.cc:636
|
||||
#line 340 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 21: // "integer"
|
||||
case 22: // "integer"
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 349 "parser.cc" // lalr1.cc:636
|
||||
#line 347 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "constant hexstring"
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 356 "parser.cc" // lalr1.cc:636
|
||||
#line 354 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 23: // "option name"
|
||||
case 24: // "option name"
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 363 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 24: // TOKEN
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 370 "parser.cc" // lalr1.cc:636
|
||||
#line 361 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 29: // option_code
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< uint16_t > (); }
|
||||
#line 377 "parser.cc" // lalr1.cc:636
|
||||
#line 368 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 30: // option_repr_type
|
||||
|
||||
#line 71 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); }
|
||||
#line 384 "parser.cc" // lalr1.cc:636
|
||||
#line 375 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
|
||||
@@ -584,11 +575,10 @@ namespace isc { namespace eval {
|
||||
yylhs.value.build< TokenOption::RepresentationType > ();
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
yylhs.value.build< std::string > ();
|
||||
break;
|
||||
|
||||
@@ -619,7 +609,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr neg(new TokenNot());
|
||||
ctx.expression.push_back(neg);
|
||||
}
|
||||
#line 623 "parser.cc" // lalr1.cc:859
|
||||
#line 613 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 5:
|
||||
@@ -628,7 +618,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr neg(new TokenAnd());
|
||||
ctx.expression.push_back(neg);
|
||||
}
|
||||
#line 632 "parser.cc" // lalr1.cc:859
|
||||
#line 622 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 6:
|
||||
@@ -637,7 +627,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr neg(new TokenOr());
|
||||
ctx.expression.push_back(neg);
|
||||
}
|
||||
#line 641 "parser.cc" // lalr1.cc:859
|
||||
#line 631 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 7:
|
||||
@@ -646,7 +636,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr eq(new TokenEqual());
|
||||
ctx.expression.push_back(eq);
|
||||
}
|
||||
#line 650 "parser.cc" // lalr1.cc:859
|
||||
#line 640 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 8:
|
||||
@@ -655,7 +645,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS));
|
||||
ctx.expression.push_back(opt);
|
||||
}
|
||||
#line 659 "parser.cc" // lalr1.cc:859
|
||||
#line 649 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 9:
|
||||
@@ -664,7 +654,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 668 "parser.cc" // lalr1.cc:859
|
||||
#line 658 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 10:
|
||||
@@ -673,7 +663,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(hex);
|
||||
}
|
||||
#line 677 "parser.cc" // lalr1.cc:859
|
||||
#line 667 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 11:
|
||||
@@ -682,7 +672,7 @@ namespace isc { namespace eval {
|
||||
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ()));
|
||||
ctx.expression.push_back(opt);
|
||||
}
|
||||
#line 686 "parser.cc" // lalr1.cc:859
|
||||
#line 676 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 12:
|
||||
@@ -706,7 +696,7 @@ namespace isc { namespace eval {
|
||||
error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
|
||||
}
|
||||
}
|
||||
#line 710 "parser.cc" // lalr1.cc:859
|
||||
#line 700 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 13:
|
||||
@@ -715,70 +705,79 @@ namespace isc { namespace eval {
|
||||
TokenPtr sub(new TokenSubstring());
|
||||
ctx.expression.push_back(sub);
|
||||
}
|
||||
#line 719 "parser.cc" // lalr1.cc:859
|
||||
#line 709 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 14:
|
||||
#line 152 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr conc(new TokenConcat());
|
||||
ctx.expression.push_back(conc);
|
||||
}
|
||||
#line 718 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 15:
|
||||
#line 156 "parser.yy" // lalr1.cc:859
|
||||
#line 159 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
|
||||
}
|
||||
#line 727 "parser.cc" // lalr1.cc:859
|
||||
#line 726 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 16:
|
||||
#line 160 "parser.yy" // lalr1.cc:859
|
||||
#line 163 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location);
|
||||
}
|
||||
#line 735 "parser.cc" // lalr1.cc:859
|
||||
#line 734 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 17:
|
||||
#line 166 "parser.yy" // lalr1.cc:859
|
||||
#line 169 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
|
||||
}
|
||||
#line 743 "parser.cc" // lalr1.cc:859
|
||||
#line 742 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 18:
|
||||
#line 170 "parser.yy" // lalr1.cc:859
|
||||
#line 173 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
|
||||
}
|
||||
#line 751 "parser.cc" // lalr1.cc:859
|
||||
#line 750 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 19:
|
||||
#line 176 "parser.yy" // lalr1.cc:859
|
||||
#line 179 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 760 "parser.cc" // lalr1.cc:859
|
||||
#line 759 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 20:
|
||||
#line 183 "parser.yy" // lalr1.cc:859
|
||||
#line 186 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 769 "parser.cc" // lalr1.cc:859
|
||||
#line 768 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 21:
|
||||
#line 188 "parser.yy" // lalr1.cc:859
|
||||
#line 191 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString("all"));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 778 "parser.cc" // lalr1.cc:859
|
||||
#line 777 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
|
||||
#line 782 "parser.cc" // lalr1.cc:859
|
||||
#line 781 "parser.cc" // lalr1.cc:859
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1033,75 +1032,77 @@ namespace isc { namespace eval {
|
||||
}
|
||||
|
||||
|
||||
const signed char EvalParser::yypact_ninf_ = -11;
|
||||
const signed char EvalParser::yypact_ninf_ = -14;
|
||||
|
||||
const signed char EvalParser::yytable_ninf_ = -1;
|
||||
|
||||
const signed char
|
||||
EvalParser::yypact_[] =
|
||||
{
|
||||
-4, -8, 9, -4, 12, -4, -11, -11, -11, 29,
|
||||
7, 37, 16, -1, -11, 16, 0, -11, -4, -4,
|
||||
-1, -11, -11, 23, 25, 26, 28, -11, -11, 38,
|
||||
-11, 30, 16, 31, 32, 22, 34, -11, 33, 27,
|
||||
-11, -11, -11, -11, 35, 11, -11, 27, -11, -11,
|
||||
39, -11
|
||||
-2, -12, -4, 3, -2, 14, -2, -14, -14, 39,
|
||||
33, 40, 16, 6, 6, -14, 16, 17, -14, -2,
|
||||
-2, 6, -14, -14, 25, 27, 28, 31, 29, -14,
|
||||
-14, 42, -14, 36, 16, 26, 6, 37, 24, 34,
|
||||
-14, 41, 35, 18, -14, -14, -14, -14, 43, 0,
|
||||
-14, -14, 18, -14, -14, 38, -14
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yydefact_[] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 9, 10, 14, 0,
|
||||
2, 0, 0, 0, 4, 0, 0, 1, 0, 0,
|
||||
0, 15, 16, 0, 0, 0, 0, 3, 5, 6,
|
||||
7, 0, 0, 0, 0, 0, 0, 19, 0, 0,
|
||||
17, 18, 8, 11, 0, 0, 12, 0, 21, 20,
|
||||
0, 13
|
||||
0, 0, 0, 0, 0, 0, 0, 9, 10, 0,
|
||||
2, 0, 0, 0, 0, 4, 0, 0, 1, 0,
|
||||
0, 0, 15, 16, 0, 0, 0, 0, 0, 3,
|
||||
5, 6, 7, 0, 0, 0, 0, 0, 0, 0,
|
||||
19, 0, 0, 0, 17, 18, 8, 11, 0, 0,
|
||||
14, 12, 0, 21, 20, 0, 13
|
||||
};
|
||||
|
||||
const signed char
|
||||
EvalParser::yypgoto_[] =
|
||||
{
|
||||
-11, -11, 8, 15, -10, 18, -11, -11
|
||||
-14, -14, 12, -13, -10, 19, -14, -14
|
||||
};
|
||||
|
||||
const signed char
|
||||
EvalParser::yydefgoto_[] =
|
||||
{
|
||||
-1, 9, 10, 11, 23, 43, 38, 50
|
||||
-1, 9, 10, 11, 24, 47, 41, 55
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yytable_[] =
|
||||
{
|
||||
1, 2, 3, 24, 2, 26, 4, 18, 19, 4,
|
||||
12, 14, 5, 16, 18, 19, 6, 27, 7, 6,
|
||||
8, 7, 36, 8, 48, 13, 28, 29, 25, 17,
|
||||
15, 40, 49, 41, 42, 30, 40, 21, 41, 22,
|
||||
20, 33, 31, 32, 35, 18, 39, 34, 45, 47,
|
||||
0, 0, 37, 44, 0, 0, 51, 46
|
||||
26, 27, 1, 2, 3, 4, 28, 12, 32, 5,
|
||||
25, 2, 3, 13, 53, 6, 15, 5, 17, 7,
|
||||
14, 8, 54, 42, 39, 19, 20, 7, 44, 8,
|
||||
45, 30, 31, 16, 44, 29, 45, 46, 22, 18,
|
||||
23, 19, 20, 21, 35, 33, 34, 36, 40, 37,
|
||||
19, 38, 43, 50, 48, 0, 56, 49, 52, 0,
|
||||
0, 0, 51
|
||||
};
|
||||
|
||||
const signed char
|
||||
EvalParser::yycheck_[] =
|
||||
{
|
||||
4, 5, 6, 4, 5, 15, 10, 7, 8, 10,
|
||||
18, 3, 16, 5, 7, 8, 20, 17, 22, 20,
|
||||
24, 22, 32, 24, 13, 16, 18, 19, 13, 0,
|
||||
18, 9, 21, 11, 12, 20, 9, 21, 11, 23,
|
||||
3, 15, 19, 18, 14, 7, 14, 19, 15, 14,
|
||||
-1, -1, 21, 19, -1, -1, 17, 39
|
||||
13, 14, 4, 5, 6, 7, 16, 19, 21, 11,
|
||||
4, 5, 6, 17, 14, 17, 4, 11, 6, 21,
|
||||
17, 23, 22, 36, 34, 8, 9, 21, 10, 23,
|
||||
12, 19, 20, 19, 10, 18, 12, 13, 22, 0,
|
||||
24, 8, 9, 3, 16, 20, 19, 16, 22, 20,
|
||||
8, 15, 15, 18, 20, -1, 18, 16, 15, -1,
|
||||
-1, -1, 43
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yystos_[] =
|
||||
{
|
||||
0, 4, 5, 6, 10, 16, 20, 22, 24, 26,
|
||||
27, 28, 18, 16, 27, 18, 27, 0, 7, 8,
|
||||
3, 21, 23, 29, 4, 28, 29, 17, 27, 27,
|
||||
28, 19, 18, 15, 19, 14, 29, 21, 31, 14,
|
||||
9, 11, 12, 30, 19, 15, 30, 14, 13, 21,
|
||||
32, 17
|
||||
0, 4, 5, 6, 7, 11, 17, 21, 23, 26,
|
||||
27, 28, 19, 17, 17, 27, 19, 27, 0, 8,
|
||||
9, 3, 22, 24, 29, 4, 28, 28, 29, 18,
|
||||
27, 27, 28, 20, 19, 16, 16, 20, 15, 29,
|
||||
22, 31, 28, 15, 10, 12, 13, 30, 20, 16,
|
||||
18, 30, 15, 14, 22, 32, 18
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
@@ -1116,7 +1117,7 @@ namespace isc { namespace eval {
|
||||
EvalParser::yyr2_[] =
|
||||
{
|
||||
0, 2, 1, 3, 2, 3, 3, 3, 6, 1,
|
||||
1, 6, 6, 8, 1, 1, 1, 1, 1, 1,
|
||||
1, 6, 6, 8, 6, 1, 1, 1, 1, 1,
|
||||
1, 1
|
||||
};
|
||||
|
||||
@@ -1128,10 +1129,10 @@ namespace isc { namespace eval {
|
||||
const EvalParser::yytname_[] =
|
||||
{
|
||||
"\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
|
||||
"\"substring\"", "\"not\"", "\"and\"", "\"or\"", "\"text\"",
|
||||
"\"relay4\"", "\"hex\"", "\"exists\"", "\"all\"", "\".\"", "\",\"",
|
||||
"\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"",
|
||||
"\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept",
|
||||
"\"substring\"", "\"concat\"", "\"not\"", "\"and\"", "\"or\"",
|
||||
"\"text\"", "\"relay4\"", "\"hex\"", "\"exists\"", "\"all\"", "\".\"",
|
||||
"\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"",
|
||||
"\"integer\"", "\"constant hexstring\"", "\"option name\"", "$accept",
|
||||
"expression", "bool_expr", "string_expr", "option_code",
|
||||
"option_repr_type", "start_expr", "length_expr", YY_NULLPTR
|
||||
};
|
||||
@@ -1141,8 +1142,8 @@ namespace isc { namespace eval {
|
||||
EvalParser::yyrline_[] =
|
||||
{
|
||||
0, 80, 80, 83, 84, 89, 94, 99, 104, 111,
|
||||
116, 121, 126, 146, 151, 155, 159, 165, 169, 175,
|
||||
182, 187
|
||||
116, 121, 126, 146, 151, 158, 162, 168, 172, 178,
|
||||
185, 190
|
||||
};
|
||||
|
||||
// Print the state stack on the debug stream.
|
||||
@@ -1177,8 +1178,8 @@ namespace isc { namespace eval {
|
||||
|
||||
#line 13 "parser.yy" // lalr1.cc:1167
|
||||
} } // isc::eval
|
||||
#line 1181 "parser.cc" // lalr1.cc:1167
|
||||
#line 194 "parser.yy" // lalr1.cc:1168
|
||||
#line 1182 "parser.cc" // lalr1.cc:1167
|
||||
#line 197 "parser.yy" // lalr1.cc:1168
|
||||
|
||||
void
|
||||
isc::eval::EvalParser::error(const location_type& loc,
|
||||
|
@@ -302,7 +302,6 @@ namespace isc { namespace eval {
|
||||
// "integer"
|
||||
// "constant hexstring"
|
||||
// "option name"
|
||||
// TOKEN
|
||||
char dummy2[sizeof(std::string)];
|
||||
|
||||
// option_code
|
||||
@@ -333,25 +332,25 @@ namespace isc { namespace eval {
|
||||
TOKEN_EQUAL = 258,
|
||||
TOKEN_OPTION = 259,
|
||||
TOKEN_SUBSTRING = 260,
|
||||
TOKEN_NOT = 261,
|
||||
TOKEN_AND = 262,
|
||||
TOKEN_OR = 263,
|
||||
TOKEN_TEXT = 264,
|
||||
TOKEN_RELAY4 = 265,
|
||||
TOKEN_HEX = 266,
|
||||
TOKEN_EXISTS = 267,
|
||||
TOKEN_ALL = 268,
|
||||
TOKEN_DOT = 269,
|
||||
TOKEN_COMA = 270,
|
||||
TOKEN_LPAREN = 271,
|
||||
TOKEN_RPAREN = 272,
|
||||
TOKEN_LBRACKET = 273,
|
||||
TOKEN_RBRACKET = 274,
|
||||
TOKEN_STRING = 275,
|
||||
TOKEN_INTEGER = 276,
|
||||
TOKEN_HEXSTRING = 277,
|
||||
TOKEN_OPTION_NAME = 278,
|
||||
TOKEN_TOKEN = 279
|
||||
TOKEN_CONCAT = 261,
|
||||
TOKEN_NOT = 262,
|
||||
TOKEN_AND = 263,
|
||||
TOKEN_OR = 264,
|
||||
TOKEN_TEXT = 265,
|
||||
TOKEN_RELAY4 = 266,
|
||||
TOKEN_HEX = 267,
|
||||
TOKEN_EXISTS = 268,
|
||||
TOKEN_ALL = 269,
|
||||
TOKEN_DOT = 270,
|
||||
TOKEN_COMA = 271,
|
||||
TOKEN_LPAREN = 272,
|
||||
TOKEN_RPAREN = 273,
|
||||
TOKEN_LBRACKET = 274,
|
||||
TOKEN_RBRACKET = 275,
|
||||
TOKEN_STRING = 276,
|
||||
TOKEN_INTEGER = 277,
|
||||
TOKEN_HEXSTRING = 278,
|
||||
TOKEN_OPTION_NAME = 279
|
||||
};
|
||||
};
|
||||
|
||||
@@ -478,6 +477,10 @@ namespace isc { namespace eval {
|
||||
symbol_type
|
||||
make_SUBSTRING (const location_type& l);
|
||||
|
||||
static inline
|
||||
symbol_type
|
||||
make_CONCAT (const location_type& l);
|
||||
|
||||
static inline
|
||||
symbol_type
|
||||
make_NOT (const location_type& l);
|
||||
@@ -550,10 +553,6 @@ namespace isc { namespace eval {
|
||||
symbol_type
|
||||
make_OPTION_NAME (const std::string& v, const location_type& l);
|
||||
|
||||
static inline
|
||||
symbol_type
|
||||
make_TOKEN (const std::string& v, const location_type& l);
|
||||
|
||||
|
||||
/// Build a parser object.
|
||||
EvalParser (EvalContext& ctx_yyarg);
|
||||
@@ -759,9 +758,9 @@ namespace isc { namespace eval {
|
||||
enum
|
||||
{
|
||||
yyeof_ = 0,
|
||||
yylast_ = 57, ///< Last index in yytable_.
|
||||
yylast_ = 62, ///< Last index in yytable_.
|
||||
yynnts_ = 8, ///< Number of nonterminal symbols.
|
||||
yyfinal_ = 17, ///< Termination state number.
|
||||
yyfinal_ = 18, ///< Termination state number.
|
||||
yyterror_ = 1,
|
||||
yyerrcode_ = 256,
|
||||
yyntokens_ = 25 ///< Number of tokens.
|
||||
@@ -847,11 +846,10 @@ namespace isc { namespace eval {
|
||||
value.copy< TokenOption::RepresentationType > (other.value);
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
value.copy< std::string > (other.value);
|
||||
break;
|
||||
|
||||
@@ -880,11 +878,10 @@ namespace isc { namespace eval {
|
||||
value.copy< TokenOption::RepresentationType > (v);
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
value.copy< std::string > (v);
|
||||
break;
|
||||
|
||||
@@ -958,11 +955,10 @@ namespace isc { namespace eval {
|
||||
value.template destroy< TokenOption::RepresentationType > ();
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
value.template destroy< std::string > ();
|
||||
break;
|
||||
|
||||
@@ -997,11 +993,10 @@ namespace isc { namespace eval {
|
||||
value.move< TokenOption::RepresentationType > (s.value);
|
||||
break;
|
||||
|
||||
case 20: // "constant string"
|
||||
case 21: // "integer"
|
||||
case 22: // "constant hexstring"
|
||||
case 23: // "option name"
|
||||
case 24: // TOKEN
|
||||
case 21: // "constant string"
|
||||
case 22: // "integer"
|
||||
case 23: // "constant hexstring"
|
||||
case 24: // "option name"
|
||||
value.move< std::string > (s.value);
|
||||
break;
|
||||
|
||||
@@ -1095,6 +1090,12 @@ namespace isc { namespace eval {
|
||||
return symbol_type (token::TOKEN_SUBSTRING, l);
|
||||
}
|
||||
|
||||
EvalParser::symbol_type
|
||||
EvalParser::make_CONCAT (const location_type& l)
|
||||
{
|
||||
return symbol_type (token::TOKEN_CONCAT, l);
|
||||
}
|
||||
|
||||
EvalParser::symbol_type
|
||||
EvalParser::make_NOT (const location_type& l)
|
||||
{
|
||||
@@ -1203,16 +1204,10 @@ namespace isc { namespace eval {
|
||||
return symbol_type (token::TOKEN_OPTION_NAME, v, l);
|
||||
}
|
||||
|
||||
EvalParser::symbol_type
|
||||
EvalParser::make_TOKEN (const std::string& v, const location_type& l)
|
||||
{
|
||||
return symbol_type (token::TOKEN_TOKEN, v, l);
|
||||
}
|
||||
|
||||
|
||||
#line 13 "parser.yy" // lalr1.cc:392
|
||||
} } // isc::eval
|
||||
#line 1216 "parser.h" // lalr1.cc:392
|
||||
#line 1211 "parser.h" // lalr1.cc:392
|
||||
|
||||
|
||||
|
||||
|
@@ -39,6 +39,7 @@ using namespace isc::eval;
|
||||
EQUAL "=="
|
||||
OPTION "option"
|
||||
SUBSTRING "substring"
|
||||
CONCAT "concat"
|
||||
NOT "not"
|
||||
AND "and"
|
||||
OR "or"
|
||||
@@ -59,7 +60,6 @@ using namespace isc::eval;
|
||||
%token <std::string> INTEGER "integer"
|
||||
%token <std::string> HEXSTRING "constant hexstring"
|
||||
%token <std::string> OPTION_NAME "option name"
|
||||
%token <std::string> TOKEN
|
||||
|
||||
%type <uint16_t> option_code
|
||||
%type <TokenOption::RepresentationType> option_repr_type
|
||||
@@ -148,8 +148,11 @@ string_expr : STRING
|
||||
TokenPtr sub(new TokenSubstring());
|
||||
ctx.expression.push_back(sub);
|
||||
}
|
||||
| TOKEN
|
||||
// Temporary unused token to avoid explicit but long errors
|
||||
| CONCAT "(" string_expr "," string_expr ")"
|
||||
{
|
||||
TokenPtr conc(new TokenConcat());
|
||||
ctx.expression.push_back(conc);
|
||||
}
|
||||
;
|
||||
|
||||
option_code : INTEGER
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Generated 20160219
|
||||
// Generated at 20160219
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Positions for Bison parsers in C++
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Generated 20160219
|
||||
// Generated at 20160219
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Stack handling for Bison parsers in C++
|
||||
|
@@ -81,14 +81,6 @@ public:
|
||||
EXPECT_EQ(expected_code, opt->getCode());
|
||||
}
|
||||
|
||||
/// @brief checks if the given token is a substring operator
|
||||
void checkTokenSubstring(const TokenPtr& token) {
|
||||
ASSERT_TRUE(token);
|
||||
boost::shared_ptr<TokenSubstring> sub =
|
||||
boost::dynamic_pointer_cast<TokenSubstring>(token);
|
||||
EXPECT_TRUE(sub);
|
||||
}
|
||||
|
||||
/// @brief check if the given token is relay4 with the expected code
|
||||
void checkTokenRelay4(const TokenPtr& token, uint16_t code) {
|
||||
ASSERT_TRUE(token);
|
||||
@@ -101,6 +93,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief checks if the given token is a substring operator
|
||||
void checkTokenSubstring(const TokenPtr& token) {
|
||||
ASSERT_TRUE(token);
|
||||
boost::shared_ptr<TokenSubstring> sub =
|
||||
boost::dynamic_pointer_cast<TokenSubstring>(token);
|
||||
EXPECT_TRUE(sub);
|
||||
}
|
||||
|
||||
/// @brief checks if the given token is a concat operator
|
||||
void checkTokenConcat(const TokenPtr& token) {
|
||||
ASSERT_TRUE(token);
|
||||
boost::shared_ptr<TokenConcat> conc =
|
||||
boost::dynamic_pointer_cast<TokenConcat>(token);
|
||||
EXPECT_TRUE(conc);
|
||||
}
|
||||
|
||||
/// @brief checks if the given expression raises the expected message
|
||||
/// when it is parsed.
|
||||
void checkError(const string& expr, const string& msg) {
|
||||
@@ -275,6 +283,33 @@ TEST_F(EvalContextTest, optionHex) {
|
||||
checkTokenOption(eval.expression.at(0), 123);
|
||||
}
|
||||
|
||||
// This test checks that the relay[code].hex can be used in expressions.
|
||||
TEST_F(EvalContextTest, relay4Option) {
|
||||
|
||||
EvalContext eval(Option::V4);
|
||||
EXPECT_NO_THROW(parsed_ =
|
||||
eval.parseString("relay4[13].hex == 'thirteen'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
ASSERT_EQ(3, eval.expression.size());
|
||||
|
||||
TokenPtr tmp1 = eval.expression.at(0);
|
||||
TokenPtr tmp2 = eval.expression.at(1);
|
||||
TokenPtr tmp3 = eval.expression.at(2);
|
||||
|
||||
checkTokenRelay4(tmp1, 13);
|
||||
checkTokenString(tmp2, "thirteen");
|
||||
checkTokenEq(tmp3);
|
||||
}
|
||||
|
||||
// Verify that relay4[13] is not usable in v6
|
||||
// There will be a separate relay accessor for v6.
|
||||
TEST_F(EvalContextTest, relay4Error) {
|
||||
universe_ = Option::V6;
|
||||
|
||||
checkError("relay4[13].hex == 'thirteen'",
|
||||
"<string>:1.1-6: relay4 can only be used in DHCPv4.");
|
||||
}
|
||||
|
||||
// Test parsing of logical operators
|
||||
TEST_F(EvalContextTest, logicalOps) {
|
||||
// option.exists
|
||||
@@ -402,31 +437,23 @@ TEST_F(EvalContextTest, substring) {
|
||||
checkTokenSubstring(tmp4);
|
||||
}
|
||||
|
||||
// This test checks that the relay[code].hex can be used in expressions.
|
||||
TEST_F(EvalContextTest, relay4Option) {
|
||||
|
||||
// Test the parsing of a concat expression
|
||||
TEST_F(EvalContextTest, concat) {
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ =
|
||||
eval.parseString("relay4[13].hex == 'thirteen'"));
|
||||
eval.parseString("concat('foo','bar') == 'foobar'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
ASSERT_EQ(3, eval.expression.size());
|
||||
|
||||
ASSERT_EQ(5, eval.expression.size());
|
||||
|
||||
TokenPtr tmp1 = eval.expression.at(0);
|
||||
TokenPtr tmp2 = eval.expression.at(1);
|
||||
TokenPtr tmp3 = eval.expression.at(2);
|
||||
|
||||
checkTokenRelay4(tmp1, 13);
|
||||
checkTokenString(tmp2, "thirteen");
|
||||
checkTokenEq(tmp3);
|
||||
}
|
||||
|
||||
// Verify that relay4[13] is not usable in v6
|
||||
// There will be a separate relay accessor for v6.
|
||||
TEST_F(EvalContextTest, relay4Error) {
|
||||
universe_ = Option::V6;
|
||||
|
||||
checkError("relay4[13].hex == 'thirteen'",
|
||||
"<string>:1.1-6: relay4 can only be used in DHCPv4.");
|
||||
checkTokenString(tmp1, "foo");
|
||||
checkTokenString(tmp2, "bar");
|
||||
checkTokenConcat(tmp3);
|
||||
}
|
||||
|
||||
// Test some scanner error cases
|
||||
@@ -439,6 +466,7 @@ TEST_F(EvalContextTest, scanErrors) {
|
||||
checkError("subtring", "<string>:1.1: Invalid character: s");
|
||||
checkError("foo", "<string>:1.1: Invalid character: f");
|
||||
checkError(" bar", "<string>:1.2: Invalid character: b");
|
||||
checkError("relay[12].hex == 'foo'", "<string>:1.1: Invalid character: r");
|
||||
}
|
||||
|
||||
// Tests some scanner/parser error cases
|
||||
@@ -546,8 +574,7 @@ TEST_F(EvalContextTest, parseErrors) {
|
||||
"<string>:1.19-20: syntax error, unexpected ==, "
|
||||
"expecting end of file");
|
||||
checkError("substring('foobar') == 'f'",
|
||||
"<string>:1.19: syntax error, "
|
||||
"unexpected ), expecting \",\"");
|
||||
"<string>:1.19: syntax error, unexpected ), expecting \",\"");
|
||||
checkError("substring('foobar',3) == 'bar'",
|
||||
"<string>:1.21: syntax error, unexpected ), expecting \",\"");
|
||||
checkError("substring('foobar','3',3) == 'bar'",
|
||||
@@ -555,6 +582,10 @@ TEST_F(EvalContextTest, parseErrors) {
|
||||
"expecting integer");
|
||||
checkError("substring('foobar',1,a) == 'foo'",
|
||||
"<string>:1.22: Invalid character: a");
|
||||
checkError("concat('foobar') == 'f'",
|
||||
"<string>:1.16: syntax error, unexpected ), expecting \",\"");
|
||||
checkError("concat('foo','bar','') == 'foobar'",
|
||||
"<string>:1.19: syntax error, unexpected \",\", expecting )");
|
||||
}
|
||||
|
||||
// Tests some type error cases
|
||||
@@ -568,6 +599,10 @@ TEST_F(EvalContextTest, typeErrors) {
|
||||
checkError("substring('foobar',0x32,1) == 'foo'",
|
||||
"<string>:1.20-23: syntax error, unexpected constant "
|
||||
"hexstring, expecting integer");
|
||||
checkError("concat('foo',3) == 'foo3'",
|
||||
"<string>:1.14: syntax error, unexpected integer");
|
||||
checkError("concat(3,'foo') == '3foo'",
|
||||
"<string>:1.8: syntax error, unexpected integer");
|
||||
checkError("('foo' == 'bar') == 'false'",
|
||||
"<string>:1.18-19: syntax error, unexpected ==, "
|
||||
"expecting end of file");
|
||||
|
@@ -341,7 +341,7 @@ TEST_F(TokenTest, optionHexString4) {
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option value is able to check
|
||||
// the existence ofthe option from an IPv4 packet.
|
||||
// the existence of the option from an IPv4 packet.
|
||||
TEST_F(TokenTest, optionExistsString4) {
|
||||
TokenPtr found;
|
||||
TokenPtr not_found;
|
||||
@@ -420,7 +420,7 @@ TEST_F(TokenTest, optionHexString6) {
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option value is able to check
|
||||
// the existence ofthe option from an IPv6 packet.
|
||||
// the existence of the option from an IPv6 packet.
|
||||
TEST_F(TokenTest, optionExistsString6) {
|
||||
TokenPtr found;
|
||||
TokenPtr not_found;
|
||||
@@ -441,6 +441,109 @@ TEST_F(TokenTest, optionExistsString6) {
|
||||
EXPECT_EQ("true", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that the existing relay option can be found.
|
||||
TEST_F(TokenTest, relayOption) {
|
||||
|
||||
// Insert relay option with sub-options 1 and 13
|
||||
insertRelay4Option();
|
||||
|
||||
// Creating the token should be safe.
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
|
||||
|
||||
// We should be able to evaluate it.
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have one value on the stack
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// The option should be found and relay[13] should evaluate to the
|
||||
// content of that sub-option, i.e. "thirteen"
|
||||
EXPECT_EQ("thirteen", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that the code properly handles cases when
|
||||
// there is a RAI option, but there's no requested sub-option.
|
||||
TEST_F(TokenTest, relayOptionNoSuboption) {
|
||||
|
||||
// Insert relay option with sub-options 1 and 13
|
||||
insertRelay4Option();
|
||||
|
||||
// Creating the token should be safe.
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(15, TokenOption::TEXTUAL)));
|
||||
|
||||
// We should be able to evaluate it.
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have one value on the stack
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// The option should NOT be found (there is no sub-option 15),
|
||||
// so the expression should evaluate to ""
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that the code properly handles cases when
|
||||
// there's no RAI option at all.
|
||||
TEST_F(TokenTest, relayOptionNoRai) {
|
||||
|
||||
// We didn't call insertRelay4Option(), so there's no RAI option.
|
||||
|
||||
// Creating the token should be safe.
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
|
||||
|
||||
// We should be able to evaluate it.
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have one value on the stack
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// The option should NOT be found (there is no sub-option 13),
|
||||
// so the expression should evaluate to ""
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that only the RAI is searched for the requested
|
||||
// sub-option.
|
||||
TEST_F(TokenTest, relayRAIOnly) {
|
||||
|
||||
// Insert relay option with sub-options 1 and 13
|
||||
insertRelay4Option();
|
||||
|
||||
// Add options 13 and 70 to the packet.
|
||||
OptionPtr opt13(new OptionString(Option::V4, 13, "THIRTEEN"));
|
||||
OptionPtr opt70(new OptionString(Option::V4, 70, "SEVENTY"));
|
||||
pkt4_->addOption(opt13);
|
||||
pkt4_->addOption(opt70);
|
||||
|
||||
// The situation is as follows:
|
||||
// Packet:
|
||||
// - option 13 (containing "THIRTEEN")
|
||||
// - option 82 (rai)
|
||||
// - option 1 (containing "one")
|
||||
// - option 13 (containing "thirteen")
|
||||
|
||||
// Let's try to get option 13. It should get the one from RAI
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("thirteen", values_.top());
|
||||
|
||||
// Try to get option 1. It should get the one from RAI
|
||||
clearStack();
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(1, TokenOption::TEXTUAL)));
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("one", values_.top());
|
||||
|
||||
// Try to get option 70. It should fail, as there's no such
|
||||
// sub option in RAI.
|
||||
clearStack();
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(70, TokenOption::TEXTUAL)));
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an == operator is able to
|
||||
// compare two values (with incorrectly built stack).
|
||||
TEST_F(TokenTest, optionEqualInvalid) {
|
||||
@@ -490,7 +593,7 @@ TEST_F(TokenTest, optionEqualTrue) {
|
||||
|
||||
// This test checks if a token representing a not is able to
|
||||
// negate a boolean value (with incorrectly built stack).
|
||||
TEST_F(TokenTest, optionNotInvalid) {
|
||||
TEST_F(TokenTest, operatorNotInvalid) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenNot()));
|
||||
|
||||
@@ -504,7 +607,7 @@ TEST_F(TokenTest, optionNotInvalid) {
|
||||
|
||||
// This test checks if a token representing a not operator is able to
|
||||
// negate a boolean value.
|
||||
TEST_F(TokenTest, optionNot) {
|
||||
TEST_F(TokenTest, operatorNot) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenNot()));
|
||||
|
||||
@@ -523,7 +626,7 @@ TEST_F(TokenTest, optionNot) {
|
||||
|
||||
// This test checks if a token representing an and is able to
|
||||
// conjugate two values (with incorrectly built stack).
|
||||
TEST_F(TokenTest, optionAndInvalid) {
|
||||
TEST_F(TokenTest, operatorAndInvalid) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenAnd()));
|
||||
|
||||
@@ -547,7 +650,7 @@ TEST_F(TokenTest, optionAndInvalid) {
|
||||
|
||||
// This test checks if a token representing an and operator is able to
|
||||
// conjugate false with another logical
|
||||
TEST_F(TokenTest, optionAndFalse) {
|
||||
TEST_F(TokenTest, operatorAndFalse) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenAnd()));
|
||||
|
||||
@@ -574,7 +677,7 @@ TEST_F(TokenTest, optionAndFalse) {
|
||||
|
||||
// This test checks if a token representing an and is able to
|
||||
// conjugate two true values.
|
||||
TEST_F(TokenTest, optionAndTrue) {
|
||||
TEST_F(TokenTest, operatorAndTrue) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenAnd()));
|
||||
|
||||
@@ -589,7 +692,7 @@ TEST_F(TokenTest, optionAndTrue) {
|
||||
|
||||
// This test checks if a token representing an or is able to
|
||||
// combinate two values (with incorrectly built stack).
|
||||
TEST_F(TokenTest, optionOrInvalid) {
|
||||
TEST_F(TokenTest, operatorOrInvalid) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenOr()));
|
||||
|
||||
@@ -613,7 +716,7 @@ TEST_F(TokenTest, optionOrInvalid) {
|
||||
|
||||
// This test checks if a token representing an or is able to
|
||||
// conjugate two false values.
|
||||
TEST_F(TokenTest, optionOrFalse) {
|
||||
TEST_F(TokenTest, operatorOrFalse) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenOr()));
|
||||
|
||||
@@ -628,7 +731,7 @@ TEST_F(TokenTest, optionOrFalse) {
|
||||
|
||||
// This test checks if a token representing an == operator is able to
|
||||
// conjugate true with another logical
|
||||
TEST_F(TokenTest, optionOrTrue) {
|
||||
TEST_F(TokenTest, operatorOrTrue) {
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenOr()));
|
||||
|
||||
@@ -655,7 +758,7 @@ TEST_F(TokenTest, optionOrTrue) {
|
||||
|
||||
};
|
||||
|
||||
// This test checks if an a token representing a substring request
|
||||
// This test checks if a token representing a substring request
|
||||
// throws an exception if there aren't enough values on the stack.
|
||||
// The stack from the top is: length, start, string.
|
||||
// The actual packet is not used.
|
||||
@@ -663,7 +766,7 @@ TEST_F(TokenTest, substringNotEnoughValues) {
|
||||
ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
|
||||
|
||||
// Subsring requires three values on the stack, try
|
||||
// with 0, 1 and 2 all should thorw an exception
|
||||
// with 0, 1 and 2 all should throw an exception
|
||||
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
||||
|
||||
values_.push("");
|
||||
@@ -790,7 +893,7 @@ TEST_F(TokenTest, substringEquals) {
|
||||
|
||||
// The substring values
|
||||
// Subsring requires three values on the stack, try
|
||||
// with 0, 1 and 2 all should thorw an exception
|
||||
// with 0, 1 and 2 all should throw an exception
|
||||
values_.push("foobar");
|
||||
values_.push("1");
|
||||
values_.push("4");
|
||||
@@ -813,7 +916,7 @@ TEST_F(TokenTest, substringEquals) {
|
||||
|
||||
// The substring values
|
||||
// Subsring requires three values on the stack, try
|
||||
// with 0, 1 and 2 all should thorw an exception
|
||||
// with 0, 1 and 2 all should throw an exception
|
||||
values_.push("foobar");
|
||||
values_.push("1");
|
||||
values_.push("4");
|
||||
@@ -829,105 +932,24 @@ TEST_F(TokenTest, substringEquals) {
|
||||
|
||||
}
|
||||
|
||||
// This test checks that the existing relay option can be found.
|
||||
TEST_F(TokenTest, relayOption) {
|
||||
// This test checks if a token representing a concat request
|
||||
// throws an exception if there aren't enough values on the stack.
|
||||
// The actual packet is not used.
|
||||
TEST_F(TokenTest, concat) {
|
||||
ASSERT_NO_THROW(t_.reset(new TokenConcat()));
|
||||
|
||||
// Insert relay option with sub-options 1 and 13
|
||||
insertRelay4Option();
|
||||
// Concat requires two values on the stack, try
|
||||
// with 0 and 1 both should throw an exception
|
||||
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
||||
|
||||
// Creating the token should be safe.
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
|
||||
values_.push("foo");
|
||||
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
||||
|
||||
// We should be able to evaluate it.
|
||||
// Two should work
|
||||
values_.push("bar");
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have one value on the stack
|
||||
// Check the result
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// The option should be found and relay[13] should evaluate to the
|
||||
// content of that sub-option, i.e. "thirteen"
|
||||
EXPECT_EQ("thirteen", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that the code properly handles cases when
|
||||
// there is a RAI option, but there's no requested sub-option.
|
||||
TEST_F(TokenTest, relayOptionNoSuboption) {
|
||||
|
||||
// Insert relay option with sub-options 1 and 13
|
||||
insertRelay4Option();
|
||||
|
||||
// Creating the token should be safe.
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(15, TokenOption::TEXTUAL)));
|
||||
|
||||
// We should be able to evaluate it.
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have one value on the stack
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// The option should NOT be found (there is no sub-option 15),
|
||||
// so the expression should evaluate to ""
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that the code properly handles cases when
|
||||
// there's no RAI option at all.
|
||||
TEST_F(TokenTest, relayOptionNoRai) {
|
||||
|
||||
// We didn't call insertRelay4Option(), so there's no RAI option.
|
||||
|
||||
// Creating the token should be safe.
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
|
||||
|
||||
// We should be able to evaluate it.
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have one value on the stack
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// The option should NOT be found (there is no sub-option 13),
|
||||
// so the expression should evaluate to ""
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This test checks that only the RAI is searched for the requested
|
||||
// sub-option.
|
||||
TEST_F(TokenTest, relayRAIOnly) {
|
||||
|
||||
// Insert relay option with sub-options 1 and 13
|
||||
insertRelay4Option();
|
||||
|
||||
// Add options 13 and 70 to the packet.
|
||||
OptionPtr opt13(new OptionString(Option::V4, 13, "THIRTEEN"));
|
||||
OptionPtr opt70(new OptionString(Option::V4, 70, "SEVENTY"));
|
||||
pkt4_->addOption(opt13);
|
||||
pkt4_->addOption(opt70);
|
||||
|
||||
// The situation is as follows:
|
||||
// Packet:
|
||||
// - option 13 (containing "THIRTEEN")
|
||||
// - option 82 (rai)
|
||||
// - option 1 (containing "one")
|
||||
// - option 13 (containing "thirteen")
|
||||
|
||||
// Let's try to get option 13. It should get the one from RAI
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("thirteen", values_.top());
|
||||
|
||||
// Try to get option 1. It should get the one from RAI
|
||||
clearStack();
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(1, TokenOption::TEXTUAL)));
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("one", values_.top());
|
||||
|
||||
// Try to get option 70. It should fail, as there's no such
|
||||
// sub option in RAI.
|
||||
clearStack();
|
||||
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(70, TokenOption::TEXTUAL)));
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("", values_.top());
|
||||
EXPECT_EQ("foobar", values_.top());
|
||||
}
|
||||
|
@@ -84,6 +84,23 @@ TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
|
||||
values.push(opt_str);
|
||||
}
|
||||
|
||||
TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
|
||||
const RepresentationType& rep_type)
|
||||
:TokenOption(option_code, rep_type) {
|
||||
}
|
||||
|
||||
OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
|
||||
|
||||
// Check if there is Relay Agent Option.
|
||||
OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
|
||||
if (!rai) {
|
||||
return (OptionPtr());
|
||||
}
|
||||
|
||||
// If there is, try to return its suboption
|
||||
return (rai->getOption(option_code_));
|
||||
}
|
||||
|
||||
void
|
||||
TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
|
||||
@@ -178,21 +195,21 @@ TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
values.push(string_str.substr(start_pos, length));
|
||||
}
|
||||
|
||||
TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
|
||||
const RepresentationType& rep_type)
|
||||
:TokenOption(option_code, rep_type) {
|
||||
}
|
||||
void
|
||||
TokenConcat::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
|
||||
OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
|
||||
|
||||
// Check if there is Relay Agent Option.
|
||||
OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
|
||||
if (!rai) {
|
||||
return (OptionPtr());
|
||||
if (values.size() < 2) {
|
||||
isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
|
||||
"2 values for concat, got " << values.size());
|
||||
}
|
||||
|
||||
// If there is, try to return its suboption
|
||||
return (rai->getOption(option_code_));
|
||||
string op1 = values.top();
|
||||
values.pop();
|
||||
string op2 = values.top();
|
||||
values.pop(); // Dammit, std::stack interface is awkward.
|
||||
|
||||
// The top of the stack was evaluated last so this is the right order
|
||||
values.push(op2 + op1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -219,6 +219,34 @@ protected:
|
||||
RepresentationType representation_type_; ///< Representation type.
|
||||
};
|
||||
|
||||
/// @brief Represents a sub-option inserted by the DHCPv4 relay.
|
||||
///
|
||||
/// DHCPv4 relays insert sub-options in option 82. This token attempts to extract
|
||||
/// such sub-options. Note in DHCPv6 it is radically different (possibly
|
||||
/// many encapsulation levels), thus there are separate classes for v4 and v6.
|
||||
///
|
||||
/// This token can represent the following expressions:
|
||||
/// relay[13].text - Textual representation of sub-option 13 in RAI (option 82)
|
||||
/// relay[13].hex - Binary representation of sub-option 13 in RAI (option 82)
|
||||
/// relay[vendor-class].text - Text representation of sub-option X in RAI (option 82)
|
||||
/// relay[vendor-class].hex - Binary representation of sub-option X in RAI (option 82)
|
||||
class TokenRelay4Option : public TokenOption {
|
||||
public:
|
||||
|
||||
/// @brief Constructor for extracting sub-option from RAI (option 82)
|
||||
///
|
||||
/// @param option_code code of the requested sub-option
|
||||
/// @param rep_type code representation (currently .hex and .text are supported)
|
||||
TokenRelay4Option(const uint16_t option_code,
|
||||
const RepresentationType& rep_type);
|
||||
|
||||
protected:
|
||||
/// @brief Attempts to obtain specified sub-option of option 82 from the packet
|
||||
/// @param pkt DHCPv4 packet (that hopefully contains option 82)
|
||||
/// @return found sub-option from option 82
|
||||
virtual OptionPtr getOption(const Pkt& pkt);
|
||||
};
|
||||
|
||||
/// @brief Token that represents equality operator (compares two other tokens)
|
||||
///
|
||||
/// For example in the expression option[vendor-class].text == "MSFT"
|
||||
@@ -300,32 +328,27 @@ public:
|
||||
void evaluate(const Pkt& pkt, ValueStack& values);
|
||||
};
|
||||
|
||||
/// @brief Represents a sub-option inserted by the DHCPv4 relay.
|
||||
/// @brief Token that represents concat operator (concatenates two other tokens)
|
||||
///
|
||||
/// DHCPv4 relays insert sub-options in option 82. This token attempts to extract
|
||||
/// such sub-options. Note in DHCPv6 it is radically different (possibly
|
||||
/// many encapsulation levels), thus there are separate classes for v4 and v6.
|
||||
///
|
||||
/// This token can represent the following expressions:
|
||||
/// relay[13].text - Textual representation of sub-option 13 in RAI (option 82)
|
||||
/// relay[13].hex - Binary representation of sub-option 13 in RAI (option 82)
|
||||
/// relay[vendor-class].text - Text representation of sub-option X in RAI (option 82)
|
||||
/// relay[vendor-class].hex - Binary representation of sub-option X in RAI (option 82)
|
||||
class TokenRelay4Option : public TokenOption {
|
||||
/// For example in the sub-expression "concat('foo','bar')" the result
|
||||
/// of the evaluation is "foobar"
|
||||
class TokenConcat : public Token {
|
||||
public:
|
||||
/// @brief Constructor (does nothing)
|
||||
TokenConcat() {}
|
||||
|
||||
/// @brief Constructor for extracting sub-option from RAI (option 82)
|
||||
/// @brief Concatenate two values.
|
||||
///
|
||||
/// @param option_code code of the requested sub-option
|
||||
/// @param rep_type code representation (currently .hex and .text are supported)
|
||||
TokenRelay4Option(const uint16_t option_code,
|
||||
const RepresentationType& rep_type);
|
||||
|
||||
protected:
|
||||
/// @brief Attempts to obtain specified sub-option of option 82 from the packet
|
||||
/// @param pkt DHCPv4 packet (that hopefully contains option 82)
|
||||
/// @return found sub-option from option 82
|
||||
virtual OptionPtr getOption(const Pkt& pkt);
|
||||
/// Evaluation does not use packet information, but rather consumes the last
|
||||
/// two parameters. It does a simple string concatenation. It requires
|
||||
/// at least two parameters to be present on stack.
|
||||
///
|
||||
/// @throw EvalBadStack if there are less than 2 values on stack
|
||||
///
|
||||
/// @param pkt (unused)
|
||||
/// @param values - stack of values (2 arguments will be popped, 1 result
|
||||
/// will be pushed)
|
||||
void evaluate(const Pkt& pkt, ValueStack& values);
|
||||
};
|
||||
|
||||
/// @brief Token that represents logical negation operator
|
||||
|
Reference in New Issue
Block a user