mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-18 12:30:28 +00:00
Add range-based error messages to -verbose-errors
Example: Cannot convert '(1 + 2)' to 'untyped bool' from 'untyped integer' x := (1 + 2) * true; ^~~~~~^
This commit is contained in:
@@ -87,7 +87,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
case BuiltinProc_DIRECTIVE: {
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name;
|
||||
String name = bd->name.string;
|
||||
if (name == "defined") {
|
||||
break;
|
||||
}
|
||||
@@ -124,7 +124,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
case BuiltinProc_DIRECTIVE: {
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name;
|
||||
String name = bd->name.string;
|
||||
if (name == "location") {
|
||||
if (ce->args.count > 1) {
|
||||
error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count);
|
||||
|
||||
@@ -5516,7 +5516,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr
|
||||
if (proc != nullptr &&
|
||||
proc->kind == Ast_BasicDirective) {
|
||||
ast_node(bd, BasicDirective, proc);
|
||||
String name = bd->name;
|
||||
String name = bd->name.string;
|
||||
if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "config" || name == "load") {
|
||||
operand->mode = Addressing_Builtin;
|
||||
operand->builtin_id = BuiltinProc_DIRECTIVE;
|
||||
@@ -6191,13 +6191,14 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
|
||||
case_ast_node(bd, BasicDirective, node);
|
||||
o->mode = Addressing_Constant;
|
||||
if (bd->name == "file") {
|
||||
String name = bd->name.string;
|
||||
if (name == "file") {
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(get_file_path_string(bd->token.pos.file_id));
|
||||
} else if (bd->name == "line") {
|
||||
} else if (name == "line") {
|
||||
o->type = t_untyped_integer;
|
||||
o->value = exact_value_i64(bd->token.pos.line);
|
||||
} else if (bd->name == "procedure") {
|
||||
} else if (name == "procedure") {
|
||||
if (c->curr_proc_decl == nullptr) {
|
||||
error(node, "#procedure may only be used within procedures");
|
||||
o->type = t_untyped_string;
|
||||
@@ -6206,7 +6207,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(c->proc_name);
|
||||
}
|
||||
} else if (bd->name == "caller_location") {
|
||||
} else if (name == "caller_location") {
|
||||
init_core_source_code_location(c->checker);
|
||||
error(node, "#caller_location may only be used as a default argument parameter");
|
||||
o->type = t_source_code_location;
|
||||
@@ -6373,7 +6374,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
if (cl->type->ArrayType.tag != nullptr) {
|
||||
Ast *tag = cl->type->ArrayType.tag;
|
||||
GB_ASSERT(tag->kind == Ast_BasicDirective);
|
||||
String name = tag->BasicDirective.name;
|
||||
String name = tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
error(node, "#soa arrays are not supported for compound literals");
|
||||
return kind;
|
||||
@@ -6385,7 +6386,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
if (cl->elems.count > 0) {
|
||||
Ast *tag = cl->type->DynamicArrayType.tag;
|
||||
GB_ASSERT(tag->kind == Ast_BasicDirective);
|
||||
String name = tag->BasicDirective.name;
|
||||
String name = tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
error(node, "#soa arrays are not supported for compound literals");
|
||||
return kind;
|
||||
@@ -8151,7 +8152,7 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
|
||||
|
||||
case_ast_node(bd, BasicDirective, node);
|
||||
str = gb_string_append_rune(str, '#');
|
||||
str = string_append_string(str, bd->name);
|
||||
str = string_append_string(str, bd->name.string);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ud, Undef, node);
|
||||
|
||||
@@ -7,7 +7,7 @@ bool is_diverging_stmt(Ast *stmt) {
|
||||
return false;
|
||||
}
|
||||
if (expr->CallExpr.proc->kind == Ast_BasicDirective) {
|
||||
String name = expr->CallExpr.proc->BasicDirective.name;
|
||||
String name = expr->CallExpr.proc->BasicDirective.name.string;
|
||||
return name == "panic";
|
||||
}
|
||||
Ast *proc = unparen_expr(expr->CallExpr.proc);
|
||||
|
||||
@@ -1191,7 +1191,7 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type *
|
||||
|
||||
if (allow_caller_location &&
|
||||
expr->kind == Ast_BasicDirective &&
|
||||
expr->BasicDirective.name == "caller_location") {
|
||||
expr->BasicDirective.name.string == "caller_location") {
|
||||
init_core_source_code_location(ctx->checker);
|
||||
param_value.kind = ParameterValue_Location;
|
||||
o.type = t_source_code_location;
|
||||
@@ -2711,7 +2711,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
bool is_partial = false;
|
||||
if (at->tag != nullptr) {
|
||||
GB_ASSERT(at->tag->kind == Ast_BasicDirective);
|
||||
String name = at->tag->BasicDirective.name;
|
||||
String name = at->tag->BasicDirective.name.string;
|
||||
if (name == "partial") {
|
||||
is_partial = true;
|
||||
} else {
|
||||
@@ -2745,7 +2745,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
|
||||
if (at->tag != nullptr) {
|
||||
GB_ASSERT(at->tag->kind == Ast_BasicDirective);
|
||||
String name = at->tag->BasicDirective.name;
|
||||
String name = at->tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
*type = make_soa_struct_fixed(ctx, e, at->elem, elem, count, generic_type);
|
||||
} else if (name == "simd") {
|
||||
@@ -2770,7 +2770,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
|
||||
if (at->tag != nullptr) {
|
||||
GB_ASSERT(at->tag->kind == Ast_BasicDirective);
|
||||
String name = at->tag->BasicDirective.name;
|
||||
String name = at->tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
*type = make_soa_struct_slice(ctx, e, at->elem, elem);
|
||||
} else {
|
||||
@@ -2790,7 +2790,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
Type *elem = check_type(ctx, dat->elem);
|
||||
if (dat->tag != nullptr) {
|
||||
GB_ASSERT(dat->tag->kind == Ast_BasicDirective);
|
||||
String name = dat->tag->BasicDirective.name;
|
||||
String name = dat->tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
*type = make_soa_struct_dynamic_array(ctx, e, dat->elem, elem);
|
||||
} else {
|
||||
|
||||
@@ -8887,7 +8887,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
||||
switch (id) {
|
||||
case BuiltinProc_DIRECTIVE: {
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name;
|
||||
String name = bd->name.string;
|
||||
GB_ASSERT(name == "location");
|
||||
String procedure = p->entity->token.string;
|
||||
TokenPos pos = ast_token(ce->proc).pos;
|
||||
@@ -11515,7 +11515,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
|
||||
case_ast_node(bd, BasicDirective, expr);
|
||||
TokenPos pos = bd->token.pos;
|
||||
GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name));
|
||||
GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string));
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Implicit, expr);
|
||||
|
||||
158
src/parser.cpp
158
src/parser.cpp
@@ -1,109 +1,4 @@
|
||||
Token ast_token(Ast *node) {
|
||||
switch (node->kind) {
|
||||
case Ast_Ident: return node->Ident.token;
|
||||
case Ast_Implicit: return node->Implicit;
|
||||
case Ast_Undef: return node->Undef;
|
||||
case Ast_BasicLit: return node->BasicLit.token;
|
||||
case Ast_BasicDirective: return node->BasicDirective.token;
|
||||
case Ast_ProcGroup: return node->ProcGroup.token;
|
||||
case Ast_ProcLit: return ast_token(node->ProcLit.type);
|
||||
case Ast_CompoundLit:
|
||||
if (node->CompoundLit.type != nullptr) {
|
||||
return ast_token(node->CompoundLit.type);
|
||||
}
|
||||
return node->CompoundLit.open;
|
||||
|
||||
case Ast_TagExpr: return node->TagExpr.token;
|
||||
case Ast_BadExpr: return node->BadExpr.begin;
|
||||
case Ast_UnaryExpr: return node->UnaryExpr.op;
|
||||
case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left);
|
||||
case Ast_ParenExpr: return node->ParenExpr.open;
|
||||
case Ast_CallExpr: return ast_token(node->CallExpr.proc);
|
||||
case Ast_SelectorExpr:
|
||||
if (node->SelectorExpr.selector != nullptr) {
|
||||
return ast_token(node->SelectorExpr.selector);
|
||||
}
|
||||
return node->SelectorExpr.token;
|
||||
case Ast_SelectorCallExpr:
|
||||
if (node->SelectorCallExpr.expr != nullptr) {
|
||||
return ast_token(node->SelectorCallExpr.expr);
|
||||
}
|
||||
return node->SelectorCallExpr.token;
|
||||
case Ast_ImplicitSelectorExpr:
|
||||
if (node->ImplicitSelectorExpr.selector != nullptr) {
|
||||
return ast_token(node->ImplicitSelectorExpr.selector);
|
||||
}
|
||||
return node->ImplicitSelectorExpr.token;
|
||||
case Ast_IndexExpr: return node->IndexExpr.open;
|
||||
case Ast_SliceExpr: return node->SliceExpr.open;
|
||||
case Ast_Ellipsis: return node->Ellipsis.token;
|
||||
case Ast_FieldValue: return node->FieldValue.eq;
|
||||
case Ast_DerefExpr: return node->DerefExpr.op;
|
||||
case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x);
|
||||
case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x);
|
||||
case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr);
|
||||
case Ast_TypeCast: return node->TypeCast.token;
|
||||
case Ast_AutoCast: return node->AutoCast.token;
|
||||
case Ast_InlineAsmExpr: return node->InlineAsmExpr.token;
|
||||
|
||||
case Ast_BadStmt: return node->BadStmt.begin;
|
||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||
case Ast_ExprStmt: return ast_token(node->ExprStmt.expr);
|
||||
case Ast_TagStmt: return node->TagStmt.token;
|
||||
case Ast_AssignStmt: return node->AssignStmt.op;
|
||||
case Ast_BlockStmt: return node->BlockStmt.open;
|
||||
case Ast_IfStmt: return node->IfStmt.token;
|
||||
case Ast_WhenStmt: return node->WhenStmt.token;
|
||||
case Ast_ReturnStmt: return node->ReturnStmt.token;
|
||||
case Ast_ForStmt: return node->ForStmt.token;
|
||||
case Ast_RangeStmt: return node->RangeStmt.token;
|
||||
case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token;
|
||||
case Ast_CaseClause: return node->CaseClause.token;
|
||||
case Ast_SwitchStmt: return node->SwitchStmt.token;
|
||||
case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
|
||||
case Ast_DeferStmt: return node->DeferStmt.token;
|
||||
case Ast_BranchStmt: return node->BranchStmt.token;
|
||||
case Ast_UsingStmt: return node->UsingStmt.token;
|
||||
|
||||
case Ast_BadDecl: return node->BadDecl.begin;
|
||||
case Ast_Label: return node->Label.token;
|
||||
|
||||
case Ast_ValueDecl: return ast_token(node->ValueDecl.names[0]);
|
||||
case Ast_PackageDecl: return node->PackageDecl.token;
|
||||
case Ast_ImportDecl: return node->ImportDecl.token;
|
||||
case Ast_ForeignImportDecl: return node->ForeignImportDecl.token;
|
||||
|
||||
case Ast_ForeignBlockDecl: return node->ForeignBlockDecl.token;
|
||||
|
||||
case Ast_Attribute:
|
||||
return node->Attribute.token;
|
||||
|
||||
case Ast_Field:
|
||||
if (node->Field.names.count > 0) {
|
||||
return ast_token(node->Field.names[0]);
|
||||
}
|
||||
return ast_token(node->Field.type);
|
||||
case Ast_FieldList:
|
||||
return node->FieldList.token;
|
||||
|
||||
case Ast_TypeidType: return node->TypeidType.token;
|
||||
case Ast_HelperType: return node->HelperType.token;
|
||||
case Ast_DistinctType: return node->DistinctType.token;
|
||||
case Ast_PolyType: return node->PolyType.token;
|
||||
case Ast_ProcType: return node->ProcType.token;
|
||||
case Ast_RelativeType: return ast_token(node->RelativeType.tag);
|
||||
case Ast_PointerType: return node->PointerType.token;
|
||||
case Ast_ArrayType: return node->ArrayType.token;
|
||||
case Ast_DynamicArrayType: return node->DynamicArrayType.token;
|
||||
case Ast_StructType: return node->StructType.token;
|
||||
case Ast_UnionType: return node->UnionType.token;
|
||||
case Ast_EnumType: return node->EnumType.token;
|
||||
case Ast_BitSetType: return node->BitSetType.token;
|
||||
case Ast_MapType: return node->MapType.token;
|
||||
}
|
||||
|
||||
return empty_token;
|
||||
}
|
||||
#include "parser_pos.cpp"
|
||||
|
||||
Token token_end_of_line(AstFile *f, Token tok) {
|
||||
u8 const *start = f->tokenizer.start + tok.pos.offset;
|
||||
@@ -474,12 +369,15 @@ Ast *clone_ast(Ast *node) {
|
||||
|
||||
void error(Ast *node, char const *fmt, ...) {
|
||||
Token token = {};
|
||||
TokenPos end_pos = {};
|
||||
if (node != nullptr) {
|
||||
token = ast_token(node);
|
||||
end_pos = ast_end_pos(node);
|
||||
}
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
error_va(token.pos, fmt, va);
|
||||
error_va(token.pos, end_pos, fmt, va);
|
||||
va_end(va);
|
||||
if (node != nullptr && node->file != nullptr) {
|
||||
node->file->error_count += 1;
|
||||
@@ -501,16 +399,28 @@ void error_no_newline(Ast *node, char const *fmt, ...) {
|
||||
}
|
||||
|
||||
void warning(Ast *node, char const *fmt, ...) {
|
||||
Token token = {};
|
||||
TokenPos end_pos = {};
|
||||
if (node != nullptr) {
|
||||
token = ast_token(node);
|
||||
end_pos = ast_end_pos(node);
|
||||
}
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
warning_va(ast_token(node).pos, fmt, va);
|
||||
warning_va(token.pos, end_pos, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_error(Ast *node, char const *fmt, ...) {
|
||||
Token token = {};
|
||||
TokenPos end_pos = {};
|
||||
if (node != nullptr) {
|
||||
token = ast_token(node);
|
||||
end_pos = ast_end_pos(node);
|
||||
}
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_error_va(ast_token(node).pos, fmt, va);
|
||||
syntax_error_va(token.pos, end_pos, fmt, va);
|
||||
va_end(va);
|
||||
if (node != nullptr && node->file != nullptr) {
|
||||
node->file->error_count += 1;
|
||||
@@ -682,7 +592,7 @@ Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_basic_directive(AstFile *f, Token token, String name) {
|
||||
Ast *ast_basic_directive(AstFile *f, Token token, Token name) {
|
||||
Ast *result = alloc_ast_node(f, Ast_BasicDirective);
|
||||
result->BasicDirective.token = token;
|
||||
result->BasicDirective.name = name;
|
||||
@@ -2042,27 +1952,27 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
if (name.string == "type") {
|
||||
return ast_helper_type(f, token, parse_type(f));
|
||||
} else if (name.string == "file") {
|
||||
return ast_basic_directive(f, token, name.string);
|
||||
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
|
||||
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
|
||||
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
|
||||
return ast_basic_directive(f, token, name);
|
||||
} else if (name.string == "line") { return ast_basic_directive(f, token, name);
|
||||
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name);
|
||||
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name);
|
||||
} else if (name.string == "location") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
return parse_call_expr(f, tag);
|
||||
} else if (name.string == "load") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
return parse_call_expr(f, tag);
|
||||
} else if (name.string == "assert") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
return parse_call_expr(f, tag);
|
||||
} else if (name.string == "defined") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
return parse_call_expr(f, tag);
|
||||
} else if (name.string == "config") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
return parse_call_expr(f, tag);
|
||||
} else if (name.string == "soa" || name.string == "simd") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
Ast *original_type = parse_type(f);
|
||||
Ast *type = unparen_expr(original_type);
|
||||
switch (type->kind) {
|
||||
@@ -2074,7 +1984,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
}
|
||||
return original_type;
|
||||
} else if (name.string == "partial") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
Ast *original_type = parse_type(f);
|
||||
Ast *type = unparen_expr(original_type);
|
||||
switch (type->kind) {
|
||||
@@ -2107,7 +2017,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
}
|
||||
return operand;
|
||||
} else if (name.string == "relative") {
|
||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
tag = parse_call_expr(f, tag);
|
||||
Ast *type = parse_type(f);
|
||||
return ast_relative_type(f, tag, type);
|
||||
@@ -4554,10 +4464,10 @@ Ast *parse_stmt(AstFile *f) {
|
||||
}
|
||||
return s;
|
||||
} else if (tag == "assert") {
|
||||
Ast *t = ast_basic_directive(f, hash_token, tag);
|
||||
Ast *t = ast_basic_directive(f, hash_token, name);
|
||||
return ast_expr_stmt(f, parse_call_expr(f, t));
|
||||
} else if (tag == "panic") {
|
||||
Ast *t = ast_basic_directive(f, hash_token, tag);
|
||||
Ast *t = ast_basic_directive(f, hash_token, name);
|
||||
return ast_expr_stmt(f, parse_call_expr(f, t));
|
||||
} else if (name.string == "force_inline" ||
|
||||
name.string == "force_no_inline") {
|
||||
|
||||
@@ -286,8 +286,8 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
Token token; \
|
||||
}) \
|
||||
AST_KIND(BasicDirective, "basic directive", struct { \
|
||||
Token token; \
|
||||
String name; \
|
||||
Token token; \
|
||||
Token name; \
|
||||
}) \
|
||||
AST_KIND(Ellipsis, "ellipsis", struct { \
|
||||
Token token; \
|
||||
@@ -324,7 +324,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
||||
AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \
|
||||
AST_KIND(SelectorCallExpr, "selector call expression", struct { Token token; Ast *expr, *call; bool modified_call; }) \
|
||||
AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \
|
||||
AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \
|
||||
AST_KIND(DerefExpr, "dereference expression", struct { Ast *expr; Token op; }) \
|
||||
AST_KIND(SliceExpr, "slice expression", struct { \
|
||||
Ast *expr; \
|
||||
Token open, close; \
|
||||
|
||||
331
src/parser_pos.cpp
Normal file
331
src/parser_pos.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
Token ast_token(Ast *node) {
|
||||
switch (node->kind) {
|
||||
case Ast_Ident: return node->Ident.token;
|
||||
case Ast_Implicit: return node->Implicit;
|
||||
case Ast_Undef: return node->Undef;
|
||||
case Ast_BasicLit: return node->BasicLit.token;
|
||||
case Ast_BasicDirective: return node->BasicDirective.token;
|
||||
case Ast_ProcGroup: return node->ProcGroup.token;
|
||||
case Ast_ProcLit: return ast_token(node->ProcLit.type);
|
||||
case Ast_CompoundLit:
|
||||
if (node->CompoundLit.type != nullptr) {
|
||||
return ast_token(node->CompoundLit.type);
|
||||
}
|
||||
return node->CompoundLit.open;
|
||||
|
||||
case Ast_TagExpr: return node->TagExpr.token;
|
||||
case Ast_BadExpr: return node->BadExpr.begin;
|
||||
case Ast_UnaryExpr: return node->UnaryExpr.op;
|
||||
case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left);
|
||||
case Ast_ParenExpr: return node->ParenExpr.open;
|
||||
case Ast_CallExpr: return ast_token(node->CallExpr.proc);
|
||||
case Ast_SelectorExpr:
|
||||
if (node->SelectorExpr.selector != nullptr) {
|
||||
return ast_token(node->SelectorExpr.selector);
|
||||
}
|
||||
return node->SelectorExpr.token;
|
||||
case Ast_SelectorCallExpr:
|
||||
if (node->SelectorCallExpr.expr != nullptr) {
|
||||
return ast_token(node->SelectorCallExpr.expr);
|
||||
}
|
||||
return node->SelectorCallExpr.token;
|
||||
case Ast_ImplicitSelectorExpr:
|
||||
if (node->ImplicitSelectorExpr.selector != nullptr) {
|
||||
return ast_token(node->ImplicitSelectorExpr.selector);
|
||||
}
|
||||
return node->ImplicitSelectorExpr.token;
|
||||
case Ast_IndexExpr: return node->IndexExpr.open;
|
||||
case Ast_SliceExpr: return node->SliceExpr.open;
|
||||
case Ast_Ellipsis: return node->Ellipsis.token;
|
||||
case Ast_FieldValue: return node->FieldValue.eq;
|
||||
case Ast_DerefExpr: return node->DerefExpr.op;
|
||||
case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x);
|
||||
case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x);
|
||||
case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr);
|
||||
case Ast_TypeCast: return node->TypeCast.token;
|
||||
case Ast_AutoCast: return node->AutoCast.token;
|
||||
case Ast_InlineAsmExpr: return node->InlineAsmExpr.token;
|
||||
|
||||
case Ast_BadStmt: return node->BadStmt.begin;
|
||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||
case Ast_ExprStmt: return ast_token(node->ExprStmt.expr);
|
||||
case Ast_TagStmt: return node->TagStmt.token;
|
||||
case Ast_AssignStmt: return node->AssignStmt.op;
|
||||
case Ast_BlockStmt: return node->BlockStmt.open;
|
||||
case Ast_IfStmt: return node->IfStmt.token;
|
||||
case Ast_WhenStmt: return node->WhenStmt.token;
|
||||
case Ast_ReturnStmt: return node->ReturnStmt.token;
|
||||
case Ast_ForStmt: return node->ForStmt.token;
|
||||
case Ast_RangeStmt: return node->RangeStmt.token;
|
||||
case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token;
|
||||
case Ast_CaseClause: return node->CaseClause.token;
|
||||
case Ast_SwitchStmt: return node->SwitchStmt.token;
|
||||
case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
|
||||
case Ast_DeferStmt: return node->DeferStmt.token;
|
||||
case Ast_BranchStmt: return node->BranchStmt.token;
|
||||
case Ast_UsingStmt: return node->UsingStmt.token;
|
||||
|
||||
case Ast_BadDecl: return node->BadDecl.begin;
|
||||
case Ast_Label: return node->Label.token;
|
||||
|
||||
case Ast_ValueDecl: return ast_token(node->ValueDecl.names[0]);
|
||||
case Ast_PackageDecl: return node->PackageDecl.token;
|
||||
case Ast_ImportDecl: return node->ImportDecl.token;
|
||||
case Ast_ForeignImportDecl: return node->ForeignImportDecl.token;
|
||||
|
||||
case Ast_ForeignBlockDecl: return node->ForeignBlockDecl.token;
|
||||
|
||||
case Ast_Attribute:
|
||||
return node->Attribute.token;
|
||||
|
||||
case Ast_Field:
|
||||
if (node->Field.names.count > 0) {
|
||||
return ast_token(node->Field.names[0]);
|
||||
}
|
||||
return ast_token(node->Field.type);
|
||||
case Ast_FieldList:
|
||||
return node->FieldList.token;
|
||||
|
||||
case Ast_TypeidType: return node->TypeidType.token;
|
||||
case Ast_HelperType: return node->HelperType.token;
|
||||
case Ast_DistinctType: return node->DistinctType.token;
|
||||
case Ast_PolyType: return node->PolyType.token;
|
||||
case Ast_ProcType: return node->ProcType.token;
|
||||
case Ast_RelativeType: return ast_token(node->RelativeType.tag);
|
||||
case Ast_PointerType: return node->PointerType.token;
|
||||
case Ast_ArrayType: return node->ArrayType.token;
|
||||
case Ast_DynamicArrayType: return node->DynamicArrayType.token;
|
||||
case Ast_StructType: return node->StructType.token;
|
||||
case Ast_UnionType: return node->UnionType.token;
|
||||
case Ast_EnumType: return node->EnumType.token;
|
||||
case Ast_BitSetType: return node->BitSetType.token;
|
||||
case Ast_MapType: return node->MapType.token;
|
||||
}
|
||||
|
||||
return empty_token;
|
||||
}
|
||||
|
||||
TokenPos token_pos_end(Token const &token) {
|
||||
TokenPos pos = token.pos;
|
||||
pos.offset += cast(i32)token.string.len;
|
||||
for (isize i = 0; i < token.string.len; i++) {
|
||||
// TODO(bill): This assumes ASCII
|
||||
char c = token.string[i];
|
||||
if (c == '\n') {
|
||||
pos.line += 1;
|
||||
pos.column = 1;
|
||||
} else {
|
||||
pos.column += 1;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
Token ast_end_token(Ast *node) {
|
||||
GB_ASSERT(node != nullptr);
|
||||
|
||||
switch (node->kind) {
|
||||
case Ast_Ident: return node->Ident.token;
|
||||
case Ast_Implicit: return node->Implicit;
|
||||
case Ast_Undef: return node->Undef;
|
||||
case Ast_BasicLit: return node->BasicLit.token;
|
||||
case Ast_BasicDirective: return node->BasicDirective.token;
|
||||
case Ast_ProcGroup: return node->ProcGroup.close;
|
||||
case Ast_ProcLit:
|
||||
if (node->ProcLit.body) {
|
||||
return ast_end_token(node->ProcLit.body);
|
||||
}
|
||||
return ast_end_token(node->ProcLit.type);
|
||||
case Ast_CompoundLit:
|
||||
return node->CompoundLit.close;
|
||||
|
||||
case Ast_BadExpr: return node->BadExpr.end;
|
||||
case Ast_TagExpr: return ast_end_token(node->TagExpr.expr);
|
||||
case Ast_UnaryExpr: return ast_end_token(node->UnaryExpr.expr);
|
||||
case Ast_BinaryExpr: return ast_end_token(node->BinaryExpr.right);
|
||||
case Ast_ParenExpr: return node->ParenExpr.close;
|
||||
case Ast_CallExpr: return node->CallExpr.close;
|
||||
case Ast_SelectorExpr:
|
||||
return ast_end_token(node->SelectorExpr.selector);
|
||||
case Ast_SelectorCallExpr:
|
||||
return ast_end_token(node->SelectorCallExpr.call);
|
||||
case Ast_ImplicitSelectorExpr:
|
||||
return ast_end_token(node->SelectorExpr.selector);
|
||||
case Ast_IndexExpr: return node->IndexExpr.close;
|
||||
case Ast_SliceExpr: return node->SliceExpr.close;
|
||||
case Ast_Ellipsis:
|
||||
if (node->Ellipsis.expr) {
|
||||
return ast_end_token(node->Ellipsis.expr);
|
||||
}
|
||||
return node->Ellipsis.token;
|
||||
case Ast_FieldValue: return ast_end_token(node->FieldValue.value);
|
||||
case Ast_DerefExpr: return node->DerefExpr.op;
|
||||
case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y);
|
||||
case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y);
|
||||
case Ast_TypeAssertion: return ast_end_token(node->TypeAssertion.type);
|
||||
case Ast_TypeCast: return ast_end_token(node->TypeCast.expr);
|
||||
case Ast_AutoCast: return ast_end_token(node->AutoCast.expr);
|
||||
case Ast_InlineAsmExpr: return node->InlineAsmExpr.close;
|
||||
|
||||
case Ast_BadStmt: return node->BadStmt.end;
|
||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||
case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr);
|
||||
case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt);
|
||||
case Ast_AssignStmt:
|
||||
if (node->AssignStmt.rhs.count > 0) {
|
||||
return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]);
|
||||
}
|
||||
return node->AssignStmt.op;
|
||||
case Ast_BlockStmt: return node->BlockStmt.close;
|
||||
case Ast_IfStmt:
|
||||
if (node->IfStmt.else_stmt) {
|
||||
return ast_end_token(node->IfStmt.else_stmt);
|
||||
}
|
||||
return ast_end_token(node->IfStmt.body);
|
||||
case Ast_WhenStmt:
|
||||
if (node->WhenStmt.else_stmt) {
|
||||
return ast_end_token(node->WhenStmt.else_stmt);
|
||||
}
|
||||
return ast_end_token(node->WhenStmt.body);
|
||||
case Ast_ReturnStmt:
|
||||
if (node->ReturnStmt.results.count > 0) {
|
||||
return ast_end_token(node->ReturnStmt.results[node->ReturnStmt.results.count-1]);
|
||||
}
|
||||
return node->ReturnStmt.token;
|
||||
case Ast_ForStmt: return ast_end_token(node->ForStmt.body);
|
||||
case Ast_RangeStmt: return ast_end_token(node->RangeStmt.body);
|
||||
case Ast_UnrollRangeStmt: return ast_end_token(node->UnrollRangeStmt.body);
|
||||
case Ast_CaseClause:
|
||||
if (node->CaseClause.stmts.count) {
|
||||
return ast_end_token(node->CaseClause.stmts[node->CaseClause.stmts.count-1]);
|
||||
} else if (node->CaseClause.list.count) {
|
||||
return ast_end_token(node->CaseClause.list[node->CaseClause.list.count-1]);
|
||||
}
|
||||
return node->CaseClause.token;
|
||||
case Ast_SwitchStmt: return ast_end_token(node->SwitchStmt.body);
|
||||
case Ast_TypeSwitchStmt: return ast_end_token(node->TypeSwitchStmt.body);
|
||||
case Ast_DeferStmt: return ast_end_token(node->DeferStmt.stmt);
|
||||
case Ast_BranchStmt:
|
||||
if (node->BranchStmt.label) {
|
||||
return ast_end_token(node->BranchStmt.label);
|
||||
}
|
||||
return node->BranchStmt.token;
|
||||
case Ast_UsingStmt:
|
||||
if (node->UsingStmt.list.count > 0) {
|
||||
return ast_end_token(node->UsingStmt.list[node->UsingStmt.list.count-1]);
|
||||
}
|
||||
return node->UsingStmt.token;
|
||||
|
||||
case Ast_BadDecl: return node->BadDecl.end;
|
||||
case Ast_Label:
|
||||
if (node->Label.name) {
|
||||
return ast_end_token(node->Label.name);
|
||||
}
|
||||
return node->Label.token;
|
||||
|
||||
case Ast_ValueDecl:
|
||||
if (node->ValueDecl.values.count > 0) {
|
||||
return ast_end_token(node->ValueDecl.values[node->ValueDecl.values.count-1]);
|
||||
}
|
||||
if (node->ValueDecl.type) {
|
||||
return ast_end_token(node->ValueDecl.type);
|
||||
}
|
||||
if (node->ValueDecl.names.count > 0) {
|
||||
return ast_end_token(node->ValueDecl.names[node->ValueDecl.names.count-1]);
|
||||
}
|
||||
return {};
|
||||
|
||||
case Ast_PackageDecl: return node->PackageDecl.name;
|
||||
case Ast_ImportDecl: return node->ImportDecl.relpath;
|
||||
case Ast_ForeignImportDecl:
|
||||
if (node->ForeignImportDecl.filepaths.count > 0) {
|
||||
return node->ForeignImportDecl.filepaths[node->ForeignImportDecl.filepaths.count-1];
|
||||
}
|
||||
if (node->ForeignImportDecl.library_name.kind != Token_Invalid) {
|
||||
return node->ForeignImportDecl.library_name;
|
||||
}
|
||||
return node->ForeignImportDecl.token;
|
||||
|
||||
case Ast_ForeignBlockDecl:
|
||||
return ast_end_token(node->ForeignBlockDecl.body);
|
||||
|
||||
case Ast_Attribute:
|
||||
if (node->Attribute.close.kind != Token_Invalid) {
|
||||
return node->Attribute.close;
|
||||
}
|
||||
return ast_end_token(node->Attribute.elems[node->Attribute.elems.count-1]);
|
||||
|
||||
case Ast_Field:
|
||||
if (node->Field.tag.kind != Token_Invalid) {
|
||||
return node->Field.tag;
|
||||
}
|
||||
if (node->Field.default_value) {
|
||||
return ast_end_token(node->Field.default_value);
|
||||
}
|
||||
if (node->Field.type) {
|
||||
return ast_end_token(node->Field.type);
|
||||
}
|
||||
return ast_end_token(node->Field.names[node->Field.names.count-1]);
|
||||
case Ast_FieldList:
|
||||
if (node->FieldList.list.count > 0) {
|
||||
return ast_end_token(node->FieldList.list[node->FieldList.list.count-1]);
|
||||
}
|
||||
return node->FieldList.token;
|
||||
|
||||
case Ast_TypeidType:
|
||||
if (node->TypeidType.specialization) {
|
||||
return ast_end_token(node->TypeidType.specialization);
|
||||
}
|
||||
return node->TypeidType.token;
|
||||
case Ast_HelperType: return ast_end_token(node->HelperType.type);
|
||||
case Ast_DistinctType: return ast_end_token(node->DistinctType.type);
|
||||
case Ast_PolyType:
|
||||
if (node->PolyType.specialization) {
|
||||
return ast_end_token(node->PolyType.specialization);
|
||||
}
|
||||
return ast_end_token(node->PolyType.type);
|
||||
case Ast_ProcType:
|
||||
if (node->ProcType.results) {
|
||||
return ast_end_token(node->ProcType.results);
|
||||
}
|
||||
if (node->ProcType.params) {
|
||||
return ast_end_token(node->ProcType.params);
|
||||
}
|
||||
return node->ProcType.token;
|
||||
case Ast_RelativeType:
|
||||
return ast_end_token(node->RelativeType.type);
|
||||
case Ast_PointerType: return ast_end_token(node->PointerType.type);
|
||||
case Ast_ArrayType: return ast_end_token(node->ArrayType.elem);
|
||||
case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem);
|
||||
case Ast_StructType:
|
||||
if (node->StructType.fields.count > 0) {
|
||||
return ast_end_token(node->StructType.fields[node->StructType.fields.count-1]);
|
||||
}
|
||||
return node->StructType.token;
|
||||
case Ast_UnionType:
|
||||
if (node->UnionType.variants.count > 0) {
|
||||
return ast_end_token(node->UnionType.variants[node->UnionType.variants.count-1]);
|
||||
}
|
||||
return node->UnionType.token;
|
||||
case Ast_EnumType:
|
||||
if (node->EnumType.fields.count > 0) {
|
||||
return ast_end_token(node->EnumType.fields[node->EnumType.fields.count-1]);
|
||||
}
|
||||
if (node->EnumType.base_type) {
|
||||
return ast_end_token(node->EnumType.base_type);
|
||||
}
|
||||
return node->EnumType.token;
|
||||
case Ast_BitSetType:
|
||||
if (node->BitSetType.underlying) {
|
||||
return ast_end_token(node->BitSetType.underlying);
|
||||
}
|
||||
return ast_end_token(node->BitSetType.elem);
|
||||
case Ast_MapType: return ast_end_token(node->MapType.value);
|
||||
}
|
||||
|
||||
return empty_token;
|
||||
}
|
||||
|
||||
TokenPos ast_end_pos(Ast *node) {
|
||||
return token_pos_end(ast_end_token(node));
|
||||
}
|
||||
@@ -423,7 +423,7 @@ void error_out(char const *fmt, ...) {
|
||||
}
|
||||
|
||||
|
||||
bool show_error_on_line(TokenPos const &pos) {
|
||||
bool show_error_on_line(TokenPos const &pos, TokenPos end) {
|
||||
if (!show_error_line()) {
|
||||
return false;
|
||||
}
|
||||
@@ -435,6 +435,8 @@ bool show_error_on_line(TokenPos const &pos) {
|
||||
if (the_line != nullptr) {
|
||||
String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line));
|
||||
|
||||
// TODO(bill): This assumes ASCII
|
||||
|
||||
enum {
|
||||
MAX_LINE_LENGTH = 76,
|
||||
MAX_TAB_WIDTH = 8,
|
||||
@@ -462,15 +464,33 @@ bool show_error_on_line(TokenPos const &pos) {
|
||||
}
|
||||
error_out("\n\t");
|
||||
|
||||
for (i32 i = 0; i < offset; i++) error_out(" ");
|
||||
error_out("^\n");
|
||||
error_out("\n");
|
||||
for (i32 i = 0; i < offset; i++) {
|
||||
error_out(" ");
|
||||
}
|
||||
error_out("^");
|
||||
if (end.file_id == pos.file_id) {
|
||||
if (end.line > pos.line) {
|
||||
for (i32 i = offset; i < line.len; i++) {
|
||||
error_out("~");
|
||||
}
|
||||
} else if (end.line == pos.line && end.column > pos.column) {
|
||||
i32 length = gb_min(end.offset - pos.offset, cast(i32)(line.len-offset));
|
||||
for (i32 i = 1; i < length-1; i++) {
|
||||
error_out("~");
|
||||
}
|
||||
if (length > 1) {
|
||||
error_out("^");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_out("\n\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void error_va(TokenPos pos, char const *fmt, va_list va) {
|
||||
void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
@@ -481,7 +501,7 @@ void error_va(TokenPos pos, char const *fmt, va_list va) {
|
||||
error_out("%s %s\n",
|
||||
token_pos_to_string(pos),
|
||||
gb_bprintf_va(fmt, va));
|
||||
show_error_on_line(pos);
|
||||
show_error_on_line(pos, end);
|
||||
}
|
||||
gb_mutex_unlock(&global_error_collector.mutex);
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) {
|
||||
@@ -489,9 +509,9 @@ void error_va(TokenPos pos, char const *fmt, va_list va) {
|
||||
}
|
||||
}
|
||||
|
||||
void warning_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
if (global_warnings_as_errors()) {
|
||||
error_va(pos, fmt, va);
|
||||
error_va(pos, end, fmt, va);
|
||||
return;
|
||||
}
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
@@ -505,7 +525,7 @@ void warning_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
error_out("%s Warning: %s\n",
|
||||
token_pos_to_string(pos),
|
||||
gb_bprintf_va(fmt, va));
|
||||
show_error_on_line(pos);
|
||||
show_error_on_line(pos, end);
|
||||
}
|
||||
}
|
||||
gb_mutex_unlock(&global_error_collector.mutex);
|
||||
@@ -537,7 +557,7 @@ void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
}
|
||||
|
||||
|
||||
void syntax_error_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
@@ -546,7 +566,7 @@ void syntax_error_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
error_out("%s Syntax Error: %s\n",
|
||||
token_pos_to_string(pos),
|
||||
gb_bprintf_va(fmt, va));
|
||||
show_error_on_line(pos);
|
||||
show_error_on_line(pos, end);
|
||||
} else if (pos.line == 0) {
|
||||
error_out("Syntax Error: %s\n", gb_bprintf_va(fmt, va));
|
||||
}
|
||||
@@ -557,9 +577,9 @@ void syntax_error_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
}
|
||||
}
|
||||
|
||||
void syntax_warning_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
if (global_warnings_as_errors()) {
|
||||
syntax_error_va(pos, fmt, va);
|
||||
syntax_error_va(pos, end, fmt, va);
|
||||
return;
|
||||
}
|
||||
gb_mutex_lock(&global_error_collector.mutex);
|
||||
@@ -571,7 +591,7 @@ void syntax_warning_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
error_out("%s Syntax Warning: %s\n",
|
||||
token_pos_to_string(pos),
|
||||
gb_bprintf_va(fmt, va));
|
||||
show_error_on_line(pos);
|
||||
show_error_on_line(pos, end);
|
||||
} else if (pos.line == 0) {
|
||||
error_out("Warning: %s\n", gb_bprintf_va(fmt, va));
|
||||
}
|
||||
@@ -584,14 +604,14 @@ void syntax_warning_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
void warning(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
warning_va(token.pos, fmt, va);
|
||||
warning_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void error(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
error_va(token.pos, fmt, va);
|
||||
error_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
@@ -600,7 +620,7 @@ void error(TokenPos pos, char const *fmt, ...) {
|
||||
va_start(va, fmt);
|
||||
Token token = {};
|
||||
token.pos = pos;
|
||||
error_va(pos, fmt, va);
|
||||
error_va(pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
@@ -615,21 +635,21 @@ void error_line(char const *fmt, ...) {
|
||||
void syntax_error(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_error_va(token.pos, fmt, va);
|
||||
syntax_error_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_error(TokenPos pos, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_error_va(pos, fmt, va);
|
||||
syntax_error_va(pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_warning(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_warning_va(token.pos, fmt, va);
|
||||
syntax_warning_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
@@ -748,7 +768,7 @@ void tokenizer_err(Tokenizer *t, char const *msg, ...) {
|
||||
pos.offset = cast(i32)(t->read_curr - t->start);
|
||||
|
||||
va_start(va, msg);
|
||||
syntax_error_va(pos, msg, va);
|
||||
syntax_error_va(pos, {}, msg, va);
|
||||
va_end(va);
|
||||
|
||||
t->error_count++;
|
||||
@@ -762,7 +782,7 @@ void tokenizer_err(Tokenizer *t, TokenPos const &pos, char const *msg, ...) {
|
||||
}
|
||||
|
||||
va_start(va, msg);
|
||||
syntax_error_va(pos, msg, va);
|
||||
syntax_error_va(pos, {}, msg, va);
|
||||
va_end(va);
|
||||
|
||||
t->error_count++;
|
||||
|
||||
Reference in New Issue
Block a user