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

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

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

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

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

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

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