error_node

This commit is contained in:
Ginger Bill
2016-11-30 10:52:09 +00:00
parent d9c686b53d
commit b76c8abe73
8 changed files with 394 additions and 325 deletions
+18 -17
View File
@@ -6,7 +6,10 @@ when ODIN_OS == "windows" {
File_Time :: type u64
File :: struct {
Handle :: type win32.HANDLE
Handle :: raw_union {
p: rawptr
i: int
}
handle: Handle
last_write_time: File_Time
}
@@ -15,10 +18,9 @@ open :: proc(name: string) -> (File, bool) {
using win32
buf: [300]byte
copy(buf[:], name as []byte)
f := File{
handle = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil),
}
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
f: File
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, nil) as rawptr
success := f.handle.p != INVALID_HANDLE_VALUE
f.last_write_time = last_write_time(^f)
return f, success
}
@@ -27,21 +29,20 @@ create :: proc(name: string) -> (File, bool) {
using win32
buf: [300]byte
copy(buf[:], name as []byte)
f := File{
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil),
}
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
f: File
f.handle.p = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, 0, nil) as rawptr
success := f.handle.p != INVALID_HANDLE_VALUE
f.last_write_time = last_write_time(^f)
return f, success
}
close :: proc(using f: ^File) {
win32.CloseHandle(handle)
win32.CloseHandle(handle.p as win32.HANDLE)
}
write :: proc(using f: ^File, buf: []byte) -> bool {
bytes_written: i32
return win32.WriteFile(handle, buf.data, buf.count as i32, ^bytes_written, nil) != 0
return win32.WriteFile(handle.p as win32.HANDLE, buf.data, buf.count as i32, ^bytes_written, nil) != 0
}
file_has_changed :: proc(f: ^File) -> bool {
@@ -57,7 +58,7 @@ file_has_changed :: proc(f: ^File) -> bool {
last_write_time :: proc(f: ^File) -> File_Time {
file_info: win32.BY_HANDLE_FILE_INFORMATION
win32.GetFileInformationByHandle(f.handle, ^file_info)
win32.GetFileInformationByHandle(f.handle.p as win32.HANDLE, ^file_info)
l := file_info.last_write_time.low_date_time as File_Time
h := file_info.last_write_time.high_date_time as File_Time
return l | h << 32
@@ -91,9 +92,9 @@ File_Standard :: type enum {
// NOTE(bill): Uses startup to initialize it
__std_files := [File_Standard.count]File{
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE)},
{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File.Handle },
{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File.Handle },
{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE) transmute File.Handle },
}
stdin := ^__std_files[File_Standard.INPUT]
@@ -113,7 +114,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
defer close(^f)
length: i64
file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0
file_size_ok := win32.GetFileSizeEx(f.handle.p as win32.HANDLE, ^length) != 0
if !file_size_ok {
return nil, false
}
@@ -136,7 +137,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
to_read = MAX
}
win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
win32.ReadFile(f.handle.p as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, nil)
if single_read_length <= 0 {
free(data.data)
return nil, false
+12 -11
View File
@@ -546,6 +546,7 @@ void init_universal_scope(void) {
add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
// TODO(bill): Set through flags in the compiler
add_global_string_constant(a, str_lit("ODIN_OS"), str_lit("windows"));
add_global_string_constant(a, str_lit("ODIN_ARCH"), str_lit("amd64"));
add_global_string_constant(a, str_lit("ODIN_VENDOR"), str_lit("odin"));
@@ -702,7 +703,6 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode
void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) {
GB_ASSERT(identifier != NULL);
if (identifier->kind == AstNode_Ident) {
GB_ASSERT(identifier->kind == AstNode_Ident);
HashKey key = hash_pointer(identifier);
map_entity_set(&i->definitions, key, entity);
} else {
@@ -754,6 +754,7 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) {
GB_ASSERT(identifier->kind == AstNode_Ident);
GB_ASSERT(str_eq(identifier->Ident.string, e->token.string));
add_entity(c, e->scope, identifier, e);
map_decl_info_set(&c->info.entities, hash_pointer(e), d);
@@ -1077,13 +1078,13 @@ void check_global_when_stmt(Checker *c, Scope *parent_scope, AstNodeWhenStmt *ws
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, ws->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error(ast_node_token(ws->cond), "Non-boolean condition in `when` statement");
error_node(ws->cond, "Non-boolean condition in `when` statement");
}
if (operand.mode != Addressing_Constant) {
error(ast_node_token(ws->cond), "Non-constant condition in `when` statement");
error_node(ws->cond, "Non-constant condition in `when` statement");
}
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
error(ast_node_token(ws->cond), "Invalid body for `when` statement");
error_node(ws->cond, "Invalid body for `when` statement");
} else {
if (operand.value.kind == ExactValue_Bool &&
operand.value.value_bool == true) {
@@ -1098,7 +1099,7 @@ void check_global_when_stmt(Checker *c, Scope *parent_scope, AstNodeWhenStmt *ws
check_global_when_stmt(c, parent_scope, &ws->else_stmt->WhenStmt, file_scopes);
break;
default:
error(ast_node_token(ws->else_stmt), "Invalid `else` statement in `when` statement");
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
break;
}
}
@@ -1200,9 +1201,9 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
if (is_string_an_identifier(filename)) {
import_name = filename;
} else {
error(ast_node_token(decl),
"File name, %.*s, cannot be as an import name as it is not a valid identifier",
LIT(filename));
error_node(decl,
"File name, %.*s, cannot be as an import name as it is not a valid identifier",
LIT(filename));
}
}
@@ -1261,9 +1262,9 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
isize rhs_count = cd->values.count;
if (rhs_count == 0 && cd->type == NULL) {
error(ast_node_token(decl), "Missing type or initial expression");
error_node(decl, "Missing type or initial expression");
} else if (lhs_count < rhs_count) {
error(ast_node_token(decl), "Extra initial expression");
error_node(decl, "Extra initial expression");
}
case_end;
case_ast_node(vd, VarDecl, decl);
@@ -1326,7 +1327,7 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
default:
if (parent_scope->is_file) {
error(ast_node_token(decl), "Only declarations are allowed at file scope");
error_node(decl, "Only declarations are allowed at file scope");
}
break;
}
+16 -19
View File
@@ -16,7 +16,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
error(ast_node_token(operand->expr),
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
@@ -175,7 +175,7 @@ void check_var_decl_node(Checker *c, AstNode *node) {
entity = found;
}
} else {
error(ast_node_token(name), "A variable declaration must be an identifier");
error_node(name, "A variable declaration must be an identifier");
}
if (entity == NULL) {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
@@ -227,7 +227,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode != Addressing_Constant) {
// TODO(bill): better error
error(ast_node_token(operand->expr),
error_node(operand->expr,
"`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
if (e->type == NULL) {
e->type = t_invalid;
@@ -237,7 +237,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
// if (!is_type_constant_type(operand->type)) {
// gbString type_str = type_to_string(operand->type);
// defer (gb_string_free(type_str));
// error(ast_node_token(operand->expr),
// error_node(operand->expr,
// "Invalid constant type: `%s`", type_str);
// if (e->type == NULL) {
// e->type = t_invalid;
@@ -272,7 +272,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
// if (!is_type_constant_type(t)) {
// gbString str = type_to_string(t);
// defer (gb_string_free(str));
// error(ast_node_token(type_expr),
// error_node(type_expr),
// "Invalid constant type `%s`", str);
// e->type = t_invalid;
// return;
@@ -380,19 +380,16 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
if (is_inline && is_no_inline) {
error(ast_node_token(pd->type),
"You cannot apply both `inline` and `no_inline` to a procedure");
error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
}
if (is_foreign && is_link_name) {
error(ast_node_token(pd->type),
"You cannot apply both `foreign` and `link_name` to a procedure");
error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
}
if (pd->body != NULL) {
if (is_foreign) {
error(ast_node_token(pd->body),
"A procedure tagged as `#foreign` cannot have a body");
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
d->scope = c->context.scope;
@@ -416,10 +413,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
Type *this_type = base_type(e->type);
Type *other_type = base_type(f->type);
if (!are_signatures_similar_enough(this_type, other_type)) {
error(ast_node_token(d->proc_decl),
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
error_node(d->proc_decl,
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
"\tat %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
}
} else {
map_entity_set(fp, key, e);
@@ -434,10 +431,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
if (found) {
Entity *f = *found;
TokenPos pos = f->token.pos;
error(ast_node_token(d->proc_decl),
"Non unique #link_name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
error_node(d->proc_decl,
"Non unique #link_name for procedure `%.*s`\n"
"\tother at %.*s(%td:%td)",
LIT(name), LIT(pos.file), pos.line, pos.column);
} else {
map_entity_set(fp, key, e);
}
+223 -205
View File
File diff suppressed because it is too large Load Diff
+38 -38
View File
@@ -216,10 +216,10 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
gbString str = expr_to_string(op_b.expr);
switch (op_b.mode) {
case Addressing_Value:
error(ast_node_token(op_b.expr), "Cannot assign to `%s`", str);
error_node(op_b.expr, "Cannot assign to `%s`", str);
break;
default:
error(ast_node_token(op_b.expr), "Cannot assign to `%s`", str);
error_node(op_b.expr, "Cannot assign to `%s`", str);
break;
}
gb_string_free(str);
@@ -284,13 +284,13 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, ws->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error(ast_node_token(ws->cond), "Non-boolean condition in `when` statement");
error_node(ws->cond, "Non-boolean condition in `when` statement");
}
if (operand.mode != Addressing_Constant) {
error(ast_node_token(ws->cond), "Non-constant condition in `when` statement");
error_node(ws->cond, "Non-constant condition in `when` statement");
}
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
error(ast_node_token(ws->cond), "Invalid body for `when` statement");
error_node(ws->cond, "Invalid body for `when` statement");
} else {
if (operand.value.kind == ExactValue_Bool &&
operand.value.value_bool) {
@@ -304,7 +304,7 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
check_when_stmt(c, &ws->else_stmt->WhenStmt, flags);
break;
default:
error(ast_node_token(ws->else_stmt), "Invalid `else` statement in `when` statement");
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
break;
}
}
@@ -323,7 +323,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
ExprKind kind = check_expr_base(c, &operand, es->expr, NULL);
switch (operand.mode) {
case Addressing_Type:
error(ast_node_token(node), "Is not an expression");
error_node(node, "Is not an expression");
break;
case Addressing_NoValue:
return;
@@ -335,7 +335,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
return;
}
gbString expr_str = expr_to_string(operand.expr);
error(ast_node_token(node), "Expression is not used: `%s`", expr_str);
error_node(node, "Expression is not used: `%s`", expr_str);
gb_string_free(expr_str);
} break;
}
@@ -343,7 +343,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(ts, TagStmt, node);
// TODO(bill): Tag Statements
error(ast_node_token(node), "Tag statements are not supported yet");
error_node(node, "Tag statements are not supported yet");
check_stmt(c, ts->stmt, flags);
case_end;
@@ -426,7 +426,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_assignment_variable(c, &operands.e[i], lhs);
}
if (lhs_count != rhs_count) {
error(ast_node_token(as->lhs.e[0]), "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
}
gb_temp_arena_memory_end(tmp);
@@ -479,7 +479,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, is->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error(ast_node_token(is->cond), "Non-boolean condition in `if` statement");
error_node(is->cond, "Non-boolean condition in `if` statement");
}
check_stmt(c, is->body, mod_flags);
@@ -491,7 +491,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_stmt(c, is->else_stmt, mod_flags);
break;
default:
error(ast_node_token(is->else_stmt), "Invalid `else` statement in `if` statement");
error_node(is->else_stmt, "Invalid `else` statement in `if` statement");
break;
}
}
@@ -526,13 +526,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
variables = tuple->variables;
}
if (rs->results.count == 0) {
error(ast_node_token(node), "Expected %td return values, got 0", result_count);
error_node(node, "Expected %td return values, got 0", result_count);
} else {
check_init_variables(c, variables, result_count,
rs->results, str_lit("return statement"));
}
} else if (rs->results.count > 0) {
error(ast_node_token(rs->results.e[0]), "No return values expected");
error_node(rs->results.e[0], "No return values expected");
}
case_end;
@@ -548,8 +548,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_expr(c, &operand, fs->cond);
if (operand.mode != Addressing_Invalid &&
!is_type_boolean(operand.type)) {
error(ast_node_token(fs->cond),
"Non-boolean condition in `for` statement");
error_node(fs->cond, "Non-boolean condition in `for` statement");
}
}
if (fs->post != NULL) {
@@ -595,15 +594,16 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
default_stmt = stmt;
}
} else {
error(ast_node_token(stmt), "Invalid AST - expected case clause");
error_node(stmt, "Invalid AST - expected case clause");
}
if (default_stmt != NULL) {
if (first_default != NULL) {
TokenPos pos = ast_node_token(first_default).pos;
error(ast_node_token(stmt),
"multiple `default` clauses\n"
"\tfirst at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column);
error_node(stmt,
"multiple `default` clauses\n"
"\tfirst at %.*s(%td:%td)",
LIT(pos.file), pos.line, pos.column);
} else {
first_default = default_stmt;
}
@@ -664,11 +664,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (are_types_identical(y.type, tap.type)) {
TokenPos pos = tap.token.pos;
gbString expr_str = expr_to_string(y.expr);
error(ast_node_token(y.expr),
"Duplicate case `%s`\n"
"\tprevious case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
error_node(y.expr,
"Duplicate case `%s`\n"
"\tprevious case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
gb_string_free(expr_str);
continue_outer = true;
break;
@@ -713,8 +713,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_assignment(c, &x, NULL, str_lit("type match expression"));
if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) {
gbString str = type_to_string(x.type);
error(ast_node_token(x.expr),
"Invalid type for this type match expression, got `%s`", str);
error_node(x.expr,
"Invalid type for this type match expression, got `%s`", str);
gb_string_free(str);
break;
}
@@ -732,15 +732,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
default_stmt = stmt;
}
} else {
error(ast_node_token(stmt), "Invalid AST - expected case clause");
error_node(stmt, "Invalid AST - expected case clause");
}
if (default_stmt != NULL) {
if (first_default != NULL) {
TokenPos pos = ast_node_token(first_default).pos;
error(ast_node_token(stmt),
"multiple `default` clauses\n"
"\tfirst at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column);
error_node(stmt,
"Multiple `default` clauses\n"
"\tfirst at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column);
} else {
first_default = default_stmt;
}
@@ -785,8 +785,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
if (!tag_type_found) {
gbString type_str = type_to_string(y.type);
error(ast_node_token(y.expr),
"Unknown tag type, got `%s`", type_str);
error_node(y.expr,
"Unknown tag type, got `%s`", type_str);
gb_string_free(type_str);
continue;
}
@@ -802,11 +802,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (found) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error(ast_node_token(y.expr),
"Duplicate type case `%s`\n"
"\tprevious type case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
error_node(y.expr,
"Duplicate type case `%s`\n"
"\tprevious type case at %.*s(%td:%td)",
expr_str,
LIT(pos.file), pos.line, pos.column);
gb_string_free(expr_str);
break;
}
+16 -1
View File
@@ -667,9 +667,24 @@ bool is_type_comparable(Type *t) {
t = base_type(get_enum_base_type(t));
switch (t->kind) {
case Type_Basic:
return t->kind != Basic_UntypedNil && t->kind != Basic_any;
return t->kind != Basic_UntypedNil;
case Type_Pointer:
return true;
case Type_Record: {
if (false && is_type_struct(t)) {
// TODO(bill): Should I even allow this?
for (isize i = 0; i < t->Record.field_count; i++) {
if (!is_type_comparable(t->Record.fields[i]->type))
return false;
}
} else if (is_type_enum(t)) {
return is_type_comparable(t->Record.enum_base);
}
return false;
} break;
case Type_Array:
return false;
// return is_type_comparable(t->Array.elem);
case Type_Vector:
return is_type_comparable(t->Vector.elem);
case Type_Proc:
+46 -16
View File
@@ -355,8 +355,6 @@ typedef struct AstNode {
#define case_end } break;
gb_inline bool is_ast_node_expr(AstNode *node) {
return gb_is_between(node->kind, AstNode__ExprBegin+1, AstNode__ExprEnd-1);
}
@@ -500,6 +498,38 @@ Token ast_node_token(AstNode *node) {
return empty_token;
}
void error_node(AstNode *node, char *fmt, ...) {
va_list va;
va_start(va, fmt);
error_va(ast_node_token(node), fmt, va);
va_end(va);
}
void warning_node(AstNode *node, char *fmt, ...) {
va_list va;
va_start(va, fmt);
warning_va(ast_node_token(node), fmt, va);
va_end(va);
}
void syntax_error_node(AstNode *node, char *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_error_va(ast_node_token(node), fmt, va);
va_end(va);
}
bool ast_node_expect(AstNode *node, AstNodeKind kind) {
if (node->kind != kind) {
error_node(node, "Expected %.*s, got %.*s", LIT(ast_node_strings[node->kind]));
return false;
}
return true;
}
// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++
AstNode *make_node(AstFile *f, AstNodeKind kind) {
gbArena *arena = &f->arena;
@@ -1232,7 +1262,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags);
void check_proc_add_tag(AstFile *f, AstNode *tag_expr, u64 *tags, ProcTag tag, String tag_name) {
if (*tags & tag) {
syntax_error(ast_node_token(tag_expr), "Procedure tag already used: %.*s", LIT(tag_name));
syntax_error_node(tag_expr, "Procedure tag already used: %.*s", LIT(tag_name));
}
*tags |= tag;
}
@@ -1306,7 +1336,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
*foreign_name = f->curr_token.string;
// TODO(bill): Check if valid string
if (!is_foreign_name_valid(*foreign_name)) {
syntax_error(ast_node_token(tag_expr), "Invalid alternative foreign procedure name: `%.*s`", LIT(*foreign_name));
syntax_error_node(tag_expr, "Invalid alternative foreign procedure name: `%.*s`", LIT(*foreign_name));
}
next_token(f);
@@ -1317,7 +1347,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
*link_name = f->curr_token.string;
// TODO(bill): Check if valid string
if (!is_foreign_name_valid(*link_name)) {
syntax_error(ast_node_token(tag_expr), "Invalid alternative link procedure name `%.*s`", LIT(*link_name));
syntax_error_node(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*link_name));
}
next_token(f);
@@ -1335,7 +1365,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
ELSE_IF_ADD_TAG(fastcall)
// ELSE_IF_ADD_TAG(cdecl)
else {
syntax_error(ast_node_token(tag_expr), "Unknown procedure tag");
syntax_error_node(tag_expr, "Unknown procedure tag");
}
#undef ELSE_IF_ADD_TAG
@@ -1437,7 +1467,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
AstNode *expr = parse_expr(f, false);
operand = make_run_expr(f, token, name, expr);
if (unparen_expr(expr)->kind != AstNode_CallExpr) {
error(ast_node_token(expr), "#run can only be applied to procedure calls");
error_node(expr, "#run can only be applied to procedure calls");
operand = make_bad_expr(f, token, f->curr_token);
}
warning(token, "#run is not yet implemented");
@@ -1999,7 +2029,7 @@ AstNodeArray parse_record_params(AstFile *f, isize *decl_count_, bool using_allo
}
array_add(&decls, vd);
} else {
syntax_error(ast_node_token(decl), "Illegal %.*s field", LIT(context));
syntax_error_node(decl, "Illegal %.*s field", LIT(context));
}
} break;
@@ -2021,7 +2051,7 @@ AstNodeArray parse_record_params(AstFile *f, isize *decl_count_, bool using_allo
break;
}
} else {
syntax_error(ast_node_token(decl), "Illegal record field: %.*s", LIT(ast_node_strings[decl->kind]));
syntax_error_node(decl, "Illegal record field: %.*s", LIT(ast_node_strings[decl->kind]));
}
}
@@ -2293,7 +2323,7 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
String n = name->Ident.string;
// NOTE(bill): Check for reserved identifiers
if (str_eq(n, str_lit("context"))) {
syntax_error(ast_node_token(name), "`context` is a reserved identifier");
syntax_error_node(name, "`context` is a reserved identifier");
break;
}
}
@@ -2326,7 +2356,7 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
next_token(f);
}
if (names.count != 1) {
syntax_error(ast_node_token(names.e[0]), "You can only declare one type at a time");
syntax_error_node(names.e[0], "You can only declare one type at a time");
return make_bad_decl(f, names.e[0]->Ident, token);
}
@@ -3164,7 +3194,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray
node->kind != AstNode_BadStmt &&
node->kind != AstNode_EmptyStmt) {
// NOTE(bill): Sanity check
syntax_error(ast_node_token(node), "Only declarations are allowed at file scope");
syntax_error_node(node, "Only declarations are allowed at file scope");
} else if (node->kind == AstNode_WhenStmt) {
parse_setup_file_when_stmt(p, f, base_dir, &node->WhenStmt);
} else if (node->kind == AstNode_ImportDecl) {
@@ -3173,9 +3203,9 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray
if (!is_import_path_valid(file_str)) {
if (id->is_load) {
syntax_error(ast_node_token(node), "Invalid #load path: `%.*s`", LIT(file_str));
syntax_error_node(node, "Invalid #load path: `%.*s`", LIT(file_str));
} else {
syntax_error(ast_node_token(node), "Invalid #import path: `%.*s`", LIT(file_str));
syntax_error_node(node, "Invalid #import path: `%.*s`", LIT(file_str));
}
// NOTE(bill): It's a naughty name
decls.e[i] = make_bad_decl(f, id->token, id->token);
@@ -3202,9 +3232,9 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, AstNodeArray
if (!is_import_path_valid(file_str)) {
if (fl->is_system) {
syntax_error(ast_node_token(node), "Invalid `foreign_system_library` path");
syntax_error_node(node, "Invalid `foreign_system_library` path");
} else {
syntax_error(ast_node_token(node), "Invalid `foreign_library` path");
syntax_error_node(node, "Invalid `foreign_library` path");
}
// NOTE(bill): It's a naughty name
f->decls.e[i] = make_bad_decl(f, fl->token, fl->token);
+25 -18
View File
@@ -177,67 +177,74 @@ void init_global_error_collector(void) {
}
void warning(Token token, char *fmt, ...) {
void warning_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.warning_count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
va_list va;
global_error_collector.prev = token.pos;
va_start(va, fmt);
gb_printf_err("%.*s(%td:%td) Warning: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
va_end(va);
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void error(Token token, char *fmt, ...) {
void error_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
va_list va;
global_error_collector.prev = token.pos;
va_start(va, fmt);
gb_printf_err("%.*s(%td:%td) %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
va_end(va);
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void syntax_error(Token token, char *fmt, ...) {
void syntax_error_va(Token token, char *fmt, va_list va) {
gb_mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
if (!token_pos_are_equal(global_error_collector.prev, token.pos)) {
va_list va;
global_error_collector.prev = token.pos;
va_start(va, fmt);
gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n",
LIT(token.pos.file), token.pos.line, token.pos.column,
gb_bprintf_va(fmt, va));
va_end(va);
}
gb_mutex_unlock(&global_error_collector.mutex);
}
void warning(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
warning_va(token, fmt, va);
va_end(va);
}
void error(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
error_va(token, fmt, va);
va_end(va);
}
void syntax_error(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_error_va(token, fmt, va);
va_end(va);
}
void compiler_error(char *fmt, ...) {
va_list va;