diff --git a/code/demo.odin b/code/demo.odin index 4b9c27a15..91f3e132e 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,6 +1,5 @@ import ( "fmt.odin"; -/* "atomics.odin"; "bits.odin"; "decimal.odin"; @@ -16,6 +15,7 @@ import ( "types.odin"; "utf8.odin"; "utf16.odin"; +/* */ ) @@ -370,9 +370,11 @@ main :: proc() { foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y); foo :: proc(x: type) do fmt.println("#3", type_info(x)); - foo(y = 3785.1546, x = 123); - foo(x = int, y = 897.513); - foo(x = f32); + f :: foo; + + f(y = 3785.1546, x = 123); + f(x = int, y = 897.513); + f(x = f32); /* general_stuff(); foreign_blocks(); diff --git a/core/_preload.odin b/core/_preload.odin index 28841d822..94ce0d8f6 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -504,8 +504,20 @@ __mem_compare :: proc(a, b: ^u8, n: int) -> int #cc_contextless { } foreign __llvm_core { - __sqrt_f32 :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---; - __sqrt_f64 :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---; + __sqrt_f32 :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---; + __sqrt_f64 :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---; + + __sin_f32 :: proc(θ: f32) -> f32 #link_name "llvm.sin.f32" ---; + __sin_f64 :: proc(θ: f64) -> f64 #link_name "llvm.sin.f64" ---; + + __cos_f32 :: proc(θ: f32) -> f32 #link_name "llvm.cos.f32" ---; + __cos_f64 :: proc(θ: f64) -> f64 #link_name "llvm.cos.f64" ---; + + __pow_f32 :: proc(x, power: f32) -> f32 #link_name "llvm.pow.f32" ---; + __pow_f64 :: proc(x, power: f64) -> f64 #link_name "llvm.pow.f64" ---; + + fmuladd32 :: proc(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32" ---; + fmuladd64 :: proc(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64" ---; } __abs_complex64 :: proc(x: complex64) -> f32 #inline #cc_contextless { r, i := real(x), imag(x); diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 14fd6f3ec..76558e948 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -191,25 +191,80 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, } Operand operand = {}; - if (init != NULL) { - check_expr_or_type(c, &operand, init); - } -#if 1 - if (operand.mode == Addressing_Type) { - e->kind = Entity_TypeName; - DeclInfo *d = c->context.decl; - d->type_expr = d->init_expr; - check_type_decl(c, e, d->type_expr, named_type); - return; + if (init != NULL) { + Entity *entity = NULL; + if (init->kind == AstNode_Ident) { + entity = check_ident(c, &operand, init, NULL, e->type, true); + } else if (init->kind == AstNode_SelectorExpr) { + entity = check_selector(c, &operand, init, e->type); + } else { + check_expr_or_type(c, &operand, init, e->type); + } + + switch (operand.mode) { + case Addressing_Type: { + e->kind = Entity_TypeName; + + DeclInfo *d = c->context.decl; + d->type_expr = d->init_expr; + check_type_decl(c, e, d->type_expr, named_type); + return; + } break; + + case Addressing_Builtin: + if (e->type != NULL) { + error(type_expr, "A constant alias of a built-in procedure may not have a type initializer"); + } + e->kind = Entity_Builtin; + e->Builtin.id = operand.builtin_id; + e->type = t_invalid; + return; + + case Addressing_Overload: + e->kind = Entity_Alias; + e->Alias.base = operand.overload_entities[0]; + e->type = t_invalid; + return; + } + + if (entity != NULL) { + switch (entity->kind) { + case Entity_Procedure: + e->kind = Entity_Alias; + e->type = entity->type; + e->Alias.base = entity; + return; + case Entity_ImportName: + e->kind = Entity_ImportName; + e->type = entity->type; + e->ImportName.path = entity->ImportName.path; + e->ImportName.name = entity->ImportName.path; + e->ImportName.scope = entity->ImportName.scope; + e->ImportName.used = false; + return; + case Entity_LibraryName: + e->kind = Entity_LibraryName; + e->type = entity->type; + e->LibraryName.path = entity->LibraryName.path; + e->LibraryName.name = entity->LibraryName.path; + e->LibraryName.used = false; + return; + } + } + } + + if (init != NULL) { + check_expr_or_type(c, &operand, init, e->type); } -#endif check_init_constant(c, e, &operand); if (operand.mode == Addressing_Invalid || base_type(operand.type) == t_invalid) { - error(e->token, "Invalid declaration type"); + gbString str = expr_to_string(init); + error(e->token, "Invalid declaration type `%s`", str); + gb_string_free(str); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f8efb0575..b2dd98fa9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -33,7 +33,7 @@ typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); void check_expr (Checker *c, Operand *operand, AstNode *expression); void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); -void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); +void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); void check_expr_with_type_hint (Checker *c, Operand *o, AstNode *e, Type *t); Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL); @@ -1260,7 +1260,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari success = false; } } - if (type_expr->kind == AstNode_HelperType) { + if (type_expr->kind == AstNode_TypeType) { is_type_param = true; if (operands != NULL) { detemine_type_from_operand = true; @@ -1283,7 +1283,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } if (default_value != NULL) { - if (type_expr->kind == AstNode_HelperType) { + if (type_expr->kind == AstNode_TypeType) { error(default_value, "A type parameter may not have a default value"); } else { Operand o = {}; @@ -1817,7 +1817,16 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * bool is_overloaded = false; isize overload_count = 0; - HashKey key = hash_string(name); + + bool is_alias = false; + while (e->kind == Entity_Alias) { + GB_ASSERT(e->Alias.base != NULL); + e = e->Alias.base; + is_alias = true; + } + + HashKey key = hash_string(e->token.string); + if (e->kind == Entity_Procedure) { // NOTE(bill): Overloads are only allowed with the same scope @@ -2135,6 +2144,10 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) } case_end; + case_ast_node(ht, HelperType, e); + return check_type_internal(c, ht->type, type, named_type); + case_end; + case_ast_node(pt, PolyType, e); AstNode *ident = pt->type; if (ident->kind != AstNode_Ident) { @@ -6047,6 +6060,24 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t o->mode = Addressing_Value; o->type = t_context; break; + + case Token_size_of: + o->mode = Addressing_Builtin; + o->builtin_id = BuiltinProc_size_of; + break; + case Token_align_of: + o->mode = Addressing_Builtin; + o->builtin_id = BuiltinProc_align_of; + break; + case Token_offset_of: + o->mode = Addressing_Builtin; + o->builtin_id = BuiltinProc_offset_of; + break; + case Token_type_of: + o->mode = Addressing_Builtin; + o->builtin_id = BuiltinProc_type_of; + break; + default: error(node, "Illegal implicit name `%.*s`", LIT(i->string)); return kind; @@ -6916,7 +6947,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } case_end; - case AstNode_HelperType: + case AstNode_TypeType: case AstNode_ProcType: case AstNode_PointerType: case AstNode_ArrayType: @@ -7001,8 +7032,8 @@ void check_expr(Checker *c, Operand *o, AstNode *e) { } -void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { - check_expr_base(c, o, e, NULL); +void check_expr_or_type(Checker *c, Operand *o, AstNode *e, Type *type_hint) { + check_expr_base(c, o, e, type_hint); check_not_tuple(c, o); error_operand_no_value(o); } @@ -7148,6 +7179,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, fv->value); case_end; + case_ast_node(ht, HelperType, node); + str = gb_string_appendc(str, "#type "); + str = write_expr_to_string(str, ht->type); + case_end; + case_ast_node(pt, PointerType, node); str = gb_string_appendc(str, "^"); str = write_expr_to_string(str, pt->type); @@ -7271,7 +7307,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, ")"); case_end; - case_ast_node(ht, HelperType, node); + case_ast_node(ht, TypeType, node); str = gb_string_appendc(str, "type"); case_end; diff --git a/src/checker.cpp b/src/checker.cpp index 8c692080a..3586f7986 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -61,6 +61,12 @@ enum BuiltinProcId { BuiltinProc_abs, BuiltinProc_clamp, +/* BuiltinProc_sqrt, + BuiltinProc_sin, + BuiltinProc_cos, + BuiltinProc_tan, + BuiltinProc_pow, */ + BuiltinProc_transmute, BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures @@ -107,6 +113,14 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("abs"), 1, false, Expr_Expr}, {STR_LIT("clamp"), 3, false, Expr_Expr}, +/* + {STR_LIT("__sqrt"), 1, false, Expr_Expr}, + {STR_LIT("__sin"), 1, false, Expr_Expr}, + {STR_LIT("__cos"), 1, false, Expr_Expr}, + {STR_LIT("__tan"), 1, false, Expr_Expr}, + {STR_LIT("__pow"), 2, false, Expr_Expr}, + */ + {STR_LIT("transmute"), 2, false, Expr_Expr}, {STR_LIT(""), 0, true, Expr_Expr}, // DIRECTIVE diff --git a/src/entity.cpp b/src/entity.cpp index e38a374fc..1f2478c25 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -12,6 +12,7 @@ struct DeclInfo; ENTITY_KIND(TypeName) \ ENTITY_KIND(Procedure) \ ENTITY_KIND(Builtin) \ + ENTITY_KIND(Alias) \ ENTITY_KIND(ImportName) \ ENTITY_KIND(LibraryName) \ ENTITY_KIND(Nil) \ @@ -108,6 +109,9 @@ struct Entity { struct { i32 id; } Builtin; + struct { + Entity *base; + } Alias; struct { String path; String name; @@ -232,6 +236,12 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type return entity; } +Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) { + Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type); + entity->Alias.base = base; + return entity; +} + Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type, String path, String name, Scope *import_scope) { Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type); diff --git a/src/ir.cpp b/src/ir.cpp index a1141905e..ed1988a5b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5639,6 +5639,13 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) { GB_ASSERT(ident->kind == AstNode_Ident); Entity *e = entity_of_ident(proc->module->info, ident); GB_ASSERT(e != NULL); + switch (e->kind) { + case Entity_TypeName: + case Entity_Procedure: + break; + default: + continue; + } bool polymorphic = is_type_polymorphic(e->type); diff --git a/src/parser.cpp b/src/parser.cpp index 5ad4a410b..2d134d420 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -375,9 +375,13 @@ AST_NODE_KIND(_DeclEnd, "", i32) \ AstNode *list; \ }) \ AST_NODE_KIND(_TypeBegin, "", i32) \ - AST_NODE_KIND(HelperType, "type", struct { \ + AST_NODE_KIND(TypeType, "type", struct { \ Token token; \ }) \ + AST_NODE_KIND(HelperType, "helper type", struct { \ + Token token; \ + AstNode *type; \ + }) \ AST_NODE_KIND(PolyType, "polymorphic type", struct { \ Token token; \ AstNode *type; \ @@ -585,6 +589,7 @@ Token ast_node_token(AstNode *node) { case AstNode_UnionField: return ast_node_token(node->UnionField.name); + case AstNode_TypeType: return node->TypeType.token; case AstNode_HelperType: return node->HelperType.token; case AstNode_PolyType: return node->PolyType.token; case AstNode_ProcType: return node->ProcType.token; @@ -829,7 +834,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { n->UnionField.list = clone_ast_node(a, n->UnionField.list); break; + case AstNode_TypeType: + break; case AstNode_HelperType: + n->HelperType.type = clone_ast_node(a, n->HelperType.type); break; case AstNode_ProcType: n->ProcType.params = clone_ast_node(a, n->ProcType.params); @@ -1367,12 +1375,20 @@ AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) { } -AstNode *ast_helper_type(AstFile *f, Token token) { - AstNode *result = make_ast_node(f, AstNode_HelperType); - result->HelperType.token = token; +AstNode *ast_type_type(AstFile *f, Token token) { + AstNode *result = make_ast_node(f, AstNode_TypeType); + result->TypeType.token = token; return result; } +AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) { + AstNode *result = make_ast_node(f, AstNode_HelperType); + result->HelperType.token = token; + result->HelperType.type = type; + return result; +} + + AstNode *ast_poly_type(AstFile *f, Token token, AstNode *type) { AstNode *result = make_ast_node(f, AstNode_PolyType); result->PolyType.token = token; @@ -2187,6 +2203,14 @@ AstNode *parse_operand(AstFile *f, bool lhs) { next_token(f); return operand; + case Token_size_of: + case Token_align_of: + case Token_offset_of: { + operand = ast_implicit(f, f->curr_token); next_token(f); + return parse_call_expr(f, operand); + } + + case Token_String: { Token token = f->curr_token; next_token(f); @@ -2228,6 +2252,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) { case Token_Hash: { Token token = expect_token(f, Token_Hash); + if (allow_token(f, Token_type)) { + return ast_helper_type(f, token, parse_type(f)); + } Token name = expect_token(f, Token_Ident); if (name.string == "run") { AstNode *expr = parse_expr(f, false); @@ -3162,7 +3189,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) { break; } if (f->type != NULL && - f->type->kind == AstNode_HelperType) { + f->type->kind == AstNode_TypeType) { is_generic = true; break; } @@ -3186,7 +3213,7 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) AstNode *type = NULL; if (allow_type_token && f->curr_token.kind == Token_type) { - type = ast_helper_type(f, expect_token(f, Token_type)); + type = ast_type_type(f, expect_token(f, Token_type)); } else { type = parse_type_attempt(f); } @@ -3473,8 +3500,6 @@ AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String } AstNode *parse_type_or_ident(AstFile *f) { - AstNode *type = NULL; - switch (f->curr_token.kind) { case Token_Dollar: { Token token = expect_token(f, Token_Dollar); @@ -3482,8 +3507,19 @@ AstNode *parse_type_or_ident(AstFile *f) { return ast_poly_type(f, token, type); } break; - case Token_Ident: - { + case Token_type_of: { + AstNode *i = ast_implicit(f, expect_token(f, Token_type_of)); + AstNode *type = parse_call_expr(f, i); + while (f->curr_token.kind == Token_Period) { + Token token = f->curr_token; + next_token(f); + AstNode *sel = parse_ident(f); + type = ast_selector_expr(f, token, type, sel); + } + return type; + } break; + + case Token_Ident: { AstNode *e = parse_ident(f); while (f->curr_token.kind == Token_Period) { Token token = f->curr_token; @@ -3496,21 +3532,28 @@ AstNode *parse_type_or_ident(AstFile *f) { // HACK NOTE(bill): For type_of_val(expr) et al. // e = parse_call_expr(f, e); // } - type = e; + return e; } break; case Token_Pointer: { Token token = expect_token(f, Token_Pointer); AstNode *elem = parse_type(f); - type = ast_pointer_type(f, token, elem); + return ast_pointer_type(f, token, elem); } break; case Token_atomic: { Token token = expect_token(f, Token_atomic); AstNode *elem = parse_type(f); - type = ast_atomic_type(f, token, elem); + return ast_atomic_type(f, token, elem); } break; + case Token_Hash: { + Token hash_token = expect_token(f, Token_Hash); + Token type_token = expect_token(f, Token_type); + AstNode *type = parse_type(f); + return ast_helper_type(f, hash_token, type); + } + case Token_OpenBracket: { Token token = expect_token(f, Token_OpenBracket); AstNode *count_expr = NULL; @@ -3541,7 +3584,7 @@ AstNode *parse_type_or_ident(AstFile *f) { if (is_vector) { return ast_vector_type(f, token, count_expr, parse_type(f)); } - type = ast_array_type(f, token, count_expr, parse_type(f)); + return ast_array_type(f, token, count_expr, parse_type(f)); } break; case Token_map: { @@ -3559,7 +3602,7 @@ AstNode *parse_type_or_ident(AstFile *f) { Token close = expect_token(f, Token_CloseBracket); value = parse_type(f); - type = ast_map_type(f, token, count, key, value); + return ast_map_type(f, token, count, key, value); } break; case Token_struct: { @@ -3610,7 +3653,7 @@ AstNode *parse_type_or_ident(AstFile *f) { decls = fields->FieldList.list; } - type = ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align); + return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align); } break; case Token_union: { @@ -3664,7 +3707,7 @@ AstNode *parse_type_or_ident(AstFile *f) { Token close = expect_token(f, Token_CloseBrace); - type = ast_union_type(f, token, decls, total_decl_name_count, variants); + return ast_union_type(f, token, decls, total_decl_name_count, variants); } break; case Token_raw_union: { @@ -3680,7 +3723,7 @@ AstNode *parse_type_or_ident(AstFile *f) { decls = fields->FieldList.list; } - type = ast_raw_union_type(f, token, decls, decl_count); + return ast_raw_union_type(f, token, decls, decl_count); } break; case Token_enum: { @@ -3694,7 +3737,7 @@ AstNode *parse_type_or_ident(AstFile *f) { Array values = parse_element_list(f); Token close = expect_token(f, Token_CloseBrace); - type = ast_enum_type(f, token, base_type, values); + return ast_enum_type(f, token, base_type, values); } break; case Token_bit_field: { @@ -3739,7 +3782,7 @@ AstNode *parse_type_or_ident(AstFile *f) { close = expect_token(f, Token_CloseBrace); - type = ast_bit_field_type(f, token, fields, align); + return ast_bit_field_type(f, token, fields, align); } break; case Token_proc: { @@ -3748,18 +3791,18 @@ AstNode *parse_type_or_ident(AstFile *f) { if (pt->ProcType.tags != 0) { syntax_error(token, "A procedure type cannot have tags"); } - type = pt; + return pt; } break; case Token_OpenParen: { Token open = expect_token(f, Token_OpenParen); AstNode *type = parse_type(f); Token close = expect_token(f, Token_CloseParen); - type = ast_paren_expr(f, type, open, close); + return ast_paren_expr(f, type, open, close); } break; } - return type; + return NULL; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 24a2397f2..3adff3e74 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -118,6 +118,10 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_context, "context"), \ TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_push_allocator, "push_allocator"), \ + TOKEN_KIND(Token_size_of, "size_of"), \ + TOKEN_KIND(Token_align_of, "align_of"), \ + TOKEN_KIND(Token_offset_of, "offset_of"), \ + TOKEN_KIND(Token_type_of, "type_of"), \ TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_yield, "yield"), \ TOKEN_KIND(Token_await, "await"), \