gencpp/base/components/interface.upfront.cpp
2024-12-14 08:04:54 -05:00

2048 lines
53 KiB
C++

#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "interface.cpp"
#endif
#pragma region Upfront
enum OpValidateResult : u32
{
OpValResult_Fail,
OpValResult_Global,
OpValResult_Member
};
internal neverinline
OpValidateResult operator__validate( Operator op, CodeParams params_code, CodeTypename ret_type, CodeSpecifiers specifier )
{
if ( op == Op_Invalid )
{
log_failure("gen::def_operator: op cannot be invalid");
return OpValResult_Fail;
}
#pragma region Helper Macros
# define check_params() \
if ( ! params_code ) \
{ \
log_failure("gen::def_operator: params is null and operator %S requires it", operator_to_str(op)); \
return OpValResult_Fail; \
} \
if ( params_code->Type != CT_Parameters ) \
{ \
log_failure("gen::def_operator: params is not of Parameters type - %S", code_debug_str( cast(Code, params_code))); \
return OpValResult_Fail; \
}
# define check_param_eq_ret() \
if ( ! is_member_symbol && ! code_is_equal(cast(Code, params_code->ValueType), cast(Code, ret_type)) ) \
{ \
log_failure("gen::def_operator: operator %S requires first parameter to equal return type\n" \
"param types: %S\n" \
"return type: %S", \
operator_to_str(op), \
code_debug_str(cast(Code, params_code)), \
code_debug_str(cast(Code, ret_type)) \
); \
return OpValResult_Fail; \
}
#pragma endregion Helper Macros
if ( ! ret_type )
{
log_failure("gen::def_operator: ret_type is null but is required by operator %S", operator_to_str(op));
}
if ( ret_type->Type != CT_Typename )
{
log_failure("gen::def_operator: operator %S - ret_type is not of typename type - %S",
operator_to_str(op),
code_debug_str(cast(Code, ret_type))
);
return OpValResult_Fail;
}
bool is_member_symbol = false;
switch ( op )
{
# define specs( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__
case Op_Assign:
check_params();
if ( params_code->NumEntries > 1 )
{
log_failure("gen::def_operator: "
"operator %S does not support non-member definition (more than one parameter provided) - %S",
operator_to_str(op),
code_debug_str(cast(Code, params_code))
);
return OpValResult_Fail;
}
is_member_symbol = true;
break;
case Op_Assign_Add:
case Op_Assign_Subtract:
case Op_Assign_Multiply:
case Op_Assign_Divide:
case Op_Assign_Modulo:
case Op_Assign_BAnd:
case Op_Assign_BOr:
case Op_Assign_BXOr:
case Op_Assign_LShift:
case Op_Assign_RShift:
check_params();
if ( params_code->NumEntries == 1 )
is_member_symbol = true;
else
check_param_eq_ret();
if (params_code->NumEntries > 2 )
{
log_failure("gen::def_operator: operator %S may not be defined with more than two parametes - param count; %d\n%S"
, operator_to_str(op)
, params_code->NumEntries
, code_debug_str(cast(Code, params_code))
);
return OpValResult_Fail;
}
break;
case Op_Increment:
case Op_Decrement:
// If its not set, it just means its a prefix member op.
if ( params_code )
{
if ( params_code->Type != CT_Parameters )
{
log_failure("gen::def_operator: operator %S params code provided is not of Parameters type - %S"
, operator_to_str(op)
, code_debug_str(cast(Code, params_code))
);
return OpValResult_Fail;
}
switch ( params_code->NumEntries )
{
case 1:
if ( code_is_equal((Code)params_code->ValueType, (Code)t_int ) )
is_member_symbol = true;
else
check_param_eq_ret();
break;
case 2:
check_param_eq_ret();
if ( ! code_is_equal((Code)params_get(params_code, 1), (Code)t_int ) )
{
log_failure("gen::def_operator: "
"operator %S requires second parameter of non-member definition to be int for post-decrement",
operator_to_str(op)
);
return OpValResult_Fail;
}
break;
default:
log_failure("gen::def_operator: operator %S recieved unexpected number of parameters recived %d instead of 0-2"
, operator_to_str(op)
, params_code->NumEntries
);
return OpValResult_Fail;
}
}
break;
case Op_Unary_Plus:
case Op_Unary_Minus:
if ( ! params_code )
is_member_symbol = true;
else
{
if ( params_code->Type != CT_Parameters )
{
log_failure("gen::def_operator: params is not of Parameters type - %S", code_debug_str((Code)params_code));
return OpValResult_Fail;
}
if ( code_is_equal((Code)params_code->ValueType, (Code)ret_type ) )
{
log_failure("gen::def_operator: "
"operator %S is non-member symbol yet first paramter does not equal return type\n"
"param type: %S\n"
"return type: %S\n"
, code_debug_str((Code)params_code)
, code_debug_str((Code)ret_type)
);
return OpValResult_Fail;
}
if ( params_code->NumEntries > 1 )
{
log_failure("gen::def_operator: operator %S may not have more than one parameter - param count: %d"
, operator_to_str(op)
, params_code->NumEntries
);
return OpValResult_Fail;
}
}
break;
case Op_BNot:
{
// Some compilers let you do this...
#if 0
if ( ! ret_type.is_equal( t_bool) )
{
log_failure( "gen::def_operator: operator %S return type is not a boolean - %S", operator_to_str(op) code_debug_str(params_code) );
return OpValidateResult::Fail;
}
#endif
if ( ! params_code )
is_member_symbol = true;
else
{
if ( params_code->Type != CT_Parameters )
{
log_failure( "gen::def_operator: operator %S - params is not of Parameters type - %S", operator_to_str(op), code_debug_str((Code)params_code) );
return OpValResult_Fail;
}
if ( params_code->NumEntries > 1 )
{
log_failure(
"gen::def_operator: operator %S may not have more than one parameter - param count: %d",
operator_to_str( op ),
params_code->NumEntries
);
return OpValResult_Fail;
}
}
break;
}
case Op_Add:
case Op_Subtract:
case Op_Multiply:
case Op_Divide:
case Op_Modulo:
case Op_BAnd:
case Op_BOr:
case Op_BXOr:
case Op_LShift:
case Op_RShift:
check_params();
switch ( params_code->NumEntries )
{
case 1:
is_member_symbol = true;
break;
case 2:
// This is allowed for arithemtic operators
// if ( ! code_is_equal((Code)params_code->ValueType, (Code)ret_type ) )
// {
// log_failure("gen::def_operator: "
// "operator %S is non-member symbol yet first paramter does not equal return type\n"
// "param type: %S\n"
// "return type: %S\n"
// , code_debug_str((Code)params_code)
// , code_debug_str((Code)ret_type)
// );
// return OpValResult_Fail;
// }
break;
default:
log_failure("gen::def_operator: operator %S recieved unexpected number of paramters recived %d instead of 0-2"
, operator_to_str(op)
, params_code->NumEntries
);
return OpValResult_Fail;
}
break;
case Op_UnaryNot:
if ( ! params_code )
is_member_symbol = true;
else
{
if ( params_code->Type != CT_Parameters )
{
log_failure("gen::def_operator: operator %S - params is not of Parameters type - %S", operator_to_str(op), code_debug_str((Code)params_code));
return OpValResult_Fail;
}
if ( params_code->NumEntries != 1 )
{
log_failure("gen::def_operator: operator %S recieved unexpected number of paramters recived %d instead of 0-1"
, operator_to_str(op)
, params_code->NumEntries
);
return OpValResult_Fail;
}
}
if ( ! code_is_equal((Code)ret_type, (Code)t_bool ))
{
log_failure("gen::def_operator: operator %S return type must be of type bool - %S"
, operator_to_str(op)
, code_debug_str((Code)ret_type)
);
return OpValResult_Fail;
}
break;
case Op_LAnd:
case Op_LOr:
case Op_LEqual:
case Op_LNot:
case Op_Lesser:
case Op_Greater:
case Op_LesserEqual:
case Op_GreaterEqual:
check_params();
switch ( params_code->NumEntries )
{
case 1:
is_member_symbol = true;
break;
case 2:
break;
default:
log_failure("gen::def_operator: operator %S recieved unexpected number of paramters recived %d instead of 1-2"
, operator_to_str(op)
, params_code->NumEntries
);
return OpValResult_Fail;
}
break;
case Op_Indirection:
case Op_AddressOf:
case Op_MemberOfPointer:
if ( params_code && params_code->NumEntries > 1)
{
log_failure("gen::def_operator: operator %S recieved unexpected number of paramters recived %d instead of 0-1"
, operator_to_str(op)
, params_code->NumEntries
);
return OpValResult_Fail;
}
else
{
is_member_symbol = true;
}
break;
case Op_PtrToMemOfPtr:
if ( params_code )
{
log_failure("gen::def_operator: operator %S expects no paramters - %S", operator_to_str(op), code_debug_str((Code)params_code));
return OpValResult_Fail;
}
break;
case Op_Subscript:
case Op_FunctionCall:
case Op_Comma:
check_params();
break;
case Op_New:
case Op_Delete:
// This library doesn't support validating new and delete yet.
break;
# undef specs
}
return is_member_symbol ? OpValResult_Member : OpValResult_Global;
# undef check_params
# undef check_ret_type
# undef check_param_eq_ret
}
forceinline
bool name__check( char const* context, Str name )
{
if ( name.Len <= 0 ) {
log_failure( "gen::%s: Invalid name length provided - %d", name.Len );
return false;
}
if ( name.Ptr == nullptr ) {
log_failure( "gen::%s: name is null" );
return false;
}
return true;
}
#define name_check( context, name ) name__check( #context, name )
forceinline
bool null__check( char const* context, char const* code_id, Code code ) {
if ( code == nullptr ) {
log_failure( "gen::%s: %s provided is null", context, code_id );
return false;
}
return true;
}
#define null_check( context, code ) null__check( #context, #code, cast(Code, code) )
/*
The implementaiton of the upfront constructors involves doing three things:
* Validate the arguments given to construct the intended type of AST is valid.
* Construct said AST type.
* Lock the AST (set to readonly) and return the valid object.
If any of the validation fails, it triggers a call to log_failure with as much info the give the user so that they can hopefully
identify the issue without having to debug too much (at least they can debug though...)
The largest of the functions is related to operator overload definitions.
The library validates a good protion of their form and thus the argument processing for is quite a bit.
*/
CodeAttributes def_attributes( Str content )
{
if ( content.Len <= 0 || content.Ptr == nullptr ) {
log_failure( "gen::def_attributes: Invalid attributes provided" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
Code
result = make_code();
result->Type = CT_PlatformAttributes;
result->Name = cache_str( content );
result->Content = result->Name;
return (CodeAttributes) result;
}
CodeComment def_comment( Str content )
{
if ( content.Len <= 0 || content.Ptr == nullptr )
{
log_failure( "gen::def_comment: Invalid comment provided:" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
StrBuilder cmt_formatted = strbuilder_make_reserve( _ctx->Allocator_Temp, kilobytes(1) );
char const* end = content.Ptr + content.Len;
char const* scanner = content.Ptr;
s32 curr = 0;
do
{
char const* next = scanner;
s32 length = 0;
while ( next != end && scanner[ length ] != '\n' )
{
next = scanner + length;
length++;
}
length++;
strbuilder_append_fmt(& cmt_formatted, "//%.*s", length, scanner );
scanner += length;
}
while ( scanner <= end );
if ( * strbuilder_back(cmt_formatted) != '\n' )
strbuilder_append_str( & cmt_formatted, txt("\n") );
Str name = strbuilder_to_str(cmt_formatted);
Code
result = make_code();
result->Type = CT_Comment;
result->Name = cache_str( name );
result->Content = result->Name;
strbuilder_free(& cmt_formatted);
return (CodeComment) result;
}
CodeConstructor def_constructor( Opts_def_constructor p )
{
if ( p.params && p.params->Type != CT_Parameters ) {
log_failure("gen::def_constructor: params must be of Parameters type - %s", code_debug_str((Code)p.params));
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeConstructor result = (CodeConstructor) make_code();
if ( p.params ) {
result->Params = p.params;
}
if ( p.initializer_list ) {
result->InitializerList = p.initializer_list;
}
if ( p.body )
{
switch ( p.body->Type ) {
case CT_Function_Body:
case CT_Untyped:
break;
default:
log_failure("gen::def_constructor: body must be either of Function_Body or Untyped type - %s", code_debug_str(p.body));
return InvalidCode;
}
result->Type = CT_Constructor;
result->Body = p.body;
}
else
{
result->Type = CT_Constructor_Fwd;
}
return result;
}
CodeClass def_class( Str name, Opts_def_struct p )
{
if ( ! name_check( def_class, name ) ) {
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();
return InvalidCode;
}
if ( p.parent && ( p.parent->Type != CT_Class && p.parent->Type != CT_Struct && p.parent->Type != CT_Typename && p.parent->Type != CT_Untyped ) ) {
log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", code_debug_str(p.parent) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeClass
result = (CodeClass) make_code();
result->Name = cache_str( name );
result->ModuleFlags = p.mflags;
if ( p.body )
{
switch ( p.body->Type )
{
case CT_Class_Body:
case CT_Untyped:
break;
default:
log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", code_debug_str(p.body));
return InvalidCode;
}
result->Type = CT_Class;
result->Body = p.body;
result->Body->Parent = cast(Code, result);
}
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 )
{
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("") );
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) );
}
return result;
}
CodeDestructor def_destructor( Opts_def_destructor p )
{
if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) {
log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", code_debug_str(p.specifiers) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeDestructor
result = (CodeDestructor) make_code();
result->Specs = p.specifiers;
if ( p.body )
{
switch ( p.body->Type )
{
case CT_Function_Body:
case CT_Untyped:
break;
default:
log_failure("gen::def_destructor: body must be either of Function_Body or Untyped type - %s", code_debug_str(p.body));
return InvalidCode;
}
result->Type = CT_Destructor;
result->Body = p.body;
}
else
{
result->Type = CT_Destructor_Fwd;
}
return result;
}
CodeEnum def_enum( Str name, Opts_def_enum p )
{
if ( ! name_check( def_enum, name ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.type && p.type->Type != CT_Typename ) {
log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", code_debug_str(p.type) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", code_debug_str(p.attributes) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeEnum
result = (CodeEnum) make_code();
result->Name = cache_str( name );
result->ModuleFlags = p.mflags;
if ( p.body )
{
switch ( p.body->Type )
{
case CT_Enum_Body:
case CT_Untyped:
break;
default:
log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", code_debug_str(p.body));
return InvalidCode;
}
result->Type = p.specifier == EnumDecl_Class ?
CT_Enum_Class : CT_Enum;
result->Body = p.body;
}
else
{
result->Type = p.specifier == EnumDecl_Class ?
CT_Enum_Class_Fwd : CT_Enum_Fwd;
}
result->Attributes = p.attributes;
if ( p.type ) {
result->UnderlyingType = p.type;
}
else if ( p.type_macro ) {
result->UnderlyingTypeMacro = p.type_macro;
}
else if ( result->Type != CT_Enum_Class_Fwd && result->Type != CT_Enum_Fwd )
{
log_failure( "gen::def_enum: enum forward declaration must have an underlying type" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
return result;
}
CodeExec def_execution( Str content )
{
if ( content.Len <= 0 || content.Ptr == nullptr ) {
log_failure( "gen::def_execution: Invalid execution provided" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeExec
result = (CodeExec) make_code();
result->Type = CT_Execution;
result->Content = cache_str( content );
return result;
}
CodeExtern def_extern_link( Str name, CodeBody body )
{
if ( ! name_check(def_extern_link, name) || ! null_check(def_extern_link, body) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( body->Type != CT_Extern_Linkage_Body && body->Type != CT_Untyped ) {
log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", code_debug_str(body));
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeExtern
result = (CodeExtern)make_code();
result->Type = CT_Extern_Linkage;
result->Name = cache_str( name );
result->Body = body;
return result;
}
CodeFriend def_friend( Code declaration )
{
if ( ! null_check( def_friend, declaration ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
switch ( declaration->Type )
{
case CT_Class_Fwd:
case CT_Function_Fwd:
case CT_Operator_Fwd:
case CT_Struct_Fwd:
case CT_Class:
case CT_Function:
case CT_Operator:
case CT_Struct:
break;
default:
log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", code_debug_str(declaration));
return InvalidCode;
}
CodeFriend
result = (CodeFriend) make_code();
result->Type = CT_Friend;
result->Declaration = declaration;
return result;
}
CodeFn def_function( Str name, Opts_def_function p )
{
if ( ! name_check( def_function, name )) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.params && p.params->Type != CT_Parameters ) {
log_failure( "gen::def_function: params was not a `Parameters` type: %s", code_debug_str(p.params) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.ret_type && p.ret_type->Type != CT_Typename ) {
log_failure( "gen::def_function: ret_type was not a Typename: %s", code_debug_str(p.ret_type) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.specs && p.specs-> Type != CT_Specifiers ) {
log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", code_debug_str(p.specs) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.attrs && p.attrs->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", code_debug_str(p.attrs) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeFn
result = (CodeFn) make_code();
result->Name = cache_str( name );
result->ModuleFlags = p.mflags;
if ( p.body )
{
switch ( p.body->Type )
{
case CT_Function_Body:
case CT_Execution:
case CT_Untyped:
break;
default:
{
log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", code_debug_str(p.body));
return InvalidCode;
}
}
result->Type = CT_Function;
result->Body = p.body;
}
else
{
result->Type = CT_Function_Fwd;
}
result->Attributes = p.attrs;
result->Specs = p.specs;
result->Params = p.params;
result->ReturnType = p.ret_type ? p.ret_type : t_void;
return result;
}
CodeInclude def_include( Str path, Opts_def_include p )
{
if ( path.Len <= 0 || path.Ptr == nullptr ) {
log_failure( "gen::def_include: Invalid path provided - %d" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
StrBuilder content = p.foreign ?
strbuilder_fmt_buf( _ctx->Allocator_Temp, "<%.*s>", path.Len, path.Ptr )
: strbuilder_fmt_buf( _ctx->Allocator_Temp, "\"%.*s\"", path.Len, path.Ptr );
CodeInclude
result = (CodeInclude) make_code();
result->Type = CT_Preprocess_Include;
result->Name = cache_str( strbuilder_to_str(content) );
result->Content = result->Name;
return result;
}
CodeModule def_module( Str name, Opts_def_module p )
{
if ( ! name_check( def_module, name )) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeModule
result = (CodeModule) make_code();
result->Type = CT_Module;
result->Name = cache_str( name );
result->ModuleFlags = p.mflags;
return result;
}
CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace p )
{
if ( ! name_check( def_namespace, name )) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( ! null_check( def_namespace, body)) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( body && body->Type != CT_Namespace_Body && body->Type != CT_Untyped ) {
log_failure("gen::def_namespace: body is not of namespace or untyped type %s", code_debug_str(body));
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeNS
result = (CodeNS) make_code();
result->Type = CT_Namespace;
result->Name = cache_str( name );
result->ModuleFlags = p.mflags;
result->Body = body;
return result;
}
CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator p )
{
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", code_debug_str(p.attributes) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) {
log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", code_debug_str(p.specifiers) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
OpValidateResult check_result = operator__validate( op, p.params, p.ret_type, p.specifiers );
if ( check_result == OpValResult_Fail ) {
return InvalidCode;
}
char const* name = nullptr;
Str op_str = operator_to_str( op );
if ( nspace.Len > 0 )
name = c_str_fmt_buf( "%.*soperator %.*s", nspace.Len, nspace.Ptr, op_str.Len, op_str.Ptr );
else
name = c_str_fmt_buf( "operator %.*s", op_str.Len, op_str.Ptr );
Str name_resolved = { name, c_str_len(name) };
CodeOperator
result = (CodeOperator) make_code();
result->Name = cache_str( name_resolved );
result->ModuleFlags = p.mflags;
result->Op = op;
if ( p.body )
{
switch ( p.body->Type )
{
case CT_Function_Body:
case CT_Execution:
case CT_Untyped:
break;
default:
{
log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", code_debug_str(p.body));
GEN_DEBUG_TRAP();
return InvalidCode;
}
}
result->Type = check_result == OpValResult_Global ?
CT_Operator : CT_Operator_Member;
result->Body = p.body;
}
else
{
result->Type = check_result == OpValResult_Global ?
CT_Operator_Fwd : CT_Operator_Member_Fwd;
}
result->Attributes = p.attributes;
result->Specs = p.specifiers;
result->ReturnType = p.ret_type;
result->Params = p.params;
return result;
}
CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast p )
{
if ( ! null_check( def_operator_cast, type )) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( type->Type != CT_Typename ) {
log_failure( "gen::def_operator_cast: type is not a typename - %s", code_debug_str(type) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeOpCast result = (CodeOpCast) make_code();
if (p.body)
{
result->Type = CT_Operator_Cast;
if ( p.body->Type != CT_Function_Body && p.body->Type != CT_Execution ) {
log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", code_debug_str(p.body) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
result->Body = p.body;
}
else
{
result->Type = CT_Operator_Cast_Fwd;
}
result->Specs = p.specs;
result->ValueType = type;
return result;
}
CodeParams def_param( CodeTypename type, Str name, Opts_def_param p )
{
if ( ! name_check( def_param, name ) || ! null_check( def_param, type ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( type->Type != CT_Typename ) {
log_failure( "gen::def_param: type is not a typename - %s", code_debug_str(type) );
return InvalidCode;
}
if ( p.value && p.value->Type != CT_Untyped ) {
log_failure( "gen::def_param: value is not untyped - %s", code_debug_str(p.value) );
return InvalidCode;
}
CodeParams
result = (CodeParams) make_code();
result->Type = CT_Parameters;
result->Name = cache_str( name );
result->ValueType = type;
result->Value = p.value;
result->NumEntries++;
return result;
}
CodePragma def_pragma( Str directive )
{
if ( directive.Len <= 0 || directive.Ptr == nullptr ) {
log_failure( "gen::def_comment: Invalid comment provided:" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodePragma
result = (CodePragma) make_code();
result->Type = CT_Preprocess_Pragma;
result->Content = cache_str( directive );
return result;
}
CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str expr )
{
if ( expr.Len <= 0 || expr.Ptr == nullptr ) {
log_failure( "gen::def_comment: Invalid comment provided:" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodePreprocessCond
result = (CodePreprocessCond) make_code();
result->Content = cache_str( expr );
switch (type)
{
case PreprocessCond_If:
result->Type = CT_Preprocess_If;
break;
case PreprocessCond_IfDef:
result->Type = CT_Preprocess_IfDef;
break;
case PreprocessCond_IfNotDef:
result->Type = CT_Preprocess_IfNotDef;
break;
case PreprocessCond_ElIf:
result->Type = CT_Preprocess_ElIf;
break;
}
return result;
}
CodeSpecifiers def_specifier( Specifier spec )
{
CodeSpecifiers
result = (CodeSpecifiers) make_code();
result->Type = CT_Specifiers;
specifiers_append(result, spec );
return result;
}
CodeStruct def_struct( Str name, Opts_def_struct p )
{
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", code_debug_str(cast(Code, p.attributes)) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.parent && p.parent->Type != CT_Typename ) {
log_failure( "gen::def_struct: parent was not a `Struct` type - %s", code_debug_str(p.parent) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.body && p.body->Type != CT_Struct_Body ) {
log_failure( "gen::def_struct: body was not a Struct_Body type - %s", code_debug_str(p.body) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeStruct
result = (CodeStruct) make_code();
result->ModuleFlags = p.mflags;
if ( name.Len )
result->Name = cache_str( name );
if ( p.body ) {
result->Type = CT_Struct;
result->Body = p.body;
}
else {
result->Type = CT_Struct_Fwd;
}
result->Attributes = p.attributes;
result->ParentAccess = p.parent_access;
result->ParentType = p.parent;
for (s32 idx = 0; idx < p.num_interfaces; idx++ ) {
struct_add_interface(result, p.interfaces[idx] );
}
return result;
}
CodeTemplate def_template( CodeParams params, Code declaration, Opts_def_template p )
{
if ( ! null_check( def_template, declaration ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( params && params->Type != CT_Parameters ){
log_failure( "gen::def_template: params is not of parameters type - %s", code_debug_str(params) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
switch (declaration->Type )
{
case CT_Class:
case CT_Function:
case CT_Struct:
case CT_Variable:
case CT_Using:
break;
default:
log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", code_debug_str(declaration) );
}
CodeTemplate
result = (CodeTemplate) make_code();
result->Type = CT_Template;
result->ModuleFlags = p.mflags;
result->Params = params;
result->Declaration = declaration;
return result;
}
CodeTypename def_type( Str name, Opts_def_type p )
{
if ( ! name_check( def_type, name )) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
Code arrayexpr = p.arrayexpr;
CodeSpecifiers specifiers = p.specifiers;
CodeAttributes attributes = p.attributes;
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_type: attributes is not of attributes type - %s", code_debug_str((Code)p.attributes) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) {
log_failure( "gen::def_type: specifiers is not of specifiers type - %s", code_debug_str((Code)p.specifiers) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.arrayexpr && p.arrayexpr->Type != CT_Untyped ) {
log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", code_debug_str((Code)p.arrayexpr) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeTypename
result = (CodeTypename) make_code();
result->Name = cache_str( name );
result->Type = CT_Typename;
result->Attributes = p.attributes;
result->Specs = p.specifiers;
result->ArrExpr = p.arrayexpr;
result->TypeTag = p.type_tag;
return result;
}
CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef p )
{
if ( ! null_check( def_typedef, type ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
switch ( type->Type )
{
case CT_Class:
case CT_Class_Fwd:
case CT_Enum:
case CT_Enum_Fwd:
case CT_Enum_Class:
case CT_Enum_Class_Fwd:
case CT_Function_Fwd:
case CT_Struct:
case CT_Struct_Fwd:
case CT_Union:
case CT_Typename:
break;
default:
log_failure( "gen::def_typedef: type was not a Class, Enum, Function Forward, Struct, Typename, or Union - %s", code_debug_str((Code)type) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", code_debug_str((Code)p.attributes) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
// Registering the type.
CodeTypename registered_type = def_type( name );
if ( ! registered_type ) {
log_failure( "gen::def_typedef: failed to register type" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeTypedef
result = (CodeTypedef) make_code();
result->Type = CT_Typedef;
result->ModuleFlags = p.mflags;
result->UnderlyingType = type;
if ( name.Len <= 0 )
{
if (type->Type != CT_Untyped) {
log_failure( "gen::def_typedef: name was empty and type was not untyped (indicating its a function typedef) - %s", code_debug_str(type) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
result->Name = cache_str( type->Name );
result->IsFunction = true;
}
else
{
result->Name = cache_str( name );
result->IsFunction = false;
}
return result;
}
CodeUnion def_union( Str name, CodeBody body, Opts_def_union p )
{
if ( ! null_check( def_union, body ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( body->Type != CT_Union_Body ) {
log_failure( "gen::def_union: body was not a Union_Body type - %s", code_debug_str(body) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", code_debug_str(p.attributes) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeUnion
result = (CodeUnion) make_code();
result->ModuleFlags = p.mflags;
result->Type = CT_Union;
result->Body = body;
result->Attributes = p.attributes;
if ( name.Ptr )
result->Name = cache_str( name );
return result;
}
CodeUsing def_using( Str name, CodeTypename type, Opts_def_using p )
{
if ( ! name_check( def_using, name ) || null_check( def_using, type ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeTypename register_type = def_type( name );
if ( ! register_type ) {
log_failure( "gen::def_using: failed to register type" );
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", code_debug_str(p.attributes) );
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeUsing
result = (CodeUsing) make_code();
result->Name = cache_str( name );
result->ModuleFlags = p.mflags;
result->Type = CT_Using;
result->UnderlyingType = type;
result->Attributes = p.attributes;
return result;
}
CodeUsing def_using_namespace( Str name )
{
if ( ! name_check( def_using_namespace, name ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
CodeUsing
result = (CodeUsing) make_code();
result->Name = cache_str( name );
result->Type = CT_Using_Namespace;
return result;
}
CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable p )
{
if ( ! name_check( def_variable, name ) || null_check( def_variable, type ) ) {
GEN_DEBUG_TRAP();
return InvalidCode;
}
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes )
{
log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", code_debug_str(p.attributes) );
return InvalidCode;
}
if ( p.specifiers && p.specifiers->Type != CT_Specifiers )
{
log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", code_debug_str(p.specifiers) );
return InvalidCode;
}
if ( type->Type != CT_Typename )
{
log_failure( "gen::def_variable: type was not a Typename - %s", code_debug_str(type) );
return InvalidCode;
}
if ( p.value && p.value->Type != CT_Untyped )
{
log_failure( "gen::def_variable: value was not a `Untyped` type - %s", code_debug_str(p.value) );
return InvalidCode;
}
CodeVar
result = (CodeVar) make_code();
result->Name = cache_str( name );
result->Type = CT_Variable;
result->ModuleFlags = p.mflags;
result->ValueType = type;
result->Attributes = p.attributes;
result->Specs = p.specifiers;
result->Value = p.value;
return result;
}
#pragma region Helper Macros for def_**_body functions
#define def_body_start( Name_ ) \
if ( num <= 0 ) \
{ \
log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \
return InvalidCode; \
}
#define def_body_code_array_start( Name_ ) \
if ( num <= 0 ) \
{ \
log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \
return InvalidCode; \
} \
\
if ( codes == nullptr ) \
{ \
log_failure("gen::" stringize(Name_)" : Provided a null array of codes"); \
return InvalidCode; \
}
#pragma endregion Helper Macros for def_**_body functions
CodeBody def_class_body( s32 num, ... )
{
def_body_start( def_class_body );
CodeBody result = ( CodeBody )make_code();
result->Type = CT_Class_Body;
va_list va;
va_start( va, num );
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry) {
log_failure("gen::"
"def_class_body"
": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_CLASS_UNALLOWED_TYPES:
log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_class_body( s32 num, Code* codes )
{
def_body_code_array_start( def_class_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Function_Body;
do
{
Code entry = *codes;
codes++;
if ( ! entry) {
log_failure("gen::" "def_class_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_CLASS_UNALLOWED_TYPES:
log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeBody def_enum_body( s32 num, ... )
{
def_body_start( def_enum_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Enum_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry ) {
log_failure("gen::def_enum_body: Provided a null entry");
return InvalidCode;
}
if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) {
log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", code_debug_str(entry) );
return InvalidCode;
}
body_append(result, entry );
}
while ( num--, num > 0 );
va_end(va);
return (CodeBody) result;
}
CodeBody def_enum_body( s32 num, Code* codes )
{
def_body_code_array_start( def_enum_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Enum_Body;
do
{
Code entry = *codes;
if ( ! entry ) {
log_failure("gen::def_enum_body: Provided a null entry");
return InvalidCode;
}
if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) {
log_failure("gen::def_enum_body: Entry type is not allowed: %s", code_debug_str(entry) );
return InvalidCode;
}
body_append(result, entry );
}
while ( codes++, num--, num > 0 );
return result;
}
CodeBody def_export_body( s32 num, ... )
{
def_body_start( def_export_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Export_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry)
{
log_failure("gen::" "def_export_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_EXPORT_UNALLOWED_TYPES:
log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_export_body( s32 num, Code* codes )
{
def_body_code_array_start( def_export_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Export_Body;
do
{
Code entry = *codes;
codes++;
if ( ! entry) {
log_failure("gen::" "def_export_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_EXPORT_UNALLOWED_TYPES:
log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeBody def_extern_link_body( s32 num, ... )
{
def_body_start( def_extern_linkage_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Extern_Linkage_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry) {
log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES:
log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_extern_link_body( s32 num, Code* codes )
{
def_body_code_array_start( def_extern_linkage_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Extern_Linkage_Body;
do
{
Code entry = *codes;
codes++;
if (!entry)
{
log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES:
log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeBody def_function_body( s32 num, ... )
{
def_body_start( def_function_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Function_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry) {
log_failure("gen::" stringize(def_function_body) ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES:
log_failure("gen::" stringize(def_function_body) ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_function_body( s32 num, Code* codes )
{
def_body_code_array_start( def_function_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Function_Body;
do
{
Code entry = *codes;
codes++;
if (!entry) {
log_failure("gen::" "def_function_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES:
log_failure("gen::" "def_function_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeBody def_global_body( s32 num, ... )
{
def_body_start( def_global_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Global_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry) {
log_failure("gen::" "def_global_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
case CT_Global_Body:
// result.body_append( entry.code_cast<CodeBody>() ) ;
body_append_body( result, cast(CodeBody, entry) );
continue;
GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES:
log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_global_body( s32 num, Code* codes )
{
def_body_code_array_start( def_global_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Global_Body;
do
{
Code entry = *codes;
codes++;
if ( ! entry) {
log_failure("gen::" "def_global_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
case CT_Global_Body:
body_append_body(result, cast(CodeBody, entry) );
continue;
GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES:
log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeBody def_namespace_body( s32 num, ... )
{
def_body_start( def_namespace_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Namespace_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry) {
log_failure("gen::" "def_namespace_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES:
log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_namespace_body( s32 num, Code* codes )
{
def_body_code_array_start( def_namespace_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Global_Body;
do
{
Code entry = *codes;
codes++;
if ( ! entry) {
log_failure("gen::" "def_namespace_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES:
log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", code_debug_str(entry) );
return InvalidCode;
default: break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeParams def_params( s32 num, ... )
{
def_body_start( def_params );
va_list va;
va_start(va, num);
Code_POD pod = va_arg(va, Code_POD);
CodeParams param = pcast( CodeParams, pod );
null_check( def_params, param );
if ( param->Type != CT_Parameters ) {
log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 );
return InvalidCode;
}
CodeParams result = (CodeParams) code_duplicate(param);
while ( -- num )
{
pod = va_arg(va, Code_POD);
param = pcast( CodeParams, pod );
if ( param->Type != CT_Parameters ) {
log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 );
return InvalidCode;
}
params_append(result, param );
}
va_end(va);
return result;
}
CodeParams def_params( s32 num, CodeParams* codes )
{
def_body_code_array_start( def_params );
# define check_current(current) \
if ( current == nullptr ) { \
log_failure("gen::def_params: Provide a null code in codes array"); \
return InvalidCode; \
} \
if (current->Type != CT_Parameters ) { \
log_failure("gen::def_params: Code in coes array is not of paramter type - %s", code_debug_str(current) ); \
return InvalidCode; \
}
CodeParams current = (CodeParams)code_duplicate(* codes);
check_current(current);
CodeParams
result = (CodeParams) make_code();
result->Name = current->Name;
result->Type = current->Type;
result->ValueType = current->ValueType;
while( codes++, current = * codes, num--, num > 0 ) {
check_current(current);
params_append(result, current );
}
# undef check_current
return result;
}
CodeSpecifiers def_specifiers( s32 num, ... )
{
if ( num <= 0 ) {
log_failure("gen::def_specifiers: num cannot be zero or less");
return InvalidCode;
}
if ( num > AST_ArrSpecs_Cap ) {
log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num);
return InvalidCode;
}
CodeSpecifiers
result = (CodeSpecifiers) make_code();
result->Type = CT_Specifiers;
va_list va;
va_start(va, num);
do {
Specifier type = (Specifier)va_arg(va, int);
specifiers_append(result, type );
}
while ( --num, num );
va_end(va);
return result;
}
CodeSpecifiers def_specifiers( s32 num, Specifier* specs )
{
if ( num <= 0 ) {
log_failure("gen::def_specifiers: num cannot be zero or less");
return InvalidCode;
}
if ( num > AST_ArrSpecs_Cap ) {
log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num);
return InvalidCode;
}
CodeSpecifiers
result = (CodeSpecifiers) make_code();
result->Type = CT_Specifiers;
s32 idx = 0;
do {
specifiers_append(result, specs[idx] );
idx++;
}
while ( --num, num );
return result;
}
CodeBody def_struct_body( s32 num, ... )
{
def_body_start( def_struct_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Struct_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast(Code, pod);
if ( ! entry) {
log_failure("gen::" "def_struct_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_STRUCT_UNALLOWED_TYPES:
log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", code_debug_str(entry));
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
va_end(va);
return result;
}
CodeBody def_struct_body( s32 num, Code* codes )
{
def_body_code_array_start( def_struct_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Struct_Body;
do
{
Code entry = *codes;
codes++;
if ( ! entry) {
log_failure("gen::" "def_struct_body" ": Provided an null entry");
return InvalidCode;
}
switch (entry->Type)
{
GEN_AST_BODY_STRUCT_UNALLOWED_TYPES:
log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", code_debug_str(entry) );
return InvalidCode;
default:
break;
}
body_append(result, entry);
}
while (num--, num > 0);
return result;
}
CodeBody def_union_body( s32 num, ... )
{
def_body_start( def_union_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Union_Body;
va_list va;
va_start(va, num);
do
{
Code_POD pod = va_arg(va, Code_POD);
Code entry = pcast( Code, pod );
if ( ! entry ) {
log_failure("gen::def_union_body: Provided a null entry");
return InvalidCode;
}
if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) {
log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", code_debug_str(entry) );
return InvalidCode;
}
body_append(result, entry );
}
while ( num--, num > 0 );
va_end(va);
return result;
}
CodeBody def_union_body( s32 num, Code* codes )
{
def_body_code_array_start( def_union_body );
CodeBody
result = (CodeBody) make_code();
result->Type = CT_Union_Body;
do
{
Code entry = *codes;
if ( ! entry ) {
log_failure("gen::def_union_body: Provided a null entry");
return InvalidCode;
}
if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) {
log_failure("gen::def_union_body: Entry type is not allowed: %s", code_debug_str(entry) );
return InvalidCode;
}
body_append(result, entry );
}
while ( codes++, num--, num > 0 );
return (CodeBody) result;
}
# undef name_check
# undef null_check
# undef def_body_start
# undef def_body_code_array_start
#pragma endregion Upfront