2023-07-06 02:29:36 +03:30
/*
* Copyright ( c ) 2022 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
* Copyright ( c ) 2023 , Ali Mohammad Pur < mpfard @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "GeneratorUtil.h"
# include <AK/GenericLexer.h>
# include <AK/SourceGenerator.h>
# include <LibCore/ArgsParser.h>
# include <LibMain/Main.h>
ErrorOr < void > generate_header_file ( JsonObject & , Core : : File & ) ;
ErrorOr < void > generate_implementation_file ( JsonObject & , Core : : File & ) ;
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
StringView generated_header_path ;
StringView generated_implementation_path ;
StringView functions_json_path ;
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the EasingFunctions header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the EasingFunctions implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
args_parser . add_option ( functions_json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
args_parser . parse ( arguments ) ;
auto json = TRY ( read_entire_file_as_json ( functions_json_path ) ) ;
VERIFY ( json . is_object ( ) ) ;
auto easing_data = json . as_object ( ) ;
auto generated_header_file = TRY ( Core : : File : : open ( generated_header_path , Core : : File : : OpenMode : : Write ) ) ;
auto generated_implementation_file = TRY ( Core : : File : : open ( generated_implementation_path , Core : : File : : OpenMode : : Write ) ) ;
TRY ( generate_header_file ( easing_data , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( easing_data , * generated_implementation_file ) ) ;
return 0 ;
}
ErrorOr < void > generate_header_file ( JsonObject & easing_data , Core : : File & file )
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
# pragma once
# include <AK/Optional.h>
# include <AK/StringView.h>
# include <AK/Vector.h>
namespace Web : : CSS {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
2023-08-21 16:06:29 +02:00
generator . appendln ( " enum class EasingFunction { " ) ;
2023-08-22 09:09:07 +02:00
easing_data . for_each_member ( [ & ] ( auto & name , auto & ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
2023-08-21 16:06:29 +02:00
member_generator . appendln ( " @name:titlecase@, " ) ;
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:06:29 +02:00
generator . appendln ( " }; " ) ;
2023-07-06 02:29:36 +03:30
2023-08-21 16:06:29 +02:00
generator . appendln ( " Optional<EasingFunction> easing_function_from_string(StringView); " ) ;
generator . appendln ( " StringView to_string(EasingFunction); " ) ;
2023-07-06 02:29:36 +03:30
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
enum class EasingFunctionParameterType {
Integer ,
Number ,
NumberZeroToOne ,
StepPosition ,
} ;
struct EasingFunctionParameter {
EasingFunctionParameterType type ;
bool is_optional { false } ;
} ;
struct EasingFunctionMetadata {
Vector < EasingFunctionParameter > parameters ;
} ;
EasingFunctionMetadata easing_function_metadata ( EasingFunction ) ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
2023-08-21 16:06:29 +02:00
generator . appendln ( " \n } " ) ;
2023-07-06 02:29:36 +03:30
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
return { } ;
}
ErrorOr < void > generate_implementation_file ( JsonObject & easing_data , Core : : File & file )
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
# include <LibWeb/CSS/EasingFunctions.h>
# include <AK/Assertions.h>
namespace Web : : CSS {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
Optional < EasingFunction > easing_function_from_string ( StringView name )
{
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
easing_data . for_each_member ( [ & ] ( auto & name , auto & ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-22 09:09:07 +02:00
member_generator . set ( " name " , name ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
if ( name . equals_ignoring_ascii_case ( " @name@ " sv ) )
return EasingFunction : : @ name : titlecase @ ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
return { } ;
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
StringView to_string ( EasingFunction easing_function )
{
switch ( easing_function ) {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
easing_data . for_each_member ( [ & ] ( auto & name , auto & ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-22 09:09:07 +02:00
member_generator . set ( " name " , name ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
case EasingFunction : : @ name : titlecase @ :
return " @name@ " sv ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
EasingFunctionMetadata easing_function_metadata ( EasingFunction easing_function )
{
switch ( easing_function ) {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
easing_data . for_each_member ( [ & ] ( auto & name , auto & value ) {
2023-07-06 02:29:36 +03:30
VERIFY ( value . is_object ( ) ) ;
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
case EasingFunction : : @ name : titlecase @ :
return EasingFunctionMetadata {
2023-08-21 16:39:43 +02:00
. parameters = { ) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
if ( auto parameters = value . as_object ( ) . get_array ( " parameters " sv ) ; parameters . has_value ( ) ) {
bool first = true ;
// parameters: [ "<foo>", "<foo [0, 1]>" ]
2023-08-22 09:09:07 +02:00
parameters . value ( ) . for_each ( [ & ] ( JsonValue const & value ) {
2023-07-06 02:29:36 +03:30
GenericLexer lexer { value . as_string ( ) } ;
VERIFY ( lexer . consume_specific ( ' < ' ) ) ;
auto parameter_type_name = lexer . consume_until ( [ ] ( char ch ) { return ch = = ' ' | | ch = = ' > ' ; } ) ;
auto has_bounds = false ;
auto is_optional = false ;
if ( lexer . consume_specific ( " [ " ) ) {
has_bounds = true ;
auto contents = lexer . consume_until ( ' ] ' ) ;
VERIFY ( contents = = " 0, 1 " sv ) ;
VERIFY ( lexer . consume_specific ( ' ] ' ) ) ;
}
VERIFY ( lexer . consume_specific ( ' > ' ) ) ;
if ( lexer . consume_specific ( ' ? ' ) )
is_optional = true ;
StringView parameter_type = " " sv ;
if ( parameter_type_name = = " number " sv )
parameter_type = has_bounds ? " NumberZeroToOne " sv : " Number " sv ;
else if ( parameter_type_name = = " integer " sv )
parameter_type = " Integer " sv ;
else if ( parameter_type_name = = " step-position " sv )
parameter_type = " StepPosition " sv ;
else
VERIFY_NOT_REACHED ( ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( first ? " " sv : " , " sv ) ;
2023-07-06 02:29:36 +03:30
first = false ;
2023-08-22 09:09:07 +02:00
member_generator . append ( MUST ( String : : formatted (
2023-07-06 02:29:36 +03:30
" {{ EasingFunctionParameterType::{}, {} }} " ,
parameter_type ,
2023-08-21 16:39:43 +02:00
is_optional ? " true " sv : " false " sv ) ) ) ;
2023-08-22 09:09:07 +02:00
} ) ;
2023-07-06 02:29:36 +03:30
}
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~( }
2023-07-06 02:29:36 +03:30
} ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-06 02:29:36 +03:30
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-06 02:29:36 +03:30
2023-08-21 16:06:29 +02:00
generator . appendln ( " \n } " ) ;
2023-07-06 02:29:36 +03:30
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
return { } ;
}