2022-02-16 22:30:43 +00:00
/*
2024-10-04 11:19:50 +00:00
* Copyright ( c ) 2020 - 2023 , Andreas Kling < andreas @ ladybird . 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 >
2024-11-01 10:14:31 +00:00
* Copyright ( c ) 2024 , Jelle Raaijmakers < jelle @ ladybird . org >
2022-02-16 22:30:43 +00:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "IDLParser.h"
2022-10-08 22:48:04 +00:00
# include <AK/Assertions.h>
2024-03-10 22:07:54 +00:00
# include <AK/Function.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 ) ;
}
2023-12-16 14:19:34 +00:00
static ByteString convert_enumeration_value_to_cpp_enum_member ( ByteString const & value , HashTable < ByteString > & 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-12-16 14:19:34 +00:00
return builder . to_byte_string ( ) ;
2022-02-16 22:30:43 +00:00
}
namespace IDL {
void Parser : : assert_specific ( char ch )
{
if ( ! lexer . consume_specific ( ch ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 ;
2023-10-10 10:42:20 +00:00
if ( lexer . consume_specific ( " // " sv ) ) {
2022-02-16 22:30:43 +00:00
lexer . consume_until ( ' \n ' ) ;
lexer . ignore ( ) ;
consumed = true ;
}
}
}
void Parser : : assert_string ( StringView expected )
{
if ( ! lexer . consume_specific ( expected ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : formatted ( " expected '{}' " , expected ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
}
2024-03-10 22:07:54 +00:00
ByteString Parser : : parse_identifier_until ( AK : : Function < bool ( char ) > 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 ( ) ;
}
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > Parser : : parse_extended_attributes ( )
2022-02-16 22:30:43 +00:00
{
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > extended_attributes ;
2022-02-16 22:30:43 +00:00
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' ] ' ) )
break ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with ( ' ] ' , ' = ' , ' , ' ) ;
2022-02-16 22:30:43 +00:00
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 ;
}
2023-12-16 14:19:34 +00:00
static HashTable < ByteString > 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
{
2024-11-14 16:13:44 +00:00
ByteString include_path ;
for ( auto import_base_path : import_base_paths ) {
auto maybe_include_path = LexicalPath : : join ( import_base_path , path ) . string ( ) ;
if ( ! FileSystem : : exists ( maybe_include_path ) )
continue ;
include_path = maybe_include_path ;
break ;
}
if ( include_path . is_empty ( ) ) {
StringBuilder error_message ;
error_message . appendff ( " Failed to find {} in the following directories: \n " , path ) ;
error_message . join ( ' \n ' , import_base_paths ) ;
report_parsing_error ( error_message . to_byte_string ( ) , 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 ( ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : formatted ( " Failed to resolve path {}: {} " , include_path , real_path_error_or . error ( ) ) , filename , input , lexer . tell ( ) ) ;
2024-01-15 16:23:24 +00:00
auto real_path = real_path_error_or . release_value ( ) ;
2023-03-24 09:57:53 +00:00
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 ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 ( ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 ( ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : formatted ( " Failed to read {}: {} " , real_path , data_or_error . error ( ) ) , filename , input , lexer . tell ( ) ) ;
2024-11-14 16:13:44 +00:00
auto & result = Parser ( this , real_path , data_or_error . value ( ) , import_base_paths ) . 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 ( ) ;
2023-10-10 10:42:20 +00:00
while ( lexer . consume_specific ( " or " sv ) ) {
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
union_member_types . append ( parse_type ( ) ) ;
consume_whitespace ( ) ;
}
assert_specific ( ' ) ' ) ;
bool nullable = lexer . consume_specific ( ' ? ' ) ;
2023-11-11 01:17:02 +00:00
auto type = adopt_ref ( * new UnionType ( " " , nullable , move ( union_member_types ) ) ) ;
2022-02-16 22:30:43 +00:00
2023-11-11 01:17:02 +00:00
if ( nullable ) {
if ( type - > number_of_nullable_member_types ( ) > 0 )
report_parsing_error ( " nullable union type cannot contain another nullable type " sv , filename , input , lexer . tell ( ) ) ;
// FIXME: A nullable union type cannot include a dictionary type as one of its flattened member types.
}
return type ;
2022-02-16 22:30:43 +00:00
}
2023-10-10 10:42:20 +00:00
bool unsigned_ = lexer . consume_specific ( " unsigned " sv ) ;
2022-02-16 22:30:43 +00:00
if ( unsigned_ )
consume_whitespace ( ) ;
2024-05-27 15:04:58 +00:00
bool unrestricted = lexer . consume_specific ( " unrestricted " sv ) ;
if ( unrestricted )
2022-08-11 14:48:40 +00:00
consume_whitespace ( ) ;
2024-05-27 15:04:58 +00:00
VERIFY ( ! ( unsigned_ & & unrestricted ) ) ;
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 ) ;
2024-05-27 15:04:58 +00:00
if ( unrestricted )
builder . append ( " unrestricted " sv ) ;
2022-02-16 22:30:43 +00:00
builder . append ( name ) ;
2023-11-11 01:17:02 +00:00
if ( nullable ) {
// https://webidl.spec.whatwg.org/#dfn-nullable-type
// The inner type must not be:
// - any,
if ( name = = " any " sv )
report_parsing_error ( " 'any' cannot be nullable " sv , filename , input , lexer . tell ( ) ) ;
// - a promise type,
if ( name = = " Promise " sv )
report_parsing_error ( " 'Promise' cannot be nullable " sv , filename , input , lexer . tell ( ) ) ;
// - an observable array type,
if ( name = = " ObservableArray " )
report_parsing_error ( " 'ObservableArray' cannot be nullable " sv , filename , input , lexer . tell ( ) ) ;
// - another nullable type, or
// - a union type that itself includes a nullable type or has a dictionary type as one of its flattened
// member types
// Note: This case is handled above
}
2022-02-16 22:30:43 +00:00
if ( is_parameterized_type )
2023-12-16 14:19:34 +00:00
return adopt_ref ( * new ParameterizedType ( builder . to_byte_string ( ) , nullable , move ( parameters ) ) ) ;
2022-02-16 22:30:43 +00:00
2023-12-16 14:19:34 +00:00
return adopt_ref ( * new Type ( builder . to_byte_string ( ) , nullable ) ) ;
2022-02-16 22:30:43 +00:00
}
2024-04-01 13:03:41 +00:00
void Parser : : parse_attribute ( HashMap < ByteString , ByteString > & extended_attributes , Interface & interface , IsStatic is_static )
2022-02-16 22:30:43 +00:00
{
2023-10-10 10:42:20 +00:00
bool inherit = lexer . consume_specific ( " inherit " sv ) ;
2022-04-05 15:09:42 +00:00
if ( inherit )
consume_whitespace ( ) ;
2023-10-10 10:42:20 +00:00
bool readonly = lexer . consume_specific ( " readonly " sv ) ;
2022-02-16 22:30:43 +00:00
if ( readonly )
consume_whitespace ( ) ;
2024-05-22 02:17:16 +00:00
// FIXME: Should we parse 'readonly setlike<T>' differently than this?
2023-10-10 10:42:20 +00:00
if ( lexer . consume_specific ( " attribute " sv ) )
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
2024-05-22 02:17:16 +00:00
else if ( lexer . consume_specific ( " setlike " sv ) & & ! inherit )
parse_setlike ( interface , readonly ) ;
2023-11-11 01:50:29 +00:00
else
report_parsing_error ( " expected 'attribute' " sv , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
auto type = parse_type ( ) ;
consume_whitespace ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space_or ( ' ; ' ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
2024-11-14 16:17:41 +00:00
ByteString attribute_callback_name ;
auto custom_callback_name = extended_attributes . find ( " AttributeCallbackName " ) ;
if ( custom_callback_name ! = extended_attributes . end ( ) ) {
attribute_callback_name = custom_callback_name - > value ;
} else {
attribute_callback_name = name . to_snakecase ( ) . replace ( " - " sv , " _ " sv , ReplaceMode : : All ) ;
}
auto getter_callback_name = ByteString : : formatted ( " {}_getter " , attribute_callback_name ) ;
auto setter_callback_name = ByteString : : formatted ( " {}_setter " , attribute_callback_name ) ;
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 ) ,
2024-03-10 22:07:54 +00:00
move ( name ) ,
2022-02-16 22:30:43 +00:00
move ( extended_attributes ) ,
move ( getter_callback_name ) ,
move ( setter_callback_name ) ,
} ;
2024-04-01 13:03:41 +00:00
if ( is_static = = IsStatic : : No )
interface . attributes . append ( move ( attribute ) ) ;
else
interface . static_attributes . append ( move ( attribute ) ) ;
2022-02-16 22:30:43 +00:00
}
void Parser : : parse_constant ( Interface & interface )
{
2023-10-10 10:42:20 +00:00
lexer . consume_specific ( " const " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
auto type = parse_type ( ) ;
consume_whitespace ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space_or ( ' = ' ) ;
2022-02-16 22:30:43 +00:00
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 ;
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > extended_attributes ;
2022-02-16 22:30:43 +00:00
if ( lexer . consume_specific ( ' [ ' ) )
extended_attributes = parse_extended_attributes ( ) ;
2023-10-10 10:42:20 +00:00
bool optional = lexer . consume_specific ( " optional " sv ) ;
2022-02-16 22:30:43 +00:00
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 ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space_or ( ' , ' , ' ) ' , ' = ' ) ;
2023-05-13 19:09:12 +00:00
Parameter parameter = { move ( type ) , move ( name ) , optional , { } , move ( extended_attributes ) , variadic } ;
2022-02-16 22:30:43 +00:00
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 ;
}
2024-04-01 13:03:41 +00:00
Function Parser : : parse_function ( HashMap < ByteString , ByteString > & extended_attributes , Interface & interface , IsStatic is_static , IsSpecialOperation is_special_operation )
2022-02-16 22:30:43 +00:00
{
2024-02-16 01:27:03 +00:00
auto position = lexer . current_position ( ) ;
2022-02-16 22:30:43 +00:00
auto return_type = parse_type ( ) ;
consume_whitespace ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space_or ( ' ( ' ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
assert_specific ( ' ( ' ) ;
auto parameters = parse_parameters ( ) ;
assert_specific ( ' ) ' ) ;
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
2024-02-16 01:27:03 +00:00
Function function { move ( return_type ) , name , move ( parameters ) , move ( extended_attributes ) , position , { } , 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 ( ) ) ) {
2024-04-01 13:03:41 +00:00
if ( is_static = = IsStatic : : No )
2022-02-16 22:30:43 +00:00
interface . functions . append ( function ) ;
else
interface . static_functions . append ( function ) ;
}
return function ;
}
2023-12-16 14:19:34 +00:00
void Parser : : parse_constructor ( HashMap < ByteString , ByteString > & 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
}
2023-12-16 14:19:34 +00:00
void Parser : : parse_stringifier ( HashMap < ByteString , ByteString > & 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 ) ;
}
2024-05-22 02:17:16 +00:00
if ( interface . set_entry_type . has_value ( ) )
report_parsing_error ( " Interfaces with an iterable declaration must not have a setlike declaration. " sv , filename , input , lexer . tell ( ) ) ;
assert_specific ( ' > ' ) ;
assert_specific ( ' ; ' ) ;
}
void Parser : : parse_setlike ( Interface & interface , bool is_readonly )
{
if ( interface . supports_indexed_properties ( ) )
report_parsing_error ( " Interfaces with a setlike declaration must not supported indexed properties. " sv , filename , input , lexer . tell ( ) ) ;
if ( interface . value_iterator_type . has_value ( ) | | interface . pair_iterator_types . has_value ( ) )
report_parsing_error ( " Interfaces with a setlike declaration must not must not be iterable. " sv , filename , input , lexer . tell ( ) ) ;
assert_string ( " setlike " sv ) ;
assert_specific ( ' < ' ) ;
interface . set_entry_type = parse_type ( ) ;
interface . is_set_readonly = is_readonly ;
2022-02-16 22:30:43 +00:00
assert_specific ( ' > ' ) ;
assert_specific ( ' ; ' ) ;
}
2023-12-16 14:19:34 +00:00
void Parser : : parse_getter ( HashMap < ByteString , ByteString > & 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 ( ) ;
2024-04-01 13:03:41 +00:00
auto function = parse_function ( extended_attributes , interface , IsStatic : : No , IsSpecialOperation : : Yes ) ;
2022-02-16 22:30:43 +00:00
if ( function . parameters . size ( ) ! = 1 )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 {
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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
}
}
2023-12-16 14:19:34 +00:00
void Parser : : parse_setter ( HashMap < ByteString , ByteString > & 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 ( ) ;
2024-04-01 13:03:41 +00:00
auto function = parse_function ( extended_attributes , interface , IsStatic : : No , IsSpecialOperation : : Yes ) ;
2022-02-16 22:30:43 +00:00
if ( function . parameters . size ( ) ! = 2 )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 {
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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
}
}
2023-12-16 14:19:34 +00:00
void Parser : : parse_deleter ( HashMap < ByteString , ByteString > & 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 ( ) ;
2024-04-01 13:03:41 +00:00
auto function = parse_function ( extended_attributes , interface , IsStatic : : No , IsSpecialOperation : : Yes ) ;
2022-02-16 22:30:43 +00:00
if ( function . parameters . size ( ) ! = 1 )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 {
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 ( ) ;
2024-03-10 22:07:54 +00:00
interface . name = parse_identifier_ending_with_space ( ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' : ' ) ) {
consume_whitespace ( ) ;
2024-03-10 22:07:54 +00:00
interface . parent_name = parse_identifier_ending_with_space ( ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
}
assert_specific ( ' { ' ) ;
for ( ; ; ) {
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > 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 ;
}
2024-05-22 02:17:16 +00:00
if ( lexer . next_is ( " setlike " ) ) {
bool is_readonly = false ;
parse_setlike ( interface , is_readonly ) ;
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 ;
}
2024-04-01 13:03:41 +00:00
bool is_static = lexer . consume_specific ( " static " ) ;
if ( ! is_static ) {
parse_function ( extended_attributes , interface , IsStatic : : No ) ;
} else {
consume_whitespace ( ) ;
if ( lexer . next_is ( " readonly " ) | | lexer . next_is ( " attribute " ) ) {
parse_attribute ( extended_attributes , interface , IsStatic : : Yes ) ;
} else {
parse_function ( extended_attributes , interface , IsStatic : : Yes ) ;
}
}
2022-02-16 22:30:43 +00:00
}
2023-03-15 18:40:51 +00:00
if ( auto legacy_namespace = interface . extended_attributes . get ( " LegacyNamespace " sv ) ; legacy_namespace . has_value ( ) )
2023-12-16 14:19:34 +00:00
interface . namespaced_name = ByteString : : formatted ( " {}.{} " , * legacy_namespace , interface . name ) ;
2023-03-15 18:40:51 +00:00
else
interface . namespaced_name = interface . name ;
2024-02-11 06:48:29 +00:00
if ( auto maybe_implemented_as = interface . extended_attributes . get ( " ImplementedAs " ) ; maybe_implemented_as . has_value ( ) )
interface . implemented_name = maybe_implemented_as . release_value ( ) ;
else
interface . implemented_name = interface . name ;
interface . constructor_class = ByteString : : formatted ( " {}Constructor " , interface . implemented_name ) ;
interface . prototype_class = ByteString : : formatted ( " {}Prototype " , interface . implemented_name ) ;
2023-12-16 14:19:34 +00:00
interface . prototype_base_class = ByteString : : formatted ( " {}Prototype " , interface . parent_name . is_empty ( ) ? " Object " : interface . parent_name ) ;
interface . global_mixin_class = ByteString : : 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 ( ) ;
2024-03-10 22:07:54 +00:00
interface . name = parse_identifier_ending_with_space ( ) ;
2023-03-15 13:55:49 +00:00
interface . is_namespace = true ;
consume_whitespace ( ) ;
assert_specific ( ' { ' ) ;
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' } ' ) ) {
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
break ;
}
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > extended_attributes ;
2023-03-15 13:55:49 +00:00
parse_function ( extended_attributes , interface ) ;
}
2023-12-16 14:19:34 +00:00
interface . namespace_class = ByteString : : formatted ( " {}Namespace " , interface . name ) ;
2023-03-15 13:55:49 +00:00
consume_whitespace ( ) ;
}
2024-11-01 10:14:31 +00:00
// https://webidl.spec.whatwg.org/#prod-Enum
2023-12-16 14:19:34 +00:00
void Parser : : parse_enumeration ( HashMap < ByteString , ByteString > extended_attributes , Interface & interface )
2022-02-16 22:30:43 +00:00
{
2022-07-11 17:32:29 +00:00
assert_string ( " enum " sv ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
Enumeration enumeration { } ;
2023-11-05 00:44:12 +00:00
enumeration . extended_attributes = move ( extended_attributes ) ;
2022-02-16 22:30:43 +00:00
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space ( ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
assert_specific ( ' { ' ) ;
for ( ; ! lexer . is_eof ( ) ; ) {
consume_whitespace ( ) ;
if ( lexer . next_is ( ' } ' ) )
break ;
assert_specific ( ' " ' ) ;
auto string = lexer . consume_until ( ' " ' ) ;
assert_specific ( ' " ' ) ;
consume_whitespace ( ) ;
if ( enumeration . values . contains ( string ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : formatted ( " Enumeration {} contains duplicate member '{}' " , name , string ) , filename , input , lexer . tell ( ) ) ;
2022-02-16 22:30:43 +00:00
else
enumeration . values . set ( string ) ;
2024-11-01 10:14:31 +00:00
if ( enumeration . first_member . is_empty ( ) )
2022-02-16 22:30:43 +00:00
enumeration . first_member = move ( string ) ;
2024-11-01 10:14:31 +00:00
if ( ! lexer . next_is ( ' } ' ) )
assert_specific ( ' , ' ) ;
2022-02-16 22:30:43 +00:00
}
consume_whitespace ( ) ;
assert_specific ( ' } ' ) ;
assert_specific ( ' ; ' ) ;
2023-12-16 14:19:34 +00:00
HashTable < ByteString > 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 ( ) ;
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > 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 ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with ( ' ; ' ) ;
2022-03-30 20:32:44 +00:00
assert_specific ( ' ; ' ) ;
2024-03-10 22:07:54 +00:00
interface . typedefs . set ( move ( name ) , Typedef { move ( extended_attributes ) , move ( type ) } ) ;
2022-03-30 20:32:44 +00:00
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 { } ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space ( ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' : ' ) ) {
consume_whitespace ( ) ;
2024-03-10 22:07:54 +00:00
dictionary . parent_name = parse_identifier_ending_with_space ( ) ;
2022-02-16 22:30:43 +00:00
consume_whitespace ( ) ;
}
assert_specific ( ' { ' ) ;
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . consume_specific ( ' } ' ) ) {
consume_whitespace ( ) ;
assert_specific ( ' ; ' ) ;
break ;
}
bool required = false ;
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > extended_attributes ;
2022-02-16 22:30:43 +00:00
2023-10-10 10:42:20 +00:00
if ( lexer . consume_specific ( " required " sv ) ) {
2022-02-16 22:30:43 +00:00
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 ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space_or ( ' ; ' ) ;
2022-02-16 22:30:43 +00:00
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 ) ,
2024-03-10 22:07:54 +00:00
move ( name ) ,
2022-02-16 22:30:43 +00:00
move ( extended_attributes ) ,
2023-12-16 14:19:34 +00:00
Optional < ByteString > ( 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
}
2023-12-16 14:19:34 +00:00
void Parser : : parse_callback_function ( HashMap < ByteString , ByteString > & 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 ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space ( ) ;
2022-03-30 20:35:13 +00:00
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 ( ' ; ' ) ;
2024-03-10 22:07:54 +00:00
interface . callback_functions . set ( move ( name ) , CallbackFunction { move ( return_type ) , move ( parameters ) , extended_attributes . contains ( " LegacyTreatNonObjectAsNull " ) } ) ;
2022-03-30 20:35:13 +00:00
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 ( ) ) {
2023-12-16 14:19:34 +00:00
HashMap < ByteString , ByteString > 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 " ) ) {
2023-11-05 00:44:12 +00:00
parse_enumeration ( extended_attributes , 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 ( ) ;
2024-03-10 22:07:54 +00:00
auto name = parse_identifier_ending_with_space ( ) ;
2022-02-16 23:45:57 +00:00
consume_whitespace ( ) ;
2023-10-10 10:42:20 +00:00
if ( lexer . consume_specific ( " includes " sv ) ) {
2022-02-16 23:45:57 +00:00
consume_whitespace ( ) ;
2024-03-10 22:07:54 +00:00
auto mixin_name = parse_identifier_ending_with_space_or ( ' ; ' ) ;
2022-02-16 23:45:57 +00:00
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-12-16 14:19:34 +00:00
static void resolve_typedef ( Interface & interface , NonnullRefPtr < Type const > & type , HashMap < ByteString , ByteString > * 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 ( ) ) {
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : formatted ( " Failed to resolve path '{}': {} " , filename , this_module_or_error . error ( ) ) , filename , input , 0 ) ;
2023-03-24 09:57:53 +00:00
VERIFY_NOT_REACHED ( ) ;
}
2024-01-15 16:23:24 +00:00
auto this_module = this_module_or_error . release_value ( ) ;
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 ;
2023-06-06 21:21:33 +00:00
{
2023-10-10 10:42:20 +00:00
while ( lexer . consume_specific ( " #import " sv ) ) {
2023-06-06 21:21:33 +00:00
consume_whitespace ( ) ;
assert_specific ( ' < ' ) ;
auto path = lexer . consume_until ( ' > ' ) ;
lexer . ignore ( ) ;
auto maybe_interface = resolve_import ( path ) ;
if ( maybe_interface . has_value ( ) ) {
imports . append ( maybe_interface . release_value ( ) ) ;
}
consume_whitespace ( ) ;
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
2023-10-10 10:42:20 +00:00
if ( lexer . consume_specific ( " interface " sv ) )
2022-04-30 17:27:50 +00:00
parse_interface ( interface ) ;
2023-10-10 10:42:20 +00:00
else if ( lexer . consume_specific ( " namespace " sv ) )
2023-03-15 13:55:49 +00:00
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 )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 ( ) )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 )
2023-12-16 14:19:34 +00:00
report_parsing_error ( ByteString : : 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 ) ;
2024-04-01 13:03:41 +00:00
for ( auto & attribute : interface . static_attributes )
resolve_typedef ( interface , attribute . type , & attribute . extended_attributes ) ;
2022-04-30 17:27:50 +00:00
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 ) {
2024-06-11 06:20:22 +00:00
if ( function . extended_attributes . contains ( " FIXME " ) )
continue ;
2022-04-30 17:27:50 +00:00
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 ) {
2024-06-11 06:20:22 +00:00
if ( function . extended_attributes . contains ( " FIXME " ) )
continue ;
2022-04-30 17:27:50 +00:00
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 ;
}
2024-03-26 13:15:38 +00:00
for ( auto & constructor : interface . constructors ) {
2024-06-11 06:20:22 +00:00
if ( constructor . extended_attributes . contains ( " FIXME " ) )
continue ;
2024-03-26 13:15:38 +00:00
auto & overload_set = interface . constructor_overload_sets . ensure ( constructor . name ) ;
constructor . overload_index = overload_set . size ( ) ;
overload_set . append ( constructor ) ;
}
for ( auto & overload_set : interface . constructor_overload_sets ) {
if ( overload_set . value . size ( ) = = 1 )
continue ;
for ( auto & overloaded_constructor : overload_set . value )
overloaded_constructor . is_overloaded = true ;
}
2022-03-05 18:51:17 +00:00
2024-02-16 01:27:03 +00:00
// Check overload sets for repeated instances of the same function
// as these will produce very cryptic errors if left alone.
for ( auto & overload_set : interface . overload_sets ) {
auto & functions = overload_set . value ;
for ( size_t i = 0 ; i < functions . size ( ) ; + + i ) {
for ( size_t j = i + 1 ; j < functions . size ( ) ; + + j ) {
if ( functions [ i ] . parameters . size ( ) ! = functions [ j ] . parameters . size ( ) )
continue ;
auto same = true ;
for ( size_t k = 0 ; k < functions [ i ] . parameters . size ( ) ; + + k ) {
if ( functions [ i ] . parameters [ k ] . type - > is_distinguishable_from ( interface , functions [ j ] . parameters [ k ] . type ) ) {
same = false ;
break ;
}
}
if ( same ) {
report_parsing_error (
ByteString : : formatted ( " Overload set '{}' contains multiple identical declarations " , overload_set . key ) ,
filename ,
input ,
functions [ j ] . source_position . offset ) ;
}
}
}
}
2022-04-30 17:27:50 +00:00
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 ;
}
2024-11-15 22:43:04 +00:00
Parser : : Parser ( ByteString filename , StringView contents , Vector < ByteString > import_base_paths )
2024-11-14 16:13:44 +00:00
: import_base_paths ( move ( import_base_paths ) )
2022-02-16 22:30:43 +00:00
, filename ( move ( filename ) )
, input ( contents )
, lexer ( input )
{
}
2024-11-15 22:43:04 +00:00
Parser : : Parser ( Parser * parent , ByteString filename , StringView contents , Vector < ByteString > import_base_paths )
2024-11-14 16:13:44 +00:00
: import_base_paths ( move ( import_base_paths ) )
2022-10-08 22:48:04 +00:00
, 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 ;
}
2023-12-16 14:19:34 +00:00
HashMap < ByteString , 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 ;
}
2023-12-16 14:19:34 +00:00
Vector < ByteString > Parser : : imported_files ( ) const
2022-11-05 10:37:33 +00:00
{
return const_cast < Parser * > ( this ) - > top_level_resolved_imports ( ) . keys ( ) ;
}
2022-02-16 22:30:43 +00:00
}