diff options
author | Tomek Mrugalski <tomasz@isc.org> | 2017-03-23 15:42:01 +0100 |
---|---|---|
committer | Tomek Mrugalski <tomasz@isc.org> | 2017-03-23 15:42:01 +0100 |
commit | 279fe78b1824ecda0efcd852c45c2a37b964337e (patch) | |
tree | 97358a64f70a48ff5536b7833b1d49cc3207e1d1 /src/lib | |
parent | [5132] evaluate renamed to evaluateBool (diff) | |
download | kea-279fe78b1824ecda0efcd852c45c2a37b964337e.tar.xz kea-279fe78b1824ecda0efcd852c45c2a37b964337e.zip |
[5132] expressions evaluated to string added
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/eval/eval_context.cc | 4 | ||||
-rw-r--r-- | src/lib/eval/eval_context.h | 17 | ||||
-rw-r--r-- | src/lib/eval/lexer.ll | 22 | ||||
-rw-r--r-- | src/lib/eval/parser.yy | 19 | ||||
-rw-r--r-- | src/lib/eval/tests/evaluate_unittest.cc | 45 |
5 files changed, 98 insertions, 9 deletions
diff --git a/src/lib/eval/eval_context.cc b/src/lib/eval/eval_context.cc index d90d71bee5..cd81796b4d 100644 --- a/src/lib/eval/eval_context.cc +++ b/src/lib/eval/eval_context.cc @@ -27,11 +27,11 @@ EvalContext::~EvalContext() } bool -EvalContext::parseString(const std::string& str) +EvalContext::parseString(const std::string& str, ParserType type) { file_ = "<string>"; string_ = str; - scanStringBegin(); + scanStringBegin(type); isc::eval::EvalParser parser(*this); parser.set_debug_level(trace_parsing_); int res = parser.parse(); diff --git a/src/lib/eval/eval_context.h b/src/lib/eval/eval_context.h index 053e8cf64b..eb914d2d9e 100644 --- a/src/lib/eval/eval_context.h +++ b/src/lib/eval/eval_context.h @@ -34,6 +34,14 @@ public: class EvalContext { public: + + /// @brief Specifies what type of expression the parser is expected to see + typedef enum { + PARSER_BOOL, ///< expression is expected to evaluate to bool + PARSER_STRING ///< expression is expected to evaluate to string + } ParserType; + + /// @brief Default constructor. /// /// @param option_universe Option universe: DHCPv4 or DHCPv6. This is used @@ -48,16 +56,19 @@ public: isc::dhcp::Expression expression; /// @brief Method called before scanning starts on a string. - void scanStringBegin(); + /// + /// @param type specifies type of the expression to be parsed + void scanStringBegin(ParserType type); /// @brief Method called after the last tokens are scanned from a string. void scanStringEnd(); /// @brief Run the parser on the string specified. /// - /// @param str string to be written + /// @param str string to be parsed + /// @param type type of the expression expected/parser type to be created /// @return true on success. - bool parseString(const std::string& str); + bool parseString(const std::string& str, ParserType type = PARSER_BOOL); /// @brief The name of the file being parsed. /// Used later to pass the file name to the location tracker. diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index 838123ad83..bfa4e65db0 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -25,6 +25,11 @@ // variable will be useful for logging errors. static isc::eval::location loc; +namespace { + bool start_token_flag = false; + isc::eval::EvalContext::ParserType start_token_value; +}; + // To avoid the call to exit... oops! #define YY_FATAL_ERROR(msg) isc::eval::EvalContext::fatal(msg) %} @@ -77,6 +82,18 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]* %{ // Code run each time evallex is called. loc.step(); + + if (start_token_flag) { + start_token_flag = false; + switch (start_token_value) { + case EvalContext::PARSER_BOOL: + return isc::eval::EvalParser::make_TOPLEVEL_BOOL(loc); + default: + case EvalContext::PARSER_STRING: + return isc::eval::EvalParser::make_TOPLEVEL_STRING(loc); + } + } + %} {blank}+ { @@ -194,8 +211,11 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]* using namespace isc::eval; void -EvalContext::scanStringBegin() +EvalContext::scanStringBegin(ParserType type) { + start_token_flag = true; + start_token_value = type; + loc.initialize(&file_); eval_flex_debug = trace_scanning_; YY_BUFFER_STATE buffer; diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 53c76897b7..9d31b01a67 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -80,6 +80,9 @@ using namespace isc::eval; ANY "*" DATA "data" ENTERPRISE "enterprise" + + TOPLEVEL_BOOL "top-level bool" + TOPLEVEL_STRING "top-level string" ; %token <std::string> STRING "constant string" @@ -106,8 +109,20 @@ using namespace isc::eval; %% -// The whole grammar starts with an expression. -%start expression; +// The whole grammar starts with a 'start' symbol... +%start start; + +// ... that expects either TOPLEVEL_BOOL or TOPLEVEL_STRING. Depending on which +// token appears first, it will determine what is allowed and what it not. +start: TOPLEVEL_BOOL expression + | TOPLEVEL_STRING string_expression +; + +// string expression can be either a string (proper) or boolean (that is internally +// stored as "true" or "false") +string_expression: bool_expr + | string_expr +; // Expression can either be a single token or a (something == something) expression diff --git a/src/lib/eval/tests/evaluate_unittest.cc b/src/lib/eval/tests/evaluate_unittest.cc index 8106bc778d..b8a69d8180 100644 --- a/src/lib/eval/tests/evaluate_unittest.cc +++ b/src/lib/eval/tests/evaluate_unittest.cc @@ -294,7 +294,7 @@ TEST_F(EvaluateTest, complex) { class ExpressionsTest : public EvaluateTest { public: - /// @brief Checks if expression can be parsed and evaluated + /// @brief Checks if expression can be parsed and evaluated to bool /// /// There are skeleton packets created in pkt4_ and pkt6_. Make sure you /// tweak them as needed before calling this method. @@ -327,6 +327,39 @@ public: EXPECT_EQ(exp_result, result) << " for expression " << expr; } + /// @brief Checks if expression can be parsed and evaluated to string + /// + /// There are skeleton packets created in pkt4_ and pkt6_. Make sure you + /// tweak them as needed before calling this method. + /// + /// @param u universe (V4 or V6) + /// @param expr expression to be parsed + /// @param exp_result expected result (string) + void testExpressionString(const Option::Universe& u, const std::string& expr, + const std::string& exp_result) { + + EvalContext eval(u); + string result; + bool parsed = false; + + EXPECT_NO_THROW(parsed = eval.parseString(expr, EvalContext::PARSER_STRING)) + << " while parsing expression " << expr; + EXPECT_TRUE(parsed) << " for expression " << expr; + + switch (u) { + case Option::V4: + ASSERT_NO_THROW(result = evaluateString(eval.expression, *pkt4_)) + << " for expression " << expr; + break; + case Option::V6: + ASSERT_NO_THROW(result = evaluateString(eval.expression, *pkt6_)) + << " for expression " << expr; + break; + } + + EXPECT_EQ(exp_result, result) << " for expression " << expr; + } + /// @brief Checks that specified expression throws expected exception. /// /// @tparam ex exception type expected to be thrown @@ -440,4 +473,14 @@ TEST_F(ExpressionsTest, invalidIntegers) { // Oops, one too much. testExpressionNegative<EvalParseError>("4294967296 == 0"); } + +// Tests whether expressions can be evaluated to a string. +TEST_F(ExpressionsTest, evaluateString) { + + testExpressionString(Option::V4, "option[100].hex", "hundred4"); + testExpressionString(Option::V6, "option[100].hex", "hundred6"); + testExpressionString(Option::V4, "option[200].hex", ""); + testExpressionString(Option::V6, "option[200].hex", ""); +} + }; |