/// 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;
/// @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);
///
/// 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_;
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
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.
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) {
"\"map\": { \"foo\": \"bar\" },"
"\"list\": [ 1, 2, 3 ],"
"\"null\": null }";
- testParser(txt, Parser6Context::SUBPARSER_JSON);
+ testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, keywordJSON) {
"\"type\": \"password\","
"\"user\": \"name\","
"\"password\": \"type\" }";
- testParser(txt, Parser6Context::SUBPARSER_JSON);
+ testParser(txt, Parser6Context::PARSER_JSON);
}
TEST(ParserTest, keywordDhcp6) {
// 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",
"<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",
"<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");