8 Commits

28 changed files with 458 additions and 194 deletions

52
LICENSE
View File

@@ -1,26 +1,44 @@
MIT License BSD 3-Clause License
Copyright (c) 2025 Edward R. Gonzalez Copyright (c) 2023, Edward R. Gonzalez
Permission is hereby granted, free of charge, to any person obtaining a copy Redistribution and use in source and binary forms, with or without
of this software and associated documentation files (the "Software"), to deal modification, are permitted provided that the following conditions are met:
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 1. Redistributions of source code must retain the above copyright notice, this
copies or substantial portions of the Software. list of conditions and the following disclaimer.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Redistributions in binary form must reproduce the above copyright notice,
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, this list of conditions and the following disclaimer in the documentation
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE and/or other materials provided with the distribution.
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 3. Neither the name of the copyright holder nor the names of its
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE contributors may be used to endorse or promote products derived from
SOFTWARE. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Source URL: https://github.com/Ed94/gencpp Source URL: https://github.com/Ed94/gencpp
Acknowledgements Acknowledgements
* The dependencies for gencpp source are derived from the zpl library: https://github.com/zpl-c/zpl * The dependencies for gencpp source are derived from the zpl library: https://github.com/zpl-c/zpl
Special thanks to:
* The Handmade Community.
* Casey Muratori, Ginger Bill (Bill Hall), Mr. 4th (Allen Webster), Ryan Fluery: Influnced conceptually how to handle staged metaprograming.
* Jonathan Blow: Jai's metaprogramming influenced the design of this library.
* My friends for putting up with discord spam on this library.

View File

@@ -3,7 +3,7 @@
# include "helpers/push_ignores.inline.hpp" # include "helpers/push_ignores.inline.hpp"
# include "components/header_start.hpp" # include "components/header_start.hpp"
# include "components/types.hpp" # include "components/types.hpp"
# include "components/gen/ecode.hpp" # include "components/gen/ecodetypes.hpp"
# include "components/gen/eoperator.hpp" # include "components/gen/eoperator.hpp"
# include "components/gen/especifier.hpp" # include "components/gen/especifier.hpp"
# include "components/ast.hpp" # include "components/ast.hpp"

View File

@@ -3,7 +3,7 @@
# include "helpers/push_ignores.inline.hpp" # include "helpers/push_ignores.inline.hpp"
# include "components/header_start.hpp" # include "components/header_start.hpp"
# include "components/types.hpp" # include "components/types.hpp"
# include "components/gen/ecode.hpp" # include "components/gen/ecodetypes.hpp"
# include "components/gen/eoperator.hpp" # include "components/gen/eoperator.hpp"
# include "components/gen/especifier.hpp" # include "components/gen/especifier.hpp"
# include "components/ast.hpp" # include "components/ast.hpp"

View File

@@ -1,9 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "types.hpp" #include "parser_types.hpp"
#include "gen/ecode.hpp"
#include "gen/eoperator.hpp"
#include "gen/especifier.hpp"
#endif #endif
/* /*
@@ -406,7 +403,8 @@ struct AST
Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal) Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
}; };
}; };
StrCached Content; // Attributes, Comment, Execution, Include StrCached Content; // Attributes, Comment, Execution, Include
TokenSlice ContentToks; // TODO(Ed): Use a token slice for content
struct { struct {
Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used. Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
@@ -422,7 +420,7 @@ struct AST
Code Next; Code Next;
Code Back; Code Back;
}; };
Token* Token; // Reference to starting token, only available if it was derived from parsing. Token* Token; // Reference to starting token, only available if it was derived from parsing. // TODO(Ed): Change this to a token slice.
Code Parent; Code Parent;
CodeType Type; CodeType Type;
// CodeFlag CodeFlags; // CodeFlag CodeFlags;

View File

@@ -38,13 +38,13 @@ void body_to_strbuilder_export( CodeBody body, StrBuilder* result )
GEN_ASSERT(result != nullptr); GEN_ASSERT(result != nullptr);
strbuilder_append_fmt( result, "export\n{\n" ); strbuilder_append_fmt( result, "export\n{\n" );
Code curr = cast(Code, body); Code curr = body->Front;
s32 left = body->NumEntries; s32 left = body->NumEntries;
while ( left-- ) while ( left-- )
{ {
code_to_strbuilder_ref(curr, result); code_to_strbuilder_ref(curr, result);
// strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) ); // strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) );
++curr; curr = curr->Next;
} }
strbuilder_append_fmt( result, "};\n" ); strbuilder_append_fmt( result, "};\n" );

View File

@@ -252,8 +252,8 @@ struct CodeSpecifiers
#if ! GEN_C_LIKE_CPP #if ! GEN_C_LIKE_CPP
Using_Code( CodeSpecifiers ); Using_Code( CodeSpecifiers );
bool append( Specifier spec ) { return specifiers_append(* this, spec); } bool append( Specifier spec ) { return specifiers_append(* this, spec); }
bool has( Specifier spec ) { return specifiers_has(* this, spec); } s32 has( Specifier spec ) { return specifiers_has(* this, spec); }
s32 index_of(Specifier spec) { return specifiers_index_of(* this, spec); } s32 index_of( Specifier spec ) { return specifiers_index_of(* this, spec); }
s32 remove( Specifier to_remove ) { return specifiers_remove(* this, to_remove); } s32 remove( Specifier to_remove ) { return specifiers_remove(* this, to_remove); }
StrBuilder to_strbuilder() { return specifiers_to_strbuilder(* this ); } StrBuilder to_strbuilder() { return specifiers_to_strbuilder(* this ); }
void to_strbuilder( StrBuilder& result ) { return specifiers_to_strbuilder_ref(* this, & result); } void to_strbuilder( StrBuilder& result ) { return specifiers_to_strbuilder_ref(* this, & result); }
@@ -1075,8 +1075,7 @@ forceinline StrBuilder to_strbuilder(CodeParams params ) {
forceinline void to_strbuilder(CodeParams params, StrBuilder& result ) { return params_to_strbuilder_ref(params, & result); } forceinline void to_strbuilder(CodeParams params, StrBuilder& result ) { return params_to_strbuilder_ref(params, & result); }
forceinline bool append (CodeSpecifiers specifiers, Specifier spec) { return specifiers_append(specifiers, spec); } forceinline bool append (CodeSpecifiers specifiers, Specifier spec) { return specifiers_append(specifiers, spec); }
forceinline bool has (CodeSpecifiers specifiers, Specifier spec) { return specifiers_has(specifiers, spec); } forceinline s32 has (CodeSpecifiers specifiers, Specifier spec) { return specifiers_has(specifiers, spec); }
forceinline s32 index_of (CodeSpecifiers specifiers, Specifier spec) { return specifiers_index_of(specifiers, spec); }
forceinline s32 remove (CodeSpecifiers specifiers, Specifier to_remove ) { return specifiers_remove(specifiers, to_remove); } forceinline s32 remove (CodeSpecifiers specifiers, Specifier to_remove ) { return specifiers_remove(specifiers, to_remove); }
forceinline StrBuilder to_strbuilder(CodeSpecifiers specifiers) { return specifiers_to_strbuilder(specifiers); } forceinline StrBuilder to_strbuilder(CodeSpecifiers specifiers) { return specifiers_to_strbuilder(specifiers); }
forceinline void to_strbuilder(CodeSpecifiers specifiers, StrBuilder& result) { return specifiers_to_strbuilder_ref(specifiers, & result); } forceinline void to_strbuilder(CodeSpecifiers specifiers, StrBuilder& result) { return specifiers_to_strbuilder_ref(specifiers, & result); }

View File

@@ -1,6 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "interface.hpp" #include "constants.hpp"
#endif #endif
#pragma region Serialization #pragma region Serialization
@@ -38,7 +38,7 @@ void body_to_strbuilder_ref( CodeBody body, StrBuilder* result )
{ {
code_to_strbuilder_ref(curr, result); code_to_strbuilder_ref(curr, result);
// strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) ); // strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) );
++curr; curr = curr->Next;
} }
} }

View File

@@ -71,6 +71,14 @@ void* fallback_allocator_proc( void* allocator_data, AllocType type, ssize size,
return nullptr; 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 internal
void define_constants() void define_constants()
{ {
@@ -283,6 +291,19 @@ void init(Context* ctx)
ctx->InitSize_Fallback_Allocator_Bucket_Size = megabytes(8); 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). // Override the current context (user has to put it back if unwanted).
_ctx = ctx; _ctx = ctx;
@@ -298,7 +319,7 @@ void init(Context* ctx)
} }
// Setup the code pool and code entries arena. // Setup the code pool and code entries arena.
{ {
Pool code_pool = pool_init( ctx->Allocator_Pool, ctx->CodePool_NumBlocks, sizeof(AST) ); Pool code_pool = pool_init( ctx->Allocator_Pool, ctx->CodePool_NumBlocks, size_of(AST) );
if ( code_pool.PhysicalStart == nullptr ) if ( code_pool.PhysicalStart == nullptr )
GEN_FATAL( "gen::init: Failed to initialize the code pool" ); GEN_FATAL( "gen::init: Failed to initialize the code pool" );
array_append( ctx->CodePools, code_pool ); array_append( ctx->CodePools, code_pool );
@@ -311,11 +332,11 @@ void init(Context* ctx)
} }
// Setup the hash tables // Setup the hash tables
{ {
ctx->StrCache = hashtable_init(StrCached, ctx->Allocator_DyanmicContainers); ctx->StrCache = hashtable_init_reserve(StrCached, ctx->Allocator_DyanmicContainers, ctx->InitSize_StrCacheTable);
if ( ctx->StrCache.Entries == nullptr ) if ( ctx->StrCache.Entries == nullptr )
GEN_FATAL( "gen::init: Failed to initialize the StringCache"); GEN_FATAL( "gen::init: Failed to initialize the StringCache");
ctx->Macros = hashtable_init(Macro, ctx->Allocator_DyanmicContainers); ctx->Macros = hashtable_init_reserve(Macro, ctx->Allocator_DyanmicContainers, ctx->InitSize_MacrosTable);
if (ctx->Macros.Hashes == nullptr || ctx->Macros.Entries == nullptr) { if (ctx->Macros.Hashes == nullptr || ctx->Macros.Entries == nullptr) {
GEN_FATAL( "gen::init: Failed to initialize the PreprocessMacros table" ); GEN_FATAL( "gen::init: Failed to initialize the PreprocessMacros table" );
} }

View File

@@ -15,23 +15,37 @@
\▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
*/ */
#if 0 enum LogLevel //: u32
enum LogLevel : u32
{ {
Info, LL_Null,
Warning, LL_Note,
Panic, 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];
}
struct LogEntry struct LogEntry
{ {
Str msg; Str msg;
u32 line_num; LogLevel level;
void* data;
}; };
typedef void LoggerCallback(LogEntry entry); typedef void LoggerProc(LogEntry entry);
#endif
// Note(Ed): This is subject to heavily change // Note(Ed): This is subject to heavily change
// with upcoming changes to the library's fallback (default) allocations strategy; // with upcoming changes to the library's fallback (default) allocations strategy;
@@ -64,9 +78,16 @@ struct Context
u32 InitSize_LexerTokens; u32 InitSize_LexerTokens;
u32 SizePer_StringArena; u32 SizePer_StringArena;
u32 InitSize_StrCacheTable;
u32 InitSize_MacrosTable;
// TODO(Ed): Symbol Table // TODO(Ed): Symbol Table
// Keep track of all resolved symbols (naemspaced identifiers) // Keep track of all resolved symbols (naemspaced identifiers)
// Logging
LoggerProc* Logger;
// Parser // Parser
// Used by the lexer to persistently treat all these identifiers as preprocessor defines. // Used by the lexer to persistently treat all these identifiers as preprocessor defines.
@@ -104,6 +125,45 @@ struct Context
// An implicit context interface will be provided instead as wrapper procedures as convience. // An implicit context interface will be provided instead as wrapper procedures as convience.
GEN_API extern Context* _ctx; GEN_API extern Context* _ctx;
// 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
// 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(PrintF_Buffer);
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 // 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); GEN_API void init(Context* ctx);
@@ -114,7 +174,7 @@ GEN_API void deinit(Context* ctx);
// Retrieves the active context (not usually needed, but here in case...) // Retrieves the active context (not usually needed, but here in case...)
GEN_API Context* get_context(); GEN_API Context* get_context();
// Clears the allocations, but doesn't free the memoery, then calls init() again. // Clears the allocations, but doesn't free the memory, then calls init() again.
// Ease of use. // Ease of use.
GEN_API void reset(Context* ctx); GEN_API void reset(Context* ctx);
@@ -334,37 +394,42 @@ forceinline CodeBody def_union_body ( s32 num, Code* codes )
#pragma region Parsing #pragma region Parsing
#if 0 struct ParseStackNode
struct StackNode
{ {
StackNode* Prev; ParseStackNode* Prev;
Token Start; TokenSlice Tokens;
Token Name; // The name of the AST node (if parsed) Token* Start;
Str FailedProc; // The name of the procedure that failed Str Name; // The name of the AST node (if parsed)
Str ProcName; // The name of the procedure
Code CodeRel; // Relevant AST node
// TODO(Ed): When an error occurs, the parse stack is not released and instead the scope is left dangling.
}; };
// Stack nodes are allocated the error's allocator
struct Error typedef struct ParseMessage ParseMessage;
struct ParseMessage
{ {
StrBuilder message; ParseMessage* Next;
StackNode* context_stack; ParseStackNode* Scope;
Str Log;
LogLevel Level;
}; };
struct ParseInfo struct ParseInfo
{ {
Arena FileMem; ParseMessage* messages;
Arena TokMem; LexedInfo lexed;
Arena CodeMem; Code result;
FileContents FileContent;
Array<Token> Tokens;
Array<Error> Errors;
// Errors are allocated to a dedicated general arena.
}; };
CodeBody parse_file( Str path ); struct ParseOpts
#endif {
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 CodeClass parse_class ( Str class_def );
GEN_API CodeConstructor parse_constructor ( Str constructor_def ); GEN_API CodeConstructor parse_constructor ( Str constructor_def );
@@ -395,9 +460,10 @@ GEN_API ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list v
//! Do not use directly. Use the token_fmt macro instead. //! Do not use directly. Use the token_fmt macro instead.
Str token_fmt_impl( ssize, ... ); Str token_fmt_impl( ssize, ... );
GEN_API Code untyped_str( Str content); GEN_API Code untyped_str ( Str content);
GEN_API Code untyped_fmt ( char const* fmt, ... ); GEN_API Code untyped_fmt ( char const* fmt, ... );
GEN_API Code untyped_token_fmt( s32 num_tokens, 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 endregion Untyped text

View File

@@ -1,6 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "gen/etoktype.cpp" #include "gen/etoktype.hpp"
#include "interface.upfront.cpp" #include "interface.upfront.cpp"
#include "lexer.cpp" #include "lexer.cpp"
#include "parser.cpp" #include "parser.cpp"
@@ -8,6 +8,29 @@
// Publically Exposed Interface // Publically Exposed Interface
ParseInfo wip_parse_str(LexedInfo lexed, ParseOpts* opts)
{
TokArray toks;
if (lexed.tokens.Num == 0 && lexed.tokens.Ptr == nullptr) {
check_parse_args(lexed.text);
toks = lex(lexed.text);
TokenSlice slice = { toks.Arr, scast(s32, array_num(toks.Arr)) };
lexed.tokens = slice;
}
ParseInfo info = struct_zero(ParseInfo);
info.lexed = lexed;
// TODO(Ed): ParseInfo should be set to the parser context.
_ctx->parser.Tokens = toks;
push_scope();
CodeBody result = parse_global_nspace(CT_Global_Body);
parser_pop(& _ctx->parser);
return info;
}
CodeClass parse_class( Str def ) CodeClass parse_class( Str def )
{ {
check_parse_args( def ); check_parse_args( def );

View File

@@ -176,3 +176,16 @@ Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... )
return result; 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;
}

View File

@@ -473,8 +473,10 @@ CodeComment def_comment( Str content )
return (CodeComment) result; return (CodeComment) result;
} }
CodeConstructor def_constructor( Opts_def_constructor p ) CodeConstructor def_constructor( Opts_def_constructor opt )
{ {
Opts_def_constructor p = get_optional(opt);
if ( p.params && p.params->Type != CT_Parameters ) { if ( p.params && p.params->Type != CT_Parameters ) {
log_failure("gen::def_constructor: params must be of Parameters type - %s", code_debug_str((Code)p.params)); log_failure("gen::def_constructor: params must be of Parameters type - %s", code_debug_str((Code)p.params));
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
@@ -510,8 +512,10 @@ CodeConstructor def_constructor( Opts_def_constructor p )
return result; return result;
} }
CodeClass def_class( Str name, Opts_def_struct p ) CodeClass def_class( Str name, Opts_def_struct opt )
{ {
Opts_def_struct p = get_optional(opt);
if ( ! name_check( def_class, name ) ) { if ( ! name_check( def_class, name ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -561,8 +565,10 @@ CodeClass def_class( Str name, Opts_def_struct p )
return result; return result;
} }
CodeDefine def_define( Str name, MacroType type, Opts_def_define p ) CodeDefine def_define( Str name, MacroType type, Opts_def_define opt )
{ {
Opts_def_define p = get_optional(opt);
if ( ! name_check( def_define, name ) ) { if ( ! name_check( def_define, name ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -585,8 +591,10 @@ CodeDefine def_define( Str name, MacroType type, Opts_def_define p )
return result; return result;
} }
CodeDestructor def_destructor( Opts_def_destructor p ) CodeDestructor def_destructor( Opts_def_destructor opt )
{ {
Opts_def_destructor p = get_optional(opt);
if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) { if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) {
log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", code_debug_str(p.specifiers) ); log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", code_debug_str(p.specifiers) );
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
@@ -619,8 +627,10 @@ CodeDestructor def_destructor( Opts_def_destructor p )
return result; return result;
} }
CodeEnum def_enum( Str name, Opts_def_enum p ) CodeEnum def_enum( Str name, Opts_def_enum opt )
{ {
Opts_def_enum p = get_optional(opt);
if ( ! name_check( def_enum, name ) ) { if ( ! name_check( def_enum, name ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -742,8 +752,10 @@ CodeFriend def_friend( Code declaration )
return result; return result;
} }
CodeFn def_function( Str name, Opts_def_function p ) CodeFn def_function( Str name, Opts_def_function opt )
{ {
Opts_def_function p = get_optional(opt);
if ( ! name_check( def_function, name )) { if ( ! name_check( def_function, name )) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -802,8 +814,10 @@ CodeFn def_function( Str name, Opts_def_function p )
return result; return result;
} }
CodeInclude def_include( Str path, Opts_def_include p ) CodeInclude def_include( Str path, Opts_def_include opt )
{ {
Opts_def_include p = get_optional(opt);
if ( path.Len <= 0 || path.Ptr == nullptr ) { if ( path.Len <= 0 || path.Ptr == nullptr ) {
log_failure( "gen::def_include: Invalid path provided - %d" ); log_failure( "gen::def_include: Invalid path provided - %d" );
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
@@ -821,8 +835,10 @@ CodeInclude def_include( Str path, Opts_def_include p )
return result; return result;
} }
CodeModule def_module( Str name, Opts_def_module p ) CodeModule def_module( Str name, Opts_def_module opt )
{ {
Opts_def_module p = get_optional(opt);
if ( ! name_check( def_module, name )) { if ( ! name_check( def_module, name )) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -835,8 +851,10 @@ CodeModule def_module( Str name, Opts_def_module p )
return result; return result;
} }
CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace p ) CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace opt )
{ {
Opts_def_namespace p = get_optional(opt);
if ( ! name_check( def_namespace, name )) { if ( ! name_check( def_namespace, name )) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -859,8 +877,10 @@ CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace p )
return result; return result;
} }
CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator p ) CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator opt )
{ {
Opts_def_operator p = get_optional(opt);
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", code_debug_str(p.attributes) ); log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", code_debug_str(p.attributes) );
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
@@ -926,8 +946,10 @@ CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator p )
return result; return result;
} }
CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast p ) CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opt )
{ {
Opts_def_operator_cast p = get_optional(opt);
if ( ! null_check( def_operator_cast, type )) { if ( ! null_check( def_operator_cast, type )) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -959,8 +981,10 @@ CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast p )
return result; return result;
} }
CodeParams def_param( CodeTypename type, Str name, Opts_def_param p ) CodeParams def_param( CodeTypename type, Str name, Opts_def_param opt )
{ {
Opts_def_param p = get_optional(opt);
if ( ! name_check( def_param, name ) || ! null_check( def_param, type ) ) { if ( ! name_check( def_param, name ) || ! null_check( def_param, type ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -1034,8 +1058,10 @@ CodeSpecifiers def_specifier( Specifier spec )
return result; return result;
} }
CodeStruct def_struct( Str name, Opts_def_struct p ) CodeStruct def_struct( Str name, Opts_def_struct opt )
{ {
Opts_def_struct p = get_optional(opt);
if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) {
log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", code_debug_str(cast(Code, p.attributes)) ); log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", code_debug_str(cast(Code, p.attributes)) );
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
@@ -1076,8 +1102,10 @@ CodeStruct def_struct( Str name, Opts_def_struct p )
return result; return result;
} }
CodeTemplate def_template( CodeParams params, Code declaration, Opts_def_template p ) CodeTemplate def_template( CodeParams params, Code declaration, Opts_def_template opt )
{ {
Opts_def_template p = get_optional(opt);
if ( ! null_check( def_template, declaration ) ) { if ( ! null_check( def_template, declaration ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -1108,8 +1136,10 @@ CodeTemplate def_template( CodeParams params, Code declaration, Opts_def_templat
return result; return result;
} }
CodeTypename def_type( Str name, Opts_def_type p ) CodeTypename def_type( Str name, Opts_def_type opt )
{ {
Opts_def_type p = get_optional(opt);
if ( ! name_check( def_type, name )) { if ( ! name_check( def_type, name )) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -1143,8 +1173,10 @@ CodeTypename def_type( Str name, Opts_def_type p )
return result; return result;
} }
CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef p ) CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opt )
{ {
Opts_def_typedef p = get_optional(opt);
if ( ! null_check( def_typedef, type ) ) { if ( ! null_check( def_typedef, type ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -1206,8 +1238,10 @@ CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef p )
return result; return result;
} }
CodeUnion def_union( Str name, CodeBody body, Opts_def_union p ) CodeUnion def_union( Str name, CodeBody body, Opts_def_union opt )
{ {
Opts_def_union p = get_optional(opt);
if ( ! null_check( def_union, body ) ) { if ( ! null_check( def_union, body ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -1233,8 +1267,10 @@ CodeUnion def_union( Str name, CodeBody body, Opts_def_union p )
return result; return result;
} }
CodeUsing def_using( Str name, CodeTypename type, Opts_def_using p ) CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opt )
{ {
Opts_def_using p = get_optional(opt);
if ( ! name_check( def_using, name ) || null_check( def_using, type ) ) { if ( ! name_check( def_using, name ) || null_check( def_using, type ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;
@@ -1274,8 +1310,10 @@ CodeUsing def_using_namespace( Str name )
return result; return result;
} }
CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable p ) CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable opt )
{ {
Opts_def_variable p = get_optional(opt);
if ( ! name_check( def_variable, name ) || ! null_check( def_variable, type ) ) { if ( ! name_check( def_variable, name ) || ! null_check( def_variable, type ) ) {
GEN_DEBUG_TRAP(); GEN_DEBUG_TRAP();
return InvalidCode; return InvalidCode;

View File

@@ -1,7 +1,7 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "interface.upfront.cpp" #include "interface.upfront.cpp"
#include "gen/etoktype.cpp" #include "gen/etoktype.hpp"
#endif #endif
StrBuilder tok_to_strbuilder(Token tok) StrBuilder tok_to_strbuilder(Token tok)
@@ -564,9 +564,12 @@ void lex_found_token( LexContext* ctx )
array_append( _ctx->Lexer_Tokens, ctx->token ); array_append( _ctx->Lexer_Tokens, ctx->token );
} }
// TODO(Ed): We should dynamically allocate the lexer's array in Allocator_DyanmicContainers.
// TODO(Ed): We need to to attempt to recover from a lex failure? // TODO(Ed): We need to to attempt to recover from a lex failure?
neverinline neverinline
// TokArray lex( Array<Token> tokens, Str content ) // void lex( Array<Token> tokens, Str content )
TokArray lex( Str content ) TokArray lex( Str content )
{ {
LexContext c; LexContext* ctx = & c; LexContext c; LexContext* ctx = & c;

View File

@@ -1,6 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "gen/etoktype.cpp" #include "gen/etoktype.hpp"
#include "parser_case_macros.cpp" #include "parser_case_macros.cpp"
#include "interface.upfront.cpp" #include "interface.upfront.cpp"
#include "lexer.cpp" #include "lexer.cpp"
@@ -11,7 +11,7 @@
constexpr bool lex_dont_skip_formatting = false; constexpr bool lex_dont_skip_formatting = false;
constexpr bool lex_skip_formatting = true; constexpr bool lex_skip_formatting = true;
void parser_push( ParseContext* ctx, StackNode* node ) void parser_push( ParseContext* ctx, ParseStackNode* node )
{ {
node->Prev = ctx->Scope; node->Prev = ctx->Scope;
ctx->Scope = node; ctx->Scope = node;
@@ -60,7 +60,7 @@ StrBuilder parser_to_strbuilder(ParseContext ctx)
else else
strbuilder_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column ); strbuilder_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column );
StackNode* curr_scope = ctx.Scope; ParseStackNode* curr_scope = ctx.Scope;
s32 level = 0; s32 level = 0;
do do
{ {
@@ -181,16 +181,17 @@ bool _check_parse_args( Str def, char const* func_name )
# define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ ) # define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ )
# define check( Type_ ) ( left && currtok.Type == Type_ ) # define check( Type_ ) ( left && currtok.Type == Type_ )
# define push_scope() \ // TODO(Ed): Don't do this anymore, we need a better initializer.
Str null_name = {}; \ # define push_scope() \
StackNode scope = { nullptr, lex_current( & _ctx->parser.Tokens, lex_dont_skip_formatting ), null_name, txt( __func__ ) }; \ Str null_name = {}; \
ParseStackNode scope = { nullptr, {nullptr, 0}, lex_current( & _ctx->parser.Tokens, lex_dont_skip_formatting ), null_name, txt( __func__ ), { nullptr} }; \
parser_push( & _ctx->parser, & scope ) parser_push( & _ctx->parser, & scope )
#pragma endregion Helper Macros #pragma endregion Helper Macros
// Procedure Forwards ( Entire parser internal parser interface ) // Procedure Forwards ( Entire parser internal parser interface )
internal Code parse_array_decl (); internal Code parse_array_decl (ParseContext* ctx);
internal CodeAttributes parse_attributes (); internal CodeAttributes parse_attributes ();
internal CodeComment parse_comment (); internal CodeComment parse_comment ();
internal Code parse_complicated_definition ( TokType which ); internal Code parse_complicated_definition ( TokType which );
@@ -490,8 +491,15 @@ StrBuilder parser_strip_formatting( Str raw_text, bool preserve_newlines )
return content; return content;
} }
StrBuilder parser_strip_formatting_2(TokenSlice tokens)
{
// TODO(Ed): Use this to produce strings for validation purposes. We shouldn't serialize down from tokens once we start storing token slices for content.
StrBuilder result = struct_zero(StrBuilder);
return result;
}
internal internal
Code parse_array_decl() Code parse_array_decl(ParseContext* ctx)
{ {
push_scope(); push_scope();
@@ -524,16 +532,20 @@ Code parse_array_decl()
return InvalidCode; return InvalidCode;
} }
TokenSlice tokens = { & currtok, 1 };
Token untyped_tok = currtok; Token untyped_tok = currtok;
while ( left && currtok.Type != Tok_BraceSquare_Close ) while ( left && currtok.Type != Tok_BraceSquare_Close )
{ {
eat( currtok.Type ); eat( currtok.Type );
++ tokens.Num;
} }
untyped_tok.Text.Len = ( (sptr)prevtok.Text.Ptr + prevtok.Text.Len ) - (sptr)untyped_tok.Text.Ptr; // untyped_tok.Text.Len = ( (sptr)prevtok.Text.Ptr + prevtok.Text.Len ) - (sptr)untyped_tok.Text.Ptr;
untyped_tok.Text = token_range_to_str(untyped_tok, prevtok);
Code array_expr = untyped_str( untyped_tok.Text ); Code array_expr = untyped_str( untyped_tok.Text );
// Code array_expr = untyped_toks( tokens ); // TODO(Ed): Use token slice instead of untyped strings.
// [ <Content> // [ <Content>
if ( left == 0 ) if ( left == 0 )
@@ -556,7 +568,7 @@ Code parse_array_decl()
// Its a multi-dimensional array // Its a multi-dimensional array
if ( check( Tok_BraceSquare_Open )) if ( check( Tok_BraceSquare_Open ))
{ {
Code adjacent_arr_expr = parse_array_decl(); Code adjacent_arr_expr = parse_array_decl(ctx);
// [ <Content> ][ <Content> ]... // [ <Content> ][ <Content> ]...
array_expr->Next = adjacent_arr_expr; array_expr->Next = adjacent_arr_expr;
@@ -1443,6 +1455,22 @@ CodeFn parse_function_after_name(
} }
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> // <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>
// Check for trailing specifiers...
CodeAttributes post_rt_attributes = parse_attributes();
if (post_rt_attributes)
{
if (attributes)
{
StrBuilder merged = strbuilder_fmt_buf(_ctx->Allocator_Temp, "%S %S", attributes->Content, post_rt_attributes->Content);
attributes->Content = cache_str(strbuilder_to_str(merged));
}
else
{
attributes = post_rt_attributes;
}
}
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> <Attributes>
CodeBody body = NullCode; CodeBody body = NullCode;
CodeComment inline_cmt = NullCode; CodeComment inline_cmt = NullCode;
if ( check( Tok_BraceCurly_Open ) ) if ( check( Tok_BraceCurly_Open ) )
@@ -1481,17 +1509,19 @@ CodeFn parse_function_after_name(
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
inline_cmt = parse_comment(); inline_cmt = parse_comment();
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>; <InlineCmt> // <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> < = 0 or delete > ; <InlineCmt>
} }
else
if (body == nullptr)
{ {
Token stmt_end = currtok; Token stmt_end = currtok;
eat( Tok_Statement_End ); eat( Tok_Statement_End );
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>; // <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> <Attributes> < = 0 or delete > ;
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
inline_cmt = parse_comment(); inline_cmt = parse_comment();
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>; <InlineCmt> // <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> < = 0 or delete > ; <InlineCmt>
} }
StrBuilder StrBuilder
@@ -1766,7 +1796,7 @@ CodeBody parse_global_nspace( CodeType which )
case Tok_Preprocess_Macro_Expr: case Tok_Preprocess_Macro_Expr:
{ {
if (tok_is_attribute(currtok)) if ( ! tok_is_attribute(currtok))
{ {
log_failure("Unbounded macro expression residing in class/struct body\n%S", parser_to_strbuilder(_ctx->parser)); log_failure("Unbounded macro expression residing in class/struct body\n%S", parser_to_strbuilder(_ctx->parser));
return InvalidCode; return InvalidCode;
@@ -2049,11 +2079,20 @@ Token parse_identifier( bool* possible_member_function )
Macro* macro = lookup_macro(currtok.Text); Macro* macro = lookup_macro(currtok.Text);
b32 accept_as_identifier = macro && bitfield_is_set(MacroFlags, macro->Flags, MF_Allow_As_Identifier ); b32 accept_as_identifier = macro && bitfield_is_set(MacroFlags, macro->Flags, MF_Allow_As_Identifier );
b32 is_decarator = macro && bitfield_is_set(MacroFlags, macro->Flags, MF_Identifier_Decorator );
// Typename can be: '::' <name> // Typename can be: '::' <name>
// If that is the case first option will be Tok_Access_StaticSymbol below // If that is the case first option will be Tok_Access_StaticSymbol below
if (check(Tok_Identifier) || accept_as_identifier) if (check(Tok_Identifier) || accept_as_identifier)
eat( Tok_Identifier ); {
if (is_decarator) {
Code name_macro = parse_simple_preprocess(currtok.Type);
name.Text.Len = ( ( sptr )prevtok.Text.Ptr + prevtok.Text.Len ) - ( sptr )name.Text.Ptr;
}
else {
eat(Tok_Identifier);
}
}
// <Name> // <Name>
parse_template_args( & name ); parse_template_args( & name );
@@ -2363,7 +2402,10 @@ CodeOperator parse_operator_after_ret_type(
case '(': case '(':
{ {
if ( currtok.Text.Ptr[1] == ')' ) if ( currtok.Text.Ptr[1] == ')' )
{
op = Op_FunctionCall; op = Op_FunctionCall;
eat(Tok_Paren_Open);
}
else else
op = Op_Invalid; op = Op_Invalid;
@@ -3260,7 +3302,7 @@ CodeVar parse_variable_after_name(
{ {
push_scope(); push_scope();
Code array_expr = parse_array_decl(); Code array_expr = parse_array_decl(& _ctx->parser);
Code expr = NullCode; Code expr = NullCode;
Code bitfield_expr = NullCode; Code bitfield_expr = NullCode;
@@ -4714,21 +4756,37 @@ CodeTypename parser_parse_type( bool from_template, bool* typedef_is_function )
else if ( currtok.Type == Tok_Decl_Class || currtok.Type == Tok_Decl_Enum || currtok.Type == Tok_Decl_Struct else if ( currtok.Type == Tok_Decl_Class || currtok.Type == Tok_Decl_Enum || currtok.Type == Tok_Decl_Struct
|| currtok.Type == Tok_Decl_Union ) || currtok.Type == Tok_Decl_Union )
{ {
switch (currtok.Type) { Token next = nexttok;
case Tok_Decl_Class : tag = Tag_Class; break;
case Tok_Decl_Enum : tag = Tag_Enum; break; if (next.Type == Tok_Identifier)
case Tok_Decl_Struct : tag = Tag_Struct; break; {
case Tok_Decl_Union : tag = Tag_Union; break; switch (currtok.Type) {
default: case Tok_Decl_Class : tag = Tag_Class; break;
break; case Tok_Decl_Enum : tag = Tag_Enum; break;
case Tok_Decl_Struct : tag = Tag_Struct; break;
case Tok_Decl_Union : tag = Tag_Union; break;
default:
break;
}
eat( currtok.Type );
// <Attributes> <Specifiers> <class, enum, struct, union>
name = parse_identifier(nullptr);
// <Attributes> <Specifiers> <class, enum, struct, union> <Name>
} }
eat( currtok.Type ); else if (next.Type == Tok_BraceCurly_Open)
// <Attributes> <Specifiers> <class, enum, struct, union> {
name = currtok;
// We have an inplace definition, we need to consume that...
name = parse_identifier(nullptr); // TODO(Ed): we need to add a way for AST_CodeTypename to track an implace definition..
b32 const inplace = true;
Code indplace_def = cast(Code, parser_parse_struct(inplace));
// name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text; // For now we lose the structural information,
// eat( Tok_Identifier ); name.Text.Len = ( ( sptr )prevtok.Text.Ptr + prevtok.Text.Len ) - ( sptr )name.Text.Ptr;
// <Attributes> <Specifiers> <class, enum, struct, union> <inplace def>
}
_ctx->parser.Scope->Name = name.Text; _ctx->parser.Scope->Name = name.Text;
// <Attributes> <Specifiers> <class, enum, struct, union> <Name> // <Attributes> <Specifiers> <class, enum, struct, union> <Name>
} }
@@ -5298,7 +5356,7 @@ CodeTypedef parser_parse_typedef()
return InvalidCode; return InvalidCode;
} }
array_expr = parse_array_decl(); array_expr = parse_array_decl(& _ctx->parser);
// <UnderlyingType> + <ArrayExpr> // <UnderlyingType> + <ArrayExpr>
} }
@@ -5544,7 +5602,7 @@ CodeUsing parser_parse_using()
type = parser_parse_type(parser_not_from_template, nullptr); type = parser_parse_type(parser_not_from_template, nullptr);
// <ModuleFlags> using <Name> <Attributes> = <UnderlyingType> // <ModuleFlags> using <Name> <Attributes> = <UnderlyingType>
array_expr = parse_array_decl(); array_expr = parse_array_decl(& _ctx->parser);
// <UnderlyingType> + <ArrExpr> // <UnderlyingType> + <ArrExpr>
} }
} }

View File

@@ -1,7 +1,7 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "types.hpp" #include "types.hpp"
#include "gen/ecode.hpp" #include "gen/ecodetypes.hpp"
#include "gen/eoperator.hpp" #include "gen/eoperator.hpp"
#include "gen/especifier.hpp" #include "gen/especifier.hpp"
#include "gen/etoktype.hpp" #include "gen/etoktype.hpp"
@@ -91,6 +91,27 @@ bool tok_is_end_definition(Token tok) {
StrBuilder tok_to_strbuilder(Token tok); StrBuilder tok_to_strbuilder(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 struct TokArray
{ {
Array(Token) Arr; Array(Token) Arr;
@@ -104,23 +125,21 @@ struct LexContext
char const* scanner; char const* scanner;
s32 line; s32 line;
s32 column; s32 column;
// StringTable defines;
Token token; Token token;
}; };
struct StackNode struct LexedInfo
{ {
StackNode* Prev; Str text;
TokenSlice tokens;
Token* Start;
Str Name; // The name of the AST node (if parsed)
Str ProcName; // The name of the procedure
}; };
typedef struct ParseStackNode ParseStackNode;
struct ParseContext struct ParseContext
{ {
TokArray Tokens; TokArray Tokens;
StackNode* Scope; ParseStackNode* Scope;
}; };
enum MacroType : u16 enum MacroType : u16
@@ -168,26 +187,36 @@ Str macrotype_to_str( MacroType type )
enum EMacroFlags : u16 enum EMacroFlags : u16
{ {
MF_Functional = bit(0), // Macro has parameters (args expected to be passed) // Macro has parameters (args expected to be passed)
MF_Expects_Body = bit(1), // Expects to assign a braced scope to its body. 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. // 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. // This is a kludge because we don't support push/pop macro pragmas rn.
MF_Allow_As_Identifier = bit(2), 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. // 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) // 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. // 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 // 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 // & 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(3), MF_Allow_As_Attribute = bit(4),
// When a macro is encountered after attributes and specifiers while parsing a function, or variable: // 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. (Yes this is for Unreal Engine) // It will consume the macro and treat it as resolving the definition.
// (MUST BE OF MT_Statement TYPE) // (MUST BE OF MT_Statement TYPE)
MF_Allow_As_Definition = bit(4), MF_Allow_As_Definition = bit(5),
MF_Allow_As_Specifier = bit(5), // Created for Unreal's PURE_VIRTUAL // Created for Unreal's PURE_VIRTUAL
MF_Allow_As_Specifier = bit(6),
MF_Null = 0, MF_Null = 0,
MF_UnderlyingType = GEN_U16_MAX, MF_UnderlyingType = GEN_U16_MAX,

View File

@@ -1,6 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "../gen.hpp" #include "interface.hpp"
#endif #endif
#pragma region StaticData #pragma region StaticData

View File

@@ -1,6 +1,18 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
#pragma once #pragma once
#include "header_start.hpp" #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 #endif
/* /*
@@ -19,16 +31,6 @@
*/ */
using LogFailType = ssize(*)(char const*, ...);
// By default this library will either crash or exit if an error is detected while generating codes.
// Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur.
#ifdef GEN_DONT_USE_FATAL
#define log_failure log_fmt
#else
#define log_failure GEN_FATAL
#endif
enum AccessSpec : u32 enum AccessSpec : u32
{ {
AccessSpec_Default, AccessSpec_Default,

View File

@@ -1,9 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
# pragma once # pragma once
# include "dependencies/platform.hpp"
# include "dependencies/macros.hpp"
# include "basic_types.hpp" # include "basic_types.hpp"
# include "macros.hpp"
#endif #endif
#pragma region Debug #pragma region Debug

View File

@@ -187,7 +187,7 @@ struct FileContents
{ {
AllocatorInfo allocator; AllocatorInfo allocator;
void* data; void* data;
ssize size; ssize size;
}; };
constexpr b32 file_zero_terminate = true; constexpr b32 file_zero_terminate = true;

View File

@@ -198,21 +198,16 @@
#ifndef forceinline #ifndef forceinline
# if GEN_COMPILER_MSVC # if GEN_COMPILER_MSVC
# define forceinline __forceinline # define forceinline __forceinline
# define neverinline __declspec( noinline )
# elif GEN_COMPILER_GCC # elif GEN_COMPILER_GCC
# define forceinline inline __attribute__((__always_inline__)) # define forceinline inline __attribute__((__always_inline__))
# define neverinline __attribute__( ( __noinline__ ) )
# elif GEN_COMPILER_CLANG # elif GEN_COMPILER_CLANG
# if __has_attribute(__always_inline__) # if __has_attribute(__always_inline__)
# define forceinline inline __attribute__((__always_inline__)) # define forceinline inline __attribute__((__always_inline__))
# define neverinline __attribute__( ( __noinline__ ) )
# else # else
# define forceinline # define forceinline
# define neverinline
# endif # endif
# else # else
# define forceinline # define forceinline
# define neverinline
# endif # endif
#endif #endif
@@ -303,10 +298,20 @@
# define GEN_PARAM_DEFAULT # define GEN_PARAM_DEFAULT
#endif #endif
#if GEN_COMPILER_CPP #ifndef struct_init
#define struct_init(type, value) {value} # if GEN_COMPILER_CPP
#else # define struct_init(type, value) value
#define struct_init(type, value) {value} # else
# define struct_init(type, value) (type) value
# endif
#endif
#ifndef struct_zero
# if GEN_COMPILER_CPP
# define struct_zero(type) {}
# else
# define struct_zero(type) {0}
# endif
#endif #endif
#if 0 #if 0
@@ -319,4 +324,12 @@
# define GEN_OPITMIZE_MAPPINGS_END # define GEN_OPITMIZE_MAPPINGS_END
#endif #endif
#ifndef get_optional
# if GEN_COMPILER_C
# define get_optional(opt) opt ? *opt : (typeof(*opt)){0}
# else
# define get_optional(opt) opt
# endif
#endif
#pragma endregion Macros #pragma endregion Macros

View File

@@ -134,12 +134,6 @@ GEN_API void* heap_allocator_proc( void* allocator_data, AllocType type, ssize s
//! The heap allocator backed by operating system's memory manager. //! The heap allocator backed by operating system's memory manager.
constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; } constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; }
//! Helper to allocate memory using heap allocator.
#define malloc( sz ) alloc( heap(), sz )
//! Helper to free memory allocated by heap allocator.
#define mfree( ptr ) free( heap(), ptr )
struct VirtualMemory struct VirtualMemory
{ {
void* data; void* data;
@@ -185,6 +179,8 @@ void arena_check (Arena* arena);
void arena_free (Arena* arena); void arena_free (Arena* arena);
ssize arena_size_remaining(Arena* arena, ssize alignment); ssize arena_size_remaining(Arena* arena, ssize alignment);
// TODO(Ed): Add arena_pos, arena_pop, and arena_pop_to
struct Arena struct Arena
{ {
AllocatorInfo Backing; AllocatorInfo Backing;

View File

@@ -1,6 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
# pragma once # pragma once
# include "strbuilder_ops.cpp" # include "string_ops.cpp"
#endif #endif
#pragma region Printing #pragma region Printing

View File

@@ -1,6 +1,6 @@
#ifdef INTELLISENSE_DIRECTIVES #ifdef INTELLISENSE_DIRECTIVES
# pragma once # pragma once
# include "strbuilder_ops.hpp" # include "string_ops.hpp"
#endif #endif
#pragma region Printing #pragma region Printing
@@ -26,17 +26,4 @@ GEN_API ssize c_str_fmt_file_va ( FileInfo* f, char const* fmt, va_list va );
constexpr constexpr
char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED"; char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED";
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;
}
#pragma endregion Printing #pragma endregion Printing

View File

@@ -320,7 +320,7 @@ inline
StrBuilder strbuilder_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) StrBuilder strbuilder_fmt_buf(AllocatorInfo allocator, char const* fmt, ...)
{ {
local_persist thread_local local_persist thread_local
PrintF_Buffer buf = struct_init(PrintF_Buffer, {0}); PrintF_Buffer buf = struct_zero(PrintF_Buffer);
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);

View File

@@ -11,9 +11,6 @@
#include "helpers/push_ignores.inline.hpp" #include "helpers/push_ignores.inline.hpp"
#include "components/header_start.hpp" #include "components/header_start.hpp"
// Has container defines pushed
#include "gen.dep.hpp"
GEN_NS_BEGIN GEN_NS_BEGIN
#include "components/types.hpp" #include "components/types.hpp"

View File

@@ -1159,6 +1159,8 @@ R"(#define <interface_name>( code ) _Generic( (code), \
Str actual_name = { fn->Name.Ptr + prefix.Len, fn->Name.Len - prefix.Len }; Str actual_name = { fn->Name.Ptr + prefix.Len, fn->Name.Len - prefix.Len };
Str new_name = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "def__%S", actual_name ).to_str(); Str new_name = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "def__%S", actual_name ).to_str();
opt_param->ValueType->Specs = def_specifier(Spec_Ptr);
// Resolve define's arguments // Resolve define's arguments
b32 has_args = fn->Params->NumEntries > 1; b32 has_args = fn->Params->NumEntries > 1;
StrBuilder params_str = StrBuilder::make_reserve(_ctx->Allocator_Temp, 32); StrBuilder params_str = StrBuilder::make_reserve(_ctx->Allocator_Temp, 32);
@@ -1172,10 +1174,10 @@ R"(#define <interface_name>( code ) _Generic( (code), \
} }
char const* tmpl_fn_macro = nullptr; char const* tmpl_fn_macro = nullptr;
if (params_str.length() > 0 ) { if (params_str.length() > 0 ) {
tmpl_fn_macro= "#define <def_name>( <params> ... ) <def__name>( <params> (<opts_type>) { __VA_ARGS__ } )\n"; tmpl_fn_macro= "#define <def_name>( <params> ... ) <def__name>( <params> & (<opts_type>) { __VA_ARGS__ } )\n";
} }
else { else {
tmpl_fn_macro= "#define <def_name>( ... ) <def__name>( (<opts_type>) { __VA_ARGS__ } )\n"; tmpl_fn_macro= "#define <def_name>( ... ) <def__name>( & (<opts_type>) { __VA_ARGS__ } )\n";
} }
Code fn_macro = untyped_str(token_fmt( Code fn_macro = untyped_str(token_fmt(
"def_name", fn->Name "def_name", fn->Name
@@ -1504,6 +1506,7 @@ R"(#define <interface_name>( code ) _Generic( (code), \
Str actual_name = { fn->Name.Ptr + prefix.Len, fn->Name.Len - prefix.Len }; Str actual_name = { fn->Name.Ptr + prefix.Len, fn->Name.Len - prefix.Len };
Str new_name = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "def__%S", actual_name ).to_str(); Str new_name = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "def__%S", actual_name ).to_str();
fn->Name = cache_str(new_name); fn->Name = cache_str(new_name);
opt_param->ValueType->Specs = def_specifier(Spec_Ptr);
} }
src_upfront.append(fn); src_upfront.append(fn);
} }

View File

@@ -53,6 +53,7 @@ word enum_underlying, gen_enum_underlying
word nullptr, gen_nullptr word nullptr, gen_nullptr
word struct_init, gen_struct_init word struct_init, gen_struct_init
word hash, gen_hash word hash, gen_hash
word txt, gen_txt
// Basic Types // Basic Types
@@ -410,6 +411,8 @@ namespace var_, gen_var_
word _ctx, gen__ctx word _ctx, gen__ctx
word get_context, gen_get_context
word init, gen_init word init, gen_init
word deinit, gen_deinit word deinit, gen_deinit
word reset, gen_reset word reset, gen_reset
@@ -532,7 +535,7 @@ namespace Lexer_, gen_Lexer_
word LexContext, gen_LexContext word LexContext, gen_LexContext
word lex, gen_lex word lex, gen_lex
word StackNode, gen_StackNode word ParseStackNode, gen_ParseStackNode
word ParseContext, gen_ParseContext word ParseContext, gen_ParseContext
// namespace parse_, gen_parse_ // namespace parse_, gen_parse_

View File

@@ -404,7 +404,7 @@ if ( $vendor -match "msvc" )
$flag_optimize_intrinsics = '/Oi' $flag_optimize_intrinsics = '/Oi'
$flag_optimized_debug_forceinline = '/d2Obforceinline' $flag_optimized_debug_forceinline = '/d2Obforceinline'
$flag_optimized_debug = '/Zo' $flag_optimized_debug = '/Zo'
$flag_ # $flag_
# $flag_out_name = '/OUT:' # $flag_out_name = '/OUT:'
$flag_path_interm = '/Fo' $flag_path_interm = '/Fo'
$flag_path_debug = '/Fd' $flag_path_debug = '/Fd'