Browse Source

[2370] separate error type token to support error code

JINMEI Tatuya 12 years ago
parent
commit
844348f6a9

+ 1 - 1
src/lib/dns/Makefile.am

@@ -95,7 +95,7 @@ libb10_dns___la_SOURCES += edns.h edns.cc
 libb10_dns___la_SOURCES += exceptions.h exceptions.cc
 libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
 libb10_dns___la_SOURCES += masterload.h masterload.cc
-libb10_dns___la_SOURCES += master_lexer.h
+libb10_dns___la_SOURCES += master_lexer.h master_lexer.cc
 libb10_dns___la_SOURCES += message.h message.cc
 libb10_dns___la_SOURCES += messagerenderer.h messagerenderer.cc
 libb10_dns___la_SOURCES += name.h name.cc

+ 47 - 0
src/lib/dns/master_lexer.cc

@@ -0,0 +1,47 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/master_lexer.h>
+
+#include <cassert>
+#include <string>
+
+namespace {
+const char* const error_text[] = {
+    "lexer not started",        // NOT_STARTED
+    "unbalanced parentheses",   // UNBALANCED_PAREN
+    "unexpected end of input",  // UNEXPECTED_END
+    "unbalanced quotes"         // UNBALANCED_QUOTES
+};
+const size_t error_text_max_count = sizeof(error_text) / sizeof(error_text[0]);
+}
+
+namespace isc {
+namespace dns {
+
+std::string
+MasterLexer::Token::getErrorText() const {
+    if (type_ != ERROR) {
+        isc_throw(InvalidOperation,
+                  "Token::getErrorText() for non error type");
+    }
+
+    // The class integrity ensures the following:
+    assert(val_.error_code_ < error_text_max_count);
+    return (error_text[val_.error_code_]);
+}
+
+
+} // end of namespace dns
+} // end of namespace isc

+ 23 - 5
src/lib/dns/master_lexer.h

@@ -32,20 +32,22 @@ public:
 class MasterLexer::Token {
 public:
     enum Type {
-        ERROR,
         END_OF_LINE,
         END_OF_FILE,
         INITIAL_WS,
+        SPECIAL_TYPE_MAX = INITIAL_WS,
         STRING,
         QSTRING,
-        NUMBER
+        NUMBER,
+        ERROR
     };
 
     enum ErrorCode {
         NOT_STARTED,
         UNBALANCED_PAREN,
         UNEXPECTED_END,
-        UNBALANCED_QUOTES
+        UNBALANCED_QUOTES,
+        MAX_ERROR_CODE = UNBALANCED_QUOTES
     };
 
     struct StringRegion {
@@ -54,7 +56,7 @@ public:
     };
 
     explicit Token(Type type) : type_(type) {
-        if (type >= STRING) {
+        if (type > SPECIAL_TYPE_MAX) {
             isc_throw(InvalidParameter, "Token per-type constructor "
                       "called with invalid type: " << type);
         }
@@ -68,6 +70,13 @@ public:
     explicit Token(uint32_t number) : type_(NUMBER) {
         val_.number_ = number;
     }
+    explicit Token(ErrorCode error_code) : type_(ERROR) {
+        if (error_code > MAX_ERROR_CODE) {
+            isc_throw(InvalidParameter, "Invalid master lexer error code: "
+                      << error_code);
+        }
+        val_.error_code_ = error_code;
+    }
 
     Type getType() const { return (type_); }
     std::string getString() const {
@@ -81,7 +90,7 @@ public:
     const StringRegion& getStringRegion() const {
         if (type_ != STRING && type_ != QSTRING) {
             isc_throw(InvalidOperation,
-                      "Token::getString() for non string-variant type");
+                      "Token::getStringRegion() for non string-variant type");
         }
         return (val_.str_region_);
     }
@@ -92,12 +101,21 @@ public:
         }
         return (val_.number_);
     }
+    ErrorCode getErrorCode() const {
+        if (type_ != ERROR) {
+            isc_throw(InvalidOperation,
+                      "Token::getErrorCode() for non error type");
+        }
+        return (val_.error_code_);
+    };
+    std::string getErrorText() const;
 
 private:
     Type type_;
     union {
         StringRegion str_region_;
         uint32_t number_;
+        ErrorCode error_code_;
     } val_;
 };
 

+ 37 - 1
src/lib/dns/tests/master_lexer_token_unittest.cc

@@ -33,12 +33,14 @@ public:
     MasterLexerTokenTest() :
         token_eof(MasterLexer::Token::END_OF_FILE),
         token_str(TEST_STRING, TEST_STRING_LEN),
-        token_num(42)
+        token_num(42),
+        token_err(MasterLexer::Token::UNEXPECTED_END)
     {}
 
     const MasterLexer::Token token_eof; // an example of special type token
     const MasterLexer::Token token_str;
     const MasterLexer::Token token_num;
+    const MasterLexer::Token token_err;
 };
 
 
@@ -116,5 +118,39 @@ TEST_F(MasterLexerTokenTest, specials) {
                  isc::InvalidParameter);
     EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::NUMBER),
                  isc::InvalidParameter);
+    EXPECT_THROW(MasterLexer::Token t(MasterLexer::Token::ERROR),
+                 isc::InvalidParameter);
+}
+
+TEST_F(MasterLexerTokenTest, errors) {
+    EXPECT_EQ(MasterLexer::Token::ERROR, token_err.getType());
+    EXPECT_EQ(MasterLexer::Token::UNEXPECTED_END, token_err.getErrorCode());
+    EXPECT_EQ("unexpected end of input", token_err.getErrorText());
+    EXPECT_EQ("lexer not started",
+              MasterLexer::Token(MasterLexer::Token::NOT_STARTED).
+              getErrorText());
+    EXPECT_EQ("unbalanced parentheses",
+              MasterLexer::Token(MasterLexer::Token::UNBALANCED_PAREN).
+              getErrorText());
+    EXPECT_EQ("unbalanced quotes",
+              MasterLexer::Token(MasterLexer::Token::UNBALANCED_QUOTES).
+              getErrorText());
+
+    // getErrorCode/Text() isn't allowed for non number types
+    EXPECT_THROW(token_num.getErrorCode(), isc::InvalidOperation);
+    EXPECT_THROW(token_num.getErrorText(), isc::InvalidOperation);
+
+    // Only the pre-defined error code is accepted.  Hardcoding '4' (max code
+    // + 1) is intentional; it'd be actually better if we notice it when we
+    // update the enum list (which shouldn't happen too often).
+    EXPECT_THROW(MasterLexer::Token(MasterLexer::Token::ErrorCode(4)),
+                 isc::InvalidParameter);
+
+    // Check the coexistence of "from number" and "from error-code"
+    // constructors won't cause confusion.
+    EXPECT_EQ(MasterLexer::Token::NUMBER,
+              MasterLexer::Token(static_cast<uint32_t>(
+                                     MasterLexer::Token::NOT_STARTED)).
+              getType());
 }
 }