mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-01 16:31:13 +00:00
Implicit parametric polymorphic procedures
This commit is contained in:
@@ -367,7 +367,10 @@ explicit_parametric_polymorphic_procedures :: proc() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
main :: proc() {
|
||||
/*
|
||||
general_stuff();
|
||||
foreign_blocks();
|
||||
default_arguments();
|
||||
@@ -381,6 +384,7 @@ main :: proc() {
|
||||
|
||||
program := "+ + * - /";
|
||||
accumulator := 0;
|
||||
*/
|
||||
|
||||
for token in program {
|
||||
match token {
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
)
|
||||
import_load "opengl_constants.odin";
|
||||
|
||||
_ := compile_assert(ODIN_OS != "osx");
|
||||
|
||||
foreign lib {
|
||||
Clear :: proc(mask: u32) #link_name "glClear" ---;
|
||||
ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---;
|
||||
|
||||
@@ -8,7 +8,6 @@ import "strings.odin";
|
||||
Handle :: i32;
|
||||
FileTime :: u64;
|
||||
Errno :: int;
|
||||
AddressSize :: int;
|
||||
|
||||
|
||||
O_RDONLY :: 0x00000;
|
||||
@@ -125,9 +124,9 @@ F_OK :: 0; // Test for file existance
|
||||
foreign libc {
|
||||
unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---;
|
||||
unix_close :: proc(handle: Handle) #link_name "close" ---;
|
||||
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read" ---;
|
||||
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write" ---;
|
||||
unix_lseek :: proc(fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek" ---;
|
||||
unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---;
|
||||
unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---;
|
||||
unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---;
|
||||
unix_gettid :: proc() -> u64 #link_name "gettid" ---;
|
||||
unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---;
|
||||
unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---;
|
||||
@@ -168,7 +167,7 @@ close :: proc(fd: Handle) {
|
||||
unix_close(fd);
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
bytes_written := unix_write(fd, &data[0], len(data));
|
||||
@@ -178,7 +177,7 @@ write :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
||||
return bytes_written, 0;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
bytes_read := unix_read(fd, &data[0], len(data));
|
||||
@@ -188,7 +187,7 @@ read :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) {
|
||||
return bytes_read, 0;
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) {
|
||||
seek :: proc(fd: Handle, offset: int, whence: int) -> (int, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
final_offset := unix_lseek(fd, offset, whence);
|
||||
|
||||
@@ -266,12 +266,12 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
String const ODIN_VERSION = str_lit("0.6.0-dev");
|
||||
|
||||
void init_build_context(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
bc->ODIN_VENDOR = str_lit("odin");
|
||||
bc->ODIN_VERSION = str_lit("0.6.0-dev");
|
||||
bc->ODIN_VERSION = ODIN_VERSION;
|
||||
bc->ODIN_ROOT = odin_root_dir();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
|
||||
@@ -329,7 +329,16 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
check_open_scope(c, pl->type);
|
||||
defer (check_close_scope(c));
|
||||
|
||||
#if 0
|
||||
if (e->token.string == "sort") {
|
||||
gb_printf_err("%.*s\n", LIT(e->token.string));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool prev_allow_polymorphic_types = c->context.allow_polymorphic_types;
|
||||
c->context.allow_polymorphic_types = true;
|
||||
check_procedure_type(c, proc_type, pl->type);
|
||||
c->context.allow_polymorphic_types = prev_allow_polymorphic_types;
|
||||
|
||||
bool is_foreign = (pl->tags & ProcTag_foreign) != 0;
|
||||
bool is_link_name = (pl->tags & ProcTag_link_name) != 0;
|
||||
@@ -348,11 +357,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
if (proc_type->Proc.calling_convention != ProcCC_Odin &&
|
||||
proc_type->Proc.calling_convention != ProcCC_Contextless) {
|
||||
if (pt->calling_convention != ProcCC_Odin &&
|
||||
pt->calling_convention != ProcCC_Contextless) {
|
||||
error(e->token, "Procedure `main` cannot have a custom calling convention");
|
||||
}
|
||||
proc_type->Proc.calling_convention = ProcCC_Contextless;
|
||||
pt->calling_convention = ProcCC_Contextless;
|
||||
}
|
||||
|
||||
if (is_inline && is_no_inline) {
|
||||
@@ -363,7 +372,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error(pl->type, "A foreign procedure cannot have an `export` tag");
|
||||
}
|
||||
|
||||
|
||||
if (pt->is_polymorphic) {
|
||||
if (pl->body == NULL) {
|
||||
error(e->token, "Polymorphic procedures must have a body");
|
||||
@@ -472,9 +480,15 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
String context_name = str_lit("variable declaration");
|
||||
|
||||
if (type_expr != NULL) {
|
||||
e->type = check_type(c, type_expr);
|
||||
}
|
||||
if (e->type != NULL && is_type_polymorphic(e->type)) {
|
||||
error(e->token, "Invalid use of a polymorphic type in %.*s", LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
}
|
||||
|
||||
|
||||
if (e->Variable.is_foreign) {
|
||||
@@ -514,7 +528,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
GB_ASSERT(entities == NULL || entities[0] == e);
|
||||
Operand operand = {};
|
||||
check_expr(c, &operand, init_expr);
|
||||
check_init_variable(c, e, &operand, str_lit("variable declaration"));
|
||||
check_init_variable(c, e, &operand, context_name);
|
||||
}
|
||||
|
||||
if (type_expr != NULL) {
|
||||
@@ -527,7 +541,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
Array<AstNode *> inits;
|
||||
array_init(&inits, c->allocator, 1);
|
||||
array_add(&inits, init_expr);
|
||||
check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration"));
|
||||
check_init_variables(c, entities, entity_count, inits, context_name);
|
||||
}
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
|
||||
@@ -1073,14 +1073,105 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As
|
||||
}
|
||||
}
|
||||
|
||||
bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound) {
|
||||
Operand o = {Addressing_Value};
|
||||
o.type = source;
|
||||
switch (poly->kind) {
|
||||
case Type_Basic:
|
||||
if (compound) return are_types_identical(poly, source);
|
||||
return check_is_assignable_to(c, &o, poly);
|
||||
case Type_Named:
|
||||
if (compound) return are_types_identical(poly, source);
|
||||
return check_is_assignable_to(c, &o, poly);
|
||||
|
||||
case Type_Generic: {
|
||||
Type *ds = default_type(source);
|
||||
gb_memmove(poly, ds, gb_size_of(Type));
|
||||
return true;
|
||||
}
|
||||
case Type_Pointer:
|
||||
if (source->kind == Type_Pointer) {
|
||||
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true);
|
||||
}
|
||||
return false;
|
||||
case Type_Atomic:
|
||||
if (source->kind == Type_Atomic) {
|
||||
return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true);
|
||||
}
|
||||
return false;
|
||||
case Type_Array:
|
||||
if (source->kind == Type_Array &&
|
||||
poly->Array.count == source->Array.count) {
|
||||
return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true);
|
||||
}
|
||||
return false;
|
||||
case Type_DynamicArray:
|
||||
if (source->kind == Type_DynamicArray) {
|
||||
return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true);
|
||||
}
|
||||
return false;
|
||||
case Type_Vector:
|
||||
if (source->kind == Type_Vector &&
|
||||
poly->Vector.count == source->Vector.count) {
|
||||
return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true);
|
||||
}
|
||||
return false;
|
||||
case Type_Slice:
|
||||
if (source->kind == Type_Slice) {
|
||||
return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true);
|
||||
}
|
||||
return false;
|
||||
|
||||
case Type_Record:
|
||||
if (source->kind == Type_Record) {
|
||||
// TODO(bill): Polymorphic type assignment
|
||||
}
|
||||
return false;
|
||||
case Type_Tuple:
|
||||
GB_PANIC("This should never happen");
|
||||
return false;
|
||||
case Type_Proc:
|
||||
if (source->kind == Type_Proc) {
|
||||
// TODO(bill): Polymorphic type assignment
|
||||
}
|
||||
return false;
|
||||
case Type_Map:
|
||||
if (source->kind == Type_Map) {
|
||||
bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true);
|
||||
bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true);
|
||||
return key || value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) {
|
||||
if (!is_operand_value(operand)) {
|
||||
error(operand.expr, "Cannot determine polymorphic type from parameter");
|
||||
return t_invalid;
|
||||
}
|
||||
if (is_polymorphic_type_assignable(c, poly_type, operand.type, false)) {
|
||||
return poly_type;
|
||||
}
|
||||
gbString pts = type_to_string(poly_type);
|
||||
gbString ots = type_to_string(operand.type);
|
||||
defer (gb_string_free(pts));
|
||||
defer (gb_string_free(ots));
|
||||
error(operand.expr,
|
||||
"Cannot determine polymorphic type from parameter: `%s` to `%s`\n"
|
||||
"\tNote: Record and procedure types are not yet supported",
|
||||
ots, pts);
|
||||
return t_invalid;
|
||||
}
|
||||
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, Array<Operand> *operands) {
|
||||
if (_params == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool allow_polymorphic_types = c->context.allow_polymorphic_types;
|
||||
|
||||
bool success = true;
|
||||
ast_node(field_list, FieldList, _params);
|
||||
Array<AstNode *> params = field_list->list;
|
||||
@@ -1123,6 +1214,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
bool default_is_nil = false;
|
||||
bool default_is_location = false;
|
||||
bool is_type_param = false;
|
||||
bool is_type_polymorphic_type = false;
|
||||
bool detemine_type_from_operand = false;
|
||||
|
||||
|
||||
if (type_expr == NULL) {
|
||||
@@ -1157,24 +1250,23 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
if (type_expr->kind == AstNode_HelperType) {
|
||||
is_type_param = true;
|
||||
if (operands != NULL) {
|
||||
Operand o = (*operands)[variable_index];
|
||||
if (o.mode == Addressing_Type) {
|
||||
type = o.type;
|
||||
} else {
|
||||
error(o.expr, "Expected a type to assign to the type parameter");
|
||||
type = t_invalid;
|
||||
success = false;
|
||||
}
|
||||
detemine_type_from_operand = true;
|
||||
type = t_invalid;
|
||||
} else {
|
||||
type = make_type_generic(c->allocator, 0, str_lit(""));
|
||||
}
|
||||
} else {
|
||||
type = check_type(c, type_expr);
|
||||
if (p->flags&FieldFlag_dollar) {
|
||||
error(type_expr, "`$` is only allowed for polymorphic type parameters at the moment");
|
||||
type = NULL;
|
||||
bool prev = c->context.allow_polymorphic_types;
|
||||
if (operands != NULL) {
|
||||
c->context.allow_polymorphic_types = true;
|
||||
}
|
||||
type = check_type(c, type_expr);
|
||||
|
||||
c->context.allow_polymorphic_types = prev;
|
||||
|
||||
if (is_type_polymorphic(type)) {
|
||||
is_type_polymorphic_type = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (default_value != NULL) {
|
||||
@@ -1218,12 +1310,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
type = t_invalid;
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
if (!is_type_pointer(type)) {
|
||||
error(params[i], "`#no_alias` can only be applied to fields of pointer type");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_c_vararg) {
|
||||
if (p->type == NULL ||
|
||||
p->type->kind != AstNode_Ellipsis) {
|
||||
@@ -1234,19 +1321,44 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for_array(j, p->names) {
|
||||
AstNode *name = p->names[j];
|
||||
if (ast_node_expect(name, AstNode_Ident)) {
|
||||
Entity *param = NULL;
|
||||
if (is_type_param) {
|
||||
if (operands != NULL) {
|
||||
Operand o = (*operands)[variable_index];
|
||||
if (o.mode == Addressing_Type) {
|
||||
type = o.type;
|
||||
} else {
|
||||
error(o.expr, "Expected a type to assign to the type parameter");
|
||||
type = t_invalid;
|
||||
}
|
||||
}
|
||||
param = make_entity_type_name(c->allocator, scope, name->Ident.token, type);
|
||||
param->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
if (operands != NULL && is_type_polymorphic_type) {
|
||||
type = determine_type_from_polymorphic(c, type, (*operands)[variable_index]);
|
||||
if (type == t_invalid) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
if (!is_type_pointer(type)) {
|
||||
error(params[i], "`#no_alias` can only be applied to fields of pointer type");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
}
|
||||
|
||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type,
|
||||
(p->flags&FieldFlag_using) != 0, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
param->Variable.default_is_location = default_is_location;
|
||||
|
||||
}
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
param->flags |= EntityFlag_NoAlias;
|
||||
@@ -1629,11 +1741,12 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
||||
if (e->kind != Entity_Variable) {
|
||||
is_polymorphic = true;
|
||||
break;
|
||||
} else if (is_type_polymorphic(e->type)) {
|
||||
is_polymorphic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (operands == NULL) {
|
||||
// GB_ASSERT(type->Proc.is_polymorphic == is_polymorphic);
|
||||
}
|
||||
type->Proc.is_polymorphic = is_polymorphic;
|
||||
|
||||
|
||||
type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count);
|
||||
@@ -2005,6 +2118,26 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, PolyType, e);
|
||||
AstNode *ident = pt->type;
|
||||
if (ident->kind != AstNode_Ident) {
|
||||
error(ident, "Expected an identifier after the $");
|
||||
*type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
Token token = ident->Ident.token;
|
||||
Type *t = make_type_generic(c->allocator, 0, token.string);
|
||||
if (c->context.allow_polymorphic_types) {
|
||||
Scope *s = c->context.scope;
|
||||
Entity *e = make_entity_type_name(c->allocator, s, token, t);
|
||||
e->TypeName.is_type_alias = true;
|
||||
add_entity(c, s, ident, e);
|
||||
}
|
||||
*type = t;
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(se, SelectorExpr, e);
|
||||
Operand o = {};
|
||||
check_selector(c, &o, e, NULL);
|
||||
@@ -2224,13 +2357,14 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||
}
|
||||
}
|
||||
|
||||
// if (is_type_polymorphic(type)) {
|
||||
if (is_type_poly_proc(type)) {
|
||||
#if 0
|
||||
if (!c->context.allow_polymorphic_types && is_type_polymorphic(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(e, "Invalid use of a polymorphic type `%s`", str);
|
||||
gb_string_free(str);
|
||||
type = t_invalid;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_type_typed(type)) {
|
||||
add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value);
|
||||
|
||||
@@ -1717,6 +1717,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
init_type = check_type(c, vd->type, NULL);
|
||||
if (init_type == NULL) {
|
||||
init_type = t_invalid;
|
||||
} else if (is_type_polymorphic(init_type)) {
|
||||
error(vd->type, "Invalid use of a polymorphic type in variable declaration");
|
||||
init_type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -261,6 +261,7 @@ struct CheckerContext {
|
||||
DeclInfo * decl;
|
||||
u32 stmt_state_flags;
|
||||
bool in_defer; // TODO(bill): Actually handle correctly
|
||||
bool allow_polymorphic_types;
|
||||
String proc_name;
|
||||
Type * type_hint;
|
||||
DeclInfo * curr_proc_decl;
|
||||
|
||||
@@ -375,7 +375,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
return 1;
|
||||
#endif
|
||||
} else if (args[1] == "version") {
|
||||
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(build_context.ODIN_VERSION));
|
||||
gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION));
|
||||
return 0;
|
||||
} else {
|
||||
usage(args[0]);
|
||||
|
||||
@@ -632,6 +632,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
|
||||
case AstNode_Undef: break;
|
||||
case AstNode_BasicLit: break;
|
||||
case AstNode_BasicDirective: break;
|
||||
|
||||
case AstNode_PolyType:
|
||||
n->PolyType.type = clone_ast_node(a, n->PolyType.type);
|
||||
break;
|
||||
case AstNode_Ellipsis:
|
||||
n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
|
||||
break;
|
||||
@@ -3259,8 +3263,10 @@ u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 se
|
||||
syntax_error(f->curr_token, "`#c_vararg` is not allowed within this field list");
|
||||
set_flags &= ~FieldFlag_c_vararg;
|
||||
}
|
||||
if ((allowed_flags&FieldFlag_dollar) == 0 && (set_flags&FieldFlag_dollar)) {
|
||||
syntax_error(f->curr_token, "`$` is only allowed within procedures");
|
||||
// if ((allowed_flags&FieldFlag_dollar) == 0 && (set_flags&FieldFlag_dollar)) {
|
||||
if ((set_flags&FieldFlag_dollar)) {
|
||||
// syntax_error(f->curr_token, "`$` is only allowed within procedures");
|
||||
syntax_error(f->curr_token, "`$` is not yet supported");
|
||||
set_flags &= ~FieldFlag_dollar;
|
||||
}
|
||||
return set_flags;
|
||||
|
||||
@@ -36,27 +36,27 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||
TOKEN_KIND(Token_CmpAnd, "&&"), \
|
||||
TOKEN_KIND(Token_CmpOr, "||"), \
|
||||
\
|
||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
TOKEN_KIND(Token_MulEq, "*="), \
|
||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||
TOKEN_KIND(Token_ModEq, "%="), \
|
||||
TOKEN_KIND(Token_ModModEq, "%%="), \
|
||||
TOKEN_KIND(Token_AndEq, "&="), \
|
||||
TOKEN_KIND(Token_OrEq, "|="), \
|
||||
TOKEN_KIND(Token_XorEq, "~="), \
|
||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||
TOKEN_KIND(Token_Inc, "++"), \
|
||||
TOKEN_KIND(Token_Dec, "--"), \
|
||||
TOKEN_KIND(Token_Undef, "---"), \
|
||||
TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
||||
TOKEN_KIND(Token_AddEq, "+="), \
|
||||
TOKEN_KIND(Token_SubEq, "-="), \
|
||||
TOKEN_KIND(Token_MulEq, "*="), \
|
||||
TOKEN_KIND(Token_QuoEq, "/="), \
|
||||
TOKEN_KIND(Token_ModEq, "%="), \
|
||||
TOKEN_KIND(Token_ModModEq, "%%="), \
|
||||
TOKEN_KIND(Token_AndEq, "&="), \
|
||||
TOKEN_KIND(Token_OrEq, "|="), \
|
||||
TOKEN_KIND(Token_XorEq, "~="), \
|
||||
TOKEN_KIND(Token_AndNotEq, "&~="), \
|
||||
TOKEN_KIND(Token_ShlEq, "<<="), \
|
||||
TOKEN_KIND(Token_ShrEq, ">>="), \
|
||||
TOKEN_KIND(Token_CmpAndEq, "&&="), \
|
||||
TOKEN_KIND(Token_CmpOrEq, "||="), \
|
||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||
TOKEN_KIND(Token_ThickArrowRight, "=>"), \
|
||||
TOKEN_KIND(Token_Inc, "++"), \
|
||||
TOKEN_KIND(Token_Dec, "--"), \
|
||||
TOKEN_KIND(Token_Undef, "---"), \
|
||||
\
|
||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||
@@ -910,7 +910,16 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break;
|
||||
|
||||
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
||||
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
||||
case '=':
|
||||
token.kind = Token_Eq;
|
||||
if (t->curr_rune == '>') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_ThickArrowRight;
|
||||
} else if (t->curr_rune == '=') {
|
||||
advance_to_next_rune(t);
|
||||
token.kind = Token_CmpEq;
|
||||
}
|
||||
break;
|
||||
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
||||
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
||||
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||
@@ -967,11 +976,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
} break;
|
||||
|
||||
case '<':
|
||||
if (t->curr_rune == '-') {
|
||||
token.kind = Token_ArrowLeft;
|
||||
} else {
|
||||
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
||||
}
|
||||
token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq);
|
||||
break;
|
||||
case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break;
|
||||
|
||||
|
||||
@@ -944,7 +944,6 @@ bool is_type_indexable(Type *t) {
|
||||
}
|
||||
|
||||
bool is_type_polymorphic(Type *t) {
|
||||
t = core_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Generic:
|
||||
return true;
|
||||
@@ -974,29 +973,36 @@ bool is_type_polymorphic(Type *t) {
|
||||
if (t->Proc.is_polymorphic) {
|
||||
return true;
|
||||
}
|
||||
// if (t->Proc.param_count > 0 &&
|
||||
// is_type_polymorphic(t->Proc.params)) {
|
||||
// return true;
|
||||
// }
|
||||
// if (t->Proc.result_count > 0 &&
|
||||
// is_type_polymorphic(t->Proc.results)) {
|
||||
// return true;
|
||||
// }
|
||||
#if 0
|
||||
if (t->Proc.param_count > 0 &&
|
||||
is_type_polymorphic(t->Proc.params)) {
|
||||
return true;
|
||||
}
|
||||
if (t->Proc.result_count > 0 &&
|
||||
is_type_polymorphic(t->Proc.results)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
// case Type_Record:
|
||||
// GB_ASSERT(t->Record.kind != TypeRecord_Enum);
|
||||
// for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
// if (is_type_polymorphic(t->Record.fields[i]->type)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||
// if (is_type_polymorphic(t->Record.variants[i]->type)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
case Type_Record:
|
||||
if (t->Record.kind == TypeRecord_Enum) {
|
||||
if (t->Record.enum_base_type != NULL) {
|
||||
return is_type_polymorphic(t->Record.enum_base_type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
if (is_type_polymorphic(t->Record.fields[i]->type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||
if (is_type_polymorphic(t->Record.variants[i]->type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Map:
|
||||
if (is_type_polymorphic(t->Map.key)) {
|
||||
@@ -2263,7 +2269,13 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
break;
|
||||
|
||||
case Type_Generic:
|
||||
str = gb_string_appendc(str, "type");
|
||||
if (type->Generic.name.len == 0) {
|
||||
str = gb_string_appendc(str, "type");
|
||||
} else {
|
||||
String name = type->Generic.name;
|
||||
str = gb_string_appendc(str, "$");
|
||||
str = gb_string_append_length(str, name.text, name.len);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Pointer:
|
||||
|
||||
Reference in New Issue
Block a user