From 5b8be2593821c7b30adf010bc90dfa8ab2930a72 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Wed, 26 Apr 2017 19:43:17 +0100 Subject: [PATCH] `fmt.String_Buffer`, Fix issue #44, Tweak overloading rules --- core/fmt.odin | 224 ++++++++++++++++++++++++++------------- core/os_windows.odin | 3 + src/check_decl.c | 75 ++++++++------ src/check_expr.c | 65 ++++++++---- src/check_stmt.c | 242 +++++++++++++++++++++++-------------------- src/checker.c | 13 ++- src/entity.c | 15 ++- src/ir.c | 33 ++++-- src/main.c | 2 +- src/parser.c | 12 ++- src/types.c | 14 +++ 11 files changed, 439 insertions(+), 259 deletions(-) diff --git a/core/fmt.odin b/core/fmt.odin index 4c998b7f6..6ec0a11bd 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -8,20 +8,64 @@ _BUFFER_SIZE :: 1<<12; -write_string :: proc(buf: ^[]byte, s: string) { - append(buf, ..cast([]byte)s); +String_Buffer :: struct { + is_dynamic: bool, + sa: []byte, + da: [dynamic]byte, +}; + +make_string_buffer_from_slice :: proc(b: []byte) -> String_Buffer { + return String_Buffer{ + is_dynamic = false, + sa = b, + }; } -write_byte :: proc(buf: ^[]byte, b: byte) { - append(buf, b); + +make_string_dynamic_buffer :: proc() -> String_Buffer { + return String_Buffer{ + is_dynamic = true, + da = make([dynamic]byte), + }; } -write_rune :: proc(buf: ^[]byte, r: rune) { +string_buffer_data :: proc(buf: ^String_Buffer) -> []byte { + return string_buffer_data(buf^); +} +string_buffer_data :: proc(buf: String_Buffer) -> []byte { + if buf.is_dynamic { + return buf.da[..]; + } + return buf.sa[..]; +} +to_string :: proc(buf: String_Buffer) -> string { + return cast(string)string_buffer_data(buf); +} + + +write_string :: proc(buf: ^String_Buffer, s: string) { + write_bytes(buf, cast([]byte)s); +} +write_bytes :: proc(buf: ^String_Buffer, b: []byte) { + if buf.is_dynamic { + append(buf.da, ..b); + } else { + append(buf.sa, ..b); + } +} +write_byte :: proc(buf: ^String_Buffer, b: byte) { + if buf.is_dynamic { + append(buf.da, b); + } else { + append(buf.sa, b); + } +} +write_rune :: proc(buf: ^String_Buffer, r: rune) { if r < utf8.RUNE_SELF { write_byte(buf, cast(byte)r); return; } b, n := utf8.encode_rune(r); - append(buf, ..b[0.. int { data: [_BUFFER_SIZE]byte; - buf := data[0..<0]; - bprint(^buf, ..args); - os.write(fd, buf); - return len(buf); + buf := make_string_buffer_from_slice(data[0..<0]); + sbprint(^buf, ..args); + res := string_buffer_data(buf); + os.write(fd, res); + return len(res); } fprintln :: proc(fd: os.Handle, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := data[0..<0]; - bprintln(^buf, ..args); - os.write(fd, buf); - return len(buf); + buf := make_string_buffer_from_slice(data[0..<0]); + sbprintln(^buf, ..args); + res := string_buffer_data(buf); + os.write(fd, res); + return len(res); } fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := data[0..<0]; - bprintf(^buf, fmt, ..args); - os.write(fd, buf); - return len(buf); + buf := make_string_buffer_from_slice(data[0..<0]); + sbprintf(^buf, fmt, ..args); + res := string_buffer_data(buf); + os.write(fd, res); + return len(res); } @@ -80,14 +127,56 @@ printf :: proc(fmt: string, args: ..any) -> int { } -fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { - data: [_BUFFER_SIZE]byte; - buf := data[0..<0]; - write_type(^buf, info); - os.write(fd, buf); +// aprint* procedures return a string that was allocated with the current context +// They must be freed accordingly +aprint :: proc(args: ..any) -> string { + buf := make_string_dynamic_buffer(); + sbprint(^buf, ..args); + return to_string(buf); +} +aprintln :: proc(args: ..any) -> string { + buf := make_string_dynamic_buffer(); + sbprintln(^buf, ..args); + return to_string(buf); +} +aprintf :: proc(fmt: string, args: ..any) -> string { + buf := make_string_dynamic_buffer(); + sbprintf(^buf, fmt, ..args); + return to_string(buf); } -write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { + +// bprint* procedures + + +// aprint* procedure return a string that was allocated with the current context +// They must be freed accordingly +bprint :: proc(buf: []byte, args: ..any) -> int { + sb := make_string_buffer_from_slice(buf[0..<0.. int { + sb := make_string_buffer_from_slice(buf[0..<0.. int { + sb := make_string_buffer_from_slice(buf[0..<0.. int { - fi: Fmt_Info; - fi.buf = buf; - - prev_string := false; - for arg, i in args { - is_string := arg != nil && types.is_string(arg.type_info); - if i > 0 && !is_string && !prev_string { - write_byte(buf, ' '); - } - fmt_value(^fi, args[i], 'v'); - prev_string = is_string; - } - return len(buf); -} - -bprintln :: proc(buf: ^[]byte, args: ..any) -> int { - fi: Fmt_Info; - fi.buf = buf; - - for arg, i in args { - if i > 0 { - write_byte(buf, ' '); - } - fmt_value(^fi, args[i], 'v'); - } - write_byte(buf, '\n'); - return len(buf); -} - -sprint :: proc(buf: []byte, args: ..any) -> string { - count := bprint(^buf, ..args); - return cast(string)buf[0.. string { - count := bprintln(^buf, ..args); - return cast(string)buf[0.. string { - count := bprintf(^buf, fmt, ..args); - return cast(string)buf[0.. (result: int, offset: int, ok: bool) { is_digit :: proc(r: rune) -> bool #inline { @@ -439,9 +483,10 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { pad_byte = '0'; } - count := min(width, cap(fi.buf)-len(fi.buf)); + data := string_buffer_data(fi.buf^); + count := min(width, cap(data)-len(data)); for _ in 0..count { - append(fi.buf, pad_byte); + write_byte(fi.buf, pad_byte); } } @@ -998,7 +1043,38 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { } -bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { + +sbprint :: proc(buf: ^String_Buffer, args: ..any) -> int { + fi: Fmt_Info; + fi.buf = buf; + + prev_string := false; + for arg, i in args { + is_string := arg != nil && types.is_string(arg.type_info); + if i > 0 && !is_string && !prev_string { + write_byte(buf, ' '); + } + fmt_value(^fi, args[i], 'v'); + prev_string = is_string; + } + return len(string_buffer_data(buf)); +} + +sbprintln :: proc(buf: ^String_Buffer, args: ..any) -> int { + fi: Fmt_Info; + fi.buf = buf; + + for arg, i in args { + if i > 0 { + write_byte(buf, ' '); + } + fmt_value(^fi, args[i], 'v'); + } + write_byte(buf, '\n'); + return len(string_buffer_data(buf)); +} + +sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ..any) -> int { fi := Fmt_Info{}; end := len(fmt); arg_index := 0; @@ -1128,5 +1204,5 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { write_string(b, ")"); } - return len(b); + return len(string_buffer_data(b)); } diff --git a/core/os_windows.odin b/core/os_windows.odin index 07d030e16..28b83e483 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -109,6 +109,9 @@ close :: proc(fd: Handle) { win32.CloseHandle(cast(win32.Handle)fd); } +write_string :: proc(fd: Handle, str: string) -> (int, Errno) { + return write(fd, cast([]byte)str); +} write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { return 0, ERROR_NONE; diff --git a/src/check_decl.c b/src/check_decl.c index 5239b67d8..ff9e2a88c 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -413,7 +413,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } -void check_alias_decl(Checker *c, Entity *e, AstNode *expr) { +void check_alias_decl(Checker *c, Entity *e, AstNode *expr, Type *named_type) { GB_ASSERT(e->type == NULL); GB_ASSERT(e->kind == Entity_Alias); @@ -431,36 +431,47 @@ void check_alias_decl(Checker *c, Entity *e, AstNode *expr) { return; } - if (expr->kind == AstNode_Ident) { - Operand o = {0}; - Entity *f = check_ident(c, &o, expr, NULL, NULL, true); - if (f != NULL) { - e->Alias.original = f; - e->type = f->type; - } - return; - } else if (expr->kind == AstNode_SelectorExpr) { - Operand o = {0}; - Entity *f = check_selector(c, &o, expr, NULL); - if (f != NULL) { - e->Alias.original = f; - e->type = f->type; - } - return; - } - - Operand o = {0}; - check_expr_or_type(c, &o, expr); - if (o.mode == Addressing_Invalid) { - return; - } - switch (o.mode) { - case Addressing_Type: - e->type = o.type; - break; - default: + Operand operand = {0}; + check_expr_or_type(c, &operand, expr); + if (operand.mode != Addressing_Type) { error_node(expr, "#alias declarations only allow types"); + return; } + e->kind = Entity_TypeName; + e->TypeName.is_type_alias = true; + e->type = NULL; + + DeclInfo *d = c->context.decl; + d->type_expr = expr; + check_type_decl(c, e, d->type_expr, named_type); + + + // Operand o = {0}; + // Entity *f = NULL; + // if (expr->kind == AstNode_Ident) { + // f = check_ident(c, &o, expr, NULL, NULL, true); + // } else if (expr->kind == AstNode_SelectorExpr) { + // f = check_selector(c, &o, expr, NULL); + // } else { + // check_expr_or_type(c, &o, expr); + // } + // if (o.mode == Addressing_Invalid) { + // return; + // } + // switch (o.mode) { + // case Addressing_Type: + // e->type = o.type; + // // e->kind = Entity_TypeName; + // // e->TypeName.is_type_alias = true; + // e->Alias.kind = EntityAlias_Type; + // e->Alias.original = f; + // break; + // default: + // error_node(expr, "#alias declarations only allow types"); + // e->kind = Entity_Invalid; + // e->type = t_invalid; + // break; + // } } void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { @@ -495,12 +506,12 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { case Entity_TypeName: check_type_decl(c, e, d->type_expr, named_type); break; + case Entity_Alias: + check_alias_decl(c, e, d->init_expr, named_type); + break; case Entity_Procedure: check_proc_lit(c, e, d); break; - case Entity_Alias: - check_alias_decl(c, e, d->init_expr); - break; } c->context = prev; diff --git a/src/check_expr.c b/src/check_expr.c index 882d467e4..b183d3ccb 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -147,7 +147,31 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { if (dst->kind == Type_Basic) { if (operand->mode == Addressing_Constant) { if (check_representable_as_constant(c, operand->value, dst, NULL)) { - return 1; + if (is_type_typed(dst) && src->kind == Type_Basic) { + switch (src->Basic.kind) { + case Basic_UntypedInteger: + if (is_type_integer(dst)) { + return 1; + } + break; + case Basic_UntypedFloat: + if (is_type_float(dst)) { + return 1; + } + break; + case Basic_UntypedComplex: + if (is_type_complex(dst)) { + return 1; + } + break; + case Basic_UntypedQuaternion: + if (is_type_quaternion(dst)) { + return 1; + } + break; + } + } + return 2; } return -1; } @@ -1058,12 +1082,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { case 32: new_type = t_u32; break; case 64: new_type = t_u64; break; default: - // NOTE(bill): It could be an empty struct that is passed - // and if that is the case, no need to pass by pointer - // (I think..) - if (size > 0) { - new_type = make_type_pointer(a, original_type); - } + new_type = make_type_pointer(a, original_type); break; } } break; @@ -1196,11 +1215,6 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * e->flags |= EntityFlag_Used; - Entity *original_e = e; - while (e != NULL && e->kind == Entity_Alias && e->Alias.original != NULL) { - e = e->Alias.original; - } - Type *type = e->type; switch (e->kind) { case Entity_Constant: @@ -1261,6 +1275,17 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * o->mode = Addressing_Value; break; + case Entity_Alias: { + // error_node(n, "#alias entities are not yet supported"); + // TODO(bill): Fix Entity_Alias rules + if (e->Alias.kind == EntityAlias_Type) { + o->mode = Addressing_Type; + } else { + o->mode = Addressing_Invalid; + return e; + } + } break; + default: compiler_error("Unknown EntityKind"); break; @@ -3136,6 +3161,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h operand->builtin_id = entity->Builtin.id; break; + case Entity_Alias: { + error_node(selector, "#alias entities are not yet supported"); + return NULL; + } break; + // NOTE(bill): These cases should never be hit but are here for sanity reasons case Entity_Nil: operand->mode = Addressing_Value; @@ -3899,8 +3929,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Operand z = {0}; Operand w = {0}; - GB_PANIC("BuiltinProc_quaternion"); - // NOTE(bill): Invalid will be the default till fixed operand->type = t_invalid; operand->mode = Addressing_Invalid; @@ -3990,12 +4018,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id BasicKind kind = core_type(x.type)->Basic.kind; switch (kind) { - case Basic_complex64: x.type = t_f32; break; - case Basic_complex128: x.type = t_f64; break; - case Basic_UntypedComplex: x.type = t_untyped_float; break; - case Basic_quaternion128: x.type = t_f32; break; - case Basic_quaternion256: x.type = t_f64; break; - case Basic_UntypedQuaternion: x.type = t_untyped_float; break; + case Basic_f32: operand->type = t_quaternion128; break; + case Basic_f64: operand->type = t_quaternion256; break; + case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break; default: GB_PANIC("Invalid type"); break; } } break; diff --git a/src/check_stmt.c b/src/check_stmt.c index f34c4c837..17bd6a2c7 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -432,6 +432,134 @@ void check_label(Checker *c, AstNode *label) { } } +// Returns `true` for `continue`, `false` for `return` +bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) { + if (e == NULL) { + error(us->token, "`using` applied to an unknown entity"); + return true; + } + + switch (e->kind) { + case Entity_Alias: { + if (e->Alias.original != NULL) { + check_using_stmt_entity(c, us, expr, is_selector, e->Alias.original); + } else { + error(us->token, "`using` cannot be applied to the alias `%.*s`", LIT(e->token.string)); + return false; + } + } break; + + case Entity_TypeName: { + Type *t = base_type(e->type); + if (is_type_union(t)) { + TokenPos pos = ast_node_token(expr).pos; + for (isize i = 1; i < t->Record.variant_count; i++) { + Entity *f = t->Record.variants[i]; + // gb_printf_err("%s\n", type_to_string(f->type)); + Entity *found = scope_insert_entity(c->context.scope, f); + if (found != NULL) { + gbString expr_str = expr_to_string(expr); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + gb_string_free(expr_str); + return false; + } + f->using_parent = e; + } + } else if (is_type_enum(t)) { + for (isize i = 0; i < t->Record.field_count; i++) { + Entity *f = t->Record.fields[i]; + Entity *found = scope_insert_entity(c->context.scope, f); + if (found != NULL) { + gbString expr_str = expr_to_string(expr); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + gb_string_free(expr_str); + return false; + } + f->using_parent = e; + } + + } else { + error(us->token, "`using` can be only applied to `union` or `enum` type entities"); + } + } break; + + case Entity_ImportName: { + Scope *scope = e->ImportName.scope; + for_array(i, scope->elements.entries) { + Entity *decl = scope->elements.entries.e[i].value; + Entity *found = scope_insert_entity(c->context.scope, decl); + if (found != NULL) { + gbString expr_str = expr_to_string(expr); + error(us->token, + "Namespace collision while `using` `%s` of: %.*s\n" + "\tat %.*s(%td:%td)\n" + "\tat %.*s(%td:%td)", + expr_str, LIT(found->token.string), + LIT(found->token.pos.file), found->token.pos.line, found->token.pos.column, + LIT(decl->token.pos.file), decl->token.pos.line, decl->token.pos.column + ); + gb_string_free(expr_str); + return false; + } + } + } break; + + case Entity_Variable: { + Type *t = base_type(type_deref(e->type)); + if (is_type_struct(t) || is_type_raw_union(t)) { + // TODO(bill): Make it work for unions too + Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); + GB_ASSERT(found != NULL); + for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries.e[i].value; + if (f->kind == Entity_Variable) { + Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); + if (is_selector) { + uvar->using_expr = expr; + } + Entity *prev = scope_insert_entity(c->context.scope, uvar); + if (prev != NULL) { + gbString expr_str = expr_to_string(expr); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); + gb_string_free(expr_str); + return false; + } + } + } + } else { + error(us->token, "`using` can only be applied to variables of type struct or raw_union"); + return false; + } + } break; + + case Entity_Constant: + error(us->token, "`using` cannot be applied to a constant"); + break; + + case Entity_Procedure: + case Entity_Builtin: + error(us->token, "`using` cannot be applied to a procedure"); + break; + + case Entity_Nil: + error(us->token, "`using` cannot be applied to `nil`"); + break; + + case Entity_Label: + error(us->token, "`using` cannot be applied to a label"); + break; + + case Entity_Invalid: + error(us->token, "`using` cannot be applied to an invalid entity"); + break; + + default: + GB_PANIC("TODO(bill): `using` other expressions?"); + } + + return true; +} + void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -1341,118 +1469,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { continue; } - if (e == NULL) { - error(us->token, "`using` applied to an unknown entity"); - continue; - } - - switch (e->kind) { - case Entity_TypeName: { - Type *t = base_type(e->type); - if (is_type_union(t)) { - TokenPos pos = ast_node_token(expr).pos; - for (isize i = 1; i < t->Record.variant_count; i++) { - Entity *f = t->Record.variants[i]; - // gb_printf_err("%s\n", type_to_string(f->type)); - Entity *found = scope_insert_entity(c->context.scope, f); - if (found != NULL) { - gbString expr_str = expr_to_string(expr); - error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); - gb_string_free(expr_str); - return; - } - f->using_parent = e; - } - } else if (is_type_enum(t)) { - for (isize i = 0; i < t->Record.field_count; i++) { - Entity *f = t->Record.fields[i]; - Entity *found = scope_insert_entity(c->context.scope, f); - if (found != NULL) { - gbString expr_str = expr_to_string(expr); - error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); - gb_string_free(expr_str); - return; - } - f->using_parent = e; - } - - } else { - error(us->token, "`using` can be only applied to `union` or `enum` type entities"); - } - } break; - - case Entity_ImportName: { - Scope *scope = e->ImportName.scope; - for_array(i, scope->elements.entries) { - Entity *decl = scope->elements.entries.e[i].value; - Entity *found = scope_insert_entity(c->context.scope, decl); - if (found != NULL) { - gbString expr_str = expr_to_string(expr); - error(us->token, - "Namespace collision while `using` `%s` of: %.*s\n" - "\tat %.*s(%td:%td)\n" - "\tat %.*s(%td:%td)", - expr_str, LIT(found->token.string), - LIT(found->token.pos.file), found->token.pos.line, found->token.pos.column, - LIT(decl->token.pos.file), decl->token.pos.line, decl->token.pos.column - ); - gb_string_free(expr_str); - return; - } - } - } break; - - case Entity_Variable: { - Type *t = base_type(type_deref(e->type)); - if (is_type_struct(t) || is_type_raw_union(t)) { - // TODO(bill): Make it work for unions too - Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node)); - GB_ASSERT(found != NULL); - for_array(i, (*found)->elements.entries) { - Entity *f = (*found)->elements.entries.e[i].value; - if (f->kind == Entity_Variable) { - Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); - if (is_selector) { - uvar->using_expr = expr; - } - Entity *prev = scope_insert_entity(c->context.scope, uvar); - if (prev != NULL) { - gbString expr_str = expr_to_string(expr); - error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); - gb_string_free(expr_str); - return; - } - } - } - } else { - error(us->token, "`using` can only be applied to variables of type struct or raw_union"); - return; - } - } break; - - case Entity_Constant: - error(us->token, "`using` cannot be applied to a constant"); - break; - - case Entity_Procedure: - case Entity_Builtin: - error(us->token, "`using` cannot be applied to a procedure"); - break; - - case Entity_Nil: - error(us->token, "`using` cannot be applied to `nil`"); - break; - - case Entity_Label: - error(us->token, "`using` cannot be applied to a label"); - break; - - case Entity_Invalid: - error(us->token, "`using` cannot be applied to an invalid entity"); - break; - - default: - GB_PANIC("TODO(bill): `using` other expressions?"); + if (!check_using_stmt_entity(c, us, expr, is_selector, e)) { + return; } } case_end; diff --git a/src/checker.c b/src/checker.c index 7ce2dc772..495a0a750 100644 --- a/src/checker.c +++ b/src/checker.c @@ -1531,11 +1531,15 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) d->type_expr = type; d->init_expr = type; } else if (up_init != NULL && up_init->kind == AstNode_Alias) { + #if 1 error_node(up_init, "#alias declarations are not yet supported"); continue; - // e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, NULL); - // d->init_expr = init->Alias.expr; - }else if (init != NULL && up_init->kind == AstNode_ProcLit) { + #else + e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, EntityAlias_Invalid, NULL); + d->type_expr = vd->type; + d->init_expr = up_init->Alias.expr; + #endif + } else if (init != NULL && up_init->kind == AstNode_ProcLit) { e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags); d->proc_lit = up_init; d->type_expr = vd->type; @@ -1989,7 +1993,8 @@ void check_parsed_files(Checker *c) { // NOTE(bill): Check for illegal cyclic type declarations for_array(i, c->info.definitions.entries) { Entity *e = c->info.definitions.entries.e[i].value; - if (e->kind == Entity_TypeName) { + if (e->kind == Entity_TypeName || + (e->kind == Entity_Alias && e->Alias.kind == EntityAlias_Type)) { if (e->type != NULL) { // i64 size = type_size_of(c->sizes, c->allocator, e->type); i64 align = type_align_of(c->allocator, e->type); diff --git a/src/entity.c b/src/entity.c index 068169e55..41d11371e 100644 --- a/src/entity.c +++ b/src/entity.c @@ -50,11 +50,18 @@ typedef enum OverloadKind { Overload_Yes, } OverloadKind; +typedef enum EntityAliasKind { + EntityAlias_Invalid, + EntityAlias_Type, + EntityAlias_Entity, +} EntityAliasKind; + // An Entity is a named "thing" in the language typedef struct Entity Entity; struct Entity { EntityKind kind; + u64 id; u32 flags; Token token; Scope * scope; @@ -101,7 +108,8 @@ struct Entity { bool used; } LibraryName; struct { - Entity *original; + EntityAliasKind kind; + Entity * original; } Alias; i32 Nil; struct { @@ -138,6 +146,7 @@ bool is_entity_exported(Entity *e) { return name.text[0] != '_'; } +gb_global u64 global_entity_id = 0; Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) { Entity *entity = gb_alloc_item(a, Entity); @@ -145,6 +154,7 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, entity->scope = scope; entity->token = token; entity->type = type; + entity->id = ++global_entity_id; return entity; } @@ -231,8 +241,9 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type } Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, - Entity *original) { + EntityAliasKind kind, Entity *original) { Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type); + entity->Alias.kind = kind; entity->Alias.original = original; return entity; } diff --git a/src/ir.c b/src/ir.c index 57cad2293..e1ccc9838 100644 --- a/src/ir.c +++ b/src/ir.c @@ -3284,23 +3284,34 @@ String ir_mangle_name(irGen *s, String path, Entity *e) { char const *ext = gb_path_extension(base); isize base_len = ext-1-base; - isize max_len = base_len + 1 + 10 + 1 + name.len; + isize max_len = base_len + 1 + 1 + 10 + 1 + name.len; bool is_overloaded = check_is_entity_overloaded(e); if (is_overloaded) { max_len += 21; } u8 *new_name = gb_alloc_array(a, u8, max_len); - isize new_name_len = gb_snprintf( - cast(char *)new_name, max_len, - "%.*s-%u.%.*s", - cast(int)base_len, base, - file->id, - LIT(name)); + isize new_name_len = 0; + if ((base_len > 0 && gb_char_is_digit(base[0])) || + base_len == 0) { + new_name_len = gb_snprintf( + cast(char *)new_name, max_len, + "_%.*s-%u.%.*s", + cast(int)base_len, base, + file->id, + LIT(name)); + } else { + new_name_len = gb_snprintf( + cast(char *)new_name, max_len, + "%.*s-%u.%.*s", + cast(int)base_len, base, + file->id, + LIT(name)); + } if (is_overloaded) { char *str = cast(char *)new_name + new_name_len-1; isize len = max_len-new_name_len; - isize extra = gb_snprintf(str, len, "-%tu", cast(usize)cast(uintptr)e); + isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); new_name_len += extra-1; } @@ -4311,7 +4322,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { irValue *kmag = ir_build_expr(proc, ce->args.e[3]); irValue *dst = ir_add_local_generated(proc, tv->type); - Type *ft = base_complex_elem_type(tv->type); + Type *ft = base_quaternion_elem_type(tv->type); real = ir_emit_conv(proc, real, ft); imag = ir_emit_conv(proc, imag, ft); jmag = ir_emit_conv(proc, jmag, ft); @@ -7217,6 +7228,7 @@ void ir_gen_tree(irGen *s) { if (var->init != NULL && var->init->kind == irValue_Constant) { Type *t = type_deref(ir_type(var->var)); if (is_type_any(t)) { + // NOTE(bill): Edge case for `any` type Type *var_type = default_type(ir_type(var->init)); irValue *g = ir_add_global_generated(proc->module, var_type, var->init); irValue *data = ir_emit_struct_ep(proc, var->var, 0); @@ -7233,7 +7245,8 @@ void ir_gen_tree(irGen *s) { irGlobalVariable *var = &global_variables.e[i]; if (var->init != NULL && var->init->kind != irValue_Constant) { Type *t = type_deref(ir_type(var->var)); - if (is_type_any(t)) { + if (is_type_any(t)) { + // NOTE(bill): Edge case for `any` type Type *var_type = default_type(ir_type(var->init)); irValue *g = ir_add_global_generated(proc->module, var_type, var->init); ir_emit_store(proc, g, var->init); diff --git a/src/main.c b/src/main.c index fd853dd82..68673949b 100644 --- a/src/main.c +++ b/src/main.c @@ -430,7 +430,7 @@ int main(int argc, char **argv) { exit_code = system_exec_command_line_app("ld-link", true, "%s \"%.*s\".o -o \"%.*s%s\" %s " - "-lc " + "-lc -lm " " %.*s " " %s " #if defined(GB_SYSTEM_OSX) diff --git a/src/parser.c b/src/parser.c index 962a04afd..a0a215789 100644 --- a/src/parser.c +++ b/src/parser.c @@ -33,6 +33,7 @@ typedef struct AstFile { // NOTE(bill): Used to prevent type literals in control clauses isize expr_level; bool allow_range; + bool ignore_operand; AstNodeArray decls; bool is_global_scope; @@ -1849,10 +1850,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { } } - Token begin = f->curr_token; - syntax_error(begin, "Expected an operand"); - fix_advance_to_next_stmt(f); - return ast_bad_expr(f, begin, f->curr_token); + return NULL; } bool is_literal_type(AstNode *node) { @@ -1937,6 +1935,12 @@ AstNode *parse_macro_call_expr(AstFile *f, AstNode *operand) { AstNode *parse_atom_expr(AstFile *f, bool lhs) { AstNode *operand = parse_operand(f, lhs); + if (operand == NULL) { + Token begin = f->curr_token; + syntax_error(begin, "Expected an operand"); + fix_advance_to_next_stmt(f); + operand = ast_bad_expr(f, begin, f->curr_token); + } bool loop = true; while (loop) { diff --git a/src/types.c b/src/types.c index 2f2bbbfef..7ddf21f30 100644 --- a/src/types.c +++ b/src/types.c @@ -551,6 +551,20 @@ bool is_type_named(Type *t) { } return t->kind == Type_Named; } +bool is_type_named_alias(Type *t) { + if (!is_type_named(t)) { + return false; + } + Entity *e = t->Named.type_name; + if (e == NULL) { + return false; + } + if (e->kind != Entity_TypeName) { + return false; + } + return e->TypeName.is_type_alias; +} + bool is_type_boolean(Type *t) { t = core_type(t); if (t->kind == Type_Basic) {