mirror of
https://github.com/odin-lang/Odin.git
synced 2026-03-01 22:28:20 +00:00
Add types.odin; Begin work on map
This commit is contained in:
@@ -11,7 +11,11 @@
|
||||
|
||||
|
||||
main :: proc() {
|
||||
T0 :: struct #align 8 {};
|
||||
Value :: type f32;
|
||||
m0: map[int]Value;
|
||||
m1: map[string]Value;
|
||||
m2: map[f32]Value;
|
||||
// fm: map[128, int]f32;
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#import "fmt.odin";
|
||||
#import "mem.odin";
|
||||
#import "utf8.odin";
|
||||
#import "hash.odin";
|
||||
|
||||
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
|
||||
// #shared_global_scope due to the internals of the compiler.
|
||||
@@ -346,6 +347,16 @@ Raw_Dynamic_Array :: struct #ordered {
|
||||
allocator: Allocator,
|
||||
};
|
||||
|
||||
Raw_Dynamic_Map :: struct #ordered {
|
||||
hashes: [dynamic]int,
|
||||
entries: Raw_Dynamic_Array,
|
||||
};
|
||||
|
||||
__default_hash :: proc(data: rawptr, len: int) -> u64 {
|
||||
return hash.murmur64(data, len);
|
||||
}
|
||||
|
||||
|
||||
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capacity: int) -> bool {
|
||||
array := cast(^Raw_Dynamic_Array)array_;
|
||||
|
||||
@@ -398,3 +409,4 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
array.count += item_count;
|
||||
return array.count;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,13 +50,66 @@ fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
||||
s := slice_ptr(cast(^u8)data, len);
|
||||
|
||||
h :u64 = 0xcbf29ce484222325;
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for i in 0..<len {
|
||||
h = (h ~ cast(u64)s[i]) * 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
murmur32 :: proc(data: rawptr, len: int) -> u32 {
|
||||
compile_assert(ODIN_ENDIAN == "little");
|
||||
|
||||
SEED :: 0x9747b28c;
|
||||
|
||||
key := cast(^u8)data;
|
||||
h: u32 = SEED;
|
||||
|
||||
if len > 3 {
|
||||
key_x4 := cast(^u32)key;
|
||||
i := len>>2;
|
||||
for {
|
||||
k := key_x4^; key_x4 += 1;
|
||||
k *= 0xcc9e2d51;
|
||||
k = (k << 15) | (k >> 17);
|
||||
k *= 0x1b873593;
|
||||
h ~= k;
|
||||
h = (h << 13) | (h >> 19);
|
||||
h += (h << 2) + 0xe6546b64;
|
||||
i -= 1;
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
key = cast(^u8)key_x4;
|
||||
}
|
||||
if len&3 != 0 {
|
||||
i := len&3;
|
||||
k: u32 = 0;
|
||||
key += i-1;
|
||||
for {
|
||||
k <<= 8;
|
||||
k |= cast(u32)key^;
|
||||
key -= 1;
|
||||
i -= 1;
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
k *= 0xcc9e2d51;
|
||||
k = (k << 15) | (k >> 17);
|
||||
k *= 0x1b873593;
|
||||
h ~= k;
|
||||
}
|
||||
|
||||
h ~= cast(u32)len;
|
||||
h ~= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ~= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ~= h >> 16;
|
||||
return h;
|
||||
}
|
||||
|
||||
murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
||||
SEED :: 0x9747b28c;
|
||||
|
||||
146
core/types.odin
Normal file
146
core/types.odin
Normal file
@@ -0,0 +1,146 @@
|
||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||
if is_integer(info) {
|
||||
i := cast(^Type_Info.Integer)info;
|
||||
return i.signed;
|
||||
}
|
||||
if is_float(info) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Integer: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_float :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Float: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_any :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Any: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_string :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.String: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Boolean: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Pointer: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_maybe :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Maybe: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Procedure: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Array: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Dynamic_Array: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Slice: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_vector :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Vector: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Tuple: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Struct: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Union: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Raw_Union: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match type i in type_info_base(info) {
|
||||
case Type_Info.Enum: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
typedef struct BuildContext {
|
||||
String ODIN_OS; // target operating system
|
||||
String ODIN_ARCH; // target architecture
|
||||
String ODIN_ENDIAN; // target endian
|
||||
String ODIN_VENDOR; // compiler vendor
|
||||
String ODIN_VERSION; // compiler version
|
||||
String ODIN_ROOT; // Odin ROOT
|
||||
@@ -243,9 +244,11 @@ void init_build_context(BuildContext *bc) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
bc->ODIN_OS = str_lit("windows");
|
||||
bc->ODIN_ARCH = str_lit("amd64");
|
||||
bc->ODIN_ENDIAN = str_lit("little");
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
bc->ODIN_OS = str_lit("osx");
|
||||
bc->ODIN_ARCH = str_lit("amd64");
|
||||
bc->ODIN_ENDIAN = str_lit("little");
|
||||
#else
|
||||
#error Implement system
|
||||
#endif
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,6 +28,7 @@ typedef enum BuiltinProcId {
|
||||
BuiltinProc_free,
|
||||
|
||||
BuiltinProc_reserve,
|
||||
BuiltinProc_clear,
|
||||
BuiltinProc_append,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
@@ -69,6 +70,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT("free"), 1, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("reserve"), 2, false, Expr_Stmt},
|
||||
{STR_LIT("clear"), 1, false, Expr_Stmt},
|
||||
{STR_LIT("append"), 1, true, Expr_Expr},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr},
|
||||
@@ -610,6 +612,7 @@ void init_universal_scope(BuildContext *bc) {
|
||||
// TODO(bill): Set through flags in the compiler
|
||||
add_global_string_constant(a, str_lit("ODIN_OS"), bc->ODIN_OS);
|
||||
add_global_string_constant(a, str_lit("ODIN_ARCH"), bc->ODIN_ARCH);
|
||||
add_global_string_constant(a, str_lit("ODIN_ENDIAN"), bc->ODIN_ENDIAN);
|
||||
add_global_string_constant(a, str_lit("ODIN_VENDOR"), bc->ODIN_VENDOR);
|
||||
add_global_string_constant(a, str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
|
||||
add_global_string_constant(a, str_lit("ODIN_ROOT"), bc->ODIN_ROOT);
|
||||
@@ -1141,6 +1144,11 @@ void init_preload(Checker *c) {
|
||||
t_context_ptr = make_type_pointer(c->allocator, t_context);
|
||||
}
|
||||
|
||||
if (t_raw_dynamic_array == NULL) {
|
||||
Entity *e = find_core_entity(c, str_lit("Raw_Dynamic_Array"));
|
||||
t_raw_dynamic_array = e->type;
|
||||
}
|
||||
|
||||
c->done_preload = true;
|
||||
}
|
||||
|
||||
|
||||
8
src/ir.c
8
src/ir.c
@@ -2987,6 +2987,14 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
|
||||
} break;
|
||||
|
||||
case BuiltinProc_clear: {
|
||||
ir_emit_comment(proc, str_lit("reserve"));
|
||||
irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]);
|
||||
irValue *count_ptr = ir_emit_struct_ep(proc, array_ptr, 1);
|
||||
ir_emit_store(proc, count_ptr, v_zero);
|
||||
return NULL;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_append: {
|
||||
ir_emit_comment(proc, str_lit("append"));
|
||||
gbAllocator a = proc->module->allocator;
|
||||
|
||||
@@ -292,6 +292,18 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
}
|
||||
ir_fprintf(f, ")*");
|
||||
} return;
|
||||
|
||||
case Type_Map: {
|
||||
if (t->Map.count > 0) {
|
||||
// ir_fprintf(f, "void");
|
||||
} else {
|
||||
ir_fprintf(f, "{");
|
||||
ir_print_type(f, m, t_raw_dynamic_array);
|
||||
ir_fprintf(f, ", ");
|
||||
ir_print_type(f, m, t_raw_dynamic_array);
|
||||
ir_fprintf(f, "}");
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
139
src/types.c
139
src/types.c
@@ -95,35 +95,40 @@ typedef struct TypeRecord {
|
||||
Entity * enum_max_value;
|
||||
} TypeRecord;
|
||||
|
||||
#define TYPE_KINDS \
|
||||
TYPE_KIND(Basic, BasicType) \
|
||||
TYPE_KIND(Pointer, struct { Type *elem; }) \
|
||||
#define TYPE_KINDS \
|
||||
TYPE_KIND(Basic, BasicType) \
|
||||
TYPE_KIND(Pointer, struct { Type *elem; }) \
|
||||
TYPE_KIND(Array, struct { Type *elem; i64 count; }) \
|
||||
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
||||
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
||||
TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \
|
||||
TYPE_KIND(Slice, struct { Type *elem; }) \
|
||||
TYPE_KIND(Maybe, struct { Type *elem; }) \
|
||||
TYPE_KIND(Record, TypeRecord) \
|
||||
TYPE_KIND(Named, struct { \
|
||||
String name; \
|
||||
Type * base; \
|
||||
Entity *type_name; /* Entity_TypeName */ \
|
||||
}) \
|
||||
TYPE_KIND(Tuple, struct { \
|
||||
Entity **variables; /* Entity_Variable */ \
|
||||
i32 variable_count; \
|
||||
bool are_offsets_set; \
|
||||
i64 * offsets; \
|
||||
}) \
|
||||
TYPE_KIND(Proc, struct { \
|
||||
Scope *scope; \
|
||||
Type * params; /* Type_Tuple */ \
|
||||
Type * results; /* Type_Tuple */ \
|
||||
i32 param_count; \
|
||||
i32 result_count; \
|
||||
bool variadic; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
})
|
||||
TYPE_KIND(Slice, struct { Type *elem; }) \
|
||||
TYPE_KIND(Maybe, struct { Type *elem; }) \
|
||||
TYPE_KIND(Record, TypeRecord) \
|
||||
TYPE_KIND(Named, struct { \
|
||||
String name; \
|
||||
Type * base; \
|
||||
Entity *type_name; /* Entity_TypeName */ \
|
||||
}) \
|
||||
TYPE_KIND(Tuple, struct { \
|
||||
Entity **variables; /* Entity_Variable */ \
|
||||
i32 variable_count; \
|
||||
bool are_offsets_set; \
|
||||
i64 * offsets; \
|
||||
}) \
|
||||
TYPE_KIND(Proc, struct { \
|
||||
Scope *scope; \
|
||||
Type * params; /* Type_Tuple */ \
|
||||
Type * results; /* Type_Tuple */ \
|
||||
i32 param_count; \
|
||||
i32 result_count; \
|
||||
bool variadic; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
}) \
|
||||
TYPE_KIND(Map, struct { \
|
||||
i64 count; /* 0 if dynamic */ \
|
||||
Type *key; \
|
||||
Type *value; \
|
||||
}) \
|
||||
|
||||
|
||||
|
||||
@@ -319,6 +324,7 @@ gb_global Type *t_allocator_ptr = NULL;
|
||||
gb_global Type *t_context = NULL;
|
||||
gb_global Type *t_context_ptr = NULL;
|
||||
|
||||
gb_global Type *t_raw_dynamic_array = NULL;
|
||||
|
||||
|
||||
|
||||
@@ -477,6 +483,23 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun
|
||||
return t;
|
||||
}
|
||||
|
||||
bool is_type_valid_for_keys(Type *t);
|
||||
|
||||
Type *make_type_map(gbAllocator a, i64 count, Type *key, Type *value) {
|
||||
Type *t = alloc_type(a, Type_Map);
|
||||
if (key != NULL) {
|
||||
GB_ASSERT(is_type_valid_for_keys(key));
|
||||
}
|
||||
t->Map.count = count;
|
||||
t->Map.key = key;
|
||||
t->Map.value = value;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Type *type_deref(Type *t) {
|
||||
if (t != NULL) {
|
||||
@@ -679,6 +702,21 @@ bool is_type_enum(Type *t) {
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum);
|
||||
}
|
||||
|
||||
bool is_type_map(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Map;
|
||||
}
|
||||
|
||||
bool is_type_fixed_map(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Map && t->Map.count > 0;
|
||||
}
|
||||
bool is_type_dynamic_map(Type *t) {
|
||||
t = base_type(t); return t->kind == Type_Map && t->Map.count == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool is_type_any(Type *t) {
|
||||
t = base_type(t);
|
||||
@@ -691,6 +729,28 @@ bool is_type_untyped_nil(Type *t) {
|
||||
|
||||
|
||||
|
||||
bool is_type_valid_for_keys(Type *t) {
|
||||
t = base_type(base_enum_type(t));
|
||||
if (is_type_untyped(t)) {
|
||||
return false;
|
||||
}
|
||||
if (is_type_integer(t)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_float(t)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(t)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_pointer(t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_indexable(Type *t) {
|
||||
return is_type_array(t) || is_type_slice(t) || is_type_vector(t) || is_type_string(t);
|
||||
}
|
||||
@@ -1458,6 +1518,14 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
return align;
|
||||
}
|
||||
|
||||
case Type_Map: {
|
||||
if (t->Map.count == 0) { // Dynamic
|
||||
// NOTE(bill): same as a dynamic array
|
||||
return s.word_size;
|
||||
}
|
||||
GB_PANIC("TODO(bill): Fixed map alignment");
|
||||
} break;
|
||||
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
@@ -1667,6 +1735,14 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
|
||||
return align_formula(size, align);
|
||||
}
|
||||
|
||||
case Type_Map: {
|
||||
if (t->Map.count == 0) { // Dynamic
|
||||
// NOTE(bill): same as a two dynamic arrays
|
||||
return 2 * type_size_of_internal(s, allocator, t_raw_dynamic_array, path);
|
||||
}
|
||||
GB_PANIC("TODO(bill): Fixed map size");
|
||||
}
|
||||
|
||||
case Type_Tuple: {
|
||||
i64 count, align, size;
|
||||
count = t->Tuple.variable_count;
|
||||
@@ -1924,6 +2000,15 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case Type_Map: {
|
||||
str = gb_string_appendc(str, "map[");
|
||||
if (type->Map.count > 0) {
|
||||
str = gb_string_appendc(str, gb_bprintf("%lld, ", type->Map.count));
|
||||
}
|
||||
str = write_type_to_string(str, type->Map.key);
|
||||
str = gb_string_appendc(str, "]");
|
||||
str = write_type_to_string(str, type->Map.value);
|
||||
} break;
|
||||
|
||||
case Type_Named:
|
||||
if (type->Named.type_name != NULL) {
|
||||
|
||||
Reference in New Issue
Block a user