From cc7fdac795fd43d64de89ac799912aa9370a0d5e Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 5 Oct 2026 00:25:48 -0400 Subject: [PATCH] more tests and fixes --- base/components/ast_types.hpp | 3 +- base/components/code_serialization.cpp | 5 +- base/components/interface.upfront.cpp | 5 +- base/components/lexer.cpp | 11 +- base/components/types.hpp | 4 +- gen_c_library/c_library.cpp | 23 +- test/c_library/test.c | 414 +++++++++++++++++++++++++ test/cpp_library/test.cpp | 397 +++++++++++++++++++++++- 8 files changed, 841 insertions(+), 21 deletions(-) diff --git a/base/components/ast_types.hpp b/base/components/ast_types.hpp index 27bfae1..2682c2d 100644 --- a/base/components/ast_types.hpp +++ b/base/components/ast_types.hpp @@ -1077,7 +1077,8 @@ struct AST_Typedef struct { CodeComment InlineCmt; - char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ]; + CodeAttributes Attributes; + char _PAD_PROPERTIES_[ sizeof(AST*) ]; Code UnderlyingType; char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; }; diff --git a/base/components/code_serialization.cpp b/base/components/code_serialization.cpp index 39dacb5..648d344 100644 --- a/base/components/code_serialization.cpp +++ b/base/components/code_serialization.cpp @@ -158,7 +158,7 @@ void class_to_strbuilder_def( CodeClass self, StrBuilder* result ) if ( self->ParentType ) { Str access_level = access_spec_to_str( self->ParentAccess ); - strbuilder_append_fmt( result, " : %S %SB", self->Name, access_level, typename_to_strbuilder(self->ParentType) ); + strbuilder_append_fmt( result, " : %S %SB", access_level, typename_to_strbuilder(self->ParentType) ); CodeTypename interface = cast(CodeTypename, self->ParentType->Next); if ( interface ) @@ -1021,6 +1021,9 @@ void typedef_to_strbuilder_ref(CodeTypedef self, StrBuilder* result ) if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + strbuilder_append_str( result, txt("typedef ")); // Determines if the typedef is a function typename diff --git a/base/components/interface.upfront.cpp b/base/components/interface.upfront.cpp index b30864b..ef21ef4 100644 --- a/base/components/interface.upfront.cpp +++ b/base/components/interface.upfront.cpp @@ -1158,7 +1158,7 @@ CodeTypename def_type( Str name, Opts_def_type opt ) return InvalidCode; } if ( p.array_expr && p.array_expr->Type != CT_Untyped ) { - log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", code_debug_str((Code)p.array_expr) ); + log_failure( "gen::def_type: arrayexpr is not of untyped type - %S", code_debug_str((Code)p.array_expr) ); GEN_DEBUG_TRAP(); return InvalidCode; } @@ -1218,6 +1218,7 @@ CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opt ) result = (CodeTypedef) make_code(); result->Type = CT_Typedef; result->ModuleFlags = p.mflags; + result->Attributes = p.attributes; result->UnderlyingType = type; if ( name.Len <= 0 ) @@ -1271,7 +1272,7 @@ CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opt ) { Opts_def_using p = get_optional(opt); - if ( ! name_check( def_using, name ) || null_check( def_using, type ) ) { + if ( ! name_check( def_using, name ) || ! null_check( def_using, type ) ) { GEN_DEBUG_TRAP(); return InvalidCode; } diff --git a/base/components/lexer.cpp b/base/components/lexer.cpp index ad82f74..3a72dcf 100644 --- a/base/components/lexer.cpp +++ b/base/components/lexer.cpp @@ -541,11 +541,16 @@ void lex_found_token( LexContext* ctx ) ctx->token.Type = macrotype_to_toktype(macro->Type); b32 is_functional = macro_is_functional(* macro); resolved_to_macro = has_args ? is_functional : ! is_functional; - if ( ! resolved_to_macro && GEN_BUILD_DEBUG ) { - log_fmt("Info(%d, %d): %S identified as a macro but usage here does not resolve to one (interpreting as identifier)\n" - , ctx->token.Line + if ( ! resolved_to_macro && GEN_BUILD_DEBUG && ! bitfield_is_set(MacroFlags, macro->Flags, MF_Allow_As_Identifier) ) { + log_fmt("Info(%d, %d): %S identified as a macro but usage here does not resolve to one (functional=%d, has_args=%d, flags=%u, next='%.*s')\n" , ctx->token.Line + , ctx->token.Column , macro->Name + , is_functional + , has_args + , macro->Flags + , min(16, ctx->left) + , ctx->scanner ); } } diff --git a/base/components/types.hpp b/base/components/types.hpp index 4b3189f..4f2bf92 100644 --- a/base/components/types.hpp +++ b/base/components/types.hpp @@ -67,9 +67,9 @@ typedef void LoggerProc(LogEntry entry); // By default this library will either crash or exit if an error is detected while generating codes. // Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur. #ifdef GEN_DONT_USE_FATAL - #define log_failure log_fmt + #define log_failure( ... ) log_fmt( __VA_ARGS__ ) #else - #define log_failure GEN_FATAL + #define log_failure( ... ) GEN_FATAL( __VA_ARGS__ ) #endif enum AccessSpec : u32 diff --git a/gen_c_library/c_library.cpp b/gen_c_library/c_library.cpp index f4dbc40..86dd4b3 100644 --- a/gen_c_library/c_library.cpp +++ b/gen_c_library/c_library.cpp @@ -129,7 +129,8 @@ int gen_main() (Macro { txt("GEN_FILE_WRITE_AT_PROC"), MT_Statement, MF_Functional | MF_Expects_Body }), (Macro { txt("GEN_FILE_SEEK_PROC"), MT_Statement, MF_Functional | MF_Expects_Body }), (Macro { txt("GEN_FILE_CLOSE_PROC"), MT_Statement, MF_Functional | MF_Expects_Body }), - (Macro { txt("log_failure"), MT_Expression, MF_Null }), + (Macro { txt("log_failure"), MT_Statement, MF_Functional }), + (Macro { txt("NullScope"), MT_Expression, MF_Null }), (Macro { txt("operator"), MT_Expression, MF_Null }), (Macro { txt("InvalidCode"), MT_Expression, MF_Null }), (Macro { txt("NullCode"), MT_Expression, MF_Null }), @@ -137,8 +138,8 @@ int gen_main() (Macro { txt("gen_main"), MT_Statement, MF_Null }) )); register_macros( args( - (Macro { txt("name"), MT_Expression, MF_Functional }), - (Macro { txt("code"), MT_Expression, MF_Functional }), + (Macro { txt("name"), MT_Expression, MF_Functional | MF_Allow_As_Identifier }), + (Macro { txt("code"), MT_Expression, MF_Functional | MF_Allow_As_Identifier }), (Macro { txt("args"), MT_Expression, MF_Functional }), (Macro { txt("code_str"), MT_Expression, MF_Functional }), (Macro { txt("code_fmt"), MT_Expression, MF_Functional }), @@ -494,10 +495,10 @@ do \ case CT_Union_Fwd: { Str type_str = codetype_to_keyword_str(entry->Type); - Str formated_tmpl = token_fmt_impl( 3, - "type", type_str - , "name", entry->Name, - stringize( + Str formated_tmpl = token_fmt_impl( 3 + , "type", type_str + , "name", entry->Name + , stringize( typedef ; )); CodeTypedef tdef = parse_typedef(formated_tmpl); @@ -597,10 +598,10 @@ do \ } Str type_str = codetype_to_keyword_str(entry->Type); - Str formated_tmpl = token_fmt_impl( 3, - "type", type_str - , "name", entry->Name, - stringize( + Str formated_tmpl = token_fmt_impl( 3 + , "type", type_str + , "name", entry->Name + , stringize( typedef ; )); CodeTypedef tdef = parse_typedef(formated_tmpl); diff --git a/test/c_library/test.c b/test/c_library/test.c index 84842f7..8571a11 100644 --- a/test/c_library/test.c +++ b/test/c_library/test.c @@ -1,3 +1,4 @@ +#define GEN_DONT_USE_FATAL #define GEN_IMPLEMENTATION #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS #include "gen_singleheader.h" @@ -28,6 +29,11 @@ gen_internal void expect_variable(gen_CodeVar var, gen_Str label) { } } +gen_internal gen_Code_POD code_pod(gen_Code code) { + gen_Code_POD result = { (gen_AST*)code }; + return result; +} + int main() { gen_Context ctx = {0}; gen_init(&ctx); @@ -39,6 +45,404 @@ int main() expect_variable(upfront, gen_txt("c11 upfront")); expect_fragments(gen_strbuilder_to_str(gen_code_to_strbuilder(upfront)), gen_txt("c11 upfront serialized")); + gen_Code array_expr = gen_untyped_str(gen_txt("3")); + gen_CodeSpecifiers type_specs = gen_def_specifier(Spec_Const); + gen_CodeAttributes type_attrs = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeTypename option_type = gen_def_type(name(Payload), + .type_tag = Tag_Struct, + .gen_array_expr = array_expr, + .specifiers = type_specs, + .attributes = type_attrs + ); + expect(option_type != 0, gen_txt("c11 type options")); + if (option_type != 0) { + expect(option_type->TypeTag == Tag_Struct, gen_txt("c11 type tag")); + expect((gen_Code)option_type->ArrExpr == array_expr, gen_txt("c11 type array expression")); + expect((gen_Code)option_type->Specs == (gen_Code)type_specs, gen_txt("c11 type specifiers")); + expect((gen_Code)option_type->Attributes == (gen_Code)type_attrs, gen_txt("c11 type attributes")); + gen_Str type_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_type)); + expect(gen_str_contains(type_text, gen_txt("struct Payload")), gen_txt("c11 type tag serialization")); + expect(gen_str_contains(type_text, gen_txt("const")), gen_txt("c11 type specifier serialization")); + expect(gen_str_contains(type_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 type attribute serialization")); + } + + gen_Code value = gen_untyped_str(code("\"UPFRONT_OPTION\"")); + gen_CodeSpecifiers variable_specs = gen_def_specifier(Spec_Static); + gen_CodeAttributes variable_attrs = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeVar option_variable = gen_def_variable(option_type, name(option_payload), + .value = value, + .specifiers = variable_specs, + .attributes = variable_attrs, + .mflags = ModuleFlag_Export + ); + expect(option_variable != 0, gen_txt("c11 variable options")); + if (option_variable != 0) { + expect((gen_Code)option_variable->ValueType == (gen_Code)option_type, gen_txt("c11 variable type")); + expect( option_variable->Value == value, gen_txt("c11 variable value")); + expect((gen_Code)option_variable->Specs == (gen_Code)variable_specs, gen_txt("c11 variable specifiers")); + expect((gen_Code)option_variable->Attributes == (gen_Code)variable_attrs, gen_txt("c11 variable attributes")); + expect( option_variable->ModuleFlags == ModuleFlag_Export, gen_txt("c11 variable module flags")); + gen_Str variable_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_variable)); + expect(gen_str_contains(variable_text, gen_txt("option_payload")), gen_txt("c11 variable name serialization")); + expect(gen_str_contains(variable_text, gen_txt("UPFRONT_OPTION")), gen_txt("c11 variable value serialization")); + expect(gen_str_contains(variable_text, gen_txt("static")), gen_txt("c11 variable specifier serialization")); + expect(gen_str_contains(variable_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 variable attribute serialization")); + expect(gen_str_contains(variable_text, gen_txt("[ 3 ]")), gen_txt("c11 variable array serialization")); + expect(gen_str_contains(variable_text, gen_txt("export")), gen_txt("c11 variable module flag serialization")); + } + + gen_CodeVar class_member = gen_def_variable(gen_def_type(name(u32)), name(class_option_member)); + gen_CodeBody class_body = gen_def_class_body(1, code_pod((gen_Code)class_member)); + gen_CodeTypename class_parent = gen_def_type(name(ClassOptionBase)); + gen_CodeTypename class_interfaces[] = { gen_def_type(name(IClassOption)) }; + gen_CodeAttributes class_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeSpecifiers class_specifiers = gen_def_specifier(Spec_Final); + gen_CodeClass option_class = gen_def_class(name(ClassOption), + .body = class_body, + .parent = class_parent, + .parent_access = AccessSpec_Public, + .attributes = class_attributes, + .interfaces = class_interfaces, + .num_interfaces = 1, + .specifiers = class_specifiers, + .mflags = ModuleFlag_Export + ); + expect(option_class != 0, gen_txt("c11 class options")); + if (option_class != 0) { + expect((gen_Code)option_class->Body == (gen_Code)class_body, gen_txt("c11 class body")); + expect((gen_Code)option_class->ParentType == (gen_Code)class_parent, gen_txt("c11 class parent")); + expect( option_class->ParentAccess == AccessSpec_Public, gen_txt("c11 class parent access")); + expect((gen_Code)option_class->Attributes == (gen_Code)class_attributes, gen_txt("c11 class attributes")); + expect((gen_Code)option_class->ParentType->Next == (gen_Code)class_interfaces[0], gen_txt("c11 class interface")); + expect((gen_Code)option_class->Specs == (gen_Code)class_specifiers, gen_txt("c11 class specifiers")); + expect( option_class->ModuleFlags == ModuleFlag_Export, gen_txt("c11 class module flags")); + gen_Str class_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_class)); + expect(gen_str_contains(class_text, gen_txt("ClassOption")), gen_txt("c11 class name serialization")); + expect(gen_str_contains(class_text, gen_txt("ClassOptionBase")), gen_txt("c11 class parent serialization")); + expect(gen_str_contains(class_text, gen_txt("IClassOption")), gen_txt("c11 class interface serialization")); + expect(gen_str_contains(class_text, gen_txt("public")), gen_txt("c11 class access serialization")); + } + + gen_CodeVar struct_member = gen_def_variable(gen_def_type(name(u32)), name(struct_option_member)); + gen_CodeBody struct_body = gen_def_struct_body(1, code_pod((gen_Code)struct_member)); + gen_CodeTypename struct_parent = gen_def_type(name(StructOptionBase)); + gen_CodeTypename struct_interfaces[] = { gen_def_type(name(IStructOption)) }; + gen_CodeAttributes struct_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeSpecifiers struct_specifiers = gen_def_specifier(Spec_Final); + gen_CodeStruct option_struct = gen_def_struct(name(StructOption), + .body = struct_body, + .parent = struct_parent, + .parent_access = AccessSpec_Public, + .attributes = struct_attributes, + .interfaces = struct_interfaces, + .num_interfaces = 1, + .specifiers = struct_specifiers, + .mflags = ModuleFlag_Export + ); + expect(option_struct != 0, gen_txt("c11 struct options")); + if (option_struct != 0) { + expect((gen_Code)option_struct->Body == (gen_Code)struct_body, gen_txt("c11 struct body")); + expect((gen_Code)option_struct->ParentType == (gen_Code)struct_parent, gen_txt("c11 struct parent")); + expect( option_struct->ParentAccess == AccessSpec_Public, gen_txt("c11 struct parent access")); + expect((gen_Code)option_struct->Attributes == (gen_Code)struct_attributes, gen_txt("c11 struct attributes")); + expect((gen_Code)option_struct->ParentType->Next == (gen_Code)struct_interfaces[0], gen_txt("c11 struct interface")); + expect((gen_Code)option_struct->Specs == (gen_Code)struct_specifiers, gen_txt("c11 struct specifiers")); + expect( option_struct->ModuleFlags == ModuleFlag_Export, gen_txt("c11 struct module flags")); + gen_Str struct_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_struct)); + expect(gen_str_contains(struct_text, gen_txt("StructOption")), gen_txt("c11 struct name serialization")); + expect(gen_str_contains(struct_text, gen_txt("StructOptionBase")), gen_txt("c11 struct parent serialization")); + expect(gen_str_contains(struct_text, gen_txt("IStructOption")), gen_txt("c11 struct interface serialization")); + expect(gen_str_contains(struct_text, gen_txt("public")), gen_txt("c11 struct access serialization")); + } + + gen_CodeBody enum_body = gen_def_enum_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("Option_None")))); + gen_CodeTypename enum_underlying = gen_def_type(name(u32)); + gen_CodeAttributes enum_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeEnum option_enum = gen_def_enum(name(OptionEnum), + .body = enum_body, + .type = enum_underlying, + .specifier = EnumDecl_Class, + .attributes = enum_attributes, + .mflags = ModuleFlag_Export + ); + expect(option_enum != 0, gen_txt("c11 enum options")); + if (option_enum != 0) { + expect((gen_Code)option_enum->Body == (gen_Code)enum_body, gen_txt("c11 enum body")); + expect((gen_Code)option_enum->UnderlyingType == (gen_Code)enum_underlying, gen_txt("c11 enum underlying type")); + expect( option_enum->Type == CT_Enum_Class, gen_txt("c11 enum specifier")); + expect((gen_Code)option_enum->Attributes == (gen_Code)enum_attributes, gen_txt("c11 enum attributes")); + expect( option_enum->ModuleFlags == ModuleFlag_Export, gen_txt("c11 enum module flags")); + gen_Str enum_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_enum)); + expect(gen_str_contains(enum_text, gen_txt("export")), gen_txt("c11 enum module flag serialization")); + expect(gen_str_contains(enum_text, gen_txt("enum class")), gen_txt("c11 enum specifier serialization")); + expect(gen_str_contains(enum_text, gen_txt("u32")), gen_txt("c11 enum type serialization")); + expect(gen_str_contains(enum_text, gen_txt("Option_None")), gen_txt("c11 enum body serialization")); + } + + gen_Code enum_macro = gen_untyped_str(gen_txt("ENUM_BASE_TYPE")); + gen_CodeEnum macro_enum = gen_def_enum(name(MacroOptionEnum), + .body = gen_def_enum_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("Macro_None")))), + .type_macro = enum_macro + ); + expect(macro_enum != 0, gen_txt("c11 enum type macro option")); + if (macro_enum != 0) { + expect(macro_enum->UnderlyingTypeMacro == enum_macro, gen_txt("c11 enum type macro")); + expect(gen_str_contains(gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)macro_enum)), gen_txt("ENUM_BASE_TYPE")), gen_txt("c11 enum type macro serialization")); + } + + gen_CodeBody union_body = gen_def_union_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("u32 union_option_value;")))); + gen_CodeAttributes union_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeUnion option_union = gen_def_union(name(OptionUnion), union_body, + .attributes = union_attributes, + .mflags = ModuleFlag_Export + ); + expect(option_union != 0, gen_txt("c11 union options")); + if (option_union != 0) { + expect((gen_Code)option_union->Body == (gen_Code)union_body, gen_txt("c11 union body")); + expect((gen_Code)option_union->Attributes == (gen_Code)union_attributes, gen_txt("c11 union attributes")); + expect( option_union->ModuleFlags == ModuleFlag_Export, gen_txt("c11 union module flags")); + gen_Str union_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_union)); + expect(gen_str_contains(union_text, gen_txt("OptionUnion")), gen_txt("c11 union name serialization")); + expect(gen_str_contains(union_text, gen_txt("union_option_value")), gen_txt("c11 union body serialization")); + expect(gen_str_contains(union_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 union attribute serialization")); + expect(gen_str_contains(union_text, gen_txt("export")), gen_txt("c11 union module flag serialization")); + } + + gen_Code typedef_type = (gen_Code)gen_def_type(name(u32)); + gen_CodeAttributes typedef_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeTypedef option_typedef = gen_def_typedef(name(OptionTypedef), typedef_type, + .attributes = typedef_attributes, + .mflags = ModuleFlag_Export + ); + expect(option_typedef != 0, gen_txt("c11 typedef options")); + if (option_typedef != 0) { + expect( option_typedef->UnderlyingType == typedef_type, gen_txt("c11 typedef underlying type")); + expect((gen_Code)option_typedef->Attributes == (gen_Code)typedef_attributes, gen_txt("c11 typedef attributes")); + expect( option_typedef->ModuleFlags == ModuleFlag_Export, gen_txt("c11 typedef module flags")); + gen_Str typedef_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_typedef)); + expect(gen_str_contains(typedef_text, gen_txt("OptionTypedef")), gen_txt("c11 typedef name serialization")); + expect(gen_str_contains(typedef_text, gen_txt("u32")), gen_txt("c11 typedef type serialization")); + expect(gen_str_contains(typedef_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 typedef attribute serialization")); + expect(gen_str_contains(typedef_text, gen_txt("export")), gen_txt("c11 typedef module flag serialization")); + } + + gen_CodeTypename using_type = gen_def_type(name(u32)); + gen_CodeAttributes using_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeUsing option_using = gen_def_using(name(OptionUsing), using_type, + .attributes = using_attributes, + .mflags = ModuleFlag_Export + ); + expect(option_using != 0, gen_txt("c11 using options")); + if (option_using != 0) { + expect((gen_Code)option_using->UnderlyingType == (gen_Code)using_type, gen_txt("c11 using underlying type")); + expect((gen_Code)option_using->Attributes == (gen_Code)using_attributes, gen_txt("c11 using attributes")); + expect( option_using->ModuleFlags == ModuleFlag_Export, gen_txt("c11 using module flags")); + gen_Str using_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_using)); + expect(gen_str_contains(using_text, gen_txt("OptionUsing")), gen_txt("c11 using name serialization")); + expect(gen_str_contains(using_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 using attribute serialization")); + expect(gen_str_contains(using_text, gen_txt("export")), gen_txt("c11 using module flag serialization")); + } + + gen_CodeParams template_params = gen_def_param(gen_def_type(name(class)), name(T)); + gen_CodeTemplate option_template = gen_def_template(template_params, (gen_Code)option_struct, .mflags = ModuleFlag_Export); + expect(option_template != 0, gen_txt("c11 template options")); + if (option_template != 0) { + expect((gen_Code)option_template->Params == (gen_Code)template_params, gen_txt("c11 template parameters")); + expect( option_template->Declaration == (gen_Code)option_struct, gen_txt("c11 template declaration")); + expect( option_template->ModuleFlags == ModuleFlag_Export, gen_txt("c11 template module flags")); + gen_Str template_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_template)); + expect(gen_str_contains(template_text, gen_txt("export")), gen_txt("c11 template module flag serialization")); + expect(gen_str_contains(template_text, gen_txt("template")), gen_txt("c11 template serialization")); + expect(gen_str_contains(template_text, gen_txt("StructOption")), gen_txt("c11 template declaration serialization")); + } + + gen_Macro source_macro = { gen_txt("OptionParamSource"), MT_Expression, MF_Functional }; gen_register_macro(source_macro); + gen_CodeDefine parsed_macro_source = gen_parse_define(gen_txt("#define OptionParamSource(param) param\n")); + expect(parsed_macro_source != 0, gen_txt("c11 define parameter source")); + gen_MacroFlags define_flags = MF_Functional | MF_Allow_As_Identifier; + gen_CodeDefine option_define = gen_def_define(name(OptionMacro), MT_Expression, + .params = parsed_macro_source->Params, + .content = gen_txt("param + 1"), + .flags = define_flags + ); + expect(option_define != 0, gen_txt("c11 define options")); + if (option_define != 0) { + expect(option_define->Params == parsed_macro_source->Params, gen_txt("c11 define parameters")); + expect(gen_str_contains(option_define->Body->Content, gen_txt("param + 1")), gen_txt("c11 define content")); + gen_Macro* option_macro = lookup_macro(name(OptionMacro)); + expect(option_macro != 0, gen_txt("c11 define registration")); + if (option_macro != 0) expect(option_macro->Flags == define_flags, gen_txt("c11 define flags")); + gen_Str define_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_define)); + expect(gen_str_contains(define_text, gen_txt("OptionMacro")), gen_txt("c11 define name serialization")); + expect(gen_str_contains(define_text, gen_txt("param + 1")), gen_txt("c11 define content serialization")); + } + + gen_CodeDefine no_register_define = gen_def_define(name(OptionMacroNoRegister), MT_Expression, + .dont_register_to_preprocess_macros = true + ); + expect(no_register_define != 0, gen_txt("c11 define registration suppression")); + expect(lookup_macro(name(OptionMacroNoRegister)) == 0, gen_txt("c11 define suppression flag")); + + gen_CodeInclude local_include = gen_def_include(gen_txt("option_local.h")); + expect(local_include != 0, gen_txt("c11 local include option")); + if (local_include != 0) { + expect(gen_str_contains(local_include->Content, gen_txt("\"option_local.h\"")), gen_txt("c11 quoted include")); + } + + gen_CodeInclude foreign_include = gen_def_include(gen_txt("option_system.h"), .foreign = true); + expect(foreign_include != 0, gen_txt("c11 foreign include option")); + if (foreign_include != 0) { + expect(gen_str_contains(foreign_include->Content, gen_txt("")), gen_txt("c11 foreign include path")); + } + + gen_CodeModule option_module = gen_def_module(name(OptionModule), .mflags = ModuleFlag_Export); + expect(option_module != 0, gen_txt("c11 module options")); + if (option_module != 0) { + expect(option_module->ModuleFlags == ModuleFlag_Export, gen_txt("c11 module flags")); + expect(gen_str_contains(gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_module)), gen_txt("export")), gen_txt("c11 module serialization")); + } + + gen_CodeVar namespace_member = gen_def_variable(gen_def_type(name(u32)), name(namespace_option_value)); + gen_CodeBody namespace_body = gen_def_namespace_body(1, code_pod((gen_Code)namespace_member)); + gen_CodeNS option_namespace = gen_def_namespace(name(OptionNamespace), namespace_body, .mflags = ModuleFlag_Export); + expect(option_namespace != 0, gen_txt("c11 namespace options")); + if (option_namespace != 0) { + expect((gen_Code)option_namespace->Body == (gen_Code)namespace_body, gen_txt("c11 namespace body")); + expect( option_namespace->ModuleFlags == ModuleFlag_Export, gen_txt("c11 namespace flags")); + gen_Str namespace_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Csode)option_namespace)); + expect(gen_str_contains(namespace_text, gen_txt("OptionNamespace")), gen_txt("c11 namespace name serialization")); + expect(gen_str_contains(namespace_text, gen_txt("namespace_option_value")), gen_txt("c11 namespace body serialization")); + expect(gen_str_contains(namespace_text, gen_txt("export")), gen_txt("c11 namespace serialization")); + } + + gen_Code parameter_value = gen_untyped_str(code(7)); + gen_CodeParams option_parameter = gen_def_param(gen_def_type(name(u32)), name(option_parameter_value), .value = parameter_value); + expect(option_parameter != 0, gen_txt("c11 parameter options")); + if (option_parameter != 0) { + expect(option_parameter->Value == parameter_value, gen_txt("c11 parameter value")); + gen_Str parameter_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_parameter)); + expect(gen_str_contains(parameter_text, gen_txt("= 7")), gen_txt("c11 parameter value serialization")); + } + + gen_CodeParams function_params = gen_def_param(gen_def_type(name(u32)), name(function_option_arg)); + gen_CodeTypename function_return = gen_def_type(name(u32)); + gen_CodeBody function_body = gen_def_function_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("return function_option_arg;")))); + gen_CodeAttributes function_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeSpecifiers function_specs = gen_def_specifier(Spec_Inline); + gen_CodeFn option_function = gen_def_function(name(OptionFunction), + .params = function_params, + .ret_type = function_return, + .body = function_body, + .specs = function_specs, + .attrs = function_attributes, + .mflags = ModuleFlag_Export + ); + expect(option_function != 0, gen_txt("c11 function options")); + if (option_function != 0) { + expect((gen_Code)option_function->Params == (gen_Code)function_params, gen_txt("c11 function parameters")); + expect((gen_Code)option_function->ReturnType == (gen_Code)function_return, gen_txt("c11 function return type")); + expect((gen_Code)option_function->Body == (gen_Code)function_body, gen_txt("c11 function body")); + expect((gen_Code)option_function->Specs == (gen_Code)function_specs, gen_txt("c11 function specifiers")); + expect((gen_Code)option_function->Attributes == (gen_Code)function_attributes, gen_txt("c11 function attributes")); + expect( option_function->ModuleFlags == ModuleFlag_Export, gen_txt("c11 function module flags")); + gen_Str function_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_function)); + expect(gen_str_contains(function_text, gen_txt("OptionFunction")), gen_txt("c11 function name serialization")); + expect(gen_str_contains(function_text, gen_txt("function_option_arg")), gen_txt("c11 function parameters serialization")); + expect(gen_str_contains(function_text, gen_txt("return function_option_arg")), gen_txt("c11 function body serialization")); + expect(gen_str_contains(function_text, gen_txt("inline")), gen_txt("c11 function specifier serialization")); + expect(gen_str_contains(function_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 function attribute serialization")); + expect(gen_str_contains(function_text, gen_txt("export")), gen_txt("c11 function module flag serialization")); + } + + gen_CodeParams constructor_params = gen_def_param(gen_def_type(name(u32)), name(constructor_option_arg)); + gen_Code initializer_list = gen_untyped_str(gen_txt("option_member( 0 )")); + gen_CodeBody constructor_body = gen_def_function_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("option_member = constructor_option_arg;")))); + gen_CodeConstructor option_constructor = gen_def_constructor( + .params = constructor_params, + .initializer_list = initializer_list, + .body = (gen_Code)constructor_body + ); + expect(option_constructor != 0, gen_txt("c11 constructor options")); + if (option_constructor != 0) { + expect((gen_Code)option_constructor->Params == (gen_Code)constructor_params, gen_txt("c11 constructor parameters")); + expect( option_constructor->InitializerList == initializer_list, gen_txt("c11 constructor initializer list")); + expect( option_constructor->Body == (gen_Code)constructor_body, gen_txt("c11 constructor body")); + } + + gen_Code_POD constructor_pod = code_pod((gen_Code)option_constructor); + gen_CodeBody constructor_class_body = gen_def_class_body(1, constructor_pod); + gen_CodeClass constructor_class = gen_def_class(name(ConstructorOptions), .body = constructor_class_body); + expect(constructor_class != 0, gen_txt("c11 constructor serialization parent")); + if (constructor_class != 0) { + gen_Str constructor_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)constructor_class)); + expect(gen_str_contains(constructor_text, gen_txt("ConstructorOptions(")), gen_txt("c11 constructor name serialization")); + expect(gen_str_contains(constructor_text, gen_txt("option_member( 0 )")), gen_txt("c11 constructor initializer serialization")); + expect(gen_str_contains(constructor_text, gen_txt("constructor_option_arg")), gen_txt("c11 constructor body serialization")); + } + + gen_Code destructor_body = gen_untyped_str(gen_txt("release_option_resource();")); + gen_CodeSpecifiers destructor_specs = gen_def_specifier(Spec_Virtual); + gen_CodeDestructor option_destructor = gen_def_destructor( + .body = destructor_body, + .specifiers = destructor_specs + ); + expect(option_destructor != 0, gen_txt("c11 destructor options")); + if (option_destructor != 0) { + expect(option_destructor->Body == destructor_body, gen_txt("c11 destructor body")); + expect((gen_Code)option_destructor->Specs == (gen_Code)destructor_specs, gen_txt("c11 destructor specifiers")); + } + + gen_CodeTypename operator_type = gen_def_type(name(OperatorOptionType)); + gen_CodeParams operator_lhs = gen_def_param(operator_type, name(operator_option_lhs)); + gen_CodeParams operator_rhs = gen_def_param(operator_type, name(operator_option_rhs)); + gen_CodeParams operator_params_array[] = { operator_lhs, operator_rhs }; + gen_CodeParams operator_params = gen_def_params_arr(2, operator_params_array); + gen_CodeBody operator_body = gen_def_function_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("return operator_option_lhs;")))); + gen_CodeSpecifiers operator_specs = gen_def_specifier(Spec_Inline); + gen_CodeAttributes operator_attributes = gen_def_attributes(gen_txt("[[maybe_unused]]")); + gen_CodeOperator option_operator = gen_def_operator(Op_Add, gen_txt(""), + .params = operator_params, + .ret_type = operator_type, + .body = operator_body, + .specifiers = operator_specs, + .attributes = operator_attributes, + .mflags = ModuleFlag_Export + ); + expect(option_operator != 0, gen_txt("c11 operator options")); + if (option_operator != 0) { + expect((gen_Code)option_operator->Params == (gen_Code)operator_params, gen_txt("c11 operator parameters")); + expect((gen_Code)option_operator->ReturnType == (gen_Code)operator_type, gen_txt("c11 operator return type")); + expect((gen_Code)option_operator->Body == (gen_Code)operator_body, gen_txt("c11 operator body")); + expect((gen_Code)option_operator->Specs == (gen_Code)operator_specs, gen_txt("c11 operator specifiers")); + expect((gen_Code)option_operator->Attributes == (gen_Code)operator_attributes, gen_txt("c11 operator attributes")); + expect( option_operator->ModuleFlags == ModuleFlag_Export, gen_txt("c11 operator module flags")); + gen_Str operator_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_operator)); + expect(gen_str_contains(operator_text, gen_txt("operator +")), gen_txt("c11 operator name serialization")); + expect(gen_str_contains(operator_text, gen_txt("operator_option_lhs")), gen_txt("c11 operator parameters serialization")); + expect(gen_str_contains(operator_text, gen_txt("return operator_option_lhs")), gen_txt("c11 operator body serialization")); + expect(gen_str_contains(operator_text, gen_txt("inline")), gen_txt("c11 operator specifier serialization")); + expect(gen_str_contains(operator_text, gen_txt("[[maybe_unused]]")), gen_txt("c11 operator attribute serialization")); + expect(gen_str_contains(operator_text, gen_txt("export")), gen_txt("c11 operator module flag serialization")); + } + + gen_CodeTypename cast_type = gen_def_type(name(s32)); + gen_CodeBody cast_body = gen_def_function_body(1, code_pod((gen_Code)gen_untyped_str(gen_txt("return 0;")))); + gen_CodeSpecifiers cast_specs = gen_def_specifier(Spec_Const); + gen_CodeOpCast option_cast = gen_def_operator_cast(cast_type, + .body = cast_body, + .specs = cast_specs + ); + expect(option_cast != 0, gen_txt("c11 operator cast options")); + if (option_cast != 0) { + expect((gen_Code)option_cast->ValueType == (gen_Code)cast_type, gen_txt("c11 operator cast type")); + expect((gen_Code)option_cast->Body == (gen_Code)cast_body, gen_txt("c11 operator cast body")); + expect((gen_Code)option_cast->Specs == (gen_Code)cast_specs, gen_txt("c11 operator cast specifiers")); + gen_Str cast_text = gen_strbuilder_to_str(gen_code_to_strbuilder((gen_Code)option_cast)); + expect(gen_str_contains(cast_text, gen_txt("operator s32")), gen_txt("c11 operator cast serialization")); + expect(gen_str_contains(cast_text, gen_txt("const")), gen_txt("c11 operator cast specifier serialization")); + expect(gen_str_contains(cast_text, gen_txt("return 0")), gen_txt("c11 operator cast body serialization")); + } + gen_Code untyped = gen_code_str(char const* baseline_message = "GENCPP_BASELINE"; ); expect(untyped != 0, gen_txt("c11 untyped")); @@ -50,6 +454,16 @@ int main() expect_variable(parsed, gen_txt("c11 parsed")); expect_fragments(gen_strbuilder_to_str(gen_code_to_strbuilder(parsed)), gen_txt("c11 parsed serialized")); +#if ! GEN_BUILD_DEBUG + gen_CodeVar wrong_array_value = gen_def_variable(gen_def_type(name(u32)), name(invalid_array_expr)); + gen_CodeTypename invalid_array_type = gen_def_type(name(InvalidArrayOption), .gen_array_expr = (gen_Code)wrong_array_value); + expect((gen_Code)invalid_array_type == gen_Code_Invalid, gen_txt("c11 wrong type invalid code")); + + gen_CodeBody missing_union_body = 0; + gen_CodeUnion missing_union = gen_def_union(name(MissingUnionBody), missing_union_body); + expect((gen_Code)missing_union == gen_Code_Invalid, gen_txt("c11 missing body invalid code")); +#endif + gen_deinit(&ctx); if (g_failures != 0) { gen_log_fmt("c11 baseline smoke failed: %d\n", g_failures); return 1; } gen_log_fmt("c11 baseline smoke passed\n"); diff --git a/test/cpp_library/test.cpp b/test/cpp_library/test.cpp index 1861446..222fb0a 100644 --- a/test/cpp_library/test.cpp +++ b/test/cpp_library/test.cpp @@ -1,3 +1,4 @@ +#define GEN_DONT_USE_FATAL #define GEN_IMPLEMENTATION #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS #define GEN_ENFORCE_STRONG_CODE_TYPES @@ -23,7 +24,7 @@ internal void expect_variable(gen::CodeVar var, gen::Str label) { expect(var->Type == gen::CT_Variable, label); expect(gen::str_contains(var->Name, txt("baseline_message")), label); expect(var->ValueType.ast != nullptr, label); - expect(var->Value.ast != nullptr, label); + expect(var->Value.ast != nullptr, label); if (var->Value.ast != nullptr) { expect(gen::str_contains(var->Value->Content, txt("GENCPP_BASELINE")), label); } @@ -42,6 +43,388 @@ int main() expect_variable(upfront, txt("cpp upfront")); expect_fragments(strbuilder_to_str(code_to_strbuilder((Code)upfront)), txt("cpp upfront serialized")); + Opts_def_type type_options = {}; + Code array_expr = untyped_str(txt("3")); + CodeSpecifiers type_specs = def_specifier(Spec_Const); + CodeAttributes type_attrs = def_attributes(txt("[[maybe_unused]]")); + type_options.type_tag = Tag_Struct; + type_options.array_expr = array_expr; + type_options.specifiers = type_specs; + type_options.attributes = type_attrs; + CodeTypename option_type = def_type(name(Payload), type_options); + expect(option_type.ast != nullptr, txt("cpp type options")); + if (option_type.ast != nullptr) { + expect(option_type->TypeTag == Tag_Struct, txt("cpp type tag")); + expect(option_type->ArrExpr.ast == array_expr.ast, txt("cpp type array expression")); + expect(option_type->Specs.ast == type_specs.ast, txt("cpp type specifiers")); + expect(option_type->Attributes.ast == type_attrs.ast, txt("cpp type attributes")); + Str type_text = strbuilder_to_str(code_to_strbuilder((Code)option_type)); + expect(str_contains(type_text, txt("struct Payload")), txt("cpp type tag serialization")); + expect(str_contains(type_text, txt("const")), txt("cpp type specifier serialization")); + expect(str_contains(type_text, txt("[[maybe_unused]]")), txt("cpp type attribute serialization")); + } + + Opts_def_variable variable_options = {}; + Code value = untyped_str(code("\"UPFRONT_OPTION\"")); + CodeSpecifiers variable_specs = def_specifier(Spec_Static); + CodeAttributes variable_attrs = def_attributes(txt("[[maybe_unused]]")); + variable_options.value = value; + variable_options.specifiers = variable_specs; + variable_options.attributes = variable_attrs; + variable_options.mflags = ModuleFlag_Export; + CodeVar option_variable = def_variable(option_type, name(option_payload), variable_options); + expect(option_variable.ast != nullptr, txt("cpp variable options")); + if (option_variable.ast != nullptr) { + expect(option_variable->ValueType.ast == option_type.ast, txt("cpp variable type")); + expect(option_variable->Value.ast == value.ast, txt("cpp variable value")); + expect(option_variable->Specs.ast == variable_specs.ast, txt("cpp variable specifiers")); + expect(option_variable->Attributes.ast == variable_attrs.ast, txt("cpp variable attributes")); + expect(option_variable->ModuleFlags == ModuleFlag_Export, txt("cpp variable module flags")); + Str variable_text = strbuilder_to_str(code_to_strbuilder((Code)option_variable)); + expect(str_contains(variable_text, txt("option_payload")), txt("cpp variable name serialization")); + expect(str_contains(variable_text, txt("UPFRONT_OPTION")), txt("cpp variable value serialization")); + expect(str_contains(variable_text, txt("static")), txt("cpp variable specifier serialization")); + expect(str_contains(variable_text, txt("[[maybe_unused]]")), txt("cpp variable attribute serialization")); + expect(str_contains(variable_text, txt("[ 3 ]")), txt("cpp variable array serialization")); + expect(str_contains(variable_text, txt("export")), txt("cpp variable module flag serialization")); + } + + CodeVar class_member = def_variable(def_type(name(u32)), name(class_option_member)); + CodeBody class_body = def_class_body(args(class_member)); + CodeTypename class_parent = def_type(name(ClassOptionBase)); + CodeTypename class_interfaces[] = { def_type(name(IClassOption)) }; + Opts_def_struct class_options = {}; + class_options.body = class_body; + class_options.parent = class_parent; + class_options.parent_access = AccessSpec_Public; + class_options.attributes = def_attributes(txt("[[maybe_unused]]")); + class_options.interfaces = class_interfaces; + class_options.num_interfaces = 1; + class_options.specifiers = def_specifier(Spec_Final); + class_options.mflags = ModuleFlag_Export; + CodeClass option_class = def_class(name(ClassOption), class_options); + expect(option_class.ast != nullptr, txt("cpp class options")); + if (option_class.ast != nullptr) { + expect(option_class->Body.ast == class_body.ast, txt("cpp class body")); + expect(option_class->ParentType.ast == class_parent.ast, txt("cpp class parent")); + expect(option_class->ParentAccess == AccessSpec_Public, txt("cpp class parent access")); + expect(option_class->Attributes.ast == class_options.attributes.ast, txt("cpp class attributes")); + expect(option_class->ParentType->Next.ast == ((Code)class_interfaces[0]).ast, txt("cpp class interface")); + expect(option_class->Specs.ast == class_options.specifiers.ast, txt("cpp class specifiers")); + expect(option_class->ModuleFlags == ModuleFlag_Export, txt("cpp class module flags")); + Str class_text = strbuilder_to_str(code_to_strbuilder((Code)option_class)); + expect(str_contains(class_text, txt("ClassOption")), txt("cpp class name serialization")); + expect(str_contains(class_text, txt("ClassOptionBase")), txt("cpp class parent serialization")); + expect(str_contains(class_text, txt("IClassOption")), txt("cpp class interface serialization")); + expect(str_contains(class_text, txt("public")), txt("cpp class access serialization")); + } + + CodeVar struct_member = def_variable(def_type(name(u32)), name(struct_option_member)); + CodeBody struct_body = def_struct_body(args(struct_member)); + CodeTypename struct_parent = def_type(name(StructOptionBase)); + CodeTypename struct_interfaces[] = { def_type(name(IStructOption)) }; + Opts_def_struct struct_options = {}; + struct_options.body = struct_body; + struct_options.parent = struct_parent; + struct_options.parent_access = AccessSpec_Public; + struct_options.attributes = def_attributes(txt("[[maybe_unused]]")); + struct_options.interfaces = struct_interfaces; + struct_options.num_interfaces = 1; + struct_options.specifiers = def_specifier(Spec_Final); + struct_options.mflags = ModuleFlag_Export; + CodeStruct option_struct = def_struct(name(StructOption), struct_options); + expect(option_struct.ast != nullptr, txt("cpp struct options")); + if (option_struct.ast != nullptr) { + expect(option_struct->Body.ast == struct_body.ast, txt("cpp struct body")); + expect(option_struct->ParentType.ast == struct_parent.ast, txt("cpp struct parent")); + expect(option_struct->ParentAccess == AccessSpec_Public, txt("cpp struct parent access")); + expect(option_struct->Attributes.ast == struct_options.attributes.ast, txt("cpp struct attributes")); + expect(option_struct->ParentType->Next.ast == ((Code)struct_interfaces[0]).ast, txt("cpp struct interface")); + expect(option_struct->Specs.ast == struct_options.specifiers.ast, txt("cpp struct specifiers")); + expect(option_struct->ModuleFlags == ModuleFlag_Export, txt("cpp struct module flags")); + Str struct_text = strbuilder_to_str(code_to_strbuilder((Code)option_struct)); + expect(str_contains(struct_text, txt("StructOption")), txt("cpp struct name serialization")); + expect(str_contains(struct_text, txt("StructOptionBase")), txt("cpp struct parent serialization")); + expect(str_contains(struct_text, txt("IStructOption")), txt("cpp struct interface serialization")); + expect(str_contains(struct_text, txt("public")), txt("cpp struct access serialization")); + } + + CodeBody enum_body = def_enum_body(args(untyped_str(txt("Option_None")))); + Opts_def_enum enum_options = {}; + enum_options.body = enum_body; + enum_options.type = def_type(name(u32)); + enum_options.specifier = EnumDecl_Class; + enum_options.attributes = def_attributes(txt("[[maybe_unused]]")); + enum_options.mflags = ModuleFlag_Export; + CodeEnum option_enum = def_enum(name(OptionEnum), enum_options); + expect(option_enum.ast != nullptr, txt("cpp enum options")); + if (option_enum.ast != nullptr) { + expect(option_enum->Body.ast == enum_body.ast, txt("cpp enum body")); + expect(option_enum->UnderlyingType.ast == enum_options.type.ast, txt("cpp enum underlying type")); + expect(option_enum->Type == CT_Enum_Class, txt("cpp enum specifier")); + expect(option_enum->Attributes.ast == enum_options.attributes.ast, txt("cpp enum attributes")); + expect(option_enum->ModuleFlags == ModuleFlag_Export, txt("cpp enum module flags")); + Str enum_text = strbuilder_to_str(code_to_strbuilder((Code)option_enum)); + expect(str_contains(enum_text, txt("export")), txt("cpp enum module flag serialization")); + expect(str_contains(enum_text, txt("enum class")), txt("cpp enum specifier serialization")); + expect(str_contains(enum_text, txt("u32")), txt("cpp enum type serialization")); + expect(str_contains(enum_text, txt("Option_None")), txt("cpp enum body serialization")); + } + Code enum_macro = untyped_str(txt("ENUM_BASE_TYPE")); + CodeEnum macro_enum = def_enum(name(MacroOptionEnum), { + .body = def_enum_body(args(untyped_str(txt("Macro_None")))), + .type_macro = enum_macro, + }); + expect(macro_enum.ast != nullptr, txt("cpp enum type macro option")); + if (macro_enum.ast != nullptr) { + expect(macro_enum->UnderlyingTypeMacro.ast == enum_macro.ast, txt("cpp enum type macro")); + expect(str_contains(strbuilder_to_str(code_to_strbuilder((Code)macro_enum)), txt("ENUM_BASE_TYPE")), txt("cpp enum type macro serialization")); + } + + CodeBody union_body = def_union_body(args(untyped_str(txt("u32 union_option_value;")))); + Opts_def_union union_options = {}; + union_options.attributes = def_attributes(txt("[[maybe_unused]]")); + union_options.mflags = ModuleFlag_Export; + CodeUnion option_union = def_union(name(OptionUnion), union_body, union_options); + expect(option_union.ast != nullptr, txt("cpp union options")); + if (option_union.ast != nullptr) { + expect(option_union->Body.ast == union_body.ast, txt("cpp union body")); + expect(option_union->Attributes.ast == union_options.attributes.ast, txt("cpp union attributes")); + expect(option_union->ModuleFlags == ModuleFlag_Export, txt("cpp union module flags")); + Str union_text = strbuilder_to_str(code_to_strbuilder((Code)option_union)); + expect(str_contains(union_text, txt("OptionUnion")), txt("cpp union name serialization")); + expect(str_contains(union_text, txt("union_option_value")), txt("cpp union body serialization")); + expect(str_contains(union_text, txt("[[maybe_unused]]")), txt("cpp union attribute serialization")); + expect(str_contains(union_text, txt("export")), txt("cpp union module flag serialization")); + } + + CodeAttributes typedef_attrs = def_attributes(txt("[[maybe_unused]]")); + Code typedef_type = (Code)def_type(name(u32)); + Opts_def_typedef typedef_options = {}; + typedef_options.attributes = typedef_attrs; + typedef_options.mflags = ModuleFlag_Export; + CodeTypedef option_typedef = def_typedef(name(OptionTypedef), typedef_type, typedef_options); + expect(option_typedef.ast != nullptr, txt("cpp typedef options")); + if (option_typedef.ast != nullptr) { + expect(option_typedef->UnderlyingType.ast == typedef_type.ast, txt("cpp typedef underlying type")); + expect(option_typedef->Attributes.ast == typedef_attrs.ast, txt("cpp typedef attributes")); + expect(option_typedef->ModuleFlags == ModuleFlag_Export, txt("cpp typedef module flags")); + Str typedef_text = strbuilder_to_str(code_to_strbuilder((Code)option_typedef)); + expect(str_contains(typedef_text, txt("OptionTypedef")), txt("cpp typedef name serialization")); + expect(str_contains(typedef_text, txt("u32")), txt("cpp typedef type serialization")); + expect(str_contains(typedef_text, txt("[[maybe_unused]]")), txt("cpp typedef attribute serialization")); + expect(str_contains(typedef_text, txt("export")), txt("cpp typedef module flag serialization")); + } + + Opts_def_using using_options = {}; + using_options.attributes = def_attributes(txt("[[maybe_unused]]")); + using_options.mflags = ModuleFlag_Export; + CodeTypename using_type = def_type(name(u32)); + CodeUsing option_using = def_using(name(OptionUsing), using_type, using_options); + expect(option_using.ast != nullptr, txt("cpp using options")); + if (option_using.ast != nullptr) { + expect(option_using->UnderlyingType.ast == using_type.ast, txt("cpp using underlying type")); + expect(option_using->Attributes.ast == using_options.attributes.ast, txt("cpp using attributes")); + expect(option_using->ModuleFlags == ModuleFlag_Export, txt("cpp using module flags")); + Str using_text = strbuilder_to_str(code_to_strbuilder((Code)option_using)); + expect(str_contains(using_text, txt("OptionUsing")), txt("cpp using name serialization")); + expect(str_contains(using_text, txt("[[maybe_unused]]")), txt("cpp using attribute serialization")); + expect(str_contains(using_text, txt("export")), txt("cpp using module flag serialization")); + } + + CodeParams template_params = def_param(def_type(name(class)), name(T)); + CodeTemplate option_template = def_template(template_params, (Code)option_struct, { .mflags = ModuleFlag_Export }); + expect(option_template.ast != nullptr, txt("cpp template options")); + if (option_template.ast != nullptr) { + expect(option_template->Params.ast == template_params.ast, txt("cpp template parameters")); + expect(option_template->Declaration.ast == ((Code)option_struct).ast, txt("cpp template declaration")); + expect(option_template->ModuleFlags == ModuleFlag_Export, txt("cpp template module flags")); + Str template_text = strbuilder_to_str(code_to_strbuilder((Code)option_template)); + expect(str_contains(template_text, txt("export")), txt("cpp template module flag serialization")); + expect(str_contains(template_text, txt("template")), txt("cpp template serialization")); + expect(str_contains(template_text, txt("StructOption")), txt("cpp template declaration serialization")); + } + + Macro source_macro = { txt("OptionParamSource"), MT_Expression, MF_Functional }; + register_macro(source_macro); + CodeDefine parsed_macro_source = parse_define(txt("#define OptionParamSource(param) param\n")); + expect(parsed_macro_source.ast != nullptr, txt("cpp define parameter source")); + Opts_def_define define_options = {}; + define_options.params = parsed_macro_source->Params; + define_options.content = txt("param + 1"); + define_options.flags = MF_Functional | MF_Allow_As_Identifier; + CodeDefine option_define = def_define(name(OptionMacro), MT_Expression, define_options); + expect(option_define.ast != nullptr, txt("cpp define options")); + if (option_define.ast != nullptr) { + expect(option_define->Params.ast == define_options.params.ast, txt("cpp define parameters")); + expect(str_contains(option_define->Body->Content, txt("param + 1")), txt("cpp define content")); + Macro* option_macro = lookup_macro(name(OptionMacro)); + expect(option_macro != nullptr, txt("cpp define registration")); + if (option_macro != nullptr) expect(option_macro->Flags == define_options.flags, txt("cpp define flags")); + Str define_text = strbuilder_to_str(code_to_strbuilder((Code)option_define)); + expect(str_contains(define_text, txt("OptionMacro")), txt("cpp define name serialization")); + expect(str_contains(define_text, txt("param + 1")), txt("cpp define content serialization")); + } + Opts_def_define no_register_options = {}; + no_register_options.dont_register_to_preprocess_macros = true; + CodeDefine no_register_define = def_define(name(OptionMacroNoRegister), MT_Expression, no_register_options); + expect(no_register_define.ast != nullptr, txt("cpp define registration suppression")); + expect(lookup_macro(name(OptionMacroNoRegister)) == nullptr, txt("cpp define suppression flag")); + + CodeInclude local_include = def_include(txt("option_local.h")); + expect(local_include.ast != nullptr, txt("cpp local include option")); + if (local_include.ast != nullptr) { + expect(str_contains(local_include->Content, txt("\"option_local.h\"")), txt("cpp quoted include")); + } + Opts_def_include foreign_include_options = {}; + foreign_include_options.foreign = true; + CodeInclude foreign_include = def_include(txt("option_system.h"), foreign_include_options); + expect(foreign_include.ast != nullptr, txt("cpp foreign include option")); + if (foreign_include.ast != nullptr) { + expect(str_contains(foreign_include->Content, txt("")), txt("cpp foreign include path")); + } + + CodeModule option_module = def_module(name(OptionModule), { .mflags = ModuleFlag_Export }); + expect(option_module.ast != nullptr, txt("cpp module options")); + if (option_module.ast != nullptr) { + expect(option_module->ModuleFlags == ModuleFlag_Export, txt("cpp module flags")); + expect(str_contains(strbuilder_to_str(code_to_strbuilder((Code)option_module)), txt("export")), txt("cpp module serialization")); + } + CodeVar namespace_member = def_variable(def_type(name(u32)), name(namespace_option_value)); + CodeBody namespace_body = def_namespace_body(args(namespace_member)); + CodeNS option_namespace = def_namespace(name(OptionNamespace), namespace_body, { .mflags = ModuleFlag_Export }); + expect(option_namespace.ast != nullptr, txt("cpp namespace options")); + if (option_namespace.ast != nullptr) { + expect(option_namespace->Body.ast == namespace_body.ast, txt("cpp namespace body")); + expect(option_namespace->ModuleFlags == ModuleFlag_Export, txt("cpp namespace flags")); + Str namespace_text = strbuilder_to_str(code_to_strbuilder((Code)option_namespace)); + expect(str_contains(namespace_text, txt("OptionNamespace")), txt("cpp namespace name serialization")); + expect(str_contains(namespace_text, txt("namespace_option_value")), txt("cpp namespace body serialization")); + expect(str_contains(namespace_text, txt("export")), txt("cpp namespace serialization")); + } + + Code parameter_value = untyped_str(code(7)); + Opts_def_param parameter_options = {}; + parameter_options.value = parameter_value; + CodeParams option_parameter = def_param(def_type(name(u32)), name(option_parameter_value), parameter_options); + expect(option_parameter.ast != nullptr, txt("cpp parameter options")); + if (option_parameter.ast != nullptr) { + expect(option_parameter->Value.ast == parameter_value.ast, txt("cpp parameter value")); + Str parameter_text = strbuilder_to_str(code_to_strbuilder((Code)option_parameter)); + expect(str_contains(parameter_text, txt("= 7")), txt("cpp parameter value serialization")); + } + + CodeParams function_params = def_param(def_type(name(u32)), name(function_option_arg)); + CodeTypename function_return = def_type(name(u32)); + CodeBody function_body = def_function_body(args(untyped_str(txt("return function_option_arg;")))); + Opts_def_function function_options = {}; + function_options.params = function_params; + function_options.ret_type = function_return; + function_options.body = function_body; + function_options.specs = def_specifier(Spec_Inline); + function_options.attrs = def_attributes(txt("[[maybe_unused]]")); + function_options.mflags = ModuleFlag_Export; + CodeFn option_function = def_function(name(OptionFunction), function_options); + expect(option_function.ast != nullptr, txt("cpp function options")); + if (option_function.ast != nullptr) { + expect(option_function->Params.ast == function_params.ast, txt("cpp function parameters")); + expect(option_function->ReturnType.ast == function_return.ast, txt("cpp function return type")); + expect(option_function->Body.ast == function_body.ast, txt("cpp function body")); + expect(option_function->Specs.ast == function_options.specs.ast, txt("cpp function specifiers")); + expect(option_function->Attributes.ast == function_options.attrs.ast, txt("cpp function attributes")); + expect(option_function->ModuleFlags == ModuleFlag_Export, txt("cpp function module flags")); + Str function_text = strbuilder_to_str(code_to_strbuilder((Code)option_function)); + expect(str_contains(function_text, txt("OptionFunction")), txt("cpp function name serialization")); + expect(str_contains(function_text, txt("function_option_arg")), txt("cpp function parameters serialization")); + expect(str_contains(function_text, txt("return function_option_arg")), txt("cpp function body serialization")); + expect(str_contains(function_text, txt("inline")), txt("cpp function specifier serialization")); + expect(str_contains(function_text, txt("[[maybe_unused]]")), txt("cpp function attribute serialization")); + expect(str_contains(function_text, txt("export")), txt("cpp function module flag serialization")); + } + + CodeParams constructor_params = def_param(def_type(name(u32)), name(constructor_option_arg)); + Code initializer_list = untyped_str(txt("option_member( 0 )")); + CodeBody constructor_body = def_function_body(args(untyped_str(txt("option_member = constructor_option_arg;")))); + Opts_def_constructor constructor_options = {}; + constructor_options.params = constructor_params; + constructor_options.initializer_list = initializer_list; + constructor_options.body = constructor_body; + CodeConstructor option_constructor = def_constructor(constructor_options); + expect(option_constructor.ast != nullptr, txt("cpp constructor options")); + if (option_constructor.ast != nullptr) { + expect(option_constructor->Params.ast == constructor_params.ast, txt("cpp constructor parameters")); + expect(option_constructor->InitializerList.ast == initializer_list.ast, txt("cpp constructor initializer list")); + expect(option_constructor->Body.ast == ((Code)constructor_body).ast, txt("cpp constructor body")); + } + CodeBody constructor_class_body = def_class_body(args(option_constructor)); + CodeClass constructor_class = def_class(name(ConstructorOptions), { .body = constructor_class_body }); + expect(constructor_class.ast != nullptr, txt("cpp constructor serialization parent")); + if (constructor_class.ast != nullptr) { + Str constructor_text = strbuilder_to_str(code_to_strbuilder((Code)constructor_class)); + expect(str_contains(constructor_text, txt("ConstructorOptions(")), txt("cpp constructor name serialization")); + expect(str_contains(constructor_text, txt("option_member( 0 )")), txt("cpp constructor initializer serialization")); + expect(str_contains(constructor_text, txt("constructor_option_arg")), txt("cpp constructor body serialization")); + } + Code destructor_body = untyped_str(txt("release_option_resource();")); + CodeSpecifiers destructor_specs = def_specifier(Spec_Virtual); + Opts_def_destructor destructor_options = {}; + destructor_options.body = destructor_body; + destructor_options.specifiers = destructor_specs; + CodeDestructor option_destructor = def_destructor(destructor_options); + expect(option_destructor.ast != nullptr, txt("cpp destructor options")); + if (option_destructor.ast != nullptr) { + expect(option_destructor->Body.ast == destructor_body.ast, txt("cpp destructor body")); + expect(option_destructor->Specs.ast == destructor_specs.ast, txt("cpp destructor specifiers")); + } + + CodeTypename operator_type = def_type(name(OperatorOptionType)); + CodeParams operator_lhs = def_param(operator_type, name(operator_option_lhs)); + CodeParams operator_rhs = def_param(operator_type, name(operator_option_rhs)); + CodeParams operator_params = def_params(args(operator_lhs, operator_rhs)); + CodeBody operator_body = def_function_body(args(untyped_str(txt("return operator_option_lhs;")))); + Opts_def_operator operator_options = {}; + operator_options.params = operator_params; + operator_options.ret_type = operator_type; + operator_options.body = operator_body; + operator_options.specifiers = def_specifier(Spec_Inline); + operator_options.attributes = def_attributes(txt("[[maybe_unused]]")); + operator_options.mflags = ModuleFlag_Export; + CodeOperator option_operator = def_operator(Op_Add, txt(""), operator_options); + expect(option_operator.ast != nullptr, txt("cpp operator options")); + if (option_operator.ast != nullptr) { + expect(option_operator->Params.ast == operator_params.ast, txt("cpp operator parameters")); + expect(option_operator->ReturnType.ast == operator_type.ast, txt("cpp operator return type")); + expect(option_operator->Body.ast == operator_body.ast, txt("cpp operator body")); + expect(option_operator->Specs.ast == operator_options.specifiers.ast, txt("cpp operator specifiers")); + expect(option_operator->Attributes.ast == operator_options.attributes.ast, txt("cpp operator attributes")); + expect(option_operator->ModuleFlags == ModuleFlag_Export, txt("cpp operator module flags")); + Str operator_text = strbuilder_to_str(code_to_strbuilder((Code)option_operator)); + expect(str_contains(operator_text, txt("operator +")), txt("cpp operator name serialization")); + expect(str_contains(operator_text, txt("operator_option_lhs")), txt("cpp operator parameters serialization")); + expect(str_contains(operator_text, txt("return operator_option_lhs")), txt("cpp operator body serialization")); + expect(str_contains(operator_text, txt("inline")), txt("cpp operator specifier serialization")); + expect(str_contains(operator_text, txt("[[maybe_unused]]")), txt("cpp operator attribute serialization")); + expect(str_contains(operator_text, txt("export")), txt("cpp operator module flag serialization")); + } + + CodeTypename cast_type = def_type(name(s32)); + CodeBody cast_body = def_function_body(args(untyped_str(txt("return 0;")))); + CodeSpecifiers cast_specs = def_specifier(Spec_Const); + Opts_def_operator_cast cast_options = {}; + cast_options.body = cast_body; + cast_options.specs = cast_specs; + CodeOpCast option_cast = def_operator_cast(cast_type, cast_options); + expect(option_cast.ast != nullptr, txt("cpp operator cast options")); + if (option_cast.ast != nullptr) { + expect(option_cast->ValueType.ast == cast_type.ast, txt("cpp operator cast type")); + expect(option_cast->Body.ast == cast_body.ast, txt("cpp operator cast body")); + expect(option_cast->Specs.ast == cast_specs.ast, txt("cpp operator cast specifiers")); + Str cast_text = strbuilder_to_str(code_to_strbuilder((Code)option_cast)); + expect(str_contains(cast_text, txt("operator s32")), txt("cpp operator cast serialization")); + expect(str_contains(cast_text, txt("const")), txt("cpp operator cast specifier serialization")); + expect(str_contains(cast_text, txt("return 0")), txt("cpp operator cast body serialization")); + } + Code untyped = code_str(char const* baseline_message = "GENCPP_BASELINE";); expect(untyped.ast != nullptr, txt("cpp untyped")); Str untyped_text = strbuilder_to_str(code_to_strbuilder(untyped)); expect_fragments(untyped_text, txt("cpp untyped content")); CodeVar parsed_untyped = parse_variable(untyped_text); expect_variable(parsed_untyped, txt("cpp untyped reparsed")); @@ -50,6 +433,18 @@ int main() expect_variable(parsed, txt("cpp parsed")); expect_fragments(strbuilder_to_str(code_to_strbuilder((Code)parsed)), txt("cpp parsed serialized")); +#if ! GEN_BUILD_DEBUG + CodeVar wrong_array_value = def_variable(def_type(name(u32)), name(invalid_array_expr)); + Opts_def_type wrong_array_options = {}; + wrong_array_options.array_expr = (Code)wrong_array_value; + CodeTypename invalid_array_type = def_type(name(InvalidArrayOption), wrong_array_options); + expect(((Code)invalid_array_type).ast == Code_Invalid.ast, txt("cpp wrong type invalid code")); + + CodeBody missing_union_body = {}; + CodeUnion missing_union = def_union(name(MissingUnionBody), missing_union_body); + expect(((Code)missing_union).ast == Code_Invalid.ast, txt("cpp missing body invalid code")); +#endif + deinit(&ctx); if (g_failures != 0) { log_fmt("cpp baseline smoke failed: %d\n", g_failures); return 1; } log_fmt("cpp baseline smoke passed\n");