WIP: Starting to improve failure/error handling (errors as values)
This commit is contained in:
1 parent
61d53362e8
commit
b754adcd96
16 files changed
+983
-292
No files matched your search
@@ -6,6 +6,8 @@
|
||||
#pragma region Constants
|
||||
// Predefined typename codes. Are set to readonly and are setup during gen::init()
|
||||
|
||||
GEN_API extern Token NullToken;
|
||||
|
||||
GEN_API extern Macro enum_underlying_macro;
|
||||
|
||||
GEN_API extern Code access_public;
|
||||
|
||||
@@ -12,12 +12,16 @@ ParseInfo wip_parse_str(LexedInfo lexed, ParseOpts* opts)
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
ParseInfo info = struct_zero(ParseInfo);
|
||||
|
||||
if (lexed.tokens.num == 0 && lexed.tokens.ptr == nullptr) {
|
||||
check_parse_args(lexed.text);
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(lexed.text) == false) {
|
||||
info.messages = ctx->parser.messages;
|
||||
goto done;
|
||||
}
|
||||
lexed = lex(ctx, lexed.text);
|
||||
}
|
||||
ParseInfo info = struct_zero(ParseInfo);
|
||||
info.lexed = lexed;
|
||||
|
||||
// TODO(Ed): ParseInfo should be set to the parser context.
|
||||
@@ -25,12 +29,16 @@ ParseInfo wip_parse_str(LexedInfo lexed, ParseOpts* opts)
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
|
||||
CodeBody result = parse_global_nspace(ctx,CT_Global_Body);
|
||||
(void)result;
|
||||
|
||||
parser_pop(& ctx->parser);
|
||||
}
|
||||
done:
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -38,20 +46,30 @@ CodeClass parse_class( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeClass result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeClass result = (CodeClass) parse_class_struct( ctx, Tok_Decl_Class, parser_not_inplace_def );
|
||||
result = (CodeClass) parse_class_struct( ctx, Tok_Decl_Class, parser_not_inplace_def );
|
||||
parser_pop(& ctx->parser);
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -59,16 +77,24 @@ CodeConstructor parse_constructor(Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeConstructor result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
|
||||
@@ -100,7 +126,7 @@ CodeConstructor parse_constructor(Str def )
|
||||
default :
|
||||
log_failure( "Invalid specifier %s for variable\n%S", spec_to_str( spec ), parser_to_strbuilder(& ctx->parser, ctx->Allocator_Temp) );
|
||||
parser_pop(& ctx->parser);
|
||||
return InvalidCode;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Every specifier after would be considered part of the type type signature
|
||||
@@ -117,8 +143,10 @@ CodeConstructor parse_constructor(Str def )
|
||||
// <specifiers> ...
|
||||
}
|
||||
|
||||
CodeConstructor result = parser_parse_constructor(ctx, specifiers);
|
||||
result = parser_parse_constructor(ctx, specifiers);
|
||||
parser_pop(& ctx->parser);
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -126,20 +154,30 @@ CodeDefine parse_define( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeDefine result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeDefine result = parser_parse_define(ctx);
|
||||
result = parser_parse_define(ctx);
|
||||
parser_pop(& ctx->parser);
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -147,20 +185,28 @@ CodeDestructor parse_destructor( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeDestructor result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO(Ed): Destructors can have prefix attributes
|
||||
// TODO(Ed): Destructors can have virtual
|
||||
|
||||
CodeDestructor result = parser_parse_destructor(ctx, NullCode);
|
||||
result = parser_parse_destructor(ctx, NullCode);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -168,106 +214,160 @@ CodeEnum parse_enum( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeEnum result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr ) {
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_enum(ctx, parser_not_inplace_def);
|
||||
result = parser_parse_enum(ctx, parser_not_inplace_def);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeBody parse_export_body( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeBody result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_export_body(ctx);
|
||||
result = parser_parse_export_body(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeExtern parse_extern_link( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeExtern result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_extern_link(ctx);
|
||||
result = parser_parse_extern_link(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeFriend parse_friend( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeFriend result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_friend(ctx);
|
||||
result = parser_parse_friend(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeFn parse_function( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeFn result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return (CodeFn) parser_parse_function(ctx);
|
||||
result = (CodeFn) parser_parse_function(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeBody parse_global_body( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeBody result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeBody result = parse_global_nspace(ctx, CT_Global_Body );
|
||||
result = parse_global_nspace(ctx, CT_Global_Body );
|
||||
parser_pop(& ctx->parser);
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -275,71 +375,108 @@ CodeNS parse_namespace( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeNS result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_namespace(ctx);
|
||||
result = parser_parse_namespace(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeOperator parse_operator( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeOperator result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return (CodeOperator) parser_parse_operator(ctx);
|
||||
result = (CodeOperator) parser_parse_operator(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeOpCast parse_operator_cast( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeOpCast result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_operator_cast(ctx, NullCode);
|
||||
result = parser_parse_operator_cast(ctx, NullCode);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeStruct parse_struct( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeStruct result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ParseStackNode scope = NullScope;
|
||||
parser_push(& ctx->parser, & scope);
|
||||
CodeStruct result = (CodeStruct) parse_class_struct( ctx, Tok_Decl_Struct, parser_not_inplace_def );
|
||||
result = (CodeStruct) parse_class_struct( ctx, Tok_Decl_Struct, parser_not_inplace_def );
|
||||
parser_pop(& ctx->parser);
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -347,102 +484,160 @@ CodeTemplate parse_template( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeTemplate result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_template(ctx);
|
||||
result = parser_parse_template(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeTypename parse_type( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeTypename result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_type( ctx, parser_not_from_template, nullptr);
|
||||
result = parser_parse_type( ctx, parser_not_from_template, nullptr);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeTypedef parse_typedef( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeTypedef result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_typedef(ctx);
|
||||
result = parser_parse_typedef(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeUnion parse_union( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeUnion result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_union(ctx, parser_not_inplace_def);
|
||||
result = parser_parse_union(ctx, parser_not_inplace_def);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeUsing parse_using( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeUsing result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
|
||||
return parser_parse_using(ctx);
|
||||
result = parser_parse_using(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeVar parse_variable( Str def )
|
||||
{
|
||||
// TODO(Ed): Lift this.
|
||||
Context* ctx = _ctx;
|
||||
|
||||
check_parse_args( def );
|
||||
CodeVar result = InvalidCode;
|
||||
LexedInfo lexed = struct_zero(LexedInfo);
|
||||
|
||||
ctx->parser = struct_zero(ParseContext);
|
||||
if (check_parse_args(def) == false)
|
||||
goto done;
|
||||
|
||||
LexedInfo lexed = lex(ctx, def);
|
||||
lexed = lex(ctx, def);
|
||||
ctx->parser.tokens = lexed.tokens;
|
||||
if ( ctx->parser.tokens.ptr == nullptr )
|
||||
return InvalidCode;
|
||||
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;
|
||||
}
|
||||
if (parser_slice_is_formatting_only(&ctx->parser)) {
|
||||
parser_record_failure(ctx, txt("parse_variable: only formatting tokens"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
return parser_parse_variable(ctx);
|
||||
result = parser_parse_variable(ctx);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
// Undef helper macros
|
||||
|
||||
+103
-70
@@ -4,11 +4,9 @@
|
||||
#include "gen/etoktype.hpp"
|
||||
#endif
|
||||
|
||||
StrBuilder tok_to_strbuilder(AllocatorInfo ainfo, Token tok)
|
||||
{
|
||||
StrBuilder tok_to_strbuilder(AllocatorInfo ainfo, Token tok) {
|
||||
StrBuilder result = strbuilder_make_reserve( ainfo, kilobytes(4) );
|
||||
Str type_str = toktype_to_str( tok.Type );
|
||||
|
||||
strbuilder_append_fmt( & result, "Line: %d Column: %d, Type: %.*s Content: %.*s"
|
||||
, tok.Line, tok.Column
|
||||
, type_str.Len, type_str.Ptr
|
||||
@@ -19,57 +17,68 @@ StrBuilder tok_to_strbuilder(AllocatorInfo ainfo, Token tok)
|
||||
|
||||
bool lex__eat(Context* ctx, ParseContext* self, TokType type );
|
||||
|
||||
Token* lex_current(ParseContext* self, bool skip_formatting )
|
||||
{
|
||||
if ( skip_formatting )
|
||||
{
|
||||
while ( self->tokens.ptr[self->token_id].Type == Tok_NewLine || self->tokens.ptr[self->token_id].Type == Tok_Comment )
|
||||
self->token_id++;
|
||||
}
|
||||
return & self->tokens.ptr[self->token_id];
|
||||
forceinline
|
||||
b32 lex_index_in_range(ParseContext const* self, s32 idx) {
|
||||
return self->tokens.ptr != nullptr
|
||||
&& idx >= 0
|
||||
&& idx < self->tokens.num;
|
||||
}
|
||||
|
||||
Token* lex_peek(ParseContext const* self, bool skip_formatting)
|
||||
{
|
||||
s32 idx = self->token_id;
|
||||
if ( skip_formatting )
|
||||
{
|
||||
while ( self->tokens.ptr[idx].Type == Tok_NewLine )
|
||||
idx++;
|
||||
forceinline
|
||||
Token* lex_token_at(ParseContext const* self, s32 idx) {
|
||||
Token* result = & NullToken;
|
||||
if (lex_index_in_range(self, idx)) result = & self->tokens.ptr[idx];
|
||||
return result;
|
||||
}
|
||||
|
||||
return & self->tokens.ptr[idx];
|
||||
Token* lex_current(ParseContext* self, bool skip_formatting) {
|
||||
if (skip_formatting) while (lex_index_in_range(self, self->token_id)) {
|
||||
TokType type = self->tokens.ptr[self->token_id].Type;
|
||||
if (type != Tok_NewLine && type != Tok_Comment) break;
|
||||
++ self->token_id;
|
||||
}
|
||||
return & self->tokens.ptr[idx];
|
||||
return lex_token_at(self, self->token_id);
|
||||
}
|
||||
|
||||
Token* lex_peek(ParseContext const* self, bool skip_formatting) {
|
||||
s32 idx = self->token_id;
|
||||
if (skip_formatting) {
|
||||
while (lex_index_in_range(self, idx) && self->tokens.ptr[idx].Type == Tok_NewLine)
|
||||
++ idx;
|
||||
}
|
||||
return lex_token_at(self, idx);
|
||||
}
|
||||
|
||||
Token* lex_previous(ParseContext const* self, bool skip_formatting)
|
||||
{
|
||||
s32 idx = self->token_id;
|
||||
if ( skip_formatting )
|
||||
Token* result = & NullToken;
|
||||
s32 idx = self->token_id;
|
||||
if (skip_formatting)
|
||||
{
|
||||
while ( self->tokens.ptr[idx].Type == Tok_NewLine )
|
||||
idx --;
|
||||
|
||||
return & self->tokens.ptr[idx];
|
||||
if (self->tokens.num > 0 && idx >= self->tokens.num)
|
||||
idx = self->tokens.num - 1;
|
||||
while (lex_index_in_range(self, idx) && self->tokens.ptr[idx].Type == Tok_NewLine && idx > 0)
|
||||
-- idx;
|
||||
if (lex_index_in_range(self, idx) && self->tokens.ptr[idx].Type != Tok_NewLine)
|
||||
result = &self->tokens.ptr[idx];
|
||||
goto done;
|
||||
}
|
||||
return & self->tokens.ptr[idx - 1];
|
||||
if (self->tokens.num > 0 && idx >= self->tokens.num) result = lex_token_at(self, self->tokens.num - 1);
|
||||
else result = lex_token_at(self, idx - 1);
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
Token* lex_next(ParseContext const* self, bool skip_formatting)
|
||||
{
|
||||
Token* lex_next(ParseContext const* self, bool skip_formatting) {
|
||||
s32 idx = self->token_id;
|
||||
if ( skip_formatting )
|
||||
{
|
||||
while ( self->tokens.ptr[idx].Type == Tok_NewLine )
|
||||
idx++;
|
||||
|
||||
return & self->tokens.ptr[idx + 1];
|
||||
if (skip_formatting) {
|
||||
while (lex_index_in_range(self, idx) && self->tokens.ptr[idx].Type == Tok_NewLine)
|
||||
-- idx;
|
||||
}
|
||||
return & self->tokens.ptr[idx + 1];
|
||||
return lex_token_at(self, idx + 1);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
Lex_Continue,
|
||||
Lex_ReturnNull,
|
||||
};
|
||||
@@ -90,19 +99,16 @@ void lexer_move_forward( LexContext* ctx )
|
||||
#define move_forward() lexer_move_forward(ctx)
|
||||
|
||||
forceinline
|
||||
void lexer_skip_whitespace( LexContext* ctx )
|
||||
{
|
||||
void lexer_skip_whitespace( LexContext* ctx ) {
|
||||
while ( ctx->left && char_is_space( * ctx->scanner ) )
|
||||
move_forward();
|
||||
}
|
||||
#define skip_whitespace() lexer_skip_whitespace(ctx)
|
||||
|
||||
forceinline
|
||||
void lexer_end_line( LexContext* ctx )
|
||||
{
|
||||
void lexer_end_line( LexContext* ctx ) {
|
||||
while ( ctx->left && (* ctx->scanner) == ' ' )
|
||||
move_forward();
|
||||
|
||||
if ( ctx->left && (* ctx->scanner) == '\r' ) {
|
||||
move_forward();
|
||||
move_forward();
|
||||
@@ -113,7 +119,9 @@ void lexer_end_line( LexContext* ctx )
|
||||
#define end_line() lexer_end_line(ctx)
|
||||
|
||||
// TODO(Ed): We need to to attempt to recover from a lex failure?
|
||||
s32 lex_preprocessor_define( LexContext* ctx )
|
||||
internal void lexer_record_failure_fmt(Context* lib_ctx, LexContext* ctx, char const* fmt, ...);
|
||||
|
||||
s32 lex_preprocessor_define(Context* lib_ctx, LexContext* ctx)
|
||||
{
|
||||
Token name = { { ctx->scanner, 1 }, Tok_Identifier, ctx->line, ctx->column, TF_Preprocess };
|
||||
move_forward();
|
||||
@@ -178,7 +186,7 @@ s32 lex_preprocessor_define( LexContext* ctx )
|
||||
}
|
||||
if (* ctx->scanner != ')' )
|
||||
{
|
||||
log_failure("lex_preprocessor_define(%d, %d): Expected a ')' after '...' (varaidc macro param) %S\n"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "lex_preprocessor_define(%d, %d): Expected a ')' after '...' (varaidc macro param) %S\n"
|
||||
, ctx->line
|
||||
, ctx->column
|
||||
, name.Text
|
||||
@@ -207,7 +215,7 @@ s32 lex_preprocessor_define( LexContext* ctx )
|
||||
last_parameter = parameter;
|
||||
}
|
||||
else {
|
||||
log_failure("lex_preprocessor_define(%d, %d): Expected a '_' or alpha character for a parameter name for %S\n"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "lex_preprocessor_define(%d, %d): Expected a '_' or alpha character for a parameter name for %S\n"
|
||||
, ctx->line
|
||||
, ctx->column
|
||||
, name.Text
|
||||
@@ -220,7 +228,7 @@ s32 lex_preprocessor_define( LexContext* ctx )
|
||||
|
||||
// There should be a comma
|
||||
if ( * ctx->scanner != ',' ) {
|
||||
log_failure("lex_preprocessor_define(%d, %d): Expected a comma after parameter %S for %S\n"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "lex_preprocessor_define(%d, %d): Expected a comma after parameter %S for %S\n"
|
||||
, ctx->line
|
||||
, ctx->column
|
||||
, last_parameter.Text
|
||||
@@ -234,7 +242,7 @@ s32 lex_preprocessor_define( LexContext* ctx )
|
||||
}
|
||||
|
||||
if ( * ctx->scanner != ')' ) {
|
||||
log_failure("lex_preprocessor_define(%d, %d): Expected a ')' after last_parameter %S for %S (ran out of characters...)\n"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "lex_preprocessor_define(%d, %d): Expected a ')' after last_parameter %S for %S (ran out of characters...)\n"
|
||||
, ctx->line
|
||||
, ctx->column
|
||||
, last_parameter.Text
|
||||
@@ -264,7 +272,7 @@ s32 lex_preprocessor_define( LexContext* ctx )
|
||||
}
|
||||
|
||||
// TODO(Ed): We need to to attempt to recover from a lex failure?
|
||||
s32 lex_preprocessor_directive( LexContext* ctx )
|
||||
s32 lex_preprocessor_directive(Context* lib_ctx, LexContext* ctx)
|
||||
{
|
||||
char const* hash = ctx->scanner;
|
||||
Token hash_tok = { { hash, 1 }, Tok_Preprocess_Hash, ctx->line, ctx->column, TF_Preprocess };
|
||||
@@ -317,11 +325,11 @@ s32 lex_preprocessor_directive( LexContext* ctx )
|
||||
}
|
||||
else
|
||||
{
|
||||
log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
|
||||
" in preprocessor directive (%d, %d)\n%.100s"
|
||||
, (* ctx->scanner), ctx->line, ctx->column
|
||||
, ctx->token.Line, ctx->token.Column, ctx->token.Text );
|
||||
break;
|
||||
return Lex_ReturnNull;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +374,7 @@ s32 lex_preprocessor_directive( LexContext* ctx )
|
||||
|
||||
if ( ctx->token.Type == Tok_Preprocess_Define )
|
||||
{
|
||||
u32 result = lex_preprocessor_define(ctx); // handles: #define <name>( <params> ) - define's content handled later on within this scope.
|
||||
u32 result = lex_preprocessor_define(lib_ctx, ctx); // handles: #define <name>( <params> ) - define's content handled later on within this scope.
|
||||
if (result != Lex_Continue)
|
||||
return Lex_ReturnNull;
|
||||
}
|
||||
@@ -381,7 +389,7 @@ s32 lex_preprocessor_directive( LexContext* ctx )
|
||||
{
|
||||
StrBuilder directive_str = strbuilder_fmt_buf( ctx->allocator_temp, "%.*s", min( 80, ctx->left + preprocess_content.Text.Len ), ctx->token.Text.Ptr );
|
||||
|
||||
log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s"
|
||||
, (* ctx->scanner)
|
||||
, preprocess_content.Line
|
||||
, preprocess_content.Column
|
||||
@@ -449,13 +457,12 @@ s32 lex_preprocessor_directive( LexContext* ctx )
|
||||
StrBuilder directive_str = strbuilder_make_length( ctx->allocator_temp, ctx->token.Text.Ptr, ctx->token.Text.Len );
|
||||
StrBuilder content_str = strbuilder_fmt_buf( ctx->allocator_temp, "%.*s", min( 400, ctx->left + preprocess_content.Text.Len ), preprocess_content.Text.Ptr );
|
||||
|
||||
log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
|
||||
lexer_record_failure_fmt(lib_ctx, ctx, "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
|
||||
" in preprocessor directive '%s' (%d, %d)\n%s"
|
||||
, (* ctx->scanner), ctx->line, ctx->column
|
||||
, directive_str, preprocess_content.Line, preprocess_content.Column
|
||||
, content_str );
|
||||
return Lex_ReturnNull;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,6 +575,29 @@ void lex_found_token( LexContext* ctx )
|
||||
|
||||
// TODO(Ed): We need to to attempt to recover from a lex failure?
|
||||
|
||||
internal
|
||||
void lexer_record_failure(Context* lib_ctx, LexContext* ctx, Str text) {
|
||||
LexerMessage* msg = rcast(LexerMessage*, alloc(lib_ctx->Allocator_DyanmicContainers, size_of(LexerMessage)));
|
||||
if (msg == nullptr) GEN_FATAL("lexer_record_failure: allocation failed");
|
||||
msg->next = ctx->messages;
|
||||
msg->content = cache_str(text);
|
||||
msg->level = LL_Error;
|
||||
ctx->messages = msg;
|
||||
}
|
||||
|
||||
internal
|
||||
void lexer_record_failure_fmt(Context* lib_ctx, LexContext* ctx, char const* fmt, ...) {
|
||||
va_list va;
|
||||
char* buf;
|
||||
Str text;
|
||||
va_start(va, fmt);
|
||||
buf = c_str_fmt_buf_va(fmt, va);
|
||||
va_end(va);
|
||||
text.Ptr = buf;
|
||||
text.Len = c_str_len(buf);
|
||||
lexer_record_failure(lib_ctx, ctx, text);
|
||||
}
|
||||
|
||||
neverinline
|
||||
LexedInfo lex(Context* lib_ctx, Str content)
|
||||
{
|
||||
@@ -586,14 +616,15 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
// 1. Ability to continue on error
|
||||
// 2. Return a lexed info.
|
||||
|
||||
b32 preprocess_args = true;
|
||||
|
||||
skip_whitespace();
|
||||
if ( c.left <= 0 ) {
|
||||
log_failure( "gen::lex: no tokens found (only whitespace provided)" );
|
||||
return info;
|
||||
lexer_record_failure(lib_ctx, ctx, txt("gen::lex: no tokens found (only whitespace provided)"));
|
||||
info.messages = c.messages;
|
||||
goto Lex_Done;
|
||||
}
|
||||
|
||||
b32 preprocess_args = true;
|
||||
|
||||
while (c.left )
|
||||
{
|
||||
c.token = struct_init(Token) { { c.scanner, 0 }, Tok_Invalid, c.line, c.column, TF_Null };
|
||||
@@ -630,7 +661,7 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
{
|
||||
case '#':
|
||||
{
|
||||
s32 result = lex_preprocessor_directive( ctx );
|
||||
s32 result = lex_preprocessor_directive(lib_ctx, ctx);
|
||||
switch ( result )
|
||||
{
|
||||
case Lex_Continue:
|
||||
@@ -662,6 +693,7 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
|
||||
case Lex_ReturnNull:
|
||||
{
|
||||
info.messages = c.messages;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -691,7 +723,9 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
{
|
||||
StrBuilder context_str = strbuilder_fmt_buf( lib_ctx->Allocator_Temp, "%s", c.scanner, min( 100, c.left ) );
|
||||
|
||||
log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", (* ctx->scanner), c.line, c.column, context_str );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1245,13 +1279,10 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
);
|
||||
}
|
||||
|
||||
StrBuilder context_str = strbuilder_fmt_buf( _ctx->Allocator_Temp, "%.*s", min( 100, c.left ), c.scanner );
|
||||
log_failure( "Failed to lex token '%c' (%d, %d)\n%s", (* ctx->scanner), c.line, c.column, context_str );
|
||||
|
||||
// Skip to next whitespace since we can't know if anything else is valid until then.
|
||||
while ( c.left && ! char_is_space( (* ctx->scanner) ) ) {
|
||||
move_forward();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
FoundToken:
|
||||
@@ -1280,13 +1311,15 @@ LexedInfo lex(Context* lib_ctx, Str content)
|
||||
}
|
||||
|
||||
if ( array_num(c.tokens) == 0 ) {
|
||||
log_failure( "Failed to lex any tokens" );
|
||||
return info;
|
||||
lexer_record_failure(lib_ctx, ctx, txt("gen::lex: failed to lex any tokens"));
|
||||
info.messages = c.messages;
|
||||
goto Lex_Done;
|
||||
}
|
||||
|
||||
info.messages = c.messages;
|
||||
info.text = content;
|
||||
info.tokens = struct_init(TokenSlice) { pcast(Token*, c.tokens), scast(s32, array_num(c.tokens)) };
|
||||
Lex_Done:
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
+125
-71
@@ -31,70 +31,96 @@ void parser_pop(ParseContext* ctx)
|
||||
|
||||
StrBuilder parser_to_strbuilder(ParseContext const* ctx, AllocatorInfo temp)
|
||||
{
|
||||
StrBuilder result = strbuilder_make_reserve( temp, kilobytes(4) );
|
||||
|
||||
Token scope_start = * ctx->scope->start;
|
||||
Token last_valid = (ctx->token_id >= ctx->tokens.num) ? ctx->tokens.ptr[ctx->tokens.num -1] : (* lex_peek(ctx, true));
|
||||
|
||||
sptr length = scope_start.Text.Len;
|
||||
char const* current = scope_start.Text.Ptr + length;
|
||||
while ( current <= ctx->tokens.ptr[ctx->tokens.num - 1].Text.Ptr && (* current) != '\n' && length < 74 )
|
||||
{
|
||||
current++;
|
||||
length++;
|
||||
StrBuilder result;
|
||||
b32 empty_slice = ctx->tokens.ptr == nullptr || ctx->tokens.num <= 0;
|
||||
if (empty_slice == false)
|
||||
empty_slice = ctx->scope->start == nullptr || ctx->scope->start->Text.Ptr == nullptr;
|
||||
// empty_scope
|
||||
if (empty_slice) {
|
||||
result = strbuilder_make_reserve(temp, 64);
|
||||
strbuilder_append_fmt(&result, "\tScope : <empty>\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
Str scope_str = { scope_start.Text.Ptr, length };
|
||||
StrBuilder line = strbuilder_make_str( temp, scope_str );
|
||||
strbuilder_append_fmt( & result, "\tScope : %s\n", line );
|
||||
strbuilder_free(& line);
|
||||
|
||||
sptr dist = (sptr)last_valid.Text.Ptr - (sptr)scope_start.Text.Ptr + 2;
|
||||
sptr length_from_err = dist;
|
||||
|
||||
Str err_str = { last_valid.Text.Ptr, length_from_err };
|
||||
StrBuilder line_from_err = strbuilder_make_str( temp, err_str );
|
||||
|
||||
if ( length_from_err < 100 )
|
||||
strbuilder_append_fmt(& result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' );
|
||||
else
|
||||
strbuilder_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column );
|
||||
|
||||
ParseStackNode* curr_scope = ctx->scope;
|
||||
s32 level = 0;
|
||||
do
|
||||
// non_empty
|
||||
{
|
||||
if ( curr_scope->name.Ptr ) {
|
||||
strbuilder_append_fmt(& result, "\t%d: %S, AST Name: %S\n", level, curr_scope->proc_name, curr_scope->name );
|
||||
}
|
||||
else {
|
||||
strbuilder_append_fmt(& result, "\t%d: %S\n", level, curr_scope->proc_name );
|
||||
result = strbuilder_make_reserve( temp, kilobytes(4) );
|
||||
|
||||
Token scope_start = * ctx->scope->start;
|
||||
Token last_valid = (ctx->token_id >= ctx->tokens.num)
|
||||
? ctx->tokens.ptr[ctx->tokens.num - 1]
|
||||
: (*lex_peek(ctx, true));
|
||||
|
||||
sptr length = scope_start.Text.Len;
|
||||
char const* current = scope_start.Text.Ptr + length;
|
||||
while ( current <= ctx->tokens.ptr[ctx->tokens.num - 1].Text.Ptr && (* current) != '\n' && length < 74 )
|
||||
{
|
||||
current++;
|
||||
length++;
|
||||
}
|
||||
|
||||
curr_scope = curr_scope->prev;
|
||||
level++;
|
||||
Str scope_str = { scope_start.Text.Ptr, length };
|
||||
StrBuilder line = strbuilder_make_str( temp, scope_str );
|
||||
strbuilder_append_fmt( & result, "\tScope : %s\n", line );
|
||||
strbuilder_free(& line);
|
||||
|
||||
sptr dist = (sptr)last_valid.Text.Ptr - (sptr)scope_start.Text.Ptr + 2;
|
||||
sptr length_from_err = dist;
|
||||
|
||||
Str err_str = { last_valid.Text.Ptr, length_from_err };
|
||||
StrBuilder line_from_err = strbuilder_make_str( temp, err_str );
|
||||
|
||||
if ( length_from_err < 100 )
|
||||
strbuilder_append_fmt(& result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' );
|
||||
else
|
||||
strbuilder_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column );
|
||||
|
||||
ParseStackNode* curr_scope = ctx->scope;
|
||||
s32 level = 0;
|
||||
do
|
||||
{
|
||||
if ( curr_scope->name.Ptr ) {
|
||||
strbuilder_append_fmt(& result, "\t%d: %S, AST Name: %S\n", level, curr_scope->proc_name, curr_scope->name );
|
||||
}
|
||||
else {
|
||||
strbuilder_append_fmt(& result, "\t%d: %S\n", level, curr_scope->proc_name );
|
||||
}
|
||||
|
||||
curr_scope = curr_scope->prev;
|
||||
level++;
|
||||
}
|
||||
while ( curr_scope );
|
||||
}
|
||||
while ( curr_scope );
|
||||
done:
|
||||
return result;
|
||||
}
|
||||
|
||||
void parser_record_failure(Context* ctx, Str text) {
|
||||
ParseMessage* msg = rcast(ParseMessage*, alloc(ctx->Allocator_DyanmicContainers, size_of(ParseMessage)));
|
||||
if (msg == nullptr) GEN_FATAL("parser_record_failure: allocation failed");
|
||||
msg->Next = ctx->parser.messages;
|
||||
msg->Scope = nullptr;
|
||||
msg->Content = cache_str(text);
|
||||
msg->Level = LL_Error;
|
||||
ctx->parser.messages = msg;
|
||||
}
|
||||
|
||||
bool lex__eat(Context* ctx, ParseContext* parser, TokType type)
|
||||
{
|
||||
if ( parser->tokens.num - parser->token_id <= 0 ) {
|
||||
log_failure( "No tokens left.\n%SB", parser_to_strbuilder(parser, ctx->Allocator_Temp) );
|
||||
return false;
|
||||
}
|
||||
|
||||
Token at_idx = parser->tokens.ptr[ parser->token_id ];
|
||||
b32 ate = false;
|
||||
Token at_idx;
|
||||
b32 not_accepted;
|
||||
b32 is_identifier;
|
||||
if (parser->tokens.num - parser->token_id <= 0)
|
||||
goto done;
|
||||
|
||||
at_idx = parser->tokens.ptr[ parser->token_id ];
|
||||
if ( ( at_idx.Type == Tok_NewLine && type != Tok_NewLine )
|
||||
|| ( at_idx.Type == Tok_Comment && type != Tok_Comment ) )
|
||||
{
|
||||
|| ( at_idx.Type == Tok_Comment && type != Tok_Comment ) ) {
|
||||
parser->token_id ++;
|
||||
}
|
||||
|
||||
b32 not_accepted = at_idx.Type != type;
|
||||
b32 is_identifier = at_idx.Type == Tok_Identifier;
|
||||
not_accepted = at_idx.Type != type;
|
||||
is_identifier = at_idx.Type == Tok_Identifier;
|
||||
if ( not_accepted )
|
||||
{
|
||||
Macro* macro = lookup_macro(at_idx.Text);
|
||||
@@ -112,7 +138,7 @@ bool lex__eat(Context* ctx, ParseContext* parser, TokType type)
|
||||
, parser_to_strbuilder(parser, ctx->Allocator_Temp)
|
||||
);
|
||||
GEN_DEBUG_TRAP();
|
||||
return false;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if 0 && GEN_BUILD_DEBUG
|
||||
@@ -120,7 +146,9 @@ bool lex__eat(Context* ctx, ParseContext* parser, TokType type)
|
||||
#endif
|
||||
|
||||
parser->token_id ++;
|
||||
return true;
|
||||
ate = true;
|
||||
done:
|
||||
return ate;
|
||||
}
|
||||
|
||||
internal
|
||||
@@ -135,22 +163,40 @@ void parser_deinit(Context* ctx)
|
||||
|
||||
#pragma region Helper Macros
|
||||
|
||||
#define check_parse_args( def ) _check_parse_args(& ctx->parser, def, stringize(_func_) )
|
||||
bool _check_parse_args(ParseContext* parser, Str def, char const* func_name )
|
||||
b32 parser_slice_is_formatting_only(ParseContext const* parser)
|
||||
{
|
||||
if ( def.Len <= 0 )
|
||||
b32 formatting_only = true;
|
||||
if (parser->tokens.ptr == nullptr || parser->tokens.num <= 0)
|
||||
goto done;
|
||||
for (s32 idx = 0; idx < parser->tokens.num; ++idx)
|
||||
{
|
||||
log_failure( c_str_fmt_buf("gen::%s: length must greater than 0", func_name) );
|
||||
parser_pop(parser);
|
||||
return false;
|
||||
TokType type = parser->tokens.ptr[idx].Type;
|
||||
if (type != Tok_NewLine && type != Tok_Comment) {
|
||||
formatting_only = false;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ( def.Ptr == nullptr )
|
||||
{
|
||||
log_failure( c_str_fmt_buf("gen::%s: def was null", func_name) );
|
||||
parser_pop(parser);
|
||||
return false;
|
||||
done:
|
||||
return formatting_only;
|
||||
}
|
||||
|
||||
#define check_parse_args( def ) _check_parse_args(ctx, def, __func__)
|
||||
bool _check_parse_args(Context* ctx, Str def, char const* func_name )
|
||||
{
|
||||
b32 ok = true;
|
||||
char const* text;
|
||||
if ( def.Len <= 0 ) {
|
||||
text = c_str_fmt_buf("gen::%s: length must greater than 0", func_name);
|
||||
parser_record_failure(ctx, to_str_from_c_str(text));
|
||||
ok = false; goto done;
|
||||
}
|
||||
return true;
|
||||
if ( def.Ptr == nullptr ) {
|
||||
text = c_str_fmt_buf("gen::%s: def was null", func_name);
|
||||
parser_record_failure(ctx, to_str_from_c_str(text));
|
||||
ok = false; goto done;
|
||||
}
|
||||
done:
|
||||
return ok;
|
||||
}
|
||||
|
||||
# define currtok_noskip (* lex_current( & ctx->parser, lex_dont_skip_formatting ))
|
||||
@@ -2455,9 +2501,12 @@ CodeOperator parse_operator_after_ret_type(Context* ctx
|
||||
was_new_or_delete = true;
|
||||
|
||||
s32 idx = ctx->parser.token_id + 1;
|
||||
{
|
||||
while ( ctx->parser.tokens.ptr[ idx ].Type == Tok_NewLine )
|
||||
idx++;
|
||||
while (idx < ctx->parser.tokens.num && ctx->parser.tokens.ptr[idx].Type == Tok_NewLine)
|
||||
idx++;
|
||||
if (idx >= ctx->parser.tokens.num) {
|
||||
parser_record_failure(ctx, txt("parse: operator new/delete ended at slice end"));
|
||||
parser_pop(&ctx->parser);
|
||||
return InvalidCode;
|
||||
}
|
||||
Token next = ctx->parser.tokens.ptr[idx];
|
||||
if ( currtok.Type == Tok_Operator && c_str_compare_len(currtok.Text.Ptr, "[]", 2) == 0)
|
||||
@@ -2479,9 +2528,12 @@ CodeOperator parse_operator_after_ret_type(Context* ctx
|
||||
was_new_or_delete = true;
|
||||
|
||||
s32 idx = ctx->parser.token_id + 1;
|
||||
{
|
||||
while ( ctx->parser.tokens.ptr[ idx ].Type == Tok_NewLine )
|
||||
idx++;
|
||||
while (idx < ctx->parser.tokens.num && ctx->parser.tokens.ptr[idx].Type == Tok_NewLine)
|
||||
idx++;
|
||||
if (idx >= ctx->parser.tokens.num) {
|
||||
parser_record_failure(ctx, txt("parse: operator new/delete ended at slice end"));
|
||||
parser_pop(&ctx->parser);
|
||||
return InvalidCode;
|
||||
}
|
||||
Token next = ctx->parser.tokens.ptr[idx];
|
||||
if ( currtok.Type == Tok_Operator && c_str_compare_len(currtok.Text.Ptr, "[]", 2) == 0)
|
||||
@@ -2673,7 +2725,9 @@ Code parse_operator_function_or_variable(Context* ctx, bool expects_function, Co
|
||||
// ( 350.0f , <--- Could be the scenario
|
||||
// Example : <Capture_Start> <Value> <Comma>
|
||||
// idx +1 +2
|
||||
bool detected_comma = ctx->parser.tokens.ptr[ ctx->parser.token_id + 2 ].Type == Tok_Comma;
|
||||
b32 detected_comma = false;
|
||||
if (ctx->parser.token_id + 2 < ctx->parser.tokens.num)
|
||||
detected_comma = ctx->parser.tokens.ptr[ctx->parser.token_id + 2].Type == Tok_Comma;
|
||||
|
||||
b32 detected_non_varadic_unpaired_param = detected_comma && nexttok.Type != Tok_Varadic_Argument;
|
||||
if (! detected_non_varadic_unpaired_param && nexttok.Type == Tok_Preprocess_Macro_Expr) for( s32 break_scope = 0; break_scope == 0; ++ break_scope)
|
||||
@@ -2701,7 +2755,7 @@ Code parse_operator_function_or_variable(Context* ctx, bool expects_function, Co
|
||||
}
|
||||
++ idx; // Will incremnt to possible comma position
|
||||
|
||||
if ( ctx->parser.tokens.ptr[ idx ].Type != Tok_Comma )
|
||||
if (idx >= ctx->parser.tokens.num || ctx->parser.tokens.ptr[idx].Type != Tok_Comma)
|
||||
break;
|
||||
|
||||
detected_non_varadic_unpaired_param = true;
|
||||
|
||||
@@ -37,8 +37,6 @@ struct Token
|
||||
u32 Flags;
|
||||
};
|
||||
|
||||
constexpr Token NullToken { {}, Tok_Invalid, 0, 0, TF_Null };
|
||||
|
||||
forceinline
|
||||
AccessSpec tok_to_access_specifier(Token tok) {
|
||||
return scast(AccessSpec, tok.Type);
|
||||
|
||||
@@ -8,6 +8,8 @@ GEN_API global Context* _ctx;
|
||||
GEN_API global u32 context_counter;
|
||||
|
||||
#pragma region Constants
|
||||
GEN_API read_only global Token NullToken = { { 0, 0 }, Tok_Invalid, 0, 0, TF_Null };
|
||||
|
||||
GEN_API global Macro enum_underlying_macro;
|
||||
|
||||
GEN_API global Code Code_Global;
|
||||
|
||||
Reference in new issue
Block a user