2023-07-13 14:59:31 +01:00
/*
* Copyright ( c ) 2022 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "GeneratorUtil.h"
# include <AK/SourceGenerator.h>
# include <AK/StringBuilder.h>
# include <LibCore/ArgsParser.h>
# include <LibMain/Main.h>
2024-07-14 18:29:33 +02:00
namespace {
2025-05-13 07:06:33 -04:00
2023-07-13 14:59:31 +01:00
ErrorOr < void > generate_header_file ( JsonObject & functions_data , Core : : File & file )
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
// This file is generated by GenerateCSSMathFunctions.cpp
# pragma once
2025-08-21 16:13:30 +01:00
# include <AK/Optional.h>
# include <AK/StringView.h>
2023-07-13 14:59:31 +01:00
namespace Web : : CSS {
enum class MathFunction {
2025-08-21 16:13:30 +01:00
Calc ,
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
2023-08-22 09:09:07 +02:00
functions_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@, " sv ) ;
2023-08-22 09:09:07 +02:00
} ) ;
2023-07-13 14:59:31 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
} ;
2025-08-21 16:13:30 +01:00
Optional < MathFunction > math_function_from_string ( StringView ) ;
2023-07-13 14:59:31 +01:00
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
return { } ;
}
2023-08-22 09:09:07 +02:00
String generate_calculation_type_check ( StringView calculation_variable_name , StringView parameter_types )
2023-07-13 14:59:31 +01:00
{
StringBuilder builder ;
auto allowed_types = parameter_types . split_view ( ' | ' ) ;
bool first_type_check = true ;
for ( auto const & allowed_type_name : allowed_types ) {
if ( ! first_type_check )
2023-08-21 16:39:43 +02:00
builder . append ( " || " sv ) ;
2023-07-13 14:59:31 +01:00
first_type_check = false ;
if ( allowed_type_name = = " <angle> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_angle(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <dimension> " sv ) {
2023-08-22 09:09:07 +02:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_dimension() " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <flex> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_flex(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <frequency> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_frequency(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <length> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_length(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <number> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_number(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <percentage> " sv ) {
2023-08-22 09:09:07 +02:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_percentage() " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <resolution> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_resolution(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else if ( allowed_type_name = = " <time> " sv ) {
2025-01-09 17:23:20 +00:00
builder . appendff ( " {}.{} " , calculation_variable_name , " matches_time(percentages_resolve_as) " sv ) ;
2023-07-13 14:59:31 +01:00
} else {
dbgln ( " I don't know what '{}' is! " , allowed_type_name ) ;
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-22 09:09:07 +02:00
return MUST ( builder . to_string ( ) ) ;
2023-07-13 14:59:31 +01:00
}
ErrorOr < void > generate_implementation_file ( JsonObject & functions_data , Core : : File & file )
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
// This file is generated by GenerateCSSMathFunctions.cpp
2025-08-21 16:13:30 +01:00
# include <LibWeb/CSS/Enums.h>
2023-07-13 14:59:31 +01:00
# include <LibWeb/CSS/MathFunctions.h>
2025-07-23 11:04:17 +01:00
# include <LibWeb/CSS/Parser/ErrorReporter.h>
2023-07-13 14:59:31 +01:00
# include <LibWeb/CSS/Parser/Parser.h>
2024-12-11 15:05:56 +00:00
# include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
2023-07-13 14:59:31 +01:00
2025-08-21 16:13:30 +01:00
namespace Web : : CSS {
Optional < MathFunction > math_function_from_string ( StringView name )
{
if ( name . equals_ignoring_ascii_case ( " calc " sv ) )
return MathFunction : : Calc ;
) ~ ~ ~ " );
functions_data . for_each_member ( [ & ] ( auto & name , auto & ) {
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:lowercase " , name ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
if ( name . equals_ignoring_ascii_case ( " @name:lowercase@ " sv ) )
return MathFunction : : @ name : titlecase @ ;
) ~ ~ ~ " );
} ) ;
generator . append ( R " ~~~(
return { } ;
}
}
2023-07-13 14:59:31 +01:00
namespace Web : : CSS : : Parser {
static Optional < RoundingStrategy > parse_rounding_strategy ( Vector < ComponentValue > const & tokens )
{
auto stream = TokenStream { tokens } ;
2024-10-09 12:29:29 +01:00
stream . discard_whitespace ( ) ;
2023-07-13 14:59:31 +01:00
if ( ! stream . has_next_token ( ) )
return { } ;
2024-10-09 12:29:29 +01:00
auto & ident = stream . consume_a_token ( ) ;
2023-07-13 14:59:31 +01:00
if ( ! ident . is ( Token : : Type : : Ident ) )
return { } ;
2024-10-09 12:29:29 +01:00
stream . discard_whitespace ( ) ;
2023-07-13 14:59:31 +01:00
if ( stream . has_next_token ( ) )
return { } ;
2024-08-14 14:06:03 +01:00
auto maybe_keyword = keyword_from_string ( ident . token ( ) . ident ( ) ) ;
if ( ! maybe_keyword . has_value ( ) )
2023-07-13 14:59:31 +01:00
return { } ;
2024-08-14 14:06:03 +01:00
return keyword_to_rounding_strategy ( maybe_keyword . value ( ) ) ;
2023-07-13 14:59:31 +01:00
}
2025-04-15 15:21:37 -06:00
RefPtr < CalculationNode const > Parser : : parse_math_function ( Function const & function , CalculationContext const & context )
2023-07-13 14:59:31 +01:00
{
2024-10-11 11:17:10 +01:00
TokenStream stream { function . value } ;
2023-07-13 14:59:31 +01:00
auto arguments = parse_a_comma_separated_list_of_component_values ( stream ) ;
2025-01-09 17:23:20 +00:00
auto const & percentages_resolve_as = context . percentages_resolve_as ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
2023-08-22 09:09:07 +02:00
functions_data . for_each_member ( [ & ] ( auto & name , JsonValue const & value ) - > void {
2023-07-13 14:59:31 +01:00
auto & function_data = value . as_object ( ) ;
auto & parameters = function_data . get_array ( " parameters " sv ) . value ( ) ;
2025-02-17 15:04:56 -05:00
auto parameter_validation_rule = function_data . get_string ( " parameter-validation " sv ) ;
2024-12-18 13:15:26 +00:00
bool requires_same_parameters = parameter_validation_rule . has_value ( ) ? ( parameter_validation_rule = = " same " sv ) : true ;
2023-07-13 14:59:31 +01:00
2023-08-21 16:42:48 +02:00
auto function_generator = generator . fork ( ) ;
2023-08-22 09:09:07 +02:00
function_generator . set ( " name:lowercase " , name ) ;
2023-08-21 16:59:41 +02:00
function_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
2024-10-11 11:17:10 +01:00
function_generator . appendln ( " if (function.name.equals_ignoring_ascii_case( \" @name:lowercase@ \" sv)) { " ) ;
2023-07-13 14:59:31 +01:00
if ( function_data . get_bool ( " is-variadic " sv ) . value_or ( false ) ) {
// Variadic function
2023-08-21 16:39:43 +02:00
function_generator . append ( R " ~~~(
2025-08-15 12:55:58 +01:00
Optional < NumericType > determined_argument_type ;
2025-04-15 15:21:37 -06:00
Vector < NonnullRefPtr < CalculationNode const > > parsed_arguments ;
2023-08-19 15:20:23 +01:00
parsed_arguments . ensure_capacity ( arguments . size ( ) ) ;
2023-07-13 14:59:31 +01:00
for ( auto & argument : arguments ) {
2025-01-08 16:14:17 +00:00
auto calculation_node = parse_a_calculation ( argument , context ) ;
2023-07-13 14:59:31 +01:00
if ( ! calculation_node ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument #{} is not a valid calculation. " , parsed_arguments . size ( ) ) ) ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
2024-12-18 13:15:26 +00:00
auto maybe_argument_type = calculation_node - > numeric_type ( ) ;
2023-07-13 14:59:31 +01:00
if ( ! maybe_argument_type . has_value ( ) ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument #{} couldn't determine its type. " , parsed_arguments . size ( ) ) ) ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
auto argument_type = maybe_argument_type . release_value ( ) ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
// Generate some type checks
VERIFY ( parameters . size ( ) = = 1 ) ;
auto & parameter_data = parameters [ 0 ] . as_object ( ) ;
2025-02-17 15:04:56 -05:00
auto parameter_type_string = parameter_data . get_string ( " type " sv ) . value ( ) ;
2023-08-22 09:09:07 +02:00
function_generator . set ( " type_check " , generate_calculation_type_check ( " argument_type " sv , parameter_type_string ) ) ;
2023-08-21 16:39:43 +02:00
function_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
if ( ! ( @ type_check @ ) ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument #{} type ({}) is not an accepted type. " , parsed_arguments . size ( ) , argument_type . dump ( ) ) ) ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
2024-12-18 13:15:26 +00:00
if ( ! determined_argument_type . has_value ( ) ) {
2023-07-13 14:59:31 +01:00
determined_argument_type = move ( argument_type ) ;
} else {
2024-12-18 13:15:26 +00:00
) ~ ~ ~ " );
if ( requires_same_parameters ) {
function_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
if ( determined_argument_type ! = argument_type ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument #{} type ({}) doesn't match type of previous arguments ({}). " , parsed_arguments . size ( ) , argument_type . dump ( ) , determined_argument_type - > dump ( ) ) ) ,
} ) ;
2024-12-18 13:15:26 +00:00
return nullptr ;
}
) ~ ~ ~ " );
} else {
function_generator . append ( R " ~~~(
if ( auto consistent_type = determined_argument_type - > consistent_type ( argument_type ) ; consistent_type . has_value ( ) ) {
determined_argument_type = consistent_type . release_value ( ) ;
} else {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument #{} type ({}) is not consistent with type of previous arguments ({}). " , parsed_arguments . size ( ) , argument_type . dump ( ) , determined_argument_type - > dump ( ) ) ) ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
2024-12-18 13:15:26 +00:00
) ~ ~ ~ " );
}
function_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
}
2023-08-19 15:20:23 +01:00
parsed_arguments . append ( calculation_node . release_nonnull ( ) ) ;
2023-07-13 14:59:31 +01:00
}
return @ name : titlecase @ CalculationNode : : create ( move ( parsed_arguments ) ) ;
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
} else {
// Function with specified parameters.
size_t min_argument_count = 0 ;
size_t max_argument_count = parameters . size ( ) ;
parameters . for_each ( [ & ] ( JsonValue const & parameter_value ) {
auto & parameter = parameter_value . as_object ( ) ;
if ( parameter . get_bool ( " required " sv ) = = true )
min_argument_count + + ;
} ) ;
2024-10-14 10:05:01 +02:00
function_generator . set ( " min_argument_count " , String : : number ( min_argument_count ) ) ;
function_generator . set ( " max_argument_count " , String : : number ( max_argument_count ) ) ;
2023-07-13 14:59:31 +01:00
2023-08-21 16:39:43 +02:00
function_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
if ( arguments . size ( ) < @ min_argument_count @ | | arguments . size ( ) > @ max_argument_count @ ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Wrong number of arguments {}, expected between @min_argument_count@ and @max_argument_count@ inclusive. " , arguments . size ( ) ) ) ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
size_t argument_index = 0 ;
2025-08-15 12:55:58 +01:00
Optional < NumericType > determined_argument_type ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
size_t parameter_index = 0 ;
2023-08-22 09:09:07 +02:00
parameters . for_each ( [ & ] ( JsonValue const & parameter_value ) {
2023-07-13 14:59:31 +01:00
auto & parameter = parameter_value . as_object ( ) ;
2025-02-17 15:04:56 -05:00
auto parameter_type_string = parameter . get_string ( " type " sv ) . value ( ) ;
2023-07-13 14:59:31 +01:00
auto parameter_required = parameter . get_bool ( " required " sv ) . value ( ) ;
2023-08-21 16:42:48 +02:00
auto parameter_generator = function_generator . fork ( ) ;
2025-02-17 15:04:56 -05:00
parameter_generator . set ( " parameter_name " , parameter . get_string ( " name " sv ) . value ( ) ) ;
2024-10-14 10:05:01 +02:00
parameter_generator . set ( " parameter_index " , String : : number ( parameter_index ) ) ;
2023-07-13 14:59:31 +01:00
bool parameter_is_calculation ;
if ( parameter_type_string = = " <rounding-strategy> " ) {
parameter_is_calculation = false ;
2023-08-21 14:38:55 +02:00
parameter_generator . set ( " parameter_type " , " RoundingStrategy " _string ) ;
parameter_generator . set ( " parse_function " , " parse_rounding_strategy(arguments[argument_index]) " _string ) ;
parameter_generator . set ( " check_function " , " .has_value() " _string ) ;
parameter_generator . set ( " release_function " , " .release_value() " _string ) ;
2025-02-17 15:04:56 -05:00
if ( auto default_value = parameter . get_string ( " default " sv ) ; default_value . has_value ( ) ) {
2023-08-22 09:09:07 +02:00
parameter_generator . set ( " parameter_default " , MUST ( String : : formatted ( " = RoundingStrategy::{} " , title_casify ( default_value . value ( ) ) ) ) ) ;
2023-07-13 14:59:31 +01:00
} else {
2023-08-21 14:38:55 +02:00
parameter_generator . set ( " parameter_default " , " " _string ) ;
2023-07-13 14:59:31 +01:00
}
} else {
// NOTE: This assumes everything not handled above is a calculation node of some kind.
parameter_is_calculation = true ;
2025-04-15 15:21:37 -06:00
parameter_generator . set ( " parameter_type " , " RefPtr<CalculationNode const> " _string ) ;
2025-01-08 16:14:17 +00:00
parameter_generator . set ( " parse_function " , " parse_a_calculation(arguments[argument_index], context) " _string ) ;
2023-08-21 14:38:55 +02:00
parameter_generator . set ( " check_function " , " != nullptr " _string ) ;
parameter_generator . set ( " release_function " , " .release_nonnull() " _string ) ;
2023-07-13 14:59:31 +01:00
// NOTE: We have exactly one default value in the data right now, and it's a `<calc-constant>`,
// so that's all we handle.
2025-02-17 15:04:56 -05:00
if ( auto default_value = parameter . get_string ( " default " sv ) ; default_value . has_value ( ) ) {
2025-02-25 16:37:10 +00:00
parameter_generator . set ( " parameter_default " , MUST ( String : : formatted ( " = NumericCalculationNode::from_keyword(Keyword::{}, context) " , title_casify ( default_value . value ( ) ) ) ) ) ;
2023-07-13 14:59:31 +01:00
} else {
2023-08-21 14:38:55 +02:00
parameter_generator . set ( " parameter_default " , " " _string ) ;
2023-07-13 14:59:31 +01:00
}
}
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
@ parameter_type @ parameter_ @ parameter_index @ @ parameter_default @ ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
if ( parameter_required ) {
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
if ( argument_index > = arguments . size ( ) ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = " Missing required argument '@parameter_name@'. " _string ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
} else {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
} else {
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
if ( argument_index < arguments . size ( ) ) {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
}
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
auto maybe_parsed_argument_ @ parameter_index @ = @ parse_function @ ;
if ( maybe_parsed_argument_ @ parameter_index @ @ check_function @ ) {
parameter_ @ parameter_index @ = maybe_parsed_argument_ @ parameter_index @ @ release_function @ ;
argument_index + + ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
if ( parameter_required ) {
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
} else {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = " Failed to parse required argument '@parameter_name@'. " _string ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
}
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
if ( parameter_is_calculation ) {
2023-08-22 09:09:07 +02:00
auto parameter_type_variable = MUST ( String : : formatted ( " argument_type_{} " , parameter_index ) ) ;
parameter_generator . set ( " type_check " , generate_calculation_type_check ( parameter_type_variable , parameter_type_string ) ) ;
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2024-12-18 13:15:26 +00:00
auto maybe_argument_type_ @ parameter_index @ = parameter_ @ parameter_index @ - > numeric_type ( ) ;
2023-07-13 14:59:31 +01:00
if ( ! maybe_argument_type_ @ parameter_index @ . has_value ( ) ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = " Argument '@parameter_name@' couldn't determine its type. " _string ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
auto argument_type_ @ parameter_index @ = maybe_argument_type_ @ parameter_index @ . release_value ( ) ;
if ( ! ( @ type_check @ ) ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument '@parameter_name@' type ({}) is not an accepted type. " , argument_type_ @ parameter_index @ . dump ( ) ) ) ,
} ) ;
2023-07-13 14:59:31 +01:00
return nullptr ;
}
2024-12-18 13:15:26 +00:00
if ( ! determined_argument_type . has_value ( ) ) {
determined_argument_type = argument_type_ @ parameter_index @ ;
} else {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
2024-12-18 13:15:26 +00:00
if ( requires_same_parameters ) {
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2024-12-18 13:15:26 +00:00
if ( determined_argument_type ! = argument_type_ @ parameter_index @ ) {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument '@parameter_name@' type ({}) doesn't match type of previous arguments ({}). " , argument_type_ @ parameter_index @ . dump ( ) , determined_argument_type - > dump ( ) ) ) ,
} ) ;
2024-12-18 13:15:26 +00:00
return nullptr ;
}
) ~ ~ ~ " );
} else {
parameter_generator . append ( R " ~~~(
if ( auto consistent_type = determined_argument_type - > consistent_type ( argument_type_ @ parameter_index @ ) ; consistent_type . has_value ( ) ) {
determined_argument_type = consistent_type . release_value ( ) ;
} else {
2025-07-23 11:04:17 +01:00
ErrorReporter : : the ( ) . report ( InvalidValueError {
. value_type = " @name:lowercase@() " _fly_string ,
. value_string = stream . dump_string ( ) ,
. description = MUST ( String : : formatted ( " Argument '@parameter_name@' type ({}) is not consistent with type of previous arguments ({}). " , argument_type_ @ parameter_index @ . dump ( ) , determined_argument_type - > dump ( ) ) ) ,
} ) ;
2024-12-18 13:15:26 +00:00
return nullptr ;
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
}
2023-08-21 16:39:43 +02:00
parameter_generator . append ( R " ~~~(
2024-12-18 13:15:26 +00:00
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
}
parameter_index + + ;
2023-08-22 09:09:07 +02:00
} ) ;
2023-07-13 14:59:31 +01:00
// Generate the call to the constructor
2023-08-21 16:39:43 +02:00
function_generator . append ( " return @name:titlecase@CalculationNode::create( " sv ) ;
2023-07-13 14:59:31 +01:00
parameter_index = 0 ;
2023-08-22 09:09:07 +02:00
parameters . for_each ( [ & ] ( JsonValue const & parameter_value ) {
2023-07-13 14:59:31 +01:00
auto & parameter = parameter_value . as_object ( ) ;
2025-02-17 15:04:56 -05:00
auto parameter_type_string = parameter . get_string ( " type " sv ) . value ( ) ;
2023-07-13 14:59:31 +01:00
2023-08-21 16:42:48 +02:00
auto parameter_generator = function_generator . fork ( ) ;
2024-10-14 10:05:01 +02:00
parameter_generator . set ( " parameter_index " sv , String : : number ( parameter_index ) ) ;
2023-07-13 14:59:31 +01:00
if ( parameter_type_string = = " <rounding-strategy> " sv ) {
2023-08-21 14:38:55 +02:00
parameter_generator . set ( " release_value " sv , " " _string ) ;
2023-07-13 14:59:31 +01:00
} else {
// NOTE: This assumes everything not handled above is a calculation node of some kind.
2023-08-21 14:38:55 +02:00
parameter_generator . set ( " release_value " sv , " .release_nonnull() " _string ) ;
2023-07-13 14:59:31 +01:00
}
if ( parameter_index = = 0 ) {
2023-08-21 16:39:43 +02:00
parameter_generator . append ( " parameter_@parameter_index@@release_value@ " sv ) ;
2023-07-13 14:59:31 +01:00
} else {
2023-08-21 16:39:43 +02:00
parameter_generator . append ( " , parameter_@parameter_index@@release_value@ " sv ) ;
2023-07-13 14:59:31 +01:00
}
parameter_index + + ;
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
function_generator . append ( R " ~~~();
2023-07-13 14:59:31 +01:00
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
}
2023-08-22 09:09:07 +02:00
} ) ;
2023-07-13 14:59:31 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-07-13 14:59:31 +01:00
return nullptr ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-07-13 14:59:31 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
return { } ;
}
2025-05-13 07:06:33 -04:00
2024-07-14 18:29:33 +02:00
} // end anonymous namespace
2025-07-08 12:14:08 +02:00
ErrorOr < int > ladybird_main ( Main : : Arguments arguments )
2024-07-14 18:29:33 +02:00
{
StringView generated_header_path ;
StringView generated_implementation_path ;
2024-08-14 14:06:03 +01:00
StringView json_path ;
2024-07-14 18:29:33 +02:00
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the MathFunctions header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the MathFunctions implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
2024-08-14 14:06:03 +01:00
args_parser . add_option ( json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
2024-07-14 18:29:33 +02:00
args_parser . parse ( arguments ) ;
2024-08-14 14:06:03 +01:00
auto json = TRY ( read_entire_file_as_json ( json_path ) ) ;
2024-07-14 18:29:33 +02:00
VERIFY ( json . is_object ( ) ) ;
auto math_functions_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 ( math_functions_data , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( math_functions_data , * generated_implementation_file ) ) ;
return 0 ;
}