2023-07-26 11:21:20 -07:00
|
|
|
#pragma region AST
|
|
|
|
|
2023-07-24 14:45:27 -07:00
|
|
|
Code Code::Global;
|
|
|
|
Code Code::Invalid;
|
|
|
|
|
|
|
|
AST* AST::duplicate()
|
|
|
|
{
|
|
|
|
using namespace ECode;
|
|
|
|
|
2023-07-26 11:21:20 -07:00
|
|
|
AST* result = make_code().ast;
|
2023-07-24 14:45:27 -07:00
|
|
|
|
2023-07-26 11:21:20 -07:00
|
|
|
mem_copy( result, this, sizeof( AST ) );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
2023-07-26 11:21:20 -07:00
|
|
|
result->Parent = nullptr;
|
2023-07-24 14:45:27 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
String AST::to_string()
|
|
|
|
{
|
|
|
|
local_persist thread_local
|
|
|
|
char SerializationLevel = 0;
|
|
|
|
|
|
|
|
// TODO : Need to refactor so that intermeidate strings are freed conviently.
|
|
|
|
String result = String::make( GlobalAllocator, "" );
|
|
|
|
|
|
|
|
switch ( Type )
|
|
|
|
{
|
|
|
|
using namespace ECode;
|
|
|
|
|
|
|
|
case Invalid:
|
|
|
|
log_failure("Attempted to serialize invalid code! - %s", Parent ? Parent->debug_str() : Name );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Untyped:
|
|
|
|
case Execution:
|
|
|
|
result.append( Content );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Comment:
|
|
|
|
{
|
|
|
|
static char line[MaxCommentLineLength];
|
|
|
|
|
|
|
|
s32 left = Content.length();
|
|
|
|
s32 index = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
s32 length = 0;
|
|
|
|
while ( left && Content[index] != '\n' )
|
|
|
|
{
|
|
|
|
length++;
|
|
|
|
left--;
|
|
|
|
}
|
|
|
|
|
|
|
|
str_copy( line, Content, length );
|
|
|
|
line[length] = '\0';
|
|
|
|
|
|
|
|
result.append_fmt( "// %s", line );
|
|
|
|
}
|
|
|
|
while ( left--, left > 0 );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Access_Private:
|
|
|
|
case Access_Protected:
|
|
|
|
case Access_Public:
|
|
|
|
result.append( Name );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PlatformAttributes:
|
|
|
|
result.append( Content );
|
|
|
|
|
|
|
|
case Class:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes || ParentType )
|
|
|
|
{
|
|
|
|
result.append( "class " );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
{
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ParentType )
|
|
|
|
{
|
|
|
|
char const* access_level = to_str( ParentAccess );
|
|
|
|
|
|
|
|
result.append_fmt( "%s : %s %s\n{\n%s\n};"
|
|
|
|
, Name
|
|
|
|
, access_level
|
|
|
|
, ParentType->to_string()
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
|
|
|
|
CodeType interface = Next->cast<CodeType>();
|
|
|
|
if ( interface )
|
|
|
|
result.append("\n");
|
|
|
|
|
|
|
|
while ( interface )
|
|
|
|
{
|
|
|
|
result.append_fmt( ", %s", interface.to_string() );
|
|
|
|
|
|
|
|
interface = interface->Next->cast<CodeType>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s \n{\n%s\n}", Name, Body->to_string() );
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "class %s\n{\n%s\n}", Name, Body->to_string() );
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
2023-07-31 21:42:08 -07:00
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Class_Fwd:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "class %s %s", Attributes->to_string(), Name );
|
|
|
|
|
|
|
|
else result.append_fmt( "class %s", Name );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
2023-07-31 21:42:08 -07:00
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Enum:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes || UnderlyingType )
|
|
|
|
{
|
|
|
|
result.append( "enum " );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( UnderlyingType )
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s : %s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Name
|
|
|
|
, UnderlyingType->to_string()
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
|
2023-07-31 21:42:08 -07:00
|
|
|
else result.append_fmt( "%s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Name
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
2023-07-31 21:42:08 -07:00
|
|
|
else result.append_fmt( "enum %s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Name
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
2023-07-31 21:42:08 -07:00
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Enum_Fwd:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "enum %s : %s", Name, UnderlyingType->to_string() );
|
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Enum_Class:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes || UnderlyingType )
|
|
|
|
{
|
|
|
|
result.append( "enum class " );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
{
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( UnderlyingType )
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s : %s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Name
|
|
|
|
, UnderlyingType->to_string()
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Name
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "enum class %s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
2023-07-31 21:42:08 -07:00
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Enum_Class_Fwd:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
result.append( "enum class " );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s : %s", Name, UnderlyingType->to_string() );
|
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Export_Body:
|
|
|
|
{
|
|
|
|
result.append_fmt( "export\n{\n" );
|
|
|
|
|
|
|
|
Code curr = { this };
|
|
|
|
s32 left = NumEntries;
|
|
|
|
while ( left-- )
|
|
|
|
{
|
|
|
|
result.append_fmt( "%s\n", curr.to_string() );
|
|
|
|
++curr;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt( "};" );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Extern_Linkage:
|
|
|
|
result.append_fmt( "extern \"%s\"\n{\n%s\n}"
|
|
|
|
, Name
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Friend:
|
|
|
|
result.append_fmt( "friend %s", Declaration->to_string() );
|
|
|
|
|
|
|
|
if ( result[ result.length() -1 ] != ';' )
|
|
|
|
result.append( ";" );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Function:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
result.append_fmt( "%s\n", Specs->to_string() );
|
|
|
|
|
|
|
|
if ( ReturnType )
|
|
|
|
result.append_fmt( "%s %s(", ReturnType->to_string(), Name );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append_fmt( "%s(", Name );
|
|
|
|
|
|
|
|
if ( Params )
|
|
|
|
result.append_fmt( "%s)", Params->to_string() );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append( "void)" );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
{
|
|
|
|
CodeSpecifiers specs = cast<CodeSpecifiers>();
|
|
|
|
|
|
|
|
for ( SpecifierT spec : specs )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( spec ) )
|
|
|
|
result.append_fmt( " %s", (char const*)ESpecifier::to_str( spec ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt( "\n{\n%s\n}"
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Function_Fwd:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
result.append_fmt( "%s\n", Specs->to_string() );
|
|
|
|
|
|
|
|
if ( ReturnType )
|
|
|
|
result.append_fmt( "%s %s(", ReturnType->to_string(), Name );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append_fmt( "%s(", Name );
|
|
|
|
|
|
|
|
if ( Params )
|
|
|
|
result.append_fmt( "%s)", Params->to_string() );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append( "void)" );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
{
|
|
|
|
CodeSpecifiers specs = cast<CodeSpecifiers>();
|
|
|
|
|
|
|
|
for ( SpecifierT spec : specs )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( spec ) )
|
|
|
|
result.append_fmt( " %s", (char const*)ESpecifier::to_str( spec ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append( ";" );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Module:
|
|
|
|
if (((u32(ModuleFlag::Export) & u32(ModuleFlags)) == u32(ModuleFlag::Export)))
|
|
|
|
result.append("export ");
|
|
|
|
|
|
|
|
if (((u32(ModuleFlag::Import) & u32(ModuleFlags)) == u32(ModuleFlag::Import)))
|
|
|
|
result.append("import ");
|
|
|
|
|
|
|
|
result.append_fmt( "%s;", Name );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Namespace:
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
result.append_fmt( "namespace %s\n{\n%s}"
|
|
|
|
, Name
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Operator:
|
|
|
|
case Operator_Member:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s\n", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( ReturnType )
|
|
|
|
result.append_fmt( "%s %s (", ReturnType->to_string(), Name );
|
|
|
|
|
|
|
|
if ( Params )
|
|
|
|
result.append_fmt( "%s)", Params->to_string() );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append( "void)" );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
{
|
|
|
|
CodeSpecifiers specs = cast<CodeSpecifiers>();
|
|
|
|
|
|
|
|
for ( SpecifierT spec : specs )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( spec ) )
|
|
|
|
result.append_fmt( " %s", (char const*)ESpecifier::to_str( spec ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt( "\n{\n%s\n}"
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Operator_Fwd:
|
|
|
|
case Operator_Member_Fwd:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
result.append_fmt( "%s", Specs->to_string() );
|
|
|
|
|
|
|
|
result.append_fmt( "%s %s (", ReturnType->to_string(), Name );
|
|
|
|
|
|
|
|
if ( Params )
|
|
|
|
result.append_fmt( "%s)", Params->to_string() );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append_fmt( "void)" );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
{
|
|
|
|
CodeSpecifiers specs = cast<CodeSpecifiers>();
|
|
|
|
|
|
|
|
for ( SpecifierT spec : specs )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( spec ) )
|
|
|
|
result.append_fmt( " %s", (char const*)ESpecifier::to_str( spec ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append( ";" );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Operator_Cast:
|
|
|
|
{
|
|
|
|
if ( Specs )
|
|
|
|
{
|
|
|
|
result.append_fmt( "operator %s()" );
|
|
|
|
|
|
|
|
CodeSpecifiers specs = cast<CodeSpecifiers>();
|
|
|
|
|
|
|
|
for ( SpecifierT spec : specs )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( spec ) )
|
|
|
|
result.append_fmt( " %s", (char const*)ESpecifier::to_str( spec ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt( "\n{\n%s\n}", Body->to_string() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt("operator %s()\n{\n%s\n}", ValueType->to_string(), Body->to_string() );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Operator_Cast_Fwd:
|
|
|
|
if ( Specs )
|
|
|
|
{
|
|
|
|
result.append_fmt( "operator %s()" );
|
|
|
|
|
|
|
|
CodeSpecifiers specs = cast<CodeSpecifiers>();
|
|
|
|
|
|
|
|
for ( SpecifierT spec : specs )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( spec ) )
|
|
|
|
result.append_fmt( " %s", (char const*)ESpecifier::to_str( spec ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt( ";", Body->to_string() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt("operator %s();", ValueType->to_string() );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Parameters:
|
|
|
|
{
|
|
|
|
if ( Name )
|
|
|
|
result.append_fmt( "%s %s", ValueType->to_string(), Name );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append_fmt( "%s", ValueType->to_string() );
|
|
|
|
|
|
|
|
if ( Value )
|
|
|
|
result.append_fmt( "= %s", Value->to_string() );
|
|
|
|
|
|
|
|
if ( NumEntries - 1 > 0)
|
|
|
|
{
|
|
|
|
for ( CodeParam param : CodeParam { (AST_Param*) Next } )
|
|
|
|
{
|
|
|
|
result.append_fmt( ", %s", param.to_string() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2023-07-29 22:21:04 -07:00
|
|
|
case Preprocess_Define:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#define %s %s\n", Name, Content );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_If:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#if %s\n", Content );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_IfDef:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#ifdef %s\n", Content );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_IfNotDef:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#ifndef %s\n", Content );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_Include:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#include \"%s\"\n", Content );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_ElIf:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#elif %s\n", Content );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_Else:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#else\n" );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_EndIf:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#endif\n" );
|
2023-07-29 22:21:04 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Preprocess_Pragma:
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "#pragma %s\n", Content );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Specifiers:
|
|
|
|
{
|
|
|
|
s32 idx = 0;
|
|
|
|
s32 left = NumEntries;
|
|
|
|
while ( left-- )
|
|
|
|
{
|
|
|
|
if ( ESpecifier::is_trailing( ArrSpecs[idx]) )
|
|
|
|
{
|
|
|
|
idx++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append_fmt( "%s ", (char const*)ESpecifier::to_str( ArrSpecs[idx]) );
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Struct:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Name == nullptr)
|
|
|
|
{
|
|
|
|
result.append( "struct\n{\n%s\n};", Body->to_string() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Attributes || ParentType )
|
|
|
|
{
|
|
|
|
result.append( "struct " );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( ParentType )
|
|
|
|
{
|
|
|
|
char const* access_level = to_str( ParentAccess );
|
|
|
|
|
|
|
|
result.append_fmt( "%s : %s %s\n{\n%s\n};"
|
|
|
|
, Name
|
|
|
|
, access_level
|
|
|
|
, ParentType->to_string()
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
|
|
|
|
CodeType interface = Next->cast<CodeType>();
|
|
|
|
if ( interface )
|
|
|
|
result.append("\n");
|
|
|
|
|
|
|
|
while ( interface )
|
|
|
|
{
|
|
|
|
result.append_fmt( ", public %s", interface.to_string() );
|
|
|
|
|
|
|
|
interface = interface->Next->cast<CodeType>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( Name )
|
|
|
|
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s \n{\n%s\n}", Name, Body->to_string() );
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "struct %s\n{\n%s\n}", Name, Body->to_string() );
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
2023-07-31 21:42:08 -07:00
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Struct_Fwd:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "struct %s %s", Attributes->to_string(), Name );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
2023-07-31 21:42:08 -07:00
|
|
|
else result.append_fmt( "struct %s", Name );
|
|
|
|
|
|
|
|
if ( Parent && Parent->Type != ECode::Typedef )
|
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Template:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
result.append_fmt( "template< %s >\n%s", Params->to_string(), Declaration->to_string() );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Typedef:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
result.append( "typedef ");
|
|
|
|
|
|
|
|
result.append_fmt( "%s %s", UnderlyingType->to_string(), Name );
|
|
|
|
|
|
|
|
if ( UnderlyingType->Type == Typename && UnderlyingType->ArrExpr )
|
|
|
|
{
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append_fmt( "[%s];\n", UnderlyingType->ArrExpr->to_string() );
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-08-01 11:02:54 -07:00
|
|
|
result.append( ";\n" );
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Typename:
|
|
|
|
{
|
|
|
|
if ( Attributes || Specs )
|
|
|
|
{
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
result.append_fmt( "%s %s", Name, Specs->to_string() );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append_fmt( "%s", Name );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result.append_fmt( "%s", Name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Union:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
result.append( "union " );
|
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( Name )
|
|
|
|
{
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "%s\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Name
|
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Anonymous union
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append_fmt( "\n{\n%s\n}"
|
2023-07-24 14:45:27 -07:00
|
|
|
, Body->to_string()
|
|
|
|
);
|
|
|
|
}
|
2023-07-31 21:42:08 -07:00
|
|
|
|
2023-08-01 02:17:24 -07:00
|
|
|
bool add_semicolon = Parent && Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable;
|
|
|
|
|
|
|
|
if ( add_semicolon )
|
2023-07-31 21:42:08 -07:00
|
|
|
result.append(";");
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Using:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Attributes->to_string() );
|
|
|
|
|
|
|
|
if ( UnderlyingType )
|
|
|
|
{
|
|
|
|
result.append_fmt( "using %s = %s", Name, UnderlyingType->to_string() );
|
|
|
|
|
|
|
|
if ( UnderlyingType->ArrExpr )
|
|
|
|
result.append_fmt( "[%s]", UnderlyingType->ArrExpr->to_string() );
|
|
|
|
|
|
|
|
result.append( ";" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result.append_fmt( "using %s;", Name );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Using_Namespace:
|
|
|
|
result.append_fmt( "using namespace %s;", Name );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Variable:
|
|
|
|
{
|
2023-07-29 02:52:06 -07:00
|
|
|
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))
|
|
|
|
result.append( "export " );
|
2023-07-24 14:45:27 -07:00
|
|
|
|
|
|
|
if ( Attributes || Specs )
|
|
|
|
{
|
|
|
|
if ( Attributes )
|
|
|
|
result.append_fmt( "%s ", Specs->to_string() );
|
|
|
|
|
|
|
|
if ( Specs )
|
|
|
|
result.append_fmt( "%s\n", Specs->to_string() );
|
|
|
|
|
|
|
|
result.append_fmt( "%s %s", ValueType->to_string(), Name );
|
|
|
|
|
|
|
|
if ( ValueType->ArrExpr )
|
|
|
|
result.append_fmt( "[%s]", ValueType->ArrExpr->to_string() );
|
|
|
|
|
2023-08-01 02:17:24 -07:00
|
|
|
if ( BitfieldSize )
|
|
|
|
result.append_fmt( " : %lu", BitfieldSize );
|
|
|
|
|
2023-07-24 14:45:27 -07:00
|
|
|
if ( Value )
|
|
|
|
result.append_fmt( " = %s", Value->to_string() );
|
|
|
|
|
|
|
|
result.append( ";" );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-08-01 02:17:24 -07:00
|
|
|
if ( BitfieldSize )
|
|
|
|
result.append_fmt( "%s : %lu", ValueType->to_string(), BitfieldSize );
|
|
|
|
|
|
|
|
else if ( UnderlyingType->ArrExpr )
|
2023-07-24 14:45:27 -07:00
|
|
|
result.append_fmt( "%s %s[%s];", UnderlyingType->to_string(), Name, UnderlyingType->ArrExpr->to_string() );
|
|
|
|
|
|
|
|
else
|
|
|
|
result.append_fmt( "%s %s;", UnderlyingType->to_string(), Name );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Class_Body:
|
|
|
|
case Enum_Body:
|
|
|
|
case Extern_Linkage_Body:
|
|
|
|
case Function_Body:
|
|
|
|
case Global_Body:
|
|
|
|
case Namespace_Body:
|
|
|
|
case Struct_Body:
|
|
|
|
case Union_Body:
|
|
|
|
{
|
|
|
|
Code curr = Front->cast<Code>();
|
|
|
|
s32 left = NumEntries;
|
|
|
|
while ( left -- )
|
|
|
|
{
|
|
|
|
result.append_fmt( "%s\n", curr.to_string() );
|
|
|
|
++curr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AST::is_equal( AST* other )
|
|
|
|
{
|
|
|
|
if ( Type != other->Type )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch ( Type )
|
|
|
|
{
|
|
|
|
case ECode::Typedef:
|
|
|
|
case ECode::Typename:
|
|
|
|
{
|
|
|
|
if ( Name != other->Name )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Name != other->Name )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AST::validate_body()
|
|
|
|
{
|
|
|
|
using namespace ECode;
|
|
|
|
|
2023-07-29 02:52:06 -07:00
|
|
|
#define CheckEntries( Unallowed_Types ) \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
for ( Code entry : cast<CodeBody>() ) \
|
|
|
|
{ \
|
|
|
|
switch ( entry->Type ) \
|
|
|
|
{ \
|
|
|
|
Unallowed_Types \
|
|
|
|
log_failure( "AST::validate_body: Invalid entry in body %s", entry.debug_str() ); \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} \
|
2023-07-24 14:45:27 -07:00
|
|
|
while (0);
|
|
|
|
|
|
|
|
switch ( Type )
|
|
|
|
{
|
|
|
|
case Class_Body:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Enum_Body:
|
|
|
|
for ( Code entry : cast<CodeBody>() )
|
|
|
|
{
|
|
|
|
if ( entry->Type != Untyped )
|
|
|
|
{
|
|
|
|
log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %s", entry.debug_str() );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Export_Body:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Extern_Linkage:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Function_Body:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Global_Body:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Namespace_Body:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Struct_Body:
|
2023-07-28 18:44:31 -07:00
|
|
|
CheckEntries( GEN_AST_BODY_STRUCT_UNALLOWED_TYPES );
|
2023-07-24 14:45:27 -07:00
|
|
|
break;
|
|
|
|
case Union_Body:
|
|
|
|
for ( Code entry : Body->cast<CodeBody>() )
|
|
|
|
{
|
|
|
|
if ( entry->Type != Untyped )
|
|
|
|
{
|
|
|
|
log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %s", entry.debug_str() );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
log_failure( "AST::validate_body: Invalid this AST does not have a body %s", debug_str() );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2023-07-29 02:52:06 -07:00
|
|
|
|
|
|
|
#undef CheckEntries
|
2023-07-24 14:45:27 -07:00
|
|
|
}
|
2023-07-26 11:21:20 -07:00
|
|
|
|
|
|
|
#pragma endregion AST
|