Commit 279fe78b authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[5132] expressions evaluated to string added

parent 97aa91c6
......@@ -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();
......
......@@ -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.
......
......@@ -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;
......
......@@ -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
......
......@@ -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", "");
}
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment