summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser.h2
-rw-r--r--src/parser/parser_core.c22
-rw-r--r--src/parser/parser_expr.c98
-rw-r--r--src/parser/parser_stmt.c138
-rw-r--r--src/parser/parser_type.c12
-rw-r--r--src/parser/parser_utils.c23
6 files changed, 152 insertions, 143 deletions
diff --git a/src/parser/parser.h b/src/parser/parser.h
index 9cdd0d2..4d105cf 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -312,7 +312,7 @@ void add_to_impl_list(ParserContext *ctx, ASTNode *node);
void add_to_global_list(ParserContext *ctx, ASTNode *node);
void register_builtins(ParserContext *ctx);
void add_instantiated_func(ParserContext *ctx, ASTNode *fn);
-void instantiate_generic(ParserContext *ctx, const char *name, const char *concrete_type);
+void instantiate_generic(ParserContext *ctx, const char *name, const char *concrete_type, Token t);
char *sanitize_mangled_name(const char *s);
void register_impl(ParserContext *ctx, const char *trait, const char *strct);
int check_impl(ParserContext *ctx, const char *trait, const char *strct);
diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c
index 1a47275..7d5bc32 100644
--- a/src/parser/parser_core.c
+++ b/src/parser/parser_core.c
@@ -76,7 +76,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
Token attr = lexer_next(l);
if (attr.type != TOK_IDENT && attr.type != TOK_COMPTIME)
{
- zpanic("Expected attribute name after @");
+ zpanic_at(attr, "Expected attribute name after @");
}
if (0 == strncmp(attr.start, "must_use", 8) && 8 == attr.len)
@@ -98,7 +98,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after deprecated message");
+ zpanic_at(lexer_peek(l), "Expected ) after deprecated message");
}
}
}
@@ -164,12 +164,12 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after section name");
+ zpanic_at(lexer_peek(l), "Expected ) after section name");
}
}
else
{
- zpanic("@section requires a name: @section(\"name\")");
+ zpanic_at(lexer_peek(l), "@section requires a name: @section(\"name\")");
}
}
else if (0 == strncmp(attr.start, "packed", 6) && 6 == attr.len)
@@ -188,12 +188,12 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after align value");
+ zpanic_at(lexer_peek(l), "Expected ) after align value");
}
}
else
{
- zpanic("@align requires a value: @align(N)");
+ zpanic_at(lexer_peek(l), "@align requires a value: @align(N)");
}
}
else if (0 == strncmp(attr.start, "derive", 6) && 6 == attr.len)
@@ -206,7 +206,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_IDENT)
{
- zpanic("Expected trait name in @derive");
+ zpanic_at(t, "Expected trait name in @derive");
}
if (derived_count < 32)
{
@@ -223,12 +223,12 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after derive traits");
+ zpanic_at(lexer_peek(l), "Expected ) after derive traits");
}
}
else
{
- zpanic("@derive requires traits: @derive(Debug, Clone)");
+ zpanic_at(lexer_peek(l), "@derive requires traits: @derive(Debug, Clone)");
}
}
else
@@ -372,7 +372,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
lexer_next(l);
if (lexer_peek(l).type != TOK_LBRACE)
{
- zpanic("Expected { after raw");
+ zpanic_at(lexer_peek(l), "Expected { after raw");
}
lexer_next(l);
@@ -384,7 +384,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type == TOK_EOF)
{
- zpanic("Unexpected EOF in raw block");
+ zpanic_at(t, "Unexpected EOF in raw block");
}
if (t.type == TOK_LBRACE)
{
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index b9a1c35..40d6ae0 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -648,7 +648,7 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l)
if (lexer_peek(l).type != TOK_LPAREN)
{
- zpanic("Expected '(' after 'fn' in lambda");
+ zpanic_at(lexer_peek(l), "Expected '(' after 'fn' in lambda");
}
lexer_next(l);
@@ -663,7 +663,7 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l)
{
if (lexer_peek(l).type != TOK_COMMA)
{
- zpanic("Expected ',' between parameters");
+ zpanic_at(lexer_peek(l), "Expected ',' between parameters");
}
lexer_next(l);
@@ -672,14 +672,14 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l)
Token name_tok = lexer_next(l);
if (name_tok.type != TOK_IDENT)
{
- zpanic("Expected parameter name");
+ zpanic_at(name_tok, "Expected parameter name");
}
param_names[num_params] = token_strdup(name_tok);
if (lexer_peek(l).type != TOK_COLON)
{
- zpanic("Expected ':' after parameter name");
+ zpanic_at(lexer_peek(l), "Expected ':' after parameter name");
}
lexer_next(l);
@@ -704,7 +704,7 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Expected '{' for lambda body");
+ zpanic_at(lexer_peek(l), "Expected '{' for lambda body");
}
ASTNode *lambda = ast_create(NODE_LAMBDA);
@@ -966,7 +966,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
if (lexer_peek(l).type != TOK_LPAREN)
{
- zpanic("Expected ( after sizeof");
+ zpanic_at(lexer_peek(l), "Expected ( after sizeof");
}
lexer_next(l);
@@ -992,7 +992,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
ASTNode *ex = parse_expression(ctx, l);
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after sizeof identifier");
+ zpanic_at(lexer_peek(l), "Expected ) after sizeof identifier");
}
node = ast_create(NODE_EXPR_SIZEOF);
node->size_of.target_type = NULL;
@@ -1005,7 +1005,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
if (lexer_peek(l).type != TOK_LPAREN)
{
- zpanic("Expected ( after typeof");
+ zpanic_at(lexer_peek(l), "Expected ( after typeof");
}
lexer_next(l);
@@ -1030,7 +1030,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
ASTNode *ex = parse_expression(ctx, l);
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after typeof expression");
+ zpanic_at(lexer_peek(l), "Expected ) after typeof expression");
}
node = ast_create(NODE_TYPEOF);
node->size_of.target_type = NULL;
@@ -1043,7 +1043,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
Token ident = lexer_next(l);
if (ident.type != TOK_IDENT)
{
- zpanic("Expected intrinsic name after @");
+ zpanic_at(ident, "Expected intrinsic name after @");
}
int kind = -1;
@@ -1057,19 +1057,25 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Unknown intrinsic @%.*s", ident.len, ident.start);
+ zpanic_at(ident, "Unknown intrinsic @%.*s", ident.len, ident.start);
}
- if (lexer_next(l).type != TOK_LPAREN)
{
- zpanic("Expected ( after intrinsic");
+ Token t = lexer_next(l);
+ if (t.type != TOK_LPAREN)
+ {
+ zpanic_at(t, "Expected ( after intrinsic");
+ }
}
Type *target = parse_type_formal(ctx, l);
- if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after intrinsic type");
+ Token t = lexer_next(l);
+ if (t.type != TOK_RPAREN)
+ {
+ zpanic_at(t, "Expected ) after intrinsic type");
+ }
}
node = ast_create(NODE_REFLECTION);
@@ -1082,9 +1088,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
ASTNode *expr = parse_expression(ctx, l);
skip_comments(l);
- if (lexer_next(l).type != TOK_LBRACE)
{
- zpanic("Expected { after match expression");
+ Token t = lexer_next(l);
+ if (t.type != TOK_LBRACE)
+ {
+ zpanic_at(t, "Expected { after match expression");
+ }
}
ASTNode *h = 0, *tl = 0;
@@ -1119,12 +1128,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
Token b = lexer_next(l);
if (b.type != TOK_IDENT)
{
- zpanic("Expected binding name");
+ zpanic_at(b, "Expected binding name");
}
binding = token_strdup(b);
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
is_destructure = 1;
}
@@ -1140,7 +1149,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
skip_comments(l);
if (lexer_next(l).type != TOK_ARROW)
{
- zpanic("Expected '=>'");
+ zpanic_at(lexer_peek(l), "Expected '=>'");
}
ASTNode *body;
@@ -1224,7 +1233,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
Token suffix = lexer_next(l);
if (suffix.type != TOK_IDENT)
{
- zpanic("Expected identifier after ::");
+ zpanic_at(suffix, "Expected identifier after ::");
}
SelectiveImport *si =
@@ -1302,7 +1311,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
if (is_struct)
{
- instantiate_generic(ctx, acc, concrete_type);
+ instantiate_generic(ctx, acc, concrete_type, t);
char *clean_type = sanitize_mangled_name(concrete_type);
@@ -1323,7 +1332,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Unknown generic %s", acc);
+ zpanic_at(t, "Unknown generic %s", acc);
}
}
changed = 1;
@@ -1394,7 +1403,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
Token fn = lexer_next(l);
if (lexer_next(l).type != TOK_COLON)
{
- zpanic("Expected :");
+ zpanic_at(lexer_peek(l), "Expected :");
}
ASTNode *val = parse_expression(ctx, l);
ASTNode *assign = ast_create(NODE_VAR_DECL);
@@ -1447,7 +1456,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
if (ac == 0)
@@ -1593,7 +1602,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
for (int i = args_provided; i < sig->total_args; i++)
{
@@ -1696,7 +1705,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
node = ast_create(NODE_EXPR_CALL);
@@ -1825,9 +1834,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
Type *cast_type_obj = parse_type_formal(ctx, l);
char *cast_type = type_to_string(cast_type_obj);
- if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after cast");
+ Token t = lexer_next(l);
+ if (t.type != TOK_RPAREN)
+ {
+ zpanic_at(t, "Expected ) after cast");
+ }
}
ASTNode *target = parse_expr_prec(ctx, l, PREC_UNARY);
@@ -1844,7 +1856,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
ASTNode *expr = parse_expression(ctx, l);
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
node = expr;
}
@@ -1878,7 +1890,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RBRACKET)
{
- zpanic("Expected ] after array literal");
+ zpanic_at(lexer_peek(l), "Expected ] after array literal");
}
node = ast_create(NODE_EXPR_ARRAY_LITERAL);
node->array_literal.elements = head;
@@ -1952,9 +1964,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
}
}
- if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after call arguments");
+ Token t = lexer_next(l);
+ if (t.type != TOK_RPAREN)
+ {
+ zpanic_at(t, "Expected ) after call arguments");
+ }
}
ASTNode *call = ast_create(NODE_EXPR_CALL);
@@ -1980,9 +1995,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
Token bracket = lexer_next(l); // consume '['
ASTNode *index = parse_expression(ctx, l);
- if (lexer_next(l).type != TOK_RBRACKET)
{
- zpanic("Expected ] after index");
+ Token t = lexer_next(l);
+ if (t.type != TOK_RBRACKET)
+ {
+ zpanic_at(t, "Expected ] after index");
+ }
}
// Static Array Bounds Check
@@ -2268,7 +2286,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
char fmt[256];
@@ -2581,7 +2599,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
Token tk = lexer_peek(l);
if (tk.type == TOK_EOF)
{
- zpanic("Unterminated sizeof");
+ zpanic_at(tk, "Unterminated sizeof");
}
if (tk.type == TOK_LPAREN)
{
@@ -2607,7 +2625,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
else
{
- zpanic("sizeof must be followed by (");
+ zpanic_at(lexer_peek(l), "sizeof must be followed by (");
}
}
else
@@ -2843,7 +2861,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
call->call.args = head;
call->call.arg_names = has_named ? arg_names : NULL;
@@ -2893,7 +2911,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
if (lexer_next(l).type != TOK_RBRACKET)
{
- zpanic("Expected ]");
+ zpanic_at(lexer_peek(l), "Expected ]");
}
if (is_slice)
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 484d742..227b5aa 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -56,7 +56,7 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
gen_param = token_strdup(gt);
if (lexer_next(l).type != TOK_RANGLE)
{
- zpanic("Expected >");
+ zpanic_at(lexer_peek(l), "Expected >");
}
}
@@ -193,9 +193,10 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l)
lexer_next(l); // eat 'match'
ASTNode *expr = parse_expression(ctx, l);
- if (lexer_next(l).type != TOK_LBRACE)
+ Token t_brace = lexer_next(l);
+ if (t_brace.type != TOK_LBRACE)
{
- zpanic("Expected { in match");
+ zpanic_at(t_brace, "Expected { in match");
}
ASTNode *h = 0, *tl = 0;
@@ -272,12 +273,12 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l)
Token b = lexer_next(l);
if (b.type != TOK_IDENT)
{
- zpanic("Expected variable name in pattern");
+ zpanic_at(b, "Expected variable name in pattern");
}
binding = token_strdup(b);
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
is_destructure = 1;
}
@@ -293,7 +294,7 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l)
if (lexer_next(l).type != TOK_ARROW)
{
- zpanic("Expected =>");
+ zpanic_at(lexer_peek(l), "Expected =>");
}
ASTNode *body;
@@ -386,7 +387,7 @@ ASTNode *parse_guard(ParserContext *ctx, Lexer *l)
Token t = lexer_peek(l);
if (t.type != TOK_IDENT || strncmp(t.start, "else", 4) != 0)
{
- zpanic("Expected 'else' after guard condition");
+ zpanic_at(t, "Expected 'else' after guard condition");
}
lexer_next(l); // consume 'else'
@@ -445,7 +446,7 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l)
// Expect {
if (lexer_peek(l).type != TOK_LBRACE)
{
- zpanic("Expected { after asm");
+ zpanic_at(lexer_peek(l), "Expected { after asm");
}
lexer_next(l);
@@ -564,7 +565,7 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Expected assembly string, instruction, or ':' in asm block");
+ zpanic_at(t, "Expected assembly string, instruction, or ':' in asm block");
}
}
@@ -601,19 +602,19 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l)
if (lexer_peek(l).type != TOK_LPAREN)
{
- zpanic("Expected ( after output mode");
+ zpanic_at(lexer_peek(l), "Expected ( after output mode");
}
lexer_next(l);
Token var = lexer_next(l);
if (var.type != TOK_IDENT)
{
- zpanic("Expected variable name");
+ zpanic_at(var, "Expected variable name");
}
if (lexer_peek(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after variable");
+ zpanic_at(lexer_peek(l), "Expected ) after variable");
}
lexer_next(l);
@@ -658,19 +659,19 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l)
if (lexer_peek(l).type != TOK_LPAREN)
{
- zpanic("Expected ( after in");
+ zpanic_at(lexer_peek(l), "Expected ( after in");
}
lexer_next(l);
Token var = lexer_next(l);
if (var.type != TOK_IDENT)
{
- zpanic("Expected variable name");
+ zpanic_at(var, "Expected variable name");
}
if (lexer_peek(l).type != TOK_RPAREN)
{
- zpanic("Expected ) after variable");
+ zpanic_at(lexer_peek(l), "Expected ) after variable");
}
lexer_next(l);
@@ -726,7 +727,7 @@ ASTNode *parse_asm(ParserContext *ctx, Lexer *l)
// Expect closing }
if (lexer_peek(l).type != TOK_RBRACE)
{
- zpanic("Expected } at end of asm block");
+ zpanic_at(lexer_peek(l), "Expected } at end of asm block");
}
lexer_next(l);
@@ -751,7 +752,7 @@ ASTNode *parse_test(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_STRING)
{
- zpanic("Test name must be a string literal");
+ zpanic_at(t, "Test name must be a string literal");
}
// Strip quotes for AST storage
@@ -784,7 +785,7 @@ ASTNode *parse_assert(ParserContext *ctx, Lexer *l)
Token st = lexer_next(l);
if (st.type != TOK_STRING)
{
- zpanic("Expected message string");
+ zpanic_at(st, "Expected message string");
}
msg = xmalloc(st.len + 1);
strncpy(msg, st.start, st.len);
@@ -895,12 +896,12 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
}
if (next.type != TOK_COMMA)
{
- zpanic("Expected comma");
+ zpanic_at(next, "Expected comma");
}
}
if (lexer_next(l).type != TOK_OP)
{
- zpanic("Expected =");
+ zpanic_at(lexer_peek(l), "Expected =");
}
ASTNode *init = parse_expression(ctx, l);
if (lexer_peek(l).type == TOK_SEMICOLON)
@@ -960,13 +961,13 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
}
if (next.type != TOK_COMMA)
{
- zpanic("Expected comma in struct pattern");
+ zpanic_at(next, "Expected comma in struct pattern");
}
}
if (lexer_next(l).type != TOK_OP)
{
- zpanic("Expected =");
+ zpanic_at(lexer_peek(l), "Expected =");
}
ASTNode *init = parse_expression(ctx, l);
if (lexer_peek(l).type == TOK_SEMICOLON)
@@ -993,12 +994,12 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ')' in guard pattern");
+ zpanic_at(lexer_peek(l), "Expected ')' in guard pattern");
}
if (lexer_next(l).type != TOK_OP)
{
- zpanic("Expected '=' after guard pattern");
+ zpanic_at(lexer_peek(l), "Expected '=' after guard pattern");
}
ASTNode *init = parse_expression(ctx, l);
@@ -1006,7 +1007,7 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_IDENT || strncmp(t.start, "else", 4) != 0)
{
- zpanic("Expected 'else' in guard statement");
+ zpanic_at(t, "Expected 'else' in guard statement");
}
ASTNode *else_blk;
@@ -1141,7 +1142,7 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
}
else if (init->type == NODE_EXPR_SLICE)
{
- zpanic("Slice Node has NO Type Info!");
+ zpanic_at(init->token, "Slice Node has NO Type Info!");
}
// Fallbacks for literals
else if (init->type == NODE_EXPR_LITERAL)
@@ -1963,7 +1964,7 @@ ASTNode *parse_macro_call(ParserContext *ctx, Lexer *l, char *macro_name)
// Expect {
if (lexer_peek(l).type != TOK_LBRACE)
{
- zpanic("Expected { after macro invocation");
+ zpanic_at(lexer_peek(l), "Expected { after macro invocation");
}
lexer_next(l); // consume {
@@ -1979,7 +1980,7 @@ ASTNode *parse_macro_call(ParserContext *ctx, Lexer *l, char *macro_name)
Token t = lexer_peek(l);
if (t.type == TOK_EOF)
{
- zpanic("Unexpected EOF in macro block");
+ zpanic_at(t, "Unexpected EOF in macro block");
}
if (t.type == TOK_LBRACE)
@@ -2025,7 +2026,7 @@ ASTNode *parse_macro_call(ParserContext *ctx, Lexer *l, char *macro_name)
char err[256];
snprintf(err, sizeof(err), "Unknown plugin: %s (did you forget 'import plugin \"%s\"'?)",
macro_name, macro_name);
- zpanic(err);
+ zpanic_at(start_tok, err);
}
// Find Plugin Definition
@@ -2036,14 +2037,14 @@ ASTNode *parse_macro_call(ParserContext *ctx, Lexer *l, char *macro_name)
{
char err[256];
snprintf(err, sizeof(err), "Plugin implementation not found: %s", plugin_name);
- zpanic(err);
+ zpanic_at(start_tok, err);
}
// Execute Plugin Immediately (Expansion)
FILE *capture = tmpfile();
if (!capture)
{
- zpanic("Failed to create capture buffer for plugin expansion");
+ zpanic_at(start_tok, "Failed to create capture buffer for plugin expansion");
}
ZApi api = {.filename = g_current_filename ? g_current_filename : "input.zc",
@@ -2166,7 +2167,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
lexer_next(l);
if (lexer_peek(l).type != TOK_IDENT || strncmp(lexer_peek(l).start, "var", 3) != 0)
{
- zpanic("Expected 'var' after autofree");
+ zpanic_at(lexer_peek(l), "Expected 'var' after autofree");
}
s = parse_var_decl(ctx, l);
s->var_decl.is_autofree = 1;
@@ -2260,7 +2261,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
lexer_next(l); // eat raw
if (lexer_peek(l).type != TOK_LBRACE)
{
- zpanic("Expected { after raw");
+ zpanic_at(lexer_peek(l), "Expected { after raw");
}
lexer_next(l); // eat {
@@ -2271,7 +2272,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type == TOK_EOF)
{
- zpanic("Unexpected EOF in raw block");
+ zpanic_at(t, "Unexpected EOF in raw block");
}
if (t.type == TOK_LBRACE)
{
@@ -2518,7 +2519,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_STRING && t.type != TOK_FSTRING)
{
- zpanic("Expected string literal after print/eprint");
+ zpanic_at(t, "Expected string literal after print/eprint");
}
char *inner = xmalloc(t.len);
@@ -2751,7 +2752,7 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
Token n = lexer_next(l);
if (n.type != TOK_IDENT)
{
- zpanic("Expected trait name");
+ zpanic_at(n, "Expected trait name");
}
char *name = xmalloc(n.len + 1);
strncpy(name, n.start, n.len);
@@ -2778,7 +2779,7 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
Token ft = lexer_next(l);
if (ft.type != TOK_IDENT || strncmp(ft.start, "fn", 2) != 0)
{
- zpanic("Expected fn in trait");
+ zpanic_at(ft, "Expected fn in trait");
}
Token mn = lexer_next(l);
@@ -2825,7 +2826,7 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
else
{
// Default implementation? Not supported yet.
- zpanic("Trait methods must end with ; for now");
+ zpanic_at(lexer_peek(l), "Trait methods must end with ; for now");
}
}
@@ -2852,7 +2853,7 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
gen_param = token_strdup(gt);
if (lexer_next(l).type != TOK_RANGLE)
{
- zpanic("Expected >");
+ zpanic_at(lexer_peek(l), "Expected >");
}
}
@@ -2954,7 +2955,7 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Expected 'fn' after 'async'");
+ zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
}
}
else
@@ -2990,7 +2991,7 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
// GENERIC IMPL TEMPLATE: impl Box<T>
if (lexer_next(l).type != TOK_LBRACE)
{
- zpanic("Expected {");
+ zpanic_at(lexer_peek(l), "Expected {");
}
ASTNode *h = 0, *tl = 0;
while (1)
@@ -3051,7 +3052,7 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Expected 'fn' after 'async'");
+ zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
}
}
else
@@ -3138,7 +3139,7 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
}
else
{
- zpanic("Expected 'fn' after 'async'");
+ zpanic_at(lexer_peek(l), "Expected 'fn' after 'async'");
}
}
else
@@ -3284,7 +3285,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
Token width_tok = lexer_next(l);
if (width_tok.type != TOK_INT)
{
- zpanic("Expected bit width integer");
+ zpanic_at(width_tok, "Expected bit width integer");
}
f->field.bit_width = atoi(token_strdup(width_tok));
}
@@ -3422,7 +3423,7 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
payload = parse_type_obj(ctx, l);
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected )");
+ zpanic_at(lexer_peek(l), "Expected )");
}
}
@@ -3541,7 +3542,7 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token plugin_tok = lexer_next(l);
if (plugin_tok.type != TOK_STRING)
{
- zpanic("Expected string literal after 'import plugin'");
+ zpanic_at(plugin_tok, "Expected string literal after 'import plugin'");
}
// Extract plugin name (strip quotes)
@@ -3559,7 +3560,7 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token alias_tok = lexer_next(l);
if (alias_tok.type != TOK_IDENT)
{
- zpanic("Expected identifier after 'as'");
+ zpanic_at(alias_tok, "Expected identifier after 'as'");
}
alias = token_strdup(alias_tok);
}
@@ -3600,7 +3601,7 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token sym_tok = lexer_next(l);
if (sym_tok.type != TOK_IDENT)
{
- zpanic("Expected identifier in selective import");
+ zpanic_at(sym_tok, "Expected identifier in selective import");
}
symbols[symbol_count] = xmalloc(sym_tok.len + 1);
@@ -3615,7 +3616,7 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token alias_tok = lexer_next(l);
if (alias_tok.type != TOK_IDENT)
{
- zpanic("Expected identifier after 'as'");
+ zpanic_at(alias_tok, "Expected identifier after 'as'");
}
aliases[symbol_count] = xmalloc(alias_tok.len + 1);
@@ -3637,7 +3638,8 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
if (from_tok.type != TOK_IDENT || from_tok.len != 4 ||
strncmp(from_tok.start, "from", 4) != 0)
{
- zpanic("Expected 'from' after selective import list, got type=%d", from_tok.type);
+ zpanic_at(from_tok, "Expected 'from' after selective import list, got type=%d",
+ from_tok.type);
}
}
@@ -3645,9 +3647,10 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_STRING)
{
- zpanic("Expected string (filename) after 'from' in selective import, got "
- "type %d",
- t.type);
+ zpanic_at(t,
+ "Expected string (filename) after 'from' in selective import, got "
+ "type %d",
+ t.type);
}
int ln = t.len - 2; // Remove quotes
char *fn = xmalloc(ln + 1);
@@ -3737,7 +3740,7 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token alias_tok = lexer_next(l);
if (alias_tok.type != TOK_IDENT)
{
- zpanic("Expected identifier after 'as'");
+ zpanic_at(alias_tok, "Expected identifier after 'as'");
}
alias = xmalloc(alias_tok.len + 1);
@@ -3767,19 +3770,6 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
// C Header: Emit include and return (don't parse)
if (strlen(fn) > 2 && strcmp(fn + strlen(fn) - 2, ".h") == 0)
{
- // We can iterate over registered modules to check if we missed setting
- // is_c_header? But we handled 'as' above. If no 'as', we need to check if
- // we should register it? Usually 'import "foo.h" as f' is required for
- // namespacing.
-
- // Emit #include
- // TODO: Where to emit? parser doesn't emit code usually.
- // Actually, we can just return a NODE_INCLUDE AST!
- // But wait, the user wants 'import as alias'.
-
- // If we return NULL, nothing happens.
- // Use NODE_INCLUDE to ensure it gets emitted.
-
ASTNode *n = ast_create(NODE_INCLUDE);
n->include.path = xstrdup(fn); // Store exact path
n->include.is_system = 0; // Double quotes
@@ -3790,7 +3780,7 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
char *src = load_file(fn);
if (!src)
{
- zpanic("Not found: %s", fn);
+ zpanic_at(t, "Not found: %s", fn);
}
Lexer i;
@@ -3869,7 +3859,7 @@ char *run_comptime_block(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type == TOK_EOF)
{
- zpanic("Unexpected EOF in comptime block");
+ zpanic_at(t, "Unexpected EOF in comptime block");
}
if (t.type == TOK_LBRACE)
{
@@ -3909,7 +3899,7 @@ char *run_comptime_block(ParserContext *ctx, Lexer *l)
FILE *f = fopen(filename, "w");
if (!f)
{
- zpanic("Could not create temp file %s", filename);
+ zpanic_at(lexer_peek(l), "Could not create temp file %s", filename);
}
emit_preamble(ctx, f);
@@ -3992,7 +3982,7 @@ char *run_comptime_block(ParserContext *ctx, Lexer *l)
int res = system(cmd);
if (res != 0)
{
- zpanic("Comptime compilation failed for:\n%s", code);
+ zpanic_at(lexer_peek(l), "Comptime compilation failed for:\n%s", code);
}
char out_file[1024];
@@ -4000,7 +3990,7 @@ char *run_comptime_block(ParserContext *ctx, Lexer *l)
sprintf(cmd, "./%s > %s", bin, out_file);
if (system(cmd) != 0)
{
- zpanic("Comptime execution failed");
+ zpanic_at(lexer_peek(l), "Comptime execution failed");
}
char *output_src = load_file(out_file);
@@ -4037,7 +4027,7 @@ ASTNode *parse_plugin(ParserContext *ctx, Lexer *l)
Token tk = lexer_next(l);
if (tk.type != TOK_IDENT)
{
- zpanic("Expected plugin name after 'plugin' keyword");
+ zpanic_at(tk, "Expected plugin name after 'plugin' keyword");
}
// Extract plugin name
@@ -4055,7 +4045,7 @@ ASTNode *parse_plugin(ParserContext *ctx, Lexer *l)
Token t = lexer_peek(l);
if (t.type == TOK_EOF)
{
- zpanic("Unexpected EOF in plugin block, expected 'end'");
+ zpanic_at(t, "Unexpected EOF in plugin block, expected 'end'");
}
// Check for 'end'
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index cc33d99..d39e498 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -399,7 +399,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
}
char *arg_str = type_to_string(arg);
- instantiate_generic(ctx, name, arg_str);
+ instantiate_generic(ctx, name, arg_str, t);
char *clean_arg = sanitize_mangled_name(arg_str);
char mangled[256];
@@ -455,7 +455,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RBRACKET)
{
- zpanic("Expected ] after array size");
+ zpanic_at(lexer_peek(l), "Expected ] after array size");
}
Type *arr = type_new(TYPE_ARRAY);
@@ -467,7 +467,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
// Otherwise it's a slice [T]
if (lexer_next(l).type != TOK_RBRACKET)
{
- zpanic("Expected ] in type");
+ zpanic_at(lexer_peek(l), "Expected ] in type");
}
// Register Slice
@@ -505,7 +505,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ) in tuple");
+ zpanic_at(lexer_peek(l), "Expected ) in tuple");
}
register_tuple(ctx, sig);
@@ -773,7 +773,7 @@ char *parse_embed(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_STRING)
{
- zpanic("String required");
+ zpanic_at(t, "String required");
}
char fn[256];
strncpy(fn, t.start + 1, t.len - 2);
@@ -782,7 +782,7 @@ char *parse_embed(ParserContext *ctx, Lexer *l)
FILE *f = fopen(fn, "rb");
if (!f)
{
- zpanic("404: %s", fn);
+ zpanic_at(t, "404: %s", fn);
}
fseek(f, 0, SEEK_END);
long len = ftell(f);
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index ba506a0..7af8d62 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1761,7 +1761,7 @@ ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, const char *
if (found)
{
- instantiate_generic(ctx, template_name, concrete_arg);
+ instantiate_generic(ctx, template_name, concrete_arg, fields->token);
}
}
free(type_copy);
@@ -1819,7 +1819,7 @@ void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it,
if (strcmp(gt->name, template_name) == 0)
{
// Found matching template, instantiate it
- instantiate_generic(ctx, template_name, arg);
+ instantiate_generic(ctx, template_name, arg, meth->token);
break;
}
gt = gt->next;
@@ -1833,7 +1833,7 @@ void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it,
add_instantiated_func(ctx, new_impl);
}
-void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg)
+void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg, Token token)
{
// Ignore generic placeholders
if (strlen(arg) == 1 && isupper(arg[0]))
@@ -1871,7 +1871,7 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg)
}
if (!t)
{
- zpanic("Unknown generic: %s", tpl);
+ zpanic_at(token, "Unknown generic: %s", tpl);
}
Instantiation *ni = xmalloc(sizeof(Instantiation));
@@ -1981,7 +1981,7 @@ char *parse_condition_raw(ParserContext *ctx, Lexer *l)
t = lexer_next(l);
if (t.type == TOK_EOF)
{
- zpanic("Unterminated condition");
+ zpanic_at(t, "Unterminated condition");
}
if (t.type == TOK_LPAREN)
{
@@ -2014,7 +2014,7 @@ char *parse_condition_raw(ParserContext *ctx, Lexer *l)
int len = (l->src + l->pos) - start;
if (len == 0)
{
- zpanic("Empty condition or missing body");
+ zpanic_at(lexer_peek(l), "Empty condition or missing body");
}
char *c = xmalloc(len + 1);
strncpy(c, start, len);
@@ -2340,9 +2340,10 @@ char *consume_and_rewrite(ParserContext *ctx, Lexer *l)
char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out, int *count_out,
Type ***types_out, char ***names_out, int *is_varargs_out)
{
- if (lexer_next(l).type != TOK_LPAREN)
+ Token t = lexer_next(l);
+ if (t.type != TOK_LPAREN)
{
- zpanic("Expected '(' in function args");
+ zpanic_at(t, "Expected '(' in function args");
}
char *buf = xmalloc(1024);
@@ -2421,13 +2422,13 @@ char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out,
{
if (t.type != TOK_IDENT)
{
- zpanic("Expected arg name");
+ zpanic_at(lexer_peek(l), "Expected arg name");
}
char *name = token_strdup(t);
names[count] = name; // Store name
if (lexer_next(l).type != TOK_COLON)
{
- zpanic("Expected ':'");
+ zpanic_at(lexer_peek(l), "Expected ':'");
}
Type *arg_type = parse_type_formal(ctx, l);
@@ -2500,7 +2501,7 @@ char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out,
}
if (lexer_next(l).type != TOK_RPAREN)
{
- zpanic("Expected ')' after args");
+ zpanic_at(lexer_peek(l), "Expected ')' after args");
}
*defaults_out = defaults;