2022-12-05 17:09:03 +01:00
/*
* Copyright ( c ) 2022 , Jelle Raaijmakers < jelle @ gmta . nl >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <AK/Array.h>
2023-12-16 17:49:34 +03:30
# include <AK/ByteString.h>
2022-12-05 17:09:03 +01:00
# include <AK/JsonObject.h>
# include <AK/NumericLimits.h>
# include <AK/Optional.h>
# include <AK/SourceGenerator.h>
# include <AK/StringBuilder.h>
# include <AK/StringView.h>
# include <AK/Vector.h>
# include <LibCore/ArgsParser.h>
2023-02-09 03:02:46 +01:00
# include <LibCore/File.h>
2022-12-05 17:09:03 +01:00
# include <LibMain/Main.h>
struct ArgumentDefinition {
2023-12-16 17:49:34 +03:30
Optional < ByteString > name ;
Optional < ByteString > cpp_type ;
ByteString expression ;
Optional < ByteString > cast_to ;
2022-12-05 17:09:03 +01:00
} ;
struct FunctionDefinition {
2023-12-16 17:49:34 +03:30
ByteString name ;
ByteString return_type ;
2022-12-05 17:09:03 +01:00
Vector < ArgumentDefinition > arguments ;
2023-12-16 17:49:34 +03:30
ByteString implementation ;
2022-12-05 17:09:03 +01:00
bool unimplemented ;
2023-12-16 17:49:34 +03:30
ByteString variant_gl_type ;
2022-12-05 17:09:03 +01:00
} ;
struct VariantType {
2023-12-16 17:49:34 +03:30
ByteString encoded_type ;
Optional < ByteString > implementation ;
2022-12-05 17:09:03 +01:00
bool unimplemented ;
} ;
struct Variants {
2023-12-16 17:49:34 +03:30
Vector < ByteString > api_suffixes { " " } ;
2022-12-05 17:09:03 +01:00
Vector < u32 > argument_counts { NumericLimits < u32 > : : max ( ) } ;
2023-12-16 17:49:34 +03:30
Vector < ByteString > argument_defaults { " " } ;
2022-12-05 17:09:03 +01:00
bool convert_range { false } ;
Vector < VariantType > types {
{
. encoded_type = " " ,
2023-12-16 17:49:34 +03:30
. implementation = Optional < ByteString > { } ,
2022-12-05 17:09:03 +01:00
. unimplemented = false ,
}
} ;
2023-12-16 17:49:34 +03:30
ByteString pointer_argument { " " } ;
2022-12-05 17:09:03 +01:00
} ;
struct EncodedTypeEntry {
StringView encoded_type ;
StringView cpp_type ;
StringView gl_type ;
} ;
// clang-format off
constexpr static Array < EncodedTypeEntry , 9 > type_definitions = {
EncodedTypeEntry { " b " sv , " GLbyte " sv , " GL_BYTE " sv } ,
EncodedTypeEntry { " d " sv , " GLdouble " sv , " GL_DOUBLE " sv } ,
EncodedTypeEntry { " f " sv , " GLfloat " sv , " GL_FLOAT " sv } ,
EncodedTypeEntry { " i " sv , " GLint " sv , " GL_INT " sv } ,
EncodedTypeEntry { " s " sv , " GLshort " sv , " GL_SHORT " sv } ,
EncodedTypeEntry { " ub " sv , " GLubyte " sv , " GL_UNSIGNED_BYTE " sv } ,
EncodedTypeEntry { " ui " sv , " GLuint " sv , " GL_UNSIGNED_INT " sv } ,
EncodedTypeEntry { " us " sv , " GLushort " sv , " GL_UNSIGNED_SHORT " sv } ,
EncodedTypeEntry { " x " sv , " GLfixed " sv , " GL_INT " sv } ,
} ;
// clang-format on
struct EncodedType {
EncodedTypeEntry type_entry ;
2023-12-16 17:49:34 +03:30
ByteString cpp_type ;
ByteString function_name_suffix ;
2022-12-05 17:09:03 +01:00
bool is_pointer ;
bool is_const_pointer ;
} ;
2023-12-16 17:49:34 +03:30
Vector < ByteString > get_name_list ( Optional < JsonValue const & > name_definition )
2022-12-05 17:09:03 +01:00
{
2022-12-21 14:37:27 +00:00
if ( ! name_definition . has_value ( ) | | name_definition - > is_null ( ) )
2022-12-05 17:09:03 +01:00
return { } ;
2023-12-16 17:49:34 +03:30
Vector < ByteString , 1 > names ;
2022-12-21 14:37:27 +00:00
if ( name_definition - > is_string ( ) ) {
names . append ( name_definition - > as_string ( ) ) ;
} else if ( name_definition - > is_array ( ) ) {
name_definition - > as_array ( ) . for_each ( [ & names ] ( auto & value ) {
2022-12-05 17:09:03 +01:00
VERIFY ( value . is_string ( ) ) ;
names . append ( value . as_string ( ) ) ;
} ) ;
} else {
VERIFY_NOT_REACHED ( ) ;
}
return names ;
}
2023-12-16 17:49:34 +03:30
Optional < EncodedType > get_encoded_type ( ByteString encoded_type )
2022-12-05 17:09:03 +01:00
{
bool is_const_pointer = ! encoded_type . ends_with ( ' ! ' ) ;
if ( ! is_const_pointer )
encoded_type = encoded_type . substring_view ( 0 , encoded_type . length ( ) - 1 ) ;
2023-12-16 17:49:34 +03:30
ByteString function_name_suffix = encoded_type ;
2022-12-05 17:09:03 +01:00
bool is_pointer = encoded_type . ends_with ( ' v ' ) ;
if ( is_pointer )
encoded_type = encoded_type . substring_view ( 0 , encoded_type . length ( ) - 1 ) ;
VERIFY ( is_const_pointer | | is_pointer ) ;
Optional < EncodedTypeEntry > type_definition ;
for ( size_t i = 0 ; i < type_definitions . size ( ) ; + + i ) {
if ( type_definitions [ i ] . encoded_type = = encoded_type ) {
type_definition = type_definitions [ i ] ;
break ;
}
}
if ( ! type_definition . has_value ( ) )
return { } ;
return EncodedType {
. type_entry = type_definition . value ( ) ,
2023-12-16 17:49:34 +03:30
. cpp_type = ByteString : : formatted (
2022-12-05 17:09:03 +01:00
" {}{}{} " ,
type_definition - > cpp_type ,
is_pointer & & is_const_pointer ? " const " : " " ,
is_pointer ? " * " : " " ) ,
. function_name_suffix = function_name_suffix ,
. is_pointer = is_pointer ,
. is_const_pointer = is_const_pointer ,
} ;
}
2023-12-16 17:49:34 +03:30
ByteString wrap_expression_in_range_conversion ( ByteString source_type , ByteString target_type , ByteString expression )
2022-12-05 17:09:03 +01:00
{
VERIFY ( target_type = = " GLfloat " | | target_type = = " GLdouble " ) ;
// No range conversion required
if ( source_type = = target_type | | source_type = = " GLdouble " )
return expression ;
if ( source_type = = " GLbyte " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " ({} + 128.) / 127.5 - 1. " , expression ) ;
2022-12-05 17:09:03 +01:00
else if ( source_type = = " GLfloat " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " static_cast<GLdouble>({}) " , expression ) ;
2022-12-05 17:09:03 +01:00
else if ( source_type = = " GLint " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " ({} + 2147483648.) / 2147483647.5 - 1. " , expression ) ;
2022-12-05 17:09:03 +01:00
else if ( source_type = = " GLshort " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " ({} + 32768.) / 32767.5 - 1. " , expression ) ;
2022-12-05 17:09:03 +01:00
else if ( source_type = = " GLubyte " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " {} / 255. " , expression ) ;
2022-12-05 17:09:03 +01:00
else if ( source_type = = " GLuint " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " {} / 4294967296. " , expression ) ;
2022-12-05 17:09:03 +01:00
else if ( source_type = = " GLushort " )
2023-12-16 17:49:34 +03:30
return ByteString : : formatted ( " {} / 65536. " , expression ) ;
2022-12-05 17:09:03 +01:00
VERIFY_NOT_REACHED ( ) ;
}
Variants read_variants_settings ( JsonObject const & variants_obj )
{
Variants variants ;
2022-12-21 14:37:27 +00:00
if ( variants_obj . has_array ( " argument_counts " sv ) ) {
2022-12-05 17:09:03 +01:00
variants . argument_counts . clear_with_capacity ( ) ;
2022-12-21 14:37:27 +00:00
variants_obj . get_array ( " argument_counts " sv ) - > for_each ( [ & ] ( auto const & argument_count_value ) {
2022-12-05 17:09:03 +01:00
variants . argument_counts . append ( argument_count_value . to_u32 ( ) ) ;
} ) ;
}
2022-12-21 14:37:27 +00:00
if ( variants_obj . has_array ( " argument_defaults " sv ) ) {
2022-12-05 17:09:03 +01:00
variants . argument_defaults . clear_with_capacity ( ) ;
2022-12-21 14:37:27 +00:00
variants_obj . get_array ( " argument_defaults " sv ) - > for_each ( [ & ] ( auto const & argument_default_value ) {
2022-12-05 17:09:03 +01:00
variants . argument_defaults . append ( argument_default_value . as_string ( ) ) ;
} ) ;
}
2022-12-21 14:37:27 +00:00
if ( variants_obj . has_bool ( " convert_range " sv ) ) {
variants . convert_range = variants_obj . get_bool ( " convert_range " sv ) . value ( ) ;
2022-12-05 17:09:03 +01:00
}
2022-12-21 14:37:27 +00:00
if ( variants_obj . has_array ( " api_suffixes " sv ) ) {
2022-12-05 17:09:03 +01:00
variants . api_suffixes . clear_with_capacity ( ) ;
2022-12-21 14:37:27 +00:00
variants_obj . get_array ( " api_suffixes " sv ) - > for_each ( [ & ] ( auto const & suffix_value ) {
2022-12-05 17:09:03 +01:00
variants . api_suffixes . append ( suffix_value . as_string ( ) ) ;
} ) ;
}
2022-12-21 14:37:27 +00:00
if ( variants_obj . has_string ( " pointer_argument " sv ) ) {
2023-12-16 17:49:34 +03:30
variants . pointer_argument = variants_obj . get_byte_string ( " pointer_argument " sv ) . value ( ) ;
2022-12-05 17:09:03 +01:00
}
2022-12-21 14:37:27 +00:00
if ( variants_obj . has_object ( " types " sv ) ) {
2022-12-05 17:09:03 +01:00
variants . types . clear_with_capacity ( ) ;
2022-12-21 14:37:27 +00:00
variants_obj . get_object ( " types " sv ) - > for_each_member ( [ & ] ( auto const & key , auto const & type_value ) {
2022-12-05 17:09:03 +01:00
auto const & type = type_value . as_object ( ) ;
variants . types . append ( VariantType {
. encoded_type = key ,
2023-12-16 17:49:34 +03:30
. implementation = type . get_byte_string ( " implementation " sv ) ,
2022-12-21 14:37:27 +00:00
. unimplemented = type . get_bool ( " unimplemented " sv ) . value_or ( false ) ,
2022-12-05 17:09:03 +01:00
} ) ;
} ) ;
}
return variants ;
}
Vector < ArgumentDefinition > copy_arguments_for_variant ( Vector < ArgumentDefinition > arguments , Variants variants ,
u32 argument_count , EncodedType encoded_type )
{
Vector < ArgumentDefinition > variant_arguments = arguments ;
auto base_cpp_type = encoded_type . type_entry . cpp_type ;
size_t variadic_index = 0 ;
for ( size_t i = 0 ; i < variant_arguments . size ( ) ; + + i ) {
// Skip arguments with a fixed type
if ( variant_arguments [ i ] . cpp_type . has_value ( ) )
continue ;
variant_arguments [ i ] . cpp_type = encoded_type . cpp_type ;
auto cast_to = variant_arguments [ i ] . cast_to ;
// Pointer argument
if ( encoded_type . is_pointer ) {
2023-12-16 17:49:34 +03:30
variant_arguments [ i ] . name = ( variadic_index = = 0 ) ? variants . pointer_argument : Optional < ByteString > { } ;
2022-12-05 17:09:03 +01:00
if ( variadic_index > = argument_count ) {
// If this variable argument is past the argument count, fall back to the defaults
variant_arguments [ i ] . expression = variants . argument_defaults [ variadic_index ] ;
2023-12-16 17:49:34 +03:30
variant_arguments [ i ] . cast_to = Optional < ByteString > { } ;
2022-12-05 17:09:03 +01:00
} else if ( argument_count = = 1 & & variants . argument_counts . size ( ) = = 1 ) {
// Otherwise, if the pointer is the only variadic argument, pass it through unchanged
2023-12-16 17:49:34 +03:30
variant_arguments [ i ] . cast_to = Optional < ByteString > { } ;
2022-12-05 17:09:03 +01:00
} else {
// Otherwise, index into the pointer argument
2023-12-16 17:49:34 +03:30
auto indexed_expression = ByteString : : formatted ( " {}[{}] " , variants . pointer_argument , variadic_index ) ;
2022-12-05 17:09:03 +01:00
if ( variants . convert_range & & cast_to . has_value ( ) )
indexed_expression = wrap_expression_in_range_conversion ( base_cpp_type , cast_to . value ( ) , indexed_expression ) ;
variant_arguments [ i ] . expression = indexed_expression ;
}
} else {
// Regular argument
if ( variadic_index > = argument_count ) {
// If the variable argument is past the argument count, fall back to the defaults
2023-12-16 17:49:34 +03:30
variant_arguments [ i ] . name = Optional < ByteString > { } ;
2022-12-05 17:09:03 +01:00
variant_arguments [ i ] . expression = variants . argument_defaults [ variadic_index ] ;
2023-12-16 17:49:34 +03:30
variant_arguments [ i ] . cast_to = Optional < ByteString > { } ;
2022-12-05 17:09:03 +01:00
} else if ( variants . convert_range & & cast_to . has_value ( ) ) {
// Otherwise, if we need to convert the input values, wrap the expression in a range conversion
variant_arguments [ i ] . expression = wrap_expression_in_range_conversion (
base_cpp_type ,
cast_to . value ( ) ,
variant_arguments [ i ] . expression ) ;
}
}
// Determine if we can skip casting to the target type
if ( cast_to = = base_cpp_type | | ( variants . convert_range & & cast_to = = " GLdouble " ) )
2023-12-16 17:49:34 +03:30
variant_arguments [ i ] . cast_to = Optional < ByteString > { } ;
2022-12-05 17:09:03 +01:00
variadic_index + + ;
}
return variant_arguments ;
}
2023-12-16 17:49:34 +03:30
Vector < FunctionDefinition > create_function_definitions ( ByteString function_name , JsonObject const & function_definition )
2022-12-05 17:09:03 +01:00
{
// A single function definition can expand to multiple generated functions by way of:
// - differing API suffices (ARB, EXT, etc.);
// - differing argument counts;
// - differing argument types.
// These can all be combined.
// Parse base argument definitions first; these may later be modified by variants
Vector < ArgumentDefinition > argument_definitions ;
2022-12-21 14:37:27 +00:00
JsonArray const & arguments = function_definition . get_array ( " arguments " sv ) . value_or ( JsonArray { } ) ;
2022-12-05 17:09:03 +01:00
arguments . for_each ( [ & argument_definitions ] ( auto const & argument_value ) {
VERIFY ( argument_value . is_object ( ) ) ;
auto const & argument = argument_value . as_object ( ) ;
2023-12-16 17:49:34 +03:30
auto type = argument . get_byte_string ( " type " sv ) ;
2022-12-21 14:37:27 +00:00
auto argument_names = get_name_list ( argument . get ( " name " sv ) ) ;
2023-12-16 17:49:34 +03:30
auto expression = argument . get_byte_string ( " expression " sv ) . value_or ( " @argument_name@ " ) ;
auto cast_to = argument . get_byte_string ( " cast_to " sv ) ;
2022-12-05 17:09:03 +01:00
// Add an empty dummy name when all we have is an expression
if ( argument_names . is_empty ( ) & & ! expression . is_empty ( ) )
argument_names . append ( " " ) ;
for ( auto const & argument_name : argument_names ) {
2023-12-16 17:49:34 +03:30
argument_definitions . append ( { . name = argument_name . is_empty ( ) ? Optional < ByteString > { } : argument_name ,
2022-12-05 17:09:03 +01:00
. cpp_type = type ,
. expression = expression ,
. cast_to = cast_to } ) ;
}
} ) ;
// Create functions for each name and/or variant
Vector < FunctionDefinition > functions ;
2023-12-16 17:49:34 +03:30
auto return_type = function_definition . get_byte_string ( " return_type " sv ) . value_or ( " void " ) ;
auto function_implementation = function_definition . get_byte_string ( " implementation " sv ) . value_or ( function_name . to_snakecase ( ) ) ;
2022-12-21 14:37:27 +00:00
auto function_unimplemented = function_definition . get_bool ( " unimplemented " sv ) . value_or ( false ) ;
2022-12-05 17:09:03 +01:00
if ( ! function_definition . has ( " variants " sv ) ) {
functions . append ( {
. name = function_name ,
. return_type = return_type ,
. arguments = argument_definitions ,
. implementation = function_implementation ,
. unimplemented = function_unimplemented ,
. variant_gl_type = " " ,
} ) ;
return functions ;
}
// Read variants settings for this function
2022-12-21 14:37:27 +00:00
auto variants_obj = function_definition . get_object ( " variants " sv ) . value ( ) ;
2022-12-05 17:09:03 +01:00
auto variants = read_variants_settings ( variants_obj ) ;
for ( auto argument_count : variants . argument_counts ) {
for ( auto const & variant_type : variants . types ) {
auto encoded_type = get_encoded_type ( variant_type . encoded_type ) ;
auto variant_arguments = encoded_type . has_value ( )
? copy_arguments_for_variant ( argument_definitions , variants , argument_count , encoded_type . value ( ) )
: argument_definitions ;
auto variant_type_implementation = variant_type . implementation . has_value ( )
? variant_type . implementation . value ( )
: function_implementation ;
for ( auto const & api_suffix : variants . api_suffixes ) {
functions . append ( {
2023-12-16 17:49:34 +03:30
. name = ByteString : : formatted (
2022-12-05 17:09:03 +01:00
" {}{}{}{} " ,
function_name ,
2023-12-16 17:49:34 +03:30
variants . argument_counts . size ( ) > 1 ? ByteString : : formatted ( " {} " , argument_count ) : " " ,
2022-12-05 17:09:03 +01:00
encoded_type . has_value ( ) & & variants . types . size ( ) > 1 ? encoded_type - > function_name_suffix : " " ,
api_suffix ) ,
. return_type = return_type ,
. arguments = variant_arguments ,
. implementation = variant_type_implementation ,
. unimplemented = variant_type . unimplemented | | function_unimplemented ,
. variant_gl_type = encoded_type . has_value ( ) ? encoded_type - > type_entry . gl_type : " " sv ,
} ) ;
}
}
}
return functions ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & api_data , Core : : File & file )
2022-12-05 17:09:03 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
generator . appendln ( " #pragma once " ) ;
generator . append ( " \n " ) ;
generator . appendln ( " #include <LibGL/GL/glplatform.h> " ) ;
generator . append ( " \n " ) ;
generator . appendln ( " #ifdef __cplusplus " ) ;
generator . appendln ( " extern \" C \" { " ) ;
generator . appendln ( " #endif " ) ;
generator . append ( " \n " ) ;
api_data . for_each_member ( [ & ] ( auto & function_name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
auto const & function = value . as_object ( ) ;
auto function_definitions = create_function_definitions ( function_name , function ) ;
for ( auto const & function_definition : function_definitions ) {
2023-08-21 16:42:48 +02:00
auto function_generator = generator . fork ( ) ;
2022-12-05 17:09:03 +01:00
function_generator . set ( " name " , function_definition . name ) ;
function_generator . set ( " return_type " , function_definition . return_type ) ;
function_generator . append ( " GLAPI @return_type@ gl@name@( " ) ;
bool first = true ;
for ( auto const & argument_definition : function_definition . arguments ) {
if ( ! argument_definition . name . has_value ( ) | | ! argument_definition . cpp_type . has_value ( ) )
continue ;
2023-08-21 16:42:48 +02:00
auto argument_generator = function_generator . fork ( ) ;
2022-12-05 17:09:03 +01:00
argument_generator . set ( " argument_type " , argument_definition . cpp_type . value ( ) ) ;
argument_generator . set ( " argument_name " , argument_definition . name . value ( ) ) ;
if ( ! first )
argument_generator . append ( " , " ) ;
first = false ;
argument_generator . append ( " @argument_type@ @argument_name@ " ) ;
}
function_generator . appendln ( " ); " ) ;
}
} ) ;
generator . appendln ( " #ifdef __cplusplus " ) ;
generator . appendln ( " } " ) ;
generator . appendln ( " #endif " ) ;
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-12-05 17:09:03 +01:00
return { } ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_implementation_file ( JsonObject & api_data , Core : : File & file )
2022-12-05 17:09:03 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
generator . appendln ( " #include <LibGL/GL/glapi.h> " ) ;
generator . appendln ( " #include <LibGL/GLContext.h> " ) ;
generator . append ( " \n " ) ;
generator . appendln ( " extern GL::GLContext* g_gl_context; " ) ;
generator . append ( " \n " ) ;
api_data . for_each_member ( [ & ] ( auto & function_name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
JsonObject const & function = value . as_object ( ) ;
auto function_definitions = create_function_definitions ( function_name , function ) ;
for ( auto const & function_definition : function_definitions ) {
2023-08-21 16:42:48 +02:00
auto function_generator = generator . fork ( ) ;
2022-12-05 17:09:03 +01:00
auto return_type = function_definition . return_type ;
function_generator . set ( " name " sv , function_definition . name ) ;
function_generator . set ( " return_type " sv , return_type ) ;
function_generator . set ( " implementation " sv , function_definition . implementation ) ;
function_generator . set ( " variant_gl_type " sv , function_definition . variant_gl_type ) ;
function_generator . append ( " @return_type@ gl@name@( " ) ;
bool first = true ;
for ( auto const & argument_definition : function_definition . arguments ) {
if ( ! argument_definition . name . has_value ( ) | | ! argument_definition . cpp_type . has_value ( ) )
continue ;
2023-08-21 16:42:48 +02:00
auto argument_generator = function_generator . fork ( ) ;
2022-12-05 17:09:03 +01:00
argument_generator . set ( " argument_type " , argument_definition . cpp_type . value ( ) ) ;
argument_generator . set ( " argument_name " , argument_definition . name . value ( ) ) ;
if ( ! first )
argument_generator . append ( " , " ) ;
first = false ;
argument_generator . append ( " @argument_type@ @argument_name@ " ) ;
}
function_generator . appendln ( " ) " ) ;
function_generator . appendln ( " { " ) ;
if ( function_definition . unimplemented ) {
function_generator . append ( " dbgln( \" gl@name@( " ) ;
first = true ;
for ( auto const & argument_definition : function_definition . arguments ) {
if ( ! argument_definition . name . has_value ( ) )
continue ;
if ( ! first )
function_generator . append ( " , " ) ;
first = false ;
if ( argument_definition . cpp_type . value ( ) . ends_with ( ' * ' ) )
function_generator . append ( " {:p} " ) ;
else if ( argument_definition . cpp_type . value ( ) = = " GLenum " )
function_generator . append ( " {:#x} " ) ;
else
function_generator . append ( " {} " ) ;
}
function_generator . append ( " ): unimplemented \" " ) ;
for ( auto const & argument_definition : function_definition . arguments ) {
if ( ! argument_definition . name . has_value ( ) )
continue ;
function_generator . append ( " , " ) ;
function_generator . append ( argument_definition . name . value ( ) ) ;
}
function_generator . appendln ( " ); " ) ;
function_generator . appendln ( " TODO(); " ) ;
} else {
function_generator . appendln ( " if (!g_gl_context) " ) ;
if ( return_type . ends_with ( ' * ' ) )
function_generator . appendln ( " return nullptr; " ) ;
else if ( return_type = = " GLboolean " sv )
function_generator . appendln ( " return GL_FALSE; " ) ;
else if ( return_type = = " GLenum " sv )
function_generator . appendln ( " return GL_INVALID_OPERATION; " ) ;
else if ( return_type = = " GLuint " sv )
function_generator . appendln ( " return 0; " ) ;
else if ( return_type = = " void " sv )
function_generator . appendln ( " return; " ) ;
else
VERIFY_NOT_REACHED ( ) ;
function_generator . append ( " " ) ;
if ( return_type ! = " void " sv )
function_generator . append ( " return " ) ;
function_generator . append ( " g_gl_context->gl_@implementation@( " ) ;
first = true ;
for ( auto const & argument_definition : function_definition . arguments ) {
2023-08-21 16:42:48 +02:00
auto argument_generator = function_generator . fork ( ) ;
2022-12-05 17:09:03 +01:00
auto cast_to = argument_definition . cast_to ;
argument_generator . set ( " argument_name " , argument_definition . name . value_or ( " " ) ) ;
argument_generator . set ( " cast_to " , cast_to . value_or ( " " ) ) ;
if ( ! first )
argument_generator . append ( " , " ) ;
first = false ;
if ( cast_to . has_value ( ) )
argument_generator . append ( " static_cast<@cast_to@>( " ) ;
argument_generator . append ( argument_definition . expression ) ;
if ( cast_to . has_value ( ) )
argument_generator . append ( " ) " ) ;
}
function_generator . appendln ( " ); " ) ;
}
function_generator . appendln ( " } " ) ;
function_generator . append ( " \n " ) ;
}
} ) ;
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-12-05 17:09:03 +01:00
return { } ;
}
ErrorOr < JsonValue > read_entire_file_as_json ( StringView filename )
{
2023-02-09 03:02:46 +01:00
auto file = TRY ( Core : : File : : open ( filename , Core : : File : : OpenMode : : Read ) ) ;
2022-12-05 17:09:03 +01:00
auto json_size = TRY ( file - > size ( ) ) ;
auto json_data = TRY ( ByteBuffer : : create_uninitialized ( json_size ) ) ;
2023-03-01 15:27:35 +01:00
TRY ( file - > read_until_filled ( json_data . bytes ( ) ) ) ;
2022-12-05 17:09:03 +01:00
return JsonValue : : from_string ( json_data ) ;
}
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
StringView generated_header_path ;
StringView generated_implementation_path ;
StringView api_json_path ;
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the OpenGL API header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the OpenGL API implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
args_parser . add_option ( api_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 ( api_json_path ) ) ;
VERIFY ( json . is_object ( ) ) ;
auto api_data = json . as_object ( ) ;
2023-02-09 03:02:46 +01:00
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 ) ) ;
2022-12-05 17:09:03 +01:00
TRY ( generate_header_file ( api_data , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( api_data , * generated_implementation_file ) ) ;
return 0 ;
}