mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Add $T: typeid/[]$E; Deprecate T: type/[]$E
`type` as a keyword will soon be removed in favour of polymorphic names (identifiers) in procedures
This commit is contained in:
+1
-1
@@ -767,7 +767,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
|||||||
return "", false;
|
return "", false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_to_enum_value :: proc(T: type, s: string) -> (T, bool) {
|
string_to_enum_value :: proc($T: typeid, s: string) -> (T, bool) {
|
||||||
ti := type_info_base(type_info_of(T));
|
ti := type_info_base(type_info_of(T));
|
||||||
if e, ok := ti.variant.(Type_Info_Enum); ok {
|
if e, ok := ti.variant.(Type_Info_Enum); ok {
|
||||||
for str, idx in e.names {
|
for str, idx in e.names {
|
||||||
|
|||||||
+1
-1
@@ -192,7 +192,7 @@ norm0 :: proc(v: $T/[$N]$E) -> T {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
identity :: proc(T: type/[$N][N]$E) -> T {
|
identity :: proc($T: typeid/[$N][N]$E) -> T {
|
||||||
m: T;
|
m: T;
|
||||||
for i in 0..N-1 do m[i][i] = E(1);
|
for i in 0..N-1 do m[i][i] = E(1);
|
||||||
return m;
|
return m;
|
||||||
|
|||||||
+6
-6
@@ -78,7 +78,7 @@ delete :: proc[
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
new :: inline proc(T: type, allocator := context.allocator, loc := #caller_location) -> ^T {
|
new :: inline proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> ^T {
|
||||||
ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc));
|
ptr := (^T)(alloc(size_of(T), align_of(T), allocator, loc));
|
||||||
if ptr != nil do ptr^ = T{};
|
if ptr != nil do ptr^ = T{};
|
||||||
return ptr;
|
return ptr;
|
||||||
@@ -90,25 +90,25 @@ new_clone :: inline proc(data: $T, allocator := context.allocator, loc := #calle
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
make_slice :: proc(T: type/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
|
make_slice :: proc($T: typeid/[]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
|
||||||
runtime.make_slice_error_loc(loc, len);
|
runtime.make_slice_error_loc(loc, len);
|
||||||
data := alloc(size_of(E)*len, align_of(E), allocator, loc);
|
data := alloc(size_of(E)*len, align_of(E), allocator, loc);
|
||||||
s := Raw_Slice{data, len};
|
s := Raw_Slice{data, len};
|
||||||
return transmute(T)s;
|
return transmute(T)s;
|
||||||
}
|
}
|
||||||
make_dynamic_array :: proc(T: type/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T {
|
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> T {
|
||||||
return make_dynamic_array_len_cap(T, 0, 16, allocator, loc);
|
return make_dynamic_array_len_cap(T, 0, 16, allocator, loc);
|
||||||
}
|
}
|
||||||
make_dynamic_array_len :: proc(T: type/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
|
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, auto_cast len: int, allocator := context.allocator, loc := #caller_location) -> T {
|
||||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc);
|
return make_dynamic_array_len_cap(T, len, len, allocator, loc);
|
||||||
}
|
}
|
||||||
make_dynamic_array_len_cap :: proc(T: type/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T {
|
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, auto_cast cap: int, allocator := context.allocator, loc := #caller_location) -> T {
|
||||||
runtime.make_dynamic_array_error_loc(loc, len, cap);
|
runtime.make_dynamic_array_error_loc(loc, len, cap);
|
||||||
data := alloc(size_of(E)*cap, align_of(E), allocator, loc);
|
data := alloc(size_of(E)*cap, align_of(E), allocator, loc);
|
||||||
s := Raw_Dynamic_Array{data, len, cap, allocator};
|
s := Raw_Dynamic_Array{data, len, cap, allocator};
|
||||||
return transmute(T)s;
|
return transmute(T)s;
|
||||||
}
|
}
|
||||||
make_map :: proc(T: type/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T {
|
make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T {
|
||||||
runtime.make_map_expr_error_loc(loc, cap);
|
runtime.make_map_expr_error_loc(loc, cap);
|
||||||
|
|
||||||
c := context;
|
c := context;
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ union_type :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See `parametric_polymorphism` procedure for details
|
// See `parametric_polymorphism` procedure for details
|
||||||
new_entity :: proc(T: type) -> ^Entity {
|
new_entity :: proc($T: typeid) -> ^Entity {
|
||||||
t := new(T);
|
t := new(T);
|
||||||
t.derived = t^;
|
t.derived = t^;
|
||||||
return t;
|
return t;
|
||||||
@@ -231,7 +231,7 @@ union_type :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See `parametric_polymorphism` procedure for details
|
// See `parametric_polymorphism` procedure for details
|
||||||
new_entity :: proc(T: type) -> ^Entity {
|
new_entity :: proc($T: typeid) -> ^Entity {
|
||||||
t := new(Entity);
|
t := new(Entity);
|
||||||
t.derived = T{entity = t};
|
t.derived = T{entity = t};
|
||||||
return t;
|
return t;
|
||||||
@@ -318,7 +318,7 @@ parametric_polymorphism :: proc() {
|
|||||||
fmt.printf("b: %T = %v\n", b, b);
|
fmt.printf("b: %T = %v\n", b, b);
|
||||||
|
|
||||||
// This is how `new` is implemented
|
// This is how `new` is implemented
|
||||||
alloc_type :: proc(T: type) -> ^T {
|
alloc_type :: proc($T: typeid) -> ^T {
|
||||||
t := cast(^T)alloc(size_of(T), align_of(T));
|
t := cast(^T)alloc(size_of(T), align_of(T));
|
||||||
t^ = T{}; // Use default initialization value
|
t^ = T{}; // Use default initialization value
|
||||||
return t;
|
return t;
|
||||||
@@ -341,21 +341,21 @@ parametric_polymorphism :: proc() {
|
|||||||
|
|
||||||
|
|
||||||
{ // Polymorphic Types and Type Specialization
|
{ // Polymorphic Types and Type Specialization
|
||||||
Table_Slot :: struct(Key, Value: type) {
|
Table_Slot :: struct(Key, Value: typeid) {
|
||||||
occupied: bool,
|
occupied: bool,
|
||||||
hash: u32,
|
hash: u32,
|
||||||
key: Key,
|
key: Key,
|
||||||
value: Value,
|
value: Value,
|
||||||
}
|
}
|
||||||
TABLE_SIZE_MIN :: 32;
|
TABLE_SIZE_MIN :: 32;
|
||||||
Table :: struct(Key, Value: type) {
|
Table :: struct(Key, Value: typeid) {
|
||||||
count: int,
|
count: int,
|
||||||
allocator: mem.Allocator,
|
allocator: mem.Allocator,
|
||||||
slots: []Table_Slot(Key, Value),
|
slots: []Table_Slot(Key, Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only allow types that are specializations of a (polymorphic) slice
|
// Only allow types that are specializations of a (polymorphic) slice
|
||||||
make_slice :: proc(T: type/[]$E, len: int) -> T {
|
make_slice :: proc($T: typeid/[]$E, len: int) -> T {
|
||||||
return make(T, len);
|
return make(T, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,6 +767,7 @@ bit_set_type :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
general_stuff();
|
general_stuff();
|
||||||
|
|||||||
+31
-12
@@ -374,18 +374,20 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
type_expr = type_expr->Ellipsis.expr;
|
type_expr = type_expr->Ellipsis.expr;
|
||||||
error(param, "A polymorphic parameter cannot be variadic");
|
error(param, "A polymorphic parameter cannot be variadic");
|
||||||
}
|
}
|
||||||
if (type_expr->kind == Ast_TypeType) {
|
if (type_expr->kind == Ast_TypeidType) {
|
||||||
|
is_type_param = true;
|
||||||
|
Type *specialization = nullptr;
|
||||||
|
if (type_expr->TypeidType.specialization != nullptr) {
|
||||||
|
Ast *s = type_expr->TypeidType.specialization;
|
||||||
|
specialization = check_type(ctx, s);
|
||||||
|
}
|
||||||
|
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||||
|
} else if (type_expr->kind == Ast_TypeType) {
|
||||||
is_type_param = true;
|
is_type_param = true;
|
||||||
Type *specialization = nullptr;
|
Type *specialization = nullptr;
|
||||||
if (type_expr->TypeType.specialization != nullptr) {
|
if (type_expr->TypeType.specialization != nullptr) {
|
||||||
Ast *s = type_expr->TypeType.specialization;
|
Ast *s = type_expr->TypeType.specialization;
|
||||||
specialization = check_type(ctx, s);
|
specialization = check_type(ctx, s);
|
||||||
// if (!is_type_polymorphic_struct(specialization)) {
|
|
||||||
// gbString str = type_to_string(specialization);
|
|
||||||
// defer (gb_string_free(str));
|
|
||||||
// error(s, "Expected a polymorphic struct, got %s", str);
|
|
||||||
// specialization = nullptr;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||||
} else {
|
} else {
|
||||||
@@ -1159,7 +1161,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ast_node(p, Field, param);
|
ast_node(p, Field, param);
|
||||||
Ast *type_expr = p->type;
|
Ast *type_expr = unparen_expr(p->type);
|
||||||
Type *type = nullptr;
|
Type *type = nullptr;
|
||||||
Ast *default_value = unparen_expr(p->default_value);
|
Ast *default_value = unparen_expr(p->default_value);
|
||||||
ParameterValue param_value = {};
|
ParameterValue param_value = {};
|
||||||
@@ -1183,7 +1185,24 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type_expr->kind == Ast_TypeType) {
|
if (type_expr->kind == Ast_TypeidType) {
|
||||||
|
ast_node(tt, TypeidType, type_expr);
|
||||||
|
if (tt->specialization) {
|
||||||
|
specialization = check_type(ctx, tt->specialization);
|
||||||
|
if (specialization == t_invalid){
|
||||||
|
specialization = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operands != nullptr) {
|
||||||
|
detemine_type_from_operand = true;
|
||||||
|
type = t_invalid;
|
||||||
|
} else {
|
||||||
|
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = t_typeid;
|
||||||
|
}
|
||||||
|
} else if (type_expr->kind == Ast_TypeType) {
|
||||||
ast_node(tt, TypeType, type_expr);
|
ast_node(tt, TypeType, type_expr);
|
||||||
is_type_param = true;
|
is_type_param = true;
|
||||||
specialization = check_type(ctx, tt->specialization);
|
specialization = check_type(ctx, tt->specialization);
|
||||||
@@ -1213,7 +1232,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (default_value != nullptr) {
|
if (default_value != nullptr) {
|
||||||
if (type_expr != nullptr && type_expr->kind == Ast_TypeType) {
|
if (type_expr != nullptr && (type_expr->kind == Ast_TypeType || type_expr->kind == Ast_TypeidType)) {
|
||||||
error(type_expr, "A type parameter may not have a default value");
|
error(type_expr, "A type parameter may not have a default value");
|
||||||
} else {
|
} else {
|
||||||
param_value = handle_parameter_value(ctx, type, nullptr, default_value, true);
|
param_value = handle_parameter_value(ctx, type, nullptr, default_value, true);
|
||||||
@@ -1281,7 +1300,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_poly_name) {
|
if (is_poly_name) {
|
||||||
if (type != nullptr && is_type_typeid(type)) {
|
if (type != nullptr && type_expr->kind == Ast_TypeidType) {
|
||||||
is_type_param = true;
|
is_type_param = true;
|
||||||
} else {
|
} else {
|
||||||
error(name, "Polymorphic names are not yet supported for non-typeid parameters");
|
error(name, "Polymorphic names are not yet supported for non-typeid parameters");
|
||||||
@@ -1324,7 +1343,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p->flags&FieldFlag_auto_cast) {
|
if (p->flags&FieldFlag_auto_cast) {
|
||||||
error(name, "'auto_cast' can only be applied variable fields");
|
error(name, "'auto_cast' can only be applied to variable fields");
|
||||||
p->flags &= ~FieldFlag_auto_cast;
|
p->flags &= ~FieldFlag_auto_cast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+55
-1
@@ -2435,6 +2435,7 @@ Ast *parse_value_decl(AstFile *f, Array<Ast *> names, CommentGroup *docs) {
|
|||||||
|
|
||||||
if (f->curr_token.kind == Token_type) {
|
if (f->curr_token.kind == Token_type) {
|
||||||
type = ast_type_type(f, advance_token(f), nullptr);
|
type = ast_type_type(f, advance_token(f), nullptr);
|
||||||
|
warning(type, "'type' is deprecated");
|
||||||
is_mutable = false;
|
is_mutable = false;
|
||||||
} else {
|
} else {
|
||||||
type = parse_type_or_ident(f);
|
type = parse_type_or_ident(f);
|
||||||
@@ -2718,6 +2719,19 @@ Ast *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) {
|
|||||||
specialization = parse_type(f);
|
specialization = parse_type(f);
|
||||||
}
|
}
|
||||||
type = ast_type_type(f, token, specialization);
|
type = ast_type_type(f, token, specialization);
|
||||||
|
if (specialization) {
|
||||||
|
warning(type, "'type' is deprecated, please use something like '$T: typeid/[]$E'");
|
||||||
|
} else {
|
||||||
|
warning(type, "'type' is deprecated, please use something like '$T: typeid'");
|
||||||
|
}
|
||||||
|
} else if (allow_type_token &&
|
||||||
|
f->curr_token.kind == Token_typeid) {
|
||||||
|
Token token = expect_token(f, Token_typeid);
|
||||||
|
Ast *specialization = nullptr;
|
||||||
|
if (allow_token(f, Token_Quo)) {
|
||||||
|
specialization = parse_type(f);
|
||||||
|
}
|
||||||
|
type = ast_typeid_type(f, token, specialization);
|
||||||
} else {
|
} else {
|
||||||
type = parse_type(f);
|
type = parse_type(f);
|
||||||
}
|
}
|
||||||
@@ -2855,7 +2869,7 @@ Array<Ast *> convert_to_ident_list(AstFile *f, Array<AstAndFlags> list, bool ign
|
|||||||
case Ast_PolyType:
|
case Ast_PolyType:
|
||||||
if (allow_poly_names) {
|
if (allow_poly_names) {
|
||||||
if (ident->PolyType.specialization == nullptr) {
|
if (ident->PolyType.specialization == nullptr) {
|
||||||
syntax_error(ident, "Polymorphic identifiers are not yet supported");
|
// syntax_error(ident, "Polymorphic identifiers are not yet supported");
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
syntax_error(ident, "Expected a polymorphic identifier without any specialization");
|
syntax_error(ident, "Expected a polymorphic identifier without any specialization");
|
||||||
@@ -2925,6 +2939,36 @@ Ast *parse_struct_field_list(AstFile *f, isize *name_count_) {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if any are polymorphic names
|
||||||
|
bool check_procedure_name_list(Array<Ast *> const &names) {
|
||||||
|
if (names.count == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool first_is_polymorphic = names[0]->kind == Ast_PolyType;
|
||||||
|
bool any_polymorphic_names = first_is_polymorphic;
|
||||||
|
for (isize i = 1; i < names.count; i++) {
|
||||||
|
Ast *name = names[i];
|
||||||
|
if (first_is_polymorphic) {
|
||||||
|
if (name->kind == Ast_PolyType) {
|
||||||
|
any_polymorphic_names = true;
|
||||||
|
} else {
|
||||||
|
syntax_error(name, "Mixture of polymorphic and non-polymorphic identifiers");
|
||||||
|
return any_polymorphic_names;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (name->kind == Ast_PolyType) {
|
||||||
|
any_polymorphic_names = true;
|
||||||
|
syntax_error(name, "Mixture of polymorphic and non-polymorphic identifiers");
|
||||||
|
return any_polymorphic_names;
|
||||||
|
} else {
|
||||||
|
// Okay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return any_polymorphic_names;
|
||||||
|
}
|
||||||
|
|
||||||
Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_type_token) {
|
Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_type_token) {
|
||||||
Token start_token = f->curr_token;
|
Token start_token = f->curr_token;
|
||||||
|
|
||||||
@@ -2965,6 +3009,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
if (names.count == 0) {
|
if (names.count == 0) {
|
||||||
syntax_error(f->curr_token, "Empty field declaration");
|
syntax_error(f->curr_token, "Empty field declaration");
|
||||||
}
|
}
|
||||||
|
bool any_polymorphic_names = check_procedure_name_list(names);
|
||||||
u32 set_flags = 0;
|
u32 set_flags = 0;
|
||||||
if (list.count > 0) {
|
if (list.count > 0) {
|
||||||
set_flags = list[0].flags;
|
set_flags = list[0].flags;
|
||||||
@@ -2978,6 +3023,10 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
expect_token_after(f, Token_Colon, "field list");
|
expect_token_after(f, Token_Colon, "field list");
|
||||||
if (f->curr_token.kind != Token_Eq) {
|
if (f->curr_token.kind != Token_Eq) {
|
||||||
type = parse_var_type(f, allow_ellipsis, allow_type_token);
|
type = parse_var_type(f, allow_ellipsis, allow_type_token);
|
||||||
|
Ast *tt = unparen_expr(type);
|
||||||
|
if (!any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
|
||||||
|
syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow_token(f, Token_Eq)) {
|
if (allow_token(f, Token_Eq)) {
|
||||||
@@ -3022,6 +3071,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
syntax_error(f->curr_token, "Empty field declaration");
|
syntax_error(f->curr_token, "Empty field declaration");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
bool any_polymorphic_names = check_procedure_name_list(names);
|
||||||
set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
|
set_flags = check_field_prefixes(f, names.count, allowed_flags, set_flags);
|
||||||
total_name_count += names.count;
|
total_name_count += names.count;
|
||||||
|
|
||||||
@@ -3030,6 +3080,10 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
expect_token_after(f, Token_Colon, "field list");
|
expect_token_after(f, Token_Colon, "field list");
|
||||||
if (f->curr_token.kind != Token_Eq) {
|
if (f->curr_token.kind != Token_Eq) {
|
||||||
type = parse_var_type(f, allow_ellipsis, allow_type_token);
|
type = parse_var_type(f, allow_ellipsis, allow_type_token);
|
||||||
|
Ast *tt = unparen_expr(type);
|
||||||
|
if (!any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
|
||||||
|
syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow_token(f, Token_Eq)) {
|
if (allow_token(f, Token_Eq)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user