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>
2022-09-12 15:39:04 +01:00
# include <LibCore/Stream.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 {
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > attributes ;
DeprecatedString type ;
DeprecatedString name ;
2019-08-03 15:15:11 +02:00
} ;
2022-12-04 18:02:33 +00:00
static DeprecatedString pascal_case ( DeprecatedString 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 ) ;
}
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2021-05-03 15:52:56 +02:00
}
2019-08-03 15:15:11 +02:00
struct Message {
2022-12-04 18:02:33 +00:00
DeprecatedString 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
2022-12-04 18:02:33 +00:00
DeprecatedString 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 ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2019-08-03 17:03:16 +02:00
}
2019-08-03 15:15:11 +02:00
} ;
struct Endpoint {
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > includes ;
DeprecatedString name ;
2021-04-25 13:19:53 +02:00
u32 magic ;
2019-08-03 15:15:11 +02:00
Vector < Message > messages ;
} ;
2022-12-04 18:02:33 +00:00
static bool is_primitive_type ( DeprecatedString const & type )
2021-05-03 08:46:40 +02:00
{
2021-05-13 15:35:05 +02:00
return type . is_one_of ( " u8 " , " i8 " , " u16 " , " i16 " , " u32 " , " i32 " , " u64 " , " i64 " , " bool " , " double " , " float " , " int " , " unsigned " , " unsigned int " ) ;
2021-05-03 08:46:40 +02:00
}
2022-12-06 19:43:46 +00:00
static bool is_simple_type ( DeprecatedString const & type )
{
// Small types that it makes sense just to pass by value.
2022-12-06 21:35:32 +00:00
return type . is_one_of ( " Gfx::Color " , " Gfx::IntPoint " , " Gfx::FloatPoint " , " Gfx::IntSize " ) ;
2022-12-06 19:43:46 +00:00
}
static bool is_primitive_or_simple_type ( DeprecatedString const & type )
{
return is_primitive_type ( type ) | | is_simple_type ( type ) ;
}
2022-12-04 18:02:33 +00:00
static DeprecatedString message_name ( DeprecatedString const & endpoint , DeprecatedString 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 ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_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 ) = = ' / ' )
lexer . ignore_until ( [ ] ( char ch ) { return ch = = ' \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 ( ) ;
}
}
2022-12-04 18:02:33 +00:00
// FIXME: This is not entirely correct. Types can have spaces, for example `HashMap<int, DeprecatedString>`.
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 ) ; } ) ;
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 = [ & ] {
2022-12-04 18:02:33 +00:00
DeprecatedString 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 ( ) ;
2020-08-21 09:18:10 -04:00
lexer . consume_specific ( " endpoint " ) ;
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 ) ; } ) ;
2022-12-04 18:02:33 +00:00
endpoints . last ( ) . magic = Traits < DeprecatedString > : : 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
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , int > build_message_ids_for_endpoint ( SourceGenerator generator , Endpoint const & endpoint )
2022-02-22 19:24:30 +01:00
{
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , 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 ) ) ;
2022-12-04 18:02:33 +00:00
generator . set ( " message.id " , DeprecatedString : : 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 ( ) ) ) ;
2022-12-04 18:02:33 +00:00
generator . set ( " message.id " , DeprecatedString : : 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
2022-12-04 18:02:33 +00:00
DeprecatedString constructor_for_message ( DeprecatedString 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 ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_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 ) ;
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_string ( ) ;
2022-02-22 19:24:30 +01:00
}
2019-08-03 16:35:49 +02:00
2022-12-04 18:02:33 +00:00
void do_message ( SourceGenerator message_generator , DeprecatedString const & name , Vector < Parameter > const & parameters , DeprecatedString 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
2022-02-22 19:24:30 +01:00
if ( ! response_type . is_null ( ) )
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
2022-01-14 13:12:49 +00:00
static OwnPtr < @ message . pascal_name @ > decode ( InputMemoryStream & stream , Core : : Stream : : 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 ) {
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 " ~~~(
2020-10-11 19:57:53 +02:00
@ parameter . type @ @ parameter . name @ = @ parameter . initial_value @ ;
2021-11-28 11:56:31 +01:00
if ( decoder . decode ( @ parameter . name @ ) . is_error ( ) )
2022-02-22 19:24:30 +01:00
return { } ; ) ~ ~ ~ " );
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-02-22 19:24:30 +01:00
return { } ; ) ~ ~ ~ " );
}
}
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
2022-02-22 19:24:30 +01:00
message_generator . set ( " message.constructor_call_parameters " , builder . build ( ) ) ;
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
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
2020-10-11 19:57:53 +02:00
virtual IPC : : MessageBuffer encode ( ) const override
{
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 ) ;
stream < < endpoint_magic ( ) ;
2022-02-22 19:24:30 +01:00
stream < < ( 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 ) {
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 " ~~~(
stream < < 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
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 ) {
auto parameter_generator = message_generator . fork ( ) ;
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 ) {
auto parameter_generator = message_generator . fork ( ) ;
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 )
{
2022-12-04 18:02:33 +00:00
auto do_implement_proxy = [ & ] ( DeprecatedString const & name , Vector < Parameter > const & parameters , bool is_synchronous , bool is_try ) {
DeprecatedString 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 ) ;
}
2022-12-04 18:02:33 +00:00
DeprecatedString inner_return_type = return_type ;
2022-02-22 19:24:30 +01:00
if ( is_try )
2022-12-04 18:02:33 +00:00
return_type = DeprecatedString : : 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 ] ;
auto argument_generator = message_generator . fork ( ) ;
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 ] ;
auto argument_generator = message_generator . fork ( ) ;
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 " ~~~();
2021-05-03 16:51:42 +02:00
if ( ! result )
2022-02-22 19:24:30 +01:00
return IPC : : ErrorCode : : PeerDisconnected ; ) ~ ~ ~ " );
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 ) ;
2022-12-04 18:02:33 +00:00
generator . set ( " endpoint.magic " , DeprecatedString : : number ( endpoint . magic ) ) ;
2022-02-22 19:24:30 +01:00
generator . appendln ( " \n namespace Messages::@endpoint.name@ { " ) ;
2022-12-04 18:02:33 +00:00
HashMap < DeprecatedString , 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 ) {
2022-12-04 18:02:33 +00:00
DeprecatedString response_name ;
2022-02-22 19:24:30 +01:00
if ( message . is_synchronous ) {
response_name = message . response_name ( ) ;
do_message ( generator . fork ( ) , response_name , message . outputs ) ;
2021-05-03 08:46:40 +02:00
}
2022-02-22 19:24:30 +01:00
do_message ( generator . fork ( ) , message . name , message . inputs , response_name ) ;
}
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 )
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-02-22 19:24:30 +01:00
generator . appendln ( 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
2022-01-14 13:12:49 +00:00
static OwnPtr < IPC : : Message > decode_message ( ReadonlyBytes buffer , [[maybe_unused]] Core : : Stream : : LocalSocket & socket )
2020-10-11 19:57:53 +02:00
{
InputMemoryStream stream { buffer } ;
2021-04-25 13:19:53 +02:00
u32 message_endpoint_magic = 0 ;
2020-10-11 19:57:53 +02:00
stream > > message_endpoint_magic ;
2022-02-22 19:24:30 +01:00
if ( stream . handle_any_error ( ) ) { ) ~ ~ ~ " );
if constexpr ( GENERATE_DEBUG ) {
generator . appendln ( R " ~~~(
dbgln ( \ " Failed to read message endpoint magic \" ))~~~ " ) ;
}
generator . appendln ( R " ~~~(
2021-01-10 16:29:28 -07:00
return { } ;
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 ) {
generator . appendln ( R " ~~~(
dbgln ( \ " @endpoint.name@: Endpoint magic number message_endpoint_magic != @endpoint.magic@, not my message! (the other endpoint may have handled it) \" ))~~~ " ) ;
}
generator . appendln ( R " ~~~(
2021-01-10 16:29:28 -07:00
return { } ;
2020-10-11 19:57:53 +02:00
}
i32 message_id = 0 ;
stream > > message_id ;
2022-02-22 19:24:30 +01:00
if ( stream . handle_any_error ( ) ) { ) ~ ~ ~ " );
if constexpr ( GENERATE_DEBUG ) {
generator . appendln ( R " ~~~(
dbgln ( \ " Failed to read message ID \" ))~~~ " ) ;
}
generator . appendln ( R " ~~~(
2021-01-10 16:29:28 -07:00
return { } ;
2020-10-11 19:57:53 +02:00
}
OwnPtr < IPC : : Message > message ;
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 ) {
2022-12-04 18:02:33 +00:00
auto do_decode_message = [ & ] ( DeprecatedString const & name ) {
2022-02-22 19:24:30 +01: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-02-22 19:24:30 +01:00
message_generator . appendln ( R " ~~~(
2021-05-03 15:52:56 +02:00
case ( int ) Messages : : @ endpoint . name @ : : MessageID : : @ message . pascal_name @ :
2022-01-14 13:12:49 +00:00
message = Messages : : @ endpoint . name @ : : @ message . pascal_name @ : : decode ( stream , socket ) ;
2022-02-22 19:24:30 +01:00
break ; ) ~ ~ ~ " );
} ;
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-02-22 19:24:30 +01:00
generator . appendln ( R " ~~~(
default : ) ~ ~ ~ " );
if constexpr ( GENERATE_DEBUG ) {
generator . appendln ( R " ~~~(
dbgln ( \ " Failed to decode @endpoint.name@.({}) \" , message_id))~~~ " ) ;
}
generator . appendln ( R " ~~~(
2021-01-10 16:29:28 -07:00
return { } ;
2020-10-11 19:57:53 +02:00
}
2020-04-06 10:12:10 +02:00
2022-02-22 19:24:30 +01:00
if ( stream . handle_any_error ( ) ) { ) ~ ~ ~ " );
if constexpr ( GENERATE_DEBUG ) {
generator . appendln ( R " ~~~(
dbgln ( \ " Failed to read the message \" );)~~~ " ) ;
}
generator . appendln ( R " ~~~(
2021-01-10 16:29:28 -07:00
return { } ;
2020-10-11 19:57:53 +02:00
}
return message ;
}
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 @ ; }
2022-12-04 18:02:33 +00:00
virtual DeprecatedString name ( ) const override { return " @endpoint.name@ " ; }
2021-05-03 08:46:40 +02:00
2021-05-02 04:39:36 +02:00
virtual 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 ) {
2022-12-04 18:02:33 +00:00
auto do_handle_message = [ & ] ( DeprecatedString const & name , Vector < Parameter > const & parameters , bool returns_something ) {
2022-02-22 19:24:30 +01: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 ) ;
2022-12-06 01:12:49 +00:00
message_generator . set ( " arguments " , argument_generator . to_deprecated_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 @ { } ;
2022-02-22 19:24:30 +01:00
return make < IPC : : MessageBuffer > ( response . encode ( ) ) ; ) ~ ~ ~ " );
} 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 ( ) )
return { } ;
2022-02-22 19:24:30 +01:00
return make < IPC : : MessageBuffer > ( response . encode ( ) ) ; ) ~ ~ ~ " );
}
} 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 @ ) ;
2022-02-22 19:24:30 +01:00
return { } ; ) ~ ~ ~ " );
}
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 :
2021-01-10 16:29:28 -07:00
return { } ;
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 ) {
auto message_generator = generator . fork ( ) ;
2020-10-11 19:57:53 +02:00
2022-12-04 18:02:33 +00:00
auto do_handle_message_decl = [ & ] ( DeprecatedString const & name , Vector < Parameter > const & parameters , bool is_response ) {
DeprecatedString 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 @ ( ) ~ ~ ~ " );
2022-12-04 18:02:33 +00:00
auto make_argument_type = [ ] ( DeprecatedString 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
2022-12-06 01:12:49 +00:00
return builder . to_deprecated_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 ] ;
auto argument_generator = message_generator . fork ( ) ;
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 ) ;
}
}
generator . appendln ( R " ~~~(#include <AK/MemoryStream.h>
# include <AK/OwnPtr.h>
# include <AK/Result.h>
# include <AK/Utf8View.h>
# include <LibIPC/Connection.h>
# include <LibIPC/Decoder.h>
# include <LibIPC/Dictionary.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 )
build_endpoint ( generator . fork ( ) , endpoint ) ;
}
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
if ( arguments . argc ! = 2 ) {
outln ( " usage: {} <IPC endpoint definition file> " , arguments . strings [ 0 ] ) ;
return 1 ;
2019-08-03 15:50:16 +02:00
}
2022-09-12 15:39:04 +01:00
auto file = TRY ( Core : : Stream : : File : : open ( arguments . strings [ 1 ] , Core : : Stream : : OpenMode : : Read ) ) ;
2022-02-22 19:24:30 +01:00
2022-09-12 15:39:04 +01:00
auto file_contents = TRY ( file - > read_all ( ) ) ;
2022-02-22 19:24:30 +01:00
auto endpoints = parse ( file_contents ) ;
StringBuilder builder ;
build ( builder , endpoints ) ;
outln ( " {} " , builder . string_view ( ) ) ;
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
}