Commit fab8be8e authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[5036] Comments added, some constants removed.

parent 39919c3b
......@@ -102,10 +102,9 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
if (start_token_flag) {
start_token_flag = false;
switch (start_token_value) {
case Parser6Context::SUBPARSER_JSON:
case Parser6Context::PARSER_JSON:
default:
return isc::dhcp::Dhcp6Parser::make_SUB_JSON(driver.loc_);
// return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(driver.loc_);
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_JSON(driver.loc_);
case Parser6Context::PARSER_DHCP6:
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(driver.loc_);
case Parser6Context::SUBPARSER_DHCP6:
......
......@@ -144,7 +144,7 @@ using namespace std;
// Not real tokens, just a way to signal what the parser is expected to
// parse.
TOPLEVEL_GENERIC_JSON
TOPLEVEL_JSON
TOPLEVEL_DHCP6
SUB_DHCP6
SUB_INTERFACES6
......@@ -155,7 +155,6 @@ using namespace std;
SUB_OPTION_DEF
SUB_OPTION_DATA
SUB_HOOKS_LIBRARY
SUB_JSON
;
%token <std::string> STRING "constant string"
......@@ -175,7 +174,7 @@ using namespace std;
// We made the same for subparsers at the exception of the JSON value.
%start start;
start: TOPLEVEL_GENERIC_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } map2
start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
| TOPLEVEL_DHCP6 { ctx.ctx_ = ctx.CONFIG; } syntax_map
| SUB_DHCP6 { ctx.ctx_ = ctx.DHCP6; } sub_dhcp6
| SUB_INTERFACES6 { ctx.ctx_ = ctx.INTERFACES_CONFIG; } sub_interfaces6
......@@ -186,7 +185,6 @@ start: TOPLEVEL_GENERIC_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } map2
| SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
| SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
| SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
| SUB_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
;
// ---- generic JSON parser ---------------------------------
......@@ -270,7 +268,7 @@ not_empty_list: value {
// Unknown keyword in a map
unknown_map_entry: STRING COLON {
const std::string& where = ctx.context_name();
const std::string& where = ctx.contextName();
const std::string& keyword = $1;
error(@1,
"got unexpected keyword \"" + keyword + "\" in " + where + " map.");
......@@ -279,7 +277,6 @@ unknown_map_entry: STRING COLON {
// This defines the top-level { } that holds Dhcp6, Dhcp4, DhcpDdns or Logging
// objects.
// ctx_ = CONFIG
syntax_map: LCURLY_BRACKET {
// This code is executed when we're about to start parsing
// the content of the map
......
......@@ -114,7 +114,7 @@ Parser6Context::leave()
}
const std::string
Parser6Context::context_name()
Parser6Context::contextName()
{
switch (ctx_) {
case NO_KEYWORD:
......
......@@ -48,41 +48,40 @@ public:
/// is being told to start parsing as SUBPARSER_HOST_RESERVATION6.
typedef enum {
/// This parser will parse the content as generic JSON.
//PARSER_GENERIC_JSON,
PARSER_JSON,
SUBPARSER_JSON,
/// This parser will parse the content as Dhcp6 config wrapped in a map (that's
/// the regular config file)
/// This parser will parse the content as Dhcp6 config wrapped in a map
/// (that's the regular config file)
PARSER_DHCP6,
/// This parser will parse the content of Dhcp6. It is mostly used
/// in unit-tests as most of the unit-tests do not define the outer
/// map and Dhcp6 entity, just the contents of it.
/// This parser will parse the content of Dhcp6 (without outer { } and
/// without "Dhcp6"). It is mostly used in unit-tests as most of the
/// unit-tests do not define the outer map and Dhcp6 entity, just the
/// contents of it.
SUBPARSER_DHCP6,
/// This will parse the conde as Subnet6 content.
/// This will parse the input as Subnet6 content.
PARSER_SUBNET6,
/// This parser will parse pool6 content.
/// This will parse the input as pool6 content.
PARSER_POOL6,
/// This parser will parse the interfaces content.
/// This will parse the input as interfaces content.
PARSER_INTERFACES,
/// This parser will parse the content as pd-pool.
/// This will parse the input as pd-pool content.
PARSER_PD_POOL,
/// This parser will parse the content as host-reservation
/// This will parse the input as host-reservation.
PARSER_HOST_RESERVATION,
/// This parser will parse the content as option definition.
/// This will parse the input as option definition.
PARSER_OPTION_DEF,
/// This parser will parse the content as option data.
/// This will parse the input as option data.
PARSER_OPTION_DATA,
/// This parser will parse the content as hooks-library
/// This will parse the input as hooks-library.
PARSER_HOOKS_LIBRARY
} ParserType;
......@@ -109,13 +108,27 @@ public:
/// @brief Run the parser on the string specified.
///
/// This method parses specified string. Depending on the value of
/// parser_type, parser may either check only that the input is valid
/// JSON, or may do more specific syntax checking. See @ref ParserType
/// for supported syntax checkers.
///
/// @param str string to be parsed
/// @param parser_type specifies expected content (either DHCP6 or generic JSON)
/// @return true on success.
/// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
/// @return Element structure representing parsed text.
isc::data::ConstElementPtr parseString(const std::string& str,
ParserType parser_type);
/// @brief Run the parser on the file specified.
///
/// This method parses specified file. Depending on the value of
/// parser_type, parser may either check only that the input is valid
/// JSON, or may do more specific syntax checking. See @ref ParserType
/// for supported syntax checkers.
///
/// @param filename file to be parsed
/// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
/// @return Element structure representing parsed text.
isc::data::ConstElementPtr parseFile(const std::string& filename,
ParserType parser_type);
......@@ -141,43 +154,86 @@ public:
///
/// Convert a bison location into an element position
/// (take the begin, the end is lost)
/// @brief loc location in bison format
/// @return Position in format accepted by Element
isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
/// @brief Defines syntactic contexts for lexical tie-ins
typedef enum {
/// at toplevel
///< This one is used in pure JSON mode.
NO_KEYWORD,
///< Used while parsing top level (that contains Dhcp6, Logging and others)
CONFIG,
/// in config
///< Used while parsing content of Dhcp6.
DHCP6,
// not yet DHCP4,
// not yet DHCP_DDNS,
///< Used while parsing content of Logging
LOGGING,
/// Dhcp6
/// Used while parsing Dhcp6/interfaces structures.
INTERFACES_CONFIG,
LEASE_DATABASE,
/// Used while parsing Dhcp6/hosts-database structures.
HOSTS_DATABASE,
/// Used while parsing Dhcp6/lease-database structures.
LEASE_DATABASE,
/// Used while parsing Dhcp6/mac-sources structures.
MAC_SOURCES,
/// Used while parsing Dhcp6/host-reservation-identifiers.
HOST_RESERVATION_IDENTIFIERS,
/// Used while parsing Dhcp6/hooks-libraries.
HOOKS_LIBRARIES,
/// Used while parsing Dhcp6/Subnet6 structures.
SUBNET6,
/// Used while parsing Dhcp6/option-def structures.
OPTION_DEF,
/// Used while parsing Dhcp6/option-data, Dhcp6/subnet6/option-data
/// or anywhere option-data is present (client classes, host
/// reservations and possibly others).
OPTION_DATA,
/// Used while parsing Dhcp6/client-classes structures.
CLIENT_CLASSES,
/// Used while parsing Dhcp6/server-id structures.
SERVER_ID,
/// Used while parsing Dhcp6/control-socket structures.
CONTROL_SOCKET,
/// subnet6
/// Used while parsing Dhcp6/subnet6/pools structures.
POOLS,
/// Used while parsing Dhcp6/subnet6/pd-pools structures.
PD_POOLS,
/// Used while parsing Dhcp6/reservations structures.
RESERVATIONS,
/// Used while parsing Dhcp6/subnet6/relay structures.
RELAY,
/// client-classes
/// Used while parsing Dhcp6/client-classes structures.
CLIENT_CLASS,
/// Logging
/// Used while parsing Logging/loggers structures.
LOGGERS,
/// loggers
/// Used while parsing Logging/loggers/output_options structures.
OUTPUT_OPTIONS
} ParserContext;
} ParserContext;
/// @brief File name
std::string file_;
......@@ -201,12 +257,24 @@ public:
FILE* sfile_;
/// @brief sFile (aka FILE) stack
///
/// This is a stack of files. Typically there's only one file (the
/// one being currently parsed), but there may be more if one
/// file includes another.
std::vector<FILE*> sfiles_;
/// @brief Current syntactic context
ParserContext ctx_;
/// @brief Enter a new syntactic context
///
/// Entering a nex syntactic context is useful in several ways.
/// First, it allows the parser to avoid conflicts. Second, it
/// allows the lexer to return different tokens depending on
/// context (e.g. if "renew-timer" string is detected, the lexer
/// will return STRING token if in JSON mode or RENEW_TIMER if
/// in DHCP6 mode. Finally, the stntactic context allows the
/// error message to be more descriptive.
void enter(const ParserContext& ctx);
/// @brief Leave a syntactic context
......@@ -214,7 +282,8 @@ public:
void leave();
/// @brief Get the syntactix context name
const std::string context_name();
/// @return printable name of the context.
const std::string contextName();
private:
/// @brief Flag determining scanner debugging.
......
......@@ -639,15 +639,24 @@ public:
NakedDhcpv6Srv srv_;
};
// For parser testing (JSON map, no exception expected)
/// @brief Runs parser in JSON mode, useful for parser testing
///
/// @param in string to be parsed
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ConstElementPtr
parseJSON(const std::string& in)
{
isc::dhcp::Parser6Context ctx;
return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_JSON));
return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_JSON));
}
// For parser testing (DHCP6)
/// @brief Runs parser in Dhcp6 mode
///
/// This is a simplified Dhcp6 mode, so no outer { } and "Dhcp6" is
/// needed. This format is used by most of the tests.
///
/// @param in string to be parsed
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ConstElementPtr
parseDHCP6(const std::string& in)
{
......@@ -656,14 +665,17 @@ parseDHCP6(const std::string& in)
return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_DHCP6));
}
catch (const std::exception& ex) {
#ifdef ENABLE_DEBUG
std::cout << "EXCEPTION: " << ex.what() << std::endl;
#endif // ENABLE_DEBUG
throw;
}
}
// For parser testing (OPTION_DEF)
/// @brief Runs parser in option definition mode
///
/// This function parses specified text as JSON that defines option definitions.
///
/// @param in string to be parsed
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ConstElementPtr
parseOPTION_DEF(const std::string& in)
{
......@@ -672,9 +684,7 @@ parseOPTION_DEF(const std::string& in)
return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEF));
}
catch (const std::exception& ex) {
#ifdef ENABLE_DEBUG
std::cout << "EXCEPTION: " << ex.what() << std::endl;
#endif // ENABLE_DEBUG
throw;
}
}
......
......@@ -65,35 +65,35 @@ void testParser2(const std::string& txt, Parser6Context::ParserType parser_type)
TEST(ParserTest, mapInMap) {
string txt = "{ \"xyzzy\": { \"foo\": 123, \"baz\": 456 } }";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, listInList) {
string txt = "[ [ \"Britain\", \"Wales\", \"Scotland\" ], "
"[ \"Pomorze\", \"Wielkopolska\", \"Tatry\"] ]";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, nestedMaps) {
string txt = "{ \"europe\": { \"UK\": { \"London\": { \"street\": \"221B Baker\" }}}}";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, nestedLists) {
string txt = "[ \"half\", [ \"quarter\", [ \"eighth\", [ \"sixteenth\" ]]]]";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, listsInMaps) {
string txt = "{ \"constellations\": { \"orion\": [ \"rigel\", \"betelguese\" ], "
"\"cygnus\": [ \"deneb\", \"albireo\"] } }";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, mapsInLists) {
string txt = "[ { \"body\": \"earth\", \"gravity\": 1.0 },"
" { \"body\": \"mars\", \"gravity\": 0.376 } ]";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, types) {
......@@ -103,7 +103,7 @@ TEST(ParserTest, types) {
"\"map\": { \"foo\": \"bar\" },"
"\"list\": [ 1, 2, 3 ],"
"\"null\": null }";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, keywordJSON) {
......@@ -111,7 +111,7 @@ TEST(ParserTest, keywordJSON) {
"\"type\": \"password\","
"\"user\": \"name\","
"\"password\": \"type\" }";
testParser(txt, Parser6Context::SUBPARSER_JSON);
testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, keywordDhcp6) {
......@@ -267,142 +267,142 @@ void testError(const std::string& txt,
// Check errors
TEST(ParserTest, errors) {
// no input
testError("", Parser6Context::SUBPARSER_JSON,
testError("", Parser6Context::PARSER_JSON,
"<string>:1.1: syntax error, unexpected end of file");
testError(" ", Parser6Context::SUBPARSER_JSON,
testError(" ", Parser6Context::PARSER_JSON,
"<string>:1.2: syntax error, unexpected end of file");
testError("\n", Parser6Context::SUBPARSER_JSON,
testError("\n", Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file");
// comments
testError("# nothing\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, "
"expecting {");
testError(" #\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, "
"expecting {");
testError("// nothing\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, "
"expecting {");
testError("/* nothing */\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, "
"expecting {");
testError("/* no\nthing */\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:3.1: syntax error, unexpected end of file, "
"expecting {");
testError("/* no\nthing */\n\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:4.1: syntax error, unexpected end of file, "
"expecting {");
testError("/* nothing\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"Comment not closed. (/* in line 1");
testError("\n\n\n/* nothing\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"Comment not closed. (/* in line 4");
testError("{ /* */*/ }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3-8: Invalid character: *");
testError("{ /* // *// }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3-11: Invalid character: /");
testError("{ /* // */// }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, "
"expecting }");
// includes
testError("<?\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"Directive not closed.");
testError("<?include\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"Directive not closed.");
string file = string(CFG_EXAMPLES) + "/" + "stateless.json";
testError("<?include \"" + file + "\"\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"Directive not closed.");
testError("<?include \"/foo/bar\" ?>/n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"Can't open include file /foo/bar");
// numbers
testError("123",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-3: syntax error, unexpected integer, "
"expecting {");
testError("-456",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-4: syntax error, unexpected integer, "
"expecting {");
testError("-0001",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-5: syntax error, unexpected integer, "
"expecting {");
testError("1234567890123456789012345678901234567890",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-40: Failed to convert "
"1234567890123456789012345678901234567890"
" to an integer.");
testError("-3.14e+0",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-8: syntax error, unexpected floating point, "
"expecting {");
testError("1e50000",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-7: Failed to convert 1e50000 "
"to a floating point.");
// strings
testError("\"aabb\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-6: syntax error, unexpected constant string, "
"expecting {");
testError("{ \"aabb\"err",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.9: Invalid character: e");
testError("{ err\"aabb\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3: Invalid character: e");
testError("\"a\n\tb\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-6: Invalid control in \"a\n\tb\"");
testError("\"a\\n\\tb\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-8: syntax error, unexpected constant string, "
"expecting {");
testError("\"a\\x01b\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-8: Bad escape in \"a\\x01b\"");
testError("\"a\\u0062\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-9: Unsupported unicode escape in \"a\\u0062\"");
testError("\"a\\u062z\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-9: Bad escape in \"a\\u062z\"");
testError("\"abc\\\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1-6: Overflow escape in \"abc\\\"");
// from data_unittest.c
testError("\\a",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1: Invalid character: \\");
testError("\\",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1: Invalid character: \\");
testError("\\\"\\\"",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1: Invalid character: \\");
// want a map
testError("[]\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.1: syntax error, unexpected [, "
"expecting {");
testError("[]\n",
......@@ -410,14 +410,14 @@ TEST(ParserTest, errors) {
"<string>:1.1: syntax error, unexpected [, "
"expecting {");
testError("{ 123 }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3-5: syntax error, unexpected integer, "
"expecting }");
testError("{ 123 }\n",
Parser6Context::PARSER_DHCP6,
"<string>:1.3-5: syntax error, unexpected integer");
testError("{ \"foo\" }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.9: syntax error, unexpected }, "
"expecting :");
testError("{ \"foo\" }\n",
......@@ -436,21 +436,21 @@ TEST(ParserTest, errors) {
"<string>:2.1: syntax error, unexpected end of file, "
"expecting \",\" or }");
testError("{}{}\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3: syntax error, unexpected {, "
"expecting end of file");
// bad commas
testError("{ , }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3: syntax error, unexpected \",\", "
"expecting }");
testError("{ , \"foo\":true }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.3: syntax error, unexpected \",\", "
"expecting }");
testError("{ \"foo\":true, }\n",
Parser6Context::SUBPARSER_JSON,
Parser6Context::PARSER_JSON,
"<string>:1.15: syntax error, unexpected }, "
"expecting constant string");
......
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