Base case for extern link parse working.

This commit is contained in:
Edward R. Gonzalez 2023-07-08 23:29:18 -04:00
parent 41f0e49cb0
commit 472189a322
4 changed files with 645 additions and 171 deletions

View File

@ -27,31 +27,31 @@ namespace gen
}
#pragma region Constants
Code type_ns(auto);
Code type_ns(void);
Code type_ns(int);
Code type_ns(bool);
Code type_ns(char);
Code type_ns(wchar_t);
Code t_auto;
Code t_void;
Code t_int;
Code t_bool;
Code t_char;
Code t_wchar_t;
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
Code type_ns(b32);
Code t_b32;
Code type_ns(s8);
Code type_ns(s16);
Code type_ns(s32);
Code type_ns(s64);
Code t_s8;
Code t_s16;
Code t_s32;
Code t_s64;
Code type_ns(u8);
Code type_ns(u16);
Code type_ns(u32);
Code type_ns(u64);
Code t_u8;
Code t_u16;
Code t_u32;
Code t_u64;
Code type_ns(sw);
Code type_ns(uw);
Code t_sw;
Code t_uw;
Code type_ns(f32);
Code type_ns(f64);
Code t_f32;
Code t_f64;
#endif
Code access_public;
@ -68,6 +68,7 @@ namespace gen
Code spec_constexpr;
Code spec_constinit;
Code spec_extern_linkage;
Code spec_global;
Code spec_inline;
Code spec_internal_linkage;
Code spec_local_persist;
@ -79,10 +80,6 @@ namespace gen
Code spec_static_member;
Code spec_thread_local;
Code spec_volatile;
Code spec_type_signed;
Code spec_type_unsigned;
Code spec_type_short;
Code spec_type_long;
#pragma endregion Constants
#pragma region AST Body Case Macros
@ -1004,8 +1001,8 @@ namespace gen
Code::Invalid.set_global();
# define def_constant_code_type( Type_ ) \
type_ns(Type_) = def_type( name(Type_) ); \
type_ns(Type_).set_global();
t_##Type_ = def_type( name(Type_) ); \
t_##Type_.set_global();
def_constant_code_type( auto );
def_constant_code_type( void );
@ -1015,7 +1012,7 @@ namespace gen
def_constant_code_type( wchar_t );
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
type_ns(b32) = def_type( name(b32) );
t_b32 = def_type( name(b32) );
def_constant_code_type( s8 );
def_constant_code_type( s16 );
@ -1068,17 +1065,26 @@ namespace gen
pragma_once->Content = pragma_once->Name;
pragma_once.set_global();
# pragma push_macro( "global" )
# pragma push_macro( "internal" )
# pragma push_macro( "local_persist" )
# define global global
# define internal internal
# define local_persist local_persist
# define def_constant_spec( Type_, ... ) \
spec_##Type_ = def_specifiers( macro_num_args(__VA_ARGS__), __VA_ARGS__); \
spec_##Type_.set_global();
def_constant_spec( const, ESpecifier::Const );
def_constant_spec( consteval, ESpecifier::Consteval );
def_constant_spec( constexpr, ESpecifier::Constexpr );
def_constant_spec( constinit, ESpecifier::Constinit );
def_constant_spec( extern_linkage, ESpecifier::External_Linkage );
def_constant_spec( const, ESpecifier::Const );
def_constant_spec( global, ESpecifier::Global );
def_constant_spec( inline, ESpecifier::Inline );
def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage );
def_constant_spec( local_persist, ESpecifier::Local_Persist );
def_constant_spec( mutable, ESpecifier::Mutable );
def_constant_spec( ptr, ESpecifier::Ptr );
def_constant_spec( ref, ESpecifier::Ref );
@ -1091,6 +1097,10 @@ namespace gen
spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist );
spec_local_persist.set_global();
# pragma pop_macro( "global" )
# pragma pop_macro( "internal" )
# pragma pop_macro( "local_persist" )
# undef def_constant_spec
}
@ -1415,7 +1425,7 @@ namespace gen
switch ( params_code->param_count() )
{
case 1:
if ( params_code->param_type()->is_equal( type_ns(int) ) )
if ( params_code->param_type()->is_equal( t_int ) )
is_member_symbol = true;
else
@ -1425,7 +1435,7 @@ namespace gen
case 2:
check_param_eq_ret();
if ( ! params_code->get_param(1)->is_equal( type_ns(int) ) )
if ( ! params_code->get_param(1)->is_equal( t_int ) )
{
log_failure("gen::def_operator: "
"operator%s requires second parameter of non-member definition to be int for post-decrement",
@ -1545,7 +1555,7 @@ namespace gen
}
}
if ( ! ret_type->is_equal( type_ns(bool) ))
if ( ! ret_type->is_equal( t_bool ))
{
log_failure("gen::def_operator: operator%s return type must be of type bool - %s"
, to_str(op)
@ -2008,7 +2018,7 @@ namespace gen
}
else
{
result->add_entry( type_ns(void) );
result->add_entry( t_void );
}
if ( params )
@ -3069,7 +3079,9 @@ namespace gen
Entry( Spec_Constexpr, "constexpr" ) \
Entry( Spec_Constinit, "constinit" ) \
Entry( Spec_Extern, "extern" ) \
Entry( Spec_Global, "global" ) \
Entry( Spec_Inline, "inline" ) \
Entry( Spec_Internal_Linkage, "internal" ) \
Entry( Spec_LocalPersist, "local_persist" ) \
Entry( Spec_Mutable, "mutable" ) \
Entry( Spec_Static, "static" ) \
@ -3674,6 +3686,7 @@ namespace gen
Code parse_exten_link ( Parser::TokArray& toks, char const* context );
Code parse_friend ( Parser::TokArray& toks, char const* context );
Code parse_function ( Parser::TokArray& toks, char const* context );
Code parse_namespace ( Parser::TokArray& toks, char const* context );
Code parse_struct ( Parser::TokArray& toks, char const* context );
Code parse_variable ( Parser::TokArray& toks, char const* context );
Code parse_type ( Parser::TokArray& toks, char const* context );
@ -3943,6 +3956,7 @@ namespace gen
while ( left && currtok.Type != TokType::BraceCurly_Close )
{
Code member = Code::Invalid;
Code specifiers = Code::Invalid;
switch ( currtok.Type )
{
@ -4002,8 +4016,6 @@ namespace gen
case TokType::Spec_ThreadLocal:
case TokType::Spec_Volatile:
{
Code specifiers = Code::Invalid;
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
@ -4045,33 +4057,35 @@ namespace gen
case TokType::Type_Short:
case TokType::Type_Long:
{
Code specifiers = Code::Invalid;
Code type = parse_type( toks, context );
if ( type == Code::Invalid )
{
log_failure( "gen::parse_variable: failed to parse type" );
return Code::Invalid;
}
Token name = currtok;
if ( check( TokType::Identifier ) )
{
name = currtok;
}
eat( TokType::Identifier );
// Parsing a member function
if ( check( TokType::Capture_Start ))
{
Code params = parse_params( toks, context );
if ( params == Code::Invalid )
{
log_failure( "gen::parse_variable: failed to parse function parameters" );
return Code::Invalid;
}
if ( check( TokType::BraceCurly_Open ) )
{
Code body = parse_function_body( toks, context);
if ( body == Code::Invalid )
{
log_failure( "gen::parse_variable: failed to parse function body" );
return Code::Invalid;
}
Code
member = make_code();
member->Name = get_cached_string( name );
@ -4128,7 +4142,10 @@ namespace gen
}
if ( member == Code::Invalid )
{
log_failure( "gen::parse_variable: failed to parse member" );
return Code::Invalid;
}
result->add_entry( member );
}
@ -4176,7 +4193,6 @@ namespace gen
case TokType::Decl_Typedef:
member = parse_typedef( toks, context );
break;
case TokType::Decl_Union:
@ -4375,22 +4391,248 @@ namespace gen
return Code::Invalid;
}
Code parse_export_body( StrC def )
Code parse_extern_link_body( Parser::TokArray& toks, char const* context )
{
not_implemented();
using namespace Parser;
using namespace ECode;
eat( TokType::BraceCurly_Open );
Code
result = make_code();
result->Type = Extern_Linkage_Body;
while ( left && currtok.Type != TokType::BraceCurly_Close )
{
Code member = Code::Invalid;
Code specifiers = Code::Invalid;
switch ( currtok.Type )
{
case TokType::Comment:
def_comment( currtok );
eat( TokType::Comment );
break;
case TokType::Decl_Enum:
member = parse_enum( toks, context);
break;
case TokType::Decl_Class:
member = parse_class( toks, context );
break;
case TokType::Decl_Extern_Linkage:
log_failure( "gen::parse_extern_link_body: nested extern linkage" );
return Code::Invalid;
case TokType::Decl_Namespace:
member = parse_namespace( toks, context );
break;
case TokType::Decl_Struct:
member = parse_struct( toks, context );
break;
case TokType::Decl_Typedef:
member = parse_typedef( toks, context );
break;
case TokType::Decl_Union:
member = parse_union( toks, context );
break;
case TokType::Decl_Using:
member = parse_using( toks, context );
break;
// TODO: Module support.
// case TokType::Module_Export:
// case TokType::Module_Import:
case TokType::Spec_Extern:
case TokType::Spec_Global:
case TokType::Spec_Inline:
case TokType::Spec_Internal_Linkage:
case TokType::Spec_Static:
{
SpecifierT specs_found[16] { ESpecifier::Invalid };
s32 num_specs = 0;
while ( left && tok_is_specifier( currtok ) )
{
SpecifierT spec = ESpecifier::to_type( currtok );
switch ( spec )
{
case ESpecifier::Const:
case ESpecifier::External_Linkage:
case ESpecifier::Global:
case ESpecifier::Inline:
case ESpecifier::Internal_Linkage:
break;
default:
log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for extern linkage scope" );
return Code::Invalid;
}
specs_found[num_specs] = spec;
num_specs++;
eat( currtok.Type );
}
if ( num_specs )
{
specifiers = def_specifiers( num_specs, specs_found );
}
}
case TokType::Identifier:
case TokType::Spec_Const:
case TokType::Type_Long:
case TokType::Type_Short:
case TokType::Type_Signed:
case TokType::Type_Unsigned:
{
Code type = parse_type( toks, context );
if ( type == Code::Invalid )
{
log_failure( "gen::parse_extern_link_body: failed to parse type" );
return Code::Invalid;
}
Token name = currtok;
eat( TokType::Identifier );
// Parsing a function
if ( check( TokType::Capture_Start ))
{
Code params = parse_params( toks, context );
if ( params == Code::Invalid )
{
log_failure( "gen::parse_extern_link_body: failed to parse function params" );
return Code::Invalid;
}
if ( check( TokType::BraceCurly_Open ))
{
Code body = parse_function_body( toks, context );
if ( body == Code::Invalid )
{
log_failure( "gen::parse_extern_link_body: failed to parse function body" );
return Code::Invalid;
}
member = make_code();
member->Name = get_cached_string( name );
if ( body )
{
switch ( body->Type )
{
case Function_Body:
case Untyped:
break;
default:
{
log_failure( "gen::parse_extern_link_body: invalid function body" );
return Code::Invalid;
}
}
member->Type = Function;
member->add_entry( body );
}
else
{
member->Type = Function_Fwd;
}
member->add_entry( type );
if ( params )
member->add_entry( params );
break;
}
}
// Parsing a variable
Code array_expr = parse_array_decl( toks, context );
Code expr = parse_variable_assignment( toks, context );
member = make_code();
member->Type = Variable;
member->Name = get_cached_string( name );
member->add_entry( type );
if ( array_expr )
type->add_entry( array_expr );
if ( specifiers )
member->add_entry( specifiers );
if ( expr )
member->add_entry( expr );
}
if ( member == Code::Invalid )
{
log_failure( "gen::parse_extern_link_body: failed to parse extern linkage member" );
return Code::Invalid;
}
result->add_entry( member );
}
eat( currtok.Type );
}
eat( TokType::BraceCurly_Close );
return result;
}
Code parse_extern_link( Parser::TokArray& toks, char const* context )
{
not_implemented();
return Code::Invalid;
using namespace Parser;
eat( TokType::Decl_Extern_Linkage );
Token name = currtok;
eat( TokType::String );
name.Text += 1;
name.Length -= 1;
Code
result = make_code();
result->Type = ECode::Extern_Linkage;
result->Name = get_cached_string( name );
Code entry = parse_extern_link_body( toks, context );
if ( entry == Code::Invalid )
{
log_failure( "gen::parse_extern_link: failed to parse body" );
return result;
}
result->add_entry( entry );
return result;
}
Code parse_extern_link( StrC def )
{
not_implemented();
check_parse_args( parse_extern_link, def );
using namespace Parser;
TokArray toks = lex( def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_extern_link( toks, txt(parse_extern_link) );
}
Code parse_friend( Parser::TokArray& toks, char const* context )

View File

@ -214,9 +214,10 @@ namespace gen
Entry( Constexpr, constexpr ) \
Entry( Constinit, constinit ) \
Entry( External_Linkage, extern ) \
Entry( Global, global ) \
Entry( Inline, inline ) \
Entry( Internal_Linkage, static ) \
Entry( Local_Persist, static ) \
Entry( Internal_Linkage, internal ) \
Entry( Local_Persist, local_persist ) \
Entry( Mutable, mutable ) \
Entry( Ptr, * ) \
Entry( Ref, & ) \
@ -241,9 +242,20 @@ namespace gen
{
local_persist
StrC lookup[ Num_Specifiers ] = {
# pragma push_macro( "global" )
# pragma push_macro( "internal" )
# pragma push_macro( "local_persist" )
# define global global
# define internal internal
# define local_persist local_persist
# define Entry( Spec_, Code_ ) { txt_n_len(Code_) },
Define_Specifiers
# undef Entry
# pragma pop_macro( "global" )
# pragma pop_macro( "internal" )
# pragma pop_macro( "local_persist" )
};
return lookup[ specifier ];
@ -818,8 +830,7 @@ namespace gen
# ifdef GEN_FEATURE_PARSING
Code parse_class ( StrC class_def );
Code parse_enum ( StrC enum_def );
Code parse_export_body( StrC export_def );
Code parse_exten_link ( StrC exten_link_def);
Code parse_extern_link ( StrC exten_link_def);
Code parse_friend ( StrC friend_def );
Code parse_function ( StrC fn_def );
Code parse_global_body ( StrC body_def );
@ -983,9 +994,6 @@ namespace gen
# define __ NoCode
// This represents the naming convention for all typename Codes generated.
# define type_ns( Name_ ) t_##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.
# define name( Id_ ) { txt_n_len( Id_ ) }
@ -1000,23 +1008,23 @@ namespace gen
{
// Predefined typename codes. Are set to readonly and are setup during gen::init()
extern Code type_ns( b32 );
extern Code t_b32;
extern Code type_ns( s8 );
extern Code type_ns( s16 );
extern Code type_ns( s32 );
extern Code type_ns( s64 );
extern Code t_s8;
extern Code t_s16;
extern Code t_s32;
extern Code t_s64;
extern Code type_ns( u8 );
extern Code type_ns( u16 );
extern Code type_ns( u32 );
extern Code type_ns( u64 );
extern Code t_u8;
extern Code t_u16;
extern Code t_u32;
extern Code t_u64;
extern Code type_ns( sw );
extern Code type_ns( uw );
extern Code t_sw;
extern Code t_uw;
extern Code type_ns( f32 );
extern Code type_ns( f64 );
extern Code t_f32;
extern Code t_f64;
}
#endif
@ -1042,12 +1050,12 @@ namespace gen
// Predefined Codes. Are set to readonly and are setup during gen::init()
extern Code type_ns( auto );
extern Code type_ns( void );
extern Code type_ns( int );
extern Code type_ns( bool );
extern Code type_ns( char );
extern Code type_ns( wchar_t );
extern Code t_auto;
extern Code t_void;
extern Code t_int;
extern Code t_bool;
extern Code t_char;
extern Code t_wchar_t;
extern Code access_public;
extern Code access_protected;
@ -1063,6 +1071,7 @@ namespace gen
extern Code spec_constexpr;
extern Code spec_constinit;
extern Code spec_extern_linkage;
extern Code spec_global;
extern Code spec_inline;
extern Code spec_internal_linkage;
extern Code spec_local_persist;
@ -1074,10 +1083,6 @@ namespace gen
extern Code spec_static_member;
extern Code spec_thread_local;
extern Code spec_volatile;
extern Code spec_type_signed;
extern Code spec_type_unsigned;
extern Code spec_type_short;
extern Code spec_type_long;
}
#pragma endregion Constants

View File

@ -7,7 +7,7 @@ u32 gen_sanity()
{
Builder
gen_sanity_file;
gen_sanity_file.open("./sanity.gen.hpp");
gen_sanity_file.open("./sanity.NonParsed.gen.hpp");
// Comment
{
@ -159,7 +159,6 @@ u32 gen_sanity()
{
// Going to make a bit flag set of overloads for this.
Code bitflagtest;
{
Code body = def_enum_body( 1, untyped_str( code(
@ -185,7 +184,6 @@ u32 gen_sanity()
}
gen_sanity_file.print(bitflagtest);
gen_sanity_file.print_fmt("\n");
gen_sanity_file.print(op_fwd);
gen_sanity_file.print(op_or);
}
@ -207,7 +205,10 @@ u32 gen_sanity()
, def_comment( StrC::from("Empty function body") )
);
Code params = def_params( 2 * 3, t_u8, 1, "a", t_u8, 1, "b" );
Code params = def_params( 2
, def_param( t_u8, name(a) )
, def_param( t_u8, name(b) )
);
def = def_function( name(test_function_wparams), params, __, body );
@ -231,10 +232,13 @@ u32 gen_sanity()
{
Code fwd_fn = def_function( name(test_function_specifiers), __, __, __, spec_inline );
// Need an op overload here
// TODO: Need an op overload here
Code t_ct_u8 = def_type( name(u8), __, spec_constexpr );
Code typedef_ConstExprTest = def_typedef( name(ConstExprTest), t_ct_u8 );
Code u8_ptr = def_type( name(u8), __, spec_ptr );
Code typedef_u8_ptr = def_typedef( name(ConstExprTest), u8_ptr );
gen_sanity_file.print(fwd_fn);
gen_sanity_file.print(typedef_u8_ptr);
}
gen_sanity_file.print_fmt("\n");
@ -244,7 +248,7 @@ u32 gen_sanity()
Code fwd = def_class( name(TestEmptyStruct) );
Code empty_body;
{
Code cmt = def_comment( StrC::from("Empty class body") );
Code cmt = def_comment( StrC::from("Empty struct body") );
Code body = def_class_body( 1, cmt );
empty_body = def_class( name(TestEmptyStruct), body );

View File

@ -4,11 +4,11 @@
using namespace gen;
void gen_sanity()
u32 gen_sanity()
{
Builder
gen_sanity_file;
gen_sanity_file.open("./sanity.gen.hpp");
gen_sanity_file.open("./sanity.Parsed.gen.hpp");
gen_sanity_file.print( def_comment( StrC::from(
"The following will show a series of base cases for the gen parsed api.\n"
@ -72,11 +72,234 @@ void gen_sanity()
// External Linkage
{
Code empty_comment = def_comment( StrC::from("Empty external linkage") );
Code c_extern = parse_extern_link( code(
extern "C"
{
};
));
c_extern.body()->add_entry( empty_comment );
gen_sanity_file.print(c_extern);
}
gen_sanity_file.print_fmt("\n");
// Friend
if (0)
{
Code fwd = parse_class( code(
class TestFriendClass;
));
Code def = parse_class( code(
class TestFriend
{
friend class TestFriendClass;
};
));
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Function
if (0)
{
Code fwd = parse_function( code(
void test_function();
));
Code def = parse_function( code(
void test_function()
{
}
));
def.body()->add_entry( def_comment( StrC::from("Empty function body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Namespace
if (0)
{
Code def = parse_namespace( code(
namespace TestNamespace
{
}
));
def.body()->add_entry( def_comment( StrC::from("Empty namespace body") ) );
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Operator
if (0)
{
Code bitflagtest = parse_class( code(
enum class EBitFlagTest : u8
{
A = 1 << 0,
B = 1 << 1,
C = 1 << 2
};
));
Code op_fwd = parse_operator( code(
EBitFlagTest operator | ( EBitFlagTest a, EBitFlagTest b );
));
Code op_or = parse_operator( code(
EBitFlagTest operator | ( EBitFlagTest a, EBitFlagTest b )
{
return EBitFlagTest( (u8)a | (u8)b );
}
));
gen_sanity_file.print(bitflagtest);
gen_sanity_file.print(op_fwd);
gen_sanity_file.print(op_or);
}
gen_sanity_file.print_fmt("\n");
// Parameters
if (0)
{
Code fwd = parse_function( code(
void test_function( int a );
));
Code def = parse_function( code(
void test_function( int a, int b )
{
}
));
def.body()->add_entry( def_comment( StrC::from("Empty function body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Specifiers
if (0)
{
Code fwd_fn = parse_function( code(
inline
void test_function_specifiers();
));
Code typedef_u8_ptr = parse_typedef( code(
typedef u8* u8_ptr;
));
gen_sanity_file.print(fwd_fn);
gen_sanity_file.print(typedef_u8_ptr);
}
gen_sanity_file.print_fmt("\n");
// Struct
if (0)
{
Code fwd = parse_struct( code(
struct TestEmptyStruct;
));
Code empty_body = parse_struct( code(
struct TestEmptyStruct
{};
));
empty_body.body()->add_entry( def_comment( StrC::from("Empty struct body") ) );
gen_sanity_file.print(fwd);
gen_sanity_file.print(empty_body);
}
gen_sanity_file.print_fmt("\n");
// Union
if (0)
{
Code empty = parse_union( code(
union TestEmptyUnion
{
};
));
empty.body()->add_entry( def_comment( StrC::from("Empty union body") ) );
Code def = parse_union( code(
union TestUnion
{
u8 a;
u16 b;
u32 c;
};
));
gen_sanity_file.print(empty);
gen_sanity_file.print(def);
}
gen_sanity_file.print_fmt("\n");
// Using
if (0)
{
Code reg = parse_using( code(
using TestUsing = u8;
));
Code nspace = parse_using( code(
namespace TestNamespace
{
};
using namespace TestUsing;
));
gen_sanity_file.print(reg);
gen_sanity_file.print(nspace);
}
gen_sanity_file.print_fmt("\n");
// Variable
if (0)
{
Code bss = parse_variable( code(
u8 test_variable;
));
Code data = parse_variable( code(
u8 test_variable = 0x12;
));
}
gen_sanity_file.print_fmt("\n");
gen_sanity_file.print( def_comment( StrC::from(
"End of base case tests\n"
)));
gen_sanity_file.write();
return 0;
}
#endif