From c8cf55403b1d23304d365b2c9890967f6f1262ed Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 14 Dec 2024 18:49:41 -0500 Subject: [PATCH] WIP: more progress on new macro handling --- base/components/ast.cpp | 25 +++- base/components/code_serialization.cpp | 79 ++++++++---- base/components/gen/ecodetypes.hpp | 3 + base/components/gen/etoktype.hpp | 10 +- base/components/header_end.hpp | 2 +- base/components/interface.cpp | 23 ++-- base/components/interface.hpp | 47 +++---- base/components/interface.upfront.cpp | 99 +++++++++++---- base/components/lexer.cpp | 162 +++++++++++++++++-------- base/components/parser.cpp | 27 +++-- base/components/parser_types.hpp | 101 +++++++++------ base/components/static_data.cpp | 2 +- base/dependencies/macros.hpp | 4 +- base/enums/ETokType.csv | 1 + base/helpers/undef.macros.h | 2 +- gen_c_library/c_library.refactor | 2 +- 16 files changed, 400 insertions(+), 189 deletions(-) diff --git a/base/components/ast.cpp b/base/components/ast.cpp index c538a4c..55067bf 100644 --- a/base/components/ast.cpp +++ b/base/components/ast.cpp @@ -36,7 +36,6 @@ Str code_debug_str(Code self) case CT_Execution: case CT_Comment: case CT_PlatformAttributes: - case CT_Preprocess_Define: case CT_Preprocess_Include: case CT_Preprocess_Pragma: case CT_Preprocess_If: @@ -52,6 +51,11 @@ Str code_debug_str(Code self) strbuilder_append_fmt( result, "\n\tContent: %S", self->Content ); break; + case CT_Preprocess_Define: + // TODO(ED): Needs implementaton + log_failure("code_debug_str: NOT IMPLEMENTED for CT_Preprocess_Define"); + break; + case CT_Class: case CT_Struct: if ( self->Prev ) @@ -259,6 +263,11 @@ Str code_debug_str(Code self) strbuilder_append_fmt( result, "\n\tValue : %S", self->Value ? strbuilder_to_str( code_to_strbuilder(self->Value)) : txt("Null") ); break; + case CT_Parameters_Define: + // TODO(ED): Needs implementaton + log_failure("code_debug_str: NOT IMPLEMENTED for CT_Parameters_Define"); + break; + case CT_Specifiers: { strbuilder_append_fmt( result, "\n\tNumEntries: %d", self->NumEntries ); @@ -497,6 +506,10 @@ void code_to_strbuilder_ptr( Code self, StrBuilder* result ) params_to_strbuilder_ref(cast(CodeParams, self), result ); break; + case CT_Parameters_Define: + define_params_to_strbuilder_ref(cast(CodeDefineParams, self), result); + break; + case CT_Preprocess_Define: define_to_strbuilder_ref(cast(CodeDefine, self), result ); break; @@ -987,11 +1000,17 @@ bool code_is_equal( Code self, Code other ) return true; } + case CT_Parameters_Define: + { + // TODO(ED): Needs implementaton + log_failure("code_is_equal: NOT IMPLEMENTED for CT_Parameters_Define"); + return false; + } + case CT_Preprocess_Define: { check_member_str( Name ); - check_member_content( Content ); - + check_member_content( Body->Content ); return true; } diff --git a/base/components/code_serialization.cpp b/base/components/code_serialization.cpp index 2161c21..b219e80 100644 --- a/base/components/code_serialization.cpp +++ b/base/components/code_serialization.cpp @@ -176,7 +176,7 @@ void class_to_strbuilder_def( CodeClass self, StrBuilder* result ) { GEN_ASSERT(self); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_str( result, txt("class ") ); @@ -221,7 +221,7 @@ void class_to_strbuilder_fwd( CodeClass self, StrBuilder* result ) { GEN_ASSERT(self); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -241,12 +241,48 @@ void class_to_strbuilder_fwd( CodeClass self, StrBuilder* result ) StrBuilder define_to_strbuilder(CodeDefine define) { - return strbuilder_fmt_buf( _ctx->Allocator_Temp, "#define %S %S", define->Name, define->Content ); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + define_to_strbuilder_ref(define, & result); + return result; } void define_to_strbuilder_ref(CodeDefine define, StrBuilder* result ) { - strbuilder_append_fmt( result, "#define %S %S", define->Name, define->Content ); + GEN_ASSERT(define); + GEN_ASSERT(define->Body); + GEN_ASSERT(define->Body->Content); + if (define->Params) { + StrBuilder params_builder = define_params_to_strbuilder(define->Params) + strbuilder_append_fmt( result, "#define %S(%S) %S", define->Name, strbuilder_to_str(params_builder), define->Body->Content ); + } + else { + strbuilder_append_fmt( result, "#define %S %S", define->Name, define->Body->Content ); + } +} + +StrBuilder define_params_to_strbuilder(CodeDefineParams params) +{ + GEN_ASSERT(params); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + define_params_to_strbuilder_ref( params, & result ); + return result; +} + +void define_params_to_strbuilder_ref(CodeDefineParams params, StrBuilder* result) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->Name.Ptr && self->Name.Len ) + { + strbuilder_append_fmt( result, " %S", self->Name ); + } + if ( self->NumEntries - 1 > 0 ) + { + for ( CodeParams param = begin_CodeDefineParams(self->Next); param != end_CodeDefineParams(self->Next); param = next_CodeDefineParams(self->Next, param) ) + { + strbuilder_append_fmt( result, ", %SB", params_to_strbuilder(param) ); + } + } } StrBuilder destructor_to_strbuilder(CodeDestructor self) @@ -329,7 +365,7 @@ StrBuilder enum_to_strbuilder(CodeEnum self) void enum_to_strbuilder_def(CodeEnum self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes || self->UnderlyingType || self->UnderlyingTypeMacro ) @@ -362,7 +398,7 @@ void enum_to_strbuilder_def(CodeEnum self, StrBuilder* result ) void enum_to_strbuilder_fwd(CodeEnum self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -389,7 +425,7 @@ void enum_to_strbuilder_fwd(CodeEnum self, StrBuilder* result ) void enum_to_strbuilder_class_def(CodeEnum self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes || self->UnderlyingType ) @@ -421,7 +457,7 @@ void enum_to_strbuilder_class_def(CodeEnum self, StrBuilder* result ) void enum_to_strbuilder_class_fwd(CodeEnum self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_str( result, txt("enum class ") ); @@ -505,7 +541,7 @@ StrBuilder fn_to_strbuilder(CodeFn self) void fn_to_strbuilder_def(CodeFn self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export") ); if ( self->Attributes ) @@ -558,7 +594,7 @@ void fn_to_strbuilder_def(CodeFn self, StrBuilder* result ) void fn_to_strbuilder_fwd(CodeFn self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -646,7 +682,7 @@ StrBuilder namespace_to_strbuilder(CodeNS self) void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_fmt( result, "namespace %S\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) ); @@ -671,7 +707,7 @@ StrBuilder code_op_to_strbuilder(CodeOperator self) void code_op_to_strbuilder_def(CodeOperator self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -725,7 +761,7 @@ void code_op_to_strbuilder_def(CodeOperator self, StrBuilder* result ) void code_op_to_strbuilder_fwd(CodeOperator self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -865,7 +901,6 @@ void opcast_to_strbuilder_fwd(CodeOpCast self, StrBuilder* result ) StrBuilder params_to_strbuilder(CodeParams self) { - GEN_ASSERT(self); GEN_ASSERT(self); StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); params_to_strbuilder_ref( self, & result ); @@ -1030,7 +1065,7 @@ void struct_to_strbuilder_def( CodeStruct self, StrBuilder* result ) { GEN_ASSERT(self); GEN_ASSERT(result); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_str( result, txt("struct ") ); @@ -1076,7 +1111,7 @@ void struct_to_strbuilder_fwd( CodeStruct self, StrBuilder* result ) { GEN_ASSERT(self); GEN_ASSERT(result); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -1105,7 +1140,7 @@ void template_to_strbuilder_ref(CodeTemplate self, StrBuilder* result ) { GEN_ASSERT(self); GEN_ASSERT(result); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Params ) @@ -1123,7 +1158,7 @@ StrBuilder typedef_to_strbuilder(CodeTypedef self) void typedef_to_strbuilder_ref(CodeTypedef self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_str( result, txt("typedef ")); @@ -1236,7 +1271,7 @@ StrBuilder union_to_strbuilder(CodeUnion self) void union_to_strbuilder_def(CodeUnion self, StrBuilder* result ) { - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_str( result, txt("union ") ); @@ -1267,7 +1302,7 @@ void union_to_strbuilder_fwd(CodeUnion self, StrBuilder* result ) { GEN_ASSERT(self); GEN_ASSERT(result); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); strbuilder_append_str( result, txt("union ") ); @@ -1304,7 +1339,7 @@ void using_to_strbuilder_ref(CodeUsing self, StrBuilder* result ) { GEN_ASSERT(self); GEN_ASSERT(result); - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes ) @@ -1401,7 +1436,7 @@ void var_to_strbuilder_ref(CodeVar self, StrBuilder* result ) return; } - if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export )) strbuilder_append_str( result, txt("export ") ); if ( self->Attributes || self->Specs ) diff --git a/base/components/gen/ecodetypes.hpp b/base/components/gen/ecodetypes.hpp index aaf6d0d..c7ad1d0 100644 --- a/base/components/gen/ecodetypes.hpp +++ b/base/components/gen/ecodetypes.hpp @@ -46,6 +46,7 @@ enum CodeType : u32 CT_Operator_Cast, CT_Operator_Cast_Fwd, CT_Parameters, + CT_Parameters_Define, CT_Preprocess_Define, CT_Preprocess_Include, CT_Preprocess_If, @@ -114,6 +115,7 @@ inline Str codetype_to_str( CodeType type ) { "Operator_Cast", sizeof( "Operator_Cast" ) - 1 }, { "Operator_Cast_Fwd", sizeof( "Operator_Cast_Fwd" ) - 1 }, { "Parameters", sizeof( "Parameters" ) - 1 }, + { "Parameters_Define", sizeof( "Parameters_Define" ) - 1 }, { "Preprocess_Define", sizeof( "Preprocess_Define" ) - 1 }, { "Preprocess_Include", sizeof( "Preprocess_Include" ) - 1 }, { "Preprocess_If", sizeof( "Preprocess_If" ) - 1 }, @@ -182,6 +184,7 @@ inline Str codetype_to_keyword_str( CodeType type ) { "operator", sizeof( "operator" ) - 1 }, { "operator", sizeof( "operator" ) - 1 }, { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, { "define", sizeof( "define" ) - 1 }, { "include", sizeof( "include" ) - 1 }, { "if", sizeof( "if" ) - 1 }, diff --git a/base/components/gen/etoktype.hpp b/base/components/gen/etoktype.hpp index 2f5ce6a..dc4a400 100644 --- a/base/components/gen/etoktype.hpp +++ b/base/components/gen/etoktype.hpp @@ -53,6 +53,7 @@ enum TokType : u32 Tok_Operator, Tok_Preprocess_Hash, Tok_Preprocess_Define, + Tok_Preprocess_Define_Param, Tok_Preprocess_If, Tok_Preprocess_IfDef, Tok_Preprocess_IfNotDef, @@ -62,7 +63,9 @@ enum TokType : u32 Tok_Preprocess_Include, Tok_Preprocess_Pragma, Tok_Preprocess_Content, - Tok_Preprocess_Macro, + Tok_Preprocess_Macro_Expr, + Tok_Preprocess_Macro_Stmt, + Tok_Preprocess_Macro_Typename, Tok_Preprocess_Unsupported, Tok_Spec_Alignas, Tok_Spec_Const, @@ -155,6 +158,7 @@ inline Str toktype_to_str( TokType type ) { "__operator__", sizeof( "__operator__" ) - 1 }, { "#", sizeof( "#" ) - 1 }, { "define", sizeof( "define" ) - 1 }, + { "__define_param__", sizeof( "__define__param__" ) - 1 }, { "if", sizeof( "if" ) - 1 }, { "ifdef", sizeof( "ifdef" ) - 1 }, { "ifndef", sizeof( "ifndef" ) - 1 }, @@ -164,7 +168,9 @@ inline Str toktype_to_str( TokType type ) { "include", sizeof( "include" ) - 1 }, { "pragma", sizeof( "pragma" ) - 1 }, { "__macro_content__", sizeof( "__macro_content__" ) - 1 }, - { "__macro__", sizeof( "__macro__" ) - 1 }, + { "__macro_expression__", sizeof( "__macro_expression__" ) - 1 }, + { "__macro_statment__", sizeof( "__macro_statment__" ) - 1 }, + { "__macro_typename__", sizeof( "__macro_typename__" ) - 1 }, { "__unsupported__", sizeof( "__unsupported__" ) - 1 }, { "alignas", sizeof( "alignas" ) - 1 }, { "const", sizeof( "const" ) - 1 }, diff --git a/base/components/header_end.hpp b/base/components/header_end.hpp index 703c1d9..edf639d 100644 --- a/base/components/header_end.hpp +++ b/base/components/header_end.hpp @@ -6,7 +6,7 @@ #pragma region Constants -extern Str enum_underlying_sig; +extern PreprocessorMacro enum_underlying_macro; extern Code access_public; extern Code access_protected; diff --git a/base/components/interface.cpp b/base/components/interface.cpp index 7e0f37f..6a2d648 100644 --- a/base/components/interface.cpp +++ b/base/components/interface.cpp @@ -206,10 +206,12 @@ void define_constants() spec_local_persist = def_specifiers( 1, Spec_Local_Persist ); code_set_global(cast(Code, spec_local_persist)); - if (enum_underlying_sig.Len == 0) { - enum_underlying_sig = txt("enum_underlying("); + if (enum_underlying_macro.Name.Len == 0) { + enum_underlying_macro.Name = txt("enum_underlying("); + enum_underlying_macro.Type = MT_Expression; + enum_underlying_macro.Flags = MF_Functional; } - array_append( _ctx->PreprocessorDefines, enum_underlying_sig); + register_preprocess_macro(enum_underlying_macro); } void init(Context* ctx) @@ -301,9 +303,6 @@ void init(Context* ctx) GEN_FATAL( "gen::init: Failed to initialize the code pool" ); array_append( ctx->CodePools, code_pool ); - // TODO(Ed): This is going to be phased out most likely. - ctx->LexArena = arena_init_from_allocator( ctx->Allocator_DyanmicContainers, ctx->InitSize_LexArena ); - // TODO(Ed): Eventually the string arenas needs to be phased out for a dedicated string slab allocator Arena strbuilder_arena = arena_init_from_allocator( ctx->Allocator_StrCache, ctx->SizePer_StringArena ); if ( strbuilder_arena.PhysicalStart == nullptr ) @@ -315,9 +314,12 @@ void init(Context* ctx) ctx->StrCache = hashtable_init(StrCached, ctx->Allocator_DyanmicContainers); if ( ctx->StrCache.Entries == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the StringCache"); + + ctx->PreprocessorMacros = hashtable_init(PreprocessorMacros, ctx->Allocator_DyanmicContainers); + if (ctx->PreprocessorMacros.Hashes == nullptr || ctx->PreprocessorMacros.Entries == nullptr) { + GEN_FATAL( "gen::init: Failed to initialize the PreprocessMacros table" ); + } } - // Preprocessor Defines - ctx->PreprocessorDefines = array_init_reserve(StrCached, ctx->Allocator_DyanmicContainers, kilobytes(1) ); define_constants(); parser_init(); @@ -354,9 +356,7 @@ void deinit(Context* ctx) array_free( ctx->CodePools); array_free( ctx->StringArenas); - // arena_free(& ctx->LexArena); - - array_free(ctx->PreprocessorDefines); + hashtable_destroy(ctx->PreprocessorMacros); left = array_num( ctx->Fallback_AllocatorBuckets); if (left) @@ -401,6 +401,7 @@ void reset(Context* ctx) while ( left--, left ); hashtable_clear(ctx->StrCache); + hashtable_clear(ctx->PreprocessorMacros); define_constants(); } diff --git a/base/components/interface.hpp b/base/components/interface.hpp index ec3326b..e56a87a 100644 --- a/base/components/interface.hpp +++ b/base/components/interface.hpp @@ -156,6 +156,7 @@ GEN_API CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEF struct Opts_def_define { MacroFlags flags; CodeDefineParams params; + Str content; b32 dont_register_to_preprocess_macros; }; GEN_API CodeDefine def_define( Str name, MacroType type, Opts_def_define opts GEN_PARAM_DEFAULT ); @@ -269,28 +270,30 @@ GEN_API CodeBody def_body( CodeType type ); // There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num, /// or provide as an array of Code objects. -GEN_API CodeBody def_class_body ( s32 num, ... ); -GEN_API CodeBody def_class_body ( s32 num, Code* codes ); -GEN_API CodeBody def_enum_body ( s32 num, ... ); -GEN_API CodeBody def_enum_body ( s32 num, Code* codes ); -GEN_API CodeBody def_export_body ( s32 num, ... ); -GEN_API CodeBody def_export_body ( s32 num, Code* codes); -GEN_API CodeBody def_extern_link_body( s32 num, ... ); -GEN_API CodeBody def_extern_link_body( s32 num, Code* codes ); -GEN_API CodeBody def_function_body ( s32 num, ... ); -GEN_API CodeBody def_function_body ( s32 num, Code* codes ); -GEN_API CodeBody def_global_body ( s32 num, ... ); -GEN_API CodeBody def_global_body ( s32 num, Code* codes ); -GEN_API CodeBody def_namespace_body ( s32 num, ... ); -GEN_API CodeBody def_namespace_body ( s32 num, Code* codes ); -GEN_API CodeParams def_params ( s32 num, ... ); -GEN_API CodeParams def_params ( s32 num, CodeParams* params ); -GEN_API CodeSpecifiers def_specifiers ( s32 num, ... ); -GEN_API CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ); -GEN_API CodeBody def_struct_body ( s32 num, ... ); -GEN_API CodeBody def_struct_body ( s32 num, Code* codes ); -GEN_API CodeBody def_union_body ( s32 num, ... ); -GEN_API CodeBody def_union_body ( s32 num, Code* codes ); +GEN_API CodeBody def_class_body ( s32 num, ... ); +GEN_API CodeBody def_class_body ( s32 num, Code* codes ); +GEN_API CodeDefineParams def_define_params ( s32 num, ... ); +GEN_API CodeDefineParams def_define_params ( s32 num, CodeDefineParams* codes ) +GEN_API CodeBody def_enum_body ( s32 num, ... ); +GEN_API CodeBody def_enum_body ( s32 num, Code* codes ); +GEN_API CodeBody def_export_body ( s32 num, ... ); +GEN_API CodeBody def_export_body ( s32 num, Code* codes); +GEN_API CodeBody def_extern_link_body( s32 num, ... ); +GEN_API CodeBody def_extern_link_body( s32 num, Code* codes ); +GEN_API CodeBody def_function_body ( s32 num, ... ); +GEN_API CodeBody def_function_body ( s32 num, Code* codes ); +GEN_API CodeBody def_global_body ( s32 num, ... ); +GEN_API CodeBody def_global_body ( s32 num, Code* codes ); +GEN_API CodeBody def_namespace_body ( s32 num, ... ); +GEN_API CodeBody def_namespace_body ( s32 num, Code* codes ); +GEN_API CodeParams def_params ( s32 num, ... ); +GEN_API CodeParams def_params ( s32 num, CodeParams* params ); +GEN_API CodeSpecifiers def_specifiers ( s32 num, ... ); +GEN_API CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ); +GEN_API CodeBody def_struct_body ( s32 num, ... ); +GEN_API CodeBody def_struct_body ( s32 num, Code* codes ); +GEN_API CodeBody def_union_body ( s32 num, ... ); +GEN_API CodeBody def_union_body ( s32 num, Code* codes ); #pragma endregion Upfront diff --git a/base/components/interface.upfront.cpp b/base/components/interface.upfront.cpp index 0faec68..1e4b6b1 100644 --- a/base/components/interface.upfront.cpp +++ b/base/components/interface.upfront.cpp @@ -516,7 +516,6 @@ CodeClass def_class( Str name, Opts_def_struct p ) GEN_DEBUG_TRAP(); return InvalidCode; } - if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", code_debug_str(p.attributes) ); GEN_DEBUG_TRAP(); @@ -529,9 +528,12 @@ CodeClass def_class( Str name, Opts_def_struct p ) } CodeClass - result = (CodeClass) make_code(); - result->Name = cache_str( name ); - result->ModuleFlags = p.mflags; + result = (CodeClass) make_code(); + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + result->Attributes = p.attributes; + result->ParentAccess = p.parent_access; + result->ParentType = p.parent; if ( p.body ) { switch ( p.body->Type ) @@ -552,44 +554,32 @@ CodeClass def_class( Str name, Opts_def_struct p ) else { result->Type = CT_Class_Fwd; } - - result->Attributes = p.attributes; - result->ParentAccess = p.parent_access; - result->ParentType = p.parent; - for (s32 idx = 0; idx < p.num_interfaces; idx++ ) { class_add_interface(result, p.interfaces[idx] ); } return result; } -CodeDefine def_define( Str name, Str content, Opts_def_define p ) +CodeDefine def_define( Str name, MacroType type, Opts_def_define p ) { if ( ! name_check( def_define, name ) ) { GEN_DEBUG_TRAP(); return InvalidCode; } - CodeDefine result = (CodeDefine) make_code(); result->Type = CT_Preprocess_Define; result->Name = cache_str( name ); - - if ( content.Len <= 0 || content.Ptr == nullptr ) - result->Content = cache_str( txt("") ); + result->Params = p.params; + if ( p.content.Len <= 0 || p.content.Ptr == nullptr ) + result->Content = cache_str( txt("\n") ); else result->Content = cache_str( strbuilder_to_str(strbuilder_fmt_buf(_ctx->Allocator_Temp, "%S\n", content)) ); - b32 append_preprocess_defines = ! p.dont_append_preprocess_defines; - if ( append_preprocess_defines ) { - // Add the define to PreprocessorDefines for usage in parsing - s32 lex_id_len = 0; - for (; lex_id_len < result->Name.Len; ++ lex_id_len ) { - if ( result->Name.Ptr[lex_id_len] == '(' ) - break; - } - Str lex_id = { result->Name.Ptr, lex_id_len }; - array_append(_ctx->PreprocessorDefines, cache_str(lex_id) ); + b32 register_define = ! p.dont_register_to_preprocess_macros; + if ( register_define ) { + macro_entry = { result->Name, type, p.flags }; + register_preprocess_macro(macro_entry); } return result; } @@ -1410,6 +1400,67 @@ CodeBody def_class_body( s32 num, Code* codes ) return result; } +CodeDefineParams def_define_params( s32 num, ... ) +{ + def_body_start( def_define_params ); + + va_list va; + va_start(va, num); + + Code_POD pod = va_arg(va, Code_POD); + CodeDefineParams param = pcast( CodeDefineParams, pod ); + + null_check( def_define_params, param ); + if ( param->Type != CT_Parameters_Define ) { + log_failure( "gen::def_define_params: param %d is not a parameter for a preprocessor define", num - num + 1 ); + return InvalidCode; + } + + CodeDefineParams result = (CodeDefineParams) code_duplicate(param); + while ( -- num ) + { + pod = va_arg(va, Code_POD); + param = pcast( CodeDefineParams, pod ); + if ( param->Type != CT_Parameters_Define ) { + log_failure( "gen::def_define_params: param %d is not a parameter for a preprocessor define", num - num + 1 ); + return InvalidCode; + } + define_params_append(result, param ); + } + va_end(va); + + return result; +} + +CodeDefineParams def_define_params( s32 num, CodeDefineParams* codes ) +{ + def_body_code_array_start( def_define_params ); + +# define check_current(current) \ + if ( current == nullptr ) { \ + log_failure("gen::def_define_params: Provide a null code in codes array"); \ + return InvalidCode; \ + } \ + if (current->Type != CT_Parameters_Define ) { \ + log_failure("gen::def_define_params: Code in coes array is not of paramter for preprocessor define type - %s", code_debug_str(current) ); \ + return InvalidCode; \ + } + CodeDefineParams current = (CodeDefineParams)code_duplicate(* codes); + check_current(current); + + CodeDefineParams + result = (CodeDefineParams) make_code(); + result->Name = current->Name; + result->Type = current->Type; + while( codes++, current = * codes, num--, num > 0 ) { + check_current(current); + define_params_append(result, current ); + } +# undef check_current + + return result; +} + CodeBody def_enum_body( s32 num, ... ) { def_body_start( def_enum_body ); diff --git a/base/components/lexer.cpp b/base/components/lexer.cpp index 54f9258..b036706 100644 --- a/base/components/lexer.cpp +++ b/base/components/lexer.cpp @@ -112,6 +112,102 @@ void lexer_end_line( LexContext* ctx ) } #define end_line() lexer_end_line(ctx) +// TODO(Ed): We need to to attempt to recover from a lex failure? +s32 lex_preprocessor_define( LexContext* ctx ) +{ + Token name = { { ctx->scanner, 1 }, Tok_Identifier, ctx->line, ctx->column, TF_Preprocess }; + move_forward(); + + PreprocessorMacro macro = { name.Text, MT_Statement, 0 }; + PreprocessorMacro* registered_macro = lookup_preprocess_macro(name.Text); + if ( registered_macro == nullptr ) { + log_fmt("Warning: %S is was not registered before the lexer processed its #define directive, it will be registered as a statement macro" + , name.Text + ); + } + while ( ctx->left && ( char_is_alphanumeric((* ctx->scanner)) || (* ctx->scanner) == '_' ) ) { + move_forward(); + name.Text.Len++; + } + array_append( _ctx->Lexer_Tokens, name ); + + if ( ctx->left && (* ctx->scanner) == '(' ) + { + if (registered_macro && ! macro_is_functional(* registered_macro)) { + log_fmt("Warning: %S registered macro is not flagged as functional yet the definition detects opening parenthesis '(' for arguments" + , name.Text + ); + } + else { + macro.Flags |= MF_Functional; + } + + Token opening_paren = { { ctx->scanner, 1 }, Tok_Capture_Start, ctx->line, ctx->column, TF_Preprocess }; + array_append( _ctx->Lexer_Tokens, opening_paren ); + move_forward(); + + // We need to tokenize the define's arguments now: + while( ctx->left && * ctx->scanner != ')') + { + skip_whitespace(); + if ( char_is_alpha( (* ctx->scanner) ) || (* ctx->scanner) == '_' ) + { + Token parameter = { { ctx->scanner, 1 }, Tok_Preprocess_Define_Param, ctx->line, ctx->column, TF_Preprocess }; + move_forward(); + + while ( ctx->left && ( char_is_alphanumeric((* ctx->scanner)) || (* ctx->scanner) == '_' ) ) + { + move_forward(); + parameter.Text.Len++; + } + array_append(_ctx->Lexer_Tokens, parameter); + skip_whitespace(); + } + else { + log_failure("lex_preprocessor_define(%d, %d): Expected a '_' or alpha character for a parameter name for %S\n" + , ctx->line + , ctx->column + , name.Text + ); + return Lex_ReturnNull; + } + // There should be a comma + if ( * ctx->scanner != ',' ) { + log_failure("lex_preprocessor_define(%d, %d): Expected a comma after parameter %S for %S\n" + , ctx->line + , ctx->column + , parameter.Text + , name.Text + ); + return Lex_ReturnNull; + } + Token comma = { { ctx->scanner, 1 }, Tok_Comma, ctx->line, ctx->column, TF_Preprocess }; + array_append(_ctx->Lexer_Tokens, comma); + move_forward(); + } + + if ( * ctx->scanner != ')' ) { + log_failure("lex_preprocessor_define(%d, %d): Expected a ')' after last_parameter %S for %S (ran out of characters...)\n" + , ctx->line + , ctx->column + , parameter.Text + , name.Text + ); + return Lex_ReturnNull; + } + Token closing_paren = { { ctx->scanner, 1 }, Tok_Capture_End, ctx->line, ctx->column, TF_Preprocess }; + array_append(_ctx->Lexer_Tokens, closing_paren); + move_forward(); + } + if ( registered_macro == nullptr ) { + register_preprocess_macro(macro); + } + + // Define's content handled by lex_preprocessor_directive (the original caller of this) + return Lex_Continue; +} + +// TODO(Ed): We need to to attempt to recover from a lex failure? forceinline s32 lex_preprocessor_directive( LexContext* ctx ) { @@ -215,31 +311,9 @@ s32 lex_preprocessor_directive( LexContext* ctx ) if ( ctx->token.Type == Tok_Preprocess_Define ) { - Token name = { { ctx->scanner, 0 }, Tok_Identifier, ctx->line, ctx->column, TF_Preprocess }; - - name.Text.Ptr = ctx->scanner; - name.Text.Len = 1; - move_forward(); - - PreprocessorMacro* registered_macro = lookup_preprocess_macro(name.Text); - - - while ( ctx->left && ( char_is_alphanumeric((* ctx->scanner)) || (* ctx->scanner) == '_' ) ) - { - move_forward(); - name.Text.Len++; - } - - if ( ctx->left && (* ctx->scanner) == '(' ) - { - move_forward(); - name.Text.Len++; - } - - array_append( _ctx->Lexer_Tokens, name ); - - u64 key = crc32( name.Text.Ptr, name.Text.Len ); - hashtable_set(ctx->defines, key, tok_to_str(name) ); + u32 result = lex_preprocessor_define(ctx); // handles: #define ( ) - define's content handled later on within this scope. + if (result != Lex_Continue) + return Lex_ReturnNull; } Token preprocess_content = { { ctx->scanner, 0 }, Tok_Preprocess_Content, ctx->line, ctx->column, TF_Preprocess }; @@ -289,7 +363,7 @@ s32 lex_preprocessor_directive( LexContext* ctx ) s32 within_string = false; s32 within_char = false; - // SkipWhitespace(); + // Consume preprocess content while ( ctx->left ) { if ( (* ctx->scanner) == '"' && ! within_char ) @@ -325,6 +399,7 @@ s32 lex_preprocessor_directive( LexContext* ctx ) , (* ctx->scanner), ctx->line, ctx->column , directive_str, preprocess_content.Line, preprocess_content.Column , content_str ); + return Lex_ReturnNull; break; } } @@ -404,14 +479,15 @@ void lex_found_token( LexContext* ctx ) } u64 key = 0; - if ( (* ctx->scanner) == '(') - key = crc32( ctx->token.Text.Ptr, ctx->token.Text.Len + 1 ); - else - key = crc32( ctx->token.Text.Ptr, ctx->token.Text.Len ); + // if ( (* ctx->scanner) == '(') + // key = crc32( ctx->token.Text.Ptr, ctx->token.Text.Len + 1 ); + // else + key = crc32( ctx->token.Text.Ptr, ctx->token.Text.Len ); - Str* define = hashtable_get(ctx->defines, key ); + Str* define = hashtable_get(_ctx->PreprocessMacros, key ); if ( define ) { + // TODO(Ed): Needs updating (Macros) ctx->token.Type = Tok_Preprocess_Macro; // Want to ignore any arguments the define may have as they can be execution expressions. @@ -456,6 +532,7 @@ void lex_found_token( LexContext* ctx ) array_append( _ctx->Lexer_Tokens, ctx->token ); } +// TODO(Ed): We need to to attempt to recover from a lex failure? neverinline // TokArray lex( Array tokens, Str content ) TokArray lex( Str content ) @@ -480,27 +557,10 @@ TokArray lex( Str content ) return null_array; } - // TODO(ED): Remove this when preprocess defines has been converted - // for ( StrCached* entry = array_begin(_ctx->PreprocessorDefines); entry != array_end(_ctx->PreprocessorDefines); entry = array_next(_ctx->PreprocessorDefines, entry)) - // { - // s32 length = 0; - // char const* entry_scanner = (*entry).Ptr; - // while ( entry->Len > length && (char_is_alphanumeric( *entry_scanner ) || *entry_scanner == '_') ) - // { - // entry_scanner++; - // length ++; - // } - // if ( entry_scanner[0] == '(' ) - // { - // length++; - // } - - // u64 key = crc32( entry->Ptr, length ); - // hashtable_set(c.defines, key, * entry ); - // } - array_clear(_ctx->Lexer_Tokens); + b32 preprocess_args = true; + while (c.left ) { #if 0 @@ -1182,6 +1242,7 @@ TokArray lex( Str content ) { lex_found_token( ctx ); TokType last_type = array_back(_ctx->Lexer_Tokens)->Type; + // TODO(Ed): Change this to just detect if its a MACRO THAT SHOULD ACCEPT NEWLINES if ( last_type == Tok_Preprocess_Macro ) { Token thanks_c = { { c.scanner, 0 }, Tok_Invalid, c.line, c.column, TF_Null }; @@ -1217,6 +1278,7 @@ TokArray lex( Str content ) TokArray result = { _ctx->Lexer_Tokens, 0 }; return result; } + #undef move_forward #undef skip_whitespace #undef end_line diff --git a/base/components/parser.cpp b/base/components/parser.cpp index f0babe6..21c2e14 100644 --- a/base/components/parser.cpp +++ b/base/components/parser.cpp @@ -825,22 +825,21 @@ CodeBody parse_class_struct_body( TokType which, Token name ) switch ( currtok_noskip.Type ) { - case Tok_Statement_End: - { + case Tok_Statement_End: { // TODO(Ed): Convert this to a general warning procedure log_fmt("Dangling end statement found %SB\n", tok_to_strbuilder(currtok_noskip)); eat( Tok_Statement_End ); continue; } - case Tok_NewLine: + case Tok_NewLine: { member = fmt_newline; eat( Tok_NewLine ); - break; - - case Tok_Comment: + break; + } + case Tok_Comment: { member = cast(Code, parse_comment()); - break; - + break; + } case Tok_Access_Public: member = access_public; eat( Tok_Access_Public ); @@ -1727,8 +1726,8 @@ CodeBody parse_global_nspace( CodeType which ) // macro_found = true; goto Preprocess_Macro_Bare_In_Body; + // TODO(Ed): MACRO UPDATE } - break; case Tok_Preprocess_Pragma: { member = cast(Code, parse_pragma()); @@ -2727,7 +2726,7 @@ CodeParams parse_params( bool use_template_capture ) // In template captures you can have a typename have direct assignment without a name // typename = typename ... // Which would result in a static value type from a struct expansion (traditionally) - if ( ( name.Text.Ptr || use_template_capture ) && bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) + if ( ( name.Text.Ptr || use_template_capture ) && bitfield_is_set( u32, currtok.Flags, TF_Assign ) ) { eat( Tok_Operator ); // ( = @@ -2839,7 +2838,7 @@ CodeParams parse_params( bool use_template_capture ) // In template captures you can have a typename have direct assignment without a name // typename = typename ... // Which would result in a static value type from a struct expansion (traditionally) - if ( ( name.Text.Ptr || use_template_capture ) && bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) + if ( ( name.Text.Ptr || use_template_capture ) && bitfield_is_set( u32, currtok.Flags, TF_Assign ) ) { eat( Tok_Operator ); // ( = , = @@ -3166,7 +3165,7 @@ CodeVar parse_variable_after_name( b32 using_constructor_initializer = false; - if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) + if ( bitfield_is_set( u32, currtok.Flags, TF_Assign ) ) { // = expr = parse_assignment_expression(); @@ -4645,6 +4644,7 @@ else if ( currtok.Type == Tok_DeclType ) } } } + // TODO(Ed): This needs updating else if ( currtok.Type == Tok_Preprocess_Macro ) { // Typename is a macro name = currtok; @@ -4988,6 +4988,7 @@ CodeTypedef parser_parse_typedef() const bool from_typedef = true; + // TODO(Ed): UPDATE MACRO USAGE HERE #if GEN_PARSER_DISABLE_MACRO_TYPEDEF if ( false ) #else @@ -5365,7 +5366,7 @@ CodeUsing parser_parse_using() if ( ! is_namespace ) { - if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) + if ( bitfield_is_set( u32, currtok.Flags, TF_Assign ) ) { attributes = parse_attributes(); // using diff --git a/base/components/parser_types.hpp b/base/components/parser_types.hpp index 55babf4..d829850 100644 --- a/base/components/parser_types.hpp +++ b/base/components/parser_types.hpp @@ -6,34 +6,6 @@ #include "gen/especifier.hpp" #endif -enum MacroTypes : u16 -{ - MT_Block_Start, // Not Supported yet - MT_Block_End, // Not Supported yet - MT_Case_Statement, // Not Supported yet - MT_Expression, - MT_Statement, - MT_Typename, - - MF_UnderlyingType = GEN_U16_Max, -}; - -enum MacroFlags : u16 -{ - MF_Functional = bit(0), // Macro has parameters (args expected to be passed) - MF_Expects_Body = bit(1), // Expects to assign a braced scope to its body. - - MF_Null = 0, - MF_UnderlyingType = GEN_U16_Max, -}; - -struct PreprocessorMacro -{ - StrCached Name; - MacroTypes Type; - MacroFlags Flags; -}; - enum TokFlags : u32 { TF_Operator = bit(0), @@ -82,42 +54,42 @@ bool tok_is_valid( Token tok ) { forceinline bool tok_is_access_operator(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_AccessOperator ); + return bitfield_is_set( u32, tok.Flags, TF_AccessOperator ); } forceinline bool tok_is_access_specifier(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_AccessSpecifier ); + return bitfield_is_set( u32, tok.Flags, TF_AccessSpecifier ); } forceinline bool tok_is_attribute(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_Attribute ); + return bitfield_is_set( u32, tok.Flags, TF_Attribute ); } forceinline bool tok_is_operator(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_Operator ); + return bitfield_is_set( u32, tok.Flags, TF_Operator ); } forceinline bool tok_is_preprocessor(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_Preprocess ); + return bitfield_is_set( u32, tok.Flags, TF_Preprocess ); } forceinline bool tok_is_preprocess_cond(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_Preprocess_Cond ); + return bitfield_is_set( u32, tok.Flags, TF_Preprocess_Cond ); } forceinline bool tok_is_specifier(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_Specifier ); + return bitfield_is_set( u32, tok.Flags, TF_Specifier ); } forceinline bool tok_is_end_definition(Token tok) { - return bitfield_is_equal( u32, tok.Flags, TF_EndDefinition ); + return bitfield_is_set( u32, tok.Flags, TF_EndDefinition ); } StrBuilder tok_to_strbuilder(Token tok); @@ -153,3 +125,60 @@ struct ParseContext TokArray Tokens; StackNode* Scope; }; + +enum MacroType : u16 +{ + MT_Statement, // A macro is assumed to be a statement if not resolved. + MT_Expression, + MT_Typename, + MT_Block_Start, // Not Supported yet + MT_Block_End, // Not Supported yet + MT_Case_Statement, // Not Supported yet + + MF_UnderlyingType = GEN_U16_Max, +}; + +Str macro_type_to_str( MacroType type ) +{ + local_persist + Str lookup[ (u32)Num_ModuleFlags ] = { + { "Statement", sizeof("Statement") - 1 }, + { "Expression", sizeof("Expression") - 1 }, + { "Typename", sizeof("Typename") - 1 }, + { "Block_Start", sizeof("Block_Start") - 1 }, + { "Block_End", sizeof("Block_End") - 1 }, + { "Case_Statement", sizeof("Case_Statement") - 1 }, + }; + local_persist + Str invalid_flag = { "Invalid", sizeof("Invalid") }; + if ( flag > ModuleFlag_Import ) + return invalid_flag; + + return lookup[ (u32)flag ]; +} + +enum MacroFlags : u16 +{ + MF_Functional = bit(0), // Macro has parameters (args expected to be passed) + MF_Expects_Body = bit(1), // Expects to assign a braced scope to its body. + + MF_Null = 0, + MF_UnderlyingType = GEN_U16_Max, +}; + +struct PreprocessorMacro +{ + StrCached Name; + MacroType Type; + MacroFlags Flags; +}; + +forceinine +b32 macro_is_functional( PreprocessorMacro macro ) { + return bitfield_is_set( macro->Flags, MF_Functional ); +} + +forceinline +b32 macro_expects_body( PreprocessorMacro macro ) { + return bitfield_is_set( macro->Flags, MF_Expects_Body ); +} diff --git a/base/components/static_data.cpp b/base/components/static_data.cpp index cad615c..70a6ff2 100644 --- a/base/components/static_data.cpp +++ b/base/components/static_data.cpp @@ -9,7 +9,7 @@ global Context* _ctx; #pragma region Constants global u32 context_counter; -global Str enum_underlying_sig; +global PreprocessorMacro enum_underlying_macro; global Code Code_Global; global Code Code_Invalid; diff --git a/base/dependencies/macros.hpp b/base/dependencies/macros.hpp index 78bbe30..cbcf0f7 100644 --- a/base/dependencies/macros.hpp +++ b/base/dependencies/macros.hpp @@ -34,8 +34,8 @@ #endif #ifndef bit -#define bit( Value ) ( 1 << Value ) -#define bitfield_is_equal( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) ) +#define bit( Value ) ( 1 << Value ) +#define bitfield_is_set( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) ) #endif // Mainly intended for forcing the base library to utilize only C-valid constructs or type coercion diff --git a/base/enums/ETokType.csv b/base/enums/ETokType.csv index 8780b28..bdf1d03 100644 --- a/base/enums/ETokType.csv +++ b/base/enums/ETokType.csv @@ -42,6 +42,7 @@ Number, "__number__" Operator, "__operator__" Preprocess_Hash, "#" Preprocess_Define, "define" +Preprocess_Define_Param, "__define_param__" Preprocess_If, "if" Preprocess_IfDef, "ifdef" Preprocess_IfNotDef, "ifndef" diff --git a/base/helpers/undef.macros.h b/base/helpers/undef.macros.h index e31d308..0bc7a48 100644 --- a/base/helpers/undef.macros.h +++ b/base/helpers/undef.macros.h @@ -41,7 +41,7 @@ #undef local_persist #undef bit -#undef bitfield_is_equal +#undef bitfield_is_set #undef cast diff --git a/gen_c_library/c_library.refactor b/gen_c_library/c_library.refactor index 1c98342..c743e5c 100644 --- a/gen_c_library/c_library.refactor +++ b/gen_c_library/c_library.refactor @@ -21,7 +21,7 @@ word global, gen_global word internal, gen_internal word local_persist, gen_local_persist word bit, gen_bit -word bitfield_is_equal, gen_bitfield_is_equal +word bitfield_is_set, gen_bitfield_is_set word cast, gen_cast word ccast, gen_ccast word pcast, gen_pcast