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

[5036] Comments added, some constants removed.

parent 39919c3b
...@@ -102,10 +102,9 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence} ...@@ -102,10 +102,9 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
if (start_token_flag) { if (start_token_flag) {
start_token_flag = false; start_token_flag = false;
switch (start_token_value) { switch (start_token_value) {
case Parser6Context::SUBPARSER_JSON: case Parser6Context::PARSER_JSON:
default: default:
return isc::dhcp::Dhcp6Parser::make_SUB_JSON(driver.loc_); return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_JSON(driver.loc_);
// return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(driver.loc_);
case Parser6Context::PARSER_DHCP6: case Parser6Context::PARSER_DHCP6:
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(driver.loc_); return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(driver.loc_);
case Parser6Context::SUBPARSER_DHCP6: case Parser6Context::SUBPARSER_DHCP6:
......
...@@ -144,7 +144,7 @@ using namespace std; ...@@ -144,7 +144,7 @@ using namespace std;
// Not real tokens, just a way to signal what the parser is expected to // Not real tokens, just a way to signal what the parser is expected to
// parse. // parse.
TOPLEVEL_GENERIC_JSON TOPLEVEL_JSON
TOPLEVEL_DHCP6 TOPLEVEL_DHCP6
SUB_DHCP6 SUB_DHCP6
SUB_INTERFACES6 SUB_INTERFACES6
...@@ -155,7 +155,6 @@ using namespace std; ...@@ -155,7 +155,6 @@ using namespace std;
SUB_OPTION_DEF SUB_OPTION_DEF
SUB_OPTION_DATA SUB_OPTION_DATA
SUB_HOOKS_LIBRARY SUB_HOOKS_LIBRARY
SUB_JSON
; ;
%token <std::string> STRING "constant string" %token <std::string> STRING "constant string"
...@@ -175,7 +174,7 @@ using namespace std; ...@@ -175,7 +174,7 @@ using namespace std;
// We made the same for subparsers at the exception of the JSON value. // We made the same for subparsers at the exception of the JSON value.
%start start; %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 | TOPLEVEL_DHCP6 { ctx.ctx_ = ctx.CONFIG; } syntax_map
| SUB_DHCP6 { ctx.ctx_ = ctx.DHCP6; } sub_dhcp6 | SUB_DHCP6 { ctx.ctx_ = ctx.DHCP6; } sub_dhcp6
| SUB_INTERFACES6 { ctx.ctx_ = ctx.INTERFACES_CONFIG; } sub_interfaces6 | SUB_INTERFACES6 { ctx.ctx_ = ctx.INTERFACES_CONFIG; } sub_interfaces6
...@@ -186,7 +185,6 @@ start: TOPLEVEL_GENERIC_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } map2 ...@@ -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_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
| SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
| SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
| SUB_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
; ;
// ---- generic JSON parser --------------------------------- // ---- generic JSON parser ---------------------------------
...@@ -270,7 +268,7 @@ not_empty_list: value { ...@@ -270,7 +268,7 @@ not_empty_list: value {
// Unknown keyword in a map // Unknown keyword in a map
unknown_map_entry: STRING COLON { unknown_map_entry: STRING COLON {
const std::string& where = ctx.context_name(); const std::string& where = ctx.contextName();
const std::string& keyword = $1; const std::string& keyword = $1;
error(@1, error(@1,
"got unexpected keyword \"" + keyword + "\" in " + where + " map."); "got unexpected keyword \"" + keyword + "\" in " + where + " map.");
...@@ -279,7 +277,6 @@ unknown_map_entry: STRING COLON { ...@@ -279,7 +277,6 @@ unknown_map_entry: STRING COLON {
// This defines the top-level { } that holds Dhcp6, Dhcp4, DhcpDdns or Logging // This defines the top-level { } that holds Dhcp6, Dhcp4, DhcpDdns or Logging
// objects. // objects.
// ctx_ = CONFIG
syntax_map: LCURLY_BRACKET { syntax_map: LCURLY_BRACKET {
// This code is executed when we're about to start parsing // This code is executed when we're about to start parsing
// the content of the map // the content of the map
......
...@@ -114,7 +114,7 @@ Parser6Context::leave() ...@@ -114,7 +114,7 @@ Parser6Context::leave()
} }
const std::string const std::string
Parser6Context::context_name() Parser6Context::contextName()
{ {
switch (ctx_) { switch (ctx_) {
case NO_KEYWORD: case NO_KEYWORD:
......
...@@ -48,41 +48,40 @@ public: ...@@ -48,41 +48,40 @@ public:
/// is being told to start parsing as SUBPARSER_HOST_RESERVATION6. /// is being told to start parsing as SUBPARSER_HOST_RESERVATION6.
typedef enum { typedef enum {
/// This parser will parse the content as generic JSON. /// 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, PARSER_DHCP6,
/// This parser will parse the content of Dhcp6. It is mostly used /// This parser will parse the content of Dhcp6 (without outer { } and
/// in unit-tests as most of the unit-tests do not define the outer /// without "Dhcp6"). It is mostly used in unit-tests as most of the
/// map and Dhcp6 entity, just the contents of it. /// unit-tests do not define the outer map and Dhcp6 entity, just the
/// contents of it.
SUBPARSER_DHCP6, SUBPARSER_DHCP6,
/// This will parse the conde as Subnet6 content. /// This will parse the input as Subnet6 content.
PARSER_SUBNET6, PARSER_SUBNET6,
/// This parser will parse pool6 content. /// This will parse the input as pool6 content.
PARSER_POOL6, PARSER_POOL6,
/// This parser will parse the interfaces content. /// This will parse the input as interfaces content.
PARSER_INTERFACES, PARSER_INTERFACES,
/// This parser will parse the content as pd-pool. /// This will parse the input as pd-pool content.
PARSER_PD_POOL, PARSER_PD_POOL,
/// This parser will parse the content as host-reservation /// This will parse the input as host-reservation.
PARSER_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, PARSER_OPTION_DEF,
/// This parser will parse the content as option data. /// This will parse the input as option data.
PARSER_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 PARSER_HOOKS_LIBRARY
} ParserType; } ParserType;
...@@ -109,13 +108,27 @@ public: ...@@ -109,13 +108,27 @@ public:
/// @brief Run the parser on the string specified. /// @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 str string to be parsed
/// @param parser_type specifies expected content (either DHCP6 or generic JSON) /// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
/// @return true on success. /// @return Element structure representing parsed text.
isc::data::ConstElementPtr parseString(const std::string& str, isc::data::ConstElementPtr parseString(const std::string& str,
ParserType parser_type); ParserType parser_type);
/// @brief Run the parser on the file specified. /// @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, isc::data::ConstElementPtr parseFile(const std::string& filename,
ParserType parser_type); ParserType parser_type);
...@@ -141,43 +154,86 @@ public: ...@@ -141,43 +154,86 @@ public:
/// ///
/// Convert a bison location into an element position /// Convert a bison location into an element position
/// (take the begin, the end is lost) /// (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); isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
/// @brief Defines syntactic contexts for lexical tie-ins /// @brief Defines syntactic contexts for lexical tie-ins
typedef enum { typedef enum {
/// at toplevel ///< This one is used in pure JSON mode.
NO_KEYWORD, NO_KEYWORD,
///< Used while parsing top level (that contains Dhcp6, Logging and others)
CONFIG, CONFIG,
/// in config
///< Used while parsing content of Dhcp6.
DHCP6, DHCP6,
// not yet DHCP4, // not yet DHCP4,
// not yet DHCP_DDNS, // not yet DHCP_DDNS,
///< Used while parsing content of Logging
LOGGING, LOGGING,
/// Dhcp6
/// Used while parsing Dhcp6/interfaces structures.
INTERFACES_CONFIG, INTERFACES_CONFIG,
LEASE_DATABASE,
/// Used while parsing Dhcp6/hosts-database structures.
HOSTS_DATABASE, HOSTS_DATABASE,
/// Used while parsing Dhcp6/lease-database structures.
LEASE_DATABASE,
/// Used while parsing Dhcp6/mac-sources structures.
MAC_SOURCES, MAC_SOURCES,
/// Used while parsing Dhcp6/host-reservation-identifiers.
HOST_RESERVATION_IDENTIFIERS, HOST_RESERVATION_IDENTIFIERS,
/// Used while parsing Dhcp6/hooks-libraries.
HOOKS_LIBRARIES, HOOKS_LIBRARIES,
/// Used while parsing Dhcp6/Subnet6 structures.
SUBNET6, SUBNET6,
/// Used while parsing Dhcp6/option-def structures.
OPTION_DEF, 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, OPTION_DATA,
/// Used while parsing Dhcp6/client-classes structures.
CLIENT_CLASSES, CLIENT_CLASSES,
/// Used while parsing Dhcp6/server-id structures.
SERVER_ID, SERVER_ID,
/// Used while parsing Dhcp6/control-socket structures.
CONTROL_SOCKET, CONTROL_SOCKET,
/// subnet6
/// Used while parsing Dhcp6/subnet6/pools structures.
POOLS, POOLS,
/// Used while parsing Dhcp6/subnet6/pd-pools structures.
PD_POOLS, PD_POOLS,
/// Used while parsing Dhcp6/reservations structures.
RESERVATIONS, RESERVATIONS,
/// Used while parsing Dhcp6/subnet6/relay structures.
RELAY, RELAY,
/// client-classes
/// Used while parsing Dhcp6/client-classes structures.
CLIENT_CLASS, CLIENT_CLASS,
/// Logging
/// Used while parsing Logging/loggers structures.
LOGGERS, LOGGERS,
/// loggers
/// Used while parsing Logging/loggers/output_options structures.
OUTPUT_OPTIONS OUTPUT_OPTIONS
} ParserContext; } ParserContext;
/// @brief File name /// @brief File name
std::string file_; std::string file_;
...@@ -201,12 +257,24 @@ public: ...@@ -201,12 +257,24 @@ public:
FILE* sfile_; FILE* sfile_;
/// @brief sFile (aka FILE) stack /// @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_; std::vector<FILE*> sfiles_;
/// @brief Current syntactic context /// @brief Current syntactic context
ParserContext ctx_; ParserContext ctx_;
/// @brief Enter a new syntactic context /// @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); void enter(const ParserContext& ctx);
/// @brief Leave a syntactic context /// @brief Leave a syntactic context
...@@ -214,7 +282,8 @@ public: ...@@ -214,7 +282,8 @@ public:
void leave(); void leave();
/// @brief Get the syntactix context name /// @brief Get the syntactix context name
const std::string context_name(); /// @return printable name of the context.
const std::string contextName();
private: private:
/// @brief Flag determining scanner debugging. /// @brief Flag determining scanner debugging.
......
...@@ -639,15 +639,24 @@ public: ...@@ -639,15 +639,24 @@ public:
NakedDhcpv6Srv srv_; 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 inline isc::data::ConstElementPtr
parseJSON(const std::string& in) parseJSON(const std::string& in)
{ {
isc::dhcp::Parser6Context ctx; 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 inline isc::data::ConstElementPtr
parseDHCP6(const std::string& in) parseDHCP6(const std::string& in)
{ {
...@@ -656,14 +665,17 @@ parseDHCP6(const std::string& in) ...@@ -656,14 +665,17 @@ parseDHCP6(const std::string& in)
return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_DHCP6)); return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_DHCP6));
} }
catch (const std::exception& ex) { catch (const std::exception& ex) {
#ifdef ENABLE_DEBUG
std::cout << "EXCEPTION: " << ex.what() << std::endl; std::cout << "EXCEPTION: " << ex.what() << std::endl;
#endif // ENABLE_DEBUG
throw; 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 inline isc::data::ConstElementPtr
parseOPTION_DEF(const std::string& in) parseOPTION_DEF(const std::string& in)
{ {
...@@ -672,9 +684,7 @@ 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)); return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEF));
} }
catch (const std::exception& ex) { catch (const std::exception& ex) {
#ifdef ENABLE_DEBUG
std::cout << "EXCEPTION: " << ex.what() << std::endl; std::cout << "EXCEPTION: " << ex.what() << std::endl;
#endif // ENABLE_DEBUG
throw; throw;
} }
} }
......
...@@ -65,35 +65,35 @@ void testParser2(const std::string& txt, Parser6Context::ParserType parser_type) ...@@ -65,35 +65,35 @@ void testParser2(const std::string& txt, Parser6Context::ParserType parser_type)
TEST(ParserTest, mapInMap) { TEST(ParserTest, mapInMap) {
string txt = "{ \"xyzzy\": { \"foo\": 123, \"baz\": 456 } }"; string txt = "{ \"xyzzy\": { \"foo\": 123, \"baz\": 456 } }";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, listInList) { TEST(ParserTest, listInList) {
string txt = "[ [ \"Britain\", \"Wales\", \"Scotland\" ], " string txt = "[ [ \"Britain\", \"Wales\", \"Scotland\" ], "
"[ \"Pomorze\", \"Wielkopolska\", \"Tatry\"] ]"; "[ \"Pomorze\", \"Wielkopolska\", \"Tatry\"] ]";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, nestedMaps) { TEST(ParserTest, nestedMaps) {
string txt = "{ \"europe\": { \"UK\": { \"London\": { \"street\": \"221B Baker\" }}}}"; string txt = "{ \"europe\": { \"UK\": { \"London\": { \"street\": \"221B Baker\" }}}}";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, nestedLists) { TEST(ParserTest, nestedLists) {
string txt = "[ \"half\", [ \"quarter\", [ \"eighth\", [ \"sixteenth\" ]]]]"; string txt = "[ \"half\", [ \"quarter\", [ \"eighth\", [ \"sixteenth\" ]]]]";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, listsInMaps) { TEST(ParserTest, listsInMaps) {
string txt = "{ \"constellations\": { \"orion\": [ \"rigel\", \"betelguese\" ], " string txt = "{ \"constellations\": { \"orion\": [ \"rigel\", \"betelguese\" ], "
"\"cygnus\": [ \"deneb\", \"albireo\"] } }"; "\"cygnus\": [ \"deneb\", \"albireo\"] } }";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, mapsInLists) { TEST(ParserTest, mapsInLists) {
string txt = "[ { \"body\": \"earth\", \"gravity\": 1.0 }," string txt = "[ { \"body\": \"earth\", \"gravity\": 1.0 },"
" { \"body\": \"mars\", \"gravity\": 0.376 } ]"; " { \"body\": \"mars\", \"gravity\": 0.376 } ]";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, types) { TEST(ParserTest, types) {
...@@ -103,7 +103,7 @@ TEST(ParserTest, types) { ...@@ -103,7 +103,7 @@ TEST(ParserTest, types) {
"\"map\": { \"foo\": \"bar\" }," "\"map\": { \"foo\": \"bar\" },"
"\"list\": [ 1, 2, 3 ]," "\"list\": [ 1, 2, 3 ],"
"\"null\": null }"; "\"null\": null }";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, keywordJSON) { TEST(ParserTest, keywordJSON) {
...@@ -111,7 +111,7 @@ TEST(ParserTest, keywordJSON) { ...@@ -111,7 +111,7 @@ TEST(ParserTest, keywordJSON) {
"\"type\": \"password\"," "\"type\": \"password\","
"\"user\": \"name\"," "\"user\": \"name\","
"\"password\": \"type\" }"; "\"password\": \"type\" }";
testParser(txt, Parser6Context::SUBPARSER_JSON); testParser(txt, Parser6Context::PARSER_JSON);
} }
TEST(ParserTest, keywordDhcp6) { TEST(ParserTest, keywordDhcp6) {
...@@ -267,142 +267,142 @@ void testError(const std::string& txt, ...@@ -267,142 +267,142 @@ void testError(const std::string& txt,
// Check errors // Check errors
TEST(ParserTest, errors) { TEST(ParserTest, errors) {
// no input // no input
testError("", Parser6Context::SUBPARSER_JSON, testError("", Parser6Context::PARSER_JSON,
"<string>:1.1: syntax error, unexpected end of file"); "<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"); "<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"); "<string>:2.1: syntax error, unexpected end of file");
// comments // comments
testError("# nothing\n", testError("# nothing\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, " "<string>:2.1: syntax error, unexpected end of file, "
"expecting {"); "expecting {");
testError(" #\n", testError(" #\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, " "<string>:2.1: syntax error, unexpected end of file, "
"expecting {"); "expecting {");
testError("// nothing\n", testError("// nothing\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, " "<string>:2.1: syntax error, unexpected end of file, "
"expecting {"); "expecting {");
testError("/* nothing */\n", testError("/* nothing */\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:2.1: syntax error, unexpected end of file, " "<string>:2.1: syntax error, unexpected end of file, "
"expecting {"); "expecting {");
testError("/* no\nthing */\n", testError("/* no\nthing */\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:3.1: syntax error, unexpected end of file, " "<string>:3.1: syntax error, unexpected end of file, "
"expecting {"); "expecting {");
testError("/* no\nthing */\n\n", testError("/* no\nthing */\n\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:4.1: syntax error, unexpected end of file, " "<string>:4.1: syntax error, unexpected end of file, "
"expecting {"); "expecting {");
testError("/* nothing\n", testError("/* nothing\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"Comment not closed. (/* in line 1"); "Comment not closed. (/* in line 1");
testError("\n\n\n/* nothing\n", testError("\n\n\n/* nothing\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"Comment not closed. (/* in line 4"); "Comment not closed. (/* in line 4");
testError("{ /* */*/ }\n", testError("{ /* */*/ }\n",
Parser6Context::SUBPARSER_JSON, Parser6Context::PARSER_JSON,
"<string>:1.3-8: Invalid character: *"); "<string>:1.3-8: Invalid character: *");
testError("{ /* // *// }\n", testError("{ /* // *// }\n",