2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2021-01-24 15:28:26 +01:00
# include <AK/Debug.h>
2020-02-14 22:29:06 +01:00
# include <AK/Function.h>
2020-08-21 09:18:10 -04:00
# include <AK/GenericLexer.h>
2019-08-03 16:18:37 +02:00
# include <AK/HashMap.h>
2020-10-11 19:57:53 +02:00
# include <AK/SourceGenerator.h>
2019-08-03 15:15:11 +02:00
# include <AK/StringBuilder.h>
2023-04-24 03:00:34 -06:00
# include <LibCore/ArgsParser.h>
2023-02-09 03:02:46 +01:00
# include <LibCore/File.h>
2022-02-22 19:24:30 +01:00
# include <LibMain/Main.h>
2019-08-03 15:15:11 +02:00
# include <ctype.h>
# include <stdio.h>
struct Parameter {
2023-12-16 17:49:34 +03:30
Vector < ByteString > attributes ;
ByteString type ;
ByteString name ;
2019-08-03 15:15:11 +02:00
} ;
2023-12-16 17:49:34 +03:30
static ByteString pascal_case ( ByteString const & identifier )
2021-05-03 15:52:56 +02:00
{
StringBuilder builder ;
bool was_new_word = true ;
for ( auto ch : identifier ) {
if ( ch = = ' _ ' ) {
was_new_word = true ;
continue ;
}
if ( was_new_word ) {
builder . append ( toupper ( ch ) ) ;
was_new_word = false ;
} else
builder . append ( ch ) ;
}
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2021-05-03 15:52:56 +02:00
}
2019-08-03 15:15:11 +02:00
struct Message {
2023-12-16 17:49:34 +03:30
ByteString name ;
2019-08-03 15:15:11 +02:00
bool is_synchronous { false } ;
Vector < Parameter > inputs ;
Vector < Parameter > outputs ;
2019-08-03 17:03:16 +02:00
2023-12-16 17:49:34 +03:30
ByteString response_name ( ) const
2019-08-03 17:03:16 +02:00
{
StringBuilder builder ;
2021-05-03 15:52:56 +02:00
builder . append ( pascal_case ( name ) ) ;
2022-07-11 17:32:29 +00:00
builder . append ( " Response " sv ) ;
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2019-08-03 17:03:16 +02:00
}
2019-08-03 15:15:11 +02:00
} ;
struct Endpoint {
2023-12-16 17:49:34 +03:30
Vector < ByteString > includes ;
ByteString name ;
2021-04-25 13:19:53 +02:00
u32 magic ;
2019-08-03 15:15:11 +02:00
Vector < Message > messages ;
} ;
2023-12-16 17:49:34 +03:30
static bool is_primitive_type ( ByteString const & type )
2021-05-03 08:46:40 +02:00
{
2022-12-02 16:13:47 -05:00
return type . is_one_of ( " u8 " , " i8 " , " u16 " , " i16 " , " u32 " , " i32 " , " u64 " , " i64 " , " size_t " , " bool " , " double " , " float " , " int " , " unsigned " , " unsigned int " ) ;
2021-05-03 08:46:40 +02:00
}
2023-12-16 17:49:34 +03:30
static bool is_simple_type ( ByteString const & type )
2022-12-06 19:43:46 +00:00
{
// Small types that it makes sense just to pass by value.
2024-03-28 22:12:23 -04:00
return type . is_one_of ( " Gfx::Color " , " Web::DevicePixels " , " Gfx::IntPoint " , " Gfx::FloatPoint " , " Web::DevicePixelPoint " , " Gfx::IntSize " , " Gfx::FloatSize " , " Web::DevicePixelSize " , " Core::File::OpenMode " , " Web::Cookie::Source " , " Web::HTML::AllowMultipleFiles " , " Web::HTML::AudioPlayState " , " Web::HTML::HistoryHandlingBehavior " ) ;
2022-12-06 19:43:46 +00:00
}
2023-12-16 17:49:34 +03:30
static bool is_primitive_or_simple_type ( ByteString const & type )
2022-12-06 19:43:46 +00:00
{
return is_primitive_type ( type ) | | is_simple_type ( type ) ;
}
2023-12-16 17:49:34 +03:30
static ByteString message_name ( ByteString const & endpoint , ByteString const & message , bool is_response )
2021-05-03 08:46:40 +02:00
{
StringBuilder builder ;
2022-07-11 17:32:29 +00:00
builder . append ( " Messages:: " sv ) ;
2021-05-03 08:46:40 +02:00
builder . append ( endpoint ) ;
2022-07-11 17:32:29 +00:00
builder . append ( " :: " sv ) ;
2021-05-03 15:52:56 +02:00
builder . append ( pascal_case ( message ) ) ;
2021-05-03 08:46:40 +02:00
if ( is_response )
2022-07-11 17:32:29 +00:00
builder . append ( " Response " sv ) ;
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2021-05-03 08:46:40 +02:00
}
2022-02-22 19:24:30 +01:00
Vector < Endpoint > parse ( ByteBuffer const & file_contents )
2019-08-03 15:15:11 +02:00
{
2020-08-21 09:18:10 -04:00
GenericLexer lexer ( file_contents ) ;
2019-08-03 15:15:11 +02:00
Vector < Endpoint > endpoints ;
2022-02-22 19:24:30 +01:00
auto assert_specific = [ & lexer ] ( char ch ) {
2020-08-21 09:18:10 -04:00
if ( lexer . peek ( ) ! = ch )
2020-10-11 19:57:53 +02:00
warnln ( " assert_specific: wanted '{}', but got '{}' at index {} " , ch , lexer . peek ( ) , lexer . tell ( ) ) ;
2020-08-21 09:18:10 -04:00
bool saw_expected = lexer . consume_specific ( ch ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( saw_expected ) ;
2019-08-03 15:15:11 +02:00
} ;
2022-02-22 19:24:30 +01:00
auto consume_whitespace = [ & lexer ] {
2020-08-21 09:18:10 -04:00
lexer . ignore_while ( [ ] ( char ch ) { return isspace ( ch ) ; } ) ;
if ( lexer . peek ( ) = = ' / ' & & lexer . peek ( 1 ) = = ' / ' )
2023-02-28 11:11:39 +00:00
lexer . ignore_until ( ' \n ' ) ;
2019-08-03 15:15:11 +02:00
} ;
auto parse_parameter = [ & ] ( Vector < Parameter > & storage ) {
for ( ; ; ) {
Parameter parameter ;
2022-01-29 11:19:16 +02:00
if ( lexer . is_eof ( ) ) {
warnln ( " EOF when parsing parameter " ) ;
VERIFY_NOT_REACHED ( ) ;
}
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
if ( lexer . peek ( ) = = ' ) ' )
2019-08-03 15:15:11 +02:00
break ;
2020-08-21 09:18:10 -04:00
if ( lexer . consume_specific ( ' [ ' ) ) {
2020-05-16 14:11:35 +02:00
for ( ; ; ) {
2020-08-21 09:18:10 -04:00
if ( lexer . consume_specific ( ' ] ' ) ) {
2020-05-16 14:11:35 +02:00
consume_whitespace ( ) ;
break ;
}
2020-08-21 09:18:10 -04:00
if ( lexer . consume_specific ( ' , ' ) ) {
2020-05-16 14:11:35 +02:00
consume_whitespace ( ) ;
}
2020-08-21 09:18:10 -04:00
auto attribute = lexer . consume_until ( [ ] ( char ch ) { return ch = = ' ] ' | | ch = = ' , ' ; } ) ;
2020-05-16 14:11:35 +02:00
parameter . attributes . append ( attribute ) ;
consume_whitespace ( ) ;
}
}
2023-12-16 17:49:34 +03:30
// FIXME: This is not entirely correct. Types can have spaces, for example `HashMap<int, ByteString>`.
2022-01-29 11:19:16 +02:00
// Maybe we should use LibCpp::Parser for parsing types.
2020-08-21 09:18:10 -04:00
parameter . type = lexer . consume_until ( [ ] ( char ch ) { return isspace ( ch ) ; } ) ;
2023-05-14 23:05:51 +02:00
if ( parameter . type . ends_with ( ' , ' ) ) {
warnln ( " Parameter type '{}' looks invalid! " , parameter . type ) ;
warnln ( " Note that templates must not include spaces. " ) ;
VERIFY_NOT_REACHED ( ) ;
}
2022-01-29 11:19:16 +02:00
VERIFY ( ! lexer . is_eof ( ) ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
parameter . name = lexer . consume_until ( [ ] ( char ch ) { return isspace ( ch ) | | ch = = ' , ' | | ch = = ' ) ' ; } ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
storage . append ( move ( parameter ) ) ;
2020-08-21 09:18:10 -04:00
if ( lexer . consume_specific ( ' , ' ) )
2019-08-03 15:15:11 +02:00
continue ;
2020-08-21 09:18:10 -04:00
if ( lexer . peek ( ) = = ' ) ' )
2019-08-03 15:15:11 +02:00
break ;
}
} ;
auto parse_parameters = [ & ] ( Vector < Parameter > & storage ) {
for ( ; ; ) {
consume_whitespace ( ) ;
parse_parameter ( storage ) ;
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
if ( lexer . consume_specific ( ' , ' ) )
2019-08-03 15:15:11 +02:00
continue ;
2020-08-21 09:18:10 -04:00
if ( lexer . peek ( ) = = ' ) ' )
2019-08-03 15:15:11 +02:00
break ;
}
} ;
auto parse_message = [ & ] {
Message message ;
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
message . name = lexer . consume_until ( [ ] ( char ch ) { return isspace ( ch ) | | ch = = ' ( ' ; } ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
assert_specific ( ' ( ' ) ;
2019-08-03 15:15:11 +02:00
parse_parameters ( message . inputs ) ;
2020-08-21 09:18:10 -04:00
assert_specific ( ' ) ' ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
assert_specific ( ' = ' ) ;
2019-08-03 15:15:11 +02:00
2020-08-21 09:18:10 -04:00
auto type = lexer . consume ( ) ;
2019-08-03 15:15:11 +02:00
if ( type = = ' > ' )
message . is_synchronous = true ;
else if ( type = = ' | ' )
message . is_synchronous = false ;
else
2021-02-23 20:42:32 +01:00
VERIFY_NOT_REACHED ( ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
if ( message . is_synchronous ) {
2020-08-21 09:18:10 -04:00
assert_specific ( ' ( ' ) ;
2019-08-03 15:15:11 +02:00
parse_parameters ( message . outputs ) ;
2020-08-21 09:18:10 -04:00
assert_specific ( ' ) ' ) ;
2019-08-03 15:15:11 +02:00
}
consume_whitespace ( ) ;
endpoints . last ( ) . messages . append ( move ( message ) ) ;
} ;
auto parse_messages = [ & ] {
for ( ; ; ) {
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
if ( lexer . peek ( ) = = ' } ' )
2019-08-03 15:15:11 +02:00
break ;
2021-06-23 17:00:38 +02:00
parse_message ( ) ;
consume_whitespace ( ) ;
2019-08-03 15:15:11 +02:00
}
} ;
2021-07-02 21:35:27 -07:00
auto parse_include = [ & ] {
2023-12-16 17:49:34 +03:30
ByteString include ;
2021-07-02 21:35:27 -07:00
consume_whitespace ( ) ;
include = lexer . consume_while ( [ ] ( char ch ) { return ch ! = ' \n ' ; } ) ;
consume_whitespace ( ) ;
endpoints . last ( ) . includes . append ( move ( include ) ) ;
} ;
auto parse_includes = [ & ] {
for ( ; ; ) {
consume_whitespace ( ) ;
if ( lexer . peek ( ) ! = ' # ' )
break ;
parse_include ( ) ;
consume_whitespace ( ) ;
}
} ;
2019-08-03 15:15:11 +02:00
auto parse_endpoint = [ & ] {
endpoints . empend ( ) ;
consume_whitespace ( ) ;
2021-07-02 21:35:27 -07:00
parse_includes ( ) ;
consume_whitespace ( ) ;
2023-10-10 12:42:20 +02:00
lexer . consume_specific ( " endpoint " sv ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
endpoints . last ( ) . name = lexer . consume_while ( [ ] ( char ch ) { return ! isspace ( ch ) ; } ) ;
2023-12-16 17:49:34 +03:30
endpoints . last ( ) . magic = Traits < ByteString > : : hash ( endpoints . last ( ) . name ) ;
2021-04-25 11:24:12 +02:00
consume_whitespace ( ) ;
2020-08-21 09:18:10 -04:00
assert_specific ( ' { ' ) ;
2019-08-03 15:15:11 +02:00
parse_messages ( ) ;
2020-08-21 09:18:10 -04:00
assert_specific ( ' } ' ) ;
2019-08-03 15:15:11 +02:00
consume_whitespace ( ) ;
} ;
2020-08-21 10:39:46 -04:00
while ( lexer . tell ( ) < file_contents . size ( ) )
2019-08-03 15:15:11 +02:00
parse_endpoint ( ) ;
2022-02-22 19:24:30 +01:00
return endpoints ;
}
2019-08-03 15:50:16 +02:00
2023-12-16 17:49:34 +03:30
HashMap < ByteString , int > build_message_ids_for_endpoint ( SourceGenerator generator , Endpoint const & endpoint )
2022-02-22 19:24:30 +01:00
{
2023-12-16 17:49:34 +03:30
HashMap < ByteString , int > message_ids ;
2019-08-03 16:18:37 +02:00
2022-02-22 19:24:30 +01:00
generator . appendln ( " \n enum class MessageID : i32 { " ) ;
for ( auto const & message : endpoint . messages ) {
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_ids . set ( message . name , message_ids . size ( ) + 1 ) ;
generator . set ( " message.pascal_name " , pascal_case ( message . name ) ) ;
2023-12-16 17:49:34 +03:30
generator . set ( " message.id " , ByteString : : number ( message_ids . size ( ) ) ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
generator . appendln ( " @message.pascal_name@ = @message.id@, " ) ;
if ( message . is_synchronous ) {
message_ids . set ( message . response_name ( ) , message_ids . size ( ) + 1 ) ;
generator . set ( " message.pascal_name " , pascal_case ( message . response_name ( ) ) ) ;
2023-12-16 17:49:34 +03:30
generator . set ( " message.id " , ByteString : : number ( message_ids . size ( ) ) ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
generator . appendln ( " @message.pascal_name@ = @message.id@, " ) ;
2019-08-03 16:18:37 +02:00
}
2022-02-22 19:24:30 +01:00
}
generator . appendln ( " }; " ) ;
return message_ids ;
}
2019-08-03 16:35:49 +02:00
2023-12-16 17:49:34 +03:30
ByteString constructor_for_message ( ByteString const & name , Vector < Parameter > const & parameters )
2022-02-22 19:24:30 +01:00
{
StringBuilder builder ;
builder . append ( name ) ;
2019-08-03 16:35:49 +02:00
2022-02-22 19:24:30 +01:00
if ( parameters . is_empty ( ) ) {
2022-07-11 17:32:29 +00:00
builder . append ( " () {} " sv ) ;
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2022-02-22 19:24:30 +01:00
}
builder . append ( ' ( ' ) ;
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
builder . appendff ( " {} {} " , parameter . type , parameter . name ) ;
if ( i ! = parameters . size ( ) - 1 )
2022-07-11 17:32:29 +00:00
builder . append ( " , " sv ) ;
2022-02-22 19:24:30 +01:00
}
2022-07-11 17:32:29 +00:00
builder . append ( " ) : " sv ) ;
2022-02-22 19:24:30 +01:00
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
builder . appendff ( " m_{}(move({})) " , parameter . name , parameter . name ) ;
if ( i ! = parameters . size ( ) - 1 )
2022-07-11 17:32:29 +00:00
builder . append ( " , " sv ) ;
2022-02-22 19:24:30 +01:00
}
2022-07-11 17:32:29 +00:00
builder . append ( " {} " sv ) ;
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2022-02-22 19:24:30 +01:00
}
2019-08-03 16:35:49 +02:00
2023-12-16 17:49:34 +03:30
void do_message ( SourceGenerator message_generator , ByteString const & name , Vector < Parameter > const & parameters , ByteString const & response_type = { } )
2022-02-22 19:24:30 +01:00
{
auto pascal_name = pascal_case ( name ) ;
message_generator . set ( " message.name " , name ) ;
message_generator . set ( " message.pascal_name " , pascal_name ) ;
message_generator . set ( " message.response_type " , response_type ) ;
message_generator . set ( " message.constructor " , constructor_for_message ( pascal_name , parameters ) ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
class @ message . pascal_name @ final : public IPC : : Message {
2022-02-22 19:24:30 +01:00
public : ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2023-10-10 15:00:58 +03:30
if ( ! response_type . is_empty ( ) )
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
typedef class @ message . response_type @ ResponseType ; ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
@ message . pascal_name @ ( decltype ( nullptr ) ) : m_ipc_message_valid ( false ) { }
@ message . pascal_name @ ( @ message . pascal_name @ const & ) = default ;
@ message . pascal_name @ ( @ message . pascal_name @ & & ) = default ;
@ message . pascal_name @ & operator = ( @ message . pascal_name @ const & ) = default ;
2022-11-08 19:58:54 -05:00
@ message . constructor @ ) ~ ~ ~ " );
if ( parameters . size ( ) = = 1 ) {
auto const & parameter = parameters [ 0 ] ;
message_generator . set ( " parameter.type " sv , parameter . type ) ;
message_generator . set ( " parameter.name " sv , parameter . name ) ;
message_generator . appendln ( R " ~~~(
template < typename WrappedReturnType >
requires ( ! SameAs < WrappedReturnType , @ parameter . type @ > )
@ message . pascal_name @ ( WrappedReturnType & & value )
: m_ @ parameter . name @ ( forward < WrappedReturnType > ( value ) )
{
} ) ~ ~ ~ " );
}
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
virtual ~ @ message . pascal_name @ ( ) override { }
2020-10-11 19:57:53 +02:00
2021-04-25 13:19:53 +02:00
virtual u32 endpoint_magic ( ) const override { return @ endpoint . magic @ ; }
2021-05-03 15:52:56 +02:00
virtual i32 message_id ( ) const override { return ( int ) MessageID : : @ message . pascal_name @ ; }
static i32 static_message_id ( ) { return ( int ) MessageID : : @ message . pascal_name @ ; }
virtual const char * message_name ( ) const override { return " @endpoint.name@::@message.pascal_name@ " ; }
2020-10-11 19:57:53 +02:00
2023-02-10 01:00:18 +01:00
static ErrorOr < NonnullOwnPtr < @ message . pascal_name @ > > decode ( Stream & stream , Core : : LocalSocket & socket )
2020-10-11 19:57:53 +02:00
{
2022-02-22 19:24:30 +01:00
IPC : : Decoder decoder { stream , socket } ; ) ~ ~ ~ " );
2019-08-03 17:03:16 +02:00
2022-02-22 19:24:30 +01:00
for ( auto const & parameter : parameters ) {
2023-08-21 16:42:48 +02:00
auto parameter_generator = message_generator . fork ( ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
parameter_generator . set ( " parameter.type " , parameter . type ) ;
parameter_generator . set ( " parameter.name " , parameter . name ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
if ( parameter . type = = " bool " )
parameter_generator . set ( " parameter.initial_value " , " false " ) ;
else
parameter_generator . set ( " parameter.initial_value " , " {} " ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
parameter_generator . appendln ( R " ~~~(
2022-12-22 20:40:33 -05:00
auto @ parameter . name @ = TRY ( ( decoder . decode < @ parameter . type @ > ( ) ) ) ; ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
if ( parameter . attributes . contains_slow ( " UTF8 " ) ) {
parameter_generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
if ( ! Utf8View ( @ parameter . name @ ) . validate ( ) )
2022-12-22 13:48:44 -05:00
return Error : : from_string_literal ( " Decoded @parameter.name@ is invalid UTF-8 " ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
}
2019-08-03 17:03:16 +02:00
2022-02-22 19:24:30 +01:00
StringBuilder builder ;
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
builder . appendff ( " move({}) " , parameter . name ) ;
if ( i ! = parameters . size ( ) - 1 )
2022-07-11 17:32:29 +00:00
builder . append ( " , " sv ) ;
2022-02-22 19:24:30 +01:00
}
2020-10-11 19:57:53 +02:00
2023-12-16 17:49:34 +03:30
message_generator . set ( " message.constructor_call_parameters " , builder . to_byte_string ( ) ) ;
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
return make < @ message . pascal_name @ > ( @ message . constructor_call_parameters @ ) ;
2022-02-22 19:24:30 +01:00
} ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2021-12-04 10:09:09 +01:00
virtual bool valid ( ) const override { return m_ipc_message_valid ; }
2021-05-02 05:20:28 +02:00
2023-01-01 23:58:49 -05:00
virtual ErrorOr < IPC : : MessageBuffer > encode ( ) const override
2020-10-11 19:57:53 +02:00
{
2021-05-02 05:20:28 +02:00
VERIFY ( valid ( ) ) ;
2020-10-11 19:57:53 +02:00
IPC : : MessageBuffer buffer ;
IPC : : Encoder stream ( buffer ) ;
2023-01-01 23:58:49 -05:00
TRY ( stream . encode ( endpoint_magic ( ) ) ) ;
TRY ( stream . encode ( ( int ) MessageID : : @ message . pascal_name @ ) ) ; ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
for ( auto const & parameter : parameters ) {
2023-08-21 16:42:48 +02:00
auto parameter_generator = message_generator . fork ( ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
parameter_generator . set ( " parameter.name " , parameter . name ) ;
parameter_generator . appendln ( R " ~~~(
2023-01-01 23:58:49 -05:00
TRY ( stream . encode ( m_ @ parameter . name @ ) ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
return buffer ;
2022-02-22 19:24:30 +01:00
} ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
for ( auto const & parameter : parameters ) {
2023-08-21 16:42:48 +02:00
auto parameter_generator = message_generator . fork ( ) ;
2022-02-22 19:24:30 +01:00
parameter_generator . set ( " parameter.type " , parameter . type ) ;
parameter_generator . set ( " parameter.name " , parameter . name ) ;
parameter_generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
const @ parameter . type @ & @ parameter . name @ ( ) const { return m_ @ parameter . name @ ; }
2022-02-22 19:24:30 +01:00
@ parameter . type @ take_ @ parameter . name @ ( ) { return move ( m_ @ parameter . name @ ) ; } ) ~ ~ ~ " );
}
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
private :
2022-02-22 19:24:30 +01:00
bool m_ipc_message_valid { true } ; ) ~ ~ ~ " );
for ( auto const & parameter : parameters ) {
2023-08-21 16:42:48 +02:00
auto parameter_generator = message_generator . fork ( ) ;
2022-02-22 19:24:30 +01:00
parameter_generator . set ( " parameter.type " , parameter . type ) ;
parameter_generator . set ( " parameter.name " , parameter . name ) ;
parameter_generator . appendln ( R " ~~~(
@ parameter . type @ m_ @ parameter . name @ { } ; ) ~ ~ ~ " );
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( " \n }; " ) ;
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
void do_message_for_proxy ( SourceGenerator message_generator , Endpoint const & endpoint , Message const & message )
{
2023-12-16 17:49:34 +03:30
auto do_implement_proxy = [ & ] ( ByteString const & name , Vector < Parameter > const & parameters , bool is_synchronous , bool is_try ) {
ByteString return_type = " void " ;
2022-02-22 19:24:30 +01:00
if ( is_synchronous ) {
if ( message . outputs . size ( ) = = 1 )
return_type = message . outputs [ 0 ] . type ;
else if ( ! message . outputs . is_empty ( ) )
return_type = message_name ( endpoint . name , message . name , true ) ;
}
2023-12-16 17:49:34 +03:30
ByteString inner_return_type = return_type ;
2022-02-22 19:24:30 +01:00
if ( is_try )
2023-12-16 17:49:34 +03:30
return_type = ByteString : : formatted ( " IPC::IPCErrorOr<{}> " , return_type ) ;
2022-02-22 19:24:30 +01:00
message_generator . set ( " message.name " , message . name ) ;
message_generator . set ( " message.pascal_name " , pascal_case ( message . name ) ) ;
message_generator . set ( " message.complex_return_type " , return_type ) ;
message_generator . set ( " async_prefix_maybe " , is_synchronous ? " " : " async_ " ) ;
message_generator . set ( " try_prefix_maybe " , is_try ? " try_ " : " " ) ;
message_generator . set ( " handler_name " , name ) ;
message_generator . appendln ( R " ~~~(
2021-05-03 16:51:42 +02:00
@ message . complex_return_type @ @ try_prefix_maybe @ @ async_prefix_maybe @ @ handler_name @ ( ) ~ ~ ~ " );
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
2023-08-21 16:42:48 +02:00
auto argument_generator = message_generator . fork ( ) ;
2022-02-22 19:24:30 +01:00
argument_generator . set ( " argument.type " , parameter . type ) ;
argument_generator . set ( " argument.name " , parameter . name ) ;
argument_generator . append ( " @argument.type@ @argument.name@ " ) ;
if ( i ! = parameters . size ( ) - 1 )
argument_generator . append ( " , " ) ;
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
message_generator . append ( " ) { " ) ;
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
if ( is_synchronous & & ! is_try ) {
if ( return_type ! = " void " ) {
message_generator . append ( R " ~~~(
2021-05-03 13:55:29 +02:00
return ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
if ( message . outputs . size ( ) ! = 1 )
message_generator . append ( " move(* " ) ;
} else {
message_generator . append ( R " ~~~(
2021-12-02 12:10:28 +00:00
( void ) ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
message_generator . append ( " m_connection.template send_sync<Messages::@endpoint.name@::@message.pascal_name@>( " ) ;
} else if ( is_try ) {
message_generator . append ( R " ~~~(
2021-05-03 16:51:42 +02:00
auto result = m_connection . template send_sync_but_allow_failure < Messages : : @ endpoint . name @ : : @ message . pascal_name @ > ( ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
} else {
message_generator . append ( R " ~~~(
2021-11-28 09:59:36 +01:00
// FIXME: Handle post_message failures.
( void ) m_connection . post_message ( Messages : : @ endpoint . name @ : : @ message . pascal_name @ { ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
2023-08-21 16:42:48 +02:00
auto argument_generator = message_generator . fork ( ) ;
2022-02-22 19:24:30 +01:00
argument_generator . set ( " argument.name " , parameter . name ) ;
2022-12-06 19:43:46 +00:00
if ( is_primitive_or_simple_type ( parameters [ i ] . type ) )
2022-02-22 19:24:30 +01:00
argument_generator . append ( " @argument.name@ " ) ;
else
argument_generator . append ( " move(@argument.name@) " ) ;
if ( i ! = parameters . size ( ) - 1 )
argument_generator . append ( " , " ) ;
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
if ( is_synchronous & & ! is_try ) {
if ( return_type ! = " void " ) {
message_generator . append ( " ) " ) ;
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
if ( message . outputs . size ( ) = = 1 ) {
message_generator . append ( " ->take_ " ) ;
message_generator . append ( message . outputs [ 0 ] . name ) ;
message_generator . append ( " () " ) ;
} else
message_generator . append ( " ) " ) ;
2021-05-03 13:55:29 +02:00
2022-02-22 19:24:30 +01:00
message_generator . append ( " ; " ) ;
} else if ( is_try ) {
message_generator . append ( R " ~~~();
2023-12-27 00:30:29 -05:00
if ( ! result ) {
m_connection . shutdown ( ) ;
return IPC : : ErrorCode : : PeerDisconnected ;
} ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
if ( inner_return_type ! = " void " ) {
message_generator . appendln ( R " ~~~(
return move ( * result ) ; ) ~ ~ ~ " );
} else {
message_generator . appendln ( R " ~~~(
return { } ; ) ~ ~ ~ " );
}
} else {
message_generator . appendln ( " }); " ) ;
}
2021-05-03 16:51:42 +02:00
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
} ) ~ ~ ~ " );
} ;
do_implement_proxy ( message . name , message . inputs , message . is_synchronous , false ) ;
if ( message . is_synchronous ) {
do_implement_proxy ( message . name , message . inputs , false , false ) ;
do_implement_proxy ( message . name , message . inputs , true , true ) ;
2021-05-03 16:51:42 +02:00
}
2022-02-22 19:24:30 +01:00
}
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
void build_endpoint ( SourceGenerator generator , Endpoint const & endpoint )
{
generator . set ( " endpoint.name " , endpoint . name ) ;
2023-12-16 17:49:34 +03:30
generator . set ( " endpoint.magic " , ByteString : : number ( endpoint . magic ) ) ;
2022-02-22 19:24:30 +01:00
generator . appendln ( " \n namespace Messages::@endpoint.name@ { " ) ;
2023-12-16 17:49:34 +03:30
HashMap < ByteString , int > message_ids = build_message_ids_for_endpoint ( generator . fork ( ) , endpoint ) ;
2022-02-22 19:24:30 +01:00
for ( auto const & message : endpoint . messages ) {
2023-12-16 17:49:34 +03:30
ByteString response_name ;
2022-02-22 19:24:30 +01:00
if ( message . is_synchronous ) {
response_name = message . response_name ( ) ;
2023-08-21 16:42:48 +02:00
do_message ( generator . fork ( ) , response_name , message . outputs ) ;
2021-05-03 08:46:40 +02:00
}
2023-08-21 16:42:48 +02:00
do_message ( generator . fork ( ) , message . name , message . inputs , response_name ) ;
2022-02-22 19:24:30 +01:00
}
generator . appendln ( R " ~~~(
} // namespace Messages::@endpoint.name@
template < typename LocalEndpoint , typename PeerEndpoint >
class @ endpoint . name @ Proxy {
public :
// Used to disambiguate the constructor call.
struct Tag { } ;
@ endpoint . name @ Proxy ( IPC : : Connection < LocalEndpoint , PeerEndpoint > & connection , Tag )
: m_connection ( connection )
{ } ) ~ ~ ~ " );
for ( auto const & message : endpoint . messages )
2023-08-21 16:42:48 +02:00
do_message_for_proxy ( generator . fork ( ) , endpoint , message ) ;
2021-05-03 08:46:40 +02:00
2022-02-22 19:24:30 +01:00
generator . appendln ( R " ~~~(
2021-05-03 08:46:40 +02:00
private :
IPC : : Connection < LocalEndpoint , PeerEndpoint > & m_connection ;
2022-02-22 19:24:30 +01:00
} ; ) ~ ~ ~ " );
2021-05-03 08:46:40 +02:00
2022-12-22 13:48:44 -05:00
generator . append ( R " ~~~(
2021-05-03 08:46:40 +02:00
template < typename LocalEndpoint , typename PeerEndpoint >
class @ endpoint . name @ Proxy ;
class @ endpoint . name @ Stub ;
class @ endpoint . name @ Endpoint {
public :
template < typename LocalEndpoint >
using Proxy = @ endpoint . name @ Proxy < LocalEndpoint , @ endpoint . name @ Endpoint > ;
using Stub = @ endpoint . name @ Stub ;
2020-10-11 19:57:53 +02:00
2021-04-25 13:19:53 +02:00
static u32 static_magic ( ) { return @ endpoint . magic @ ; }
2020-10-11 19:57:53 +02:00
2023-02-08 23:05:44 +01:00
static ErrorOr < NonnullOwnPtr < IPC : : Message > > decode_message ( ReadonlyBytes buffer , [[maybe_unused]] Core : : LocalSocket & socket )
2020-10-11 19:57:53 +02:00
{
2023-01-30 11:05:43 +01:00
FixedMemoryStream stream { buffer } ;
auto message_endpoint_magic = TRY ( stream . read_value < u32 > ( ) ) ; ) ~ ~ ~ " );
2022-12-22 13:48:44 -05:00
generator . append ( R " ~~~(
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
if ( message_endpoint_magic ! = @ endpoint . magic @ ) { ) ~ ~ ~ " );
if constexpr ( GENERATE_DEBUG ) {
2022-12-22 13:48:44 -05:00
generator . append ( R " ~~~(
2022-12-22 13:15:48 -05:00
dbgln ( " @endpoint.name@: Endpoint magic number message_endpoint_magic != @endpoint.magic@, not my message! (the other endpoint may have handled it) " ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
generator . appendln ( R " ~~~(
2022-12-22 13:48:44 -05:00
return Error : : from_string_literal ( " Endpoint magic number mismatch, not my message! " ) ;
2020-10-11 19:57:53 +02:00
}
2023-01-30 11:05:43 +01:00
auto message_id = TRY ( stream . read_value < i32 > ( ) ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
switch ( message_id ) { ) ~ ~ ~ " );
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
for ( auto const & message : endpoint . messages ) {
2023-12-16 17:49:34 +03:30
auto do_decode_message = [ & ] ( ByteString const & name ) {
2023-08-21 16:42:48 +02:00
auto message_generator = generator . fork ( ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . set ( " message.name " , name ) ;
message_generator . set ( " message.pascal_name " , pascal_case ( name ) ) ;
2020-10-11 19:57:53 +02:00
2022-12-22 13:48:44 -05:00
message_generator . append ( R " ~~~(
2021-05-03 15:52:56 +02:00
case ( int ) Messages : : @ endpoint . name @ : : MessageID : : @ message . pascal_name @ :
2023-01-30 11:05:43 +01:00
return TRY ( Messages : : @ endpoint . name @ : : @ message . pascal_name @ : : decode ( stream , socket ) ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
} ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
do_decode_message ( message . name ) ;
if ( message . is_synchronous )
do_decode_message ( message . response_name ( ) ) ;
}
2020-10-11 19:57:53 +02:00
2022-12-22 13:48:44 -05:00
generator . append ( R " ~~~(
2022-02-22 19:24:30 +01:00
default : ) ~ ~ ~ " );
if constexpr ( GENERATE_DEBUG ) {
2022-12-22 13:48:44 -05:00
generator . append ( R " ~~~(
2022-12-22 13:15:48 -05:00
dbgln ( " Failed to decode @endpoint.name@.({}) " , message_id ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
generator . appendln ( R " ~~~(
2022-12-22 13:48:44 -05:00
return Error : : from_string_literal ( " Failed to decode @endpoint.name@ message " ) ;
} ) ~ ~ ~ " );
2020-04-06 10:12:10 +02:00
2022-02-22 19:24:30 +01:00
generator . appendln ( R " ~~~(
2022-12-22 13:48:44 -05:00
VERIFY_NOT_REACHED ( ) ;
2020-10-11 19:57:53 +02:00
}
2021-05-03 08:46:40 +02:00
} ;
class @ endpoint . name @ Stub : public IPC : : Stub {
public :
@ endpoint . name @ Stub ( ) { }
virtual ~ @ endpoint . name @ Stub ( ) override { }
virtual u32 magic ( ) const override { return @ endpoint . magic @ ; }
2023-12-16 17:49:34 +03:30
virtual ByteString name ( ) const override { return " @endpoint.name@ " ; }
2021-05-03 08:46:40 +02:00
2023-01-01 23:58:49 -05:00
virtual ErrorOr < OwnPtr < IPC : : MessageBuffer > > handle ( const IPC : : Message & message ) override
2020-10-11 19:57:53 +02:00
{
2022-02-22 19:24:30 +01:00
switch ( message . message_id ( ) ) { ) ~ ~ ~ " );
for ( auto const & message : endpoint . messages ) {
2023-12-16 17:49:34 +03:30
auto do_handle_message = [ & ] ( ByteString const & name , Vector < Parameter > const & parameters , bool returns_something ) {
2023-08-21 16:42:48 +02:00
auto message_generator = generator . fork ( ) ;
2021-05-02 19:54:34 +02:00
2022-02-22 19:24:30 +01:00
StringBuilder argument_generator ;
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
2022-07-11 17:32:29 +00:00
argument_generator . append ( " request. " sv ) ;
2022-02-22 19:24:30 +01:00
argument_generator . append ( parameter . name ) ;
2022-07-11 17:32:29 +00:00
argument_generator . append ( " () " sv ) ;
2022-02-22 19:24:30 +01:00
if ( i ! = parameters . size ( ) - 1 )
2022-07-11 17:32:29 +00:00
argument_generator . append ( " , " sv ) ;
2022-02-22 19:24:30 +01:00
}
message_generator . set ( " message.pascal_name " , pascal_case ( name ) ) ;
message_generator . set ( " message.response_type " , pascal_case ( message . response_name ( ) ) ) ;
message_generator . set ( " handler_name " , name ) ;
2023-12-16 17:49:34 +03:30
message_generator . set ( " arguments " , argument_generator . to_byte_string ( ) ) ;
2022-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
case ( int ) Messages : : @ endpoint . name @ : : MessageID : : @ message . pascal_name @ : { ) ~ ~ ~ " );
if ( returns_something ) {
if ( message . outputs . is_empty ( ) ) {
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
[[maybe_unused]] auto & request = static_cast < const Messages : : @ endpoint . name @ : : @ message . pascal_name @ & > ( message ) ;
2021-05-02 19:54:34 +02:00
@ handler_name @ ( @ arguments @ ) ;
2021-05-02 05:20:28 +02:00
auto response = Messages : : @ endpoint . name @ : : @ message . response_type @ { } ;
2023-01-01 23:58:49 -05:00
return make < IPC : : MessageBuffer > ( TRY ( response . encode ( ) ) ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
} else {
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
[[maybe_unused]] auto & request = static_cast < const Messages : : @ endpoint . name @ : : @ message . pascal_name @ & > ( message ) ;
2021-05-02 19:54:34 +02:00
auto response = @ handler_name @ ( @ arguments @ ) ;
2021-05-02 05:20:28 +02:00
if ( ! response . valid ( ) )
2023-01-01 23:58:49 -05:00
return Error : : from_string_literal ( " Failed to handle @endpoint.name@::@message.pascal_name@ message " ) ;
return make < IPC : : MessageBuffer > ( TRY ( response . encode ( ) ) ) ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
} else {
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
[[maybe_unused]] auto & request = static_cast < const Messages : : @ endpoint . name @ : : @ message . pascal_name @ & > ( message ) ;
2021-05-02 19:54:34 +02:00
@ handler_name @ ( @ arguments @ ) ;
2023-01-01 23:58:49 -05:00
return nullptr ; ) ~ ~ ~ " );
2022-02-22 19:24:30 +01:00
}
message_generator . appendln ( R " ~~~(
} ) ~ ~ ~ " );
} ;
do_handle_message ( message . name , message . inputs , message . is_synchronous ) ;
}
generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
default :
2023-01-01 23:58:49 -05:00
return Error : : from_string_literal ( " Unknown message ID for @endpoint.name@ endpoint " ) ;
2020-10-11 19:57:53 +02:00
}
2022-02-22 19:24:30 +01:00
} ) ~ ~ ~ " );
2019-08-03 15:50:16 +02:00
2022-02-22 19:24:30 +01:00
for ( auto const & message : endpoint . messages ) {
2023-08-21 16:42:48 +02:00
auto message_generator = generator . fork ( ) ;
2020-10-11 19:57:53 +02:00
2023-12-16 17:49:34 +03:30
auto do_handle_message_decl = [ & ] ( ByteString const & name , Vector < Parameter > const & parameters , bool is_response ) {
ByteString return_type = " void " ;
2022-02-22 19:24:30 +01:00
if ( message . is_synchronous & & ! message . outputs . is_empty ( ) & & ! is_response )
return_type = message_name ( endpoint . name , message . name , true ) ;
message_generator . set ( " message.complex_return_type " , return_type ) ;
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
message_generator . set ( " handler_name " , name ) ;
message_generator . appendln ( R " ~~~(
2021-05-02 19:54:34 +02:00
virtual @ message . complex_return_type @ @ handler_name @ ( ) ~ ~ ~ " );
2023-12-16 17:49:34 +03:30
auto make_argument_type = [ ] ( ByteString const & type ) {
2022-02-22 19:24:30 +01:00
StringBuilder builder ;
2021-05-02 19:54:34 +02:00
2022-12-06 19:43:46 +00:00
bool const_ref = ! is_primitive_or_simple_type ( type ) ;
2021-05-02 19:54:34 +02:00
2022-02-22 19:24:30 +01:00
builder . append ( type ) ;
if ( const_ref )
2022-07-11 17:32:29 +00:00
builder . append ( " const& " sv ) ;
2021-05-02 19:54:34 +02:00
2023-12-16 17:49:34 +03:30
return builder . to_byte_string ( ) ;
2022-02-22 19:24:30 +01:00
} ;
2021-05-02 19:54:34 +02:00
2022-02-22 19:24:30 +01:00
for ( size_t i = 0 ; i < parameters . size ( ) ; + + i ) {
auto const & parameter = parameters [ i ] ;
2023-08-21 16:42:48 +02:00
auto argument_generator = message_generator . fork ( ) ;
2022-02-22 19:24:30 +01:00
argument_generator . set ( " argument.type " , make_argument_type ( parameter . type ) ) ;
argument_generator . set ( " argument.name " , parameter . name ) ;
argument_generator . append ( " [[maybe_unused]] @argument.type@ @argument.name@ " ) ;
if ( i ! = parameters . size ( ) - 1 )
argument_generator . append ( " , " ) ;
}
2020-10-11 19:57:53 +02:00
2022-02-22 19:24:30 +01:00
if ( is_response ) {
message_generator . append ( " ) { }; " ) ;
} else {
message_generator . appendln ( " ) = 0; " ) ;
}
} ;
2021-05-02 19:54:34 +02:00
2022-02-22 19:24:30 +01:00
do_handle_message_decl ( message . name , message . inputs , false ) ;
}
2019-08-03 15:50:16 +02:00
2022-02-22 19:24:30 +01:00
generator . appendln ( R " ~~~(
2020-10-11 19:57:53 +02:00
private :
} ;
2021-07-05 19:00:43 +02:00
2022-10-04 15:04:13 -04:00
# if defined(AK_COMPILER_CLANG)
2021-07-05 19:00:43 +02:00
# pragma clang diagnostic pop
2022-02-22 19:24:30 +01:00
# endif)~~~");
}
void build ( StringBuilder & builder , Vector < Endpoint > const & endpoints )
{
SourceGenerator generator { builder } ;
generator . appendln ( " #pragma once " ) ;
// This must occur before LibIPC/Decoder.h
for ( auto const & endpoint : endpoints ) {
for ( auto const & include : endpoint . includes ) {
generator . appendln ( include ) ;
}
}
2023-01-14 22:04:55 +01:00
generator . appendln ( R " ~~~(#include <AK/Error.h>
2023-01-25 20:19:05 +01:00
# include <AK/MemoryStream.h>
2022-02-22 19:24:30 +01:00
# include <AK/OwnPtr.h>
# include <AK/Result.h>
# include <AK/Utf8View.h>
# include <LibIPC/Connection.h>
# include <LibIPC/Decoder.h>
# include <LibIPC/Encoder.h>
# include <LibIPC/File.h>
# include <LibIPC/Message.h>
# include <LibIPC/Stub.h>
2022-10-04 15:04:13 -04:00
# if defined(AK_COMPILER_CLANG)
2022-02-22 19:24:30 +01:00
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdefaulted-function-deleted"
# endif)~~~");
for ( auto const & endpoint : endpoints )
2023-08-21 16:42:48 +02:00
build_endpoint ( generator . fork ( ) , endpoint ) ;
2022-02-22 19:24:30 +01:00
}
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
2023-04-24 03:00:34 -06:00
StringView ipc_file ;
StringView output_file = " - " sv ;
Core : : ArgsParser parser ;
parser . add_positional_argument ( ipc_file , " IPC endpoint definition file " , " input " ) ;
parser . add_option ( output_file , " Place to write file " , " output " , ' o ' , " output-file " ) ;
parser . parse ( arguments ) ;
auto output = TRY ( Core : : File : : open_file_or_standard_stream ( output_file , Core : : File : : OpenMode : : Write ) ) ;
2019-08-03 15:50:16 +02:00
2023-04-24 03:00:34 -06:00
auto file = TRY ( Core : : File : : open ( ipc_file , Core : : File : : OpenMode : : Read ) ) ;
2022-02-22 19:24:30 +01:00
2022-12-11 17:49:00 +01:00
auto file_contents = TRY ( file - > read_until_eof ( ) ) ;
2022-02-22 19:24:30 +01:00
auto endpoints = parse ( file_contents ) ;
StringBuilder builder ;
build ( builder , endpoints ) ;
2023-04-24 03:00:34 -06:00
TRY ( output - > write_until_depleted ( builder . string_view ( ) . bytes ( ) ) ) ;
2020-10-11 19:57:53 +02:00
2021-07-12 01:32:46 -06:00
if constexpr ( GENERATE_DEBUG ) {
for ( auto & endpoint : endpoints ) {
warnln ( " Endpoint '{}' (magic: {}) " , endpoint . name , endpoint . magic ) ;
for ( auto & message : endpoint . messages ) {
warnln ( " Message: '{}' " , message . name ) ;
warnln ( " Sync: {} " , message . is_synchronous ) ;
warnln ( " Inputs: " ) ;
for ( auto & parameter : message . inputs )
2020-10-11 19:57:53 +02:00
warnln ( " Parameter: {} ({}) " , parameter . name , parameter . type ) ;
2021-07-12 01:32:46 -06:00
if ( message . inputs . is_empty ( ) )
2020-10-11 19:57:53 +02:00
warnln ( " (none) " ) ;
2021-07-12 01:32:46 -06:00
if ( message . is_synchronous ) {
warnln ( " Outputs: " ) ;
for ( auto & parameter : message . outputs )
warnln ( " Parameter: {} ({}) " , parameter . name , parameter . type ) ;
if ( message . outputs . is_empty ( ) )
warnln ( " (none) " ) ;
}
2019-08-03 15:15:11 +02:00
}
}
}
2022-02-22 19:24:30 +01:00
return 0 ;
2019-08-03 15:15:11 +02:00
}