#panic; Minor change to demo.odin; Fix #assert bug at file scope

This commit is contained in:
gingerBill
2019-10-13 12:38:23 +01:00
parent fa81061db0
commit 2a6d9e8927
10 changed files with 145 additions and 122 deletions
+1 -1
View File
@@ -1091,7 +1091,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case: error(p, stmt.pos, "#complete can only be applied to a switch statement");
}
return stmt;
case "assert":
case "assert", "panic":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(tag));
bd.tok = tok;
bd.name = name;
+28 -26
View File
@@ -6,6 +6,7 @@ package runtime
import "core:os"
import "core:mem"
import "core:log"
import "intrinsics"
// Naming Conventions:
// In general, Ada_Case for types and snake_case for values
@@ -187,12 +188,13 @@ Typeid_Kind :: enum u8 {
#assert(len(Typeid_Kind) < 32);
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
index: 8*size_of(align_of(uintptr)) - 8,
index: 8*size_of(uintptr) - 8,
kind: 5, // Typeid_Kind
named: 1,
special: 1, // signed, cstring, etc
reserved: 1,
}
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
@@ -678,7 +680,7 @@ assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool
if p == nil {
p = default_assertion_failure_proc;
}
p("Runtime assertion", message, loc);
p("runtime assertion", message, loc);
}(message, loc);
}
return condition;
@@ -690,7 +692,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
if p == nil {
p = default_assertion_failure_proc;
}
p("Panic", message, loc);
p("panic", message, loc);
}
@builtin
@@ -816,8 +818,7 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
value: V,
};
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
header.is_key_string = is_string;
header.is_key_string = intrinsics.type_is_string(K);
header.entry_size = int(size_of(Entry));
header.entry_align = int(align_of(Entry));
header.value_offset = uintptr(offset_of(Entry, value));
@@ -828,33 +829,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
__get_map_key :: proc "contextless" (k: $K) -> Map_Key {
key := k;
map_key: Map_Key;
ti := type_info_base_without_enum(type_info_of(K));
switch _ in ti.variant {
case Type_Info_Integer:
switch 8*size_of(key) {
case 8: map_key.hash = u64(( ^u8)(&key)^);
case 16: map_key.hash = u64(( ^u16)(&key)^);
case 32: map_key.hash = u64(( ^u32)(&key)^);
case 64: map_key.hash = u64(( ^u64)(&key)^);
case: panic("Unhandled integer size");
}
case Type_Info_Rune:
T :: intrinsics.type_core_type(K);
when intrinsics.type_is_integer(T) {
sz :: 8*size_of(T);
when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
else do #assert(false, "Unhandled integer size");
} else when intrinsics.type_is_rune(T) {
map_key.hash = u64((^rune)(&key)^);
case Type_Info_Pointer:
} else when intrinsics.type_is_pointer(T) {
map_key.hash = u64(uintptr((^rawptr)(&key)^));
case Type_Info_Float:
switch 8*size_of(key) {
case 32: map_key.hash = u64((^u32)(&key)^);
case 64: map_key.hash = u64((^u64)(&key)^);
case: panic("Unhandled float size");
}
case Type_Info_String:
} else when intrinsics.type_is_float(T) {
sz :: 8*size_of(T);
when sz == 32 do map_key.hash = u64((^u32)(&key)^);
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
else do #assert(false, "Unhandled float size");
} else when intrinsics.type_is_string(T) {
#assert(T == string);
str := (^string)(&key)^;
map_key.hash = default_hash_string(str);
map_key.str = str;
case:
panic("Unhandled map key type");
} else {
#assert(false, "Unhandled map key type");
}
return map_key;
}
+10 -10
View File
@@ -28,9 +28,9 @@ when os.OS == "windows" {
Answers to common questions about Odin.
*/
@(link_name="general_stuff")
general_stuff :: proc() {
fmt.println("# general_stuff");
@(link_name="extra_general_stuff")
extra_general_stuff :: proc() {
fmt.println("# extra_general_stuff");
{ // `do` for inline statements rather than block
foo :: proc() do fmt.println("Foo!");
if false do foo();
@@ -209,8 +209,8 @@ union_type :: proc() {
}
}
Vector3 :: struct {x, y, z: f32};
Quaternion :: struct {x, y, z, w: f32};
Vector3 :: distinct [3]f32;
Quaternion :: distinct quaternion128;
// More realistic examples
{
@@ -320,17 +320,17 @@ union_type :: proc() {
/*
Entity :: struct {
..
...
derived: union{^Frog, ^Monster},
}
Frog :: struct {
using entity: Entity,
..
...
}
Monster :: struct {
using entity: Entity,
..
...
}
new_entity :: proc(T: type) -> ^Entity {
@@ -539,7 +539,7 @@ parametric_polymorphism :: proc() {
fmt.println(r);
r = 123;
fmt.println(r);
r = Error.Foo0;
r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
fmt.println(r);
}
@@ -1190,7 +1190,7 @@ where_clauses :: proc() {
main :: proc() {
when true {
general_stuff();
extra_general_stuff();
union_type();
parametric_polymorphism();
threading_example();
+20 -2
View File
@@ -3071,7 +3071,6 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
if (selector->kind != Ast_Ident) {
// if (selector->kind != Ast_Ident) {
error(selector, "Illegal selector kind: '%.*s'", LIT(ast_strings[selector->kind]));
operand->mode = Addressing_Invalid;
operand->expr = node;
@@ -3544,6 +3543,25 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->type = t_untyped_bool;
operand->mode = Addressing_Constant;
} else if (name == "panic") {
if (ce->args.count != 1) {
error(call, "'#panic' expects 1 argument, got %td", ce->args.count);
return false;
}
if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) {
gbString str = expr_to_string(ce->args[0]);
error(call, "'%s' is not a constant string", str);
gb_string_free(str);
return false;
}
error(call, "Compile time panic: %.*s", LIT(operand->value.value_string));
if (c->proc_name != "") {
gbString str = type_to_string(c->curr_proc_sig);
error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
gb_string_free(str);
}
operand->type = t_invalid;
operand->mode = Addressing_NoValue;
} else if (name == "defined") {
if (ce->args.count != 1) {
error(call, "'#defined' expects 1 argument, got %td", ce->args.count);
@@ -6349,7 +6367,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
ce->proc->kind == Ast_BasicDirective) {
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name;
if (name == "location" || name == "assert" || name == "defined" || name == "load") {
if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "load") {
operand->mode = Addressing_Builtin;
operand->builtin_id = BuiltinProc_DIRECTIVE;
operand->expr = ce->proc;
+31 -8
View File
@@ -1847,7 +1847,7 @@ Array<Type *> systemv_distribute_struct_fields(Type *t) {
}
auto distributed = array_make<Type *>(heap_allocator(), 0, distributed_cap);
i64 sz = type_size_of(bt);
switch (bt->kind) {
case Type_Basic:
switch (bt->Basic.kind){
@@ -1925,9 +1925,9 @@ Array<Type *> systemv_distribute_struct_fields(Type *t) {
array_add(&distributed, t_int);
break;
case Type_Union:
case Type_DynamicArray:
case Type_Map:
case Type_Union:
case Type_BitField: // TODO(bill): Ignore?
// NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet
goto DEFAULT;
@@ -1937,7 +1937,7 @@ Array<Type *> systemv_distribute_struct_fields(Type *t) {
case Type_SimdVector: // TODO(bill): Is this correct logic?
default:
DEFAULT:;
if (type_size_of(bt) > 0) {
if (sz > 0) {
array_add(&distributed, bt);
}
break;
@@ -1959,13 +1959,22 @@ Type *handle_single_distributed_type_parameter(Array<Type *> const &types, bool
if (types.count == 1) {
if (offset) *offset = 1;
i64 sz = type_size_of(types[0]);
if (is_type_float(types[0])) {
return types[0];
} else if (type_size_of(types[0]) == 8) {
return types[0];
} else {
return t_u64;
}
switch (sz) {
case 0:
GB_PANIC("Zero sized type found!");
case 1:
case 2:
case 4:
case 8:
return types[0];
}
return t_u64;
} else if (types.count >= 2) {
if (types[0] == t_f32 && types[1] == t_f32) {
if (offset) *offset = 2;
@@ -2050,7 +2059,7 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) {
Type *final_type = nullptr;
if (field_types.count == 0) {
return t;
final_type = t;
} else if (field_types.count == 1) {
final_type = field_types[0];
} else {
@@ -2072,8 +2081,22 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) {
variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false);
final_type = alloc_type_tuple();
final_type->Tuple.variables = variables;
if (t->kind == Type_Struct) {
// NOTE(bill): Make this packed
final_type->Tuple.is_packed = t->Struct.is_packed;
}
}
}
GB_ASSERT(final_type != nullptr);
i64 ftsz = type_size_of(final_type);
i64 otsz = type_size_of(original_type);
if (ftsz != otsz) {
// TODO(bill): Handle this case which will be caused by #packed most likely
GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %lld vs %lld", ftsz, otsz);
}
return final_type;
}
}
+10 -3
View File
@@ -3367,8 +3367,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
if (es->expr->kind == Ast_CallExpr) {
ast_node(ce, CallExpr, es->expr);
if (ce->proc->kind == Ast_BasicDirective) {
Operand o = {};
check_expr(ctx, &o, es->expr);
if (ctx->collect_delayed_decls) {
array_add(&ctx->scope->delayed_directives, es->expr);
}
}
}
case_end;
@@ -3525,12 +3526,18 @@ void check_import_entities(Checker *c) {
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx;
add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_imports) {
Ast *decl = f->scope->delayed_imports[j];
check_add_import_decl(&ctx, decl);
}
}
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx;
add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_directives) {
Ast *expr = f->scope->delayed_directives[j];
Operand o = {};
+1
View File
@@ -222,6 +222,7 @@ struct ForeignContext {
typedef Array<Entity *> CheckerTypePath;
typedef Array<Type *> CheckerPolyPath;
// CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo {
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
+5 -9
View File
@@ -445,7 +445,7 @@ bool parse_build_flags(Array<String> args) {
path = substring(path, 0, string_extension_position(path));
}
#endif
build_context.out_filepath = path;
build_context.out_filepath = path_to_full_path(heap_allocator(), path);
} else {
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
bad_flags = true;
@@ -624,7 +624,7 @@ bool parse_build_flags(Array<String> args) {
break;
}
if (str == "dll") {
if (str == "dll" || str == "shared") {
build_context.is_dll = true;
} else if (str == "exe") {
build_context.is_dll = false;
@@ -1112,7 +1112,7 @@ int main(int arg_count, char **arg_ptr) {
if (0) {
#ifdef GB_SYSTEM_UNIX
} else if (selected_target_metrics->metrics == &target_essence_amd64) {
system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
#endif
} else {
@@ -1239,10 +1239,7 @@ int main(int arg_count, char **arg_ptr) {
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
// framework thingie
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
} else if (string_ends_with(lib, str_lit(".framework"))) {
if (string_ends_with(lib, str_lit(".framework"))) {
// framework thingie
String lib_name = lib;
lib_name = remove_extension_from_path(lib_name);
@@ -1251,8 +1248,7 @@ int main(int arg_count, char **arg_ptr) {
// static libs, absolute full path relative to the file in which the lib was imported from
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
} else if (string_ends_with(lib, str_lit(".dylib"))) {
// dynamic lib, relative path to executable
// lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
// dynamic lib
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
} else {
// dynamic or static system lib, just link regularly searching system library paths
+4 -34
View File
@@ -3970,34 +3970,6 @@ Ast *parse_stmt(AstFile *f) {
return s;
}
// case Token_static: {
// CommentGroup *docs = f->lead_comment;
// Token token = expect_token(f, Token_static);
// Ast *decl = nullptr;
// Array<Ast *> list = parse_lhs_expr_list(f);
// if (list.count == 0) {
// syntax_error(token, "Illegal use of 'static' statement");
// expect_semicolon(f, nullptr);
// return ast_bad_stmt(f, token, f->curr_token);
// }
// expect_token_after(f, Token_Colon, "identifier list");
// decl = parse_value_decl(f, list, docs);
// if (decl != nullptr && decl->kind == Ast_ValueDecl) {
// if (decl->ValueDecl.is_mutable) {
// decl->ValueDecl.is_static = true;
// } else {
// error(token, "'static' may only be currently used with variable declaration");
// }
// return decl;
// }
// syntax_error(token, "Illegal use of 'static' statement");
// return ast_bad_stmt(f, token, f->curr_token);
// } break;
case Token_using: {
CommentGroup *docs = f->lead_comment;
Token token = expect_token(f, Token_using);
@@ -4071,12 +4043,10 @@ Ast *parse_stmt(AstFile *f) {
} else if (tag == "assert") {
Ast *t = ast_basic_directive(f, hash_token, tag);
return ast_expr_stmt(f, parse_call_expr(f, t));
} /* else if (name.string == "no_deferred") {
s = parse_stmt(f);
s->stmt_state_flags |= StmtStateFlag_no_deferred;
} */
if (tag == "include") {
} else if (tag == "panic") {
Ast *t = ast_basic_directive(f, hash_token, tag);
return ast_expr_stmt(f, parse_call_expr(f, t));
} else if (tag == "include") {
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
s = ast_bad_stmt(f, token, f->curr_token);
} else {
+35 -29
View File
@@ -113,21 +113,22 @@ struct BasicType {
struct TypeStruct {
Array<Entity *> fields;
Array<String> tags;
Ast *node;
Scope * scope;
Array<i64> offsets;
Ast * node;
Scope * scope;
Array<i64> offsets;
bool are_offsets_set;
bool are_offsets_being_processed;
bool is_packed;
bool is_raw_union;
bool is_polymorphic;
bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
i64 custom_align; // NOTE(bill): Only used in structs at the moment
i64 custom_align;
Entity * names;
bool are_offsets_set;
bool are_offsets_being_processed;
bool is_packed;
bool is_raw_union;
bool is_polymorphic;
bool is_poly_specialized;
};
struct TypeUnion {
@@ -137,12 +138,11 @@ struct TypeUnion {
i64 variant_block_size;
i64 custom_align;
i64 tag_size;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
bool no_nil;
bool is_polymorphic;
bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
bool is_polymorphic;
bool is_poly_specialized;
};
#define TYPE_KINDS \
@@ -190,7 +190,9 @@ struct TypeUnion {
TYPE_KIND(Tuple, struct { \
Array<Entity *> variables; /* Entity_Variable */ \
Array<i64> offsets; \
bool are_offsets_being_processed; \
bool are_offsets_set; \
bool is_packed; \
}) \
TYPE_KIND(Proc, struct { \
Ast *node; \
@@ -201,9 +203,8 @@ struct TypeUnion {
i32 result_count; \
Array<Type *> abi_compat_params; \
Type * abi_compat_result_type; \
bool return_by_pointer; \
bool variadic; \
i32 variadic_index; \
bool variadic; \
bool require_results; \
bool c_vararg; \
bool is_polymorphic; \
@@ -211,6 +212,7 @@ struct TypeUnion {
bool has_proc_default_values; \
bool has_named_results; \
bool diverging; /* no return */ \
bool return_by_pointer; \
u64 tags; \
isize specialization_count; \
ProcCallingConvention calling_convention; \
@@ -1782,7 +1784,8 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Tuple:
if (y->kind == Type_Tuple) {
if (x->Tuple.variables.count == y->Tuple.variables.count) {
if (x->Tuple.variables.count == y->Tuple.variables.count &&
x->Tuple.is_packed == y->Tuple.is_packed) {
for_array(i, x->Tuple.variables) {
Entity *xe = x->Tuple.variables[i];
Entity *ye = y->Tuple.variables[i];
@@ -2231,19 +2234,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
if (type->Array.count <= 4) {
// HACK(bill): Memory leak
switch (type->Array.count) {
#define _ARRAY_FIELD_CASE(_length, _name) \
case (_length): \
if (field_name == _name) { \
#define _ARRAY_FIELD_CASE_IF(_length, _name) \
if (field_name == (_name)) { \
selection_add_index(&sel, (_length)-1); \
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
return sel; \
} \
}
#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
case (_length): \
_ARRAY_FIELD_CASE_IF(_length, _name0); \
_ARRAY_FIELD_CASE_IF(_length, _name1); \
/*fallthrough*/
_ARRAY_FIELD_CASE(4, "w");
_ARRAY_FIELD_CASE(3, "z");
_ARRAY_FIELD_CASE(2, "y");
_ARRAY_FIELD_CASE(1, "x");
_ARRAY_FIELD_CASE(4, "w", "a");
_ARRAY_FIELD_CASE(3, "z", "b");
_ARRAY_FIELD_CASE(2, "y", "g");
_ARRAY_FIELD_CASE(1, "x", "r");
default: break;
#undef _ARRAY_FIELD_CASE
@@ -2590,9 +2596,9 @@ bool type_set_offsets(Type *t) {
}
} else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) {
t->Struct.are_offsets_being_processed = true;
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false);
t->Struct.are_offsets_being_processed = false;
t->Tuple.are_offsets_being_processed = true;
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
t->Tuple.are_offsets_being_processed = false;
t->Tuple.are_offsets_set = true;
return true;
}