// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)

#pragma once

#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wvarargs"
#pragma clang diagnostic ignored "-Wunused-function"
#endif

#if __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wcomment"
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#pragma once

/*
    gencpp: An attempt at "simple" staged metaprogramming for c/c++.

    See Readme.md for more information from the project repository.

    Public Address:
    https://github.com/Ed94/gencpp
*/
#if ! defined( GEN_DONT_ENFORCE_GEN_TIME_GUARD ) && ! defined( GEN_TIME )
#error Gen.hpp : GEN_TIME not defined
#endif

//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file.
// Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl
#ifndef GEN_ROLL_OWN_DEPENDENCIES
#include "gen.dep.hpp"
#endif

#ifndef GEN_NS_BEGIN
#ifdef GEN_DONT_USE_NAMESPACE
#define GEN_NS
#define GEN_NS_BEGIN
#define GEN_NS_END
#else
#define GEN_NS gen::
#define GEN_NS_BEGIN \
	namespace gen    \
	{
#define GEN_NS_END }
#endif
#endif

GEN_NS_BEGIN

#pragma region Types

using LogFailType = sw ( * )( char const*, ... );

// By default this library will either crash or exit if an error is detected while generating codes.
// Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur.
#ifdef GEN_DONT_USE_FATAL
#define log_failure log_fmt
#else
#define log_failure GEN_FATAL
#endif

enum class AccessSpec : u32
{
	Default,
	Private,
	Protected,
	Public,

	Num_AccessSpec,
	Invalid,
};

inline char const* to_str( AccessSpec type )
{
	local_persist char const* lookup[(u32)AccessSpec::Num_AccessSpec] = {
		"",
		"private",
		"protected",
		"public",
	};

	if ( type > AccessSpec::Public )
		return "Invalid";

	return lookup[(u32)type];
}

enum CodeFlag : u32
{
	None          = 0,
	FunctionType  = bit( 0 ),
	ParamPack     = bit( 1 ),
	Module_Export = bit( 2 ),
	Module_Import = bit( 3 ),
};

// Used to indicate if enum definitoin is an enum class or regular enum.
enum class EnumT : u8
{
	Regular,
	Class
};

constexpr EnumT EnumClass   = EnumT::Class;
constexpr EnumT EnumRegular = EnumT::Regular;

enum class ModuleFlag : u32
{
	None   = 0,
	Export = bit( 0 ),
	Import = bit( 1 ),

	Num_ModuleFlags,
	Invalid,
};

StrC to_str( ModuleFlag flag )
{
	local_persist StrC lookup[(u32)ModuleFlag::Num_ModuleFlags] = {
		{ sizeof( "__none__" ), "__none__" },
		{ sizeof( "export" ),   "export"   },
		{ sizeof( "import" ),   "import"   },
	};

	if ( flag > ModuleFlag::Import )
		return { sizeof( "invalid" ), "invalid" };

	return lookup[(u32)flag];
}

ModuleFlag operator|( ModuleFlag A, ModuleFlag B )
{
	return (ModuleFlag)( (u32)A | (u32)B );
}

enum class EPreprocessCond : u32
{
	If,
	IfDef,
	IfNotDef,
	ElIf
};

constexpr EPreprocessCond PreprocessCond_If       = EPreprocessCond::If;
constexpr EPreprocessCond PreprocessCond_IfDef    = EPreprocessCond::IfDef;
constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef;
constexpr EPreprocessCond PreprocessCond_ElIf     = EPreprocessCond::ElIf;

namespace ECode
{
	enum Type : u32
	{
		Invalid,
		Untyped,
		NewLine,
		Comment,
		Access_Private,
		Access_Protected,
		Access_Public,
		PlatformAttributes,
		Class,
		Class_Fwd,
		Class_Body,
		Constructor,
		Constructor_Fwd,
		Destructor,
		Destructor_Fwd,
		Enum,
		Enum_Fwd,
		Enum_Body,
		Enum_Class,
		Enum_Class_Fwd,
		Execution,
		Export_Body,
		Extern_Linkage,
		Extern_Linkage_Body,
		Friend,
		Function,
		Function_Fwd,
		Function_Body,
		Global_Body,
		Module,
		Namespace,
		Namespace_Body,
		Operator,
		Operator_Fwd,
		Operator_Member,
		Operator_Member_Fwd,
		Operator_Cast,
		Operator_Cast_Fwd,
		Parameters,
		Preprocess_Define,
		Preprocess_Include,
		Preprocess_If,
		Preprocess_IfDef,
		Preprocess_IfNotDef,
		Preprocess_ElIf,
		Preprocess_Else,
		Preprocess_EndIf,
		Preprocess_Pragma,
		Specifiers,
		Struct,
		Struct_Fwd,
		Struct_Body,
		Template,
		Typedef,
		Typename,
		Union,
		Union_Body,
		Using,
		Using_Namespace,
		Variable,
		NumTypes
	};

	StrC to_str( Type type )
	{
		local_persist StrC lookup[] {
			{ sizeof( "Invalid" ),             "Invalid"             },
			{ sizeof( "Untyped" ),             "Untyped"             },
			{ sizeof( "NewLine" ),             "NewLine"             },
			{ sizeof( "Comment" ),             "Comment"             },
			{ sizeof( "Access_Private" ),      "Access_Private"      },
			{ sizeof( "Access_Protected" ),    "Access_Protected"    },
			{ sizeof( "Access_Public" ),       "Access_Public"       },
			{ sizeof( "PlatformAttributes" ),  "PlatformAttributes"  },
			{ sizeof( "Class" ),               "Class"               },
			{ sizeof( "Class_Fwd" ),           "Class_Fwd"           },
			{ sizeof( "Class_Body" ),          "Class_Body"          },
			{ sizeof( "Constructor" ),         "Constructor"         },
			{ sizeof( "Constructor_Fwd" ),     "Constructor_Fwd"     },
			{ sizeof( "Destructor" ),          "Destructor"          },
			{ sizeof( "Destructor_Fwd" ),      "Destructor_Fwd"      },
			{ sizeof( "Enum" ),                "Enum"                },
			{ sizeof( "Enum_Fwd" ),            "Enum_Fwd"            },
			{ sizeof( "Enum_Body" ),           "Enum_Body"           },
			{ sizeof( "Enum_Class" ),          "Enum_Class"          },
			{ sizeof( "Enum_Class_Fwd" ),      "Enum_Class_Fwd"      },
			{ sizeof( "Execution" ),           "Execution"           },
			{ sizeof( "Export_Body" ),         "Export_Body"         },
			{ sizeof( "Extern_Linkage" ),      "Extern_Linkage"      },
			{ sizeof( "Extern_Linkage_Body" ), "Extern_Linkage_Body" },
			{ sizeof( "Friend" ),              "Friend"              },
			{ sizeof( "Function" ),            "Function"            },
			{ sizeof( "Function_Fwd" ),        "Function_Fwd"        },
			{ sizeof( "Function_Body" ),       "Function_Body"       },
			{ sizeof( "Global_Body" ),         "Global_Body"         },
			{ sizeof( "Module" ),              "Module"              },
			{ sizeof( "Namespace" ),           "Namespace"           },
			{ sizeof( "Namespace_Body" ),      "Namespace_Body"      },
			{ sizeof( "Operator" ),            "Operator"            },
			{ sizeof( "Operator_Fwd" ),        "Operator_Fwd"        },
			{ sizeof( "Operator_Member" ),     "Operator_Member"     },
			{ sizeof( "Operator_Member_Fwd" ), "Operator_Member_Fwd" },
			{ sizeof( "Operator_Cast" ),       "Operator_Cast"       },
			{ sizeof( "Operator_Cast_Fwd" ),   "Operator_Cast_Fwd"   },
			{ sizeof( "Parameters" ),          "Parameters"          },
			{ sizeof( "Preprocess_Define" ),   "Preprocess_Define"   },
			{ sizeof( "Preprocess_Include" ),  "Preprocess_Include"  },
			{ sizeof( "Preprocess_If" ),       "Preprocess_If"       },
			{ sizeof( "Preprocess_IfDef" ),    "Preprocess_IfDef"    },
			{ sizeof( "Preprocess_IfNotDef" ), "Preprocess_IfNotDef" },
			{ sizeof( "Preprocess_ElIf" ),     "Preprocess_ElIf"     },
			{ sizeof( "Preprocess_Else" ),     "Preprocess_Else"     },
			{ sizeof( "Preprocess_EndIf" ),    "Preprocess_EndIf"    },
			{ sizeof( "Preprocess_Pragma" ),   "Preprocess_Pragma"   },
			{ sizeof( "Specifiers" ),          "Specifiers"          },
			{ sizeof( "Struct" ),              "Struct"              },
			{ sizeof( "Struct_Fwd" ),          "Struct_Fwd"          },
			{ sizeof( "Struct_Body" ),         "Struct_Body"         },
			{ sizeof( "Template" ),            "Template"            },
			{ sizeof( "Typedef" ),             "Typedef"             },
			{ sizeof( "Typename" ),            "Typename"            },
			{ sizeof( "Union" ),               "Union"               },
			{ sizeof( "Union_Body" ),          "Union_Body"          },
			{ sizeof( "Using" ),               "Using"               },
			{ sizeof( "Using_Namespace" ),     "Using_Namespace"     },
			{ sizeof( "Variable" ),            "Variable"            },
		};
		return lookup[type];
	}

}    // namespace ECode

using CodeT = ECode::Type;

namespace EOperator
{
	enum Type : u32
	{
		Invalid,
		Assign,
		Assign_Add,
		Assign_Subtract,
		Assign_Multiply,
		Assign_Divide,
		Assign_Modulo,
		Assign_BAnd,
		Assign_BOr,
		Assign_BXOr,
		Assign_LShift,
		Assign_RShift,
		Increment,
		Decrement,
		Unary_Plus,
		Unary_Minus,
		UnaryNot,
		Add,
		Subtract,
		Multiply,
		Divide,
		Modulo,
		BNot,
		BAnd,
		BOr,
		BXOr,
		LShift,
		RShift,
		LAnd,
		LOr,
		LEqual,
		LNot,
		Lesser,
		Greater,
		LesserEqual,
		GreaterEqual,
		Subscript,
		Indirection,
		AddressOf,
		MemberOfPointer,
		PtrToMemOfPtr,
		FunctionCall,
		Comma,
		New,
		NewArray,
		Delete,
		DeleteArray,
		NumOps
	};

	StrC to_str( Type op )
	{
		local_persist StrC lookup[] {
			{ sizeof( "INVALID" ),  "INVALID"  },
			{ sizeof( "=" ),        "="        },
			{ sizeof( "+=" ),       "+="       },
			{ sizeof( "-=" ),       "-="       },
			{ sizeof( "*=" ),       "*="       },
			{ sizeof( "/=" ),       "/="       },
			{ sizeof( "%=" ),       "%="       },
			{ sizeof( "&=" ),       "&="       },
			{ sizeof( "|=" ),       "|="       },
			{ sizeof( "^=" ),       "^="       },
			{ sizeof( "<<=" ),      "<<="      },
			{ sizeof( ">>=" ),      ">>="      },
			{ sizeof( "++" ),       "++"       },
			{ sizeof( "--" ),       "--"       },
			{ sizeof( "+" ),        "+"        },
			{ sizeof( "-" ),        "-"        },
			{ sizeof( "!" ),        "!"        },
			{ sizeof( "+" ),        "+"        },
			{ sizeof( "-" ),        "-"        },
			{ sizeof( "*" ),        "*"        },
			{ sizeof( "/" ),        "/"        },
			{ sizeof( "%" ),        "%"        },
			{ sizeof( "~" ),        "~"        },
			{ sizeof( "&" ),        "&"        },
			{ sizeof( "|" ),        "|"        },
			{ sizeof( "^" ),        "^"        },
			{ sizeof( "<<" ),       "<<"       },
			{ sizeof( ">>" ),       ">>"       },
			{ sizeof( "&&" ),       "&&"       },
			{ sizeof( "||" ),       "||"       },
			{ sizeof( "==" ),       "=="       },
			{ sizeof( "!=" ),       "!="       },
			{ sizeof( "<" ),        "<"        },
			{ sizeof( ">" ),        ">"        },
			{ sizeof( "<=" ),       "<="       },
			{ sizeof( ">=" ),       ">="       },
			{ sizeof( "[]" ),       "[]"       },
			{ sizeof( "*" ),        "*"        },
			{ sizeof( "&" ),        "&"        },
			{ sizeof( "->" ),       "->"       },
			{ sizeof( "->*" ),      "->*"      },
			{ sizeof( "()" ),       "()"       },
			{ sizeof( "," ),        ","        },
			{ sizeof( "new" ),      "new"      },
			{ sizeof( "new[]" ),    "new[]"    },
			{ sizeof( "delete" ),   "delete"   },
			{ sizeof( "delete[]" ), "delete[]" },
		};
		return lookup[op];
	}

}    // namespace EOperator

using OperatorT = EOperator::Type;

namespace ESpecifier
{
	enum Type : u32
	{
		Invalid,
		Consteval,
		Constexpr,
		Constinit,
		Explicit,
		External_Linkage,
		ForceInline,
		Global,
		Inline,
		Internal_Linkage,
		Local_Persist,
		Mutable,
		NeverInline,
		Ptr,
		Ref,
		Register,
		RValue,
		Static,
		Thread_Local,
		Virtual,
		Const,
		Final,
		NoExceptions,
		Override,
		Pure,
		Volatile,
		NumSpecifiers
	};

	bool is_trailing( Type specifier )
	{
		return specifier > Virtual;
	}

	StrC to_str( Type type )
	{
		local_persist StrC lookup[] {
			{ sizeof( "INVALID" ),       "INVALID"       },
			{ sizeof( "consteval" ),     "consteval"     },
			{ sizeof( "constexpr" ),     "constexpr"     },
			{ sizeof( "constinit" ),     "constinit"     },
			{ sizeof( "explicit" ),      "explicit"      },
			{ sizeof( "extern" ),        "extern"        },
			{ sizeof( "FORCEINLINE" ),   "FORCEINLINE"   },
			{ sizeof( "global" ),        "global"        },
			{ sizeof( "inline" ),        "inline"        },
			{ sizeof( "internal" ),      "internal"      },
			{ sizeof( "local_persist" ), "local_persist" },
			{ sizeof( "mutable" ),       "mutable"       },
			{ sizeof( "neverinline" ),   "neverinline"   },
			{ sizeof( "*" ),             "*"             },
			{ sizeof( "&" ),             "&"             },
			{ sizeof( "register" ),      "register"      },
			{ sizeof( "&&" ),            "&&"            },
			{ sizeof( "static" ),        "static"        },
			{ sizeof( "thread_local" ),  "thread_local"  },
			{ sizeof( "virtual" ),       "virtual"       },
			{ sizeof( "const" ),         "const"         },
			{ sizeof( "final" ),         "final"         },
			{ sizeof( "noexcept" ),      "noexcept"      },
			{ sizeof( "override" ),      "override"      },
			{ sizeof( "= 0" ),           "= 0"           },
			{ sizeof( "volatile" ),      "volatile"      },
		};
		return lookup[type];
	}

	Type to_type( StrC str )
	{
		local_persist u32 keymap[NumSpecifiers];
		do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ )
		{
			StrC enum_str = to_str( (Type)index );
			keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 );
		}
		do_once_end u32 hash = crc32( str.Ptr, str.Len );
		for ( u32 index = 0; index < NumSpecifiers; index++ )
		{
			if ( keymap[index] == hash )
				return (Type)index;
		}
		return Invalid;
	}

}    // namespace ESpecifier

using SpecifierT = ESpecifier::Type;

#pragma endregion Types

#pragma region AST

struct AST;
struct AST_Body;
struct AST_Attributes;
struct AST_Comment;
struct AST_Constructor;
// struct AST_BaseClass;
struct AST_Class;
struct AST_Define;
struct AST_Destructor;
struct AST_Enum;
struct AST_Exec;
struct AST_Extern;
struct AST_Include;
struct AST_Friend;
struct AST_Fn;
struct AST_Module;
struct AST_NS;
struct AST_Operator;
struct AST_OpCast;
struct AST_Param;
struct AST_Pragma;
struct AST_PreprocessCond;
struct AST_Specifiers;

#if GEN_EXECUTION_EXPRESSION_SUPPORT
struct AST_Expr;
struct AST_Expr_Assign;
struct AST_Expr_Alignof;
struct AST_Expr_Binary;
struct AST_Expr_CStyleCast;
struct AST_Expr_FunctionalCast;
struct AST_Expr_CppCast;
struct AST_Expr_ProcCall;
struct AST_Expr_Decltype;
struct AST_Expr_Comma;    // TODO(Ed) : This is a binary op not sure if it needs its own AST...
struct AST_Expr_AMS;      // Access Member Symbol
struct AST_Expr_Sizeof;
struct AST_Expr_Subscript;
struct AST_Expr_Ternary;
struct AST_Expr_UnaryPrefix;
struct AST_Expr_UnaryPostfix;
struct AST_Expr_Element;

struct AST_Stmt;
struct AST_Stmt_Break;
struct AST_Stmt_Case;
struct AST_Stmt_Continue;
struct AST_Stmt_Decl;
struct AST_Stmt_Do;
struct AST_Stmt_Expr;    // TODO(Ed) : Is this distinction needed? (Should it be a flag instead?)
struct AST_Stmt_Else;
struct AST_Stmt_If;
struct AST_Stmt_For;
struct AST_Stmt_Goto;
struct AST_Stmt_Label;
struct AST_Stmt_Switch;
struct AST_Stmt_While;
#endif

struct AST_Struct;
struct AST_Template;
struct AST_Type;
struct AST_Typedef;
struct AST_Union;
struct AST_Using;
struct AST_Var;

struct Code;
struct CodeBody;
// These are to offer ease of use and optionally strong type safety for the AST.
struct CodeAttributes;
// struct CodeBaseClass;
struct CodeComment;
struct CodeClass;
struct CodeConstructor;
struct CodeDefine;
struct CodeDestructor;
struct CodeEnum;
struct CodeExec;
struct CodeExtern;
struct CodeInclude;
struct CodeFriend;
struct CodeFn;
struct CodeModule;
struct CodeNS;
struct CodeOperator;
struct CodeOpCast;
struct CodeParam;
struct CodePreprocessCond;
struct CodePragma;
struct CodeSpecifiers;

#if GEN_EXECUTION_EXPRESSION_SUPPORT
struct CodeExpr;
struct CodeExpr_Assign;
struct CodeExpr_Alignof;
struct CodeExpr_Binary;
struct CodeExpr_CStyleCast;
struct CodeExpr_FunctionalCast;
struct CodeExpr_CppCast;
struct CodeExpr_Element;
struct CodeExpr_ProcCall;
struct CodeExpr_Decltype;
struct CodeExpr_Comma;
struct CodeExpr_AMS;    // Access Member Symbol
struct CodeExpr_Sizeof;
struct CodeExpr_Subscript;
struct CodeExpr_Ternary;
struct CodeExpr_UnaryPrefix;
struct CodeExpr_UnaryPostfix;

struct CodeStmt;
struct CodeStmt_Break;
struct CodeStmt_Case;
struct CodeStmt_Continue;
struct CodeStmt_Decl;
struct CodeStmt_Do;
struct CodeStmt_Expr;
struct CodeStmt_Else;
struct CodeStmt_If;
struct CodeStmt_For;
struct CodeStmt_Goto;
struct CodeStmt_Label;
struct CodeStmt_Switch;
struct CodeStmt_While;
#endif

struct CodeStruct;
struct CodeTemplate;
struct CodeType;
struct CodeTypedef;
struct CodeUnion;
struct CodeUsing;
struct CodeVar;

namespace parser
{
	struct Token;
}

/*
    AST* wrapper
    - Not constantly have to append the '*' as this is written often..
    - Allows for implicit conversion to any of the ASTs (raw or filtered).
*/
struct Code
{
#pragma region Statics
	// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
	static Code Global;

	// Used to identify invalid generated code.
	static Code Invalid;
#pragma endregion Statics

#define Using_Code( Typename )            \
	char const* debug_str();              \
	Code        duplicate();              \
	bool        is_equal( Code other );   \
	bool        is_valid();               \
	void        set_global();             \
	String      to_string();              \
	Typename&   operator=( AST* other );  \
	Typename&   operator=( Code other );  \
	bool        operator==( Code other ); \
	bool        operator!=( Code other ); \
	operator bool();

	Using_Code( Code );

	template<class Type>
	FORCEINLINE Type cast()
	{
		return *rcast( Type*, this );
	}

	AST* operator->()
	{
		return ast;
	}

	Code& operator++();

	// TODO(Ed) : Remove this overload.
	auto& operator*()
	{
		local_persist thread_local Code NullRef = { nullptr };

		if ( ast == nullptr )
			return NullRef;

		return *this;
	}

	AST* ast;

#ifdef GEN_ENFORCE_STRONG_CODE_TYPES
#define operator explicit operator
#endif
	operator CodeBody() const;
	operator CodeAttributes() const;
	// operator CodeBaseClass() const;
	operator CodeComment() const;
	operator CodeClass() const;
	operator CodeConstructor() const;
	operator CodeDefine() const;
	operator CodeDestructor() const;
	operator CodeExec() const;
	operator CodeEnum() const;
	operator CodeExtern() const;
	operator CodeInclude() const;
	operator CodeFriend() const;
	operator CodeFn() const;
	operator CodeModule() const;
	operator CodeNS() const;
	operator CodeOperator() const;
	operator CodeOpCast() const;
	operator CodeParam() const;
	operator CodePragma() const;
	operator CodePreprocessCond() const;
	operator CodeSpecifiers() const;
	operator CodeStruct() const;
	operator CodeTemplate() const;
	operator CodeType() const;
	operator CodeTypedef() const;
	operator CodeUnion() const;
	operator CodeUsing() const;
	operator CodeVar() const;
#undef operator
};

struct Code_POD
{
	AST* ast;
};

static_assert( sizeof( Code ) == sizeof( Code_POD ), "ERROR: Code is not POD" );

// Desired width of the AST data structure.
constexpr int const AST_POD_Size = 128;

/*
    Simple AST POD with functionality to seralize into C++ syntax.
*/
struct AST
{
#pragma region Member Functions
	void        append( AST* other );
	char const* debug_str();
	AST*        duplicate();
	Code&       entry( u32 idx );
	bool        has_entries();
	bool        is_equal( AST* other );
	char const* type_str();
	bool        validate_body();

	String to_string();

	neverinline void to_string( String& result );

	template<class Type>
	FORCEINLINE Type cast()
	{
		return *this;
	}

	operator Code();
	operator CodeBody();
	operator CodeAttributes();
	// operator CodeBaseClass();
	operator CodeComment();
	operator CodeConstructor();
	operator CodeDestructor();
	operator CodeClass();
	operator CodeDefine();
	operator CodeEnum();
	operator CodeExec();
	operator CodeExtern();
	operator CodeInclude();
	operator CodeFriend();
	operator CodeFn();
	operator CodeModule();
	operator CodeNS();
	operator CodeOperator();
	operator CodeOpCast();
	operator CodeParam();
	operator CodePragma();
	operator CodePreprocessCond();
	operator CodeSpecifiers();
	operator CodeStruct();
	operator CodeTemplate();
	operator CodeType();
	operator CodeTypedef();
	operator CodeUnion();
	operator CodeUsing();
	operator CodeVar();
#pragma endregion Member Functions

	constexpr static int ArrSpecs_Cap = ( AST_POD_Size - sizeof( AST* ) * 3 - sizeof( parser::Token* ) - sizeof( AST* ) - sizeof( StringCached )
	                                      - sizeof( CodeT ) - sizeof( ModuleFlag ) - sizeof( int ) )
	        / sizeof( int )
	    - 1;    // -1 for 4 extra bytes

	union
	{
		struct
		{
			AST* InlineCmt;     // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
			AST* Attributes;    // Class, Enum, Function, Struct, Typedef, Union, Using, Variable
			AST* Specs;         // Destructor, Function, Operator, Typename, Variable

			union
			{
				AST* InitializerList;    // Constructor
				AST* ParentType;         // Class, Struct, ParentType->Next has a possible list of interfaces.
				AST* ReturnType;         // Function, Operator, Typename
				AST* UnderlyingType;     // Enum, Typedef
				AST* ValueType;          // Parameter, Variable
			};

			union
			{
				AST* Macro;           // Parameter
				AST* BitfieldSize;    // Variable (Class/Struct Data Member)
				AST* Params;          // Constructor, Function, Operator, Template, Typename
			};

			union
			{
				AST* ArrExpr;        // Typename
				AST* Body;           // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union
				AST* Declaration;    // Friend, Template
				AST* Value;          // Parameter, Variable
			};

			union
			{
				AST* NextVar;    // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr =
				                 // NextVar->Value )
				AST* SuffixSpecs;    // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
			};
		};

		StringCached Content;    // Attributes, Comment, Execution, Include

		struct
		{
			SpecifierT ArrSpecs[ArrSpecs_Cap];    // Specifiers
			AST*       NextSpecs;                 // Specifiers; If ArrSpecs is full, then NextSpecs is used.
		};
	};

	union
	{
		AST* Prev;
		AST* Front;
		AST* Last;
	};

	union
	{
		AST* Next;
		AST* Back;
	};

	parser::Token* Token;    // Reference to starting token, only avaialble if it was derived from parsing.
	AST*           Parent;
	StringCached   Name;
	CodeT          Type;
	//	CodeFlag          CodeFlags;
	ModuleFlag ModuleFlags;

	union
	{
		b32        IsFunction;     // Used by typedef to not serialize the name field.
		b32        IsParamPack;    // Used by typename to know if type should be considered a parameter pack.
		OperatorT  Op;
		AccessSpec ParentAccess;
		s32        NumEntries;
	};
};

struct AST_POD
{
	union
	{
		struct
		{
			AST* InlineCmt;     // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
			AST* Attributes;    // Class, Enum, Function, Struct, Typedef, Union, Using, Variable
			AST* Specs;         // Destructor, Function, Operator, Typename, Variable

			union
			{
				AST* InitializerList;    // Constructor
				AST* ParentType;         // Class, Struct, ParentType->Next has a possible list of interfaces.
				AST* ReturnType;         // Function, Operator, Typename
				AST* UnderlyingType;     // Enum, Typedef
				AST* ValueType;          // Parameter, Variable
			};

			union
			{
				AST* Macro;           // Parameter
				AST* BitfieldSize;    // Variable (Class/Struct Data Member)
				AST* Params;          // Constructor, Function, Operator, Template, Typename
			};

			union
			{
				AST* ArrExpr;        // Typename
				AST* Body;           // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union
				AST* Declaration;    // Friend, Template
				AST* Value;          // Parameter, Variable
			};

			union
			{
				AST* NextVar;    // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr =
				                 // NextVar->Value )
				AST* SuffixSpecs;    // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
			};
		};

		StringCached Content;    // Attributes, Comment, Execution, Include

		struct
		{
			SpecifierT ArrSpecs[AST::ArrSpecs_Cap];    // Specifiers
			AST*       NextSpecs;                      // Specifiers; If ArrSpecs is full, then NextSpecs is used.
		};
	};

	union
	{
		AST* Prev;
		AST* Front;
		AST* Last;
	};

	union
	{
		AST* Next;
		AST* Back;
	};

	parser::Token* Token;    // Reference to starting token, only avaialble if it was derived from parsing.
	AST*           Parent;
	StringCached   Name;
	CodeT          Type;
	CodeFlag       CodeFlags;
	ModuleFlag     ModuleFlags;

	union
	{
		b32        IsFunction;     // Used by typedef to not serialize the name field.
		b32        IsParamPack;    // Used by typename to know if type should be considered a parameter pack.
		OperatorT  Op;
		AccessSpec ParentAccess;
		s32        NumEntries;
	};
};

struct test
{
	SpecifierT ArrSpecs[AST::ArrSpecs_Cap];    // Specifiers
	AST*       NextSpecs;                      // Specifiers; If ArrSpecs is full, then NextSpecs is used.
};

constexpr int pls = sizeof( test );

// Its intended for the AST to have equivalent size to its POD.
// All extra functionality within the AST namespace should just be syntatic sugar.
static_assert( sizeof( AST ) == sizeof( AST_POD ), "ERROR: AST IS NOT POD" );
static_assert( sizeof( AST_POD ) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" );

// Used when the its desired when omission is allowed in a definition.
#define NoCode  \
	{           \
		nullptr \
	}
#define CodeInvalid ( *Code::Invalid.ast )    // Uses an implicitly overloaded cast from the AST to the desired code type.

#pragma region Code Types

struct CodeBody
{
	Using_Code( CodeBody );

	void append( Code other )
	{
		raw()->append( other.ast );
	}

	void append( CodeBody body )
	{
		for ( Code entry : body )
		{
			append( entry );
		}
	}

	bool has_entries()
	{
		return rcast( AST*, ast )->has_entries();
	}

	void to_string( String& result );
	void to_string_export( String& result );

	AST* raw()
	{
		return rcast( AST*, ast );
	}

	AST_Body* operator->()
	{
		return ast;
	}

	operator Code()
	{
		return *rcast( Code*, this );
	}

#pragma region Iterator

	Code begin()
	{
		if ( ast )
			return { rcast( AST*, ast )->Front };

		return { nullptr };
	}

	Code end()
	{
		return { rcast( AST*, ast )->Back->Next };
	}

#pragma endregion Iterator

	AST_Body* ast;
};

struct CodeClass
{
	Using_Code( CodeClass );

	void add_interface( CodeType interface );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw()
	{
		return rcast( AST*, ast );
	}

	operator Code()
	{
		return *rcast( Code*, this );
	}

	AST_Class* operator->()
	{
		if ( ast == nullptr )
		{
			log_failure( "Attempt to dereference a nullptr" );
			return nullptr;
		}
		return ast;
	}

	AST_Class* ast;
};

struct CodeParam
{
	Using_Code( CodeParam );

	void append( CodeParam other );

	CodeParam get( s32 idx );
	bool      has_entries();
	void      to_string( String& result );

	AST* raw()
	{
		return rcast( AST*, ast );
	}

	AST_Param* operator->()
	{
		if ( ast == nullptr )
		{
			log_failure( "Attempt to dereference a nullptr!" );
			return nullptr;
		}
		return ast;
	}

	operator Code()
	{
		return { (AST*)ast };
	}

#pragma region Iterator

	CodeParam begin()
	{
		if ( ast )
			return { ast };

		return { nullptr };
	}

	CodeParam end()
	{
		// return { (AST_Param*) rcast( AST*, ast)->Last };
		return { nullptr };
	}

	CodeParam& operator++();

	CodeParam operator*()
	{
		return *this;
	}

#pragma endregion Iterator

	AST_Param* ast;
};

struct CodeSpecifiers
{
	Using_Code( CodeSpecifiers );

	bool append( SpecifierT spec )
	{
		if ( ast == nullptr )
		{
			log_failure( "CodeSpecifiers: Attempted to append to a null specifiers AST!" );
			return false;
		}

		if ( raw()->NumEntries == AST::ArrSpecs_Cap )
		{
			log_failure( "CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap );
			return false;
		}

		raw()->ArrSpecs[raw()->NumEntries] = spec;
		raw()->NumEntries++;
		return true;
	}

	s32 has( SpecifierT spec )
	{
		for ( s32 idx = 0; idx < raw()->NumEntries; idx++ )
		{
			if ( raw()->ArrSpecs[idx] == spec )
				return idx;
		}

		return -1;
	}

	void to_string( String& result );

	AST* raw()
	{
		return rcast( AST*, ast );
	}

	AST_Specifiers* operator->()
	{
		if ( ast == nullptr )
		{
			log_failure( "Attempt to dereference a nullptr!" );
			return nullptr;
		}
		return ast;
	}

	operator Code()
	{
		return { (AST*)ast };
	}

#pragma region Iterator

	SpecifierT* begin()
	{
		if ( ast )
			return &raw()->ArrSpecs[0];

		return nullptr;
	}

	SpecifierT* end()
	{
		return raw()->ArrSpecs + raw()->NumEntries;
	}

#pragma endregion Iterator

	AST_Specifiers* ast;
};

struct CodeStruct
{
	Using_Code( CodeStruct );

	void add_interface( CodeType interface );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw()
	{
		return rcast( AST*, ast );
	}

	operator Code()
	{
		return *rcast( Code*, this );
	}

	AST_Struct* operator->()
	{
		if ( ast == nullptr )
		{
			log_failure( "Attempt to dereference a nullptr" );
			return nullptr;
		}
		return ast;
	}

	AST_Struct* ast;
};

#define Define_CodeType( Typename )   \
	struct Code##Typename             \
	{                                 \
		Using_Code( Code##Typename ); \
		AST* raw();                   \
		operator Code();              \
		AST_##Typename* operator->(); \
		AST_##Typename* ast;          \
	}

Define_CodeType( Attributes );
// Define_CodeType( BaseClass );
Define_CodeType( Comment );

struct CodeConstructor
{
	Using_Code( CodeConstructor );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw();
	operator Code();
	AST_Constructor* operator->();
	AST_Constructor* ast;
};

struct CodeDefine
{
	Using_Code( CodeDefine );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Define* operator->();
	AST_Define* ast;
};

struct CodeDestructor
{
	Using_Code( CodeDestructor );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw();
	operator Code();
	AST_Destructor* operator->();
	AST_Destructor* ast;
};

struct CodeEnum
{
	Using_Code( CodeEnum );

	void to_string_def( String& result );
	void to_string_fwd( String& result );
	void to_string_class_def( String& result );
	void to_string_class_fwd( String& result );

	AST* raw();
	operator Code();
	AST_Enum* operator->();
	AST_Enum* ast;
};

Define_CodeType( Exec );

#if GEN_EXECUTION_EXPRESSION_SUPPORT
struct CodeExpr
{
	Using_Code( CodeExpr );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr* operator->();
	AST_Expr* ast;
};

struct CodeExpr_Assign
{
	Using_Code( CodeExpr_Assign );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Assign* operator->();
	AST_Expr_Assign* ast;
};

struct CodeExpr_Alignof
{
	Using_Code( CodeExpr_Alignof );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Alignof* operator->();
	AST_Expr_Alignof* ast;
};

struct CodeExpr_Binary
{
	Using_Code( CodeExpr_Binary );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Binary* operator->();
	AST_Expr_Binary* ast;
};

struct CodeExpr_CStyleCast
{
	Using_Code( CodeExpr_CStyleCast );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_CStyleCast* operator->();
	AST_Expr_CStyleCast* ast;
};

struct CodeExpr_FunctionalCast
{
	Using_Code( CodeExpr_FunctionalCast );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_FunctionalCast* operator->();
	AST_Expr_FunctionalCast* ast;
};

struct CodeExpr_CppCast
{
	Using_Code( CodeExpr_CppCast );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_CppCast* operator->();
	AST_Expr_CppCast* ast;
};

struct CodeExpr_Element
{
	Using_Code( CodeExpr_Element );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Element* operator->();
	AST_Expr_Element* ast;
};

struct CodeExpr_ProcCall
{
	Using_Code( CodeExpr_ProcCall );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_ProcCall* operator->();
	AST_Expr_ProcCall* ast;
};

struct CodeExpr_Decltype
{
	Using_Code( CodeExpr_Decltype );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Decltype* operator->();
	AST_Expr_Decltype* ast;
};

struct CodeExpr_Comma
{
	Using_Code( CodeExpr_Comma );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Comma* operator->();
	AST_Expr_Comma* ast;
};

struct CodeExpr_AMS
{
	Using_Code( CodeExpr_AMS );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_AMS* operator->();
	AST_Expr_AMS* ast;
};

struct CodeExpr_Sizeof
{
	Using_Code( CodeExpr_Sizeof );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Sizeof* operator->();
	AST_Expr_Sizeof* ast;
};

struct CodeExpr_Subscript
{
	Using_Code( CodeExpr_Subscript );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Subscript* operator->();
	AST_Expr_Subscript* ast;
};

struct CodeExpr_Ternary
{
	Using_Code( CodeExpr_Ternary );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_Ternary* operator->();
	AST_Expr_Ternary* ast;
};

struct CodeExpr_UnaryPrefix
{
	Using_Code( CodeExpr_UnaryPrefix );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_UnaryPrefix* operator->();
	AST_Expr_UnaryPrefix* ast;
};

struct CodeExpr_UnaryPostfix
{
	Using_Code( CodeExpr_UnaryPostfix );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Expr_UnaryPostfix* operator->();
	AST_Expr_UnaryPostfix* ast;
};
#endif

struct CodeExtern
{
	Using_Code( CodeExtern );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Extern* operator->();
	AST_Extern* ast;
};

struct CodeInclude
{
	Using_Code( CodeInclude );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Include* operator->();
	AST_Include* ast;
};

struct CodeFriend
{
	Using_Code( CodeFriend );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Friend* operator->();
	AST_Friend* ast;
};

struct CodeFn
{
	Using_Code( CodeFn );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw();
	operator Code();
	AST_Fn* operator->();
	AST_Fn* ast;
};

struct CodeModule
{
	Using_Code( CodeModule );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Module* operator->();
	AST_Module* ast;
};

struct CodeNS
{
	Using_Code( CodeNS );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_NS* operator->();
	AST_NS* ast;
};

struct CodeOperator
{
	Using_Code( CodeOperator );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw();
	operator Code();
	AST_Operator* operator->();
	AST_Operator* ast;
};

struct CodeOpCast
{
	Using_Code( CodeOpCast );

	void to_string_def( String& result );
	void to_string_fwd( String& result );

	AST* raw();
	operator Code();
	AST_OpCast* operator->();
	AST_OpCast* ast;
};

struct CodePragma
{
	Using_Code( CodePragma );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Pragma* operator->();
	AST_Pragma* ast;
};

struct CodePreprocessCond
{
	Using_Code( CodePreprocessCond );

	void to_string_if( String& result );
	void to_string_ifdef( String& result );
	void to_string_ifndef( String& result );
	void to_string_elif( String& result );
	void to_string_else( String& result );
	void to_string_endif( String& result );

	AST* raw();
	operator Code();
	AST_PreprocessCond* operator->();
	AST_PreprocessCond* ast;
};

#if GEN_EXECUTION_EXPRESSION_SUPPORT
struct CodeStmt
{
	Using_Code( CodeStmt );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt* operator->();
	AST_Stmt* ast;
};

struct CodeStmt_Break
{
	Using_Code( CodeStmt_Break );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Break* operator->();
	AST_Stmt_Break* ast;
};

struct CodeStmt_Case
{
	Using_Code( CodeStmt_Case );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Case* operator->();
	AST_Stmt_Case* ast;
};

struct CodeStmt_Continue
{
	Using_Code( CodeStmt_Continue );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Continue* operator->();
	AST_Stmt_Continue* ast;
};

struct CodeStmt_Decl
{
	Using_Code( CodeStmt_Decl );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Decl* operator->();
	AST_Stmt_Decl* ast;
};

struct CodeStmt_Do
{
	Using_Code( CodeStmt_Do );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Do* operator->();
	AST_Stmt_Do* ast;
};

struct CodeStmt_Expr
{
	Using_Code( CodeStmt_Expr );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Expr* operator->();
	AST_Stmt_Expr* ast;
};

struct CodeStmt_Else
{
	Using_Code( CodeStmt_Else );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Else* operator->();
	AST_Stmt_Else* ast;
};

struct CodeStmt_If
{
	Using_Code( CodeStmt_If );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_If* operator->();
	AST_Stmt_If* ast;
};

struct CodeStmt_For
{
	Using_Code( CodeStmt_For );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_For* operator->();
	AST_Stmt_For* ast;
};

struct CodeStmt_Goto
{
	Using_Code( CodeStmt_Goto );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Goto* operator->();
	AST_Stmt_Goto* ast;
};

struct CodeStmt_Label
{
	Using_Code( CodeStmt_Label );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Label* operator->();
	AST_Stmt_Label* ast;
};

struct CodeStmt_Switch
{
	Using_Code( CodeStmt_Switch );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_Switch* operator->();
	AST_Stmt_Switch* ast;
};

struct CodeStmt_While
{
	Using_Code( CodeStmt_While );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Stmt_While* operator->();
	AST_Stmt_While* ast;
};
#endif

struct CodeTemplate
{
	Using_Code( CodeTemplate );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Template* operator->();
	AST_Template* ast;
};

struct CodeType
{
	Using_Code( CodeType );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Type* operator->();
	AST_Type* ast;
};

struct CodeTypedef
{
	Using_Code( CodeTypedef );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Typedef* operator->();
	AST_Typedef* ast;
};

struct CodeUnion
{
	Using_Code( CodeUnion );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Union* operator->();
	AST_Union* ast;
};

struct CodeUsing
{
	Using_Code( CodeUsing );

	void to_string( String& result );
	void to_string_ns( String& result );

	AST* raw();
	operator Code();
	AST_Using* operator->();
	AST_Using* ast;
};

struct CodeVar
{
	Using_Code( CodeVar );

	void to_string( String& result );

	AST* raw();
	operator Code();
	AST_Var* operator->();
	AST_Var* ast;
};

#undef Define_CodeType
#undef Using_Code

#pragma endregion Code Types

#pragma region AST Types

/*
    Show only relevant members of the AST for its type.
    AST* fields are replaced with Code types.
        - Guards assignemnts to AST* fields to ensure the AST is duplicated if assigned to another parent.
*/

struct AST_Body
{
	char           _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	Code           Front;
	Code           Back;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag )];
	s32            NumEntries;
};

static_assert( sizeof( AST_Body ) == sizeof( AST ), "ERROR: AST_Body is not the same size as AST" );

struct AST_Attributes
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Attributes ) == sizeof( AST ), "ERROR: AST_Attributes is not the same size as AST" );

#if 0
struct AST_BaseClass
{
	union {
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
	};
	Code              Prev;
	Code              Next;
	parser::Token*    Tok;
	Code              Parent;
	StringCached      Name;
	CodeT             Type;
	char              _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_BaseClass) == sizeof(AST), "ERROR: AST_BaseClass is not the same size as AST");
#endif

struct AST_Comment
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Comment ) == sizeof( AST ), "ERROR: AST_Comment is not the same size as AST" );

struct AST_Class
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;    // Only supported by forward declarations
			CodeAttributes Attributes;
			char           _PAD_SPECS_[sizeof( AST* )];
			CodeType       ParentType;
			char           _PAD_PARAMS_[sizeof( AST* )];
			CodeBody       Body;
			char           _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	CodeType       Prev;
	CodeType       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	AccessSpec     ParentAccess;
};

static_assert( sizeof( AST_Class ) == sizeof( AST ), "ERROR: AST_Class is not the same size as AST" );

struct AST_Constructor
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;    // Only supported by forward declarations
			char           _PAD_PROPERTIES_[sizeof( AST* ) * 1];
			CodeSpecifiers Specs;
			Code           InitializerList;
			CodeParam      Params;
			Code           Body;
			char           _PAD_PROPERTIES_2_[sizeof( AST* ) * 2];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Constructor ) == sizeof( AST ), "ERROR: AST_Constructor is not the same size as AST" );

struct AST_Define
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Define ) == sizeof( AST ), "ERROR: AST_Define is not the same size as AST" );

struct AST_Destructor
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			char           _PAD_PROPERTIES_[sizeof( AST* ) * 1];
			CodeSpecifiers Specs;
			char           _PAD_PROPERTIES_2_[sizeof( AST* ) * 2];
			Code           Body;
			char           _PAD_PROPERTIES_3_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Destructor ) == sizeof( AST ), "ERROR: AST_Destructor is not the same size as AST" );

struct AST_Enum
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			CodeAttributes Attributes;
			char           _PAD_SPEC_[sizeof( AST* )];
			CodeType       UnderlyingType;
			char           _PAD_PARAMS_[sizeof( AST* )];
			CodeBody       Body;
			char           _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Enum ) == sizeof( AST ), "ERROR: AST_Enum is not the same size as AST" );

struct AST_Exec
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Exec ) == sizeof( AST ), "ERROR: AST_Exec is not the same size as AST" );

#if GEN_EXECUTION_EXPRESSION_SUPPORT
struct AST_Expr
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr ) == sizeof( AST ), "ERROR: AST_Expr is not the same size as AST" );

struct AST_Expr_Assign
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Assign ) == sizeof( AST ), "ERROR: AST_Expr_Assign is not the same size as AST" );

struct AST_Expr_Alignof
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Alignof ) == sizeof( AST ), "ERROR: AST_Expr_Alignof is not the same size as AST" );

struct AST_Expr_Binary
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Binary ) == sizeof( AST ), "ERROR: AST_Expr_Binary is not the same size as AST" );

struct AST_Expr_CStyleCast
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_CStyleCast ) == sizeof( AST ), "ERROR: AST_Expr_CStyleCast is not the same size as AST" );

struct AST_Expr_FunctionalCast
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_FunctionalCast ) == sizeof( AST ), "ERROR: AST_Expr_FunctionalCast is not the same size as AST" );

struct AST_Expr_CppCast
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_CppCast ) == sizeof( AST ), "ERROR: AST_Expr_CppCast is not the same size as AST" );

struct AST_Expr_ProcCall
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_ProcCall ) == sizeof( AST ), "ERROR: AST_Expr_Identifier is not the same size as AST" );

struct AST_Expr_Decltype
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Decltype ) == sizeof( AST ), "ERROR: AST_Expr_Decltype is not the same size as AST" );

struct AST_Expr_Comma
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Comma ) == sizeof( AST ), "ERROR: AST_Expr_Comma is not the same size as AST" );

struct AST_Expr_AMS
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_AMS ) == sizeof( AST ), "ERROR: AST_Expr_AMS is not the same size as AST" );

struct AST_Expr_Sizeof
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Sizeof ) == sizeof( AST ), "ERROR: AST_Expr_Sizeof is not the same size as AST" );

struct AST_Expr_Subscript
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Subscript ) == sizeof( AST ), "ERROR: AST_Expr_Subscript is not the same size as AST" );

struct AST_Expr_Ternary
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Ternary ) == sizeof( AST ), "ERROR: AST_Expr_Ternary is not the same size as AST" );

struct AST_Expr_UnaryPrefix
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_UnaryPrefix ) == sizeof( AST ), "ERROR: AST_Expr_UnaryPrefix is not the same size as AST" );

struct AST_Expr_UnaryPostfix
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_UnaryPostfix ) == sizeof( AST ), "ERROR: AST_Expr_UnaryPostfix is not the same size as AST" );

struct AST_Expr_Element
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Expr_Element ) == sizeof( AST ), "ERROR: AST_Expr_Element is not the same size as AST" );
#endif

struct AST_Extern
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			char     _PAD_PROPERTIES_[sizeof( AST* ) * 5];
			CodeBody Body;
			char     _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Extern ) == sizeof( AST ), "ERROR: AST_Extern is not the same size as AST" );

struct AST_Include
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Include ) == sizeof( AST ), "ERROR: AST_Include is not the same size as AST" );

struct AST_Friend
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment InlineCmt;
			char        _PAD_PROPERTIES_[sizeof( AST* ) * 4];
			Code        Declaration;
			char        _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Friend ) == sizeof( AST ), "ERROR: AST_Friend is not the same size as AST" );

struct AST_Fn
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			CodeAttributes Attributes;
			CodeSpecifiers Specs;
			CodeType       ReturnType;
			CodeParam      Params;
			CodeBody       Body;
			char           _PAD_PROPERTIES_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Fn ) == sizeof( AST ), "ERROR: AST_Fn is not the same size as AST" );

struct AST_Module
{
	char           _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Module ) == sizeof( AST ), "ERROR: AST_Module is not the same size as AST" );

struct AST_NS
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			char     _PAD_PROPERTIES_[sizeof( AST* ) * 5];
			CodeBody Body;
			char     _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_NS ) == sizeof( AST ), "ERROR: AST_NS is not the same size as AST" );

struct AST_Operator
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			CodeAttributes Attributes;
			CodeSpecifiers Specs;
			CodeType       ReturnType;
			CodeParam      Params;
			CodeBody       Body;
			char           _PAD_PROPERTIES_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	OperatorT      Op;
};

static_assert( sizeof( AST_Operator ) == sizeof( AST ), "ERROR: AST_Operator is not the same size as AST" );

struct AST_OpCast
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			char           _PAD_PROPERTIES_[sizeof( AST* )];
			CodeSpecifiers Specs;
			CodeType       ValueType;
			char           _PAD_PROPERTIES_2_[sizeof( AST* )];
			CodeBody       Body;
			char           _PAD_PROPERTIES_3_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_OpCast ) == sizeof( AST ), "ERROR: AST_OpCast is not the same size as AST" );

struct AST_Param
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			char     _PAD_PROPERTIES_2_[sizeof( AST* ) * 3];
			CodeType ValueType;
			Code     Macro;
			Code     Value;
			char     _PAD_PROPERTIES_3_[sizeof( AST* )];
		};
	};

	CodeParam      Last;
	CodeParam      Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag )];
	s32            NumEntries;
};

static_assert( sizeof( AST_Param ) == sizeof( AST ), "ERROR: AST_Param is not the same size as AST" );

struct AST_Pragma
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Pragma ) == sizeof( AST ), "ERROR: AST_Pragma is not the same size as AST" );

struct AST_PreprocessCond
{
	union
	{
		char         _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
		StringCached Content;
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_PreprocessCond ) == sizeof( AST ), "ERROR: AST_PreprocessCond is not the same size as AST" );

struct AST_Specifiers
{
	SpecifierT     ArrSpecs[AST::ArrSpecs_Cap];
	CodeSpecifiers NextSpecs;
	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag )];
	s32            NumEntries;
};

static_assert( sizeof( AST_Specifiers ) == sizeof( AST ), "ERROR: AST_Specifier is not the same size as AST" );

#if GEN_EXECUTION_EXPRESSION_SUPPORT
struct AST_Stmt
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt ) == sizeof( AST ), "ERROR: AST_Stmt is not the same size as AST" );

struct AST_Stmt_Break
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Break ) == sizeof( AST ), "ERROR: AST_Stmt_Break is not the same size as AST" );

struct AST_Stmt_Case
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Case ) == sizeof( AST ), "ERROR: AST_Stmt_Case is not the same size as AST" );

struct AST_Stmt_Continue
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Continue ) == sizeof( AST ), "ERROR: AST_Stmt_Continue is not the same size as AST" );

struct AST_Stmt_Decl
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Decl ) == sizeof( AST ), "ERROR: AST_Stmt_Decl is not the same size as AST" );

struct AST_Stmt_Do
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Do ) == sizeof( AST ), "ERROR: AST_Stmt_Do is not the same size as AST" );

struct AST_Stmt_Expr
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Expr ) == sizeof( AST ), "ERROR: AST_Stmt_Expr is not the same size as AST" );

struct AST_Stmt_Else
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Else ) == sizeof( AST ), "ERROR: AST_Stmt_Else is not the same size as AST" );

struct AST_Stmt_If
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_If ) == sizeof( AST ), "ERROR: AST_Stmt_If is not the same size as AST" );

struct AST_Stmt_For
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_For ) == sizeof( AST ), "ERROR: AST_Stmt_For is not the same size as AST" );

struct AST_Stmt_Goto
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Goto ) == sizeof( AST ), "ERROR: AST_Stmt_Goto is not the same size as AST" );

struct AST_Stmt_Label
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Label ) == sizeof( AST ), "ERROR: AST_Stmt_Label is not the same size as AST" );

struct AST_Stmt_Switch
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_Switch ) == sizeof( AST ), "ERROR: AST_Stmt_Switch is not the same size as AST" );

struct AST_Stmt_While
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];
	} CodeExpr Prev;

	CodeExpr       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag ) + sizeof( u32 )];
};

static_assert( sizeof( AST_Stmt_While ) == sizeof( AST ), "ERROR: AST_Stmt_While is not the same size as AST" );
#endif

struct AST_Struct
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			CodeAttributes Attributes;
			char           _PAD_SPECS_[sizeof( AST* )];
			CodeType       ParentType;
			char           _PAD_PARAMS_[sizeof( AST* )];
			CodeBody       Body;
			char           _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	CodeType       Prev;
	CodeType       Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	AccessSpec     ParentAccess;
};

static_assert( sizeof( AST_Struct ) == sizeof( AST ), "ERROR: AST_Struct is not the same size as AST" );

struct AST_Template
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			char      _PAD_PROPERTIES_[sizeof( AST* ) * 4];
			CodeParam Params;
			Code      Declaration;
			char      _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Template ) == sizeof( AST ), "ERROR: AST_Template is not the same size as AST" );

#if 0
// WIP... The type ast is going to become more advanced and lead to a major change to AST design.
struct AST_Type
{
	union {
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
		struct
		{
			char           _PAD_INLINE_CMT_[ sizeof(AST*) ];
			CodeAttributes Attributes;
			CodeSpecifiers Specs;
			Code           QualifierID;
			// CodeType       ReturnType;      // Only used for function signatures
			// CodeParam      Params;          // Only used for function signatures
			Code           ArrExpr;
			// CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures
		};
	};
	Code                   Prev;
	Code                   Next;
	parser::Token*         Tok;
	Code                   Parent;
	StringCached           Name;
	CodeT                  Type;
	char 			       _PAD_UNUSED_[ sizeof(ModuleFlag) ];
	b32                    IsParamPack;
};
static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST");
#endif

struct AST_Type
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			char           _PAD_INLINE_CMT_[sizeof( AST* )];
			CodeAttributes Attributes;
			CodeSpecifiers Specs;
			CodeType       ReturnType;    // Only used for function signatures
			CodeParam      Params;        // Only used for function signatures
			Code           ArrExpr;
			CodeSpecifiers SpecsFuncSuffix;    // Only used for function signatures
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	char           _PAD_UNUSED_[sizeof( ModuleFlag )];
	b32            IsParamPack;
};

static_assert( sizeof( AST_Type ) == sizeof( AST ), "ERROR: AST_Type is not the same size as AST" );

struct AST_Typedef
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment InlineCmt;
			char        _PAD_PROPERTIES_[sizeof( AST* ) * 2];
			Code        UnderlyingType;
			char        _PAD_PROPERTIES_2_[sizeof( AST* ) * 3];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	b32            IsFunction;
};

static_assert( sizeof( AST_Typedef ) == sizeof( AST ), "ERROR: AST_Typedef is not the same size as AST" );

struct AST_Union
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			char           _PAD_INLINE_CMT_[sizeof( AST* )];
			CodeAttributes Attributes;
			char           _PAD_PROPERTIES_[sizeof( AST* ) * 3];
			CodeBody       Body;
			char           _PAD_PROPERTIES_2_[sizeof( AST* )];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Union ) == sizeof( AST ), "ERROR: AST_Union is not the same size as AST" );

struct AST_Using
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			CodeAttributes Attributes;
			char           _PAD_SPECS_[sizeof( AST* )];
			CodeType       UnderlyingType;
			char           _PAD_PROPERTIES_[sizeof( AST* ) * 3];
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Using ) == sizeof( AST ), "ERROR: AST_Using is not the same size as AST" );

struct AST_Var
{
	union
	{
		char _PAD_[sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* )];

		struct
		{
			CodeComment    InlineCmt;
			CodeAttributes Attributes;
			CodeSpecifiers Specs;
			CodeType       ValueType;
			Code           BitfieldSize;
			Code           Value;
			CodeVar        NextVar;
		};
	};

	Code           Prev;
	Code           Next;
	parser::Token* Tok;
	Code           Parent;
	StringCached   Name;
	CodeT          Type;
	ModuleFlag     ModuleFlags;
	char           _PAD_UNUSED_[sizeof( u32 )];
};

static_assert( sizeof( AST_Var ) == sizeof( AST ), "ERROR: AST_Var is not the same size as AST" );

#pragma endregion AST Types

#pragma endregion AST

#pragma region Gen Interface

// Initialize the library.
// This currently just initializes the CodePool.
void init();

// Currently manually free's the arenas, code for checking for leaks.
// However on Windows at least, it doesn't need to occur as the OS will clean up after the process.
void deinit();

// Clears the allocations, but doesn't return to the heap, the calls init() again.
// Ease of use.
void reset();

// Used internally to retrive or make string allocations.
// Strings are stored in a series of string arenas of fixed size (SizePer_StringArena)
StringCached get_cached_string( StrC str );

/*
    This provides a fresh Code AST.
    The gen interface use this as their method from getting a new AST object from the CodePool.
    Use this if you want to make your own API for formatting the supported Code Types.
*/
Code make_code();

// Set these before calling gen's init() procedure.

void set_allocator_data_arrays( AllocatorInfo data_array_allocator );
void set_allocator_code_pool( AllocatorInfo pool_allocator );
void set_allocator_lexer( AllocatorInfo lex_allocator );
void set_allocator_string_arena( AllocatorInfo string_allocator );
void set_allocator_string_table( AllocatorInfo string_allocator );
void set_allocator_type_table( AllocatorInfo type_reg_allocator );

#pragma region Upfront

CodeAttributes def_attributes( StrC content );
CodeComment    def_comment( StrC content );

CodeClass def_class(
    StrC           name,
    Code           body           = NoCode,
    CodeType       parent         = NoCode,
    AccessSpec     access         = AccessSpec::Default,
    CodeAttributes attributes     = NoCode,
    ModuleFlag     mflags         = ModuleFlag::None,
    CodeType*      interfaces     = nullptr,
    s32            num_interfaces = 0
);

CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode );

CodeDefine def_define( StrC name, StrC content );

CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = NoCode );

CodeEnum def_enum(
    StrC           name,
    Code           body       = NoCode,
    CodeType       type       = NoCode,
    EnumT          specifier  = EnumRegular,
    CodeAttributes attributes = NoCode,
    ModuleFlag     mflags     = ModuleFlag::None
);

CodeExec   def_execution( StrC content );
CodeExtern def_extern_link( StrC name, Code body );
CodeFriend def_friend( Code symbol );

CodeFn def_function(
    StrC           name,
    CodeParam      params     = NoCode,
    CodeType       ret_type   = NoCode,
    Code           body       = NoCode,
    CodeSpecifiers specifiers = NoCode,
    CodeAttributes attributes = NoCode,
    ModuleFlag     mflags     = ModuleFlag::None
);

CodeInclude def_include( StrC content, bool foreign = false );
CodeModule  def_module( StrC name, ModuleFlag mflags = ModuleFlag::None );
CodeNS      def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag::None );

CodeOperator def_operator(
    OperatorT      op,
    StrC           nspace,
    CodeParam      params     = NoCode,
    CodeType       ret_type   = NoCode,
    Code           body       = NoCode,
    CodeSpecifiers specifiers = NoCode,
    CodeAttributes attributes = NoCode,
    ModuleFlag     mflags     = ModuleFlag::None
);

CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode );

CodeParam  def_param( CodeType type, StrC name, Code value = NoCode );
CodePragma def_pragma( StrC directive );

CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC content );

CodeSpecifiers def_specifier( SpecifierT specifier );

CodeStruct def_struct(
    StrC           name,
    Code           body           = NoCode,
    CodeType       parent         = NoCode,
    AccessSpec     access         = AccessSpec::Default,
    CodeAttributes attributes     = NoCode,
    ModuleFlag     mflags         = ModuleFlag::None,
    CodeType*      interfaces     = nullptr,
    s32            num_interfaces = 0
);

CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None );

CodeType    def_type( StrC name, Code arrayexpr = NoCode, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode );
CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None );

CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None );

CodeUsing def_using( StrC name, CodeType type = NoCode, CodeAttributes attributess = NoCode, ModuleFlag mflags = ModuleFlag::None );

CodeUsing def_using_namespace( StrC name );

CodeVar def_variable(
    CodeType       type,
    StrC           name,
    Code           value      = NoCode,
    CodeSpecifiers specifiers = NoCode,
    CodeAttributes attributes = NoCode,
    ModuleFlag     mflags     = ModuleFlag::None
);

// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries.
CodeBody def_body( CodeT 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.

CodeBody       def_class_body( s32 num, ... );
CodeBody       def_class_body( s32 num, Code* codes );
CodeBody       def_enum_body( s32 num, ... );
CodeBody       def_enum_body( s32 num, Code* codes );
CodeBody       def_export_body( s32 num, ... );
CodeBody       def_export_body( s32 num, Code* codes );
CodeBody       def_extern_link_body( s32 num, ... );
CodeBody       def_extern_link_body( s32 num, Code* codes );
CodeBody       def_function_body( s32 num, ... );
CodeBody       def_function_body( s32 num, Code* codes );
CodeBody       def_global_body( s32 num, ... );
CodeBody       def_global_body( s32 num, Code* codes );
CodeBody       def_namespace_body( s32 num, ... );
CodeBody       def_namespace_body( s32 num, Code* codes );
CodeParam      def_params( s32 num, ... );
CodeParam      def_params( s32 num, CodeParam* params );
CodeSpecifiers def_specifiers( s32 num, ... );
CodeSpecifiers def_specifiers( s32 num, SpecifierT* specs );
CodeBody       def_struct_body( s32 num, ... );
CodeBody       def_struct_body( s32 num, Code* codes );
CodeBody       def_union_body( s32 num, ... );
CodeBody       def_union_body( s32 num, Code* codes );

#pragma endregion Upfront

#pragma region Parsing

// TODO(Ed) : Implmeent the new parser API design.

#if 0
namespace parser {
	struct StackNode
	{
		StackNode* Prev;

		Token Start;
		Token Name;       // The name of the AST node (if parsed)
		StrC  FailedProc; // The name of the procedure that failed
	};
	// Stack nodes are allocated the error's allocator

	struct Error
	{
		String     message;
		StackNode* context_stack;
	};
}

struct ParseInfo

	Arena FileMem;
	Arena TokMem;
	Arena CodeMem;

	FileContents         FileContent;
	Array<parser::Token> Tokens;
	Array<parser::Error> Errors;
	// Errors are allocated to a dedicated general arena.
;

CodeBody parse_file( StrC path );
#endif

CodeClass       parse_class( StrC class_def );
CodeConstructor parse_constructor( StrC constructor_def );
CodeDestructor  parse_destructor( StrC destructor_def );
CodeEnum        parse_enum( StrC enum_def );
CodeBody        parse_export_body( StrC export_def );
CodeExtern      parse_extern_link( StrC exten_link_def );
CodeFriend      parse_friend( StrC friend_def );
CodeFn          parse_function( StrC fn_def );
CodeBody        parse_global_body( StrC body_def );
CodeNS          parse_namespace( StrC namespace_def );
CodeOperator    parse_operator( StrC operator_def );
CodeOpCast      parse_operator_cast( StrC operator_def );
CodeStruct      parse_struct( StrC struct_def );
CodeTemplate    parse_template( StrC template_def );
CodeType        parse_type( StrC type_def );
CodeTypedef     parse_typedef( StrC typedef_def );
CodeUnion       parse_union( StrC union_def );
CodeUsing       parse_using( StrC using_def );
CodeVar         parse_variable( StrC var_def );

#pragma endregion Parsing

#pragma region Untyped text

sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va );
//! Do not use directly. Use the token_fmt macro instead.
StrC token_fmt_impl( sw, ... );

Code untyped_str( StrC content );
Code untyped_fmt( char const* fmt, ... );
Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... );

#pragma endregion Untyped text

#pragma endregion Gen Interface

#pragma region Inlines

void AST::append( AST* other )
{
	if ( other->Parent )
		other = other->duplicate();

	other->Parent = this;

	if ( Front == nullptr )
	{
		Front = other;
		Back  = other;

		NumEntries++;
		return;
	}

	AST* Current  = Back;
	Current->Next = other;
	other->Prev   = Current;
	Back          = other;
	NumEntries++;
}

Code& AST::entry( u32 idx )
{
	AST** current = &Front;
	while ( idx >= 0 && current != nullptr )
	{
		if ( idx == 0 )
			return *rcast( Code*, current );

		current = &( *current )->Next;
		idx--;
	}

	return *rcast( Code*, current );
}

bool AST::has_entries()
{
	return NumEntries;
}

char const* AST::type_str()
{
	return ECode::to_str( Type );
}

AST::operator Code()
{
	return { this };
}

Code& Code::operator++()
{
	if ( ast )
		ast = ast->Next;

	return *this;
}

void CodeClass::add_interface( CodeType type )
{
	CodeType possible_slot = ast->ParentType;
	if ( possible_slot.ast )
	{
		// Were adding an interface to parent type, so we need to make sure the parent type is public.
		ast->ParentAccess = AccessSpec::Public;
		// If your planning on adding a proper parent,
		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly.
	}

	while ( possible_slot.ast != nullptr )
	{
		possible_slot.ast = (AST_Type*)possible_slot->Next.ast;
	}

	possible_slot.ast = type.ast;
}

void CodeParam::append( CodeParam other )
{
	AST* self  = (AST*)ast;
	AST* entry = (AST*)other.ast;

	if ( entry->Parent )
		entry = entry->duplicate();

	entry->Parent = self;

	if ( self->Last == nullptr )
	{
		self->Last = entry;
		self->Next = entry;
		self->NumEntries++;
		return;
	}

	self->Last->Next = entry;
	self->Last       = entry;
	self->NumEntries++;
}

CodeParam CodeParam::get( s32 idx )
{
	CodeParam param = *this;
	do
	{
		if ( ! ++param )
			return { nullptr };

		return { (AST_Param*)param.raw()->Next };
	} while ( --idx );

	return { nullptr };
}

bool CodeParam::has_entries()
{
	return ast->NumEntries > 0;
}

CodeParam& CodeParam::operator++()
{
	ast = ast->Next.ast;
	return *this;
}

void CodeStruct::add_interface( CodeType type )
{
	CodeType possible_slot = ast->ParentType;
	if ( possible_slot.ast )
	{
		// Were adding an interface to parent type, so we need to make sure the parent type is public.
		ast->ParentAccess = AccessSpec::Public;
		// If your planning on adding a proper parent,
		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly.
	}

	while ( possible_slot.ast != nullptr )
	{
		possible_slot.ast = (AST_Type*)possible_slot->Next.ast;
	}

	possible_slot.ast = type.ast;
}

CodeBody def_body( CodeT type )
{
	switch ( type )
	{
		using namespace ECode;
		case Class_Body :
		case Enum_Body :
		case Export_Body :
		case Extern_Linkage :
		case Function_Body :
		case Global_Body :
		case Namespace_Body :
		case Struct_Body :
		case Union_Body :
			break;

		default :
			log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str( type ) );
			return (CodeBody)Code::Invalid;
	}

	Code result  = make_code();
	result->Type = type;
	return (CodeBody)result;
}

StrC token_fmt_impl( sw num, ... )
{
	local_persist thread_local char buf[GEN_PRINTF_MAXLEN] = { 0 };
	mem_set( buf, 0, GEN_PRINTF_MAXLEN );

	va_list va;
	va_start( va, num );
	sw result = token_fmt_va( buf, GEN_PRINTF_MAXLEN, num, va );
	va_end( va );

	return { result, buf };
}

#pragma region generated code inline implementation

char const* Code::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code Code::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool Code::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool Code::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void Code::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

Code& Code::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool Code::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool Code::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

Code::operator bool()
{
	return ast != nullptr;
}

char const* CodeBody::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeBody::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeBody::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeBody::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeBody::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeBody& CodeBody::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeBody::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeBody::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeBody::operator bool()
{
	return ast != nullptr;
}

char const* CodeAttributes::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeAttributes::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeAttributes::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeAttributes::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeAttributes::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeAttributes& CodeAttributes::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeAttributes::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeAttributes::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeAttributes::operator bool()
{
	return ast != nullptr;
}

AST* CodeAttributes::raw()
{
	return rcast( AST*, ast );
}

CodeAttributes::operator Code()
{
	return *rcast( Code*, this );
}

AST_Attributes* CodeAttributes::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeComment::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeComment::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeComment::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeComment::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeComment::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeComment& CodeComment::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeComment::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeComment::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeComment::operator bool()
{
	return ast != nullptr;
}

AST* CodeComment::raw()
{
	return rcast( AST*, ast );
}

CodeComment::operator Code()
{
	return *rcast( Code*, this );
}

AST_Comment* CodeComment::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeConstructor::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeConstructor::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeConstructor::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeConstructor::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeConstructor::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeConstructor& CodeConstructor::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeConstructor::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeConstructor::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeConstructor::operator bool()
{
	return ast != nullptr;
}

AST* CodeConstructor::raw()
{
	return rcast( AST*, ast );
}

CodeConstructor::operator Code()
{
	return *rcast( Code*, this );
}

AST_Constructor* CodeConstructor::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeClass::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeClass::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeClass::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeClass::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeClass::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeClass& CodeClass::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeClass::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeClass::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeClass::operator bool()
{
	return ast != nullptr;
}

char const* CodeDefine::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeDefine::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeDefine::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeDefine::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeDefine::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeDefine& CodeDefine::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeDefine::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeDefine::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeDefine::operator bool()
{
	return ast != nullptr;
}

AST* CodeDefine::raw()
{
	return rcast( AST*, ast );
}

CodeDefine::operator Code()
{
	return *rcast( Code*, this );
}

AST_Define* CodeDefine::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeDestructor::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeDestructor::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeDestructor::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeDestructor::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeDestructor::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeDestructor& CodeDestructor::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeDestructor::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeDestructor::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeDestructor::operator bool()
{
	return ast != nullptr;
}

AST* CodeDestructor::raw()
{
	return rcast( AST*, ast );
}

CodeDestructor::operator Code()
{
	return *rcast( Code*, this );
}

AST_Destructor* CodeDestructor::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeEnum::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeEnum::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeEnum::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeEnum::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeEnum::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeEnum& CodeEnum::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeEnum::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeEnum::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeEnum::operator bool()
{
	return ast != nullptr;
}

AST* CodeEnum::raw()
{
	return rcast( AST*, ast );
}

CodeEnum::operator Code()
{
	return *rcast( Code*, this );
}

AST_Enum* CodeEnum::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeExec::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeExec::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeExec::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeExec::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeExec::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeExec& CodeExec::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeExec::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeExec::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeExec::operator bool()
{
	return ast != nullptr;
}

AST* CodeExec::raw()
{
	return rcast( AST*, ast );
}

CodeExec::operator Code()
{
	return *rcast( Code*, this );
}

AST_Exec* CodeExec::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeExtern::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeExtern::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeExtern::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeExtern::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeExtern::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeExtern& CodeExtern::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeExtern::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeExtern::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeExtern::operator bool()
{
	return ast != nullptr;
}

AST* CodeExtern::raw()
{
	return rcast( AST*, ast );
}

CodeExtern::operator Code()
{
	return *rcast( Code*, this );
}

AST_Extern* CodeExtern::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeFriend::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeFriend::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeFriend::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeFriend::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeFriend::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeFriend& CodeFriend::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeFriend::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeFriend::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeFriend::operator bool()
{
	return ast != nullptr;
}

AST* CodeFriend::raw()
{
	return rcast( AST*, ast );
}

CodeFriend::operator Code()
{
	return *rcast( Code*, this );
}

AST_Friend* CodeFriend::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeFn::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeFn::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeFn::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeFn::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeFn::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeFn& CodeFn::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeFn::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeFn::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeFn::operator bool()
{
	return ast != nullptr;
}

AST* CodeFn::raw()
{
	return rcast( AST*, ast );
}

CodeFn::operator Code()
{
	return *rcast( Code*, this );
}

AST_Fn* CodeFn::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeInclude::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeInclude::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeInclude::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeInclude::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeInclude::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeInclude& CodeInclude::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeInclude::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeInclude::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeInclude::operator bool()
{
	return ast != nullptr;
}

AST* CodeInclude::raw()
{
	return rcast( AST*, ast );
}

CodeInclude::operator Code()
{
	return *rcast( Code*, this );
}

AST_Include* CodeInclude::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeModule::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeModule::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeModule::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeModule::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeModule::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeModule& CodeModule::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeModule::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeModule::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeModule::operator bool()
{
	return ast != nullptr;
}

AST* CodeModule::raw()
{
	return rcast( AST*, ast );
}

CodeModule::operator Code()
{
	return *rcast( Code*, this );
}

AST_Module* CodeModule::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeNS::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeNS::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeNS::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeNS::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeNS::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeNS& CodeNS::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeNS::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeNS::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeNS::operator bool()
{
	return ast != nullptr;
}

AST* CodeNS::raw()
{
	return rcast( AST*, ast );
}

CodeNS::operator Code()
{
	return *rcast( Code*, this );
}

AST_NS* CodeNS::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeOperator::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeOperator::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeOperator::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeOperator::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeOperator::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeOperator& CodeOperator::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeOperator::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeOperator::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeOperator::operator bool()
{
	return ast != nullptr;
}

AST* CodeOperator::raw()
{
	return rcast( AST*, ast );
}

CodeOperator::operator Code()
{
	return *rcast( Code*, this );
}

AST_Operator* CodeOperator::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeOpCast::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeOpCast::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeOpCast::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeOpCast::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeOpCast::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeOpCast& CodeOpCast::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeOpCast::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeOpCast::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeOpCast::operator bool()
{
	return ast != nullptr;
}

AST* CodeOpCast::raw()
{
	return rcast( AST*, ast );
}

CodeOpCast::operator Code()
{
	return *rcast( Code*, this );
}

AST_OpCast* CodeOpCast::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeParam::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeParam::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeParam::is_equal( Code other )
{
	if ( ast == nullptr && other.ast == nullptr)
		return true;

	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeParam::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeParam::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeParam& CodeParam::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeParam::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeParam::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeParam::operator bool()
{
	return ast != nullptr;
}

char const* CodePragma::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodePragma::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodePragma::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodePragma::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodePragma::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodePragma& CodePragma::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodePragma::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodePragma::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodePragma::operator bool()
{
	return ast != nullptr;
}

AST* CodePragma::raw()
{
	return rcast( AST*, ast );
}

CodePragma::operator Code()
{
	return *rcast( Code*, this );
}

AST_Pragma* CodePragma::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodePreprocessCond::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodePreprocessCond::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodePreprocessCond::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodePreprocessCond::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodePreprocessCond::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodePreprocessCond& CodePreprocessCond::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodePreprocessCond::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodePreprocessCond::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodePreprocessCond::operator bool()
{
	return ast != nullptr;
}

AST* CodePreprocessCond::raw()
{
	return rcast( AST*, ast );
}

CodePreprocessCond::operator Code()
{
	return *rcast( Code*, this );
}

AST_PreprocessCond* CodePreprocessCond::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeSpecifiers::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeSpecifiers::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeSpecifiers::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeSpecifiers::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeSpecifiers::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeSpecifiers& CodeSpecifiers::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeSpecifiers::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeSpecifiers::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeSpecifiers::operator bool()
{
	return ast != nullptr;
}

char const* CodeStruct::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeStruct::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeStruct::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeStruct::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeStruct::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeStruct& CodeStruct::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeStruct::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeStruct::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeStruct::operator bool()
{
	return ast != nullptr;
}

char const* CodeTemplate::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeTemplate::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeTemplate::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeTemplate::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeTemplate::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeTemplate& CodeTemplate::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeTemplate::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeTemplate::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeTemplate::operator bool()
{
	return ast != nullptr;
}

AST* CodeTemplate::raw()
{
	return rcast( AST*, ast );
}

CodeTemplate::operator Code()
{
	return *rcast( Code*, this );
}

AST_Template* CodeTemplate::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeType::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeType::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeType::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeType::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeType::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeType& CodeType::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeType::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeType::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeType::operator bool()
{
	return ast != nullptr;
}

AST* CodeType::raw()
{
	return rcast( AST*, ast );
}

CodeType::operator Code()
{
	return *rcast( Code*, this );
}

AST_Type* CodeType::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeTypedef::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeTypedef::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeTypedef::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeTypedef::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeTypedef::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeTypedef& CodeTypedef::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeTypedef::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeTypedef::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeTypedef::operator bool()
{
	return ast != nullptr;
}

AST* CodeTypedef::raw()
{
	return rcast( AST*, ast );
}

CodeTypedef::operator Code()
{
	return *rcast( Code*, this );
}

AST_Typedef* CodeTypedef::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeUnion::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeUnion::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeUnion::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeUnion::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeUnion::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeUnion& CodeUnion::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeUnion::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeUnion::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeUnion::operator bool()
{
	return ast != nullptr;
}

AST* CodeUnion::raw()
{
	return rcast( AST*, ast );
}

CodeUnion::operator Code()
{
	return *rcast( Code*, this );
}

AST_Union* CodeUnion::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeUsing::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeUsing::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeUsing::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeUsing::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeUsing::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeUsing& CodeUsing::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeUsing::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeUsing::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeUsing::operator bool()
{
	return ast != nullptr;
}

AST* CodeUsing::raw()
{
	return rcast( AST*, ast );
}

CodeUsing::operator Code()
{
	return *rcast( Code*, this );
}

AST_Using* CodeUsing::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

char const* CodeVar::debug_str()
{
	if ( ast == nullptr )
		return "Code::debug_str: AST is null!";
	return rcast( AST*, ast )->debug_str();
}

Code CodeVar::duplicate()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" );
		return Code::Invalid;
	}
	return { rcast( AST*, ast )->duplicate() };
}

bool CodeVar::is_equal( Code other )
{
	if ( ast == nullptr || other.ast == nullptr )
	{
		log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
		return false;
	}
	return rcast( AST*, ast )->is_equal( other.ast );
}

bool CodeVar::is_valid()
{
	return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid;
}

void CodeVar::set_global()
{
	if ( ast == nullptr )
	{
		log_failure( "Code::set_global: Cannot set code as global, AST is null!" );
		return;
	}
	rcast( AST*, ast )->Parent = Code::Global.ast;
}

CodeVar& CodeVar::operator=( Code other )
{
	if ( other.ast && other->Parent )
	{
		ast                        = rcast( decltype( ast ), other.ast->duplicate() );
		rcast( AST*, ast )->Parent = nullptr;
	}
	ast = rcast( decltype( ast ), other.ast );
	return *this;
}

bool CodeVar::operator==( Code other )
{
	return (AST*)ast == other.ast;
}

bool CodeVar::operator!=( Code other )
{
	return (AST*)ast != other.ast;
}

CodeVar::operator bool()
{
	return ast != nullptr;
}

AST* CodeVar::raw()
{
	return rcast( AST*, ast );
}

CodeVar::operator Code()
{
	return *rcast( Code*, this );
}

AST_Var* CodeVar::operator->()
{
	if ( ast == nullptr )
	{
		log_failure( "Attempt to dereference a nullptr!" );
		return nullptr;
	}
	return ast;
}

#pragma endregion generated code inline implementation

#pragma region generated AST/Code cast implementation

AST::operator CodeBody()
{
	return { rcast( AST_Body*, this ) };
}

Code::operator CodeBody() const
{
	return { (AST_Body*)ast };
}

AST::operator CodeAttributes()
{
	return { rcast( AST_Attributes*, this ) };
}

Code::operator CodeAttributes() const
{
	return { (AST_Attributes*)ast };
}

AST::operator CodeComment()
{
	return { rcast( AST_Comment*, this ) };
}

Code::operator CodeComment() const
{
	return { (AST_Comment*)ast };
}

AST::operator CodeConstructor()
{
	return { rcast( AST_Constructor*, this ) };
}

Code::operator CodeConstructor() const
{
	return { (AST_Constructor*)ast };
}

AST::operator CodeClass()
{
	return { rcast( AST_Class*, this ) };
}

Code::operator CodeClass() const
{
	return { (AST_Class*)ast };
}

AST::operator CodeDefine()
{
	return { rcast( AST_Define*, this ) };
}

Code::operator CodeDefine() const
{
	return { (AST_Define*)ast };
}

AST::operator CodeDestructor()
{
	return { rcast( AST_Destructor*, this ) };
}

Code::operator CodeDestructor() const
{
	return { (AST_Destructor*)ast };
}

AST::operator CodeEnum()
{
	return { rcast( AST_Enum*, this ) };
}

Code::operator CodeEnum() const
{
	return { (AST_Enum*)ast };
}

AST::operator CodeExec()
{
	return { rcast( AST_Exec*, this ) };
}

Code::operator CodeExec() const
{
	return { (AST_Exec*)ast };
}

AST::operator CodeExtern()
{
	return { rcast( AST_Extern*, this ) };
}

Code::operator CodeExtern() const
{
	return { (AST_Extern*)ast };
}

AST::operator CodeFriend()
{
	return { rcast( AST_Friend*, this ) };
}

Code::operator CodeFriend() const
{
	return { (AST_Friend*)ast };
}

AST::operator CodeFn()
{
	return { rcast( AST_Fn*, this ) };
}

Code::operator CodeFn() const
{
	return { (AST_Fn*)ast };
}

AST::operator CodeInclude()
{
	return { rcast( AST_Include*, this ) };
}

Code::operator CodeInclude() const
{
	return { (AST_Include*)ast };
}

AST::operator CodeModule()
{
	return { rcast( AST_Module*, this ) };
}

Code::operator CodeModule() const
{
	return { (AST_Module*)ast };
}

AST::operator CodeNS()
{
	return { rcast( AST_NS*, this ) };
}

Code::operator CodeNS() const
{
	return { (AST_NS*)ast };
}

AST::operator CodeOperator()
{
	return { rcast( AST_Operator*, this ) };
}

Code::operator CodeOperator() const
{
	return { (AST_Operator*)ast };
}

AST::operator CodeOpCast()
{
	return { rcast( AST_OpCast*, this ) };
}

Code::operator CodeOpCast() const
{
	return { (AST_OpCast*)ast };
}

AST::operator CodeParam()
{
	return { rcast( AST_Param*, this ) };
}

Code::operator CodeParam() const
{
	return { (AST_Param*)ast };
}

AST::operator CodePragma()
{
	return { rcast( AST_Pragma*, this ) };
}

Code::operator CodePragma() const
{
	return { (AST_Pragma*)ast };
}

AST::operator CodePreprocessCond()
{
	return { rcast( AST_PreprocessCond*, this ) };
}

Code::operator CodePreprocessCond() const
{
	return { (AST_PreprocessCond*)ast };
}

AST::operator CodeSpecifiers()
{
	return { rcast( AST_Specifiers*, this ) };
}

Code::operator CodeSpecifiers() const
{
	return { (AST_Specifiers*)ast };
}

AST::operator CodeStruct()
{
	return { rcast( AST_Struct*, this ) };
}

Code::operator CodeStruct() const
{
	return { (AST_Struct*)ast };
}

AST::operator CodeTemplate()
{
	return { rcast( AST_Template*, this ) };
}

Code::operator CodeTemplate() const
{
	return { (AST_Template*)ast };
}

AST::operator CodeType()
{
	return { rcast( AST_Type*, this ) };
}

Code::operator CodeType() const
{
	return { (AST_Type*)ast };
}

AST::operator CodeTypedef()
{
	return { rcast( AST_Typedef*, this ) };
}

Code::operator CodeTypedef() const
{
	return { (AST_Typedef*)ast };
}

AST::operator CodeUnion()
{
	return { rcast( AST_Union*, this ) };
}

Code::operator CodeUnion() const
{
	return { (AST_Union*)ast };
}

AST::operator CodeUsing()
{
	return { rcast( AST_Using*, this ) };
}

Code::operator CodeUsing() const
{
	return { (AST_Using*)ast };
}

AST::operator CodeVar()
{
	return { rcast( AST_Var*, this ) };
}

Code::operator CodeVar() const
{
	return { (AST_Var*)ast };
}

#pragma endregion generated AST / Code cast implementation

#pragma endregion Inlines

#pragma region Constants

#ifndef GEN_GLOBAL_BUCKET_SIZE
#define GEN_GLOBAL_BUCKET_SIZE megabytes( 8 )
#endif
#ifndef GEN_CODEPOOL_NUM_BLOCKS
#define GEN_CODEPOOL_NUM_BLOCKS kilobytes( 16 )
#endif
#ifndef GEN_SIZE_PER_STRING_ARENA
#define GEN_SIZE_PER_STRING_ARENA megabytes( 1 )
#endif
#ifndef GEN_MAX_COMMENT_LINE_LENGTH
#define GEN_MAX_COMMENT_LINE_LENGTH 1024
#endif
#ifndef GEN_MAX_NAME_LENGTH
#define GEN_MAX_NAME_LENGTH 128
#endif
#ifndef GEN_MAX_UNTYPED_STR_LENGTH
#define GEN_MAX_UNTYPED_STR_LENGTH megabytes( 1 )
#endif
#ifndef GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE
#define GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE kilobytes( 4 )
#endif
#ifndef GEN_LEX_ALLOCATOR_SIZE
#define GEN_LEX_ALLOCATOR_SIZE megabytes( 4 )
#endif
#ifndef GEN_BUILDER_STR_BUFFER_RESERVE
#define GEN_BUILDER_STR_BUFFER_RESERVE megabytes( 2 )
#endif

// These constexprs are used for allocation behavior of data structures
// or string handling while constructing or serializing.
// Change them to suit your needs.

constexpr s32 InitSize_DataArrays = 16;

// NOTE: This limits the maximum size of an allocation
// If you are generating a string larger than this, increase the size of the bucket here.
constexpr uw  Global_BucketSize         = GEN_GLOBAL_BUCKET_SIZE;
constexpr s32 CodePool_NumBlocks        = GEN_CODEPOOL_NUM_BLOCKS;
constexpr s32 SizePer_StringArena       = GEN_SIZE_PER_STRING_ARENA;

constexpr s32 MaxCommentLineLength      = GEN_MAX_COMMENT_LINE_LENGTH;
constexpr s32 MaxNameLength             = GEN_MAX_NAME_LENGTH;
constexpr s32 MaxUntypedStrLength       = GEN_MAX_UNTYPED_STR_LENGTH;
constexpr s32 TokenFmt_TokenMap_MemSize = GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE;
constexpr s32 LexAllocator_Size         = GEN_LEX_ALLOCATOR_SIZE;
constexpr s32 Builder_StrBufferReserve  = GEN_BUILDER_STR_BUFFER_RESERVE;

extern Code access_public;
extern Code access_protected;
extern Code access_private;

extern CodeAttributes attrib_api_export;
extern CodeAttributes attrib_api_import;

extern Code module_global_fragment;
extern Code module_private_fragment;

extern Code fmt_newline;

extern CodePragma pragma_once;

extern CodeParam param_varadic;

extern CodePreprocessCond preprocess_else;
extern CodePreprocessCond preprocess_endif;

extern CodeSpecifiers spec_const;
extern CodeSpecifiers spec_consteval;
extern CodeSpecifiers spec_constexpr;
extern CodeSpecifiers spec_constinit;
extern CodeSpecifiers spec_extern_linkage;
extern CodeSpecifiers spec_final;
extern CodeSpecifiers spec_FORCEINLINE;
extern CodeSpecifiers spec_global;
extern CodeSpecifiers spec_inline;
extern CodeSpecifiers spec_internal_linkage;
extern CodeSpecifiers spec_local_persist;
extern CodeSpecifiers spec_mutable;
extern CodeSpecifiers spec_neverinline;
extern CodeSpecifiers spec_noexcept;
extern CodeSpecifiers spec_override;
extern CodeSpecifiers spec_ptr;
extern CodeSpecifiers spec_pure;
extern CodeSpecifiers spec_ref;
extern CodeSpecifiers spec_register;
extern CodeSpecifiers spec_rvalue;
extern CodeSpecifiers spec_static_member;
extern CodeSpecifiers spec_thread_local;
extern CodeSpecifiers spec_virtual;
extern CodeSpecifiers spec_volatile;

extern CodeType t_empty;    // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
extern CodeType t_auto;
extern CodeType t_void;
extern CodeType t_int;
extern CodeType t_bool;
extern CodeType t_char;
extern CodeType t_wchar_t;
extern CodeType t_class;
extern CodeType t_typename;

#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
// Predefined typename codes. Are set to readonly and are setup during gen::init()

extern CodeType t_b32;

extern CodeType t_s8;
extern CodeType t_s16;
extern CodeType t_s32;
extern CodeType t_s64;

extern CodeType t_u8;
extern CodeType t_u16;
extern CodeType t_u32;
extern CodeType t_u64;

extern CodeType t_sw;
extern CodeType t_uw;

extern CodeType t_f32;
extern CodeType t_f64;
#endif

#pragma endregion Constants

#pragma region Macros

#define gen_main main

#define __       NoCode

//	Convienence for defining any name used with the gen api.
//  Lets you provide the length and string literal to the functions without the need for the DSL.
#define name( Id_ )                                      \
	{                                                    \
		sizeof( stringize( Id_ ) ) - 1, stringize( Id_ ) \
	}

//  Same as name just used to indicate intention of literal for code instead of names.
#define code( ... )                                                      \
	{                                                                    \
		sizeof( stringize( __VA_ARGS__ ) ) - 1, stringize( __VA_ARGS__ ) \
	}

#define args( ... )     num_args( __VA_ARGS__ ), __VA_ARGS__

#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) )
#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) )

// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string.
#define token_fmt( ... ) GEN_NS token_fmt_impl( ( num_args( __VA_ARGS__ ) + 1 ) / 2, __VA_ARGS__ )

#pragma endregion Macros

// Used by the lexer to persistently treat all these identifiers as preprocessor defines.
// Populate with strings via gen::get_cached_string.
// Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments.
extern Array<StringCached> PreprocessorDefines;

#ifdef GEN_EXPOSE_BACKEND

// Global allocator used for data with process lifetime.
extern AllocatorInfo GlobalAllocator;
extern Array<Arena>  Global_AllocatorBuckets;

extern Array<Pool>  CodePools;
extern Array<Arena> StringArenas;

extern StringTable StringCache;

extern Arena LexArena;

extern AllocatorInfo Allocator_DataArrays;
extern AllocatorInfo Allocator_CodePool;
extern AllocatorInfo Allocator_Lexer;
extern AllocatorInfo Allocator_StringArena;
extern AllocatorInfo Allocator_StringTable;
extern AllocatorInfo Allocator_TypeTable;

#endif
GEN_NS_END

#if __clang__
#pragma clang diagnostic pop
#endif

#if __GNUC__
#pragma GCC diagnostic pop
#endif
