test(gencpp): add full gencpp/base samples and comprehensive test suite
- Copied 58 files from C:\projects\gencpp\base\ to tests/assets/gencpp_samples - Added test_gencpp_full_suite.py that validates: - Skeleton generation for all .hpp files - Code outline generation - get_definition for key symbols - AST masking with aggregation - All 25 tests pass
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,457 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "parser_types.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
______ ______ ________ __ __ ______ __
|
||||
/ \ / \| \ | \ | \ / \ | \
|
||||
| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ | ▓▓\ | ▓▓ | ▓▓▓▓▓▓\ ______ ____| ▓▓ ______
|
||||
| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓▓\| ▓▓ | ▓▓ \▓▓/ \ / ▓▓/ \
|
||||
| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
|
||||
| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓
|
||||
| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓ | ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓
|
||||
| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓▓ \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \
|
||||
\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
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_DefineParams;
|
||||
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_Params;
|
||||
struct AST_Pragma;
|
||||
struct AST_PreprocessCond;
|
||||
struct AST_Specifiers;
|
||||
|
||||
#ifdef 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_Typename;
|
||||
struct AST_Typedef;
|
||||
struct AST_Union;
|
||||
struct AST_Using;
|
||||
struct AST_Var;
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST* Code;
|
||||
#else
|
||||
struct Code;
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Body* CodeBody;
|
||||
typedef AST_Attributes* CodeAttributes;
|
||||
typedef AST_Comment* CodeComment;
|
||||
typedef AST_Class* CodeClass;
|
||||
typedef AST_Constructor* CodeConstructor;
|
||||
typedef AST_Define* CodeDefine;
|
||||
typedef AST_DefineParams* CodeDefineParams;
|
||||
typedef AST_Destructor* CodeDestructor;
|
||||
typedef AST_Enum* CodeEnum;
|
||||
typedef AST_Exec* CodeExec;
|
||||
typedef AST_Extern* CodeExtern;
|
||||
typedef AST_Include* CodeInclude;
|
||||
typedef AST_Friend* CodeFriend;
|
||||
typedef AST_Fn* CodeFn;
|
||||
typedef AST_Module* CodeModule;
|
||||
typedef AST_NS* CodeNS;
|
||||
typedef AST_Operator* CodeOperator;
|
||||
typedef AST_OpCast* CodeOpCast;
|
||||
typedef AST_Params* CodeParams;
|
||||
typedef AST_PreprocessCond* CodePreprocessCond;
|
||||
typedef AST_Pragma* CodePragma;
|
||||
typedef AST_Specifiers* CodeSpecifiers;
|
||||
#else
|
||||
struct CodeBody;
|
||||
struct CodeAttributes;
|
||||
struct CodeComment;
|
||||
struct CodeClass;
|
||||
struct CodeConstructor;
|
||||
struct CodeDefine;
|
||||
struct CodeDefineParams;
|
||||
struct CodeDestructor;
|
||||
struct CodeEnum;
|
||||
struct CodeExec;
|
||||
struct CodeExtern;
|
||||
struct CodeInclude;
|
||||
struct CodeFriend;
|
||||
struct CodeFn;
|
||||
struct CodeModule;
|
||||
struct CodeNS;
|
||||
struct CodeOperator;
|
||||
struct CodeOpCast;
|
||||
struct CodeParams;
|
||||
struct CodePreprocessCond;
|
||||
struct CodePragma;
|
||||
struct CodeSpecifiers;
|
||||
#endif
|
||||
|
||||
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Expr* CodeExpr;
|
||||
typedef AST_Expr_Assign* CodeExpr_Assign;
|
||||
typedef AST_Expr_Alignof* CodeExpr_Alignof;
|
||||
typedef AST_Expr_Binary* CodeExpr_Binary;
|
||||
typedef AST_Expr_CStyleCast* CodeExpr_CStyleCast;
|
||||
typedef AST_Expr_FunctionalCast* CodeExpr_FunctionalCast;
|
||||
typedef AST_Expr_CppCast* CodeExpr_CppCast;
|
||||
typedef AST_Expr_Element* CodeExpr_Element;
|
||||
typedef AST_Expr_ProcCall* CodeExpr_ProcCall;
|
||||
typedef AST_Expr_Decltype* CodeExpr_Decltype;
|
||||
typedef AST_Expr_Comma* CodeExpr_Comma;
|
||||
typedef AST_Expr_AMS* CodeExpr_AMS; // Access Member Symbol
|
||||
typedef AST_Expr_Sizeof* CodeExpr_Sizeof;
|
||||
typedef AST_Expr_Subscript* CodeExpr_Subscript;
|
||||
typedef AST_Expr_Ternary* CodeExpr_Ternary;
|
||||
typedef AST_Expr_UnaryPrefix* CodeExpr_UnaryPrefix;
|
||||
typedef AST_Expr_UnaryPostfix* CodeExpr_UnaryPostfix;
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Stmt* CodeStmt;
|
||||
typedef AST_Stmt_Break* CodeStmt_Break;
|
||||
typedef AST_Stmt_Case* CodeStmt_Case;
|
||||
typedef AST_Stmt_Continue* CodeStmt_Continue;
|
||||
typedef AST_Stmt_Decl* CodeStmt_Decl;
|
||||
typedef AST_Stmt_Do* CodeStmt_Do;
|
||||
typedef AST_Stmt_Expr* CodeStmt_Expr;
|
||||
typedef AST_Stmt_Else* CodeStmt_Else;
|
||||
typedef AST_Stmt_If* CodeStmt_If;
|
||||
typedef AST_Stmt_For* CodeStmt_For;
|
||||
typedef AST_Stmt_Goto* CodeStmt_Goto;
|
||||
typedef AST_Stmt_Label* CodeStmt_Label;
|
||||
typedef AST_Stmt_Lambda* CodeStmt_Lambda;
|
||||
typedef AST_Stmt_Switch* CodeStmt_Switch;
|
||||
typedef AST_Stmt_While* CodeStmt_While;
|
||||
#else
|
||||
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_Lambda;
|
||||
struct CodeStmt_Switch;
|
||||
struct CodeStmt_While;
|
||||
#endif
|
||||
|
||||
// GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Struct* CodeStruct;
|
||||
typedef AST_Template* CodeTemplate;
|
||||
typedef AST_Typename* CodeTypename;
|
||||
typedef AST_Typedef* CodeTypedef;
|
||||
typedef AST_Union* CodeUnion;
|
||||
typedef AST_Using* CodeUsing;
|
||||
typedef AST_Var* CodeVar;
|
||||
#else
|
||||
struct CodeStruct;
|
||||
struct CodeTemplate;
|
||||
struct CodeTypename;
|
||||
struct CodeTypedef;
|
||||
struct CodeUnion;
|
||||
struct CodeUsing;
|
||||
struct CodeVar;
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); }
|
||||
#endif
|
||||
|
||||
#pragma region Code C-Interface
|
||||
|
||||
void code_append (Code code, Code other );
|
||||
GEN_API Str code_debug_str (Code code);
|
||||
GEN_API Code code_duplicate (Code code);
|
||||
Code* code_entry (Code code, u32 idx );
|
||||
bool code_has_entries (Code code);
|
||||
bool code_is_body (Code code);
|
||||
GEN_API bool code_is_equal (Code code, Code other);
|
||||
bool code_is_valid (Code code);
|
||||
void code_set_global (Code code);
|
||||
GEN_API StrBuilder code_to_strbuilder (Code self );
|
||||
GEN_API void code_to_strbuilder_ref(Code self, StrBuilder* result );
|
||||
Str code_type_str (Code self );
|
||||
GEN_API bool code_validate_body (Code self );
|
||||
|
||||
#pragma endregion Code C-Interface
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
/*
|
||||
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
|
||||
{
|
||||
AST* ast;
|
||||
|
||||
# define Using_Code( Typename ) \
|
||||
forceinline Str debug_str() { return code_debug_str(* this); } \
|
||||
forceinline Code duplicate() { return code_duplicate(* this); } \
|
||||
forceinline bool is_equal( Code other ) { return code_is_equal(* this, other); } \
|
||||
forceinline bool is_body() { return code_is_body(* this); } \
|
||||
forceinline bool is_valid() { return code_is_valid(* this); } \
|
||||
forceinline void set_global() { return code_set_global(* this); }
|
||||
|
||||
# define Using_CodeOps( Typename ) \
|
||||
forceinline Typename& operator = ( Code other ); \
|
||||
forceinline bool operator ==( Code other ) { return (AST*)ast == other.ast; } \
|
||||
forceinline bool operator !=( Code other ) { return (AST*)ast != other.ast; } \
|
||||
forceinline bool operator ==(std::nullptr_t) const { return ast == nullptr; } \
|
||||
forceinline bool operator !=(std::nullptr_t) const { return ast != nullptr; } \
|
||||
operator bool();
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
Using_Code( Code );
|
||||
forceinline void append(Code other) { return code_append(* this, other); }
|
||||
forceinline Code* entry(u32 idx) { return code_entry(* this, idx); }
|
||||
forceinline bool has_entries() { return code_has_entries(* this); }
|
||||
forceinline StrBuilder to_strbuilder() { return code_to_strbuilder(* this); }
|
||||
forceinline void to_strbuilder(StrBuilder& result) { return code_to_strbuilder_ref(* this, & result); }
|
||||
forceinline Str type_str() { return code_type_str(* this); }
|
||||
forceinline bool validate_body() { return code_validate_body(*this); }
|
||||
#endif
|
||||
|
||||
Using_CodeOps( Code );
|
||||
forceinline Code operator *() { return * this; } // Required to support for-range iteration.
|
||||
forceinline AST* operator ->() { return ast; }
|
||||
|
||||
Code& operator ++();
|
||||
|
||||
#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 CodeDefineParams() 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 CodeParams() const;
|
||||
operator CodePragma() const;
|
||||
operator CodePreprocessCond() const;
|
||||
operator CodeSpecifiers() const;
|
||||
operator CodeStruct() const;
|
||||
operator CodeTemplate() const;
|
||||
operator CodeTypename() const;
|
||||
operator CodeTypedef() const;
|
||||
operator CodeUnion() const;
|
||||
operator CodeUsing() const;
|
||||
operator CodeVar() const;
|
||||
#undef operator
|
||||
};
|
||||
#endif
|
||||
|
||||
#pragma region Statics
|
||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
|
||||
GEN_API extern Code Code_Global;
|
||||
|
||||
// Used to identify invalid generated code.
|
||||
GEN_API extern Code Code_Invalid;
|
||||
#pragma endregion Statics
|
||||
|
||||
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;
|
||||
|
||||
constexpr static
|
||||
int AST_ArrSpecs_Cap =
|
||||
(
|
||||
AST_POD_Size
|
||||
- sizeof(Code)
|
||||
- sizeof(StrCached)
|
||||
- sizeof(Code) * 2
|
||||
- sizeof(Token*)
|
||||
- sizeof(Code)
|
||||
- sizeof(CodeType)
|
||||
- sizeof(ModuleFlag)
|
||||
- sizeof(u32)
|
||||
)
|
||||
/ sizeof(Specifier) - 1;
|
||||
|
||||
/*
|
||||
Simple AST POD with functionality to seralize into C++ syntax.
|
||||
TODO(Ed): Eventually haven't a transparent AST like this will longer be viable once statements & expressions are in (most likely....)
|
||||
*/
|
||||
struct AST
|
||||
{
|
||||
union {
|
||||
struct
|
||||
{
|
||||
Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
|
||||
Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable // TODO(Ed): Parameters can have attributes
|
||||
Code Specs; // Class, Destructor, Function, Operator, Struct, Typename, Variable
|
||||
union {
|
||||
Code InitializerList; // Constructor
|
||||
Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces.
|
||||
Code ReturnType; // Function, Operator, Typename
|
||||
Code UnderlyingType; // Enum, Typedef
|
||||
Code ValueType; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
Code Macro; // Parameter
|
||||
Code BitfieldSize; // Variable (Class/Struct Data Member)
|
||||
Code Params; // Constructor, Define, Function, Operator, Template, Typename
|
||||
Code UnderlyingTypeMacro; // Enum
|
||||
};
|
||||
union {
|
||||
Code ArrExpr; // Typename
|
||||
Code Body; // Class, Constructor, Define, Destructor, Enum, Friend, Function, Namespace, Struct, Union
|
||||
Code Declaration; // Friend, Template
|
||||
Code Value; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
Code NextVar; // Variable
|
||||
Code SuffixSpecs; // Typename, Function (Thanks Unreal)
|
||||
Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
|
||||
};
|
||||
};
|
||||
StrCached Content; // Attributes, Comment, Execution, Include
|
||||
TokenSlice ContentToks; // TODO(Ed): Use a token slice for content
|
||||
struct {
|
||||
Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
|
||||
Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
|
||||
};
|
||||
};
|
||||
StrCached Name;
|
||||
union {
|
||||
Code Prev;
|
||||
Code Front;
|
||||
Code Last;
|
||||
};
|
||||
union {
|
||||
Code Next;
|
||||
Code Back;
|
||||
};
|
||||
Token* Token; // Reference to starting token, only available if it was derived from parsing. // TODO(Ed): Change this to a token slice.
|
||||
Code Parent;
|
||||
CodeType Type;
|
||||
// CodeFlag CodeFlags;
|
||||
ModuleFlag ModuleFlags;
|
||||
union {
|
||||
b32 IsFunction; // Used by typedef to not serialize the name field.
|
||||
struct {
|
||||
b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack.
|
||||
ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union)
|
||||
};
|
||||
Operator Op;
|
||||
AccessSpec ParentAccess;
|
||||
s32 NumEntries;
|
||||
s32 VarParenthesizedInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression.
|
||||
};
|
||||
};
|
||||
static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" );
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
// Uses an implicitly overloaded cast from the AST to the desired code type.
|
||||
// Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
struct InvalidCode_ImplictCaster;
|
||||
#define InvalidCode (InvalidCode_ImplictCaster{})
|
||||
#else
|
||||
#define InvalidCode (void*){ (void*)Code_Invalid }
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
struct NullCode_ImplicitCaster;
|
||||
// Used when the its desired when omission is allowed in a definition.
|
||||
#define NullCode (NullCode_ImplicitCaster{})
|
||||
#else
|
||||
#define NullCode nullptr
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
// These macros are used in the swtich cases within ast.cpp, inteface.upfront.cpp, parser.cpp
|
||||
|
||||
# define GEN_AST_BODY_CLASS_UNALLOWED_TYPES_CASES \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Extern_Linkage: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Function_Fwd: \
|
||||
case CT_Global_Body: \
|
||||
case CT_Namespace: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator: \
|
||||
case CT_Operator_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
# define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES_CASES GEN_AST_BODY_CLASS_UNALLOWED_TYPES_CASES
|
||||
|
||||
# define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES_CASES \
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Extern_Linkage: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Function_Fwd: \
|
||||
case CT_Global_Body: \
|
||||
case CT_Namespace: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator: \
|
||||
case CT_Operator_Fwd: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
|
||||
# define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES_CASES \
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Execution: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
# define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES_CASES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES_CASES
|
||||
# define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES_CASES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES_CASES
|
||||
|
||||
# define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES_CASES \
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Execution: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "interface.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Constants
|
||||
// Predefined typename codes. Are set to readonly and are setup during gen::init()
|
||||
|
||||
GEN_API extern Macro enum_underlying_macro;
|
||||
|
||||
GEN_API extern Code access_public;
|
||||
GEN_API extern Code access_protected;
|
||||
GEN_API extern Code access_private;
|
||||
|
||||
GEN_API extern CodeAttributes attrib_api_export;
|
||||
GEN_API extern CodeAttributes attrib_api_import;
|
||||
|
||||
GEN_API extern Code module_global_fragment;
|
||||
GEN_API extern Code module_private_fragment;
|
||||
|
||||
GEN_API extern Code fmt_newline;
|
||||
|
||||
GEN_API extern CodePragma pragma_once;
|
||||
|
||||
GEN_API extern CodeParams param_varadic;
|
||||
|
||||
GEN_API extern CodePreprocessCond preprocess_else;
|
||||
GEN_API extern CodePreprocessCond preprocess_endif;
|
||||
|
||||
GEN_API extern CodeSpecifiers spec_const;
|
||||
GEN_API extern CodeSpecifiers spec_consteval;
|
||||
GEN_API extern CodeSpecifiers spec_constexpr;
|
||||
GEN_API extern CodeSpecifiers spec_constinit;
|
||||
GEN_API extern CodeSpecifiers spec_extern_linkage;
|
||||
GEN_API extern CodeSpecifiers spec_final;
|
||||
GEN_API extern CodeSpecifiers spec_forceinline;
|
||||
GEN_API extern CodeSpecifiers spec_global;
|
||||
GEN_API extern CodeSpecifiers spec_inline;
|
||||
GEN_API extern CodeSpecifiers spec_internal_linkage;
|
||||
GEN_API extern CodeSpecifiers spec_local_persist;
|
||||
GEN_API extern CodeSpecifiers spec_mutable;
|
||||
GEN_API extern CodeSpecifiers spec_neverinline;
|
||||
GEN_API extern CodeSpecifiers spec_noexcept;
|
||||
GEN_API extern CodeSpecifiers spec_override;
|
||||
GEN_API extern CodeSpecifiers spec_ptr;
|
||||
GEN_API extern CodeSpecifiers spec_pure;
|
||||
GEN_API extern CodeSpecifiers spec_ref;
|
||||
GEN_API extern CodeSpecifiers spec_register;
|
||||
GEN_API extern CodeSpecifiers spec_rvalue;
|
||||
GEN_API extern CodeSpecifiers spec_static_member;
|
||||
GEN_API extern CodeSpecifiers spec_thread_local;
|
||||
GEN_API extern CodeSpecifiers spec_virtual;
|
||||
GEN_API extern CodeSpecifiers spec_volatile;
|
||||
|
||||
GEN_API extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
|
||||
GEN_API extern CodeTypename t_auto;
|
||||
GEN_API extern CodeTypename t_void;
|
||||
GEN_API extern CodeTypename t_int;
|
||||
GEN_API extern CodeTypename t_bool;
|
||||
GEN_API extern CodeTypename t_char;
|
||||
GEN_API extern CodeTypename t_wchar_t;
|
||||
GEN_API extern CodeTypename t_class;
|
||||
GEN_API extern CodeTypename t_typename;
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
GEN_API extern CodeTypename t_b32;
|
||||
|
||||
GEN_API extern CodeTypename t_s8;
|
||||
GEN_API extern CodeTypename t_s16;
|
||||
GEN_API extern CodeTypename t_s32;
|
||||
GEN_API extern CodeTypename t_s64;
|
||||
|
||||
GEN_API extern CodeTypename t_u8;
|
||||
GEN_API extern CodeTypename t_u16;
|
||||
GEN_API extern CodeTypename t_u32;
|
||||
GEN_API extern CodeTypename t_u64;
|
||||
|
||||
GEN_API extern CodeTypename t_ssize;
|
||||
GEN_API extern CodeTypename t_usize;
|
||||
|
||||
GEN_API extern CodeTypename t_f32;
|
||||
GEN_API extern CodeTypename t_f64;
|
||||
#endif
|
||||
|
||||
#pragma endregion Constants
|
||||
@@ -0,0 +1,32 @@
|
||||
#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 --------------------------------------------------------------.
|
||||
| _____ _____ _ _ |
|
||||
| / ____) / ____} | | | |
|
||||
| | / ___ ___ _ __ ___ _ __ _ __ | {___ | |__ _ _, __ _, ___ __| | |
|
||||
| | |{_ |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` | |
|
||||
| | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| | |
|
||||
| \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l |
|
||||
| | | | | __} | |
|
||||
| l_l l_l {___/ |
|
||||
! ----------------------------------------------------------------------- VERSION: v0.25-Alpha |
|
||||
! ============================================================================================ |
|
||||
! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION |
|
||||
! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL |
|
||||
! ============================================================================================ /
|
||||
*/
|
||||
#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
|
||||
@@ -0,0 +1,753 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "constants.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Serialization
|
||||
inline
|
||||
StrBuilder attributes_to_strbuilder(CodeAttributes attributes) {
|
||||
GEN_ASSERT(attributes);
|
||||
char* raw = ccast(char*, str_duplicate( attributes->Content, get_context()->Allocator_Temp ).Ptr);
|
||||
StrBuilder result = { raw };
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void attributes_to_strbuilder_ref(CodeAttributes attributes, StrBuilder* result) {
|
||||
GEN_ASSERT(attributes);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_str(result, attributes->Content);
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder comment_to_strbuilder(CodeComment comment) {
|
||||
GEN_ASSERT(comment);
|
||||
char* raw = ccast(char*, str_duplicate( comment->Content, get_context()->Allocator_Temp ).Ptr);
|
||||
StrBuilder result = { raw };
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void body_to_strbuilder_ref( CodeBody body, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(body != nullptr);
|
||||
GEN_ASSERT(result != nullptr);
|
||||
Code curr = body->Front;
|
||||
s32 left = body->NumEntries;
|
||||
while ( left -- )
|
||||
{
|
||||
code_to_strbuilder_ref(curr, result);
|
||||
// strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) );
|
||||
curr = curr->Next;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void comment_to_strbuilder_ref(CodeComment comment, StrBuilder* result) {
|
||||
GEN_ASSERT(comment);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_str(result, comment->Content);
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder define_to_strbuilder(CodeDefine define)
|
||||
{
|
||||
GEN_ASSERT(define);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 );
|
||||
define_to_strbuilder_ref(define, & result);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder define_params_to_strbuilder(CodeDefineParams params)
|
||||
{
|
||||
GEN_ASSERT(params);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
|
||||
define_params_to_strbuilder_ref( params, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder exec_to_strbuilder(CodeExec exec)
|
||||
{
|
||||
GEN_ASSERT(exec);
|
||||
char* raw = ccast(char*, str_duplicate( exec->Content, _ctx->Allocator_Temp ).Ptr);
|
||||
StrBuilder result = { raw };
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void exec_to_strbuilder_ref(CodeExec exec, StrBuilder* result) {
|
||||
GEN_ASSERT(exec);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_str(result, exec->Content);
|
||||
}
|
||||
|
||||
inline
|
||||
void extern_to_strbuilder(CodeExtern self, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(result);
|
||||
if ( self->Body )
|
||||
strbuilder_append_fmt( result, "extern \"%S\"\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) );
|
||||
else
|
||||
strbuilder_append_fmt( result, "extern \"%S\"\n{}\n", self->Name );
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder friend_to_strbuilder(CodeFriend self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 );
|
||||
friend_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void friend_to_strbuilder_ref(CodeFriend self, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "friend %SB", code_to_strbuilder(self->Declaration) );
|
||||
|
||||
if ( self->Declaration->Type != CT_Function && self->Declaration->Type != CT_Operator && (* result)[ strbuilder_length(* result) - 1 ] != ';' )
|
||||
{
|
||||
strbuilder_append_str( result, txt(";") );
|
||||
}
|
||||
|
||||
if ( self->InlineCmt )
|
||||
strbuilder_append_fmt( result, " %S", self->InlineCmt->Content );
|
||||
else
|
||||
strbuilder_append_str( result, txt("\n"));
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder include_to_strbuilder(CodeInclude include)
|
||||
{
|
||||
GEN_ASSERT(include);
|
||||
return strbuilder_fmt_buf( _ctx->Allocator_Temp, "#include %S\n", include->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
void include_to_strbuilder_ref( CodeInclude include, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(include);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "#include %S\n", include->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder module_to_strbuilder(CodeModule self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 );
|
||||
module_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder namespace_to_strbuilder(CodeNS self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 );
|
||||
namespace_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(result);
|
||||
if ( bitfield_is_set( u32, self->ModuleFlags, ModuleFlag_Export ))
|
||||
strbuilder_append_str( result, txt("export ") );
|
||||
|
||||
strbuilder_append_fmt( result, "namespace %S\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) );
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder params_to_strbuilder(CodeParams self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
|
||||
params_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder pragma_to_strbuilder(CodePragma self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 );
|
||||
pragma_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "#pragma %S\n", self->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
void preprocess_to_strbuilder_if(CodePreprocessCond cond, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(cond);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "#if %S", cond->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
void preprocess_to_strbuilder_ifdef(CodePreprocessCond cond, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(cond);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "#ifdef %S\n", cond->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(cond);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "#ifndef %S", cond->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
void preprocess_to_strbuilder_elif(CodePreprocessCond cond, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(cond);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_fmt( result, "#elif %S\n", cond->Content );
|
||||
}
|
||||
|
||||
inline
|
||||
void preprocess_to_strbuilder_else(CodePreprocessCond cond, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(cond);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_str( result, txt("#else\n") );
|
||||
}
|
||||
|
||||
inline
|
||||
void preprocess_to_strbuilder_endif(CodePreprocessCond cond, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(cond);
|
||||
GEN_ASSERT(result);
|
||||
strbuilder_append_str( result, txt("#endif\n") );
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder specifiers_to_strbuilder(CodeSpecifiers self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 );
|
||||
specifiers_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder template_to_strbuilder(CodeTemplate self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 1024 );
|
||||
template_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder typedef_to_strbuilder(CodeTypedef self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
|
||||
typedef_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder typename_to_strbuilder(CodeTypename self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_str( _ctx->Allocator_Temp, txt("") );
|
||||
typename_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder using_to_strbuilder(CodeUsing self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
|
||||
switch ( self->Type )
|
||||
{
|
||||
case CT_Using:
|
||||
using_to_strbuilder_ref( self, & result );
|
||||
break;
|
||||
case CT_Using_Namespace:
|
||||
using_to_strbuilder_ns( self, & result );
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void using_to_strbuilder_ns(CodeUsing self, StrBuilder* result )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(result);
|
||||
if ( self->InlineCmt )
|
||||
strbuilder_append_fmt( result, "using namespace $S; %S", self->Name, self->InlineCmt->Content );
|
||||
else
|
||||
strbuilder_append_fmt( result, "using namespace %S;\n", self->Name );
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder var_to_strbuilder(CodeVar self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
StrBuilder result = strbuilder_make_reserve( get_context()->Allocator_Temp, 256 );
|
||||
var_to_strbuilder_ref( self, & result );
|
||||
return result;
|
||||
}
|
||||
#pragma endregion Serialization
|
||||
|
||||
#pragma region Code
|
||||
inline
|
||||
void code_append( Code self, Code other )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(other);
|
||||
GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself.");
|
||||
|
||||
if ( other->Parent != nullptr )
|
||||
other = code_duplicate(other);
|
||||
|
||||
other->Parent = self;
|
||||
|
||||
if ( self->Front == nullptr )
|
||||
{
|
||||
self->Front = other;
|
||||
self->Back = other;
|
||||
|
||||
self->NumEntries++;
|
||||
return;
|
||||
}
|
||||
|
||||
Code
|
||||
Current = self->Back;
|
||||
Current->Next = other;
|
||||
other->Prev = Current;
|
||||
self->Back = other;
|
||||
self->NumEntries++;
|
||||
}
|
||||
inline
|
||||
bool code_is_body(Code self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
switch (self->Type)
|
||||
{
|
||||
case CT_Enum_Body:
|
||||
case CT_Class_Body:
|
||||
case CT_Union_Body:
|
||||
case CT_Export_Body:
|
||||
case CT_Global_Body:
|
||||
case CT_Struct_Body:
|
||||
case CT_Function_Body:
|
||||
case CT_Namespace_Body:
|
||||
case CT_Extern_Linkage_Body:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline
|
||||
Code* code_entry( Code self, u32 idx )
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
Code* current = & self->Front;
|
||||
while ( idx >= 0 && current != nullptr )
|
||||
{
|
||||
if ( idx == 0 )
|
||||
return rcast( Code*, current);
|
||||
|
||||
current = & ( * current )->Next;
|
||||
idx--;
|
||||
}
|
||||
|
||||
return rcast( Code*, current);
|
||||
}
|
||||
forceinline
|
||||
bool code_is_valid(Code self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
return self != nullptr && self->Type != CT_Invalid;
|
||||
}
|
||||
forceinline
|
||||
bool code_has_entries(Code self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
return self->NumEntries > 0;
|
||||
}
|
||||
forceinline
|
||||
void code_set_global(Code self)
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("Code::set_global: Cannot set code as global, AST is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
self->Parent = Code_Global;
|
||||
}
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
Code& Code::operator ++()
|
||||
{
|
||||
if ( ast )
|
||||
ast = ast->Next.ast;
|
||||
|
||||
return * this;
|
||||
}
|
||||
#endif
|
||||
forceinline
|
||||
Str code_type_str(Code self)
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
return codetype_to_str( self->Type );
|
||||
}
|
||||
#pragma endregion Code
|
||||
|
||||
#pragma region CodeBody
|
||||
inline
|
||||
void body_append( CodeBody self, Code other )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(other);
|
||||
|
||||
if (code_is_body(other)) {
|
||||
body_append_body( self, cast(CodeBody, other) );
|
||||
return;
|
||||
}
|
||||
|
||||
code_append( cast(Code, self), other );
|
||||
}
|
||||
inline
|
||||
void body_append_body( CodeBody self, CodeBody body )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(body);
|
||||
GEN_ASSERT_MSG(self != body, "Attempted to append body to itself.");
|
||||
|
||||
for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) {
|
||||
body_append( self, entry );
|
||||
}
|
||||
}
|
||||
inline
|
||||
Code begin_CodeBody( CodeBody body) {
|
||||
GEN_ASSERT(body);
|
||||
if ( body != nullptr )
|
||||
return body->Front;
|
||||
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
Code end_CodeBody(CodeBody body ){
|
||||
GEN_ASSERT(body);
|
||||
return body->Back->Next;
|
||||
}
|
||||
inline
|
||||
Code next_CodeBody(CodeBody body, Code entry) {
|
||||
GEN_ASSERT(body);
|
||||
GEN_ASSERT(entry);
|
||||
return entry->Next;
|
||||
}
|
||||
#pragma endregion CodeBody
|
||||
|
||||
#pragma region CodeClass
|
||||
inline
|
||||
void class_add_interface( CodeClass self, CodeTypename type )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(type);
|
||||
CodeTypename possible_slot = self->ParentType;
|
||||
if ( possible_slot != nullptr )
|
||||
{
|
||||
// Were adding an interface to parent type, so we need to make sure the parent type is public.
|
||||
self->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->Next != nullptr )
|
||||
{
|
||||
possible_slot = cast(CodeTypename, possible_slot->Next);
|
||||
}
|
||||
|
||||
possible_slot->Next = cast(Code, type);
|
||||
}
|
||||
#pragma endregion CodeClass
|
||||
|
||||
#pragma region CodeParams
|
||||
inline
|
||||
void params_append( CodeParams appendee, CodeParams other )
|
||||
{
|
||||
GEN_ASSERT(appendee);
|
||||
GEN_ASSERT(other);
|
||||
GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself.");
|
||||
Code self = cast(Code, appendee);
|
||||
Code entry = cast(Code, other);
|
||||
|
||||
if ( entry->Parent != nullptr )
|
||||
entry = code_duplicate( entry );
|
||||
|
||||
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++;
|
||||
}
|
||||
inline
|
||||
CodeParams params_get(CodeParams self, s32 idx )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
CodeParams param = self;
|
||||
do
|
||||
{
|
||||
if ( ++ param != nullptr )
|
||||
return NullCode;
|
||||
|
||||
param = cast(CodeParams, cast(Code, param)->Next);
|
||||
}
|
||||
while ( --idx );
|
||||
|
||||
return param;
|
||||
}
|
||||
forceinline
|
||||
bool params_has_entries(CodeParams self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
return self->NumEntries > 0;
|
||||
}
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
CodeParams& CodeParams::operator ++()
|
||||
{
|
||||
* this = ast->Next;
|
||||
return * this;
|
||||
}
|
||||
#endif
|
||||
forceinline
|
||||
CodeParams begin_CodeParams(CodeParams params)
|
||||
{
|
||||
if ( params != nullptr )
|
||||
return params;
|
||||
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
CodeParams end_CodeParams(CodeParams params)
|
||||
{
|
||||
// return { (AST_Params*) rcast( AST*, ast)->Last };
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
CodeParams next_CodeParams(CodeParams params, CodeParams param_iter)
|
||||
{
|
||||
GEN_ASSERT(param_iter);
|
||||
return param_iter->Next;
|
||||
}
|
||||
#pragma endregion CodeParams
|
||||
|
||||
#pragma region CodeDefineParams
|
||||
forceinline void define_params_append (CodeDefineParams appendee, CodeDefineParams other ) { params_append( cast(CodeParams, appendee), cast(CodeParams, other) ); }
|
||||
forceinline CodeDefineParams define_params_get (CodeDefineParams self, s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, self), idx); }
|
||||
forceinline bool define_params_has_entries(CodeDefineParams self) { return params_has_entries( cast(CodeParams, self)); }
|
||||
|
||||
forceinline CodeDefineParams begin_CodeDefineParams(CodeDefineParams params) { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, (Code)params)); }
|
||||
forceinline CodeDefineParams end_CodeDefineParams (CodeDefineParams params) { return (CodeDefineParams) (Code) end_CodeParams ( cast(CodeParams, (Code)params)); }
|
||||
forceinline CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter) { return (CodeDefineParams) (Code) next_CodeParams ( cast(CodeParams, (Code)params), cast(CodeParams, (Code)entry_iter)); }
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
CodeDefineParams& CodeDefineParams::operator ++()
|
||||
{
|
||||
* this = ast->Next;
|
||||
return * this;
|
||||
}
|
||||
#endif
|
||||
#pragma endregion CodeDefineParams
|
||||
|
||||
#pragma region CodeSpecifiers
|
||||
inline
|
||||
bool specifiers_append(CodeSpecifiers self, Specifier spec )
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!");
|
||||
return false;
|
||||
}
|
||||
if ( self->NumEntries == AST_ArrSpecs_Cap )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
|
||||
return false;
|
||||
}
|
||||
|
||||
self->ArrSpecs[ self->NumEntries ] = spec;
|
||||
self->NumEntries++;
|
||||
return true;
|
||||
}
|
||||
inline
|
||||
bool specifiers_has(CodeSpecifiers self, Specifier spec)
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
for ( s32 idx = 0; idx < self->NumEntries; idx++ ) {
|
||||
if ( self->ArrSpecs[ idx ] == spec )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline
|
||||
s32 specifiers_index_of(CodeSpecifiers self, Specifier spec)
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
for ( s32 idx = 0; idx < self->NumEntries; idx++ ) {
|
||||
if ( self->ArrSpecs[ idx ] == spec )
|
||||
return idx;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
inline
|
||||
s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove )
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!");
|
||||
return -1;
|
||||
}
|
||||
if ( self->NumEntries == AST_ArrSpecs_Cap )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 result = -1;
|
||||
|
||||
s32 curr = 0;
|
||||
s32 next = 0;
|
||||
for(; next < self->NumEntries; ++ curr, ++ next)
|
||||
{
|
||||
Specifier spec = self->ArrSpecs[next];
|
||||
if (spec == to_remove)
|
||||
{
|
||||
result = next;
|
||||
|
||||
next ++;
|
||||
if (next >= self->NumEntries)
|
||||
break;
|
||||
|
||||
spec = self->ArrSpecs[next];
|
||||
}
|
||||
|
||||
self->ArrSpecs[ curr ] = spec;
|
||||
}
|
||||
|
||||
if (result > -1) {
|
||||
self->NumEntries --;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
forceinline
|
||||
Specifier* begin_CodeSpecifiers(CodeSpecifiers self)
|
||||
{
|
||||
if ( self != nullptr )
|
||||
return & self->ArrSpecs[0];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
forceinline
|
||||
Specifier* end_CodeSpecifiers(CodeSpecifiers self)
|
||||
{
|
||||
return self->ArrSpecs + self->NumEntries;
|
||||
}
|
||||
forceinline
|
||||
Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter)
|
||||
{
|
||||
return spec_iter + 1;
|
||||
}
|
||||
#pragma endregion CodeSpecifiers
|
||||
|
||||
#pragma region CodeStruct
|
||||
inline
|
||||
void struct_add_interface(CodeStruct self, CodeTypename type )
|
||||
{
|
||||
CodeTypename possible_slot = self->ParentType;
|
||||
if ( possible_slot != nullptr )
|
||||
{
|
||||
// Were adding an interface to parent type, so we need to make sure the parent type is public.
|
||||
self->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->Next != nullptr )
|
||||
{
|
||||
possible_slot = cast(CodeTypename, possible_slot->Next);
|
||||
}
|
||||
|
||||
possible_slot->Next = cast(Code, type);
|
||||
}
|
||||
#pragma endregion Code
|
||||
|
||||
#pragma region Interface
|
||||
inline
|
||||
CodeBody def_body( CodeType type )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case CT_Class_Body:
|
||||
case CT_Enum_Body:
|
||||
case CT_Export_Body:
|
||||
case CT_Extern_Linkage:
|
||||
case CT_Function_Body:
|
||||
case CT_Global_Body:
|
||||
case CT_Namespace_Body:
|
||||
case CT_Struct_Body:
|
||||
case CT_Union_Body:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_failure( "def_body: Invalid type %s", codetype_to_str(type).Ptr );
|
||||
return (CodeBody)Code_Invalid;
|
||||
}
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = type;
|
||||
return (CodeBody)result;
|
||||
}
|
||||
|
||||
inline
|
||||
Str token_fmt_impl( ssize 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 );
|
||||
ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va);
|
||||
va_end(va);
|
||||
|
||||
Str str = { buf, result };
|
||||
return str;
|
||||
}
|
||||
#pragma endregion Interface
|
||||
@@ -0,0 +1,542 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "code_serialization.cpp"
|
||||
#endif
|
||||
|
||||
internal void parser_init(Context* ctx);
|
||||
internal void parser_deinit(Context* ctx);
|
||||
|
||||
internal
|
||||
void* fallback_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
GEN_ASSERT(_ctx);
|
||||
GEN_ASSERT(_ctx->Fallback_AllocatorBuckets);
|
||||
Arena* last = array_back(_ctx->Fallback_AllocatorBuckets);
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case EAllocation_ALLOC:
|
||||
{
|
||||
if ( ( last->TotalUsed + size ) > last->TotalSize )
|
||||
{
|
||||
Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets");
|
||||
|
||||
if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) )
|
||||
GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets");
|
||||
|
||||
last = array_back(_ctx->Fallback_AllocatorBuckets);
|
||||
}
|
||||
|
||||
return alloc_align( arena_allocator_info(last), size, alignment );
|
||||
}
|
||||
case EAllocation_FREE:
|
||||
{
|
||||
// Doesn't recycle.
|
||||
}
|
||||
break;
|
||||
case EAllocation_FREE_ALL:
|
||||
{
|
||||
// Memory::cleanup instead.
|
||||
}
|
||||
break;
|
||||
case EAllocation_RESIZE:
|
||||
{
|
||||
if ( last->TotalUsed + size > last->TotalSize )
|
||||
{
|
||||
Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets");
|
||||
|
||||
if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) )
|
||||
GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets");
|
||||
|
||||
last = array_back( _ctx->Fallback_AllocatorBuckets);
|
||||
}
|
||||
|
||||
void* result = alloc_align( last->Backing, size, alignment );
|
||||
|
||||
if ( result != nullptr && old_memory != nullptr )
|
||||
{
|
||||
mem_copy( result, old_memory, old_size );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
internal
|
||||
void fallback_logger(LogEntry entry)
|
||||
{
|
||||
GEN_ASSERT(entry.msg.Len > 0);
|
||||
GEN_ASSERT(entry.msg.Ptr);
|
||||
log_fmt("%S: %S", loglevel_to_str(entry.level), entry.msg);
|
||||
}
|
||||
|
||||
internal
|
||||
void define_constants()
|
||||
{
|
||||
// We only initalize these if there is no base context.
|
||||
if ( context_counter > 0 )
|
||||
return;
|
||||
|
||||
Code_Global = make_code();
|
||||
Code_Global->Name = cache_str( txt("Global Code") );
|
||||
Code_Global->Content = Code_Global->Name;
|
||||
|
||||
Code_Invalid = make_code();
|
||||
code_set_global(Code_Invalid);
|
||||
|
||||
t_empty = (CodeTypename) make_code();
|
||||
t_empty->Type = CT_Typename;
|
||||
t_empty->Name = cache_str( txt("") );
|
||||
code_set_global(cast(Code, t_empty));
|
||||
|
||||
access_private = make_code();
|
||||
access_private->Type = CT_Access_Private;
|
||||
access_private->Name = cache_str( txt("private:\n") );
|
||||
code_set_global(cast(Code, access_private));
|
||||
|
||||
access_protected = make_code();
|
||||
access_protected->Type = CT_Access_Protected;
|
||||
access_protected->Name = cache_str( txt("protected:\n") );
|
||||
code_set_global(access_protected);
|
||||
|
||||
access_public = make_code();
|
||||
access_public->Type = CT_Access_Public;
|
||||
access_public->Name = cache_str( txt("public:\n") );
|
||||
code_set_global(access_public);
|
||||
|
||||
Str api_export_str = code(GEN_API_Export_Code);
|
||||
attrib_api_export = def_attributes( api_export_str );
|
||||
code_set_global(cast(Code, attrib_api_export));
|
||||
|
||||
Str api_import_str = code(GEN_API_Import_Code);
|
||||
attrib_api_import = def_attributes( api_import_str );
|
||||
code_set_global(cast(Code, attrib_api_import));
|
||||
|
||||
module_global_fragment = make_code();
|
||||
module_global_fragment->Type = CT_Untyped;
|
||||
module_global_fragment->Name = cache_str( txt("module;") );
|
||||
module_global_fragment->Content = module_global_fragment->Name;
|
||||
code_set_global(cast(Code, module_global_fragment));
|
||||
|
||||
module_private_fragment = make_code();
|
||||
module_private_fragment->Type = CT_Untyped;
|
||||
module_private_fragment->Name = cache_str( txt("module : private;") );
|
||||
module_private_fragment->Content = module_private_fragment->Name;
|
||||
code_set_global(cast(Code, module_private_fragment));
|
||||
|
||||
fmt_newline = make_code();
|
||||
fmt_newline->Type = CT_NewLine;
|
||||
code_set_global((Code)fmt_newline);
|
||||
|
||||
pragma_once = (CodePragma) make_code();
|
||||
pragma_once->Type = CT_Preprocess_Pragma;
|
||||
pragma_once->Name = cache_str( txt("once") );
|
||||
pragma_once->Content = pragma_once->Name;
|
||||
code_set_global((Code)pragma_once);
|
||||
|
||||
param_varadic = (CodeParams) make_code();
|
||||
param_varadic->Type = CT_Parameters;
|
||||
param_varadic->Name = cache_str( txt("...") );
|
||||
param_varadic->ValueType = t_empty;
|
||||
code_set_global((Code)param_varadic);
|
||||
|
||||
preprocess_else = (CodePreprocessCond) make_code();
|
||||
preprocess_else->Type = CT_Preprocess_Else;
|
||||
code_set_global((Code)preprocess_else);
|
||||
|
||||
preprocess_endif = (CodePreprocessCond) make_code();
|
||||
preprocess_endif->Type = CT_Preprocess_EndIf;
|
||||
code_set_global((Code)preprocess_endif);
|
||||
|
||||
Str auto_str = txt("auto"); t_auto = def_type( auto_str ); code_set_global( t_auto );
|
||||
Str void_str = txt("void"); t_void = def_type( void_str ); code_set_global( t_void );
|
||||
Str int_str = txt("int"); t_int = def_type( int_str ); code_set_global( t_int );
|
||||
Str bool_str = txt("bool"); t_bool = def_type( bool_str ); code_set_global( t_bool );
|
||||
Str char_str = txt("char"); t_char = def_type( char_str ); code_set_global( t_char );
|
||||
Str wchar_str = txt("wchar_t"); t_wchar_t = def_type( wchar_str ); code_set_global( t_wchar_t );
|
||||
Str class_str = txt("class"); t_class = def_type( class_str ); code_set_global( t_class );
|
||||
Str typename_str = txt("typename"); t_typename = def_type( typename_str ); code_set_global( t_typename );
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
t_b32 = def_type( name(b32) ); code_set_global( t_b32 );
|
||||
|
||||
Str s8_str = txt("s8"); t_s8 = def_type( s8_str ); code_set_global( t_s8 );
|
||||
Str s16_str = txt("s16"); t_s16 = def_type( s16_str ); code_set_global( t_s16 );
|
||||
Str s32_str = txt("s32"); t_s32 = def_type( s32_str ); code_set_global( t_s32 );
|
||||
Str s64_str = txt("s64"); t_s64 = def_type( s64_str ); code_set_global( t_s64 );
|
||||
|
||||
Str u8_str = txt("u8"); t_u8 = def_type( u8_str ); code_set_global( t_u8 );
|
||||
Str u16_str = txt("u16"); t_u16 = def_type( u16_str ); code_set_global( t_u16 );
|
||||
Str u32_str = txt("u32"); t_u32 = def_type( u32_str ); code_set_global( t_u32 );
|
||||
Str u64_str = txt("u64"); t_u64 = def_type( u64_str ); code_set_global( t_u64 );
|
||||
|
||||
Str ssize_str = txt("ssize"); t_ssize = def_type( ssize_str ); code_set_global( t_ssize );
|
||||
Str usize_str = txt("usize"); t_usize = def_type( usize_str ); code_set_global( t_usize );
|
||||
|
||||
Str f32_str = txt("f32"); t_f32 = def_type( f32_str ); code_set_global( t_f32 );
|
||||
Str f64_str = txt("f64"); t_f64 = def_type( f64_str ); code_set_global( t_f64 );
|
||||
#endif
|
||||
|
||||
spec_const = def_specifier( Spec_Const); code_set_global( cast(Code, spec_const ));
|
||||
spec_consteval = def_specifier( Spec_Consteval); code_set_global( cast(Code, spec_consteval ));
|
||||
spec_constexpr = def_specifier( Spec_Constexpr); code_set_global( cast(Code, spec_constexpr ));
|
||||
spec_constinit = def_specifier( Spec_Constinit); code_set_global( cast(Code, spec_constinit ));
|
||||
spec_extern_linkage = def_specifier( Spec_External_Linkage); code_set_global( cast(Code, spec_extern_linkage ));
|
||||
spec_final = def_specifier( Spec_Final); code_set_global( cast(Code, spec_final ));
|
||||
spec_forceinline = def_specifier( Spec_ForceInline); code_set_global( cast(Code, spec_forceinline ));
|
||||
spec_global = def_specifier( Spec_Global); code_set_global( cast(Code, spec_global ));
|
||||
spec_inline = def_specifier( Spec_Inline); code_set_global( cast(Code, spec_inline ));
|
||||
spec_internal_linkage = def_specifier( Spec_Internal_Linkage); code_set_global( cast(Code, spec_internal_linkage ));
|
||||
spec_local_persist = def_specifier( Spec_Local_Persist); code_set_global( cast(Code, spec_local_persist ));
|
||||
spec_mutable = def_specifier( Spec_Mutable); code_set_global( cast(Code, spec_mutable ));
|
||||
spec_neverinline = def_specifier( Spec_NeverInline); code_set_global( cast(Code, spec_neverinline ));
|
||||
spec_noexcept = def_specifier( Spec_NoExceptions); code_set_global( cast(Code, spec_noexcept ));
|
||||
spec_override = def_specifier( Spec_Override); code_set_global( cast(Code, spec_override ));
|
||||
spec_ptr = def_specifier( Spec_Ptr); code_set_global( cast(Code, spec_ptr ));
|
||||
spec_pure = def_specifier( Spec_Pure); code_set_global( cast(Code, spec_pure ));
|
||||
spec_ref = def_specifier( Spec_Ref); code_set_global( cast(Code, spec_ref ));
|
||||
spec_register = def_specifier( Spec_Register); code_set_global( cast(Code, spec_register ));
|
||||
spec_rvalue = def_specifier( Spec_RValue); code_set_global( cast(Code, spec_rvalue ));
|
||||
spec_static_member = def_specifier( Spec_Static); code_set_global( cast(Code, spec_static_member ));
|
||||
spec_thread_local = def_specifier( Spec_Thread_Local); code_set_global( cast(Code, spec_thread_local ));
|
||||
spec_virtual = def_specifier( Spec_Virtual); code_set_global( cast(Code, spec_virtual ));
|
||||
spec_volatile = def_specifier( Spec_Volatile); code_set_global( cast(Code, spec_volatile ));
|
||||
|
||||
spec_local_persist = def_specifiers( 1, Spec_Local_Persist );
|
||||
code_set_global(cast(Code, spec_local_persist));
|
||||
|
||||
if (enum_underlying_macro.Name.Len == 0) {
|
||||
enum_underlying_macro.Name = txt("enum_underlying");
|
||||
enum_underlying_macro.Type = MT_Expression;
|
||||
enum_underlying_macro.Flags = MF_Functional;
|
||||
}
|
||||
register_macro(enum_underlying_macro);
|
||||
}
|
||||
|
||||
void init(Context* ctx)
|
||||
{
|
||||
do_once() {
|
||||
context_counter = 0;
|
||||
}
|
||||
AllocatorInfo fallback_allocator = { & fallback_allocator_proc, nullptr };
|
||||
|
||||
b32 using_fallback_allocator = false;
|
||||
if (ctx->Allocator_DyanmicContainers.Proc == nullptr) {
|
||||
ctx->Allocator_DyanmicContainers = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
if (ctx->Allocator_Pool.Proc == nullptr ) {
|
||||
ctx->Allocator_Pool = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
if (ctx->Allocator_StrCache.Proc == nullptr) {
|
||||
ctx->Allocator_StrCache = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
if (ctx->Allocator_Temp.Proc == nullptr) {
|
||||
ctx->Allocator_Temp = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
// Setup fallback allocator
|
||||
if (using_fallback_allocator)
|
||||
{
|
||||
ctx->Fallback_AllocatorBuckets = array_init_reserve(Arena, heap(), 128 );
|
||||
if ( ctx->Fallback_AllocatorBuckets == nullptr )
|
||||
GEN_FATAL( "Failed to reserve memory for Fallback_AllocatorBuckets");
|
||||
|
||||
Arena bucket = arena_init_from_allocator( heap(), ctx->InitSize_Fallback_Allocator_Bucket_Size );
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create first bucket for Fallback_AllocatorBuckets");
|
||||
|
||||
array_append( ctx->Fallback_AllocatorBuckets, bucket );
|
||||
}
|
||||
|
||||
if (ctx->Max_CommentLineLength == 0) {
|
||||
ctx->Max_CommentLineLength = 1024;
|
||||
}
|
||||
if (ctx->Max_StrCacheLength == 0) {
|
||||
ctx->Max_StrCacheLength = kilobytes(512);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_BuilderBuffer == 0) {
|
||||
ctx->InitSize_BuilderBuffer = megabytes(2);
|
||||
}
|
||||
if (ctx->InitSize_CodePoolsArray == 0) {
|
||||
ctx->InitSize_CodePoolsArray = 16;
|
||||
}
|
||||
if (ctx->InitSize_StringArenasArray == 0) {
|
||||
ctx->InitSize_StringArenasArray = 16;
|
||||
}
|
||||
if (ctx->CodePool_NumBlocks == 0) {
|
||||
ctx->CodePool_NumBlocks = kilobytes(16);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_LexerTokens == 0 ) {
|
||||
ctx->InitSize_LexerTokens = kilobytes(64);
|
||||
}
|
||||
if (ctx->SizePer_StringArena == 0) {
|
||||
ctx->SizePer_StringArena = megabytes(1);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_Fallback_Allocator_Bucket_Size == 0) {
|
||||
ctx->InitSize_Fallback_Allocator_Bucket_Size = megabytes(8);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_StrCacheTable == 0)
|
||||
{
|
||||
ctx->InitSize_StrCacheTable = kilobytes(8);
|
||||
}
|
||||
if (ctx->InitSize_MacrosTable == 0)
|
||||
{
|
||||
ctx->InitSize_MacrosTable = kilobytes(8);
|
||||
}
|
||||
|
||||
if (ctx->Logger == nullptr) {
|
||||
ctx->Logger = & fallback_logger;
|
||||
}
|
||||
|
||||
// Override the current context (user has to put it back if unwanted).
|
||||
_ctx = ctx;
|
||||
|
||||
// Setup the arrays
|
||||
{
|
||||
ctx->CodePools = array_init_reserve(Pool, ctx->Allocator_DyanmicContainers, ctx->InitSize_CodePoolsArray );
|
||||
if ( ctx->CodePools == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the CodePools array" );
|
||||
|
||||
ctx->StringArenas = array_init_reserve(Arena, ctx->Allocator_DyanmicContainers, ctx->InitSize_StringArenasArray );
|
||||
if ( ctx->StringArenas == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" );
|
||||
}
|
||||
// Setup the code pool and code entries arena.
|
||||
{
|
||||
Pool code_pool = pool_init( ctx->Allocator_Pool, ctx->CodePool_NumBlocks, size_of(AST) );
|
||||
if ( code_pool.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the code pool" );
|
||||
array_append( ctx->CodePools, code_pool );
|
||||
|
||||
// TODO(Ed): Eventually the string arenas needs to be phased out for a dedicated string slab allocator
|
||||
Arena strbuilder_arena = arena_init_from_allocator( ctx->Allocator_StrCache, ctx->SizePer_StringArena );
|
||||
if ( strbuilder_arena.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the string arena" );
|
||||
array_append( ctx->StringArenas, strbuilder_arena );
|
||||
}
|
||||
// Setup the hash tables
|
||||
{
|
||||
ctx->StrCache = hashtable_init_reserve(StrCached, ctx->Allocator_DyanmicContainers, ctx->InitSize_StrCacheTable);
|
||||
if ( ctx->StrCache.Entries == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the StringCache");
|
||||
|
||||
ctx->Macros = hashtable_init_reserve(Macro, ctx->Allocator_DyanmicContainers, ctx->InitSize_MacrosTable);
|
||||
if (ctx->Macros.Hashes == nullptr || ctx->Macros.Entries == nullptr) {
|
||||
GEN_FATAL( "gen::init: Failed to initialize the PreprocessMacros table" );
|
||||
}
|
||||
}
|
||||
|
||||
define_constants();
|
||||
parser_init(ctx);
|
||||
|
||||
++ context_counter;
|
||||
}
|
||||
|
||||
void deinit(Context* ctx)
|
||||
{
|
||||
GEN_ASSERT(context_counter);
|
||||
GEN_ASSERT_MSG(context_counter > 0, "Attempted to deinit a context that for some reason wan't accounted for!");
|
||||
usize index = 0;
|
||||
usize left = array_num(ctx->CodePools);
|
||||
do
|
||||
{
|
||||
Pool* code_pool = & ctx->CodePools[index];
|
||||
pool_free(code_pool);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
index = 0;
|
||||
left = array_num(ctx->StringArenas);
|
||||
do
|
||||
{
|
||||
Arena* strbuilder_arena = & ctx->StringArenas[index];
|
||||
arena_free(strbuilder_arena);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
hashtable_destroy(ctx->StrCache);
|
||||
|
||||
array_free( ctx->CodePools);
|
||||
array_free( ctx->StringArenas);
|
||||
|
||||
hashtable_destroy(ctx->Macros);
|
||||
|
||||
left = array_num( ctx->Fallback_AllocatorBuckets);
|
||||
if (left)
|
||||
{
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
Arena* bucket = & ctx->Fallback_AllocatorBuckets[ index ];
|
||||
arena_free(bucket);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
array_free( ctx->Fallback_AllocatorBuckets);
|
||||
}
|
||||
parser_deinit(ctx);
|
||||
|
||||
if (_ctx == ctx)
|
||||
_ctx = nullptr;
|
||||
-- context_counter;
|
||||
|
||||
Context wipe = {};
|
||||
* ctx = wipe;
|
||||
}
|
||||
|
||||
Context* get_context() {
|
||||
return _ctx;
|
||||
}
|
||||
|
||||
void reset(Context* ctx)
|
||||
{
|
||||
s32 index = 0;
|
||||
s32 left = array_num(ctx->CodePools);
|
||||
do
|
||||
{
|
||||
Pool* code_pool = & ctx->CodePools[index];
|
||||
pool_clear(code_pool);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
index = 0;
|
||||
left = array_num(ctx->StringArenas);
|
||||
do
|
||||
{
|
||||
Arena* strbuilder_arena = & ctx->StringArenas[index];
|
||||
strbuilder_arena->TotalUsed = 0;;
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
hashtable_clear(ctx->StrCache);
|
||||
hashtable_clear(ctx->Macros);
|
||||
define_constants();
|
||||
}
|
||||
|
||||
void set_context(Context* new_ctx) {
|
||||
GEN_ASSERT(new_ctx);
|
||||
_ctx = new_ctx;
|
||||
}
|
||||
|
||||
AllocatorInfo get_cached_str_allocator( s32 str_length )
|
||||
{
|
||||
Arena* last = array_back(_ctx->StringArenas);
|
||||
usize size_req = str_length + sizeof(StrBuilderHeader) + sizeof(char*);
|
||||
if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize )
|
||||
{
|
||||
Arena new_arena = arena_init_from_allocator( _ctx->Allocator_StrCache, _ctx->SizePer_StringArena );
|
||||
if ( ! array_append( _ctx->StringArenas, new_arena ) )
|
||||
GEN_FATAL( "gen::get_cached_str_allocator: Failed to allocate a new string arena" );
|
||||
|
||||
last = array_back( _ctx->StringArenas);
|
||||
}
|
||||
return arena_allocator_info(last);
|
||||
}
|
||||
|
||||
// Will either make or retrive a code string.
|
||||
StrCached cache_str( Str str )
|
||||
{
|
||||
if (str.Len > _ctx->Max_StrCacheLength) {
|
||||
// Do not cache the string, just shove into the arena and and return it.
|
||||
Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str ));
|
||||
return result;
|
||||
}
|
||||
u64 key = crc32( str.Ptr, str.Len ); {
|
||||
StrCached* result = hashtable_get( _ctx->StrCache, key );
|
||||
if ( result )
|
||||
return * result;
|
||||
}
|
||||
Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str ));
|
||||
hashtable_set( _ctx->StrCache, key, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
// Used internally to retireve a Code object form the CodePool.
|
||||
Code make_code()
|
||||
{
|
||||
Pool* allocator = array_back( _ctx->CodePools);
|
||||
if ( allocator->FreeList == nullptr )
|
||||
{
|
||||
Pool code_pool = pool_init( _ctx->Allocator_Pool, _ctx->CodePool_NumBlocks, sizeof(AST) );
|
||||
|
||||
if ( code_pool.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." );
|
||||
|
||||
if ( ! array_append( _ctx->CodePools, code_pool ) )
|
||||
GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." );
|
||||
|
||||
allocator = array_back( _ctx->CodePools);
|
||||
}
|
||||
Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) };
|
||||
mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) );
|
||||
return result;
|
||||
}
|
||||
|
||||
Macro* lookup_macro( Str name ) {
|
||||
u32 key = crc32( name.Ptr, name.Len );
|
||||
return hashtable_get( _ctx->Macros, key );
|
||||
}
|
||||
|
||||
void register_macro( Macro macro ) {
|
||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||
GEN_ASSERT(macro.Name.Len > 0);
|
||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||
macro.Name = cache_str(macro.Name);
|
||||
hashtable_set( _ctx->Macros, key, macro );
|
||||
}
|
||||
|
||||
void register_macros( s32 num, ... )
|
||||
{
|
||||
GEN_ASSERT(num > 0);
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
do
|
||||
{
|
||||
Macro macro = va_arg(va, Macro);
|
||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||
GEN_ASSERT(macro.Name.Len > 0);
|
||||
macro.Name = cache_str(macro.Name);
|
||||
|
||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||
hashtable_set( _ctx->Macros, key, macro );
|
||||
}
|
||||
while (num--, num > 0);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void register_macros_arr( s32 num, Macro* macros )
|
||||
{
|
||||
GEN_ASSERT(num > 0);
|
||||
do
|
||||
{
|
||||
Macro macro = * macros;
|
||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||
GEN_ASSERT(macro.Name.Len > 0);
|
||||
macro.Name = cache_str(macro.Name);
|
||||
|
||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||
hashtable_set( _ctx->Macros, key, macro );
|
||||
++ macros;
|
||||
}
|
||||
while (num--, num > 0);
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "ast_types.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Gen Interface
|
||||
/*
|
||||
/ \ | \ | \ / \
|
||||
| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______
|
||||
| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \
|
||||
| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
|
||||
| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓
|
||||
| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓
|
||||
\▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \
|
||||
\▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
// Note(Ed): This is subject to heavily change
|
||||
// with upcoming changes to the library's fallback (default) allocations strategy;
|
||||
// and major changes to lexer/parser context usage.
|
||||
struct Context
|
||||
{
|
||||
// User Configuration
|
||||
|
||||
// Persistent Data Allocation
|
||||
AllocatorInfo Allocator_DyanmicContainers; // By default will use a genral slab allocator (TODO(Ed): Currently does not)
|
||||
AllocatorInfo Allocator_Pool; // By default will use the growing vmem reserve (TODO(Ed): Currently does not)
|
||||
AllocatorInfo Allocator_StrCache; // By default will use a dedicated slab allocator (TODO(Ed): Currently does not)
|
||||
|
||||
// Temporary Allocation
|
||||
AllocatorInfo Allocator_Temp;
|
||||
|
||||
// LoggerCallaback* log_callback; // TODO(Ed): Impl user logger callback as an option.
|
||||
|
||||
// Initalization config
|
||||
u32 Max_CommentLineLength; // Used by def_comment
|
||||
u32 Max_StrCacheLength; // Any cached string longer than this is always allocated again.
|
||||
|
||||
u32 InitSize_BuilderBuffer;
|
||||
u32 InitSize_CodePoolsArray;
|
||||
u32 InitSize_StringArenasArray;
|
||||
|
||||
u32 CodePool_NumBlocks;
|
||||
|
||||
// TODO(Ed): Review these... (No longer needed if using the proper allocation strategy)
|
||||
u32 InitSize_LexerTokens;
|
||||
u32 SizePer_StringArena;
|
||||
|
||||
u32 InitSize_StrCacheTable;
|
||||
u32 InitSize_MacrosTable;
|
||||
|
||||
// TODO(Ed): Symbol Table
|
||||
// Keep track of all resolved symbols (naemspaced identifiers)
|
||||
|
||||
// Logging
|
||||
|
||||
LoggerProc* Logger;
|
||||
|
||||
// Parser
|
||||
|
||||
// Used by the lexer to persistently treat all these identifiers as preprocessor defines.
|
||||
// Populate with strings via gen::cache_str.
|
||||
// Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments.
|
||||
MacroTable Macros;
|
||||
|
||||
// Backend
|
||||
|
||||
// The fallback allocator is utilized if any fo the three above allocators is not specified by the user.
|
||||
u32 InitSize_Fallback_Allocator_Bucket_Size;
|
||||
Array(Arena) Fallback_AllocatorBuckets;
|
||||
|
||||
StringTable token_fmt_map;
|
||||
|
||||
// Array(Token) LexerTokens;
|
||||
|
||||
Array(Pool) CodePools;
|
||||
Array(Arena) StringArenas;
|
||||
|
||||
StringTable StrCache;
|
||||
|
||||
// TODO(Ed): Active parse context vs a parse result need to be separated conceptually
|
||||
ParseContext parser;
|
||||
|
||||
// TODO(Ed): Formatting - This will eventually be in a separate struct when in the process of serialization of the builder.
|
||||
s32 temp_serialize_indent;
|
||||
};
|
||||
|
||||
// TODO(Ed): Eventually this library should opt out of an implicit context for baseline implementation
|
||||
// This would automatically make it viable for multi-threaded purposes among other things
|
||||
// An implicit context interface will be provided instead as wrapper procedures as convience.
|
||||
GEN_API extern Context* _ctx;
|
||||
|
||||
// TODO(Ed): Swap all usage of this with logger_fmt (then rename logger_fmt to log_fmt)
|
||||
inline
|
||||
ssize log_fmt(char const* fmt, ...)
|
||||
{
|
||||
ssize res;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
res = c_str_fmt_out_va(fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline
|
||||
void logger_fmt(Context* ctx, LogLevel level, char const* fmt, ...)
|
||||
{
|
||||
local_persist thread_local
|
||||
PrintF_Buffer buf = struct_zero_init();
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) -1;
|
||||
va_end(va);
|
||||
|
||||
StrBuilder msg = strbuilder_make_length(ctx->Allocator_Temp, buf, res);
|
||||
|
||||
LogEntry entry = { strbuilder_to_str(msg), level };
|
||||
ctx->Logger(entry);
|
||||
}
|
||||
|
||||
// Initialize the library. There first ctx initialized must exist for lifetime of other contextes that come after as its the one that
|
||||
GEN_API void init(Context* ctx);
|
||||
|
||||
// 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.
|
||||
GEN_API void deinit(Context* ctx);
|
||||
|
||||
// Retrieves the active context (not usually needed, but here in case...)
|
||||
GEN_API Context* get_context();
|
||||
|
||||
// Clears the allocations, but doesn't free the memory, then calls init() again.
|
||||
// Ease of use.
|
||||
GEN_API void reset(Context* ctx);
|
||||
|
||||
GEN_API void set_context(Context* ctx);
|
||||
|
||||
// Mostly intended for the parser
|
||||
GEN_API Macro* lookup_macro( Str Name );
|
||||
|
||||
// Alternative way to add a preprocess define entry for the lexer & parser to utilize
|
||||
// if the user doesn't want to use def_define
|
||||
// Macros are tracked by name so if the name already exists the entry will be overwritten.
|
||||
GEN_API void register_macro( Macro macro );
|
||||
|
||||
// Ease of use batch registration
|
||||
GEN_API void register_macros( s32 num, ... );
|
||||
GEN_API void register_macros_arr( s32 num, Macro* macros );
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline void register_macros( s32 num, Macro* macros ) { return register_macros_arr(num, macros); }
|
||||
#endif
|
||||
|
||||
// Used internally to retrive or make string allocations.
|
||||
// Strings are stored in a series of string arenas of fixed size (SizePer_StringArena)
|
||||
GEN_API StrCached cache_str( Str 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.
|
||||
*/
|
||||
GEN_API Code make_code();
|
||||
|
||||
// Set these before calling gen's init() procedure.
|
||||
|
||||
#pragma region Upfront
|
||||
|
||||
GEN_API CodeAttributes def_attributes( Str content );
|
||||
GEN_API CodeComment def_comment ( Str content );
|
||||
|
||||
struct Opts_def_struct {
|
||||
CodeBody body;
|
||||
CodeTypename parent;
|
||||
AccessSpec parent_access;
|
||||
CodeAttributes attributes;
|
||||
CodeTypename* interfaces;
|
||||
s32 num_interfaces;
|
||||
CodeSpecifiers specifiers; // Only used for final specifier for now.
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_constructor {
|
||||
CodeParams params;
|
||||
Code initializer_list;
|
||||
Code body;
|
||||
};
|
||||
GEN_API CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_define {
|
||||
CodeDefineParams params;
|
||||
Str content;
|
||||
MacroFlags flags;
|
||||
b32 dont_register_to_preprocess_macros;
|
||||
};
|
||||
GEN_API CodeDefine def_define( Str name, MacroType type, Opts_def_define opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_destructor {
|
||||
Code body;
|
||||
CodeSpecifiers specifiers;
|
||||
};
|
||||
GEN_API CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_enum {
|
||||
CodeBody body;
|
||||
CodeTypename type;
|
||||
EnumT specifier;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
Code type_macro;
|
||||
};
|
||||
GEN_API CodeEnum def_enum( Str name, Opts_def_enum opts GEN_PARAM_DEFAULT );
|
||||
|
||||
GEN_API CodeExec def_execution ( Str content );
|
||||
GEN_API CodeExtern def_extern_link( Str name, CodeBody body );
|
||||
GEN_API CodeFriend def_friend ( Code code );
|
||||
|
||||
struct Opts_def_function {
|
||||
CodeParams params;
|
||||
CodeTypename ret_type;
|
||||
CodeBody body;
|
||||
CodeSpecifiers specs;
|
||||
CodeAttributes attrs;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeFn def_function( Str name, Opts_def_function opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_include { b32 foreign; };
|
||||
struct Opts_def_module { ModuleFlag mflags; };
|
||||
struct Opts_def_namespace { ModuleFlag mflags; };
|
||||
GEN_API CodeInclude def_include ( Str content, Opts_def_include opts GEN_PARAM_DEFAULT );
|
||||
GEN_API CodeModule def_module ( Str name, Opts_def_module opts GEN_PARAM_DEFAULT );
|
||||
GEN_API CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_operator {
|
||||
CodeParams params;
|
||||
CodeTypename ret_type;
|
||||
CodeBody body;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_operator_cast {
|
||||
CodeBody body;
|
||||
CodeSpecifiers specs;
|
||||
};
|
||||
GEN_API CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_param { Code value; };
|
||||
GEN_API CodeParams def_param ( CodeTypename type, Str name, Opts_def_param opts GEN_PARAM_DEFAULT );
|
||||
GEN_API CodePragma def_pragma( Str directive );
|
||||
|
||||
GEN_API CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str content );
|
||||
|
||||
GEN_API CodeSpecifiers def_specifier( Specifier specifier );
|
||||
|
||||
GEN_API CodeStruct def_struct( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_template { ModuleFlag mflags; };
|
||||
GEN_API CodeTemplate def_template( CodeParams params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_type {
|
||||
ETypenameTag type_tag;
|
||||
Code array_expr;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
};
|
||||
GEN_API CodeTypename def_type( Str name, Opts_def_type opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_typedef {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_union {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeUnion def_union( Str name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_using {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT );
|
||||
|
||||
GEN_API CodeUsing def_using_namespace( Str name );
|
||||
|
||||
struct Opts_def_variable
|
||||
{
|
||||
Code value;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable opts GEN_PARAM_DEFAULT );
|
||||
|
||||
// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries.
|
||||
CodeBody def_body( CodeType type );
|
||||
|
||||
// There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num,
|
||||
/// or provide as an array of Code objects.
|
||||
|
||||
GEN_API CodeBody def_class_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_class_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeDefineParams def_define_params ( s32 num, ... );
|
||||
GEN_API CodeDefineParams def_define_params_arr ( s32 num, CodeDefineParams* codes );
|
||||
GEN_API CodeBody def_enum_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_enum_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_export_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_export_body_arr ( s32 num, Code* codes);
|
||||
GEN_API CodeBody def_extern_link_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_extern_link_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_function_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_function_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_global_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_global_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_namespace_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_namespace_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeParams def_params ( s32 num, ... );
|
||||
GEN_API CodeParams def_params_arr ( s32 num, CodeParams* params );
|
||||
GEN_API CodeSpecifiers def_specifiers ( s32 num, ... );
|
||||
GEN_API CodeSpecifiers def_specifiers_arr ( s32 num, Specifier* specs );
|
||||
GEN_API CodeBody def_struct_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_struct_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_union_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_union_body_arr ( s32 num, Code* codes );
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline CodeBody def_class_body ( s32 num, Code* codes ) { return def_class_body_arr(num, codes); }
|
||||
forceinline CodeDefineParams def_define_params ( s32 num, CodeDefineParams* codes ) { return def_define_params_arr(num, codes); }
|
||||
forceinline CodeBody def_enum_body ( s32 num, Code* codes ) { return def_enum_body_arr(num, codes); }
|
||||
forceinline CodeBody def_export_body ( s32 num, Code* codes) { return def_export_body_arr(num, codes); }
|
||||
forceinline CodeBody def_extern_link_body( s32 num, Code* codes ) { return def_extern_link_body_arr(num, codes); }
|
||||
forceinline CodeBody def_function_body ( s32 num, Code* codes ) { return def_function_body_arr(num, codes); }
|
||||
forceinline CodeBody def_global_body ( s32 num, Code* codes ) { return def_global_body_arr(num, codes); }
|
||||
forceinline CodeBody def_namespace_body ( s32 num, Code* codes ) { return def_namespace_body_arr(num, codes); }
|
||||
forceinline CodeParams def_params ( s32 num, CodeParams* params ) { return def_params_arr(num, params); }
|
||||
forceinline CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ) { return def_specifiers_arr(num, specs); }
|
||||
forceinline CodeBody def_struct_body ( s32 num, Code* codes ) { return def_struct_body_arr(num, codes); }
|
||||
forceinline CodeBody def_union_body ( s32 num, Code* codes ) { return def_union_body_arr(num, codes); }
|
||||
#endif
|
||||
|
||||
#pragma endregion Upfront
|
||||
|
||||
#pragma region Parsing
|
||||
|
||||
struct ParseStackNode
|
||||
{
|
||||
ParseStackNode* prev;
|
||||
|
||||
TokenSlice tokens;
|
||||
Token* start;
|
||||
Str name; // The name of the AST node (if parsed)
|
||||
Str proc_name; // The name of the procedure
|
||||
Code code_rel; // Relevant AST node
|
||||
// TODO(Ed): When an error occurs, the parse stack is not released and instead the scope is left dangling.
|
||||
};
|
||||
|
||||
struct ParseInfo
|
||||
{
|
||||
ParseMessage* messages;
|
||||
LexedInfo lexed;
|
||||
Code result;
|
||||
};
|
||||
|
||||
struct ParseOpts
|
||||
{
|
||||
AllocatorInfo backing_msgs;
|
||||
AllocatorInfo backing_tokens;
|
||||
AllocatorInfo backing_ast;
|
||||
};
|
||||
|
||||
ParseInfo wip_parse_str( LexedInfo lexed, ParseOpts* opts GEN_PARAM_DEFAULT );
|
||||
|
||||
GEN_API CodeClass parse_class ( Str class_def );
|
||||
GEN_API CodeConstructor parse_constructor ( Str constructor_def );
|
||||
GEN_API CodeDefine parse_define ( Str define_def );
|
||||
GEN_API CodeDestructor parse_destructor ( Str destructor_def );
|
||||
GEN_API CodeEnum parse_enum ( Str enum_def );
|
||||
GEN_API CodeBody parse_export_body ( Str export_def );
|
||||
GEN_API CodeExtern parse_extern_link ( Str exten_link_def );
|
||||
GEN_API CodeFriend parse_friend ( Str friend_def );
|
||||
GEN_API CodeFn parse_function ( Str fn_def );
|
||||
GEN_API CodeBody parse_global_body ( Str body_def );
|
||||
GEN_API CodeNS parse_namespace ( Str namespace_def );
|
||||
GEN_API CodeOperator parse_operator ( Str operator_def );
|
||||
GEN_API CodeOpCast parse_operator_cast( Str operator_def );
|
||||
GEN_API CodeStruct parse_struct ( Str struct_def );
|
||||
GEN_API CodeTemplate parse_template ( Str template_def );
|
||||
GEN_API CodeTypename parse_type ( Str type_def );
|
||||
GEN_API CodeTypedef parse_typedef ( Str typedef_def );
|
||||
GEN_API CodeUnion parse_union ( Str union_def );
|
||||
GEN_API CodeUsing parse_using ( Str using_def );
|
||||
GEN_API CodeVar parse_variable ( Str var_def );
|
||||
|
||||
#pragma endregion Parsing
|
||||
|
||||
#pragma region Untyped text
|
||||
|
||||
GEN_API ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va );
|
||||
//! Do not use directly. Use the token_fmt macro instead.
|
||||
Str token_fmt_impl( ssize, ... );
|
||||
|
||||
GEN_API Code untyped_str ( Str content);
|
||||
GEN_API Code untyped_fmt ( char const* fmt, ... );
|
||||
GEN_API Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... );
|
||||
GEN_API Code untyped_toks ( TokenSlice tokens );
|
||||
|
||||
#pragma endregion Untyped text
|
||||
|
||||
#pragma region Macros
|
||||
|
||||
#ifndef gen_main
|
||||
#define gen_main main
|
||||
#endif
|
||||
|
||||
#ifndef name
|
||||
// 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.
|
||||
# if GEN_COMPILER_C
|
||||
# define name( Id_ ) (Str){ stringize(Id_), sizeof(stringize( Id_ )) - 1 }
|
||||
# else
|
||||
# define name( Id_ ) Str { stringize(Id_), sizeof(stringize( Id_ )) - 1 }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef code
|
||||
// Same as name just used to indicate intention of literal for code instead of names.
|
||||
# if GEN_COMPILER_C
|
||||
# define code( ... ) (Str){ stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 }
|
||||
# else
|
||||
# define code( ... ) Str { stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef args
|
||||
// Provides the number of arguments while passing args inplace.
|
||||
#define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#ifndef code_str
|
||||
// Just wrappers over common untyped code definition constructions.
|
||||
#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#ifndef code_fmt
|
||||
#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#ifndef parse_fmt
|
||||
#define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#ifndef token_fmt
|
||||
/*
|
||||
Takes a format string (char const*) and a list of tokens (Str) and returns a Str of the formatted string.
|
||||
Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va)
|
||||
---------------------------------------------------------
|
||||
Example - A string with:
|
||||
typedef <type> <name> <name>;
|
||||
Will have a token_fmt arguments populated with:
|
||||
"type", str_for_type,
|
||||
"name", str_for_name,
|
||||
and:
|
||||
stringize( typedef <type> <name> <name>; )
|
||||
-----------------------------------------------------------
|
||||
So the full call for this example would be:
|
||||
token_fmt(
|
||||
"type", str_for_type
|
||||
, "name", str_for_name
|
||||
, stringize(
|
||||
typedef <type> <name> <name>
|
||||
));
|
||||
!----------------------------------------------------------
|
||||
! Note: token_fmt_va is whitespace sensitive for the tokens.
|
||||
! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default.
|
||||
*/
|
||||
#define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#pragma endregion Macros
|
||||
|
||||
#pragma endregion Gen Interface
|
||||
@@ -0,0 +1,473 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "gen/etoktype.hpp"
|
||||
#include "interface.upfront.cpp"
|
||||
#include "lexer.cpp"
|
||||
#include "parser.cpp"
|
||||
#endif
|
||||
|
||||
// Publically Exposed Interface
|
||||
|
||||
ParseInfo wip_parse_str(LexedInfo lexed, ParseOpts* opts)
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
if (lexed.tokens.num == 0 && lexed.tokens.ptr == nullptr) {
|
||||
check_parse_args(lexed.text);
|
||||
lexed = lex(ctx, lexed.text);
|
||||
}
|
||||
ParseInfo info = struct_zero(ParseInfo);
|
||||
info.lexed = lexed;
|
||||
|
||||
// TODO(Ed): ParseInfo should be set to the parser context.
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
|
||||
CodeBody result = parse_global_nspace(ctx,CT_Global_Body);
|
||||
|
||||
parser_pop(& ctx->parser);
|
||||
return info;
|
||||
}
|
||||
|
||||
CodeClass parse_class( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeClass result = (CodeClass) parse_class_struct( ctx, Tok_Decl_Class, parser_not_inplace_def );
|
||||
parser_pop(& ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeConstructor parse_constructor(Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
|
||||
// TODO(Ed): Constructors can have prefix attributes
|
||||
|
||||
CodeSpecifiers specifiers = NullCode;
|
||||
Specifier specs_found[ 16 ] = { Spec_NumSpecifiers };
|
||||
s32 NumSpecifiers = 0;
|
||||
|
||||
while ( left && tok_is_specifier(currtok) )
|
||||
{
|
||||
Specifier spec = str_to_specifier( currtok.Text );
|
||||
|
||||
b32 ignore_spec = false;
|
||||
|
||||
switch ( spec )
|
||||
{
|
||||
case Spec_Constexpr :
|
||||
case Spec_Explicit:
|
||||
case Spec_Inline :
|
||||
case Spec_ForceInline :
|
||||
case Spec_NeverInline :
|
||||
break;
|
||||
|
||||
case Spec_Const :
|
||||
ignore_spec = true;
|
||||
break;
|
||||
|
||||
default :
|
||||
log_failure( "Invalid specifier %s for variable\n%S", spec_to_str( spec ), parser_to_strbuilder(& ctx->parser, ctx->Allocator_Temp) );
|
||||
parser_pop(& ctx->parser);
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
// Every specifier after would be considered part of the type type signature
|
||||
if (ignore_spec)
|
||||
break;
|
||||
|
||||
specs_found[ NumSpecifiers ] = spec;
|
||||
NumSpecifiers++;
|
||||
eat( currtok.Type );
|
||||
}
|
||||
|
||||
if ( NumSpecifiers ) {
|
||||
specifiers = def_specifiers_arr( NumSpecifiers, specs_found );
|
||||
// <specifiers> ...
|
||||
}
|
||||
|
||||
CodeConstructor result = parser_parse_constructor(ctx, specifiers);
|
||||
parser_pop(& ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeDefine parse_define( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeDefine result = parser_parse_define(ctx);
|
||||
parser_pop(& ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeDestructor parse_destructor( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
// TODO(Ed): Destructors can have prefix attributes
|
||||
// TODO(Ed): Destructors can have virtual
|
||||
|
||||
CodeDestructor result = parser_parse_destructor(ctx, NullCode);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeEnum parse_enum( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr ) {
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return parser_parse_enum(ctx, parser_not_inplace_def);
|
||||
}
|
||||
|
||||
CodeBody parse_export_body( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_export_body(ctx);
|
||||
}
|
||||
|
||||
CodeExtern parse_extern_link( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_extern_link(ctx);
|
||||
}
|
||||
|
||||
CodeFriend parse_friend( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_friend(ctx);
|
||||
}
|
||||
|
||||
CodeFn parse_function( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return (CodeFn) parser_parse_function(ctx);
|
||||
}
|
||||
|
||||
CodeBody parse_global_body( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeBody result = parse_global_nspace(ctx, CT_Global_Body );
|
||||
parser_pop(& ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeNS parse_namespace( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_namespace(ctx);
|
||||
}
|
||||
|
||||
CodeOperator parse_operator( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return (CodeOperator) parser_parse_operator(ctx);
|
||||
}
|
||||
|
||||
CodeOpCast parse_operator_cast( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_operator_cast(ctx, NullCode);
|
||||
}
|
||||
|
||||
CodeStruct parse_struct( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeStruct result = (CodeStruct) parse_class_struct( ctx, Tok_Decl_Struct, parser_not_inplace_def );
|
||||
parser_pop(& ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeTemplate parse_template( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_template(ctx);
|
||||
}
|
||||
|
||||
CodeTypename parse_type( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_type( ctx, parser_not_from_template, nullptr);
|
||||
}
|
||||
|
||||
CodeTypedef parse_typedef( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_typedef(ctx);
|
||||
}
|
||||
|
||||
CodeUnion parse_union( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_union(ctx, parser_not_inplace_def);
|
||||
}
|
||||
|
||||
CodeUsing parse_using( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_using(ctx);
|
||||
}
|
||||
|
||||
CodeVar parse_variable( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
return parser_parse_variable(ctx);
|
||||
}
|
||||
|
||||
// Undef helper macros
|
||||
#undef check_parse_args
|
||||
#undef currtok_noskip
|
||||
#undef currtok
|
||||
#undef peektok
|
||||
#undef prevtok
|
||||
#undef nexttok
|
||||
#undef nexttok_noskip
|
||||
#undef eat
|
||||
#undef left
|
||||
#undef check
|
||||
#undef push_scope
|
||||
#undef NullScope
|
||||
#undef def_assign
|
||||
|
||||
// Here for C Variant
|
||||
#undef lex_dont_skip_formatting
|
||||
#undef lex_skip_formatting
|
||||
|
||||
#undef parser_inplace_def
|
||||
#undef parser_not_inplace_def
|
||||
#undef parser_dont_consume_braces
|
||||
#undef parser_consume_braces
|
||||
#undef parser_not_from_template
|
||||
#undef parser_use_parenthesis
|
||||
#undef parser_strip_formatting_dont_preserve_newlines
|
||||
@@ -0,0 +1,191 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "interface.parsing.cpp"
|
||||
#endif
|
||||
|
||||
ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
|
||||
{
|
||||
char const* buf_begin = buf;
|
||||
ssize remaining = buf_size;
|
||||
|
||||
if (_ctx->token_fmt_map.Hashes == nullptr) {
|
||||
_ctx->token_fmt_map = hashtable_init(Str, _ctx->Allocator_DyanmicContainers );
|
||||
}
|
||||
// Populate token pairs
|
||||
{
|
||||
s32 left = num_tokens - 1;
|
||||
|
||||
while ( left-- )
|
||||
{
|
||||
char const* token = va_arg( va, char const* );
|
||||
Str value = va_arg( va, Str );
|
||||
|
||||
u32 key = crc32( token, c_str_len(token) );
|
||||
hashtable_set( _ctx->token_fmt_map, key, value );
|
||||
}
|
||||
}
|
||||
|
||||
char const* fmt = va_arg( va, char const* );
|
||||
char current = *fmt;
|
||||
|
||||
while ( current )
|
||||
{
|
||||
ssize len = 0;
|
||||
|
||||
while ( current && current != '<' && remaining )
|
||||
{
|
||||
* buf = * fmt;
|
||||
buf++;
|
||||
fmt++;
|
||||
remaining--;
|
||||
|
||||
current = * fmt;
|
||||
}
|
||||
|
||||
if ( current == '<' )
|
||||
{
|
||||
char const* scanner = fmt + 1;
|
||||
|
||||
s32 tok_len = 0;
|
||||
|
||||
while ( *scanner != '>' )
|
||||
{
|
||||
tok_len++;
|
||||
scanner++;
|
||||
}
|
||||
|
||||
char const* token = fmt + 1;
|
||||
|
||||
u32 key = crc32( token, tok_len );
|
||||
Str* value = hashtable_get(_ctx->token_fmt_map, key );
|
||||
|
||||
if ( value )
|
||||
{
|
||||
ssize left = value->Len;
|
||||
char const* str = value->Ptr;
|
||||
|
||||
while ( left-- )
|
||||
{
|
||||
* buf = * str;
|
||||
buf++;
|
||||
str++;
|
||||
remaining--;
|
||||
}
|
||||
|
||||
scanner++;
|
||||
fmt = scanner;
|
||||
current = * fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
* buf = * fmt;
|
||||
buf++;
|
||||
fmt++;
|
||||
remaining--;
|
||||
|
||||
current = * fmt;
|
||||
}
|
||||
}
|
||||
hashtable_clear(_ctx->token_fmt_map);
|
||||
ssize result = buf_size - remaining;
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_str( Str content )
|
||||
{
|
||||
if ( content.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_str: empty string" );
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = cache_str( content );
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = result->Name;
|
||||
|
||||
if ( result->Name.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_str: could not cache string" );
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_fmt( char const* fmt, ...)
|
||||
{
|
||||
if ( fmt == nullptr )
|
||||
{
|
||||
log_failure( "untyped_fmt: null format string" );
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize length = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va);
|
||||
va_end(va);
|
||||
Str content = { buf, length };
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = cache_str( content );
|
||||
|
||||
if ( result->Name.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_fmt: could not cache string" );
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... )
|
||||
{
|
||||
if ( num_tokens == 0 )
|
||||
{
|
||||
log_failure( "untyped_token_fmt: zero tokens" );
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va);
|
||||
va_end(va);
|
||||
|
||||
Str buf_str = { buf, length };
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = cache_str( buf_str );
|
||||
|
||||
if ( result->Name.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_fmt: could not cache string" );
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_toks( TokenSlice tokens )
|
||||
{
|
||||
if ( tokens.num == 0 ) {
|
||||
log_failure( "untyped_toks: empty token slice" );
|
||||
return InvalidCode;
|
||||
}
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = CT_Untyped;
|
||||
result->ContentToks = tokens;
|
||||
return result;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
// These macros are used in the swtich cases within parser.cpp
|
||||
|
||||
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIER_CASES \
|
||||
case Tok_Spec_Consteval: \
|
||||
case Tok_Spec_Constexpr: \
|
||||
case Tok_Spec_Constinit: \
|
||||
case Tok_Spec_Explicit: \
|
||||
case Tok_Spec_ForceInline: \
|
||||
case Tok_Spec_Inline: \
|
||||
case Tok_Spec_Mutable: \
|
||||
case Tok_Spec_NeverInline: \
|
||||
case Tok_Spec_Static: \
|
||||
case Tok_Spec_Volatile: \
|
||||
case Tok_Spec_Virtual
|
||||
|
||||
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIER_CASES \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_Explicit: \
|
||||
case Spec_Inline: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static: \
|
||||
case Spec_Volatile: \
|
||||
case Spec_Virtual
|
||||
|
||||
#define GEN_PARSER_CLASS_GLOBAL_NSPACE_ALLOWED_MEMBER_TOK_SPECIFIER_CASES \
|
||||
case Tok_Spec_Consteval: \
|
||||
case Tok_Spec_Constexpr: \
|
||||
case Tok_Spec_Constinit: \
|
||||
case Tok_Spec_Extern: \
|
||||
case Tok_Spec_ForceInline: \
|
||||
case Tok_Spec_Global: \
|
||||
case Tok_Spec_Inline: \
|
||||
case Tok_Spec_Internal_Linkage: \
|
||||
case Tok_Spec_NeverInline: \
|
||||
case Tok_Spec_Static
|
||||
|
||||
#define GEN_PARSER_CLASS_GLOBAL_NSPACE_ALLOWED_MEMBER_SPECIFIER_CASES \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Global: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Internal_Linkage: \
|
||||
case Spec_Inline: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static: \
|
||||
case Spec_Volatile
|
||||
|
||||
#define GEN_PARSER_FRIEND_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Inline: \
|
||||
case Spec_ForceInline
|
||||
|
||||
#define GEN_PARSER_FUNCTION_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Consteval: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Internal_Linkage: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Inline: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static
|
||||
|
||||
#define GEN_PARSER_OPERATOR_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Inline: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static
|
||||
|
||||
#define GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Global: \
|
||||
case Spec_Inline: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Local_Persist: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_Static: \
|
||||
case Spec_Thread_Local: \
|
||||
case Spec_Volatile
|
||||
|
||||
#define GEN_PARSER_VARIABLE_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Global: \
|
||||
case Spec_Inline: \
|
||||
case Spec_Local_Persist: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_Restrict: \
|
||||
case Spec_Static: \
|
||||
case Spec_Thread_Local: \
|
||||
case Spec_Volatile
|
||||
|
||||
#define GEN_PARSER_TYPENAME_ALLOWED_SUFFIX_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Ptr: \
|
||||
case Spec_Restrict: \
|
||||
case Spec_Ref: \
|
||||
case Spec_RValue
|
||||
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "types.hpp"
|
||||
#include "gen/ecodetypes.hpp"
|
||||
#include "gen/eoperator.hpp"
|
||||
#include "gen/especifier.hpp"
|
||||
#include "gen/etoktype.hpp"
|
||||
#endif
|
||||
|
||||
enum TokFlags : u32
|
||||
{
|
||||
TF_Operator = bit(0),
|
||||
TF_Assign = bit(1),
|
||||
TF_Identifier = bit(2),
|
||||
TF_Preprocess = bit(3),
|
||||
TF_Preprocess_Cond = bit(4),
|
||||
TF_Attribute = bit(5),
|
||||
TF_AccessOperator = bit(6),
|
||||
TF_AccessSpecifier = bit(7),
|
||||
TF_Specifier = bit(8),
|
||||
TF_EndDefinition = bit(9), // Either ; or }
|
||||
TF_Formatting = bit(10),
|
||||
TF_Literal = bit(11),
|
||||
TF_Macro_Functional = bit(12),
|
||||
TF_Macro_Expects_Body = bit(13),
|
||||
|
||||
TF_Null = 0,
|
||||
TF_UnderlyingType = GEN_U32_MAX,
|
||||
};
|
||||
|
||||
struct Token
|
||||
{
|
||||
Str Text;
|
||||
TokType Type;
|
||||
s32 Line;
|
||||
s32 Column;
|
||||
u32 Flags;
|
||||
};
|
||||
|
||||
constexpr Token NullToken { {}, Tok_Invalid, 0, 0, TF_Null };
|
||||
|
||||
forceinline
|
||||
AccessSpec tok_to_access_specifier(Token tok) {
|
||||
return scast(AccessSpec, tok.Type);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_valid( Token tok ) {
|
||||
return tok.Text.Ptr && tok.Text.Len && tok.Type != Tok_Invalid;
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_access_operator(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_AccessOperator );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_access_specifier(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_AccessSpecifier );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_attribute(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Attribute );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_operator(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Operator );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_preprocessor(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Preprocess );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_preprocess_cond(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Preprocess_Cond );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_specifier(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Specifier );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_end_definition(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_EndDefinition );
|
||||
}
|
||||
|
||||
StrBuilder tok_to_strbuilder(AllocatorInfo ainfo, Token tok);
|
||||
|
||||
struct TokenSlice
|
||||
{
|
||||
Token* ptr;
|
||||
s32 num;
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline operator Token* () const { return ptr; }
|
||||
forceinline Token& operator[]( ssize index ) const { return ptr[index]; }
|
||||
#endif
|
||||
};
|
||||
|
||||
forceinline
|
||||
Str token_range_to_str(Token start, Token end)
|
||||
{
|
||||
Str result = {
|
||||
start.Text.Ptr,
|
||||
(scast(sptr, rcast(uptr, end.Text.Ptr)) + end.Text.Len) - scast(sptr, rcast(uptr, start.Text.Ptr))
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
struct TokArray
|
||||
{
|
||||
Array(Token) Arr;
|
||||
s32 Idx;
|
||||
};
|
||||
|
||||
typedef struct LexerMessage LexerMessage;
|
||||
struct LexerMessage
|
||||
{
|
||||
LexerMessage* next;
|
||||
Str content;
|
||||
LogLevel level;
|
||||
};
|
||||
|
||||
struct LexContext
|
||||
{
|
||||
AllocatorInfo allocator_temp;
|
||||
LexerMessage* messages;
|
||||
Str content;
|
||||
s32 left;
|
||||
char const* scanner;
|
||||
s32 line;
|
||||
s32 column;
|
||||
Token token;
|
||||
Array(Token) tokens;
|
||||
};
|
||||
|
||||
struct LexedInfo
|
||||
{
|
||||
LexerMessage* messages;
|
||||
Str text;
|
||||
TokenSlice tokens;
|
||||
};
|
||||
|
||||
typedef struct ParseStackNode ParseStackNode;
|
||||
|
||||
typedef struct ParseMessage ParseMessage;
|
||||
struct ParseMessage
|
||||
{
|
||||
ParseMessage* Next;
|
||||
ParseStackNode* Scope;
|
||||
Str Content;
|
||||
LogLevel Level;
|
||||
};
|
||||
|
||||
struct ParseContext
|
||||
{
|
||||
ParseMessage* messages;
|
||||
ParseStackNode* scope;
|
||||
// TokArray Tokens;
|
||||
TokenSlice tokens;
|
||||
s32 token_id;
|
||||
};
|
||||
|
||||
enum MacroType : u16
|
||||
{
|
||||
MT_Expression, // A macro is assumed to be a expression if not resolved.
|
||||
MT_Statement,
|
||||
MT_Typename,
|
||||
MT_Block_Start, // Not Supported yet
|
||||
MT_Block_End, // Not Supported yet
|
||||
MT_Case_Statement, // Not Supported yet
|
||||
|
||||
MT_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
|
||||
forceinline
|
||||
TokType macrotype_to_toktype( MacroType type ) {
|
||||
switch ( type ) {
|
||||
case MT_Statement : return Tok_Preprocess_Macro_Stmt;
|
||||
case MT_Expression : return Tok_Preprocess_Macro_Expr;
|
||||
case MT_Typename : return Tok_Preprocess_Macro_Typename;
|
||||
}
|
||||
// All others unsupported for now.
|
||||
return Tok_Invalid;
|
||||
}
|
||||
|
||||
inline
|
||||
Str macrotype_to_str( MacroType type )
|
||||
{
|
||||
local_persist
|
||||
Str lookup[] = {
|
||||
{ "Statement", sizeof("Statement") - 1 },
|
||||
{ "Expression", sizeof("Expression") - 1 },
|
||||
{ "Typename", sizeof("Typename") - 1 },
|
||||
{ "Block_Start", sizeof("Block_Start") - 1 },
|
||||
{ "Block_End", sizeof("Block_End") - 1 },
|
||||
{ "Case_Statement", sizeof("Case_Statement") - 1 },
|
||||
};
|
||||
local_persist
|
||||
Str invalid = { "Invalid", sizeof("Invalid") };
|
||||
if ( type > MT_Case_Statement )
|
||||
return invalid;
|
||||
|
||||
return lookup[ type ];
|
||||
}
|
||||
|
||||
enum EMacroFlags : u16
|
||||
{
|
||||
// Macro has parameters (args expected to be passed)
|
||||
MF_Functional = bit(0),
|
||||
|
||||
// Expects to assign a braced scope to its body.
|
||||
MF_Expects_Body = bit(1),
|
||||
|
||||
// lex__eat wil treat this macro as an identifier if the parser attempts to consume it as one.
|
||||
// This is a kludge because we don't support push/pop macro pragmas rn.
|
||||
MF_Allow_As_Identifier = bit(2),
|
||||
|
||||
// When parsing identifiers, it will allow the consumption of the macro parameters (as its expected to be a part of constructing the identifier)
|
||||
// Example of a decarator macro from stb_sprintf.h:
|
||||
// STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char* buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3);
|
||||
// ^^ STB_SPRINTF_DECORATE is decorating sprintf
|
||||
MF_Identifier_Decorator = bit(3),
|
||||
|
||||
// lex__eat wil treat this macro as an attribute if the parser attempts to consume it as one.
|
||||
// This a kludge because unreal has a macro that behaves as both a 'statement' and an attribute (UE_DEPRECATED, PRAGMA_ENABLE_DEPRECATION_WARNINGS, etc)
|
||||
// TODO(Ed): We can keep the MF_Allow_As_Attribute flag for macros, however, we need to add the ability of AST_Attributes to chain themselves.
|
||||
// Its thats already a thing in the standard language anyway
|
||||
// & it would allow UE_DEPRECATED, (UE_PROPERTY / UE_FUNCTION) to chain themselves as attributes of a resolved member function/variable definition
|
||||
MF_Allow_As_Attribute = bit(4),
|
||||
|
||||
// When a macro is encountered after attributes and specifiers while parsing a function, or variable:
|
||||
// It will consume the macro and treat it as resolving the definition.
|
||||
// (MUST BE OF MT_Statement TYPE)
|
||||
MF_Allow_As_Definition = bit(5),
|
||||
|
||||
// Created for Unreal's PURE_VIRTUAL
|
||||
MF_Allow_As_Specifier = bit(6),
|
||||
|
||||
MF_Null = 0,
|
||||
MF_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
typedef u16 MacroFlags;
|
||||
|
||||
struct Macro
|
||||
{
|
||||
StrCached Name;
|
||||
MacroType Type;
|
||||
MacroFlags Flags;
|
||||
};
|
||||
|
||||
forceinline
|
||||
b32 macro_is_functional( Macro macro ) {
|
||||
return bitfield_is_set( b16, macro.Flags, MF_Functional );
|
||||
}
|
||||
|
||||
forceinline
|
||||
b32 macro_expects_body( Macro macro ) {
|
||||
return bitfield_is_set( b16, macro.Flags, MF_Expects_Body );
|
||||
}
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline b32 is_functional( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Functional ); }
|
||||
forceinline b32 expects_body ( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); }
|
||||
#endif
|
||||
|
||||
typedef HashTable(Macro) MacroTable;
|
||||
@@ -0,0 +1,11 @@
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
#endif
|
||||
|
||||
#include "gen.hpp"
|
||||
|
||||
//! 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.cpp"
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "interface.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region StaticData
|
||||
GEN_API global Context* _ctx;
|
||||
GEN_API global u32 context_counter;
|
||||
|
||||
#pragma region Constants
|
||||
GEN_API global Macro enum_underlying_macro;
|
||||
|
||||
GEN_API global Code Code_Global;
|
||||
GEN_API global Code Code_Invalid;
|
||||
|
||||
GEN_API global Code access_public;
|
||||
GEN_API global Code access_protected;
|
||||
GEN_API global Code access_private;
|
||||
|
||||
GEN_API global CodeAttributes attrib_api_export;
|
||||
GEN_API global CodeAttributes attrib_api_import;
|
||||
|
||||
GEN_API global Code module_global_fragment;
|
||||
GEN_API global Code module_private_fragment;
|
||||
|
||||
GEN_API global Code fmt_newline;
|
||||
|
||||
GEN_API global CodeParams param_varadic;
|
||||
|
||||
GEN_API global CodePragma pragma_once;
|
||||
|
||||
GEN_API global CodePreprocessCond preprocess_else;
|
||||
GEN_API global CodePreprocessCond preprocess_endif;
|
||||
|
||||
GEN_API global CodeSpecifiers spec_const;
|
||||
GEN_API global CodeSpecifiers spec_consteval;
|
||||
GEN_API global CodeSpecifiers spec_constexpr;
|
||||
GEN_API global CodeSpecifiers spec_constinit;
|
||||
GEN_API global CodeSpecifiers spec_extern_linkage;
|
||||
GEN_API global CodeSpecifiers spec_final;
|
||||
GEN_API global CodeSpecifiers spec_forceinline;
|
||||
GEN_API global CodeSpecifiers spec_global;
|
||||
GEN_API global CodeSpecifiers spec_inline;
|
||||
GEN_API global CodeSpecifiers spec_internal_linkage;
|
||||
GEN_API global CodeSpecifiers spec_local_persist;
|
||||
GEN_API global CodeSpecifiers spec_mutable;
|
||||
GEN_API global CodeSpecifiers spec_noexcept;
|
||||
GEN_API global CodeSpecifiers spec_neverinline;
|
||||
GEN_API global CodeSpecifiers spec_override;
|
||||
GEN_API global CodeSpecifiers spec_ptr;
|
||||
GEN_API global CodeSpecifiers spec_pure;
|
||||
GEN_API global CodeSpecifiers spec_ref;
|
||||
GEN_API global CodeSpecifiers spec_register;
|
||||
GEN_API global CodeSpecifiers spec_rvalue;
|
||||
GEN_API global CodeSpecifiers spec_static_member;
|
||||
GEN_API global CodeSpecifiers spec_thread_local;
|
||||
GEN_API global CodeSpecifiers spec_virtual;
|
||||
GEN_API global CodeSpecifiers spec_volatile;
|
||||
|
||||
GEN_API global CodeTypename t_empty;
|
||||
GEN_API global CodeTypename t_auto;
|
||||
GEN_API global CodeTypename t_void;
|
||||
GEN_API global CodeTypename t_int;
|
||||
GEN_API global CodeTypename t_bool;
|
||||
GEN_API global CodeTypename t_char;
|
||||
GEN_API global CodeTypename t_wchar_t;
|
||||
GEN_API global CodeTypename t_class;
|
||||
GEN_API global CodeTypename t_typename;
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
GEN_API global CodeTypename t_b32;
|
||||
|
||||
GEN_API global CodeTypename t_s8;
|
||||
GEN_API global CodeTypename t_s16;
|
||||
GEN_API global CodeTypename t_s32;
|
||||
GEN_API global CodeTypename t_s64;
|
||||
|
||||
GEN_API global CodeTypename t_u8;
|
||||
GEN_API global CodeTypename t_u16;
|
||||
GEN_API global CodeTypename t_u32;
|
||||
GEN_API global CodeTypename t_u64;
|
||||
|
||||
GEN_API global CodeTypename t_ssize;
|
||||
GEN_API global CodeTypename t_usize;
|
||||
|
||||
GEN_API global CodeTypename t_f32;
|
||||
GEN_API global CodeTypename t_f64;
|
||||
#endif
|
||||
|
||||
#pragma endregion Constants
|
||||
|
||||
#pragma endregion StaticData
|
||||
@@ -0,0 +1,181 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "dependencies/platform.hpp"
|
||||
#include "dependencies/macros.hpp"
|
||||
#include "dependencies/basic_types.hpp"
|
||||
#include "dependencies/debug.hpp"
|
||||
#include "dependencies/memory.hpp"
|
||||
#include "dependencies/string_ops.hpp"
|
||||
#include "dependencies/printing.hpp"
|
||||
#include "dependencies/containers.hpp"
|
||||
#include "dependencies/hashing.hpp"
|
||||
#include "dependencies/strings.hpp"
|
||||
#include "dependencies/filesystem.hpp"
|
||||
#include "dependencies/timing.hpp"
|
||||
#include "dependencies/parsing.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
________ __ __ ________
|
||||
| \ | \ | \ | \
|
||||
| ▓▓▓▓▓▓▓▓_______ __ __ ______ ____ _______ | ▓▓\ | ▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______
|
||||
| ▓▓__ | \| \ | \ \ \ / \ | ▓▓▓\| ▓▓ | ▓▓ | \ | \/ \ / \ / \
|
||||
| ▓▓ \ | ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\ ▓▓▓▓▓▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓
|
||||
| ▓▓▓▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓ \ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \
|
||||
| ▓▓_____| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\ | ▓▓ \▓▓▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\
|
||||
| ▓▓ \ ▓▓ | ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ \▓▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓
|
||||
\▓▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓
|
||||
| \__| ▓▓ ▓▓
|
||||
\▓▓ ▓▓ ▓▓
|
||||
\▓▓▓▓▓▓ \▓▓
|
||||
|
||||
*/
|
||||
|
||||
enum LogLevel //: u32
|
||||
{
|
||||
LL_Null,
|
||||
LL_Note,
|
||||
LL_Warning,
|
||||
LL_Error,
|
||||
LL_Fatal,
|
||||
LL_UnderlyingType = GEN_U32_MAX,
|
||||
};
|
||||
typedef enum LogLevel LogLevel;
|
||||
|
||||
Str loglevel_to_str(LogLevel level)
|
||||
{
|
||||
local_persist
|
||||
Str lookup[] = {
|
||||
{ "Null", sizeof("Null") - 1 },
|
||||
{ "Note", sizeof("Note") - 1 },
|
||||
{ "Warning", sizeof("Info") - 1 },
|
||||
{ "Error", sizeof("Error") - 1 },
|
||||
{ "Fatal", sizeof("Fatal") - 1 },
|
||||
};
|
||||
return lookup[level];
|
||||
}
|
||||
|
||||
typedef struct LogEntry LogEntry;
|
||||
struct LogEntry
|
||||
{
|
||||
Str msg;
|
||||
LogLevel level;
|
||||
};
|
||||
|
||||
typedef void LoggerProc(LogEntry entry);
|
||||
|
||||
// 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 AccessSpec : u32
|
||||
{
|
||||
AccessSpec_Default,
|
||||
AccessSpec_Private,
|
||||
AccessSpec_Protected,
|
||||
AccessSpec_Public,
|
||||
|
||||
AccessSpec_Num_AccessSpec,
|
||||
AccessSpec_Invalid,
|
||||
|
||||
AccessSpec_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" );
|
||||
|
||||
inline
|
||||
Str access_spec_to_str( AccessSpec type )
|
||||
{
|
||||
local_persist
|
||||
Str lookup[ (u32)AccessSpec_Num_AccessSpec ] = {
|
||||
{ "", sizeof( "" ) - 1 },
|
||||
{ "private", sizeof("prviate") - 1 },
|
||||
{ "private", sizeof("protected") - 1 },
|
||||
{ "public", sizeof("public") - 1 },
|
||||
};
|
||||
|
||||
Str invalid = { "Invalid", sizeof("Invalid") - 1 };
|
||||
if ( type > AccessSpec_Public )
|
||||
return invalid;
|
||||
|
||||
return lookup[ (u32)type ];
|
||||
}
|
||||
|
||||
enum CodeFlag : u32
|
||||
{
|
||||
CodeFlag_None = 0,
|
||||
CodeFlag_FunctionType = bit(0),
|
||||
CodeFlag_ParamPack = bit(1),
|
||||
CodeFlag_Module_Export = bit(2),
|
||||
CodeFlag_Module_Import = bit(3),
|
||||
|
||||
CodeFlag_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(CodeFlag) == size_of(u32), "CodeFlag not u32 size" );
|
||||
|
||||
// Used to indicate if enum definitoin is an enum class or regular enum.
|
||||
enum EnumDecl : u8
|
||||
{
|
||||
EnumDecl_Regular,
|
||||
EnumDecl_Class,
|
||||
|
||||
EnumT_SizeDef = GEN_U8_MAX,
|
||||
};
|
||||
typedef u8 EnumT;
|
||||
|
||||
enum ModuleFlag : u32
|
||||
{
|
||||
ModuleFlag_None = 0,
|
||||
ModuleFlag_Export = bit(0),
|
||||
ModuleFlag_Import = bit(1),
|
||||
|
||||
Num_ModuleFlags,
|
||||
ModuleFlag_Invalid,
|
||||
|
||||
ModuleFlag_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" );
|
||||
|
||||
inline
|
||||
Str module_flag_to_str( ModuleFlag flag )
|
||||
{
|
||||
local_persist
|
||||
Str lookup[ (u32)Num_ModuleFlags ] = {
|
||||
{ "__none__", sizeof("__none__") - 1 },
|
||||
{ "export", sizeof("export") - 1 },
|
||||
{ "import", sizeof("import") - 1 },
|
||||
};
|
||||
|
||||
local_persist
|
||||
Str invalid_flag = { "invalid", sizeof("invalid") };
|
||||
if ( flag > ModuleFlag_Import )
|
||||
return invalid_flag;
|
||||
|
||||
return lookup[ (u32)flag ];
|
||||
}
|
||||
|
||||
enum EPreprocessCond : u32
|
||||
{
|
||||
PreprocessCond_If,
|
||||
PreprocessCond_IfDef,
|
||||
PreprocessCond_IfNotDef,
|
||||
PreprocessCond_ElIf,
|
||||
|
||||
EPreprocessCond_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" );
|
||||
|
||||
enum ETypenameTag : u16
|
||||
{
|
||||
Tag_None,
|
||||
Tag_Class,
|
||||
Tag_Enum,
|
||||
Tag_Struct,
|
||||
Tag_Union,
|
||||
|
||||
Tag_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
static_assert( size_of(ETypenameTag) == size_of(u16), "ETypenameTag is not u16 size");
|
||||
Reference in New Issue
Block a user