Browse Source

[4088fd] Split the syntax into untyped/typed

Francis Dupont 9 years ago
parent
commit
2760bbdf57
6 changed files with 573 additions and 209 deletions
  1. 129 89
      src/lib/eval/lexer.cc
  2. 15 0
      src/lib/eval/lexer.ll
  3. 207 55
      src/lib/eval/parser.cc
  4. 72 28
      src/lib/eval/parser.h
  5. 68 0
      src/lib/eval/parser.yy
  6. 82 37
      src/lib/eval/tests/context_unittest.cc

+ 129 - 89
src/lib/eval/lexer.cc

@@ -469,8 +469,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 15
-#define YY_END_OF_BUFFER 16
+#define YY_NUM_RULES 18
+#define YY_END_OF_BUFFER 19
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -478,12 +478,14 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[40] =
+static yyconst flex_int16_t yy_accept[55] =
     {   0,
-        0,    0,   16,   14,    1,    2,   14,    9,   10,   13,
-        5,    5,   14,   11,   12,   14,   14,    1,    2,    0,
-        3,    5,    0,    6,    0,    0,    4,    0,    0,    0,
-        0,    0,    0,    7,    0,    0,    0,    8,    0
+        0,    0,   19,   17,    1,    2,   17,   12,   13,   16,
+        7,    7,   17,   14,   15,   17,   17,   17,    1,    2,
+        0,    5,    0,    0,    0,    7,    0,    8,    0,    0,
+        0,    3,    0,    6,    0,    0,    0,    0,    0,    0,
+        0,    4,    0,    0,    0,    9,    0,    0,    0,    0,
+        0,   11,   10,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -492,16 +494,16 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    2,    1,    1,    1,    1,    1,    1,    4,    5,
-        6,    1,    1,    7,    1,    1,    1,    8,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    1,    1,    1,
-       10,    1,    1,    1,   11,   11,   11,   11,   11,   11,
+        6,    1,    1,    7,    8,    1,    1,    9,   10,   10,
+       10,   10,   10,   10,   10,   10,   10,   11,    1,    1,
+       12,    1,    1,    1,   13,   13,   13,   13,   13,   13,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,   12,    1,    1,
-       13,    1,   14,    1,    1,    1,   11,   15,   11,   11,
+        1,    1,    1,    1,    1,    1,    1,   14,    1,    1,
+       15,    1,   16,    1,    1,    1,   17,   18,   13,   19,
 
-       11,   11,   16,    1,   17,    1,    1,    1,    1,   18,
-       19,   20,    1,   21,   22,   23,   24,    1,    1,   12,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+       20,   13,   21,    1,   22,    1,    1,   23,    1,   24,
+       25,   26,    1,   27,   28,   29,   30,    1,    1,   14,
+       31,    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,
@@ -518,59 +520,72 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[25] =
+static yyconst flex_int32_t yy_meta[32] =
     {   0,
-        1,    1,    2,    1,    1,    1,    1,    3,    3,    1,
-        3,    1,    1,    1,    3,    1,    1,    1,    1,    1,
-        1,    1,    1,    1
+        1,    1,    2,    1,    1,    1,    1,    1,    3,    3,
+        1,    1,    3,    1,    1,    1,    3,    3,    3,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1
     } ;
 
-static yyconst flex_int16_t yy_base[42] =
+static yyconst flex_int16_t yy_base[57] =
     {   0,
-        0,    0,   55,   56,   52,   50,   48,   56,   56,   56,
-       17,   19,   41,   56,   56,   30,   25,   46,   44,   42,
-       56,   22,    0,   56,   22,   29,    0,   26,   20,   22,
-       17,   21,   17,   56,   20,   18,   19,   56,   56,   31,
-       30
+        0,    0,   84,   85,   81,   79,   28,   85,   85,   85,
+       25,   31,   69,   85,   85,   54,   49,   54,   75,   73,
+       71,   85,   38,   40,   29,   44,    0,   85,   45,   55,
+       43,   85,   39,    0,   49,   42,   38,   64,   42,   37,
+       38,   85,   37,   33,   39,   85,   36,   38,   32,   44,
+       30,   85,   85,   85,   62,   43
     } ;
 
-static yyconst flex_int16_t yy_def[42] =
+static yyconst flex_int16_t yy_def[57] =
     {   0,
-       39,    1,   39,   39,   39,   39,   40,   39,   39,   39,
-       39,   39,   39,   39,   39,   39,   39,   39,   39,   40,
-       39,   39,   41,   39,   39,   39,   41,   39,   39,   39,
-       39,   39,   39,   39,   39,   39,   39,   39,    0,   39,
-       39
+       54,    1,   54,   54,   54,   54,   55,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
+       55,   54,   55,   55,   55,   54,   56,   54,   54,   54,
+       54,   54,   55,   56,   54,   54,   54,   55,   54,   54,
+       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,    0,   54,   54
     } ;
 
-static yyconst flex_int16_t yy_nxt[81] =
+static yyconst flex_int16_t yy_nxt[117] =
     {   0,
-        4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
-        4,    4,   14,   15,    4,    4,    4,    4,   16,    4,
-        4,   17,    4,    4,   22,   22,   22,   22,   23,   22,
-       22,   20,   27,   20,   38,   37,   36,   35,   34,   33,
-       32,   31,   30,   29,   28,   21,   19,   18,   26,   25,
-       24,   21,   19,   18,   39,    3,   39,   39,   39,   39,
-       39,   39,   39,   39,   39,   39,   39,   39,   39,   39,
-       39,   39,   39,   39,   39,   39,   39,   39,   39,   39
+        4,    5,    6,    7,    8,    9,   10,    4,   11,   12,
+        4,   13,    4,    4,   14,   15,    4,    4,    4,    4,
+        4,    4,    4,    4,   16,    4,    4,   17,    4,   18,
+        4,   22,   22,   26,   26,   23,   24,   24,   27,   26,
+       26,   22,   22,   32,   25,   34,   24,   24,   24,   24,
+       53,   33,   26,   26,   52,   51,   50,   49,   48,   47,
+       46,   38,   21,   45,   21,   44,   43,   42,   41,   40,
+       39,   37,   36,   35,   22,   20,   19,   31,   30,   29,
+       28,   20,   19,   54,    3,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
+
+       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54
     } ;
 
-static yyconst flex_int16_t yy_chk[81] =
+static yyconst flex_int16_t yy_chk[117] =
     {   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,   11,   11,   12,   12,   11,   22,
-       22,   40,   41,   40,   37,   36,   35,   33,   32,   31,
-       30,   29,   28,   26,   25,   20,   19,   18,   17,   16,
-       13,    7,    6,    5,    3,   39,   39,   39,   39,   39,
-       39,   39,   39,   39,   39,   39,   39,   39,   39,   39,
-       39,   39,   39,   39,   39,   39,   39,   39,   39,   39
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    7,   25,   11,   11,    7,    7,    7,   11,   12,
+       12,   23,   33,   24,    7,   56,   23,   23,   24,   24,
+       51,   25,   26,   26,   50,   49,   48,   47,   45,   44,
+       43,   33,   55,   41,   55,   40,   39,   38,   37,   36,
+       35,   31,   30,   29,   21,   20,   19,   18,   17,   16,
+       13,    6,    5,    3,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
+
+       54,   54,   54,   54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54
     } ;
 
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[16] =
+static yyconst flex_int32_t yy_rule_can_match_eol[19] =
     {   0,
-0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     };
+0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     };
 
 static yy_state_type yy_last_accepting_state;
 static char *yy_last_accepting_cpos;
@@ -578,10 +593,10 @@ static char *yy_last_accepting_cpos;
 extern int yy_flex_debug;
 int yy_flex_debug = 1;
 
-static yyconst flex_int16_t yy_rule_linenum[15] =
+static yyconst flex_int16_t yy_rule_linenum[18] =
     {   0,
-       83,   87,   93,  103,  109,  132,  133,  134,  135,  136,
-      137,  138,  139,  141
+       83,   87,   93,  101,  107,  117,  123,  146,  147,  148,
+      149,  150,  151,  152,  153,  154,  156
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -648,7 +663,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 652 "lexer.cc"
+#line 667 "lexer.cc"
 
 #define INITIAL 0
 
@@ -931,7 +946,7 @@ YY_DECL
     loc.step();
 
 
-#line 935 "lexer.cc"
+#line 950 "lexer.cc"
 
 	while ( 1 )		/* loops until end-of-file is reached */
 		{
@@ -960,13 +975,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 >= 40 )
+				if ( yy_current_state >= 55 )
 					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_current_state != 39 );
+		while ( yy_current_state != 54 );
 		yy_cp = (yy_last_accepting_cpos);
 		yy_current_state = (yy_last_accepting_state);
 
@@ -995,13 +1010,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 < 15 )
+			else if ( yy_act < 18 )
 				fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
 				         (long)yy_rule_linenum[yy_act], yytext );
-			else if ( yy_act == 15 )
+			else if ( yy_act == 18 )
 				fprintf( stderr, "--accepting default rule (\"%s\")\n",
 				         yytext );
-			else if ( yy_act == 16 )
+			else if ( yy_act == 19 )
 				fprintf( stderr, "--(end of buffer or a NUL)\n" );
 			else
 				fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@ -1039,6 +1054,26 @@ case 3:
 YY_RULE_SETUP
 #line 93 "lexer.ll"
 {
+    // A string containing a number. Quotes should be removed, see below.
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+
+    return isc::eval::EvalParser::make_NUMBER(tmp, loc);
+}
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 101 "lexer.ll"
+{
+     // A string containing the "all" keyword.
+
+     return isc::eval::EvalParser::make_ALL("all", loc);
+}
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 107 "lexer.ll"
+{
     // A string has been matched. It contains the actual string and single quotes.
     // We need to get those quotes out of the way and just use its content, e.g.
     // for 'foo' we should get foo
@@ -1048,18 +1083,18 @@ YY_RULE_SETUP
     return isc::eval::EvalParser::make_STRING(tmp, loc);
 }
 	YY_BREAK
-case 4:
+case 6:
 YY_RULE_SETUP
-#line 103 "lexer.ll"
+#line 117 "lexer.ll"
 {
     // A hex string has been matched. It contains the '0x' or '0X' header
     // followed by at least one hexadecimal digit.
     return isc::eval::EvalParser::make_HEXSTRING(yytext, loc);
 }
 	YY_BREAK
-case 5:
+case 7:
 YY_RULE_SETUP
-#line 109 "lexer.ll"
+#line 123 "lexer.ll"
 {
     // A code (16 bit unsigned integer) was found.
     std::string tmp(yytext);
@@ -1083,61 +1118,66 @@ YY_RULE_SETUP
     return isc::eval::EvalParser::make_CODE(static_cast<uint16_t>(n), loc);
 }
 	YY_BREAK
-case 6:
+case 8:
 YY_RULE_SETUP
-#line 132 "lexer.ll"
+#line 146 "lexer.ll"
 return isc::eval::EvalParser::make_EQUAL(loc);
 	YY_BREAK
-case 7:
+case 9:
 YY_RULE_SETUP
-#line 133 "lexer.ll"
+#line 147 "lexer.ll"
 return isc::eval::EvalParser::make_OPTION(loc);
 	YY_BREAK
-case 8:
+case 10:
 YY_RULE_SETUP
-#line 134 "lexer.ll"
+#line 148 "lexer.ll"
 return isc::eval::EvalParser::make_SUBSTRING(loc);
 	YY_BREAK
-case 9:
+case 11:
+YY_RULE_SETUP
+#line 149 "lexer.ll"
+return isc::eval::EvalParser::make_UNTYPED(loc);
+	YY_BREAK
+case 12:
 YY_RULE_SETUP
-#line 135 "lexer.ll"
+#line 150 "lexer.ll"
 return isc::eval::EvalParser::make_LPAREN(loc);
 	YY_BREAK
-case 10:
+case 13:
 YY_RULE_SETUP
-#line 136 "lexer.ll"
+#line 151 "lexer.ll"
 return isc::eval::EvalParser::make_RPAREN(loc);
 	YY_BREAK
-case 11:
+case 14:
 YY_RULE_SETUP
-#line 137 "lexer.ll"
+#line 152 "lexer.ll"
 return isc::eval::EvalParser::make_LBRACKET(loc);
 	YY_BREAK
-case 12:
+case 15:
 YY_RULE_SETUP
-#line 138 "lexer.ll"
+#line 153 "lexer.ll"
 return isc::eval::EvalParser::make_RBRACKET(loc);
 	YY_BREAK
-case 13:
+case 16:
 YY_RULE_SETUP
-#line 139 "lexer.ll"
+#line 154 "lexer.ll"
 return isc::eval::EvalParser::make_COMA(loc);
 	YY_BREAK
-case 14:
+case 17:
 YY_RULE_SETUP
-#line 141 "lexer.ll"
+#line 156 "lexer.ll"
 driver.error (loc, "Invalid character: " + std::string(yytext));
 	YY_BREAK
 case YY_STATE_EOF(INITIAL):
-#line 142 "lexer.ll"
+#line 157 "lexer.ll"
 return isc::eval::EvalParser::make_END(loc);
 	YY_BREAK
-case 15:
+case 18:
 YY_RULE_SETUP
-#line 143 "lexer.ll"
+#line 158 "lexer.ll"
 ECHO;
 	YY_BREAK
-#line 1141 "lexer.cc"
+#line 1181 "lexer.cc"
 
 	case YY_END_OF_BUFFER:
 		{
@@ -1450,7 +1490,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 >= 40 )
+			if ( yy_current_state >= 55 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1483,11 +1523,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 >= 40 )
+		if ( yy_current_state >= 55 )
 			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 == 39);
+	yy_is_jam = (yy_current_state == 54);
 
 		return yy_is_jam ? 0 : yy_current_state;
 }
@@ -2225,7 +2265,7 @@ void yyfree (void * ptr )
 
 /* %ok-for-header */
 
-#line 143 "lexer.ll"
+#line 158 "lexer.ll"
 
 
 

+ 15 - 0
src/lib/eval/lexer.ll

@@ -90,6 +90,20 @@ blank [ \t]
     loc.step();
 }
 
+\'\-?{int}\' {
+    // A string containing a number. Quotes should be removed, see below.
+    std::string tmp(yytext+1);
+    tmp.resize(tmp.size() - 1);
+
+    return isc::eval::EvalParser::make_NUMBER(tmp, loc);
+}
+
+"'all'" {
+     // A string containing the "all" keyword.
+
+     return isc::eval::EvalParser::make_ALL("all", loc);
+}
+
 \'[^\'\n]*\' {
     // A string has been matched. It contains the actual string and single quotes.
     // We need to get those quotes out of the way and just use its content, e.g.
@@ -132,6 +146,7 @@ blank [ \t]
 "=="        return isc::eval::EvalParser::make_EQUAL(loc);
 "option"    return isc::eval::EvalParser::make_OPTION(loc);
 "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
+"untyped:"  return isc::eval::EvalParser::make_UNTYPED(loc);
 "("         return isc::eval::EvalParser::make_LPAREN(loc);
 ")"         return isc::eval::EvalParser::make_RPAREN(loc);
 "["         return isc::eval::EvalParser::make_LBRACKET(loc);

+ 207 - 55
src/lib/eval/parser.cc

@@ -251,12 +251,14 @@ namespace isc { namespace eval {
   {
       switch (that.type_get ())
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         value.move< std::string > (that.value);
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         value.move< uint16_t > (that.value);
         break;
 
@@ -275,12 +277,14 @@ namespace isc { namespace eval {
     state = that.state;
       switch (that.type_get ())
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         value.copy< std::string > (that.value);
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         value.copy< uint16_t > (that.value);
         break;
 
@@ -320,25 +324,39 @@ namespace isc { namespace eval {
         << yysym.location << ": ";
     switch (yytype)
     {
-            case 11: // "constant string"
+            case 12: // "a number in a constant string"
 
-#line 56 "parser.yy" // lalr1.cc:636
+#line 59 "parser.yy" // lalr1.cc:636
         { yyoutput << yysym.value.template as< std::string > (); }
-#line 328 "parser.cc" // lalr1.cc:636
+#line 332 "parser.cc" // lalr1.cc:636
         break;
 
-      case 12: // "constant hexstring"
+      case 13: // "the all constant string"
 
-#line 56 "parser.yy" // lalr1.cc:636
+#line 59 "parser.yy" // lalr1.cc:636
         { yyoutput << yysym.value.template as< std::string > (); }
-#line 335 "parser.cc" // lalr1.cc:636
+#line 339 "parser.cc" // lalr1.cc:636
         break;
 
-      case 13: // "option code"
+      case 14: // "constant string"
 
-#line 56 "parser.yy" // lalr1.cc:636
+#line 59 "parser.yy" // lalr1.cc:636
+        { yyoutput << yysym.value.template as< std::string > (); }
+#line 346 "parser.cc" // lalr1.cc:636
+        break;
+
+      case 15: // "constant hexstring"
+
+#line 59 "parser.yy" // lalr1.cc:636
+        { yyoutput << yysym.value.template as< std::string > (); }
+#line 353 "parser.cc" // lalr1.cc:636
+        break;
+
+      case 16: // "option code"
+
+#line 59 "parser.yy" // lalr1.cc:636
         { yyoutput << yysym.value.template as< uint16_t > (); }
-#line 342 "parser.cc" // lalr1.cc:636
+#line 360 "parser.cc" // lalr1.cc:636
         break;
 
 
@@ -538,12 +556,14 @@ namespace isc { namespace eval {
          when using variants.  */
         switch (yyr1_[yyn])
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         yylhs.value.build< std::string > ();
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         yylhs.value.build< uint16_t > ();
         break;
 
@@ -564,53 +584,161 @@ namespace isc { namespace eval {
         {
           switch (yyn)
             {
-  case 2:
-#line 65 "parser.yy" // lalr1.cc:859
+  case 4:
+#line 73 "parser.yy" // lalr1.cc:859
     {
     TokenPtr eq(new TokenEqual());
     ctx.expression.push_back(eq);
   }
-#line 574 "parser.cc" // lalr1.cc:859
+#line 594 "parser.cc" // lalr1.cc:859
     break;
 
-  case 4:
-#line 73 "parser.yy" // lalr1.cc:859
+  case 6:
+#line 81 "parser.yy" // lalr1.cc:859
     {
     TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
     ctx.expression.push_back(str);
   }
-#line 583 "parser.cc" // lalr1.cc:859
+#line 603 "parser.cc" // lalr1.cc:859
     break;
 
-  case 5:
-#line 77 "parser.yy" // lalr1.cc:859
+  case 7:
+#line 85 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
+    ctx.expression.push_back(str);
+  }
+#line 612 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 8:
+#line 89 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString("all"));
+    ctx.expression.push_back(str);
+  }
+#line 621 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 9:
+#line 93 "parser.yy" // lalr1.cc:859
     {
     TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
     ctx.expression.push_back(hex);
   }
-#line 592 "parser.cc" // lalr1.cc:859
+#line 630 "parser.cc" // lalr1.cc:859
     break;
 
-  case 6:
-#line 81 "parser.yy" // lalr1.cc:859
+  case 10:
+#line 97 "parser.yy" // lalr1.cc:859
     {
     TokenPtr opt(new TokenOption(yystack_[1].value.as< uint16_t > ()));
     ctx.expression.push_back(opt);
   }
-#line 601 "parser.cc" // lalr1.cc:859
+#line 639 "parser.cc" // lalr1.cc:859
     break;
 
-  case 7:
-#line 85 "parser.yy" // lalr1.cc:859
+  case 11:
+#line 101 "parser.yy" // lalr1.cc:859
     {
     TokenPtr sub(new TokenSubstring());
     ctx.expression.push_back(sub);
   }
-#line 610 "parser.cc" // lalr1.cc:859
+#line 648 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 12:
+#line 108 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr eq(new TokenEqual());
+    ctx.expression.push_back(eq);
+  }
+#line 657 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 13:
+#line 115 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
+    ctx.expression.push_back(str);
+  }
+#line 666 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 14:
+#line 119 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
+    ctx.expression.push_back(str);
+  }
+#line 675 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 15:
+#line 123 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString("all"));
+    ctx.expression.push_back(str);
+  }
+#line 684 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 16:
+#line 127 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
+    ctx.expression.push_back(hex);
+  }
+#line 693 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 17:
+#line 131 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr opt(new TokenOption(yystack_[1].value.as< uint16_t > ()));
+    ctx.expression.push_back(opt);
+  }
+#line 702 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 18:
+#line 135 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr sub(new TokenSubstring());
+    ctx.expression.push_back(sub);
+  }
+#line 711 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 19:
+#line 142 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
+    ctx.expression.push_back(str);
+  }
+#line 720 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 20:
+#line 149 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
+    ctx.expression.push_back(str);
+  }
+#line 729 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 21:
+#line 153 "parser.yy" // lalr1.cc:859
+    {
+    TokenPtr str(new TokenString("all"));
+    ctx.expression.push_back(str);
+  }
+#line 738 "parser.cc" // lalr1.cc:859
     break;
 
 
-#line 614 "parser.cc" // lalr1.cc:859
+#line 742 "parser.cc" // lalr1.cc:859
             default:
               break;
             }
@@ -865,67 +993,86 @@ namespace isc { namespace eval {
   }
 
 
-  const signed char EvalParser::yypact_ninf_ = -9;
+  const signed char EvalParser::yypact_ninf_ = -27;
 
   const signed char EvalParser::yytable_ninf_ = -1;
 
   const signed char
   EvalParser::yypact_[] =
   {
-      -1,    -4,    -6,    -9,    -9,     6,     5,     0,    -1,    -9,
-      -1,     2,     8,    -9,    -9,    -1,     9,    -1,    10,    -9
+       0,    -3,     1,    14,   -27,   -27,   -27,   -27,     8,   -27,
+      13,     5,    18,    15,    16,   -27,   -27,   -27,   -27,   -27,
+      31,   -27,    18,    24,    29,    21,    14,    14,   -27,   -27,
+      26,    28,    33,   -27,   -27,    34,   -27,    14,   -10,    35,
+     -27,   -27,    36,    14,   -27,    37,   -27
   };
 
   const unsigned char
   EvalParser::yydefact_[] =
   {
-       0,     0,     0,     4,     5,     0,     3,     0,     0,     1,
-       0,     0,     0,     2,     6,     0,     0,     0,     0,     7
+       0,     0,     0,     0,    14,    15,    13,    16,     0,     3,
+       0,     0,     0,     0,     0,     7,     8,     6,     9,     2,
+       5,     1,     0,     0,     0,     0,     0,     0,    12,    17,
+       0,     0,     0,     4,    19,     0,    10,     0,     0,     0,
+      20,    21,     0,     0,    18,     0,    11
   };
 
   const signed char
   EvalParser::yypgoto_[] =
   {
-      -9,    -9,    -8
+     -27,   -27,   -27,   -26,   -27,    -2,   -27,   -27
   };
 
   const signed char
   EvalParser::yydefgoto_[] =
   {
-      -1,     5,     6
+      -1,     8,    19,    20,     9,    10,    35,    42
   };
 
   const unsigned char
   EvalParser::yytable_[] =
   {
-      12,     8,    13,     1,     2,     7,     9,    16,    10,    18,
-       3,     4,    14,    11,    15,    17,     0,     0,    19
+      32,    33,    40,    41,     1,     2,     3,    11,    21,    12,
+      24,    39,     4,     5,     6,     7,    22,    45,    13,    14,
+      28,    23,     1,     2,    26,    25,    15,    16,    17,    18,
+       4,     5,     6,     7,    27,    29,    30,    31,    34,    36,
+      37,    38,    43,     0,     0,    44,    46
   };
 
   const signed char
   EvalParser::yycheck_[] =
   {
-       8,     7,    10,     4,     5,     9,     0,    15,     3,    17,
-      11,    12,    10,    13,     6,     6,    -1,    -1,     8
+      26,    27,    12,    13,     4,     5,     6,    10,     0,     8,
+      12,    37,    12,    13,    14,    15,     3,    43,     4,     5,
+      22,    16,     4,     5,     8,    10,    12,    13,    14,    15,
+      12,    13,    14,    15,     3,    11,     7,    16,    12,    11,
+       7,     7,     7,    -1,    -1,     9,     9
   };
 
   const unsigned char
   EvalParser::yystos_[] =
   {
-       0,     4,     5,    11,    12,    15,    16,     9,     7,     0,
-       3,    13,    16,    16,    10,     6,    16,     6,    16,     8
+       0,     4,     5,     6,    12,    13,    14,    15,    18,    21,
+      22,    10,     8,     4,     5,    12,    13,    14,    15,    19,
+      20,     0,     3,    16,    22,    10,     8,     3,    22,    11,
+       7,    16,    20,    20,    12,    23,    11,     7,     7,    20,
+      12,    13,    24,     7,     9,    20,     9
   };
 
   const unsigned char
   EvalParser::yyr1_[] =
   {
-       0,    14,    15,    15,    16,    16,    16,    16
+       0,    17,    18,    18,    19,    19,    20,    20,    20,    20,
+      20,    20,    21,    22,    22,    22,    22,    22,    22,    23,
+      24,    24
   };
 
   const unsigned char
   EvalParser::yyr2_[] =
   {
-       0,     2,     3,     1,     1,     1,     4,     8
+       0,     2,     2,     1,     3,     1,     1,     1,     1,     1,
+       4,     8,     3,     1,     1,     1,     1,     4,     8,     1,
+       1,     1
   };
 
 
@@ -936,16 +1083,21 @@ namespace isc { namespace eval {
   const EvalParser::yytname_[] =
   {
   "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
-  "\"substring\"", "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"",
-  "\"constant string\"", "\"constant hexstring\"", "\"option code\"",
-  "$accept", "expression", "token", YY_NULLPTR
+  "\"substring\"", "\"untyped:\"", "\",\"", "\"(\"", "\")\"", "\"[\"",
+  "\"]\"", "\"a number in a constant string\"",
+  "\"the all constant string\"", "\"constant string\"",
+  "\"constant hexstring\"", "\"option code\"", "$accept", "expression",
+  "untyped_expr", "token", "bool_expr", "string_expr", "start_expr",
+  "length_expr", YY_NULLPTR
   };
 
 #if YYDEBUG
   const unsigned char
   EvalParser::yyrline_[] =
   {
-       0,    65,    65,    69,    73,    77,    81,    85
+       0,    68,    68,    69,    73,    77,    81,    85,    89,    93,
+      97,   101,   108,   115,   119,   123,   127,   131,   135,   142,
+     149,   153
   };
 
   // Print the state stack on the debug stream.
@@ -980,8 +1132,8 @@ namespace isc { namespace eval {
 
 #line 21 "parser.yy" // lalr1.cc:1167
 } } // isc::eval
-#line 984 "parser.cc" // lalr1.cc:1167
-#line 91 "parser.yy" // lalr1.cc:1168
+#line 1136 "parser.cc" // lalr1.cc:1167
+#line 159 "parser.yy" // lalr1.cc:1168
 
 void
 isc::eval::EvalParser::error(const location_type& loc,

+ 72 - 28
src/lib/eval/parser.h

@@ -293,6 +293,8 @@ namespace isc { namespace eval {
     /// An auxiliary type to compute the largest semantic type.
     union union_type
     {
+      // "a number in a constant string"
+      // "the all constant string"
       // "constant string"
       // "constant hexstring"
       char dummy1[sizeof(std::string)];
@@ -325,14 +327,17 @@ namespace isc { namespace eval {
         TOKEN_EQUAL = 258,
         TOKEN_OPTION = 259,
         TOKEN_SUBSTRING = 260,
-        TOKEN_COMA = 261,
-        TOKEN_LPAREN = 262,
-        TOKEN_RPAREN = 263,
-        TOKEN_LBRACKET = 264,
-        TOKEN_RBRACKET = 265,
-        TOKEN_STRING = 266,
-        TOKEN_HEXSTRING = 267,
-        TOKEN_CODE = 268
+        TOKEN_UNTYPED = 261,
+        TOKEN_COMA = 262,
+        TOKEN_LPAREN = 263,
+        TOKEN_RPAREN = 264,
+        TOKEN_LBRACKET = 265,
+        TOKEN_RBRACKET = 266,
+        TOKEN_NUMBER = 267,
+        TOKEN_ALL = 268,
+        TOKEN_STRING = 269,
+        TOKEN_HEXSTRING = 270,
+        TOKEN_CODE = 271
       };
     };
 
@@ -459,6 +464,10 @@ namespace isc { namespace eval {
 
     static inline
     symbol_type
+    make_UNTYPED (const location_type& l);
+
+    static inline
+    symbol_type
     make_COMA (const location_type& l);
 
     static inline
@@ -479,6 +488,14 @@ namespace isc { namespace eval {
 
     static inline
     symbol_type
+    make_NUMBER (const std::string& v, const location_type& l);
+
+    static inline
+    symbol_type
+    make_ALL (const std::string& v, const location_type& l);
+
+    static inline
+    symbol_type
     make_STRING (const std::string& v, const location_type& l);
 
     static inline
@@ -694,12 +711,12 @@ namespace isc { namespace eval {
     enum
     {
       yyeof_ = 0,
-      yylast_ = 18,     ///< Last index in yytable_.
-      yynnts_ = 3,  ///< Number of nonterminal symbols.
-      yyfinal_ = 9, ///< Termination state number.
+      yylast_ = 46,     ///< Last index in yytable_.
+      yynnts_ = 8,  ///< Number of nonterminal symbols.
+      yyfinal_ = 21, ///< Termination state number.
       yyterror_ = 1,
       yyerrcode_ = 256,
-      yyntokens_ = 14  ///< Number of tokens.
+      yyntokens_ = 17  ///< Number of tokens.
     };
 
 
@@ -742,9 +759,10 @@ namespace isc { namespace eval {
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16
     };
-    const unsigned int user_token_number_max_ = 268;
+    const unsigned int user_token_number_max_ = 271;
     const token_number_type undef_token_ = 2;
 
     if (static_cast<int>(t) <= yyeof_)
@@ -777,12 +795,14 @@ namespace isc { namespace eval {
   {
       switch (other.type_get ())
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         value.copy< std::string > (other.value);
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         value.copy< uint16_t > (other.value);
         break;
 
@@ -803,12 +823,14 @@ namespace isc { namespace eval {
     (void) v;
       switch (this->type_get ())
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         value.copy< std::string > (v);
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         value.copy< uint16_t > (v);
         break;
 
@@ -867,12 +889,14 @@ namespace isc { namespace eval {
     // Type destructor.
     switch (yytype)
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         value.template destroy< std::string > ();
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         value.template destroy< uint16_t > ();
         break;
 
@@ -899,12 +923,14 @@ namespace isc { namespace eval {
     super_type::move(s);
       switch (this->type_get ())
     {
-      case 11: // "constant string"
-      case 12: // "constant hexstring"
+      case 12: // "a number in a constant string"
+      case 13: // "the all constant string"
+      case 14: // "constant string"
+      case 15: // "constant hexstring"
         value.move< std::string > (s.value);
         break;
 
-      case 13: // "option code"
+      case 16: // "option code"
         value.move< uint16_t > (s.value);
         break;
 
@@ -964,7 +990,7 @@ namespace isc { namespace eval {
     yytoken_number_[] =
     {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268
+     265,   266,   267,   268,   269,   270,   271
     };
     return static_cast<token_type> (yytoken_number_[type]);
   }
@@ -994,6 +1020,12 @@ namespace isc { namespace eval {
   }
 
   EvalParser::symbol_type
+  EvalParser::make_UNTYPED (const location_type& l)
+  {
+    return symbol_type (token::TOKEN_UNTYPED, l);
+  }
+
+  EvalParser::symbol_type
   EvalParser::make_COMA (const location_type& l)
   {
     return symbol_type (token::TOKEN_COMA, l);
@@ -1024,6 +1056,18 @@ namespace isc { namespace eval {
   }
 
   EvalParser::symbol_type
+  EvalParser::make_NUMBER (const std::string& v, const location_type& l)
+  {
+    return symbol_type (token::TOKEN_NUMBER, v, l);
+  }
+
+  EvalParser::symbol_type
+  EvalParser::make_ALL (const std::string& v, const location_type& l)
+  {
+    return symbol_type (token::TOKEN_ALL, v, l);
+  }
+
+  EvalParser::symbol_type
   EvalParser::make_STRING (const std::string& v, const location_type& l)
   {
     return symbol_type (token::TOKEN_STRING, v, l);
@@ -1044,7 +1088,7 @@ namespace isc { namespace eval {
 
 #line 21 "parser.yy" // lalr1.cc:392
 } } // isc::eval
-#line 1048 "parser.h" // lalr1.cc:392
+#line 1092 "parser.h" // lalr1.cc:392
 
 
 

+ 68 - 0
src/lib/eval/parser.yy

@@ -44,12 +44,15 @@ using namespace isc::eval;
   EQUAL "=="
   OPTION "option"
   SUBSTRING "substring"
+  UNTYPED "untyped:"
   COMA ","
   LPAREN  "("
   RPAREN  ")"
   LBRACKET "["
   RBRACKET "]"
 ;
+%token <std::string> NUMBER "a number in a constant string"
+%token <std::string> ALL "the all constant string"
 %token <std::string> STRING "constant string"
 %token <std::string> HEXSTRING "constant hexstring"
 %token <uint16_t> CODE "option code"
@@ -62,6 +65,11 @@ using namespace isc::eval;
 // Expression can either be a single token or a (something == something) expression
 
 expression:
+UNTYPED untyped_expr
+| bool_expr
+;
+
+untyped_expr:
 token EQUAL token {
     TokenPtr eq(new TokenEqual());
     ctx.expression.push_back(eq);
@@ -74,6 +82,14 @@ STRING {
     TokenPtr str(new TokenString($1));
     ctx.expression.push_back(str);
   }
+| NUMBER {
+    TokenPtr str(new TokenString($1));
+    ctx.expression.push_back(str);
+  }
+| ALL {
+    TokenPtr str(new TokenString("all"));
+    ctx.expression.push_back(str);
+  }
 | HEXSTRING {
     TokenPtr hex(new TokenHexString($1));
     ctx.expression.push_back(hex);
@@ -88,6 +104,58 @@ STRING {
   }
 ;
 
+bool_expr:
+string_expr EQUAL string_expr {
+    TokenPtr eq(new TokenEqual());
+    ctx.expression.push_back(eq);
+  }
+;
+
+string_expr:
+STRING {
+    TokenPtr str(new TokenString($1));
+    ctx.expression.push_back(str);
+  }
+| NUMBER {
+    TokenPtr str(new TokenString($1));
+    ctx.expression.push_back(str);
+  }
+| ALL {
+    TokenPtr str(new TokenString("all"));
+    ctx.expression.push_back(str);
+  }
+| HEXSTRING {
+    TokenPtr hex(new TokenHexString($1));
+    ctx.expression.push_back(hex);
+  }
+| OPTION "[" CODE "]" {
+    TokenPtr opt(new TokenOption($3));
+    ctx.expression.push_back(opt);
+  }
+| SUBSTRING "(" string_expr "," start_expr "," length_expr ")" {
+    TokenPtr sub(new TokenSubstring());
+    ctx.expression.push_back(sub);
+  }
+;
+
+start_expr:
+NUMBER {
+    TokenPtr str(new TokenString($1));
+    ctx.expression.push_back(str);
+  }
+;
+
+length_expr:
+NUMBER {
+    TokenPtr str(new TokenString($1));
+    ctx.expression.push_back(str);
+  }
+| ALL {
+    TokenPtr str(new TokenString("all"));
+    ctx.expression.push_back(str);
+  }
+;
+
 %%
 void
 isc::eval::EvalParser::error(const location_type& loc,

+ 82 - 37
src/lib/eval/tests/context_unittest.cc

@@ -109,6 +109,29 @@ public:
         }
     }
 
+    /// @brief checks if the given expression raises the expected message
+    /// when it is parsed by the strongly typed parser but is accepted
+    /// by the untyped one.
+    void checkTyped(const string& expr, const string& msg) {
+        EvalContext eval;
+        parsed_ = false;
+        EXPECT_NO_THROW(parsed_ = eval.parseString("untyped:" + expr));
+        EXPECT_TRUE(parsed_);
+        parsed_ = false;
+        try {
+            parsed_ = eval.parseString(expr);
+            FAIL() << "Expected EvalParseError but nothing was raised";
+        }
+        catch (const EvalParseError& ex) {
+            EXPECT_EQ(msg, ex.what());
+            EXPECT_FALSE(parsed_);
+        }
+        catch (...) {
+            FAIL() << "Expected EvalParseError but something else was raised";
+        }
+    }
+  
+
     bool parsed_; ///< Parsing status
 };
 
@@ -125,7 +148,7 @@ TEST_F(EvalContextTest, basic) {
 TEST_F(EvalContextTest, string) {
     EvalContext eval;
 
-    EXPECT_NO_THROW(parsed_ = eval.parseString("'foo'"));
+    EXPECT_NO_THROW(parsed_ = eval.parseString("untyped: 'foo'"));
     EXPECT_TRUE(parsed_);
 
     ASSERT_EQ(1, eval.expression.size());
@@ -139,7 +162,7 @@ TEST_F(EvalContextTest, string) {
 TEST_F(EvalContextTest, hexstring) {
     EvalContext eval;
 
-    EXPECT_NO_THROW(parsed_ = eval.parseString("0x666f6f"));
+    EXPECT_NO_THROW(parsed_ = eval.parseString("untyped: 0x666f6f"));
     EXPECT_TRUE(parsed_);
 
     ASSERT_EQ(1, eval.expression.size());
@@ -171,7 +194,7 @@ TEST_F(EvalContextTest, equal) {
 TEST_F(EvalContextTest, option) {
     EvalContext eval;
 
-    EXPECT_NO_THROW(parsed_ = eval.parseString("option[123]"));
+    EXPECT_NO_THROW(parsed_ = eval.parseString("untyped: option[123]"));
     EXPECT_TRUE(parsed_);
     ASSERT_EQ(1, eval.expression.size());
     checkTokenOption(eval.expression.at(0), 123);
@@ -181,7 +204,8 @@ TEST_F(EvalContextTest, option) {
 TEST_F(EvalContextTest, substring) {
     EvalContext eval;
 
-    EXPECT_NO_THROW(parsed_ = eval.parseString("substring('foobar','2','3')"));
+    EXPECT_NO_THROW(parsed_ =
+        eval.parseString("untyped: substring('foobar','2','3')"));
     EXPECT_TRUE(parsed_);
 
     ASSERT_EQ(4, eval.expression.size());
@@ -204,54 +228,75 @@ TEST_F(EvalContextTest, scanErrors) {
     checkError("'\n'", "<string>:1.1: Invalid character: '");
     checkError("0x123h", "<string>:1.6: Invalid character: h");
     checkError("=", "<string>:1.1: Invalid character: =");
-    checkError("option[65536]", "<string>:1.8-12: Option code has invalid "
-                                "value in 65536. Allowed range: 0..65535");
+    checkError("option[65536]",
+               "<string>:1.8-12: Option code has invalid "
+               "value in 65536. Allowed range: 0..65535");
     checkError("subtring", "<string>:1.1: Invalid character: s");
+    checkError("untype: 'abc'", "<string>:1.1: Invalid character: u");
+    checkError("untyped 'abc'", "<string>:1.1: Invalid character: u");
     checkError("foo", "<string>:1.1: Invalid character: f");
     checkError(" bar", "<string>:1.2: Invalid character: b");
 }
 
 // Tests some scanner/parser error cases
 TEST_F(EvalContextTest, scanParseErrors) {
-    checkError("", "<string>:1.1: syntax error, unexpected end of file, "
-                   "expecting option or substring or constant string or "
-                   "constant hexstring");
-    checkError("0x", "<string>:1.1: syntax error, unexpected option code, "
-                     "expecting option or substring or constant string or "
-                     "constant hexstring");
-    checkError("===", "<string>:1.1-2: syntax error, unexpected ==, "
-                      "expecting option or substring or constant string "
-                      "or constant hexstring");
+    checkError("", "<string>:1.1: syntax error, unexpected end of file");
+    checkError("untyped:",
+               "<string>:1.9: syntax error, unexpected end of file");
+    checkError("0x", "<string>:1.1: syntax error, unexpected option code");
+    checkError("===", "<string>:1.1-2: syntax error, unexpected ==");
 }
 
 // Tests some parser error cases
 TEST_F(EvalContextTest, parseErrors) {
-    checkError("'foo''bar'", "<string>:1.6-10: syntax error, unexpected "
-                             "constant string, expecting end of file");
-    checkError("== 'ab'", "<string>:1.1-2: syntax error, unexpected ==, "
-                          "expecting option or substring or constant string "
-                          "or constant hexstring");
-    checkError("'foo' ==", "<string>:1.9: syntax error, unexpected end "
-                           "of file, expecting option or substring or "
-                           "constant string or constant hexstring");
-    checkError("option 'ab'", "<string>:1.8-11: syntax error, unexpected "
-                              "constant string, expecting [");
-    checkError("option(10) == 'ab'", "<string>:1.7: syntax error, "
-                                     "unexpected (, expecting [");
-    checkError("option['ab'] == 'foo'", "<string>:1.8-11: syntax error, "
-                                        "unexpected constant string, "
-                                        "expecting option code");
-    checkError("option[0xa] == 'ab'", "<string>:1.8-10: syntax error, "
-                                      "unexpected constant hexstring, "
-                                      "expecting option code");
-    checkError("substring('foobar') == 'f'", "<string>:1.19: syntax error, "
-                                             "unexpected ), expecting \",\"");
+    checkError("untyped:'foo''bar'",
+               "<string>:1.14-18: syntax error, unexpected "
+               "constant string, expecting end of file");
+    checkError("'foo''bar'",
+               "<string>:1.6-10: syntax error, unexpected constant string, "
+               "expecting ==");
+    checkError("== 'ab'", "<string>:1.1-2: syntax error, unexpected ==");
+    checkError("'foo' ==",
+               "<string>:1.9: syntax error, unexpected end of file");
+    checkError("option 'ab'",
+               "<string>:1.8-11: syntax error, unexpected "
+               "constant string, expecting [");
+    checkError("option(10) == 'ab'",
+               "<string>:1.7: syntax error, "
+               "unexpected (, expecting [");
+    checkError("option['ab'] == 'foo'",
+               "<string>:1.8-11: syntax error, "
+               "unexpected constant string, "
+               "expecting option code");
+    checkError("option[0xa] == 'ab'",
+               "<string>:1.8-10: syntax error, "
+               "unexpected constant hexstring, "
+               "expecting option code");
+    checkError("substring('foobar') == 'f'",
+               "<string>:1.19: syntax error, "
+               "unexpected ), expecting \",\"");
     checkError("substring('foobar','3') == 'bar'",
                "<string>:1.23: syntax error, unexpected ), expecting \",\"");
     checkError("substring('foobar',3,3) == 'bar'",
                "<string>:1.20: syntax error, unexpected option code, "
-               "expecting option or substring or constant string or "
-               "constant hexstring");
+               "expecting a number in a constant string");
+}
+
+// Tests some type error cases (caught only by the strongly typed parser)
+TEST_F(EvalContextTest, typeErrors) {
+    checkTyped("'foobar'",
+               "<string>:1.9: syntax error, unexpected end of file, "
+               "expecting ==");
+    checkTyped("substring('foobar','a','1') == 'foo'",
+               "<string>:1.20-22: syntax error, unexpected constant string, "
+               "expecting a number in a constant string");
+    checkTyped("substring('foobar','1','a') == 'foo'",
+               "<string>:1.24-26: syntax error, unexpected constant string, "
+               "expecting a number in a constant string or the all constant "
+               "string");
+    checkTyped("substring('foobar',0x32,'1') == 'foo'",
+               "<string>:1.20-23: syntax error, unexpected constant "
+               "hexstring, expecting a number in a constant string");
 }
 
 };