Started to implement context stack for parser.

This commit is contained in:
Edward R. Gonzalez 2023-07-28 21:44:31 -04:00
parent 3f0b7e7fc6
commit 31e1c38c18
11 changed files with 350 additions and 260 deletions

View File

@ -5,11 +5,6 @@ An attempt at simple staged metaprogramming for c/c++.
The library API is a composition of code element constructors. The library API is a composition of code element constructors.
These build up a code AST to then serialize with a file builder. These build up a code AST to then serialize with a file builder.
General goal is to have a less than 15k sloc library that takes at most a couple of hours to learn and make use of.
*Why 15k ?* Assuming a seasoned coder of C++ can read and understand around 1000-2000 lines of code per hour, 15,000 could be understood in under 16-18 hours
and have confidence in modifying for their use case.
This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto), This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto),
its not meant to be a black box metaprogramming utility, its meant for the user to extend for their project domain. its not meant to be a black box metaprogramming utility, its meant for the user to extend for their project domain.
@ -30,17 +25,17 @@ The project has reached an *alpha* state, all the current functionality works fo
The project has no external dependencies beyond: The project has no external dependencies beyond:
* `errno.h` (gen.dep.cpp) * `errno.h`
* `stat.h` (gen.dep.cpp) * `stat.h`
* `stdarg.h` (gen.dep.hpp) * `stdarg.h`
* `stddef.h` (gen.dep.hpp * `stddef.h`
* `stdio.h` (gen.dep.cpp) * `stdio.h`
* `copyfile.h` (Mac, gen.dep.cpp) * `copyfile.h` (Mac)
* `types.h` (Linux, gen.dep.cpp) * `types.h` (Linux)
* `unistd.h` (Linux/Mac, gen.dep.cpp) * `unistd.h` (Linux/Mac)
* `intrin.h` (Windows, gen.dep.hpp) * `intrin.h` (Windows)
* `io.h` (Windows with gcc, gen.dep.cpp) * `io.h` (Windows with gcc)
* `windows.h` (Windows, gen.dep.cpp) * `windows.h` (Windows)
Dependencies for the project are wrapped within `GENCPP_ROLL_OWN_DEPENDENCIES` (Defining it will disable them). Dependencies for the project are wrapped within `GENCPP_ROLL_OWN_DEPENDENCIES` (Defining it will disable them).
The majority of the dependency's implementation was derived from the [c-zpl library](https://github.com/zpl-c/zpl). The majority of the dependency's implementation was derived from the [c-zpl library](https://github.com/zpl-c/zpl).
@ -561,6 +556,7 @@ The following are provided predefined by the library as they are commonly used:
* `access_private` * `access_private`
* `module_global_fragment` * `module_global_fragment`
* `module_private_fragment` * `module_private_fragment`
* `param_varaidc` (Used for varadic definitions)
* `pragma_once` * `pragma_once`
* `spec_const` * `spec_const`
* `spec_consteval` * `spec_consteval`
@ -586,7 +582,7 @@ The following are provided predefined by the library as they are commonly used:
* `spec_type_unsigned` * `spec_type_unsigned`
* `spec_type_short` * `spec_type_short`
* `spec_type_long` * `spec_type_long`
* `t_empty` * `t_empty` (Used for varaidc macros)
* `t_auto` * `t_auto`
* `t_void` * `t_void`
* `t_int` * `t_int`

View File

@ -37,8 +37,12 @@ Module_Import, "import"
Module_Export, "export" Module_Export, "export"
Number, "number" Number, "number"
Operator, "operator" Operator, "operator"
Preprocessor_Directive, "#" Preprocess_Define, "#define"
Preprocessor_Include, "include" Preprocess_Include, "#include"
Preprocess_If, "#if"
Preprocess_ElIF, "#elif"
Preprocess_Else, "#else"
Preprocess_EndIf, "#endif"
Spec_Alignas, "alignas" Spec_Alignas, "alignas"
Spec_Const, "const" Spec_Const, "const"
Spec_Consteval, "consteval" Spec_Consteval, "consteval"

1 Invalid __invalid__
37 Module_Export export
38 Number number
39 Operator operator
40 Preprocessor_Directive Preprocess_Define # #define
41 Preprocessor_Include Preprocess_Include include #include
42 Preprocess_If #if
43 Preprocess_ElIF #elif
44 Preprocess_Else #else
45 Preprocess_EndIf #endif
46 Spec_Alignas alignas
47 Spec_Const const
48 Spec_Consteval consteval

View File

@ -778,7 +778,7 @@ bool AST::validate_body()
switch ( Type ) switch ( Type )
{ {
case Class_Body: case Class_Body:
CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES );
break; break;
case Enum_Body: case Enum_Body:
for ( Code entry : cast<CodeBody>() ) for ( Code entry : cast<CodeBody>() )
@ -791,22 +791,22 @@ bool AST::validate_body()
} }
break; break;
case Export_Body: case Export_Body:
CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES );
break; break;
case Extern_Linkage: case Extern_Linkage:
CheckEntries( AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES );
break; break;
case Function_Body: case Function_Body:
CheckEntries( AST_BODY_FUNCTION_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES );
break; break;
case Global_Body: case Global_Body:
CheckEntries( AST_BODY_GLOBAL_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES );
break; break;
case Namespace_Body: case Namespace_Body:
CheckEntries( AST_BODY_NAMESPACE_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES );
break; break;
case Struct_Body: case Struct_Body:
CheckEntries( AST_BODY_STRUCT_UNALLOWED_TYPES ); CheckEntries( GEN_AST_BODY_STRUCT_UNALLOWED_TYPES );
break; break;
case Union_Body: case Union_Body:
for ( Code entry : Body->cast<CodeBody>() ) for ( Code entry : Body->cast<CodeBody>() )

View File

@ -1,4 +1,4 @@
# define AST_BODY_CLASS_UNALLOWED_TYPES \ # define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \
case PlatformAttributes: \ case PlatformAttributes: \
case Class_Body: \ case Class_Body: \
case Enum_Body: \ case Enum_Body: \
@ -14,8 +14,9 @@
case Specifiers: \ case Specifiers: \
case Struct_Body: \ case Struct_Body: \
case Typename: case Typename:
# define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES
# define AST_BODY_FUNCTION_UNALLOWED_TYPES \ # define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES \
case Access_Public: \ case Access_Public: \
case Access_Protected: \ case Access_Protected: \
case Access_Private: \ case Access_Private: \
@ -38,7 +39,7 @@
case Struct_Body: \ case Struct_Body: \
case Typename: case Typename:
# define AST_BODY_GLOBAL_UNALLOWED_TYPES \ # define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES \
case Access_Public: \ case Access_Public: \
case Access_Protected: \ case Access_Protected: \
case Access_Private: \ case Access_Private: \
@ -56,9 +57,10 @@
case Specifiers: \ case Specifiers: \
case Struct_Body: \ case Struct_Body: \
case Typename: case Typename:
# define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES
# define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES
# define AST_BODY_EXPORT_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES # define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES \
# define AST_BODY_NAMESPACE_UNALLOWED_TYPES \
case Access_Public: \ case Access_Public: \
case Access_Protected: \ case Access_Protected: \
case Access_Private: \ case Access_Private: \
@ -75,7 +77,3 @@
case Specifiers: \ case Specifiers: \
case Struct_Body: \ case Struct_Body: \
case Typename: case Typename:
# define AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES
# define AST_BODY_STRUCT_UNALLOWED_TYPES AST_BODY_CLASS_UNALLOWED_TYPES

View File

@ -1,4 +1,5 @@
#pragma region StaticData #pragma region StaticData
// TODO : Convert global allocation strategy to use a slab allocation strategy. // TODO : Convert global allocation strategy to use a slab allocation strategy.
global AllocatorInfo GlobalAllocator; global AllocatorInfo GlobalAllocator;
global Array<Arena> Global_AllocatorBuckets; global Array<Arena> Global_AllocatorBuckets;
@ -16,9 +17,11 @@ global AllocatorInfo Allocator_Lexer = heap();
global AllocatorInfo Allocator_StringArena = heap(); global AllocatorInfo Allocator_StringArena = heap();
global AllocatorInfo Allocator_StringTable = heap(); global AllocatorInfo Allocator_StringTable = heap();
global AllocatorInfo Allocator_TypeTable = heap(); global AllocatorInfo Allocator_TypeTable = heap();
#pragma endregion StaticData #pragma endregion StaticData
#pragma region Constants #pragma region Constants
global CodeType t_empty; global CodeType t_empty;
global CodeType t_auto; global CodeType t_auto;
global CodeType t_void; global CodeType t_void;
@ -83,4 +86,5 @@ global CodeSpecifiers spec_static_member;
global CodeSpecifiers spec_thread_local; global CodeSpecifiers spec_thread_local;
global CodeSpecifiers spec_virtual; global CodeSpecifiers spec_virtual;
global CodeSpecifiers spec_volatile; global CodeSpecifiers spec_volatile;
#pragma endregion Constants #pragma endregion Constants

View File

@ -9,6 +9,12 @@ namespace Parser
Attributes_Start is only used to indicate the start of the user_defined attribute list. Attributes_Start is only used to indicate the start of the user_defined attribute list.
*/ */
#ifndef GEN_Define_Attribute_Tokens
# define GEN_Define_Attribute_Tokens \
Entry( API_Export, "GEN_API_Export_Code" ) \
Entry( API_Import, "GEN_API_Import_Code" )
#endif
# define Define_TokType \ # define Define_TokType \
Entry( Invalid, "INVALID" ) \ Entry( Invalid, "INVALID" ) \
Entry( Access_Private, "private" ) \ Entry( Access_Private, "private" ) \
@ -49,8 +55,12 @@ namespace Parser
Entry( Module_Export, "export" ) \ Entry( Module_Export, "export" ) \
Entry( Number, "number" ) \ Entry( Number, "number" ) \
Entry( Operator, "operator" ) \ Entry( Operator, "operator" ) \
Entry( Preprocessor_Directive, "#") \ Entry( Preprocess_Define, "#define") \
Entry( Preprocessor_Include, "include" ) \ Entry( Preproces_Include, "include" ) \
Entry( Preprocess_If, "#if") \
Entry( Preprocess_Elif, "#elif") \
Entry( Preprocess_Else, "#else") \
Entry( Preprocess_EndIf, "#endif") \
Entry( Spec_Alignas, "alignas" ) \ Entry( Spec_Alignas, "alignas" ) \
Entry( Spec_Const, "const" ) \ Entry( Spec_Const, "const" ) \
Entry( Spec_Consteval, "consteval" ) \ Entry( Spec_Consteval, "consteval" ) \

View File

@ -84,6 +84,7 @@ Code& Code::operator ++()
} }
#pragma region AST & Code Gen Common #pragma region AST & Code Gen Common
#define Define_CodeImpl( Typename ) \ #define Define_CodeImpl( Typename ) \
char const* Typename::debug_str() \ char const* Typename::debug_str() \
{ \ { \
@ -243,6 +244,7 @@ Define_CodeCast( Using );
Define_CodeCast( Var ); Define_CodeCast( Var );
Define_CodeCast( Body); Define_CodeCast( Body);
#undef Define_CodeCast #undef Define_CodeCast
#pragma endregion AST & Code Gen Common #pragma endregion AST & Code Gen Common
void CodeClass::add_interface( CodeType type ) void CodeClass::add_interface( CodeType type )
@ -361,9 +363,11 @@ StrC token_fmt_impl( sw num, ... )
return { result, buf }; return { result, buf };
} }
#pragma endregion Inlines #pragma endregion Inlines
#pragma region Constants #pragma region Constants
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
// Predefined typename codes. Are set to readonly and are setup during gen::init() // Predefined typename codes. Are set to readonly and are setup during gen::init()
@ -477,9 +481,11 @@ extern CodeSpecifiers spec_static_member;
extern CodeSpecifiers spec_thread_local; extern CodeSpecifiers spec_thread_local;
extern CodeSpecifiers spec_virtual; extern CodeSpecifiers spec_virtual;
extern CodeSpecifiers spec_volatile; extern CodeSpecifiers spec_volatile;
#pragma endregion Constants #pragma endregion Constants
#pragma region Macros #pragma region Macros
# define gen_main main # define gen_main main
# define __ NoCode # define __ NoCode
@ -498,9 +504,11 @@ extern CodeSpecifiers spec_volatile;
// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. // Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string.
# define token_fmt( ... ) gen::token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) # define token_fmt( ... ) gen::token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ )
#pragma endregion Macros #pragma endregion Macros
#ifdef GEN_EXPOSE_BACKEND #ifdef GEN_EXPOSE_BACKEND
// Global allocator used for data with process lifetime. // Global allocator used for data with process lifetime.
extern AllocatorInfo GlobalAllocator; extern AllocatorInfo GlobalAllocator;
extern Array< Arena > Global_AllocatorBuckets; extern Array< Arena > Global_AllocatorBuckets;
@ -517,4 +525,5 @@ extern CodeSpecifiers spec_volatile;
extern AllocatorInfo Allocator_StringArena; extern AllocatorInfo Allocator_StringArena;
extern AllocatorInfo Allocator_StringTable; extern AllocatorInfo Allocator_StringTable;
extern AllocatorInfo Allocator_TypeTable; extern AllocatorInfo Allocator_TypeTable;
#endif #endif

View File

@ -4,13 +4,21 @@ These constructors are the most implementation intensive other than the editor o
namespace Parser namespace Parser
{ {
struct Token struct Token
{ {
// TokType Type;
// s32 Start;
// s32 End;
// s32 Line;
// s32 Column;
// TokFlags Flags;
char const* Text; char const* Text;
sptr Length; sptr Length;
TokType Type; TokType Type;
bool IsAssign; bool IsAssign;
s32 Line;
s32 Column;
operator bool() operator bool()
{ {
@ -21,60 +29,42 @@ namespace Parser
{ {
return { Length, Text }; return { Length, Text };
} }
};
internal inline bool is_access_specifier()
bool tok_is_specifier( Token const& tok )
{ {
return (tok.Type <= TokType::Star && tok.Type >= TokType::Spec_Alignas) return Type >= TokType::Access_Private && Type <= TokType::Access_Public;
|| tok.Type == TokType::Ampersand }
|| tok.Type == TokType::Ampersand_DBL
bool is_attribute()
{
return Type > TokType::Attributes_Start;
}
bool is_preprocessor()
{
return Type >= TokType::Preprocess_Define && Type <= TokType::Preprocess_EndIf;
}
bool is_specifier()
{
return (Type <= TokType::Star && Type >= TokType::Spec_Alignas)
|| Type == TokType::Ampersand
|| Type == TokType::Ampersand_DBL
; ;
} }
internal inline AccessSpec to_access_specifier()
bool tok_is_access_specifier( Token const& tok )
{ {
return tok.Type >= TokType::Access_Private && tok.Type <= TokType::Access_Public; return scast(AccessSpec, Type);
}
internal inline
AccessSpec tok_to_access_specifier( Token const& tok )
{
return scast(AccessSpec, tok.Type);
}
internal inline
bool tok_is_attribute( Token const& tok )
{
return tok.Type > TokType::Attributes_Start;
} }
};
struct TokArray struct TokArray
{ {
Array<Token> Arr; Array<Token> Arr;
s32 Idx; s32 Idx;
bool __eat( TokType type, char const* context ) bool __eat( TokType type );
{
if ( Arr.num() - Idx <= 0 )
{
log_failure( "gen::%s: No tokens left", context );
return false;
}
if ( Arr[Idx].Type != type )
{
String token_str = String::make( GlobalAllocator, { Arr[Idx].Length, Arr[Idx].Text } );
log_failure( "gen::%s: expected %s, got %s", context, ETokType::to_str(type), ETokType::to_str(Arr[Idx].Type) );
return false;
}
Idx++;
return true;
}
Token& current() Token& current()
{ {
@ -92,13 +82,87 @@ namespace Parser
} }
}; };
TokArray lex( StrC content, bool keep_preprocess_directives = false ) struct StackNode
{
StackNode* Prev;
Token Name; // The name of the AST node (if parsed)
StrC ProcName; // The name of the procedure
};
struct ParseContext
{
TokArray Tokens;
StackNode* Scope;
String to_string()
{
String result = String::make_reserve( GlobalAllocator, kilobytes(4) );
result.append_fmt("\tContext:\n");
StackNode* current = Scope;
do
{
String name = String::make( GlobalAllocator, current->Name ? (StrC)current->Name : txt_StrC("Unresolved") );
result.append_fmt("\tProcedure: %s, AST Name: %s\n\t(%d, %d):", current->ProcName, name );
current = current->Prev;
name.free();
}
while ( current );
return result;
}
};
global ParseContext Context;
bool TokArray::__eat( TokType type )
{
if ( Arr.num() - Idx <= 0 )
{
log_failure( "No tokens left\n", Context.Scope->ProcName );
return false;
}
if ( Arr[Idx].Type != type )
{
String token_str = String::make( GlobalAllocator, { Arr[Idx].Length, Arr[Idx].Text } );
log_failure( "gen::%s: expected %s, got %s", Context.Scope->ProcName, ETokType::to_str(type), ETokType::to_str(Arr[Idx].Type) );
return false;
}
Idx++;
return true;
}
enum TokFlags : u32
{
IsAssign = bit(0),
};
TokArray lex( StrC content, bool keep_preprocess_directives = true )
{ {
# define current ( * scanner ) # define current ( * scanner )
# define move_forward() \ # define move_forward() \
{ \
if ( current == '\n' ) \
{ \
line++; \
column = 0; \
} \
else \
{ \
column++; \
} \
left--; \ left--; \
scanner++ scanner++; \
}
# define SkipWhitespace() \ # define SkipWhitespace() \
while ( left && char_is_space( current ) ) \ while ( left && char_is_space( current ) ) \
@ -126,6 +190,9 @@ namespace Parser
char const* word = scanner; char const* word = scanner;
s32 word_length = 0; s32 word_length = 0;
s32 line = 0;
s32 column = 0;
SkipWhitespace(); SkipWhitespace();
if ( left <= 0 ) if ( left <= 0 )
{ {
@ -142,7 +209,7 @@ namespace Parser
while (left ) while (left )
{ {
Token token = { nullptr, 0, TokType::Invalid, false }; Token token = { nullptr, 0, TokType::Invalid, false, line, column };
SkipWhitespace(); SkipWhitespace();
if ( left <= 0 ) if ( left <= 0 )
@ -153,11 +220,15 @@ namespace Parser
case '#': case '#':
token.Text = scanner; token.Text = scanner;
token.Length = 1; token.Length = 1;
token.Type = TokType::Preprocessor_Directive;
move_forward(); move_forward();
while (left && current != '\n' ) while (left && current != '\n' )
{ {
if ( token.Type == ETokType::Invalid && current == ' ' )
{
token.Type = ETokType::to_type( token );
}
if ( current == '\\' ) if ( current == '\\' )
{ {
move_forward(); move_forward();
@ -178,8 +249,9 @@ namespace Parser
token.Length = 1; token.Length = 1;
token.Type = TokType::Access_MemberSymbol; token.Type = TokType::Access_MemberSymbol;
if (left) if (left) {
move_forward(); move_forward();
}
if ( current == '.' ) if ( current == '.' )
{ {
@ -577,7 +649,7 @@ namespace Parser
if ( token.Type != TokType::Invalid ) if ( token.Type != TokType::Invalid )
{ {
if ( token.Type == TokType::Preprocessor_Directive && keep_preprocess_directives == false ) if ( token.is_preprocessor() && keep_preprocess_directives == false )
continue; continue;
Tokens.append( token ); Tokens.append( token );
@ -608,6 +680,7 @@ namespace Parser
} }
#pragma region Helper Macros #pragma region Helper Macros
# define check_parse_args( func, def ) \ # define check_parse_args( func, def ) \
if ( def.Len <= 0 ) \ if ( def.Len <= 0 ) \
{ \ { \
@ -620,13 +693,16 @@ if ( def.Ptr == nullptr ) \
return CodeInvalid; \ return CodeInvalid; \
} }
# define nexttok toks.next() # define nexttok Context.Tokens.next()
# define currtok toks.current() # define currtok Context.Tokens.current()
# define prevtok toks.previous() # define prevtok Context.Tokens.previous()
# define eat( Type_ ) toks.__eat( Type_, context ) # define eat( Type_ ) Context.Tokens.__eat( Type_ )
# define left ( toks.Arr.num() - toks.Idx ) # define left ( Context.Tokens.Arr.num() - Context.Tokens.Idx )
# define check( Type_ ) ( left && currtok.Type == Type_ ) # define check( Type_ ) ( left && currtok.Type == Type_ )
// # define
#pragma endregion Helper Macros #pragma endregion Helper Macros
struct ParseContext struct ParseContext
@ -635,28 +711,28 @@ struct ParseContext
char const* Fn; char const* Fn;
}; };
internal Code parse_function_body( Parser::TokArray& toks, char const* context ); internal Code parse_function_body();
internal Code parse_global_nspace( Parser::TokArray& toks, char const* context ); internal Code parse_global_nspace();
internal CodeClass parse_class ( Parser::TokArray& toks, char const* context ); internal CodeClass parse_class ();
internal CodeEnum parse_enum ( Parser::TokArray& toks, char const* context ); internal CodeEnum parse_enum ();
internal CodeBody parse_export_body ( Parser::TokArray& toks, char const* context ); internal CodeBody parse_export_body ();
internal CodeBody parse_extern_link_body( Parser::TokArray& toks, char const* context ); internal CodeBody parse_extern_link_body();
internal CodeExtern parse_exten_link ( Parser::TokArray& toks, char const* context ); internal CodeExtern parse_exten_link ();
internal CodeFriend parse_friend ( Parser::TokArray& toks, char const* context ); internal CodeFriend parse_friend ();
internal CodeFn parse_function ( Parser::TokArray& toks, char const* context ); internal CodeFn parse_function ();
internal CodeNamespace parse_namespace ( Parser::TokArray& toks, char const* context ); internal CodeNamespace parse_namespace ();
internal CodeOpCast parse_operator_cast ( Parser::TokArray& toks, char const* context ); internal CodeOpCast parse_operator_cast ();
internal CodeStruct parse_struct ( Parser::TokArray& toks, char const* context ); internal CodeStruct parse_struct ();
internal CodeVar parse_variable ( Parser::TokArray& toks, char const* context ); internal CodeVar parse_variable ();
internal CodeTemplate parse_template ( Parser::TokArray& toks, char const* context ); internal CodeTemplate parse_template ();
internal CodeType parse_type ( Parser::TokArray& toks, char const* context ); internal CodeType parse_type ();
internal CodeTypedef parse_typedef ( Parser::TokArray& toks, char const* context ); internal CodeTypedef parse_typedef ();
internal CodeUnion parse_union ( Parser::TokArray& toks, char const* context ); internal CodeUnion parse_union ();
internal CodeUsing parse_using ( Parser::TokArray& toks, char const* context ); internal CodeUsing parse_using ();
internal inline internal inline
Code parse_array_decl( Parser::TokArray& toks, char const* context ) Code parse_array_decl()
{ {
using namespace Parser; using namespace Parser;
@ -707,7 +783,7 @@ Code parse_array_decl( Parser::TokArray& toks, char const* context )
} }
internal inline internal inline
CodeAttributes parse_attributes( Parser::TokArray& toks, char const* context ) CodeAttributes parse_attributes()
{ {
using namespace Parser; using namespace Parser;
@ -759,7 +835,7 @@ CodeAttributes parse_attributes( Parser::TokArray& toks, char const* context )
s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text;
} }
else if ( tok_is_attribute( currtok ) ) else if ( currtok.is_attribute() )
{ {
eat(currtok.Type); eat(currtok.Type);
s32 len = start.Length; s32 len = start.Length;
@ -775,7 +851,7 @@ CodeAttributes parse_attributes( Parser::TokArray& toks, char const* context )
} }
internal inline internal inline
Parser::Token parse_identifier( Parser::TokArray& toks, char const* context ) Parser::Token parse_identifier()
{ {
using namespace Parser; using namespace Parser;
Token name = currtok; Token name = currtok;
@ -788,7 +864,7 @@ Parser::Token parse_identifier( Parser::TokArray& toks, char const* context )
if ( left == 0 ) if ( left == 0 )
{ {
log_failure( "%s: Error, unexpected end of type definition, expected identifier", context ); log_failure( "%s: Error, unexpected end of type definition, expected identifier", Context.to_string() );
return { nullptr, 0, TokType::Invalid }; return { nullptr, 0, TokType::Invalid };
} }
@ -806,7 +882,7 @@ Parser::Token parse_identifier( Parser::TokArray& toks, char const* context )
} }
internal internal
CodeParam parse_params( Parser::TokArray& toks, char const* context, bool use_template_capture = false ) CodeParam parse_params( bool use_template_capture = false )
{ {
using namespace Parser; using namespace Parser;
using namespace ECode; using namespace ECode;
@ -973,15 +1049,13 @@ CodeFn parse_function_after_name(
, CodeSpecifiers specifiers , CodeSpecifiers specifiers
, CodeType ret_type , CodeType ret_type
, StrC name , StrC name
, Parser::TokArray& toks
, char const* context
) )
{ {
using namespace Parser; using namespace Parser;
CodeParam params = parse_params( toks, stringize(parse_function) ); CodeParam params = parse_params( toks, stringize(parse_function) );
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
specifiers.append( ESpecifier::to_type(currtok) ); specifiers.append( ESpecifier::to_type(currtok) );
eat( currtok.Type ); eat( currtok.Type );
@ -1041,12 +1115,12 @@ CodeFn parse_function_after_name(
} }
internal inline internal inline
CodeOperator parse_operator_after_ret_type( ModuleFlag mflags CodeOperator parse_operator_after_ret_type(
ModuleFlag mflags
, CodeAttributes attributes , CodeAttributes attributes
, CodeSpecifiers specifiers , CodeSpecifiers specifiers
, CodeType ret_type , CodeType ret_type
, Parser::TokArray& toks )
, char const* context )
{ {
using namespace Parser; using namespace Parser;
using namespace EOperator; using namespace EOperator;
@ -1251,7 +1325,7 @@ CodeOperator parse_operator_after_ret_type( ModuleFlag mflags
// Parse Params // Parse Params
CodeParam params = parse_params( toks, stringize(parse_operator) ); CodeParam params = parse_params( toks, stringize(parse_operator) );
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
specifiers.append( ESpecifier::to_type(currtok) ); specifiers.append( ESpecifier::to_type(currtok) );
eat( currtok.Type ); eat( currtok.Type );
@ -1341,7 +1415,7 @@ CodeVar parse_variable_after_name(
} }
internal inline internal inline
Code parse_variable_assignment( Parser::TokArray& toks, char const* context ) Code parse_variable_assignment()
{ {
using namespace Parser; using namespace Parser;
@ -1372,7 +1446,7 @@ Code parse_variable_assignment( Parser::TokArray& toks, char const* context )
} }
internal inline internal inline
Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers, Parser::TokArray& toks, char const* context ) Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers )
{ {
using namespace Parser; using namespace Parser;
@ -1416,7 +1490,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes
} }
internal internal
CodeBody parse_class_struct_body( Parser::TokType which, Parser::TokArray& toks, char const* context ) CodeBody parse_class_struct_body( Parser::TokType which )
{ {
using namespace Parser; using namespace Parser;
using namespace ECode; using namespace ECode;
@ -1508,7 +1582,7 @@ CodeBody parse_class_struct_body( Parser::TokType which, Parser::TokArray& toks,
GEN_Define_Attribute_Tokens GEN_Define_Attribute_Tokens
#undef Entry #undef Entry
{ {
attributes = parse_attributes( toks, context ); attributes = parse_attributes();
} }
//! Fallthrough intended //! Fallthrough intended
case TokType::Spec_Consteval: case TokType::Spec_Consteval:
@ -1522,7 +1596,7 @@ CodeBody parse_class_struct_body( Parser::TokType which, Parser::TokArray& toks,
SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; SpecifierT specs_found[16] { ESpecifier::NumSpecifiers };
s32 NumSpecifiers = 0; s32 NumSpecifiers = 0;
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -1597,7 +1671,7 @@ CodeBody parse_class_struct_body( Parser::TokType which, Parser::TokArray& toks,
} }
internal internal
Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char const* context ) Code parse_class_struct( Parser::TokType which )
{ {
using namespace Parser; using namespace Parser;
@ -1625,7 +1699,7 @@ Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char con
eat( which ); eat( which );
attributes = parse_attributes( toks, context ); attributes = parse_attributes();
if ( check( TokType::Identifier ) ) if ( check( TokType::Identifier ) )
name = parse_identifier( toks, context ); name = parse_identifier( toks, context );
@ -1638,9 +1712,9 @@ Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char con
{ {
eat( TokType::Assign_Classifer ); eat( TokType::Assign_Classifer );
if ( tok_is_access_specifier( currtok ) ) if ( currtok.is_access_specifier() )
{ {
access = tok_to_access_specifier( currtok ); access = currtok.to_access_specifier();
} }
Token parent_tok = parse_identifier( toks, context ); Token parent_tok = parse_identifier( toks, context );
@ -1650,7 +1724,7 @@ Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char con
{ {
eat(TokType::Access_Public); eat(TokType::Access_Public);
if ( tok_is_access_specifier( currtok ) ) if ( currtok.is_access_specifier() )
{ {
eat(currtok.Type); eat(currtok.Type);
} }
@ -1685,7 +1759,7 @@ Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char con
} }
internal internal
Code parse_function_body( Parser::TokArray& toks, char const* context ) Code parse_function_body()
{ {
using namespace Parser; using namespace Parser;
using namespace ECode; using namespace ECode;
@ -1724,7 +1798,7 @@ Code parse_function_body( Parser::TokArray& toks, char const* context )
} }
internal internal
CodeBody parse_global_nspace( CodeT which, Parser::TokArray& toks, char const* context ) CodeBody parse_global_nspace( CodeT which )
{ {
using namespace Parser; using namespace Parser;
using namespace ECode; using namespace ECode;
@ -1811,7 +1885,7 @@ CodeBody parse_global_nspace( CodeT which, Parser::TokArray& toks, char const* c
GEN_Define_Attribute_Tokens GEN_Define_Attribute_Tokens
#undef Entry #undef Entry
{ {
attributes = parse_attributes( toks, context ); attributes = parse_attributes();
} }
//! Fallthrough intentional //! Fallthrough intentional
case TokType::Spec_Consteval: case TokType::Spec_Consteval:
@ -1826,7 +1900,7 @@ CodeBody parse_global_nspace( CodeT which, Parser::TokArray& toks, char const* c
SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; SpecifierT specs_found[16] { ESpecifier::NumSpecifiers };
s32 NumSpecifiers = 0; s32 NumSpecifiers = 0;
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -1890,7 +1964,7 @@ CodeBody parse_global_nspace( CodeT which, Parser::TokArray& toks, char const* c
} }
internal internal
CodeClass parse_class( Parser::TokArray& toks, char const* context ) CodeClass parse_class()
{ {
return (CodeClass) parse_class_struct( Parser::TokType::Decl_Class, toks, context ); return (CodeClass) parse_class_struct( Parser::TokType::Decl_Class, toks, context );
} }
@ -1908,7 +1982,7 @@ CodeClass parse_class( StrC def )
} }
internal internal
CodeEnum parse_enum( Parser::TokArray& toks, char const* context ) CodeEnum parse_enum()
{ {
using namespace Parser; using namespace Parser;
using namespace ECode; using namespace ECode;
@ -2027,7 +2101,7 @@ CodeEnum parse_enum( StrC def )
} }
internal inline internal inline
CodeBody parse_export_body( Parser::TokArray& toks, char const* context ) CodeBody parse_export_body()
{ {
return parse_global_nspace( ECode::Export_Body, toks, context ); return parse_global_nspace( ECode::Export_Body, toks, context );
} }
@ -2170,9 +2244,9 @@ CodeFn parse_functon( Parser::TokArray& toks, char const* context )
eat( TokType::Module_Export ); eat( TokType::Module_Export );
} }
attributes = parse_attributes( toks, context ); attributes = parse_attributes();
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -2294,9 +2368,9 @@ CodeOperator parse_operator( Parser::TokArray& toks, char const* context )
eat( TokType::Module_Export ); eat( TokType::Module_Export );
} }
attributes = parse_attributes( toks, context ); attributes = parse_attributes();
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -2492,9 +2566,9 @@ CodeTemplate parse_template( Parser::TokArray& toks, char const* context )
SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; SpecifierT specs_found[16] { ESpecifier::NumSpecifiers };
s32 NumSpecifiers = 0; s32 NumSpecifiers = 0;
attributes = parse_attributes( toks, stringize(parse_template) ); attributes = parse_attributes();
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -2576,9 +2650,9 @@ CodeType parse_type( Parser::TokArray& toks, char const* context )
Token name = { nullptr, 0, TokType::Invalid }; Token name = { nullptr, 0, TokType::Invalid };
Token brute_sig = { currtok.Text, 0, TokType::Invalid }; Token brute_sig = { currtok.Text, 0, TokType::Invalid };
CodeAttributes attributes = parse_attributes( toks, context ); CodeAttributes attributes = parse_attributes();
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -2651,7 +2725,7 @@ CodeType parse_type( Parser::TokArray& toks, char const* context )
} }
} }
while ( left && tok_is_specifier( currtok ) ) while ( left && currtok.is_specifier() )
{ {
SpecifierT spec = ESpecifier::to_type( currtok ); SpecifierT spec = ESpecifier::to_type( currtok );
@ -2842,7 +2916,7 @@ CodeUnion parse_union( Parser::TokArray& toks, char const* context )
eat( TokType::Decl_Union ); eat( TokType::Decl_Union );
CodeAttributes attributes = parse_attributes( toks, context ); CodeAttributes attributes = parse_attributes();
StrC name = { 0, nullptr }; StrC name = { 0, nullptr };
@ -2986,12 +3060,10 @@ CodeUsing parse_using( StrC def )
} }
internal internal
CodeVar parse_variable( Parser::TokArray& toks, char const* context ) CodeVar parse_variable()
{ {
using namespace Parser; using namespace Parser;
Token name = { nullptr, 0, TokType::Invalid };
SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; SpecifierT specs_found[16] { ESpecifier::NumSpecifiers };
s32 NumSpecifiers = 0; s32 NumSpecifiers = 0;
@ -3005,7 +3077,7 @@ CodeVar parse_variable( Parser::TokArray& toks, char const* context )
eat( TokType::Module_Export ); eat( TokType::Module_Export );
} }
attributes = parse_attributes( toks, context ); attributes = parse_attributes();
while ( left && tok_is_specifier( currtok ) ) while ( left && tok_is_specifier( currtok ) )
{ {
@ -3050,24 +3122,32 @@ CodeVar parse_variable( Parser::TokArray& toks, char const* context )
if ( type == Code::Invalid ) if ( type == Code::Invalid )
return CodeInvalid; return CodeInvalid;
name = currtok; Context.Scope->Name = current;
eat( TokType::Identifier ); eat( TokType::Identifier );
CodeVar result = parse_variable_after_name( mflags, attributes, specifiers, type, name, toks, context ); CodeVar result = parse_variable_after_name( mflags, attributes, specifiers, type, Context.Scope->Name, Context.Tokens, Context.Scope->ProcName );
return result; return result;
} }
CodeVar parse_variable( StrC def ) CodeVar parse_variable( StrC def )
{ {
check_parse_args( parse_variable, def );
using namespace Parser; using namespace Parser;
check_parse_args( parse_variable, def );
TokArray toks = lex( def ); TokArray toks = lex( def );
if ( toks.Arr == nullptr ) if ( toks.Arr == nullptr )
return CodeInvalid; return CodeInvalid;
return parse_variable( toks, stringize(parse_variable) ); Context.Tokens = toks;
Parser::StackNode root
{
toks.current(),
{ nullptr, 0, TokType::Invalid },
name(parse_variable)
};
return parse_variable();
} }
// Undef helper macros // Undef helper macros
@ -3075,4 +3155,3 @@ CodeVar parse_variable( StrC def )
# undef curr_tok # undef curr_tok
# undef eat # undef eat
# undef left # undef left

View File

@ -1338,7 +1338,7 @@ CodeBody def_class_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_class_body ); def_body_code_validation_start( def_class_body );
AST_BODY_CLASS_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES
def_body_code_validation_end( def_class_body ); def_body_code_validation_end( def_class_body );
va_end(va); va_end(va);
@ -1354,7 +1354,7 @@ CodeBody def_class_body( s32 num, Code* codes )
result->Type = Function_Body; result->Type = Function_Body;
def_body_code_array_validation_start( def_class_body ); def_body_code_array_validation_start( def_class_body );
AST_BODY_CLASS_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES
def_body_code_validation_end( def_class_body ); def_body_code_validation_end( def_class_body );
return result; return result;
@ -1437,7 +1437,7 @@ CodeBody def_export_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_export_body ); def_body_code_validation_start( def_export_body );
AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_EXPORT_UNALLOWED_TYPES
def_body_code_validation_end( def_export_body ); def_body_code_validation_end( def_export_body );
va_end(va); va_end(va);
@ -1453,7 +1453,7 @@ CodeBody def_export_body( s32 num, Code* codes )
result->Type = Export_Body; result->Type = Export_Body;
def_body_code_array_validation_start( def_export_body ); def_body_code_array_validation_start( def_export_body );
AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_EXPORT_UNALLOWED_TYPES
def_body_code_validation_end( def_export_body ); def_body_code_validation_end( def_export_body );
return result; return result;
@ -1470,7 +1470,7 @@ CodeBody def_extern_link_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_extern_linkage_body ); def_body_code_validation_start( def_extern_linkage_body );
AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES
def_body_code_validation_end( def_extern_linkage_body ); def_body_code_validation_end( def_extern_linkage_body );
va_end(va); va_end(va);
@ -1486,7 +1486,7 @@ CodeBody def_extern_link_body( s32 num, Code* codes )
result->Type = Extern_Linkage_Body; result->Type = Extern_Linkage_Body;
def_body_code_array_validation_start( def_extern_linkage_body ); def_body_code_array_validation_start( def_extern_linkage_body );
AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES
def_body_code_validation_end( def_extern_linkage_body ); def_body_code_validation_end( def_extern_linkage_body );
return result; return result;
@ -1503,7 +1503,7 @@ CodeBody def_function_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_function_body ); def_body_code_validation_start( def_function_body );
AST_BODY_FUNCTION_UNALLOWED_TYPES GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES
def_body_code_validation_end( def_function_body ); def_body_code_validation_end( def_function_body );
va_end(va); va_end(va);
@ -1519,7 +1519,7 @@ CodeBody def_function_body( s32 num, Code* codes )
result->Type = Function_Body; result->Type = Function_Body;
def_body_code_array_validation_start( def_function_body ); def_body_code_array_validation_start( def_function_body );
AST_BODY_FUNCTION_UNALLOWED_TYPES GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES
def_body_code_validation_end( def_function_body ); def_body_code_validation_end( def_function_body );
return result; return result;
@ -1536,7 +1536,7 @@ CodeBody def_global_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_global_body ); def_body_code_validation_start( def_global_body );
AST_BODY_GLOBAL_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES
def_body_code_validation_end( def_global_body ); def_body_code_validation_end( def_global_body );
va_end(va); va_end(va);
@ -1552,7 +1552,7 @@ CodeBody def_global_body( s32 num, Code* codes )
result->Type = Global_Body; result->Type = Global_Body;
def_body_code_array_validation_start( def_global_body ); def_body_code_array_validation_start( def_global_body );
AST_BODY_GLOBAL_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES
def_body_code_validation_end( def_global_body ); def_body_code_validation_end( def_global_body );
return result; return result;
@ -1569,7 +1569,7 @@ CodeBody def_namespace_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_namespace_body ); def_body_code_validation_start( def_namespace_body );
AST_BODY_NAMESPACE_UNALLOWED_TYPES GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES
def_body_code_validation_end( def_namespace_body ); def_body_code_validation_end( def_namespace_body );
va_end(va); va_end(va);
@ -1585,7 +1585,7 @@ CodeBody def_namespace_body( s32 num, Code* codes )
result->Type = Global_Body; result->Type = Global_Body;
def_body_code_array_validation_start( def_namespace_body ); def_body_code_array_validation_start( def_namespace_body );
AST_BODY_NAMESPACE_UNALLOWED_TYPES GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES
def_body_code_validation_end( def_namespace_body ); def_body_code_validation_end( def_namespace_body );
return result; return result;
@ -1737,7 +1737,7 @@ CodeBody def_struct_body( s32 num, ... )
va_list va; va_list va;
va_start(va, num); va_start(va, num);
def_body_code_validation_start( def_struct_body ); def_body_code_validation_start( def_struct_body );
AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_STRUCT_UNALLOWED_TYPES
def_body_code_validation_end( def_struct_body ); def_body_code_validation_end( def_struct_body );
va_end(va); va_end(va);
@ -1753,7 +1753,7 @@ CodeBody def_struct_body( s32 num, Code* codes )
result->Type = Struct_Body; result->Type = Struct_Body;
def_body_code_array_validation_start( def_struct_body ); def_body_code_array_validation_start( def_struct_body );
AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_STRUCT_UNALLOWED_TYPES
def_body_code_validation_end( def_struct_body ); def_body_code_validation_end( def_struct_body );
return result; return result;

View File

@ -100,10 +100,3 @@ constexpr char const* Attribute_Keyword = stringize( GEN_Attribute_Keyword );
constexpr char const* Attribute_Keyword = ""; constexpr char const* Attribute_Keyword = "";
#endif #endif
#ifndef GEN_Define_Attribute_Tokens
# define GEN_Define_Attribute_Tokens \
Entry( API_Export, "GEN_API_Export_Code" ) \
Entry( API_Import, "GEN_API_Import_Code" )
#endif

View File

@ -50,7 +50,6 @@ CodeBody gen_ecode( char const* path )
#pragma pop_macro( "local_persist" ) #pragma pop_macro( "local_persist" )
CodeNamespace nspace = def_namespace( name(ECode), def_namespace_body( args( enum_code, to_str ) ) ); CodeNamespace nspace = def_namespace( name(ECode), def_namespace_body( args( enum_code, to_str ) ) );
CodeUsing code_t = def_using( name(CodeT), def_type( name(ECode::Type) ) ); CodeUsing code_t = def_using( name(CodeT), def_type( name(ECode::Type) ) );
return def_global_body( args( nspace, code_t ) ); return def_global_body( args( nspace, code_t ) );
@ -217,8 +216,6 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
CSV_Object csv_enum_nodes; CSV_Object csv_enum_nodes;
csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false ); csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false );
// memset( scratch_mem, 0, sizeof(scratch_mem) );
// scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) );
FileContents attrib_content = file_read_contents( scratch, zero_terminate, attr_path ); FileContents attrib_content = file_read_contents( scratch, zero_terminate, attr_path );
CSV_Object csv_attr_nodes; CSV_Object csv_attr_nodes;