progress
This commit is contained in:
1 parent
b754adcd96
commit
1a60fd54fc
11 files changed
+355
-125
No files matched your search
@@ -15,6 +15,13 @@
|
||||
\▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
struct ParseInfo
|
||||
{
|
||||
ParseMessage* messages;
|
||||
LexedInfo lexed;
|
||||
Code result;
|
||||
};
|
||||
|
||||
// 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.
|
||||
@@ -80,6 +87,7 @@ struct Context
|
||||
|
||||
// TODO(Ed): Active parse context vs a parse result need to be separated conceptually
|
||||
ParseContext parser;
|
||||
ParseInfo parse_info;
|
||||
|
||||
// TODO(Ed): Formatting - This will eventually be in a separate struct when in the process of serialization of the builder.
|
||||
s32 temp_serialize_indent;
|
||||
@@ -363,13 +371,6 @@ struct ParseStackNode
|
||||
// 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;
|
||||
@@ -388,7 +389,15 @@ 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 );
|
||||
|
||||
struct Opts_parse_global_body
|
||||
{
|
||||
Context* ctx;
|
||||
ParseInfo* info;
|
||||
};
|
||||
GEN_API void parse_global_body_base( Context* ctx, Str body_def, ParseInfo* info );
|
||||
GEN_API CodeBody parse_global_body( Str body_def, Opts_parse_global_body opts GEN_PARAM_DEFAULT );
|
||||
|
||||
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 );
|
||||
|
||||
@@ -55,7 +55,7 @@ CodeClass parse_class( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -86,7 +86,7 @@ CodeConstructor parse_constructor(Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -163,7 +163,7 @@ CodeDefine parse_define( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -194,7 +194,7 @@ CodeDestructor parse_destructor( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -223,7 +223,7 @@ CodeEnum parse_enum( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -249,7 +249,7 @@ CodeBody parse_export_body( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -275,7 +275,7 @@ CodeExtern parse_extern_link( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -301,7 +301,7 @@ CodeFriend parse_friend( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -327,7 +327,7 @@ CodeFn parse_function( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -340,35 +340,55 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeBody parse_global_body( Str def )
|
||||
void parse_global_body_base( Context* ctx, Str def, ParseInfo* info )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
CodeBody result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
LexedInfo lexed;
|
||||
CodeBody body;
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
if ( ctx == nullptr || info == nullptr )
|
||||
GEN_FATAL( "parse_global_body_base: null context or info" );
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
parser_record_failure(ctx, txt("parse: lex produced no tokens"));
|
||||
goto done;
|
||||
info[0] = struct_zero( ParseInfo );
|
||||
lexed = struct_zero( LexedInfo );
|
||||
body = (CodeBody) make_code();
|
||||
body->Type = CT_Global_Body;
|
||||
|
||||
ctx->parser = struct_zero( ParseContext );
|
||||
if ( check_parse_args( def ) == false ) {
|
||||
info->result = cast( Code, body );
|
||||
info->messages = ctx->parser.messages;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
result = parse_global_nspace(ctx, CT_Global_Body );
|
||||
parser_pop(& ctx->parser);
|
||||
lexed = lex( ctx, def );
|
||||
info->lexed = lexed;
|
||||
if ( lexed.tokens.num == 0 ) {
|
||||
info->result = cast( Code, body );
|
||||
info->messages = ctx->parser.messages;
|
||||
return;
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
|
||||
ctx->parser.tokens = lexed.tokens; {
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push( & ctx->parser, & scope );
|
||||
body = parse_global_nspace( ctx, CT_Global_Body );
|
||||
parser_pop( & ctx->parser );
|
||||
}
|
||||
info->result = cast( Code, body );
|
||||
info->messages = ctx->parser.messages;
|
||||
}
|
||||
|
||||
CodeBody parse_global_body( Str def, Opts_parse_global_body opts ) {
|
||||
Opts_parse_global_body resolved = get_optional( opts );
|
||||
Context* ctx = resolved.ctx;
|
||||
ParseInfo* info;
|
||||
|
||||
if ( ctx == nullptr ) ctx = _ctx;
|
||||
if ( ctx == nullptr ) GEN_FATAL( "parse_global_body: no context" );
|
||||
info = resolved.info; if ( info == nullptr ) info = & ctx->parse_info;
|
||||
|
||||
parse_global_body_base( ctx, def, info );
|
||||
return cast( CodeBody, info->result );
|
||||
}
|
||||
|
||||
CodeNS parse_namespace( Str def )
|
||||
@@ -384,7 +404,7 @@ CodeNS parse_namespace( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -410,7 +430,7 @@ CodeOperator parse_operator( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -436,7 +456,7 @@ CodeOpCast parse_operator_cast( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -462,7 +482,7 @@ CodeStruct parse_struct( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -493,7 +513,7 @@ CodeTemplate parse_template( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -519,7 +539,7 @@ CodeTypename parse_type( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -545,7 +565,7 @@ CodeTypedef parse_typedef( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -571,7 +591,7 @@ CodeUnion parse_union( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -597,7 +617,7 @@ CodeUsing parse_using( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
@@ -623,7 +643,7 @@ CodeVar parse_variable( Str def )
|
||||
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if (ctx->parser.tokens.ptr == nullptr) {
|
||||
if (lexed.messages != nullptr || ctx->parser.tokens.num == 0) {
|
||||
if (lexed.messages != nullptr && lexed.messages->content.Ptr != nullptr)
|
||||
parser_record_failure(ctx, lexed.messages->content);
|
||||
else
|
||||
|
||||
@@ -694,7 +694,7 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
case Lex_ReturnNull:
|
||||
{
|
||||
info.messages = c.messages;
|
||||
return info;
|
||||
goto Lex_Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,7 +725,7 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", (* ctx->scanner), c.line, c.column, context_str );
|
||||
info.messages = c.messages;
|
||||
return info;
|
||||
goto Lex_Done;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1282,7 +1282,7 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
StrBuilder context_str = strbuilder_fmt_buf( lib_ctx->Allocator_Temp, "%.*s", min( 100, c.left ), c.scanner );
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "Failed to lex token '%c' (%d, %d)\n%s", (* ctx->scanner), c.line, c.column, context_str );
|
||||
info.messages = c.messages;
|
||||
return info;
|
||||
goto Lex_Done;
|
||||
}
|
||||
|
||||
FoundToken:
|
||||
@@ -1318,8 +1318,8 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
|
||||
info.messages = c.messages;
|
||||
info.text = content;
|
||||
info.tokens = struct_init(TokenSlice) { pcast(Token*, c.tokens), scast(s32, array_num(c.tokens)) };
|
||||
Lex_Done:
|
||||
info.tokens = struct_init(TokenSlice) { pcast(Token*, c.tokens), scast(s32, array_num(c.tokens)) };
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -1715,9 +1715,9 @@ CodeBody parse_global_nspace(Context* ctx, CodeType which)
|
||||
{
|
||||
case Tok_Comma:
|
||||
{
|
||||
log_failure("Dangling comma found: %SB\nContext:\n%SB", tok_to_strbuilder(ctx->Allocator_Temp, currtok), parser_to_strbuilder(& ctx->parser, ctx->Allocator_Temp));
|
||||
parser_record_failure(ctx, txt("Dangling comma"));
|
||||
parser_pop( & ctx->parser);
|
||||
return InvalidCode;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case Tok_Statement_End:
|
||||
|
||||
+3
-3
@@ -15,6 +15,9 @@ You can think of this parser as *frontend parser* vs a *semantic parser*. Its in
|
||||
User exposed interface:
|
||||
|
||||
```cpp
|
||||
CodeBody parse_global_body ( Str body_def, Opts_parse_global_body opts );
|
||||
void parse_global_body_base( Context* ctx, Str body_def, ParseInfo* info );
|
||||
|
||||
CodeClass parse_class ( Str class_def );
|
||||
CodeConstructor parse_constructor ( Str constructor_def );
|
||||
CodeDefine parse_define ( Str define_def );
|
||||
@@ -24,7 +27,6 @@ CodeBody parse_export_body ( Str export_def );
|
||||
CodeExtern parse_extern_link ( Str exten_link_def );
|
||||
CodeFriend parse_friend ( Str friend_def );
|
||||
CodeFn parse_function ( Str fn_def );
|
||||
CodeBody parse_global_body ( Str body_def );
|
||||
CodeNS parse_namespace ( Str namespace_def );
|
||||
CodeOperator parse_operator ( Str operator_def );
|
||||
CodeOpCast parse_operator_cast( Str operator_def );
|
||||
@@ -155,5 +157,3 @@ typedef HashTable(Macro) MacroTable;
|
||||
* typedefs have attributes with the type (`parse_type`)
|
||||
* Parsing attributes can be extended to support user defined macros by defining `GEN_DEFINE_ATTRIBUTE_TOKENS` (see `gen.hpp` for the formatting)
|
||||
* This is useful for example: parsing Unreal `Module_API` macros.
|
||||
|
||||
**The lexer & parser do not gracefully attempt to continue when it comes across incorrect code, and doesn't properly track errors into a listing (yet).**
|
||||
@@ -739,10 +739,10 @@ do \
|
||||
{
|
||||
// pop the array entry
|
||||
array_token->NumEntries -= 1;
|
||||
Code next = array_entry->Next;
|
||||
Code prev = array_entry->Prev;
|
||||
next->Prev = array_entry->Prev;
|
||||
prev->Next = next;
|
||||
Code next = array_entry->Next;
|
||||
Code prev = array_entry->Prev;
|
||||
next->Prev = array_entry->Prev;
|
||||
prev->Next = next;
|
||||
if ( array_token->Front == array_entry )
|
||||
array_token->Front = next;
|
||||
|
||||
@@ -1142,6 +1142,27 @@ R"(#define <interface_name>( code ) _Generic( (code), \
|
||||
for ( CodeParams opt_param : fn->Params ) if (opt_param->ValueType->Name.starts_with(txt("Opts_")))
|
||||
{
|
||||
// Convert the definition to use a default struct: https://vxtwitter.com/vkrajacic/status/1749816169736073295
|
||||
if ( fn->Name.is_equal( txt("parse_global_body") ) )
|
||||
{
|
||||
Str new_name = txt("parse_global_body_opts");
|
||||
char const* tmpl_fn_macro = "#define <def_name>( <params> ... ) <def__name>( <params> & (<opts_type>) { __VA_ARGS__ } )\n";
|
||||
Code fn_macro;
|
||||
|
||||
opt_param->ValueType->Specs = def_specifier( Spec_Ptr );
|
||||
fn_macro = untyped_str( token_fmt(
|
||||
"def_name", fn->Name
|
||||
, "def__name", new_name
|
||||
, "params", txt("def, ")
|
||||
, "opts_type", opt_param->ValueType->Name
|
||||
, tmpl_fn_macro
|
||||
));
|
||||
fn->Name = cache_str( new_name );
|
||||
interface.append( fn );
|
||||
interface.append( fn_macro );
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Str prefix = txt("def_");
|
||||
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();
|
||||
@@ -1409,6 +1430,29 @@ R"(#define <interface_name>( code ) _Generic( (code), \
|
||||
Code src_code_serialization = scan_file( path_base "components/code_serialization.cpp" );
|
||||
|
||||
Code src_parsing_interface = scan_file( path_base "components/interface.parsing.cpp" );
|
||||
{
|
||||
Str needle = txt("CodeBody parse_global_body( Str def, Opts_parse_global_body opts )");
|
||||
Str scanned = src_parsing_interface->Content;
|
||||
ssize signature_at = -1;
|
||||
ssize scan_offset;
|
||||
ssize last_offset = scanned.Len - needle.Len;
|
||||
for ( scan_offset = 0; scan_offset <= last_offset; ++ scan_offset )
|
||||
{
|
||||
if ( c_str_compare_len( scanned.Ptr + scan_offset, needle.Ptr, needle.Len ) == 0 ) {
|
||||
signature_at = scan_offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( signature_at < 0 ) GEN_FATAL( "c_library: parse_global_body signature missing from scanned interface.parsing.cpp" );
|
||||
/*Resolved replacement*/ {
|
||||
Str replacement = txt("CodeBody parse_global_body_opts( Str def, Opts_parse_global_body* opts )");
|
||||
StrBuilder rebuilt = strbuilder_make_reserve( _ctx->Allocator_Temp, scanned.Len + replacement.Len );
|
||||
strbuilder_append_str( & rebuilt, Str { scanned.Ptr, signature_at } );
|
||||
strbuilder_append_str( & rebuilt, replacement );
|
||||
strbuilder_append_str( & rebuilt, Str { scanned.Ptr + signature_at + needle.Len, scanned.Len - signature_at - needle.Len } );
|
||||
src_parsing_interface = untyped_str( strbuilder_to_str( rebuilt ) );
|
||||
}
|
||||
}
|
||||
Code src_untyped = scan_file( path_base "components/interface.untyped.cpp" );
|
||||
Code src_parser_case_macros = scan_file( path_base "components/parser_case_macros.cpp" );
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ args:
|
||||
test
|
||||
parser_bounds
|
||||
lexer_failures
|
||||
parse_body_messages
|
||||
clang
|
||||
msvc : By default this project builds with clang, specifying msvc will build with MSVC.
|
||||
debug
|
||||
|
||||
+64
-37
@@ -65,19 +65,20 @@ if ($null -eq $is_linux) {
|
||||
Push-Location $path_root
|
||||
|
||||
#region Arguments
|
||||
$vendor = $null
|
||||
$release = $null
|
||||
[bool] $verbose = $false
|
||||
[bool] $base = $false
|
||||
[bool] $segmented = $false
|
||||
[bool] $singleheader = $false
|
||||
[bool] $c_lib = $false
|
||||
[bool] $c_lib_static = $false
|
||||
[bool] $c_lib_dyn = $false
|
||||
[bool] $unreal = $false
|
||||
[bool] $test = $false
|
||||
[bool] $parser_bounds = $false
|
||||
[bool] $lexer_failures = $false
|
||||
$vendor = $null
|
||||
$release = $null
|
||||
[bool] $verbose = $false
|
||||
[bool] $base = $false
|
||||
[bool] $segmented = $false
|
||||
[bool] $singleheader = $false
|
||||
[bool] $c_lib = $false
|
||||
[bool] $c_lib_static = $false
|
||||
[bool] $c_lib_dyn = $false
|
||||
[bool] $unreal = $false
|
||||
[bool] $test = $false
|
||||
[bool] $parser_bounds = $false
|
||||
[bool] $lexer_failures = $false
|
||||
[bool] $parse_body_messages = $false
|
||||
|
||||
[array] $vendors = @( "clang", "msvc" )
|
||||
|
||||
@@ -85,20 +86,21 @@ Push-Location $path_root
|
||||
|
||||
if ( $args ) { $args | ForEach-Object {
|
||||
switch ($_){
|
||||
{ $_ -in $vendors } { $vendor = $_; break }
|
||||
"verbose" { $verbose = $true }
|
||||
"release" { $release = $true }
|
||||
"debug" { $release = $false }
|
||||
"base" { $base = $true }
|
||||
"segmented" { $segmented = $true }
|
||||
"singleheader" { $singleheader = $true }
|
||||
"c_lib" { $c_lib = $true }
|
||||
"c_lib_static" { $c_lib_static = $true }
|
||||
"c_lib_dyn" { $c_lib_dyn = $true }
|
||||
"unreal" { $unreal = $true }
|
||||
"test" { $test = $true }
|
||||
"parser_bounds" { $parser_bounds = $true }
|
||||
"lexer_failures" { $lexer_failures = $true }
|
||||
{ $_ -in $vendors } { $vendor = $_; break }
|
||||
"verbose" { $verbose = $true }
|
||||
"release" { $release = $true }
|
||||
"debug" { $release = $false }
|
||||
"base" { $base = $true }
|
||||
"segmented" { $segmented = $true }
|
||||
"singleheader" { $singleheader = $true }
|
||||
"c_lib" { $c_lib = $true }
|
||||
"c_lib_static" { $c_lib_static = $true }
|
||||
"c_lib_dyn" { $c_lib_dyn = $true }
|
||||
"unreal" { $unreal = $true }
|
||||
"test" { $test = $true }
|
||||
"parser_bounds" { $parser_bounds = $true }
|
||||
"lexer_failures" { $lexer_failures = $true }
|
||||
"parse_body_messages" { $parse_body_messages = $true }
|
||||
}
|
||||
}}
|
||||
#endregion Arguments
|
||||
@@ -127,16 +129,17 @@ else {
|
||||
$optimize = $true
|
||||
}
|
||||
|
||||
$cannot_build = $base -eq $false
|
||||
$cannot_build = $cannot_build -and $segmented -eq $false
|
||||
$cannot_build = $cannot_build -and $singleheader -eq $false
|
||||
$cannot_build = $cannot_build -and $c_lib -eq $false
|
||||
$cannot_build = $cannot_build -and $c_lib_static -eq $false
|
||||
$cannot_build = $cannot_build -and $c_lib_dyn -eq $false
|
||||
$cannot_build = $cannot_build -and $unreal -eq $false
|
||||
$cannot_build = $cannot_build -and $test -eq $false
|
||||
$cannot_build = $cannot_build -and $parser_bounds -eq $false
|
||||
$cannot_build = $cannot_build -and $lexer_failures -eq $false
|
||||
$cannot_build = $base -eq $false
|
||||
$cannot_build = $cannot_build -and $segmented -eq $false
|
||||
$cannot_build = $cannot_build -and $singleheader -eq $false
|
||||
$cannot_build = $cannot_build -and $c_lib -eq $false
|
||||
$cannot_build = $cannot_build -and $c_lib_static -eq $false
|
||||
$cannot_build = $cannot_build -and $c_lib_dyn -eq $false
|
||||
$cannot_build = $cannot_build -and $unreal -eq $false
|
||||
$cannot_build = $cannot_build -and $test -eq $false
|
||||
$cannot_build = $cannot_build -and $parser_bounds -eq $false
|
||||
$cannot_build = $cannot_build -and $lexer_failures -eq $false
|
||||
$cannot_build = $cannot_build -and $parse_body_messages -eq $false
|
||||
if ( $cannot_build ) {
|
||||
Stop-stage "No build target specified"
|
||||
}
|
||||
@@ -495,6 +498,30 @@ if ($lexer_failures)
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
invoke-stageTool -stage "lexer_failures" -compiled $result -executable $executable -path_work $path_probe
|
||||
}
|
||||
|
||||
if ($parse_body_messages)
|
||||
{
|
||||
$path_probe = join-path $path_test parse_body_messages
|
||||
$path_build = join-path $path_probe build
|
||||
if ( -not(Test-Path($path_build) )) {
|
||||
new-item -ItemType Directory -Path $path_build | Out-Null
|
||||
}
|
||||
|
||||
$includes = @( $path_base )
|
||||
$unit = join-path $path_probe "test.cpp"
|
||||
$executable = join-path $path_build "parse_body_messages.exe"
|
||||
|
||||
$compiler_args = @()
|
||||
$compiler_args += ( $flag_define + 'GEN_TIME' )
|
||||
$compiler_args += $flag_cpp17
|
||||
|
||||
$linker_args = @(
|
||||
$flag_link_win_subsystem_console
|
||||
)
|
||||
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
invoke-stageTool -stage "parse_body_messages" -compiled $result -executable $executable -path_work $path_probe
|
||||
}
|
||||
#endregion Building
|
||||
|
||||
pop-location # $path_root
|
||||
|
||||
+26
-22
@@ -1,28 +1,29 @@
|
||||
$misc = Join-Path $PSScriptRoot 'helpers/misc.psm1'
|
||||
Import-Module $misc
|
||||
|
||||
$path_root = Get-ScriptRepoRoot
|
||||
$path_base = Join-Path $path_root base
|
||||
$path_base_build = Join-Path $path_base build
|
||||
$path_c_library = Join-Path $path_root gen_c_library
|
||||
$path_c_library_build = Join-Path $path_c_library build
|
||||
$path_c_library_gen = Join-Path $path_c_library gen
|
||||
$path_segmented = Join-Path $path_root gen_segmented
|
||||
$path_segmented_build = Join-Path $path_segmented build
|
||||
$path_segmented_gen = Join-Path $path_segmented gen
|
||||
$path_singleheader = Join-Path $path_root gen_singleheader
|
||||
$path_singleheader_build = Join-Path $path_singleheader build
|
||||
$path_singleheader_gen = Join-Path $path_singleheader gen
|
||||
$path_unreal = Join-Path $path_root gen_unreal_engine
|
||||
$path_unreal_build = Join-Path $path_unreal build
|
||||
$path_unreal_gen = Join-Path $path_unreal gen
|
||||
$path_test = Join-Path $path_root test
|
||||
$path_test_build = Join-Path $path_test build
|
||||
$path_test_gen = Join-Path $path_test gen
|
||||
$path_parser_bounds_build = Join-Path $path_test "parser_bounds\build"
|
||||
$path_lexer_failures_build = Join-Path $path_test "lexer_failures\build"
|
||||
$path_x64 = Join-Path $path_root x64
|
||||
$path_release = Join-Path $path_root release
|
||||
$path_root = Get-ScriptRepoRoot
|
||||
$path_base = Join-Path $path_root base
|
||||
$path_base_build = Join-Path $path_base build
|
||||
$path_c_library = Join-Path $path_root gen_c_library
|
||||
$path_c_library_build = Join-Path $path_c_library build
|
||||
$path_c_library_gen = Join-Path $path_c_library gen
|
||||
$path_segmented = Join-Path $path_root gen_segmented
|
||||
$path_segmented_build = Join-Path $path_segmented build
|
||||
$path_segmented_gen = Join-Path $path_segmented gen
|
||||
$path_singleheader = Join-Path $path_root gen_singleheader
|
||||
$path_singleheader_build = Join-Path $path_singleheader build
|
||||
$path_singleheader_gen = Join-Path $path_singleheader gen
|
||||
$path_unreal = Join-Path $path_root gen_unreal_engine
|
||||
$path_unreal_build = Join-Path $path_unreal build
|
||||
$path_unreal_gen = Join-Path $path_unreal gen
|
||||
$path_test = Join-Path $path_root test
|
||||
$path_test_build = Join-Path $path_test build
|
||||
$path_test_gen = Join-Path $path_test gen
|
||||
$path_parser_bounds_build = Join-Path $path_test "parser_bounds\build"
|
||||
$path_lexer_failures_build = Join-Path $path_test "lexer_failures\build"
|
||||
$path_parse_body_messages_build = Join-Path $path_test "parse_body_messages\build"
|
||||
$path_x64 = Join-Path $path_root x64
|
||||
$path_release = Join-Path $path_root release
|
||||
|
||||
if ( Test-Path $path_base_build) {
|
||||
Remove-Item $path_base_build -Recurse -Verbose
|
||||
@@ -66,6 +67,9 @@ if ( Test-Path $path_parser_bounds_build ) {
|
||||
if ( Test-Path $path_lexer_failures_build ) {
|
||||
Remove-Item $path_lexer_failures_build -Recurse -Verbose
|
||||
}
|
||||
if ( Test-Path $path_parse_body_messages_build ) {
|
||||
Remove-Item $path_parse_body_messages_build -Recurse -Verbose
|
||||
}
|
||||
if ( Test-Path $path_x64) {
|
||||
Remove-Item $path_x64 -Recurse -Verbose
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ internal void expect(int condition, Str label) {
|
||||
if (condition == false) { log_fmt("FAIL %S\n", label); ++g_failures; }
|
||||
}
|
||||
|
||||
internal void expect_public(Str def, Str needle, Str label)
|
||||
{
|
||||
internal void expect_public(Str def, Str needle, Str label) {
|
||||
Context ctx = {}; init(&ctx);
|
||||
CodeVar parsed = parse_variable(def); expect(cast(Code, parsed) == Code_Invalid, label);
|
||||
expect(_ctx->parser.messages != nullptr, label);
|
||||
@@ -31,7 +30,7 @@ internal void expect_public(Str def, Str needle, Str label)
|
||||
internal void expect_lex_fail(Str def, Str needle, Str label) {
|
||||
Context ctx = {}; init(&ctx);
|
||||
LexedInfo lexed = lex(&ctx, def);
|
||||
expect(lexed.tokens.ptr == nullptr, label);
|
||||
expect(lexed.tokens.ptr != nullptr, label);
|
||||
expect(lexed.messages != nullptr, label);
|
||||
if (lexed.messages != nullptr) expect(str_contains(lexed.messages->content, needle), label);
|
||||
deinit(&ctx);
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
#define GEN_TIME
|
||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
#define GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
#include "gen.cpp"
|
||||
|
||||
using namespace gen;
|
||||
|
||||
global int g_failures = 0;
|
||||
|
||||
internal void expect(int condition, Str label) {
|
||||
if (condition == false) { log_fmt("FAIL %S\n", label); ++g_failures; }
|
||||
}
|
||||
|
||||
internal Str body_text(CodeBody body) {
|
||||
return strbuilder_to_str(code_to_strbuilder(cast(Code, body)));
|
||||
}
|
||||
|
||||
internal void expect_good_base(Context* ctx, Str label) {
|
||||
ParseInfo info = {};
|
||||
Str def = txt("struct Context { int a; int b; };");
|
||||
parse_global_body_base(ctx, def, &info);
|
||||
CodeBody body = cast(CodeBody, info.result);
|
||||
Str text = body_text(body);
|
||||
expect(body.ast != nullptr, label);
|
||||
expect(str_contains(text, txt("Context")), label);
|
||||
expect(str_contains(text, txt("a")), label);
|
||||
expect(str_contains(text, txt("b")), label);
|
||||
expect(info.messages == nullptr, label);
|
||||
expect(info.lexed.messages == nullptr, label);
|
||||
expect(info.lexed.tokens.ptr != nullptr, label);
|
||||
expect(info.lexed.tokens.num > 0, label);
|
||||
}
|
||||
|
||||
internal void expect_at(Str label) {
|
||||
Context ctx = {};
|
||||
ParseInfo info = {};
|
||||
Str def = txt("struct Context { int a; int b; };\n@");
|
||||
init(&ctx);
|
||||
parse_global_body_base(&ctx, def, &info);
|
||||
CodeBody body = cast(CodeBody, info.result);
|
||||
Str text = body_text(body);
|
||||
expect(body.ast != nullptr, label);
|
||||
expect(str_contains(text, txt("Context")), label);
|
||||
expect(info.lexed.messages != nullptr, label);
|
||||
if (info.lexed.messages != nullptr)
|
||||
expect(str_contains(info.lexed.messages->content, txt("Failed to lex token")), label);
|
||||
expect(info.lexed.tokens.ptr != nullptr, label);
|
||||
expect(info.lexed.tokens.num > 0, label);
|
||||
expect_good_base(&ctx, txt("at-reuse"));
|
||||
deinit(&ctx);
|
||||
}
|
||||
|
||||
internal void expect_comma(Str label) {
|
||||
Context ctx = {};
|
||||
ParseInfo info = {};
|
||||
Str def = txt("struct Context { int a; int b; };\n,");
|
||||
init(&ctx);
|
||||
parse_global_body_base(&ctx, def, &info);
|
||||
CodeBody body = cast(CodeBody, info.result);
|
||||
Str text = body_text(body);
|
||||
expect(str_contains(text, txt("Context")), label);
|
||||
expect(info.messages != nullptr, label);
|
||||
if (info.messages != nullptr)
|
||||
expect(str_contains(info.messages->Content, txt("Dangling comma")), label);
|
||||
expect_good_base(&ctx, txt("comma-reuse"));
|
||||
deinit(&ctx);
|
||||
}
|
||||
|
||||
internal void expect_space(Str label) {
|
||||
Context ctx = {};
|
||||
ParseInfo info = {};
|
||||
init(&ctx);
|
||||
parse_global_body_base(&ctx, txt(" \t\n"), &info);
|
||||
CodeBody body = cast(CodeBody, info.result);
|
||||
expect(body.ast != nullptr, label);
|
||||
expect(body->Type == CT_Global_Body, label);
|
||||
expect(info.lexed.tokens.num == 0, label);
|
||||
expect(info.lexed.messages != nullptr, label);
|
||||
if (info.lexed.messages != nullptr)
|
||||
expect(str_contains(info.lexed.messages->content, txt("no tokens found")), label);
|
||||
expect_good_base(&ctx, txt("space-reuse"));
|
||||
deinit(&ctx);
|
||||
}
|
||||
|
||||
internal void expect_empty(Str label) {
|
||||
Context ctx = {};
|
||||
ParseInfo info = {};
|
||||
Str def = { nullptr, 0 };
|
||||
init(&ctx);
|
||||
parse_global_body_base(&ctx, def, &info);
|
||||
CodeBody body = cast(CodeBody, info.result);
|
||||
expect(body.ast != nullptr, label);
|
||||
expect(info.messages != nullptr, label);
|
||||
if (info.messages != nullptr)
|
||||
expect(str_contains(info.messages->Content, txt("length must greater than 0")), label);
|
||||
expect_good_base(&ctx, txt("empty-reuse"));
|
||||
deinit(&ctx);
|
||||
}
|
||||
|
||||
internal void expect_wrapper(Str label) {
|
||||
Context ctx = {};
|
||||
CodeBody body;
|
||||
Str text;
|
||||
init(&ctx);
|
||||
body = parse_global_body(txt("struct Context { int a; int b; };"));
|
||||
text = body_text(body);
|
||||
expect(str_contains(text, txt("Context")), label);
|
||||
expect(ctx.parse_info.messages == nullptr, label);
|
||||
expect(str_contains(body_text(cast(CodeBody, ctx.parse_info.result)), txt("Context")), label);
|
||||
deinit(&ctx);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Context ctx = {}; init(& ctx);
|
||||
expect_good_base(&ctx, txt("good"));
|
||||
deinit(& ctx);
|
||||
expect_at(txt("at"));
|
||||
expect_comma(txt("comma"));
|
||||
expect_space(txt("space"));
|
||||
expect_empty(txt("empty"));
|
||||
expect_wrapper(txt("wrapper"));
|
||||
if (g_failures != 0) { log_fmt("parse body messages failed: %d\n", g_failures); return 1; }
|
||||
log_fmt("parse body messages passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user