2022-02-16 22:30:43 +00:00
/*
2023-02-20 17:56:08 +00:00
* Copyright ( c ) 2020 - 2023 , Andreas Kling < kling @ serenityos . org >
2022-10-20 22:42:27 +00:00
* Copyright ( c ) 2021 - 2022 , Linus Groh < linusg @ serenityos . org >
2022-02-16 22:30:43 +00:00
* Copyright ( c ) 2021 , Luke Wilde < lukew @ serenityos . org >
* Copyright ( c ) 2022 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "IDLParser.h"
2022-10-08 22:48:04 +00:00
# include <AK/Assertions.h>
2022-02-16 22:30:43 +00:00
# include <AK/LexicalPath.h>
# include <AK/QuickSort.h>
2023-02-09 02:02:46 +00:00
# include <LibCore/File.h>
2023-03-21 15:35:30 +00:00
# include <LibFileSystem/FileSystem.h>
2022-02-16 22:30:43 +00:00
[[noreturn]] static void report_parsing_error ( StringView message , StringView filename , StringView input , size_t offset )
{
// FIXME: Spaghetti code ahead.
size_t lineno = 1 ;
size_t colno = 1 ;
size_t start_line = 0 ;
size_t line_length = 0 ;
for ( size_t index = 0 ; index < input . length ( ) ; + + index ) {
if ( offset = = index )
colno = index - start_line + 1 ;
if ( input [ index ] = = ' \n ' ) {
if ( index > = offset )
break ;
start_line = index + 1 ;
line_length = 0 ;
+ + lineno ;
} else {
+ + line_length ;
}
}
StringBuilder error_message ;
error_message . appendff ( " {} \n " , input . substring_view ( start_line , line_length ) ) ;
for ( size_t i = 0 ; i < colno - 1 ; + + i )
error_message . append ( ' ' ) ;
2022-07-11 17:32:29 +00:00
error_message . append ( " \033 [1;31m^ \n " sv ) ;
2022-02-16 22:30:43 +00:00
error_message . appendff ( " {}:{}: error: {} \033 [0m \n " , filename , lineno , message ) ;
warnln ( " {} " , error_message . string_view ( ) ) ;
exit ( EXIT_FAILURE ) ;
}
2022-12-04 18:02:33 +00:00
static DeprecatedString convert_enumeration_value_to_cpp_enum_member ( DeprecatedString const & value , HashTable < DeprecatedString > & names_already_seen )
2022-02-16 22:30:43 +00:00
{
StringBuilder builder ;
GenericLexer lexer { value } ;
while ( ! lexer . is_eof ( ) ) {
lexer . ignore_while ( [ ] ( auto c ) { return is_ascii_space ( c ) | | c = = ' - ' | | c = = ' _ ' ; } ) ;
auto word = lexer . consume_while ( [ ] ( auto c ) { return is_ascii_alphanumeric ( c ) ; } ) ;
if ( ! word . is_empty ( ) ) {
builder . append ( word . to_titlecase_string ( ) ) ;
} else {
auto non_alnum_string = lexer . consume_while ( [ ] ( auto c ) { return ! is_ascii_alphanumeric ( c ) ; } ) ;
if ( ! non_alnum_string . is_empty ( ) )
2022-07-11 20:10:18 +00:00
builder . append ( ' _ ' ) ;
2022-02-16 22:30:43 +00:00
}
}
if ( builder . is_empty ( ) )
2022-07-11 17:32:29 +00:00
builder . append ( " Empty " sv ) ;
2022-02-16 22:30:43 +00:00
while ( names_already_seen . contains ( builder . string_view ( ) ) )
builder . append ( ' _ ' ) ;
names_already_seen . set ( builder . string_view ( ) ) ;
2023-01-26 18:58:09 +00:00
return builder . to_deprecated_string ( ) ;
2022-02-16 22:30:43 +00:00
}
namespace IDL {
void Parser : : assert_specific ( char ch )
{
if ( ! lexer . consume_specific ( ch ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " expected '{}' " , ch ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
}
void Parser : : consume_whitespace ( )
{
bool consumed = true ;
while ( consumed ) {
consumed = lexer . consume_while ( is_ascii_space ) . length ( ) > 0 ;
if ( lexer . consume_specific ( " // " ) ) {
lexer . consume_until ( ' \n ' ) ;
lexer . ignore ( ) ;
consumed = true ;
}
}
}
void Parser : : assert_string ( StringView expected )
{
if ( ! lexer . consume_specific ( expected ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " expected '{}' " , expected ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
}
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > Parser : : parse_extended_attributes ( )
2022-02-16 22:30:43 +00:00
{
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
2022-02-16 22:30:43 +00:00
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' ] ' ) )
break ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return ch = = ' ] ' | | ch = = ' = ' | | ch = = ' , ' ; } ) ;
if ( lexer . consume_specific ( ' = ' ) ) {
2022-10-08 22:47:08 +00:00
bool did_open_paren = false ;
auto value = lexer . consume_until (
2022-11-19 01:09:53 +00:00
[ & did_open_paren ] ( auto ch ) {
2022-10-08 22:47:08 +00:00
if ( ch = = ' ( ' ) {
did_open_paren = true ;
return false ;
}
if ( did_open_paren )
return ch = = ' ) ' ;
return ch = = ' ] ' | | ch = = ' , ' ;
} ) ;
2022-02-16 22:30:43 +00:00
extended_attributes . set ( name , value ) ;
} else {
extended_attributes . set ( name , { } ) ;
}
lexer . consume_specific ( ' , ' ) ;
}
consume_whitespace ( ) ;
return extended_attributes ;
}
2022-12-04 18:02:33 +00:00
static HashTable < DeprecatedString > import_stack ;
2022-04-30 17:27:50 +00:00
Optional < Interface & > Parser : : resolve_import ( auto path )
2022-02-16 22:30:43 +00:00
{
auto include_path = LexicalPath : : join ( import_base_path , path ) . string ( ) ;
2023-03-21 15:35:30 +00:00
if ( ! FileSystem : : exists ( include_path ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " {}: No such file or directory " , include_path ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
2023-03-24 09:57:53 +00:00
auto real_path_error_or = FileSystem : : real_path ( include_path ) ;
if ( real_path_error_or . is_error ( ) )
report_parsing_error ( DeprecatedString : : formatted ( " Failed to resolve path {}: {} " , include_path , real_path_error_or . error ( ) ) , filename , input , lexer . tell ( ) ) ;
auto real_path = real_path_error_or . release_value ( ) . to_deprecated_string ( ) ;
2022-10-08 22:48:04 +00:00
if ( top_level_resolved_imports ( ) . contains ( real_path ) )
return * top_level_resolved_imports ( ) . find ( real_path ) - > value ;
2022-02-16 22:30:43 +00:00
2022-04-01 18:43:02 +00:00
if ( import_stack . contains ( real_path ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Circular import detected: {} " , include_path ) , filename , input , lexer . tell ( ) ) ;
2022-04-01 18:43:02 +00:00
import_stack . set ( real_path ) ;
2022-02-16 22:30:43 +00:00
2023-02-09 02:02:46 +00:00
auto file_or_error = Core : : File : : open ( real_path , Core : : File : : OpenMode : : Read ) ;
2022-02-16 22:30:43 +00:00
if ( file_or_error . is_error ( ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Failed to open {}: {} " , real_path , file_or_error . error ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
2022-12-08 14:04:49 +00:00
auto data_or_error = file_or_error . value ( ) - > read_until_eof ( ) ;
if ( data_or_error . is_error ( ) )
report_parsing_error ( DeprecatedString : : formatted ( " Failed to read {}: {} " , real_path , data_or_error . error ( ) ) , filename , input , lexer . tell ( ) ) ;
auto & result = Parser ( this , real_path , data_or_error . value ( ) , import_base_path ) . parse ( ) ;
2022-04-01 18:43:02 +00:00
import_stack . remove ( real_path ) ;
2022-10-08 22:48:04 +00:00
top_level_resolved_imports ( ) . set ( real_path , & result ) ;
2022-03-30 20:30:12 +00:00
return result ;
2022-02-16 22:30:43 +00:00
}
2023-02-20 17:56:08 +00:00
NonnullRefPtr < Type const > Parser : : parse_type ( )
2022-02-16 22:30:43 +00:00
{
if ( lexer . consume_specific ( ' ( ' ) ) {
2023-03-06 13:17:01 +00:00
Vector < NonnullRefPtr < Type const > > union_member_types ;
2022-02-16 22:30:43 +00:00
union_member_types . append ( parse_type ( ) ) ;
consume_whitespace ( ) ;
2022-07-11 17:32:29 +00:00
assert_string ( " or " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
union_member_types . append ( parse_type ( ) ) ;
consume_whitespace ( ) ;
while ( lexer . consume_specific ( " or " ) ) {
consume_whitespace ( ) ;
union_member_types . append ( parse_type ( ) ) ;
consume_whitespace ( ) ;
}
assert_specific ( ' ) ' ) ;
bool nullable = lexer . consume_specific ( ' ? ' ) ;
return adopt_ref ( * new UnionType ( " " , nullable , move ( union_member_types ) ) ) ;
}
bool unsigned_ = lexer . consume_specific ( " unsigned " ) ;
if ( unsigned_ )
consume_whitespace ( ) ;
2022-08-11 14:48:40 +00:00
// FIXME: Actually treat "unrestricted" and normal floats/doubles differently.
if ( lexer . consume_specific ( " unrestricted " ) )
consume_whitespace ( ) ;
2022-02-16 22:30:43 +00:00
auto name = lexer . consume_until ( [ ] ( auto ch ) { return ! is_ascii_alphanumeric ( ch ) & & ch ! = ' _ ' ; } ) ;
2022-05-09 20:25:42 +00:00
2023-03-10 07:48:54 +00:00
if ( name . equals_ignoring_ascii_case ( " long " sv ) ) {
2022-05-09 20:25:42 +00:00
consume_whitespace ( ) ;
if ( lexer . consume_specific ( " long " sv ) )
2022-07-11 17:32:29 +00:00
name = " long long " sv ;
2022-05-09 20:25:42 +00:00
}
2023-03-06 13:17:01 +00:00
Vector < NonnullRefPtr < Type const > > parameters ;
2022-02-16 22:30:43 +00:00
bool is_parameterized_type = false ;
if ( lexer . consume_specific ( ' < ' ) ) {
is_parameterized_type = true ;
parameters . append ( parse_type ( ) ) ;
while ( lexer . consume_specific ( ' , ' ) ) {
consume_whitespace ( ) ;
parameters . append ( parse_type ( ) ) ;
}
lexer . consume_specific ( ' > ' ) ;
}
auto nullable = lexer . consume_specific ( ' ? ' ) ;
StringBuilder builder ;
if ( unsigned_ )
2022-07-11 17:32:29 +00:00
builder . append ( " unsigned " sv ) ;
2022-02-16 22:30:43 +00:00
builder . append ( name ) ;
if ( is_parameterized_type )
2022-12-06 01:12:49 +00:00
return adopt_ref ( * new ParameterizedType ( builder . to_deprecated_string ( ) , nullable , move ( parameters ) ) ) ;
2022-02-16 22:30:43 +00:00
2022-12-06 01:12:49 +00:00
return adopt_ref ( * new Type ( builder . to_deprecated_string ( ) , nullable ) ) ;
2022-02-16 22:30:43 +00:00
}
2022-12-04 18:02:33 +00:00
void Parser : : parse_attribute ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-04-05 15:09:42 +00:00
bool inherit = lexer . consume_specific ( " inherit " ) ;
if ( inherit )
consume_whitespace ( ) ;
2022-02-16 22:30:43 +00:00
bool readonly = lexer . consume_specific ( " readonly " ) ;
if ( readonly )
consume_whitespace ( ) ;
if ( lexer . consume_specific ( " attribute " ) )
consume_whitespace ( ) ;
auto type = parse_type ( ) ;
consume_whitespace ( ) ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' ; ' ; } ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
2022-12-06 01:12:49 +00:00
auto name_as_string = name . to_deprecated_string ( ) ;
2022-12-04 18:02:33 +00:00
auto getter_callback_name = DeprecatedString : : formatted ( " {}_getter " , name_as_string . to_snakecase ( ) ) ;
auto setter_callback_name = DeprecatedString : : formatted ( " {}_setter " , name_as_string . to_snakecase ( ) ) ;
2022-02-16 22:30:43 +00:00
Attribute attribute {
2022-04-05 15:09:42 +00:00
inherit ,
2022-02-16 22:30:43 +00:00
readonly ,
move ( type ) ,
move ( name_as_string ) ,
move ( extended_attributes ) ,
move ( getter_callback_name ) ,
move ( setter_callback_name ) ,
} ;
interface . attributes . append ( move ( attribute ) ) ;
}
void Parser : : parse_constant ( Interface & interface )
{
lexer . consume_specific ( " const " ) ;
consume_whitespace ( ) ;
auto type = parse_type ( ) ;
consume_whitespace ( ) ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' = ' ; } ) ;
consume_whitespace ( ) ;
lexer . consume_specific ( ' = ' ) ;
consume_whitespace ( ) ;
auto value = lexer . consume_while ( [ ] ( auto ch ) { return ! is_ascii_space ( ch ) & & ch ! = ' ; ' ; } ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
Constant constant {
move ( type ) ,
move ( name ) ,
move ( value ) ,
} ;
interface . constants . append ( move ( constant ) ) ;
}
Vector < Parameter > Parser : : parse_parameters ( )
{
consume_whitespace ( ) ;
Vector < Parameter > parameters ;
for ( ; ; ) {
if ( lexer . next_is ( ' ) ' ) )
break ;
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
2022-02-16 22:30:43 +00:00
if ( lexer . consume_specific ( ' [ ' ) )
extended_attributes = parse_extended_attributes ( ) ;
bool optional = lexer . consume_specific ( " optional " ) ;
if ( optional )
consume_whitespace ( ) ;
2023-03-05 21:55:22 +00:00
if ( lexer . consume_specific ( ' [ ' ) ) {
// Not explicitly forbidden by the grammar but unlikely to happen in practice - if it does,
// we'll have to teach the parser how to merge two sets of extended attributes.
VERIFY ( extended_attributes . is_empty ( ) ) ;
extended_attributes = parse_extended_attributes ( ) ;
}
2022-02-16 22:30:43 +00:00
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 = = ' = ' ; } ) ;
Parameter parameter = { move ( type ) , move ( name ) , optional , { } , extended_attributes , variadic } ;
consume_whitespace ( ) ;
if ( variadic ) {
// Variadic parameters must be last and do not have default values.
parameters . append ( move ( parameter ) ) ;
break ;
}
if ( lexer . next_is ( ' ) ' ) ) {
parameters . append ( move ( parameter ) ) ;
break ;
}
if ( lexer . next_is ( ' = ' ) & & optional ) {
assert_specific ( ' = ' ) ;
consume_whitespace ( ) ;
auto default_value = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' , ' | | ch = = ' ) ' ; } ) ;
parameter . optional_default_value = default_value ;
}
parameters . append ( move ( parameter ) ) ;
if ( lexer . next_is ( ' ) ' ) )
break ;
assert_specific ( ' , ' ) ;
consume_whitespace ( ) ;
}
return parameters ;
}
2022-12-04 18:02:33 +00:00
Function Parser : : parse_function ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface , IsSpecialOperation is_special_operation )
2022-02-16 22:30:43 +00:00
{
bool static_ = false ;
if ( lexer . consume_specific ( " static " ) ) {
static_ = true ;
consume_whitespace ( ) ;
}
auto return_type = parse_type ( ) ;
consume_whitespace ( ) ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' ( ' ; } ) ;
consume_whitespace ( ) ;
assert_specific ( ' ( ' ) ;
auto parameters = parse_parameters ( ) ;
assert_specific ( ' ) ' ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
2022-03-05 18:51:17 +00:00
Function function { move ( return_type ) , name , move ( parameters ) , move ( extended_attributes ) , { } , false } ;
2022-02-16 22:30:43 +00:00
// "Defining a special operation with an identifier is equivalent to separating the special operation out into its own declaration without an identifier."
if ( is_special_operation = = IsSpecialOperation : : No | | ( is_special_operation = = IsSpecialOperation : : Yes & & ! name . is_empty ( ) ) ) {
if ( ! static_ )
interface . functions . append ( function ) ;
else
interface . static_functions . append ( function ) ;
}
return function ;
}
2023-03-23 07:48:44 +00:00
void Parser : : parse_constructor ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " constructor " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
assert_specific ( ' ( ' ) ;
auto parameters = parse_parameters ( ) ;
assert_specific ( ' ) ' ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
2023-03-23 07:48:44 +00:00
interface . constructors . append ( Constructor { interface . name , move ( parameters ) , move ( extended_attributes ) } ) ;
2022-02-16 22:30:43 +00:00
}
2022-12-04 18:02:33 +00:00
void Parser : : parse_stringifier ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " stringifier " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
interface . has_stringifier = true ;
2022-04-05 15:09:42 +00:00
if ( lexer . next_is ( " attribute " sv ) | | lexer . next_is ( " inherit " sv ) | | lexer . next_is ( " readonly " sv ) ) {
2022-02-16 22:30:43 +00:00
parse_attribute ( extended_attributes , interface ) ;
interface . stringifier_attribute = interface . attributes . last ( ) . name ;
} else {
assert_specific ( ' ; ' ) ;
}
}
void Parser : : parse_iterable ( Interface & interface )
{
2022-07-11 17:32:29 +00:00
assert_string ( " iterable " sv ) ;
2022-02-16 22:30:43 +00:00
assert_specific ( ' < ' ) ;
auto first_type = parse_type ( ) ;
if ( lexer . next_is ( ' , ' ) ) {
if ( interface . supports_indexed_properties ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " Interfaces with a pair iterator must not supported indexed properties. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
assert_specific ( ' , ' ) ;
consume_whitespace ( ) ;
auto second_type = parse_type ( ) ;
interface . pair_iterator_types = Tuple { move ( first_type ) , move ( second_type ) } ;
} else {
if ( ! interface . supports_indexed_properties ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " Interfaces with a value iterator must supported indexed properties. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
interface . value_iterator_type = move ( first_type ) ;
}
assert_specific ( ' > ' ) ;
assert_specific ( ' ; ' ) ;
}
2022-12-04 18:02:33 +00:00
void Parser : : parse_getter ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " getter " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
auto function = parse_function ( extended_attributes , interface , IsSpecialOperation : : Yes ) ;
if ( function . parameters . size ( ) ! = 1 )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Named/indexed property getters must have only 1 parameter, got {} parameters. " , function . parameters . size ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
auto & identifier = function . parameters . first ( ) ;
2022-08-24 16:22:09 +00:00
if ( identifier . type - > is_nullable ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " identifier's type must not be nullable. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
if ( identifier . optional )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " identifier must not be optional. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
// FIXME: Disallow variadic functions once they're supported.
2022-08-24 16:22:09 +00:00
if ( identifier . type - > name ( ) = = " DOMString " ) {
2022-02-16 22:30:43 +00:00
if ( interface . named_property_getter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " An interface can only have one named property getter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
interface . named_property_getter = move ( function ) ;
2022-08-24 16:22:09 +00:00
} else if ( identifier . type - > name ( ) = = " unsigned long " ) {
2022-02-16 22:30:43 +00:00
if ( interface . indexed_property_getter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " An interface can only have one indexed property getter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
interface . indexed_property_getter = move ( function ) ;
} else {
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'. " , identifier . type - > name ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
}
}
2022-12-04 18:02:33 +00:00
void Parser : : parse_setter ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " setter " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
auto function = parse_function ( extended_attributes , interface , IsSpecialOperation : : Yes ) ;
if ( function . parameters . size ( ) ! = 2 )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Named/indexed property setters must have only 2 parameters, got {} parameter(s). " , function . parameters . size ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
auto & identifier = function . parameters . first ( ) ;
2022-08-24 16:22:09 +00:00
if ( identifier . type - > is_nullable ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " identifier's type must not be nullable. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
if ( identifier . optional )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " identifier must not be optional. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
// FIXME: Disallow variadic functions once they're supported.
2022-08-24 16:22:09 +00:00
if ( identifier . type - > name ( ) = = " DOMString " ) {
2022-02-16 22:30:43 +00:00
if ( interface . named_property_setter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " An interface can only have one named property setter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
if ( ! interface . named_property_getter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " A named property setter must be accompanied by a named property getter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
interface . named_property_setter = move ( function ) ;
2022-08-24 16:22:09 +00:00
} else if ( identifier . type - > name ( ) = = " unsigned long " ) {
2022-02-16 22:30:43 +00:00
if ( interface . indexed_property_setter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " An interface can only have one indexed property setter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
if ( ! interface . indexed_property_getter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " An indexed property setter must be accompanied by an indexed property getter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
interface . indexed_property_setter = move ( function ) ;
} else {
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'. " , identifier . type - > name ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
}
}
2022-12-04 18:02:33 +00:00
void Parser : : parse_deleter ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " deleter " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
auto function = parse_function ( extended_attributes , interface , IsSpecialOperation : : Yes ) ;
if ( function . parameters . size ( ) ! = 1 )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Named property deleter must have only 1 parameter, got {} parameters. " , function . parameters . size ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
auto & identifier = function . parameters . first ( ) ;
2022-08-24 16:22:09 +00:00
if ( identifier . type - > is_nullable ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " identifier's type must not be nullable. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
if ( identifier . optional )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " identifier must not be optional. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
// FIXME: Disallow variadic functions once they're supported.
2022-08-24 16:22:09 +00:00
if ( identifier . type - > name ( ) = = " DOMString " ) {
2022-02-16 22:30:43 +00:00
if ( interface . named_property_deleter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " An interface can only have one named property deleter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
if ( ! interface . named_property_getter . has_value ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " A named property deleter must be accompanied by a named property getter. " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
interface . named_property_deleter = move ( function ) ;
} else {
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Named property deleter's identifier's type must be 'DOMString', got '{}'. " , identifier . type - > name ( ) ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
}
}
void Parser : : parse_interface ( Interface & interface )
{
consume_whitespace ( ) ;
interface . name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' : ' ) ) {
consume_whitespace ( ) ;
interface . parent_name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
}
assert_specific ( ' { ' ) ;
for ( ; ; ) {
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' } ' ) ) {
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
break ;
}
if ( lexer . consume_specific ( ' [ ' ) ) {
extended_attributes = parse_extended_attributes ( ) ;
if ( ! interface . has_unscopable_member & & extended_attributes . contains ( " Unscopable " ) )
interface . has_unscopable_member = true ;
}
if ( lexer . next_is ( " constructor " ) ) {
2023-03-23 07:48:44 +00:00
parse_constructor ( extended_attributes , interface ) ;
2022-02-16 22:30:43 +00:00
continue ;
}
if ( lexer . next_is ( " const " ) ) {
parse_constant ( interface ) ;
continue ;
}
if ( lexer . next_is ( " stringifier " ) ) {
parse_stringifier ( extended_attributes , interface ) ;
continue ;
}
if ( lexer . next_is ( " iterable " ) ) {
parse_iterable ( interface ) ;
continue ;
}
2022-04-05 15:09:42 +00:00
if ( lexer . next_is ( " inherit " ) | | lexer . next_is ( " readonly " ) | | lexer . next_is ( " attribute " ) ) {
2022-02-16 22:30:43 +00:00
parse_attribute ( extended_attributes , interface ) ;
continue ;
}
if ( lexer . next_is ( " getter " ) ) {
parse_getter ( extended_attributes , interface ) ;
continue ;
}
if ( lexer . next_is ( " setter " ) ) {
parse_setter ( extended_attributes , interface ) ;
continue ;
}
if ( lexer . next_is ( " deleter " ) ) {
parse_deleter ( extended_attributes , interface ) ;
continue ;
}
parse_function ( extended_attributes , interface ) ;
}
2023-03-15 18:40:51 +00:00
if ( auto legacy_namespace = interface . extended_attributes . get ( " LegacyNamespace " sv ) ; legacy_namespace . has_value ( ) )
interface . namespaced_name = DeprecatedString : : formatted ( " {}.{} " , * legacy_namespace , interface . name ) ;
else
interface . namespaced_name = interface . name ;
2022-12-04 18:02:33 +00:00
interface . constructor_class = DeprecatedString : : formatted ( " {}Constructor " , interface . name ) ;
interface . prototype_class = DeprecatedString : : formatted ( " {}Prototype " , interface . name ) ;
interface . prototype_base_class = DeprecatedString : : formatted ( " {}Prototype " , interface . parent_name . is_empty ( ) ? " Object " : interface . parent_name ) ;
2023-03-05 15:50:56 +00:00
interface . global_mixin_class = DeprecatedString : : formatted ( " {}GlobalMixin " , interface . name ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
}
2023-03-15 13:55:49 +00:00
void Parser : : parse_namespace ( Interface & interface )
{
consume_whitespace ( ) ;
interface . name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
interface . is_namespace = true ;
consume_whitespace ( ) ;
assert_specific ( ' { ' ) ;
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' } ' ) ) {
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
break ;
}
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
parse_function ( extended_attributes , interface ) ;
}
interface . namespace_class = DeprecatedString : : formatted ( " {}Namespace " , interface . name ) ;
consume_whitespace ( ) ;
}
2022-02-16 22:30:43 +00:00
void Parser : : parse_enumeration ( Interface & interface )
{
2022-07-11 17:32:29 +00:00
assert_string ( " enum " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
Enumeration enumeration { } ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
assert_specific ( ' { ' ) ;
bool first = true ;
for ( ; ! lexer . is_eof ( ) ; ) {
consume_whitespace ( ) ;
if ( lexer . next_is ( ' } ' ) )
break ;
if ( ! first ) {
assert_specific ( ' , ' ) ;
consume_whitespace ( ) ;
}
assert_specific ( ' " ' ) ;
auto string = lexer . consume_until ( ' " ' ) ;
assert_specific ( ' " ' ) ;
consume_whitespace ( ) ;
if ( enumeration . values . contains ( string ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Enumeration {} contains duplicate member '{}' " , name , string ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
else
enumeration . values . set ( string ) ;
if ( first )
enumeration . first_member = move ( string ) ;
first = false ;
}
consume_whitespace ( ) ;
assert_specific ( ' } ' ) ;
assert_specific ( ' ; ' ) ;
2022-12-04 18:02:33 +00:00
HashTable < DeprecatedString > names_already_seen ;
2022-02-16 22:30:43 +00:00
for ( auto & entry : enumeration . values )
enumeration . translated_cpp_names . set ( entry , convert_enumeration_value_to_cpp_enum_member ( entry , names_already_seen ) ) ;
interface . enumerations . set ( name , move ( enumeration ) ) ;
consume_whitespace ( ) ;
}
2022-03-30 20:32:44 +00:00
void Parser : : parse_typedef ( Interface & interface )
{
2022-07-11 17:32:29 +00:00
assert_string ( " typedef " sv ) ;
2022-03-30 20:32:44 +00:00
consume_whitespace ( ) ;
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
2022-03-30 20:32:44 +00:00
if ( lexer . consume_specific ( ' [ ' ) )
extended_attributes = parse_extended_attributes ( ) ;
auto type = parse_type ( ) ;
consume_whitespace ( ) ;
auto name = lexer . consume_until ( ' ; ' ) ;
assert_specific ( ' ; ' ) ;
interface . typedefs . set ( name , Typedef { move ( extended_attributes ) , move ( type ) } ) ;
consume_whitespace ( ) ;
}
2022-02-16 22:30:43 +00:00
void Parser : : parse_dictionary ( Interface & interface )
{
2022-07-11 17:32:29 +00:00
assert_string ( " dictionary " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
Dictionary dictionary { } ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' : ' ) ) {
consume_whitespace ( ) ;
dictionary . parent_name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
}
assert_specific ( ' { ' ) ;
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' } ' ) ) {
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
break ;
}
bool required = false ;
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
2022-02-16 22:30:43 +00:00
if ( lexer . consume_specific ( " required " ) ) {
required = true ;
consume_whitespace ( ) ;
}
2023-03-15 22:33:09 +00:00
if ( lexer . consume_specific ( ' [ ' ) )
extended_attributes = parse_extended_attributes ( ) ;
2022-02-16 22:30:43 +00:00
auto type = parse_type ( ) ;
consume_whitespace ( ) ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' ; ' ; } ) ;
consume_whitespace ( ) ;
Optional < StringView > default_value ;
if ( lexer . consume_specific ( ' = ' ) ) {
VERIFY ( ! required ) ;
consume_whitespace ( ) ;
default_value = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' ; ' ; } ) ;
consume_whitespace ( ) ;
}
assert_specific ( ' ; ' ) ;
DictionaryMember member {
required ,
move ( type ) ,
name ,
move ( extended_attributes ) ,
2022-12-04 18:02:33 +00:00
Optional < DeprecatedString > ( move ( default_value ) ) ,
2022-02-16 22:30:43 +00:00
} ;
dictionary . members . append ( move ( member ) ) ;
}
// dictionary members need to be evaluated in lexicographical order
quick_sort ( dictionary . members , [ & ] ( auto & one , auto & two ) {
return one . name < two . name ;
} ) ;
interface . dictionaries . set ( name , move ( dictionary ) ) ;
consume_whitespace ( ) ;
}
2022-02-16 23:45:57 +00:00
void Parser : : parse_interface_mixin ( Interface & interface )
{
2022-04-30 17:27:50 +00:00
auto mixin_interface_ptr = make < Interface > ( ) ;
auto & mixin_interface = * mixin_interface_ptr ;
2022-10-08 22:48:04 +00:00
VERIFY ( top_level_interfaces ( ) . set ( move ( mixin_interface_ptr ) ) = = AK : : HashSetResult : : InsertedNewEntry ) ;
2022-04-30 17:27:50 +00:00
mixin_interface . module_own_path = interface . module_own_path ;
mixin_interface . is_mixin = true ;
2022-02-16 23:45:57 +00:00
2022-07-11 17:32:29 +00:00
assert_string ( " interface " sv ) ;
2022-02-16 23:45:57 +00:00
consume_whitespace ( ) ;
2022-07-11 17:32:29 +00:00
assert_string ( " mixin " sv ) ;
2022-02-16 23:45:57 +00:00
auto offset = lexer . tell ( ) ;
2022-04-30 17:27:50 +00:00
parse_interface ( mixin_interface ) ;
if ( ! mixin_interface . parent_name . is_empty ( ) )
2022-07-11 17:32:29 +00:00
report_parsing_error ( " Mixin interfaces are not allowed to have inherited parents " sv , filename , input , offset ) ;
2022-02-16 23:45:57 +00:00
2022-04-30 17:27:50 +00:00
auto name = mixin_interface . name ;
interface . mixins . set ( move ( name ) , & mixin_interface ) ;
2022-02-16 23:45:57 +00:00
}
2022-12-04 18:02:33 +00:00
void Parser : : parse_callback_function ( HashMap < DeprecatedString , DeprecatedString > & extended_attributes , Interface & interface )
2022-03-30 20:35:13 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " callback " sv ) ;
2022-03-30 20:35:13 +00:00
consume_whitespace ( ) ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
assert_specific ( ' = ' ) ;
consume_whitespace ( ) ;
auto return_type = parse_type ( ) ;
consume_whitespace ( ) ;
assert_specific ( ' ( ' ) ;
auto parameters = parse_parameters ( ) ;
assert_specific ( ' ) ' ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
interface . callback_functions . set ( name , CallbackFunction { move ( return_type ) , move ( parameters ) , extended_attributes . contains ( " LegacyTreatNonObjectAsNull " ) } ) ;
consume_whitespace ( ) ;
}
2022-02-16 22:30:43 +00:00
void Parser : : parse_non_interface_entities ( bool allow_interface , Interface & interface )
{
2022-07-27 19:19:40 +00:00
consume_whitespace ( ) ;
2022-02-16 22:30:43 +00:00
while ( ! lexer . is_eof ( ) ) {
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , DeprecatedString > extended_attributes ;
2022-03-30 20:34:12 +00:00
if ( lexer . consume_specific ( ' [ ' ) )
extended_attributes = parse_extended_attributes ( ) ;
2022-02-16 22:30:43 +00:00
if ( lexer . next_is ( " dictionary " ) ) {
parse_dictionary ( interface ) ;
} else if ( lexer . next_is ( " enum " ) ) {
parse_enumeration ( interface ) ;
2022-03-30 20:32:44 +00:00
} else if ( lexer . next_is ( " typedef " ) ) {
parse_typedef ( interface ) ;
2022-02-16 23:45:57 +00:00
} else if ( lexer . next_is ( " interface mixin " ) ) {
parse_interface_mixin ( interface ) ;
2022-03-30 20:35:13 +00:00
} else if ( lexer . next_is ( " callback " ) ) {
parse_callback_function ( extended_attributes , interface ) ;
2023-03-15 13:55:49 +00:00
} else if ( ( allow_interface & & ! lexer . next_is ( " interface " ) & & ! lexer . next_is ( " namespace " ) ) | | ! allow_interface ) {
2022-02-16 23:45:57 +00:00
auto current_offset = lexer . tell ( ) ;
auto name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) ; } ) ;
consume_whitespace ( ) ;
if ( lexer . consume_specific ( " includes " ) ) {
consume_whitespace ( ) ;
auto mixin_name = lexer . consume_until ( [ ] ( auto ch ) { return is_ascii_space ( ch ) | | ch = = ' ; ' ; } ) ;
interface . included_mixins . ensure ( name ) . set ( mixin_name ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
consume_whitespace ( ) ;
} else {
2022-07-11 17:32:29 +00:00
report_parsing_error ( " expected 'enum' or 'dictionary' " sv , filename , input , current_offset ) ;
2022-02-16 23:45:57 +00:00
}
2022-02-16 22:30:43 +00:00
} else {
2022-03-30 20:34:12 +00:00
interface . extended_attributes = move ( extended_attributes ) ;
2022-02-16 22:30:43 +00:00
break ;
}
}
2022-07-27 19:19:40 +00:00
consume_whitespace ( ) ;
2022-02-16 22:30:43 +00:00
}
2022-11-10 19:19:53 +00:00
static void resolve_union_typedefs ( Interface & interface , UnionType & union_ ) ;
2023-02-20 17:56:08 +00:00
static void resolve_typedef ( Interface & interface , NonnullRefPtr < Type const > & type , HashMap < DeprecatedString , DeprecatedString > * extended_attributes = { } )
2022-03-30 20:32:44 +00:00
{
if ( is < ParameterizedType > ( * type ) ) {
2023-02-20 17:56:08 +00:00
auto & parameterized_type = const_cast < Type & > ( * type ) . as_parameterized ( ) ;
auto & parameters = static_cast < Vector < NonnullRefPtr < Type const > > & > ( parameterized_type . parameters ( ) ) ;
2022-03-30 20:32:44 +00:00
for ( auto & parameter : parameters )
resolve_typedef ( interface , parameter ) ;
return ;
}
2022-11-10 19:19:53 +00:00
// Resolve anonymous union types until we get named types that can be resolved in the next step.
if ( is < UnionType > ( * type ) & & type - > name ( ) . is_empty ( ) ) {
2023-02-20 17:56:08 +00:00
resolve_union_typedefs ( interface , const_cast < Type & > ( * type ) . as_union ( ) ) ;
2022-11-10 19:19:53 +00:00
return ;
}
2022-08-24 16:22:09 +00:00
auto it = interface . typedefs . find ( type - > name ( ) ) ;
2022-03-30 20:32:44 +00:00
if ( it = = interface . typedefs . end ( ) )
return ;
2022-08-24 16:22:09 +00:00
bool nullable = type - > is_nullable ( ) ;
2022-03-30 20:32:44 +00:00
type = it - > value . type ;
2023-02-20 17:56:08 +00:00
const_cast < Type & > ( * type ) . set_nullable ( nullable ) ;
2022-11-10 19:14:37 +00:00
if ( extended_attributes ) {
for ( auto & attribute : it - > value . extended_attributes )
extended_attributes - > set ( attribute . key , attribute . value ) ;
}
2022-10-20 22:42:27 +00:00
// Recursively resolve typedefs in unions after we resolved the type itself - e.g. for this:
// typedef (A or B) Union1;
// typedef (C or D) Union2;
// typedef (Union1 or Union2) NestedUnion;
// We run:
// - resolve_typedef(NestedUnion) -> NestedUnion gets replaced by UnionType(Union1, Union2)
// - resolve_typedef(Union1) -> Union1 gets replaced by UnionType(A, B)
// - resolve_typedef(Union2) -> Union2 gets replaced by UnionType(C, D)
// So whatever referenced NestedUnion ends up with the following resolved union:
// UnionType(UnionType(A, B), UnionType(C, D))
// Note that flattening unions is handled separately as per the spec.
2022-11-10 19:19:53 +00:00
if ( is < UnionType > ( * type ) )
2023-02-20 17:56:08 +00:00
resolve_union_typedefs ( interface , const_cast < Type & > ( * type ) . as_union ( ) ) ;
2022-03-30 20:32:44 +00:00
}
2022-11-10 19:19:53 +00:00
static void resolve_union_typedefs ( Interface & interface , UnionType & union_ )
{
2023-02-20 17:56:08 +00:00
auto & member_types = static_cast < Vector < NonnullRefPtr < Type const > > & > ( union_ . member_types ( ) ) ;
2022-11-10 19:19:53 +00:00
for ( auto & member_type : member_types )
resolve_typedef ( interface , member_type ) ;
}
2022-08-22 13:50:06 +00:00
static void resolve_parameters_typedefs ( Interface & interface , Vector < Parameter > & parameters )
2022-03-30 20:32:44 +00:00
{
for ( auto & parameter : parameters )
resolve_typedef ( interface , parameter . type , & parameter . extended_attributes ) ;
}
2022-11-10 19:19:53 +00:00
2022-03-30 20:32:44 +00:00
template < typename FunctionType >
void resolve_function_typedefs ( Interface & interface , FunctionType & function )
{
resolve_typedef ( interface , function . return_type ) ;
resolve_parameters_typedefs ( interface , function . parameters ) ;
}
2022-04-30 17:27:50 +00:00
Interface & Parser : : parse ( )
2022-02-16 22:30:43 +00:00
{
2023-03-24 09:57:53 +00:00
auto this_module_or_error = FileSystem : : real_path ( filename ) ;
if ( this_module_or_error . is_error ( ) ) {
report_parsing_error ( DeprecatedString : : formatted ( " Failed to resolve path '{}': {} " , filename , this_module_or_error . error ( ) ) , filename , input , 0 ) ;
VERIFY_NOT_REACHED ( ) ;
}
auto this_module = this_module_or_error . release_value ( ) . to_deprecated_string ( ) ;
2022-02-16 22:30:43 +00:00
2022-04-30 17:27:50 +00:00
auto interface_ptr = make < Interface > ( ) ;
auto & interface = * interface_ptr ;
2022-10-08 22:48:04 +00:00
VERIFY ( top_level_interfaces ( ) . set ( move ( interface_ptr ) ) = = AK : : HashSetResult : : InsertedNewEntry ) ;
2022-04-30 17:27:50 +00:00
interface . module_own_path = this_module ;
2022-10-08 22:48:04 +00:00
top_level_resolved_imports ( ) . set ( this_module , & interface ) ;
2022-02-16 22:30:43 +00:00
2022-04-30 17:27:50 +00:00
Vector < Interface & > imports ;
2022-12-04 18:02:33 +00:00
HashTable < DeprecatedString > required_imported_paths ;
2022-02-16 22:30:43 +00:00
while ( lexer . consume_specific ( " #import " ) ) {
consume_whitespace ( ) ;
assert_specific ( ' < ' ) ;
auto path = lexer . consume_until ( ' > ' ) ;
lexer . ignore ( ) ;
auto maybe_interface = resolve_import ( path ) ;
if ( maybe_interface . has_value ( ) ) {
2022-04-30 17:27:50 +00:00
for ( auto & entry : maybe_interface . value ( ) . required_imported_paths )
2022-03-30 20:30:12 +00:00
required_imported_paths . set ( entry ) ;
2022-02-16 22:30:43 +00:00
imports . append ( maybe_interface . release_value ( ) ) ;
}
consume_whitespace ( ) ;
}
2022-04-30 17:27:50 +00:00
interface . required_imported_paths = required_imported_paths ;
2022-02-16 22:30:43 +00:00
2022-04-30 17:27:50 +00:00
parse_non_interface_entities ( true , interface ) ;
2022-02-16 22:30:43 +00:00
if ( lexer . consume_specific ( " interface " ) )
2022-04-30 17:27:50 +00:00
parse_interface ( interface ) ;
2023-03-15 13:55:49 +00:00
else if ( lexer . consume_specific ( " namespace " ) )
parse_namespace ( interface ) ;
2022-02-16 22:30:43 +00:00
2022-04-30 17:27:50 +00:00
parse_non_interface_entities ( false , interface ) ;
2022-02-16 22:30:43 +00:00
for ( auto & import : imports ) {
// FIXME: Instead of copying every imported entity into the current interface, query imports directly
for ( auto & dictionary : import . dictionaries )
2022-04-30 17:27:50 +00:00
interface . dictionaries . set ( dictionary . key , dictionary . value ) ;
2022-02-16 22:30:43 +00:00
for ( auto & enumeration : import . enumerations ) {
auto enumeration_copy = enumeration . value ;
enumeration_copy . is_original_definition = false ;
2022-04-30 17:27:50 +00:00
interface . enumerations . set ( enumeration . key , move ( enumeration_copy ) ) ;
2022-02-16 22:30:43 +00:00
}
2022-02-16 23:45:57 +00:00
2022-03-30 20:32:44 +00:00
for ( auto & typedef_ : import . typedefs )
2022-04-30 17:27:50 +00:00
interface . typedefs . set ( typedef_ . key , typedef_ . value ) ;
2022-03-30 20:32:44 +00:00
2022-02-16 23:45:57 +00:00
for ( auto & mixin : import . mixins ) {
2022-04-30 17:27:50 +00:00
if ( auto it = interface . mixins . find ( mixin . key ) ; it ! = interface . mixins . end ( ) & & it - > value ! = mixin . value )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Mixin '{}' was already defined in {} " , mixin . key , mixin . value - > module_own_path ) , filename , input , lexer . tell ( ) ) ;
2022-04-30 17:27:50 +00:00
interface . mixins . set ( mixin . key , mixin . value ) ;
2022-02-16 23:45:57 +00:00
}
2022-03-30 20:35:13 +00:00
for ( auto & callback_function : import . callback_functions )
2022-04-30 17:27:50 +00:00
interface . callback_functions . set ( callback_function . key , callback_function . value ) ;
2022-02-16 22:30:43 +00:00
}
2022-02-16 23:45:57 +00:00
// Resolve mixins
2022-04-30 17:27:50 +00:00
if ( auto it = interface . included_mixins . find ( interface . name ) ; it ! = interface . included_mixins . end ( ) ) {
2022-02-16 23:45:57 +00:00
for ( auto & entry : it - > value ) {
2022-04-30 17:27:50 +00:00
auto mixin_it = interface . mixins . find ( entry ) ;
if ( mixin_it = = interface . mixins . end ( ) )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Mixin '{}' was never defined " , entry ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 23:45:57 +00:00
auto & mixin = mixin_it - > value ;
2022-04-30 17:27:50 +00:00
interface . attributes . extend ( mixin - > attributes ) ;
interface . constants . extend ( mixin - > constants ) ;
interface . functions . extend ( mixin - > functions ) ;
interface . static_functions . extend ( mixin - > static_functions ) ;
if ( interface . has_stringifier & & mixin - > has_stringifier )
2022-12-04 18:02:33 +00:00
report_parsing_error ( DeprecatedString : : formatted ( " Both interface '{}' and mixin '{}' have defined stringifier attributes " , interface . name , mixin - > name ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 23:45:57 +00:00
if ( mixin - > has_stringifier ) {
2022-04-30 17:27:50 +00:00
interface . stringifier_attribute = mixin - > stringifier_attribute ;
interface . has_stringifier = true ;
2022-02-16 23:45:57 +00:00
}
2022-07-30 10:28:29 +00:00
if ( mixin - > has_unscopable_member )
interface . has_unscopable_member = true ;
2022-02-16 23:45:57 +00:00
}
}
2022-03-30 20:32:44 +00:00
// Resolve typedefs
2022-04-30 17:27:50 +00:00
for ( auto & attribute : interface . attributes )
resolve_typedef ( interface , attribute . type , & attribute . extended_attributes ) ;
for ( auto & constant : interface . constants )
resolve_typedef ( interface , constant . type ) ;
for ( auto & constructor : interface . constructors )
resolve_parameters_typedefs ( interface , constructor . parameters ) ;
for ( auto & function : interface . functions )
resolve_function_typedefs ( interface , function ) ;
for ( auto & static_function : interface . static_functions )
resolve_function_typedefs ( interface , static_function ) ;
if ( interface . value_iterator_type . has_value ( ) )
resolve_typedef ( interface , * interface . value_iterator_type ) ;
if ( interface . pair_iterator_types . has_value ( ) ) {
resolve_typedef ( interface , interface . pair_iterator_types - > get < 0 > ( ) ) ;
resolve_typedef ( interface , interface . pair_iterator_types - > get < 1 > ( ) ) ;
2022-03-30 20:32:44 +00:00
}
2022-04-30 17:27:50 +00:00
if ( interface . named_property_getter . has_value ( ) )
resolve_function_typedefs ( interface , * interface . named_property_getter ) ;
if ( interface . named_property_setter . has_value ( ) )
resolve_function_typedefs ( interface , * interface . named_property_setter ) ;
if ( interface . indexed_property_getter . has_value ( ) )
resolve_function_typedefs ( interface , * interface . indexed_property_getter ) ;
if ( interface . indexed_property_setter . has_value ( ) )
resolve_function_typedefs ( interface , * interface . indexed_property_setter ) ;
if ( interface . named_property_deleter . has_value ( ) )
resolve_function_typedefs ( interface , * interface . named_property_deleter ) ;
if ( interface . named_property_getter . has_value ( ) )
resolve_function_typedefs ( interface , * interface . named_property_getter ) ;
for ( auto & dictionary : interface . dictionaries ) {
2022-03-30 20:32:44 +00:00
for ( auto & dictionary_member : dictionary . value . members )
2022-04-30 17:27:50 +00:00
resolve_typedef ( interface , dictionary_member . type , & dictionary_member . extended_attributes ) ;
2022-03-30 20:32:44 +00:00
}
2022-04-30 17:27:50 +00:00
for ( auto & callback_function : interface . callback_functions )
resolve_function_typedefs ( interface , callback_function . value ) ;
2022-03-30 20:32:44 +00:00
2022-03-05 18:51:17 +00:00
// Create overload sets
2022-04-30 17:27:50 +00:00
for ( auto & function : interface . functions ) {
auto & overload_set = interface . overload_sets . ensure ( function . name ) ;
2022-03-05 18:51:17 +00:00
function . overload_index = overload_set . size ( ) ;
overload_set . append ( function ) ;
}
2022-04-30 17:27:50 +00:00
for ( auto & overload_set : interface . overload_sets ) {
2022-03-05 18:51:17 +00:00
if ( overload_set . value . size ( ) = = 1 )
continue ;
for ( auto & overloaded_function : overload_set . value )
overloaded_function . is_overloaded = true ;
}
2022-04-30 17:27:50 +00:00
for ( auto & function : interface . static_functions ) {
auto & overload_set = interface . static_overload_sets . ensure ( function . name ) ;
2022-03-05 18:51:17 +00:00
function . overload_index = overload_set . size ( ) ;
overload_set . append ( function ) ;
}
2022-04-30 17:27:50 +00:00
for ( auto & overload_set : interface . static_overload_sets ) {
2022-03-05 18:51:17 +00:00
if ( overload_set . value . size ( ) = = 1 )
continue ;
for ( auto & overloaded_function : overload_set . value )
overloaded_function . is_overloaded = true ;
}
// FIXME: Add support for overloading constructors
2022-04-30 17:27:50 +00:00
if ( interface . will_generate_code ( ) )
interface . required_imported_paths . set ( this_module ) ;
interface . imported_modules = move ( imports ) ;
2022-02-16 22:30:43 +00:00
2022-10-08 22:48:04 +00:00
if ( top_level_parser ( ) = = this )
VERIFY ( import_stack . is_empty ( ) ) ;
2022-02-16 22:30:43 +00:00
return interface ;
}
2022-12-04 18:02:33 +00:00
Parser : : Parser ( DeprecatedString filename , StringView contents , DeprecatedString import_base_path )
2022-02-16 22:30:43 +00:00
: import_base_path ( move ( import_base_path ) )
, filename ( move ( filename ) )
, input ( contents )
, lexer ( input )
{
}
2022-12-04 18:02:33 +00:00
Parser : : Parser ( Parser * parent , DeprecatedString filename , StringView contents , DeprecatedString import_base_path )
2022-10-08 22:48:04 +00:00
: import_base_path ( move ( import_base_path ) )
, filename ( move ( filename ) )
, input ( contents )
, lexer ( input )
, parent ( parent )
{
}
Parser * Parser : : top_level_parser ( )
{
Parser * current = this ;
for ( Parser * next = this ; next ; next = next - > parent )
current = next ;
return current ;
}
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , Interface * > & Parser : : top_level_resolved_imports ( )
2022-10-08 22:48:04 +00:00
{
return top_level_parser ( ) - > resolved_imports ;
}
HashTable < NonnullOwnPtr < Interface > > & Parser : : top_level_interfaces ( )
{
return top_level_parser ( ) - > interfaces ;
}
2022-11-05 10:37:33 +00:00
Vector < DeprecatedString > Parser : : imported_files ( ) const
{
return const_cast < Parser * > ( this ) - > top_level_resolved_imports ( ) . keys ( ) ;
}
2022-02-16 22:30:43 +00:00
}