Browse Source

[4088fd] Fixed error handling

Francis Dupont 9 years ago
parent
commit
92e9995c0e

+ 3 - 1
src/lib/eval/lexer.cc

@@ -2234,6 +2234,7 @@ using namespace isc::eval;
 void
 EvalContext::scanFileBegin()
 {
+    loc.initialize(&file_);
     yy_flex_debug = trace_scanning_;
     if (file_.empty () || file_ == "-") {
         yyin = stdin;
@@ -2253,8 +2254,9 @@ EvalContext::scanFileEnd()
 void
 EvalContext::scanStringBegin()
 {
-    YY_BUFFER_STATE buffer;
+    loc.initialize(&file_);
     yy_flex_debug = trace_scanning_;
+    YY_BUFFER_STATE buffer;
     buffer = yy_scan_bytes(string_.c_str(),string_.size());
     if (!buffer) {
         error("cannot scan string");

+ 3 - 1
src/lib/eval/lexer.ll

@@ -147,6 +147,7 @@ using namespace isc::eval;
 void
 EvalContext::scanFileBegin()
 {
+    loc.initialize(&file_);
     yy_flex_debug = trace_scanning_;
     if (file_.empty () || file_ == "-") {
         yyin = stdin;
@@ -166,8 +167,9 @@ EvalContext::scanFileEnd()
 void
 EvalContext::scanStringBegin()
 {
-    YY_BUFFER_STATE buffer;
+    loc.initialize(&file_);
     yy_flex_debug = trace_scanning_;
+    YY_BUFFER_STATE buffer;
     buffer = yy_scan_bytes(string_.c_str(), string_.size());
     if (!buffer) {
         error("cannot scan string");

+ 18 - 27
src/lib/eval/parser.cc

@@ -49,7 +49,7 @@
 
 #line 51 "parser.cc" // lalr1.cc:412
 // Unqualified %code blocks.
-#line 43 "parser.yy" // lalr1.cc:413
+#line 38 "parser.yy" // lalr1.cc:413
 
 # include "eval_context.h"
 
@@ -322,21 +322,21 @@ namespace isc { namespace eval {
     {
             case 11: // "constant string"
 
-#line 61 "parser.yy" // lalr1.cc:636
+#line 56 "parser.yy" // lalr1.cc:636
         { yyoutput << yysym.value.template as< std::string > (); }
 #line 328 "parser.cc" // lalr1.cc:636
         break;
 
       case 12: // "constant hexstring"
 
-#line 61 "parser.yy" // lalr1.cc:636
+#line 56 "parser.yy" // lalr1.cc:636
         { yyoutput << yysym.value.template as< std::string > (); }
 #line 335 "parser.cc" // lalr1.cc:636
         break;
 
       case 13: // "option code"
 
-#line 61 "parser.yy" // lalr1.cc:636
+#line 56 "parser.yy" // lalr1.cc:636
         { yyoutput << yysym.value.template as< uint16_t > (); }
 #line 342 "parser.cc" // lalr1.cc:636
         break;
@@ -450,15 +450,6 @@ namespace isc { namespace eval {
     YYCDEBUG << "Starting parse" << std::endl;
 
 
-    // User initialization code.
-    #line 36 "parser.yy" // lalr1.cc:745
-{
-  // Initialize the initial location.
-  yyla.location.begin.filename = yyla.location.end.filename = &ctx.file_;
-}
-
-#line 461 "parser.cc" // lalr1.cc:745
-
     /* Initialize the stack.  The initial state will be set in
        yynewstate, since the latter expects the semantical and the
        location values to have been already stored, initialize these
@@ -574,52 +565,52 @@ namespace isc { namespace eval {
           switch (yyn)
             {
   case 2:
-#line 70 "parser.yy" // lalr1.cc:859
+#line 65 "parser.yy" // lalr1.cc:859
     {
     TokenPtr eq(new TokenEqual());
     ctx.expression.push_back(eq);
   }
-#line 583 "parser.cc" // lalr1.cc:859
+#line 574 "parser.cc" // lalr1.cc:859
     break;
 
   case 4:
-#line 78 "parser.yy" // lalr1.cc:859
+#line 73 "parser.yy" // lalr1.cc:859
     {
     TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
     ctx.expression.push_back(str);
   }
-#line 592 "parser.cc" // lalr1.cc:859
+#line 583 "parser.cc" // lalr1.cc:859
     break;
 
   case 5:
-#line 82 "parser.yy" // lalr1.cc:859
+#line 77 "parser.yy" // lalr1.cc:859
     {
     TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
     ctx.expression.push_back(hex);
   }
-#line 601 "parser.cc" // lalr1.cc:859
+#line 592 "parser.cc" // lalr1.cc:859
     break;
 
   case 6:
-#line 86 "parser.yy" // lalr1.cc:859
+#line 81 "parser.yy" // lalr1.cc:859
     {
     TokenPtr opt(new TokenOption(yystack_[1].value.as< uint16_t > ()));
     ctx.expression.push_back(opt);
   }
-#line 610 "parser.cc" // lalr1.cc:859
+#line 601 "parser.cc" // lalr1.cc:859
     break;
 
   case 7:
-#line 90 "parser.yy" // lalr1.cc:859
+#line 85 "parser.yy" // lalr1.cc:859
     {
     TokenPtr sub(new TokenSubstring());
     ctx.expression.push_back(sub);
   }
-#line 619 "parser.cc" // lalr1.cc:859
+#line 610 "parser.cc" // lalr1.cc:859
     break;
 
 
-#line 623 "parser.cc" // lalr1.cc:859
+#line 614 "parser.cc" // lalr1.cc:859
             default:
               break;
             }
@@ -954,7 +945,7 @@ namespace isc { namespace eval {
   const unsigned char
   EvalParser::yyrline_[] =
   {
-       0,    70,    70,    74,    78,    82,    86,    90
+       0,    65,    65,    69,    73,    77,    81,    85
   };
 
   // Print the state stack on the debug stream.
@@ -989,8 +980,8 @@ namespace isc { namespace eval {
 
 #line 21 "parser.yy" // lalr1.cc:1167
 } } // isc::eval
-#line 993 "parser.cc" // lalr1.cc:1167
-#line 96 "parser.yy" // lalr1.cc:1168
+#line 984 "parser.cc" // lalr1.cc:1167
+#line 91 "parser.yy" // lalr1.cc:1168
 
 void
 isc::eval::EvalParser::error(const location_type& loc,

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

@@ -32,11 +32,6 @@ using namespace isc::eval;
 // The parsing context.
 %param { EvalContext& ctx }
 %locations
-%initial-action
-{
-  // Initialize the initial location.
-  @$.begin.filename = @$.end.filename = &ctx.file_;
-};
 %define parse.trace
 %define parse.error verbose
 %code

+ 59 - 2
src/lib/eval/tests/context_unittest.cc

@@ -27,8 +27,10 @@ using namespace isc::dhcp;
 
 namespace {
 
+/// @brief Test class for testing EvalContext aka class test parsing
 class EvalContextTest : public ::testing::Test {
 public:
+    /// @brief checks if the given token is a string with the expected value
     void checkTokenString(const TokenPtr& token, const std::string& expected) {
         ASSERT_TRUE(token);
         boost::shared_ptr<TokenString> str =
@@ -45,6 +47,7 @@ public:
         EXPECT_EQ(expected, values.top());
     }
 
+    /// @brief checks if the given token is a hex string with the expected value
     void checkTokenHexString(const TokenPtr& token,
                              const std::string& expected) {
         ASSERT_TRUE(token);
@@ -62,6 +65,7 @@ public:
         EXPECT_EQ(expected, values.top());
     }
 
+    /// @brief checks if the given token is an equal operator
     void checkTokenEq(const TokenPtr& token) {
         ASSERT_TRUE(token);
         boost::shared_ptr<TokenEqual> eq =
@@ -69,15 +73,17 @@ public:
         EXPECT_TRUE(eq);
     }
 
-    void checkTokenOption(const TokenPtr& token, uint16_t expected_option) {
+    /// @brief checks if the given token is an option with the expected code
+    void checkTokenOption(const TokenPtr& token, uint16_t expected_code) {
         ASSERT_TRUE(token);
         boost::shared_ptr<TokenOption> opt =
             boost::dynamic_pointer_cast<TokenOption>(token);
         ASSERT_TRUE(opt);
 
-        EXPECT_EQ(expected_option, opt->getCode());
+        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 =
@@ -85,9 +91,28 @@ public:
         EXPECT_TRUE(sub);
     }
 
+    /// @brief checks if the given expression raises the expected message
+    /// when it is parsed.
+    void checkError(const string& expr, const string& msg) {
+        EvalContext eval;
+        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
 };
 
+// Test the parsing of a basic expression
 TEST_F(EvalContextTest, basic) {
 
     EvalContext tmp;
@@ -96,6 +121,7 @@ TEST_F(EvalContextTest, basic) {
     EXPECT_TRUE(parsed_);
 }
 
+// Test the parsing of a string terminal
 TEST_F(EvalContextTest, string) {
     EvalContext eval;
 
@@ -109,6 +135,7 @@ TEST_F(EvalContextTest, string) {
     checkTokenString(tmp, "foo");
 }
 
+// Test the parsing of a hexstring terminal
 TEST_F(EvalContextTest, hexstring) {
     EvalContext eval;
 
@@ -122,6 +149,7 @@ TEST_F(EvalContextTest, hexstring) {
     checkTokenHexString(tmp, "foo");
 }
 
+// Test the parsing of an equal expression
 TEST_F(EvalContextTest, equal) {
     EvalContext eval;
 
@@ -139,6 +167,7 @@ TEST_F(EvalContextTest, equal) {
     checkTokenEq(tmp3);
 }
 
+// Test the parsing of an option terminal
 TEST_F(EvalContextTest, option) {
     EvalContext eval;
 
@@ -148,6 +177,7 @@ TEST_F(EvalContextTest, option) {
     checkTokenOption(eval.expression.at(0), 123);
 }
 
+// Test the parsing of a substring expression
 TEST_F(EvalContextTest, substring) {
     EvalContext eval;
 
@@ -167,4 +197,31 @@ TEST_F(EvalContextTest, substring) {
     checkTokenSubstring(tmp4);
 }
 
+// Test some scanner error cases
+TEST_F(EvalContextTest, scanErrors) {
+    checkError("'", "<string>:1.1: Invalid character: '");
+    checkError("'\''", "<string>:1.3: Invalid character: '");
+    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("subtring", "<string>:1.1: Invalid character: s");
+    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");
+}
+
 };