From 9eaae99da7ffceb04484184ae0322bdf3c1f54ec Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Sun, 10 Mar 2024 22:07:54 +0000 Subject: [PATCH] LibIDL: Ignore leading underscores in IDL identifier names According to the WebIDL specification, any leading underscores in identifier names are ignored. A leading underscore is used when an identifier would otherwise be a reserved word. --- Userland/Libraries/LibIDL/IDLParser.cpp | 67 ++++++++++++++++--------- Userland/Libraries/LibIDL/IDLParser.h | 4 ++ 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/Userland/Libraries/LibIDL/IDLParser.cpp b/Userland/Libraries/LibIDL/IDLParser.cpp index fa725e99a0..6f1f74dc1f 100644 --- a/Userland/Libraries/LibIDL/IDLParser.cpp +++ b/Userland/Libraries/LibIDL/IDLParser.cpp @@ -9,6 +9,7 @@ #include "IDLParser.h" #include +#include #include #include #include @@ -104,6 +105,27 @@ void Parser::assert_string(StringView expected) report_parsing_error(ByteString::formatted("expected '{}'", expected), filename, input, lexer.tell()); } +ByteString Parser::parse_identifier_until(AK::Function predicate) +{ + auto identifier = lexer.consume_until(move(predicate)); + return identifier.trim("_"sv, TrimMode::Left); +} + +ByteString Parser::parse_identifier_ending_with_space_or(auto... possible_terminating_characters) +{ + return parse_identifier_until([&](auto ch) { return (is_ascii_space(ch) || ... || (ch == possible_terminating_characters)); }); +} + +ByteString Parser::parse_identifier_ending_with(auto... possible_terminating_characters) +{ + return parse_identifier_until([&](auto ch) { return (... || (ch == possible_terminating_characters)); }); +} + +ByteString Parser::parse_identifier_ending_with_space() +{ + return parse_identifier_ending_with_space_or(); +} + HashMap Parser::parse_extended_attributes() { HashMap extended_attributes; @@ -111,7 +133,7 @@ HashMap Parser::parse_extended_attributes() consume_whitespace(); if (lexer.consume_specific(']')) break; - auto name = lexer.consume_until([](auto ch) { return ch == ']' || ch == '=' || ch == ','; }); + auto name = parse_identifier_ending_with(']', '=', ','); if (lexer.consume_specific('=')) { bool did_open_paren = false; auto value = lexer.consume_until( @@ -277,20 +299,19 @@ void Parser::parse_attribute(HashMap& extended_attribute auto type = parse_type(); consume_whitespace(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == ';'; }); + auto name = parse_identifier_ending_with_space_or(';'); consume_whitespace(); assert_specific(';'); - auto name_as_string = name.to_byte_string(); - auto getter_callback_name = ByteString::formatted("{}_getter", name_as_string.to_snakecase()); - auto setter_callback_name = ByteString::formatted("{}_setter", name_as_string.to_snakecase()); + auto getter_callback_name = ByteString::formatted("{}_getter", name.to_snakecase()); + auto setter_callback_name = ByteString::formatted("{}_setter", name.to_snakecase()); Attribute attribute { inherit, readonly, move(type), - move(name_as_string), + move(name), move(extended_attributes), move(getter_callback_name), move(setter_callback_name), @@ -305,7 +326,7 @@ void Parser::parse_constant(Interface& interface) auto type = parse_type(); consume_whitespace(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == '='; }); + auto name = parse_identifier_ending_with_space_or('='); consume_whitespace(); lexer.consume_specific('='); consume_whitespace(); @@ -343,7 +364,7 @@ Vector Parser::parse_parameters() auto type = parse_type(); bool variadic = lexer.consume_specific("..."sv); consume_whitespace(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == ',' || ch == ')' || ch == '='; }); + auto name = parse_identifier_ending_with_space_or(',', ')', '='); Parameter parameter = { move(type), move(name), optional, {}, move(extended_attributes), variadic }; consume_whitespace(); if (variadic) { @@ -381,7 +402,7 @@ Function Parser::parse_function(HashMap& extended_attrib auto return_type = parse_type(); consume_whitespace(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == '('; }); + auto name = parse_identifier_ending_with_space_or('('); consume_whitespace(); assert_specific('('); auto parameters = parse_parameters(); @@ -560,11 +581,11 @@ void Parser::parse_deleter(HashMap& extended_attributes, void Parser::parse_interface(Interface& interface) { consume_whitespace(); - interface.name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + interface.name = parse_identifier_ending_with_space(); consume_whitespace(); if (lexer.consume_specific(':')) { consume_whitespace(); - interface.parent_name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + interface.parent_name = parse_identifier_ending_with_space(); consume_whitespace(); } assert_specific('{'); @@ -650,7 +671,7 @@ void Parser::parse_namespace(Interface& interface) { consume_whitespace(); - interface.name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + interface.name = parse_identifier_ending_with_space(); interface.is_namespace = true; consume_whitespace(); @@ -681,7 +702,7 @@ void Parser::parse_enumeration(HashMap extended_attribut Enumeration enumeration {}; enumeration.extended_attributes = move(extended_attributes); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + auto name = parse_identifier_ending_with_space(); consume_whitespace(); assert_specific('{'); @@ -736,10 +757,10 @@ void Parser::parse_typedef(Interface& interface) auto type = parse_type(); consume_whitespace(); - auto name = lexer.consume_until(';'); + auto name = parse_identifier_ending_with(';'); assert_specific(';'); - interface.typedefs.set(name, Typedef { move(extended_attributes), move(type) }); + interface.typedefs.set(move(name), Typedef { move(extended_attributes), move(type) }); consume_whitespace(); } @@ -750,12 +771,12 @@ void Parser::parse_dictionary(Interface& interface) Dictionary dictionary {}; - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + auto name = parse_identifier_ending_with_space(); consume_whitespace(); if (lexer.consume_specific(':')) { consume_whitespace(); - dictionary.parent_name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + dictionary.parent_name = parse_identifier_ending_with_space(); consume_whitespace(); } assert_specific('{'); @@ -783,7 +804,7 @@ void Parser::parse_dictionary(Interface& interface) auto type = parse_type(); consume_whitespace(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == ';'; }); + auto name = parse_identifier_ending_with_space_or(';'); consume_whitespace(); Optional default_value; @@ -800,7 +821,7 @@ void Parser::parse_dictionary(Interface& interface) DictionaryMember member { required, move(type), - name, + move(name), move(extended_attributes), Optional(move(default_value)), }; @@ -842,7 +863,7 @@ void Parser::parse_callback_function(HashMap& extended_a assert_string("callback"sv); consume_whitespace(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + auto name = parse_identifier_ending_with_space(); consume_whitespace(); assert_specific('='); @@ -856,7 +877,7 @@ void Parser::parse_callback_function(HashMap& extended_a consume_whitespace(); assert_specific(';'); - interface.callback_functions.set(name, CallbackFunction { move(return_type), move(parameters), extended_attributes.contains("LegacyTreatNonObjectAsNull") }); + interface.callback_functions.set(move(name), CallbackFunction { move(return_type), move(parameters), extended_attributes.contains("LegacyTreatNonObjectAsNull") }); consume_whitespace(); } @@ -880,11 +901,11 @@ void Parser::parse_non_interface_entities(bool allow_interface, Interface& inter parse_callback_function(extended_attributes, interface); } else if ((allow_interface && !lexer.next_is("interface") && !lexer.next_is("namespace")) || !allow_interface) { auto current_offset = lexer.tell(); - auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + auto name = parse_identifier_ending_with_space(); consume_whitespace(); if (lexer.consume_specific("includes"sv)) { consume_whitespace(); - auto mixin_name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == ';'; }); + auto mixin_name = parse_identifier_ending_with_space_or(';'); interface.included_mixins.ensure(name).set(mixin_name); consume_whitespace(); assert_specific(';'); diff --git a/Userland/Libraries/LibIDL/IDLParser.h b/Userland/Libraries/LibIDL/IDLParser.h index 2320ed17f8..c8db88d0ff 100644 --- a/Userland/Libraries/LibIDL/IDLParser.h +++ b/Userland/Libraries/LibIDL/IDLParser.h @@ -57,6 +57,10 @@ private: Vector parse_parameters(); NonnullRefPtr parse_type(); void parse_constant(Interface&); + ByteString parse_identifier_until(AK::Function predicate); + ByteString parse_identifier_ending_with(auto... possible_terminating_characters); + ByteString parse_identifier_ending_with_space(); + ByteString parse_identifier_ending_with_space_or(auto... possible_terminating_characters); ByteString import_base_path; ByteString filename;