mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-17 19:32:23 -07:00
Merge branch 'master' of github.com:gingerBill/Odin
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=1
|
||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
set release_mode=0
|
||||
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_flags=%compiler_flags% -Od -MDd -Z7
|
||||
@@ -42,13 +42,10 @@ set linker_settings=%libs% %linker_flags%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
odin run code/demo.odin
|
||||
rem cl %compiler_settings% "src\main.c" ^
|
||||
rem /link %linker_settings% -OUT:%exe_name% ^
|
||||
rem && odin run code/demo.odin
|
||||
rem && odin build code/metagen.odin ^
|
||||
rem && call "code\metagen.exe" "src\ast_nodes.metagen"
|
||||
rem && odin run code/Jaze/src/main.odin
|
||||
rem odin run code/demo.odin
|
||||
cl %compiler_settings% "src\main.cpp" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run code/demo.odin
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
|
||||
+94
-94
@@ -1,98 +1,7 @@
|
||||
#define ARRAY_GROW_FORMULA(x) (2*(x) + 8)
|
||||
GB_STATIC_ASSERT(ARRAY_GROW_FORMULA(0) > 0);
|
||||
|
||||
#define Array(Type_) struct { \
|
||||
gbAllocator allocator; \
|
||||
Type_ * e; \
|
||||
isize count; \
|
||||
isize capacity; \
|
||||
}
|
||||
|
||||
typedef Array(void) ArrayVoid;
|
||||
|
||||
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
|
||||
void **e = cast(void **)&((x_)->e); \
|
||||
GB_ASSERT((x_) != NULL); \
|
||||
(x_)->allocator = (allocator_); \
|
||||
(x_)->count = 0; \
|
||||
(x_)->capacity = (init_capacity_); \
|
||||
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \
|
||||
} while (0)
|
||||
|
||||
#define array_init_count(x_, allocator_, init_count_) do { \
|
||||
void **e = cast(void **)&((x_)->e); \
|
||||
GB_ASSERT((x_) != NULL); \
|
||||
(x_)->allocator = (allocator_); \
|
||||
(x_)->count = (init_count_); \
|
||||
(x_)->capacity = (init_count_); \
|
||||
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \
|
||||
} while (0)
|
||||
|
||||
#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0)
|
||||
#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0)
|
||||
#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0)
|
||||
|
||||
#define array_grow(x_, min_capacity_) do { \
|
||||
isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \
|
||||
if (new_capacity < (min_capacity_)) { \
|
||||
new_capacity = (min_capacity_); \
|
||||
} \
|
||||
array_set_capacity(x_, new_capacity); \
|
||||
} while (0)
|
||||
|
||||
#define array_add(x_, item_) do { \
|
||||
if ((x_)->capacity < (x_)->count+1) { \
|
||||
array_grow(x_, 0); \
|
||||
} \
|
||||
(x_)->e[(x_)->count++] = item_; \
|
||||
} while (0)
|
||||
|
||||
#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0)
|
||||
#define array_clear(x_) do { (x_)->count = 0; } while (0)
|
||||
|
||||
#define array_resize(x_, new_count_) do { \
|
||||
if ((x_)->capacity < (new_count_)) { \
|
||||
array_grow((x_), (new_count_)); \
|
||||
} \
|
||||
(x_)->count = (new_count_); \
|
||||
} while (0)
|
||||
|
||||
#define array_reserve(x_, new_capacity_) do { \
|
||||
if ((x_)->capacity < (new_capacity_)) { \
|
||||
array_set_capacity((x_), (new_capacity_)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
|
||||
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
|
||||
ArrayVoid *x = cast(ArrayVoid *)ptr;
|
||||
GB_ASSERT(ptr != NULL);
|
||||
|
||||
GB_ASSERT(element_size > 0);
|
||||
|
||||
if (capacity == x->capacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (capacity < x->count) {
|
||||
if (x->capacity < capacity) {
|
||||
isize new_capacity = ARRAY_GROW_FORMULA(x->capacity);
|
||||
if (new_capacity < capacity) {
|
||||
new_capacity = capacity;
|
||||
}
|
||||
array__set_capacity(ptr, new_capacity, element_size);
|
||||
}
|
||||
x->count = capacity;
|
||||
}
|
||||
|
||||
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
|
||||
x->capacity = capacity;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
template <typename T>
|
||||
struct Array {
|
||||
gbAllocator allocator;
|
||||
@@ -224,6 +133,97 @@ void array_set_capacity(Array<T> *array, isize capacity) {
|
||||
array->capacity = capacity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define Array(Type_) struct { \
|
||||
gbAllocator allocator; \
|
||||
Type_ * e; \
|
||||
isize count; \
|
||||
isize capacity; \
|
||||
}
|
||||
|
||||
typedef Array(void) ArrayVoid;
|
||||
|
||||
#define array_init_reserve(x_, allocator_, init_capacity_) do { \
|
||||
void **e = cast(void **)&((x_)->e); \
|
||||
GB_ASSERT((x_) != NULL); \
|
||||
(x_)->allocator = (allocator_); \
|
||||
(x_)->count = 0; \
|
||||
(x_)->capacity = (init_capacity_); \
|
||||
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \
|
||||
} while (0)
|
||||
|
||||
#define array_init_count(x_, allocator_, init_count_) do { \
|
||||
void **e = cast(void **)&((x_)->e); \
|
||||
GB_ASSERT((x_) != NULL); \
|
||||
(x_)->allocator = (allocator_); \
|
||||
(x_)->count = (init_count_); \
|
||||
(x_)->capacity = (init_count_); \
|
||||
*e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \
|
||||
} while (0)
|
||||
|
||||
#define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0)
|
||||
#define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0)
|
||||
#define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0)
|
||||
|
||||
#define array_grow(x_, min_capacity_) do { \
|
||||
isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \
|
||||
if (new_capacity < (min_capacity_)) { \
|
||||
new_capacity = (min_capacity_); \
|
||||
} \
|
||||
array_set_capacity(x_, new_capacity); \
|
||||
} while (0)
|
||||
|
||||
#define array_add(x_, item_) do { \
|
||||
if ((x_)->capacity < (x_)->count+1) { \
|
||||
array_grow(x_, 0); \
|
||||
} \
|
||||
(x_)->e[(x_)->count++] = item_; \
|
||||
} while (0)
|
||||
|
||||
#define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0)
|
||||
#define array_clear(x_) do { (x_)->count = 0; } while (0)
|
||||
|
||||
#define array_resize(x_, new_count_) do { \
|
||||
if ((x_)->capacity < (new_count_)) { \
|
||||
array_grow((x_), (new_count_)); \
|
||||
} \
|
||||
(x_)->count = (new_count_); \
|
||||
} while (0)
|
||||
|
||||
#define array_reserve(x_, new_capacity_) do { \
|
||||
if ((x_)->capacity < (new_capacity_)) { \
|
||||
array_set_capacity((x_), (new_capacity_)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
|
||||
void array__set_capacity(void *ptr, isize capacity, isize element_size) {
|
||||
ArrayVoid *x = cast(ArrayVoid *)ptr;
|
||||
GB_ASSERT(ptr != NULL);
|
||||
|
||||
GB_ASSERT(element_size > 0);
|
||||
|
||||
if (capacity == x->capacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (capacity < x->count) {
|
||||
if (x->capacity < capacity) {
|
||||
isize new_capacity = ARRAY_GROW_FORMULA(x->capacity);
|
||||
if (new_capacity < capacity) {
|
||||
new_capacity = capacity;
|
||||
}
|
||||
array__set_capacity(ptr, new_capacity, element_size);
|
||||
}
|
||||
x->count = capacity;
|
||||
}
|
||||
|
||||
x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
|
||||
x->capacity = capacity;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This stores the information for the specify architecture of this build
|
||||
typedef struct BuildContext {
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
String ODIN_OS; // target operating system
|
||||
String ODIN_ARCH; // target architecture
|
||||
@@ -15,7 +15,7 @@ typedef struct BuildContext {
|
||||
String llc_flags;
|
||||
String link_flags;
|
||||
bool is_dll;
|
||||
} BuildContext;
|
||||
};
|
||||
|
||||
|
||||
gb_global BuildContext build_context = {0};
|
||||
@@ -35,7 +35,7 @@ String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
Array(wchar_t) path_buf;
|
||||
Array<wchar_t> path_buf;
|
||||
isize len, i;
|
||||
gbTempArenaMemory tmp;
|
||||
wchar_t *text;
|
||||
@@ -48,7 +48,7 @@ String odin_root_dir(void) {
|
||||
|
||||
len = 0;
|
||||
for (;;) {
|
||||
len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count);
|
||||
len = GetModuleFileNameW(NULL, &path_buf[0], path_buf.count);
|
||||
if (len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ String odin_root_dir(void) {
|
||||
GetModuleFileNameW(NULL, text, len);
|
||||
path = string16_to_string(heap_allocator(), make_string16(text, len));
|
||||
for (i = path.len-1; i >= 0; i--) {
|
||||
u8 c = path.text[i];
|
||||
u8 c = path[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ String odin_root_dir(void) {
|
||||
len = 0;
|
||||
for (;;) {
|
||||
int sz = path_buf.count;
|
||||
int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
|
||||
int res = _NSGetExecutablePath(&path_buf[0], &sz);
|
||||
if(res == 0) {
|
||||
len = sz;
|
||||
break;
|
||||
@@ -114,11 +114,11 @@ String odin_root_dir(void) {
|
||||
|
||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
|
||||
gb_memmove(text, &path_buf.e[0], len);
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
path = make_string(text, len);
|
||||
for (i = path.len-1; i >= 0; i--) {
|
||||
u8 c = path.text[i];
|
||||
u8 c = path[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
@@ -158,7 +158,7 @@ String odin_root_dir(void) {
|
||||
// of this compiler, it should be _good enough_.
|
||||
// That said, there's no solid 100% method on Linux to get the program's
|
||||
// path without checking this link. Sorry.
|
||||
len = readlink("/proc/self/exe", &path_buf.e[0], path_buf.count);
|
||||
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
|
||||
if(len == 0) {
|
||||
return make_string(NULL, 0);
|
||||
}
|
||||
@@ -171,11 +171,11 @@ String odin_root_dir(void) {
|
||||
|
||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
|
||||
gb_memmove(text, &path_buf.e[0], len);
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
path = make_string(text, len);
|
||||
for (i = path.len-1; i >= 0; i--) {
|
||||
u8 c = path.text[i];
|
||||
u8 c = path[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
@@ -200,10 +200,10 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
String16 string16 = string_to_string16(string_buffer_allocator, s);
|
||||
String result = {0};
|
||||
|
||||
DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
|
||||
DWORD len = GetFullPathNameW(&string16[0], 0, NULL, NULL);
|
||||
if (len != 0) {
|
||||
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
||||
GetFullPathNameW(string16.text, len, text, NULL);
|
||||
GetFullPathNameW(&string16[0], len, text, NULL);
|
||||
text[len] = 0;
|
||||
result = string16_to_string(a, make_string16(text, len));
|
||||
}
|
||||
@@ -212,7 +212,7 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
String path_to_fullpath(gbAllocator a, String s) {
|
||||
char *p = realpath(cast(char *)s.text, 0);
|
||||
char *p = realpath(cast(char *)&s[0], 0);
|
||||
if(p == NULL) return make_string_c("");
|
||||
|
||||
return make_string_c(p);
|
||||
@@ -229,8 +229,8 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
||||
|
||||
isize i = 0;
|
||||
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
|
||||
gb_memmove(str+i, path.text, path.len);
|
||||
gb_memmove(str+i, &base_dir[0], base_dir.len); i += base_dir.len;
|
||||
gb_memmove(str+i, &path[0], path.len);
|
||||
str[str_len] = '\0';
|
||||
res = path_to_fullpath(a, make_string(str, str_len));
|
||||
gb_free(heap_allocator(), str);
|
||||
@@ -247,9 +247,9 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
isize str_len = module_dir.len + core_len + path.len;
|
||||
u8 *str = gb_alloc_array(heap_allocator(), u8, str_len+1);
|
||||
|
||||
gb_memmove(str, module_dir.text, module_dir.len);
|
||||
gb_memmove(str, &module_dir[0], module_dir.len);
|
||||
gb_memmove(str+module_dir.len, core, core_len);
|
||||
gb_memmove(str+module_dir.len+core_len, path.text, path.len);
|
||||
gb_memmove(str+module_dir.len+core_len, &path[0], path.len);
|
||||
str[str_len] = '\0';
|
||||
|
||||
res = path_to_fullpath(a, make_string(str, str_len));
|
||||
@@ -294,7 +294,7 @@ void init_build_context(void) {
|
||||
|
||||
// NOTE(zangent): MacOS systems are x64 only, so ld doesn't have
|
||||
// an architecture option. All compilation done on MacOS must be x64.
|
||||
GB_ASSERT(str_eq(bc->ODIN_ARCH, str_lit("amd64")));
|
||||
GB_ASSERT(bc->ODIN_ARCH == "amd64");
|
||||
|
||||
#define LINK_FLAG_X64 ""
|
||||
#define LINK_FLAG_X86 ""
|
||||
@@ -311,12 +311,12 @@ void init_build_context(void) {
|
||||
#define LINK_FLAG_X86 "-arch x86"
|
||||
#endif
|
||||
|
||||
if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
|
||||
if (bc->ODIN_ARCH == "amd64") {
|
||||
bc->word_size = 8;
|
||||
bc->max_align = 16;
|
||||
bc->llc_flags = str_lit("-march=x86-64 ");
|
||||
bc->link_flags = str_lit(LINK_FLAG_X64 " ");
|
||||
} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
|
||||
} else if (bc->ODIN_ARCH == "x86") {
|
||||
bc->word_size = 4;
|
||||
bc->max_align = 8;
|
||||
bc->llc_flags = str_lit("-march=x86 ");
|
||||
@@ -13,7 +13,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
// TODO(bill): is this a good enough error message?
|
||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||
error_node(operand->expr,
|
||||
"Cannot assign builtin procedure `%s` in %.*s",
|
||||
"Cannot assign built-in procedure `%s` in %.*s",
|
||||
expr_str,
|
||||
LIT(context_name));
|
||||
|
||||
@@ -58,7 +58,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
return e->type;
|
||||
}
|
||||
|
||||
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) {
|
||||
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
|
||||
if ((lhs == NULL || lhs_count == 0) && inits.count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -67,20 +67,20 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
ArrayOperand operands = {0};
|
||||
array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
|
||||
Array<Operand> operands = {};
|
||||
array_init(&operands, c->tmp_allocator, 2*lhs_count);
|
||||
check_unpack_arguments(c, lhs_count, &operands, inits, true);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
if (operands.e[i].mode == Addressing_Invalid) {
|
||||
if (operands[i].mode == Addressing_Invalid) {
|
||||
rhs_count--;
|
||||
}
|
||||
}
|
||||
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
for (isize i = 0; i < max; i++) {
|
||||
check_init_variable(c, lhs[i], &operands.e[i], context_name);
|
||||
check_init_variable(c, lhs[i], &operands[i], context_name);
|
||||
}
|
||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
@@ -145,7 +145,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
|
||||
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
|
||||
|
||||
Type *bt = check_type_extra(c, type_expr, named);
|
||||
Type *bt = check_type(c, type_expr, named);
|
||||
named->Named.base = base_type(bt);
|
||||
if (named->Named.base == t_invalid) {
|
||||
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
||||
@@ -174,7 +174,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
e->type = t;
|
||||
}
|
||||
|
||||
Operand operand = {0};
|
||||
Operand operand = {};
|
||||
if (init != NULL) {
|
||||
check_expr_or_type(c, &operand, init);
|
||||
}
|
||||
@@ -274,7 +274,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
bool is_require_results = (pd->tags & ProcTag_require_results) != 0;
|
||||
|
||||
|
||||
if (d->scope->is_file && str_eq(e->token.string, str_lit("main"))) {
|
||||
if (d->scope->is_file && e->token.string == "main") {
|
||||
if (proc_type != NULL) {
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
if (pt->param_count != 0 ||
|
||||
@@ -319,7 +319,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
if (is_foreign) {
|
||||
MapEntity *fp = &c->info.foreigns;
|
||||
auto *fp = &c->info.foreigns;
|
||||
String name = e->token.string;
|
||||
if (pd->foreign_name.len > 0) {
|
||||
name = pd->foreign_name;
|
||||
@@ -334,7 +334,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
String name = foreign_library->Ident.string;
|
||||
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||
if (found == NULL) {
|
||||
if (str_eq(name, str_lit("_"))) {
|
||||
if (name == "_") {
|
||||
error_node(foreign_library, "`_` cannot be used as a value type");
|
||||
} else {
|
||||
error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
|
||||
@@ -352,7 +352,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
e->Procedure.foreign_name = name;
|
||||
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_entity_get(fp, key);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
@@ -365,7 +365,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
} else {
|
||||
map_entity_set(fp, key, e);
|
||||
map_set(fp, key, e);
|
||||
}
|
||||
} else {
|
||||
String name = e->token.string;
|
||||
@@ -374,12 +374,12 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
if (is_link_name || is_export) {
|
||||
MapEntity *fp = &c->info.foreigns;
|
||||
auto *fp = &c->info.foreigns;
|
||||
|
||||
e->Procedure.link_name = name;
|
||||
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_entity_get(fp, key);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
@@ -389,7 +389,7 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
"\tother at %.*s(%td:%td)",
|
||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||
} else {
|
||||
map_entity_set(fp, key, e);
|
||||
map_set(fp, key, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,7 +408,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
if (type_expr != NULL) {
|
||||
e->type = check_type_extra(c, type_expr, NULL);
|
||||
e->type = check_type(c, type_expr);
|
||||
}
|
||||
|
||||
if (init_expr == NULL) {
|
||||
@@ -420,7 +420,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
|
||||
if (entities == NULL || entity_count == 1) {
|
||||
GB_ASSERT(entities == NULL || entities[0] == e);
|
||||
Operand operand = {0};
|
||||
Operand operand = {};
|
||||
check_expr(c, &operand, init_expr);
|
||||
check_init_variable(c, e, &operand, str_lit("variable declaration"));
|
||||
}
|
||||
@@ -431,8 +431,8 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeArray inits;
|
||||
array_init_reserve(&inits, c->allocator, 1);
|
||||
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"));
|
||||
}
|
||||
@@ -443,7 +443,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
}
|
||||
|
||||
if (d == NULL) {
|
||||
DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e));
|
||||
DeclInfo **found = map_get(&c->info.entities, hash_pointer(e));
|
||||
if (found) {
|
||||
d = *found;
|
||||
} else {
|
||||
@@ -484,7 +484,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||
|
||||
String proc_name = {0};
|
||||
String proc_name = {};
|
||||
if (token.kind == Token_Ident) {
|
||||
proc_name = token.string;
|
||||
} else {
|
||||
@@ -511,10 +511,10 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
Scope **found = map_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;
|
||||
Entity *f = (*found)->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
@@ -555,9 +555,9 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
if (decl->parent != NULL) {
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
for_array(i, decl->deps.entries) {
|
||||
HashKey key = decl->deps.entries.e[i].key;
|
||||
HashKey key = decl->deps.entries[i].key;
|
||||
Entity *e = cast(Entity *)key.ptr;
|
||||
map_bool_set(&decl->parent->deps, key, true);
|
||||
map_set(&decl->parent->deps, key, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
|
||||
if (stmts.count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -12,13 +12,13 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
|
||||
isize max = stmts.count;
|
||||
for (isize i = stmts.count-1; i >= 0; i--) {
|
||||
if (stmts.e[i]->kind != AstNode_EmptyStmt) {
|
||||
if (stmts[i]->kind != AstNode_EmptyStmt) {
|
||||
break;
|
||||
}
|
||||
max--;
|
||||
}
|
||||
for (isize i = 0; i < max; i++) {
|
||||
AstNode *n = stmts.e[i];
|
||||
AstNode *n = stmts[i];
|
||||
if (n->kind == AstNode_EmptyStmt) {
|
||||
continue;
|
||||
}
|
||||
@@ -40,10 +40,10 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
|
||||
}
|
||||
|
||||
bool check_is_terminating_list(AstNodeArray stmts) {
|
||||
bool check_is_terminating_list(Array<AstNode *> stmts) {
|
||||
// Iterate backwards
|
||||
for (isize n = stmts.count-1; n >= 0; n--) {
|
||||
AstNode *stmt = stmts.e[n];
|
||||
AstNode *stmt = stmts[n];
|
||||
if (stmt->kind != AstNode_EmptyStmt) {
|
||||
return check_is_terminating(stmt);
|
||||
}
|
||||
@@ -52,9 +52,9 @@ bool check_is_terminating_list(AstNodeArray stmts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_has_break_list(AstNodeArray stmts, bool implicit) {
|
||||
bool check_has_break_list(Array<AstNode *> stmts, bool implicit) {
|
||||
for_array(i, stmts) {
|
||||
AstNode *stmt = stmts.e[i];
|
||||
AstNode *stmt = stmts[i];
|
||||
if (check_has_break(stmt, implicit)) {
|
||||
return true;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ bool check_is_terminating(AstNode *node) {
|
||||
case_ast_node(ms, MatchStmt, node);
|
||||
bool has_default = false;
|
||||
for_array(i, ms->body->BlockStmt.stmts) {
|
||||
AstNode *clause = ms->body->BlockStmt.stmts.e[i];
|
||||
AstNode *clause = ms->body->BlockStmt.stmts[i];
|
||||
ast_node(cc, CaseClause, clause);
|
||||
if (cc->list.count == 0) {
|
||||
has_default = true;
|
||||
@@ -153,7 +153,7 @@ bool check_is_terminating(AstNode *node) {
|
||||
case_ast_node(ms, TypeMatchStmt, node);
|
||||
bool has_default = false;
|
||||
for_array(i, ms->body->BlockStmt.stmts) {
|
||||
AstNode *clause = ms->body->BlockStmt.stmts.e[i];
|
||||
AstNode *clause = ms->body->BlockStmt.stmts[i];
|
||||
ast_node(cc, CaseClause, clause);
|
||||
if (cc->list.count == 0) {
|
||||
has_default = true;
|
||||
@@ -187,7 +187,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (node->kind == AstNode_Ident &&
|
||||
str_eq(node->Ident.string, str_lit("_"))) {
|
||||
node->Ident.string == "_") {
|
||||
add_entity_definition(&c->info, node, NULL);
|
||||
check_assignment(c, rhs, NULL, str_lit("assignment to `_` identifier"));
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
@@ -218,7 +218,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
if (t == t_invalid) {
|
||||
continue;
|
||||
}
|
||||
Operand x = {0};
|
||||
Operand x = {};
|
||||
x.mode = Addressing_Value;
|
||||
x.type = t;
|
||||
if (check_is_assignable_to(c, &x, lhs.type)) {
|
||||
@@ -340,11 +340,11 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
|
||||
return rhs->type;
|
||||
}
|
||||
|
||||
typedef enum MatchTypeKind {
|
||||
enum MatchTypeKind {
|
||||
MatchType_Invalid,
|
||||
MatchType_Union,
|
||||
MatchType_Any,
|
||||
} MatchTypeKind;
|
||||
};
|
||||
|
||||
MatchTypeKind check_valid_type_match_type(Type *type) {
|
||||
type = type_deref(type);
|
||||
@@ -384,15 +384,10 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
|
||||
|
||||
typedef struct TypeAndToken {
|
||||
struct TypeAndToken {
|
||||
Type *type;
|
||||
Token token;
|
||||
} TypeAndToken;
|
||||
|
||||
#define MAP_TYPE TypeAndToken
|
||||
#define MAP_PROC map_type_and_token_
|
||||
#define MAP_NAME MapTypeAndToken
|
||||
#include "map.c"
|
||||
};
|
||||
|
||||
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
|
||||
flags &= ~Stmt_CheckScopeDecls;
|
||||
@@ -434,7 +429,7 @@ void check_label(Checker *c, AstNode *label) {
|
||||
return;
|
||||
}
|
||||
String name = l->name->Ident.string;
|
||||
if (str_eq(name, str_lit("_"))) {
|
||||
if (name == "_") {
|
||||
error_node(l->name, "A label's name cannot be a blank identifier");
|
||||
return;
|
||||
}
|
||||
@@ -448,8 +443,8 @@ void check_label(Checker *c, AstNode *label) {
|
||||
|
||||
bool ok = true;
|
||||
for_array(i, c->context.decl->labels) {
|
||||
BlockLabel bl = c->context.decl->labels.e[i];
|
||||
if (str_eq(bl.name, name)) {
|
||||
BlockLabel bl = c->context.decl->labels[i];
|
||||
if (bl.name == name) {
|
||||
error_node(label, "Duplicate label with the name `%.*s`", LIT(name));
|
||||
ok = false;
|
||||
break;
|
||||
@@ -513,7 +508,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
case Entity_ImportName: {
|
||||
Scope *scope = e->ImportName.scope;
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *decl = scope->elements.entries.e[i].value;
|
||||
Entity *decl = scope->elements.entries[i].value;
|
||||
Entity *found = scope_insert_entity(c->context.scope, decl);
|
||||
if (found != NULL) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
@@ -535,11 +530,11 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t) || is_type_union(t)) {
|
||||
// TODO(bill): Make it work for unions too
|
||||
Scope **found_ = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
Scope **found_ = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found_ != NULL);
|
||||
Scope *found = *found_;
|
||||
for_array(i, found->elements.entries) {
|
||||
Entity *f = found->elements.entries.e[i].value;
|
||||
Entity *f = found->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
// if (is_selector) {
|
||||
@@ -645,7 +640,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
Operand x = {0};
|
||||
Operand x = {};
|
||||
check_expr(c, &x, s->expr);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return;
|
||||
@@ -693,23 +688,23 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
ArrayOperand operands = {0};
|
||||
array_init_reserve(&operands, c->tmp_allocator, 2 * lhs_count);
|
||||
Array<Operand> operands = {};
|
||||
array_init(&operands, c->tmp_allocator, 2 * lhs_count);
|
||||
check_unpack_arguments(c, lhs_count, &operands, as->rhs, true);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
if (operands.e[i].mode == Addressing_Invalid) {
|
||||
if (operands[i].mode == Addressing_Invalid) {
|
||||
rhs_count--;
|
||||
}
|
||||
}
|
||||
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
for (isize i = 0; i < max; i++) {
|
||||
check_assignment_variable(c, &operands.e[i], as->lhs.e[i]);
|
||||
check_assignment_variable(c, &operands[i], as->lhs[i]);
|
||||
}
|
||||
if (lhs_count != rhs_count) {
|
||||
error_node(as->lhs.e[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
error_node(as->lhs[0], "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count);
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
@@ -732,15 +727,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
be->op = op;
|
||||
be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add));
|
||||
// NOTE(bill): Only use the first one will be used
|
||||
be->left = as->lhs.e[0];
|
||||
be->right = as->rhs.e[0];
|
||||
be->left = as->lhs[0];
|
||||
be->right = as->rhs[0];
|
||||
|
||||
check_binary_expr(c, &operand, &binary_expr);
|
||||
if (operand.mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
// NOTE(bill): Only use the first one will be used
|
||||
check_assignment_variable(c, &operand, as->lhs.e[0]);
|
||||
check_assignment_variable(c, &operand, as->lhs[0]);
|
||||
} break;
|
||||
}
|
||||
case_end;
|
||||
@@ -794,7 +789,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
|
||||
Type *proc_type = c->proc_stack.e[c->proc_stack.count-1];
|
||||
Type *proc_type = c->proc_stack[c->proc_stack.count-1];
|
||||
isize result_count = 0;
|
||||
if (proc_type->Proc.results) {
|
||||
result_count = proc_type->Proc.results->Tuple.variable_count;
|
||||
@@ -816,13 +811,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_init_variables(c, variables, result_count,
|
||||
rs->results, str_lit("return statement"));
|
||||
// if (pos.line == 10) {
|
||||
// AstNode *x = rs->results.e[0];
|
||||
// AstNode *x = rs->results[0];
|
||||
// gb_printf_err("%s\n", expr_to_string(x));
|
||||
// gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x)));
|
||||
// }
|
||||
}
|
||||
} else if (rs->results.count > 0) {
|
||||
error_node(rs->results.e[0], "No return values expected");
|
||||
error_node(rs->results[0], "No return values expected");
|
||||
}
|
||||
case_end;
|
||||
|
||||
@@ -863,7 +858,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
Type *val = NULL;
|
||||
Type *idx = NULL;
|
||||
Entity *entities[2] = {0};
|
||||
Entity *entities[2] = {};
|
||||
isize entity_count = 0;
|
||||
|
||||
AstNode *expr = unparen_expr(rs->expr);
|
||||
@@ -943,10 +938,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
if (x.mode != Addressing_Constant) {
|
||||
x.value = (ExactValue){0};
|
||||
x.value = empty_exact_value;
|
||||
}
|
||||
if (y.mode != Addressing_Constant) {
|
||||
y.value = (ExactValue){0};
|
||||
y.value = empty_exact_value;
|
||||
}
|
||||
|
||||
|
||||
@@ -1032,7 +1027,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
String str = token.string;
|
||||
Entity *found = NULL;
|
||||
|
||||
if (str_ne(str, str_lit("_"))) {
|
||||
if (str != "_") {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == NULL) {
|
||||
@@ -1072,7 +1067,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(ms, MatchStmt, node);
|
||||
Operand x = {0};
|
||||
Operand x = {};
|
||||
|
||||
mod_flags |= Stmt_BreakAllowed;
|
||||
check_open_scope(c, node);
|
||||
@@ -1089,7 +1084,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
x.type = t_bool;
|
||||
x.value = exact_value_bool(true);
|
||||
|
||||
Token token = {0};
|
||||
Token token = {};
|
||||
token.pos = ast_node_token(ms->body).pos;
|
||||
token.string = str_lit("true");
|
||||
x.expr = ast_ident(c->curr_ast_file, token);
|
||||
@@ -1106,7 +1101,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *first_default = NULL;
|
||||
ast_node(bs, BlockStmt, ms->body);
|
||||
for_array(i, bs->stmts) {
|
||||
AstNode *stmt = bs->stmts.e[i];
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
AstNode *default_stmt = NULL;
|
||||
if (stmt->kind == AstNode_CaseClause) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
@@ -1130,11 +1125,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
|
||||
MapTypeAndToken seen = {0}; // NOTE(bill): Multimap
|
||||
map_type_and_token_init(&seen, heap_allocator());
|
||||
Map<TypeAndToken> seen = {}; // NOTE(bill): Multimap
|
||||
map_init(&seen, heap_allocator());
|
||||
|
||||
for_array(i, bs->stmts) {
|
||||
AstNode *stmt = bs->stmts.e[i];
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
if (stmt->kind != AstNode_CaseClause) {
|
||||
// NOTE(bill): error handled by above multiple default checker
|
||||
continue;
|
||||
@@ -1142,12 +1137,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
|
||||
for_array(j, cc->list) {
|
||||
AstNode *expr = unparen_expr(cc->list.e[j]);
|
||||
AstNode *expr = unparen_expr(cc->list[j]);
|
||||
|
||||
if (is_ast_node_a_range(expr)) {
|
||||
ast_node(ie, BinaryExpr, expr);
|
||||
Operand lhs = {0};
|
||||
Operand rhs = {0};
|
||||
Operand lhs = {};
|
||||
Operand rhs = {};
|
||||
check_expr(c, &lhs, ie->left);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
continue;
|
||||
@@ -1168,7 +1163,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
|
||||
TokenKind op = {0};
|
||||
TokenKind op = {};
|
||||
|
||||
Operand a = lhs;
|
||||
Operand b = rhs;
|
||||
@@ -1197,7 +1192,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
Operand b1 = rhs;
|
||||
check_comparison(c, &a1, &b1, op);
|
||||
} else {
|
||||
Operand y = {0};
|
||||
Operand y = {};
|
||||
check_expr(c, &y, expr);
|
||||
if (x.mode == Addressing_Invalid ||
|
||||
y.mode == Addressing_Invalid) {
|
||||
@@ -1222,13 +1217,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
if (y.value.kind != ExactValue_Invalid) {
|
||||
HashKey key = hash_exact_value(y.value);
|
||||
TypeAndToken *found = map_type_and_token_get(&seen, key);
|
||||
TypeAndToken *found = map_get(&seen, key);
|
||||
if (found != NULL) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
isize count = map_type_and_token_multi_count(&seen, key);
|
||||
isize count = multi_map_count(&seen, key);
|
||||
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
|
||||
|
||||
map_type_and_token_multi_get_all(&seen, key, taps);
|
||||
multi_map_get_all(&seen, key, taps);
|
||||
bool continue_outer = false;
|
||||
|
||||
for (isize i = 0; i < count; i++) {
|
||||
@@ -1254,7 +1249,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
TypeAndToken tap = {y.type, ast_node_token(y.expr)};
|
||||
map_type_and_token_multi_insert(&seen, key, tap);
|
||||
multi_map_insert(&seen, key, tap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1268,13 +1263,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_close_scope(c);
|
||||
}
|
||||
|
||||
map_type_and_token_destroy(&seen);
|
||||
map_destroy(&seen);
|
||||
|
||||
check_close_scope(c);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ms, TypeMatchStmt, node);
|
||||
Operand x = {0};
|
||||
Operand x = {};
|
||||
|
||||
mod_flags |= Stmt_BreakAllowed;
|
||||
check_open_scope(c, node);
|
||||
@@ -1297,8 +1292,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
syntax_error(as_token, "Expected 1 expression after `in`");
|
||||
break;
|
||||
}
|
||||
AstNode *lhs = as->lhs.e[0];
|
||||
AstNode *rhs = as->rhs.e[0];
|
||||
AstNode *lhs = as->lhs[0];
|
||||
AstNode *rhs = as->rhs[0];
|
||||
|
||||
check_expr(c, &x, rhs);
|
||||
check_assignment(c, &x, NULL, str_lit("type match expression"));
|
||||
@@ -1316,7 +1311,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *first_default = NULL;
|
||||
ast_node(bs, BlockStmt, ms->body);
|
||||
for_array(i, bs->stmts) {
|
||||
AstNode *stmt = bs->stmts.e[i];
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
AstNode *default_stmt = NULL;
|
||||
if (stmt->kind == AstNode_CaseClause) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
@@ -1346,11 +1341,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
|
||||
MapBool seen = {0}; // Multimap
|
||||
map_bool_init(&seen, heap_allocator());
|
||||
Map<bool> seen = {}; // Multimap
|
||||
map_init(&seen, heap_allocator());
|
||||
|
||||
for_array(i, bs->stmts) {
|
||||
AstNode *stmt = bs->stmts.e[i];
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
if (stmt->kind != AstNode_CaseClause) {
|
||||
// NOTE(bill): error handled by above multiple default checker
|
||||
continue;
|
||||
@@ -1362,9 +1357,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
Type *case_type = NULL;
|
||||
for_array(type_index, cc->list) {
|
||||
AstNode *type_expr = cc->list.e[type_index];
|
||||
AstNode *type_expr = cc->list[type_index];
|
||||
if (type_expr != NULL) { // Otherwise it's a default expression
|
||||
Operand y = {0};
|
||||
Operand y = {};
|
||||
check_expr_or_type(c, &y, type_expr);
|
||||
|
||||
if (match_type_kind == MatchType_Union) {
|
||||
@@ -1391,7 +1386,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
HashKey key = hash_pointer(y.type);
|
||||
bool *found = map_bool_get(&seen, key);
|
||||
bool *found = map_get(&seen, key);
|
||||
if (found) {
|
||||
TokenPos pos = cc->token.pos;
|
||||
gbString expr_str = expr_to_string(y.expr);
|
||||
@@ -1403,7 +1398,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
gb_string_free(expr_str);
|
||||
break;
|
||||
}
|
||||
map_bool_set(&seen, key, cast(bool)true);
|
||||
map_set(&seen, key, cast(bool)true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1434,7 +1429,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
check_stmt_list(c, cc->stmts, mod_flags);
|
||||
check_close_scope(c);
|
||||
}
|
||||
map_bool_destroy(&seen);
|
||||
map_destroy(&seen);
|
||||
|
||||
check_close_scope(c);
|
||||
case_end;
|
||||
@@ -1481,7 +1476,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
AstNode *ident = bs->label;
|
||||
String name = ident->Ident.string;
|
||||
Operand o = {0};
|
||||
Operand o = {};
|
||||
Entity *e = check_ident(c, &o, ident, NULL, NULL, false);
|
||||
if (e == NULL) {
|
||||
error_node(ident, "Undeclared label name: %.*s", LIT(name));
|
||||
@@ -1502,15 +1497,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
return;
|
||||
}
|
||||
for_array(i, us->list) {
|
||||
AstNode *expr = unparen_expr(us->list.e[0]);
|
||||
AstNode *expr = unparen_expr(us->list[0]);
|
||||
Entity *e = NULL;
|
||||
|
||||
bool is_selector = false;
|
||||
if (expr->kind == AstNode_Ident) {
|
||||
Operand o = {0};
|
||||
Operand o = {};
|
||||
e = check_ident(c, &o, expr, NULL, NULL, true);
|
||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||
Operand o = {0};
|
||||
Operand o = {};
|
||||
e = check_selector(c, &o, expr, NULL);
|
||||
is_selector = true;
|
||||
} else if (expr->kind == AstNode_Implicit) {
|
||||
@@ -1526,7 +1521,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
|
||||
case_ast_node(pa, PushAllocator, node);
|
||||
Operand op = {0};
|
||||
Operand op = {};
|
||||
check_expr(c, &op, pa->expr);
|
||||
check_assignment(c, &op, t_allocator, str_lit("argument to push_allocator"));
|
||||
check_stmt(c, pa->body, mod_flags);
|
||||
@@ -1534,7 +1529,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
|
||||
case_ast_node(pa, PushContext, node);
|
||||
Operand op = {0};
|
||||
Operand op = {};
|
||||
check_expr(c, &op, pa->expr);
|
||||
check_assignment(c, &op, t_context, str_lit("argument to push_context"));
|
||||
check_stmt(c, pa->body, mod_flags);
|
||||
@@ -1555,7 +1550,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
AstNode *name = vd->names[i];
|
||||
Entity *entity = NULL;
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error_node(name, "A variable declaration must be an identifier");
|
||||
@@ -1564,11 +1559,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
String str = token.string;
|
||||
Entity *found = NULL;
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (str_ne(str, str_lit("_"))) {
|
||||
if (str != "_") {
|
||||
found = current_scope_lookup_entity(c->context.scope, str);
|
||||
}
|
||||
if (found == NULL) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, vd->flags&VarDeclFlag_immutable);
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, (vd->flags&VarDeclFlag_immutable) != 0);
|
||||
entity->identifier = name;
|
||||
} else {
|
||||
TokenPos pos = found->token.pos;
|
||||
@@ -1588,7 +1583,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
Type *init_type = NULL;
|
||||
if (vd->type) {
|
||||
init_type = check_type_extra(c, vd->type, NULL);
|
||||
init_type = check_type(c, vd->type, NULL);
|
||||
if (init_type == NULL) {
|
||||
init_type = t_invalid;
|
||||
}
|
||||
@@ -1635,10 +1630,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
Scope **found = map_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;
|
||||
Entity *f = (*found)->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
+210
-243
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#define GB_NO_DEFER
|
||||
// #define GB_NO_DEFER
|
||||
#define GB_IMPLEMENTATION
|
||||
#include "gb/gb.h"
|
||||
|
||||
@@ -13,22 +13,27 @@ gbAllocator heap_allocator(void) {
|
||||
return gb_heap_allocator();
|
||||
}
|
||||
|
||||
#include "unicode.c"
|
||||
#include "string.c"
|
||||
#include "array.c"
|
||||
#include "integer128.c"
|
||||
#include "murmurhash3.c"
|
||||
#include "unicode.cpp"
|
||||
#include "string.cpp"
|
||||
#include "array.cpp"
|
||||
#include "integer128.cpp"
|
||||
#include "murmurhash3.cpp"
|
||||
|
||||
u128 fnv128a(void const *data, isize len) {
|
||||
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
|
||||
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
|
||||
u8 const *bytes = cast(u8 const *)data;
|
||||
for (isize i = 0; i < len; i++) {
|
||||
h = u128_mul(u128_xor(h, u128_from_u64(bytes[i])), o);
|
||||
h.lo ^= bytes[i];
|
||||
h = h * o;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
#include "map.cpp"
|
||||
|
||||
|
||||
|
||||
gb_global String global_module_path = {0};
|
||||
gb_global bool global_module_path_set = false;
|
||||
|
||||
@@ -43,8 +48,6 @@ gbAllocator scratch_allocator(void) {
|
||||
return gb_scratch_allocator(&scratch_memory);
|
||||
}
|
||||
|
||||
typedef struct DynamicArenaBlock DynamicArenaBlock;
|
||||
typedef struct DynamicArena DynamicArena;
|
||||
|
||||
struct DynamicArenaBlock {
|
||||
DynamicArenaBlock *prev;
|
||||
@@ -236,27 +239,4 @@ f64 gb_sqrt(f64 x) {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generic Data Structures
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef Array(i32) Array_i32;
|
||||
typedef Array(isize) Array_isize;
|
||||
|
||||
|
||||
#define MAP_TYPE String
|
||||
#define MAP_PROC map_string_
|
||||
#define MAP_NAME MapString
|
||||
#include "map.c"
|
||||
|
||||
#define MAP_TYPE bool
|
||||
#define MAP_PROC map_bool_
|
||||
#define MAP_NAME MapBool
|
||||
#include "map.c"
|
||||
|
||||
#define MAP_TYPE isize
|
||||
#define MAP_PROC map_isize_
|
||||
#define MAP_NAME MapIsize
|
||||
#include "map.c"
|
||||
@@ -1,7 +1,7 @@
|
||||
typedef struct Scope Scope;
|
||||
typedef struct Checker Checker;
|
||||
typedef struct Type Type;
|
||||
typedef struct DeclInfo DeclInfo;
|
||||
struct Scope;
|
||||
struct Checker;
|
||||
struct Type;
|
||||
struct DeclInfo;
|
||||
// typedef enum BuiltinProcId BuiltinProcId;
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ typedef struct DeclInfo DeclInfo;
|
||||
ENTITY_KIND(Nil) \
|
||||
ENTITY_KIND(Label)
|
||||
|
||||
typedef enum EntityKind {
|
||||
enum EntityKind {
|
||||
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
|
||||
ENTITY_KINDS
|
||||
#undef ENTITY_KIND
|
||||
Entity_Count,
|
||||
} EntityKind;
|
||||
};
|
||||
|
||||
String const entity_strings[] = {
|
||||
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
||||
@@ -32,7 +32,7 @@ String const entity_strings[] = {
|
||||
#undef ENTITY_KIND
|
||||
};
|
||||
|
||||
typedef enum EntityFlag {
|
||||
enum EntityFlag {
|
||||
EntityFlag_Visited = 1<<0,
|
||||
EntityFlag_Used = 1<<1,
|
||||
EntityFlag_Using = 1<<2,
|
||||
@@ -45,24 +45,23 @@ typedef enum EntityFlag {
|
||||
EntityFlag_Value = 1<<9,
|
||||
EntityFlag_Sret = 1<<10,
|
||||
EntityFlag_BitFieldValue = 1<<11,
|
||||
} EntityFlag;
|
||||
};
|
||||
|
||||
// Zero value means the overloading process is not yet done
|
||||
typedef enum OverloadKind {
|
||||
enum OverloadKind {
|
||||
Overload_Unknown,
|
||||
Overload_No,
|
||||
Overload_Yes,
|
||||
} OverloadKind;
|
||||
};
|
||||
|
||||
typedef enum EntityAliasKind {
|
||||
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;
|
||||
@@ -82,10 +81,11 @@ struct Entity {
|
||||
ExactValue value;
|
||||
} Constant;
|
||||
struct {
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
bool is_immutable;
|
||||
bool is_thread_local;
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
bool is_immutable;
|
||||
bool is_thread_local;
|
||||
ExactValue default_value;
|
||||
} Variable;
|
||||
struct {
|
||||
bool is_type_alias;
|
||||
@@ -148,7 +148,7 @@ bool is_entity_exported(Entity *e) {
|
||||
if (name.len == 0) {
|
||||
return false;
|
||||
}
|
||||
return name.text[0] != '_';
|
||||
return name[0] != '_';
|
||||
}
|
||||
|
||||
gb_global u64 global_entity_id = 0;
|
||||
@@ -3,13 +3,14 @@
|
||||
// TODO(bill): Big numbers
|
||||
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
|
||||
|
||||
typedef struct AstNode AstNode;
|
||||
struct AstNode;
|
||||
struct HashKey;
|
||||
|
||||
typedef struct Complex128 {
|
||||
struct Complex128 {
|
||||
f64 real, imag;
|
||||
} Complex128;
|
||||
};
|
||||
|
||||
typedef enum ExactValueKind {
|
||||
enum ExactValueKind {
|
||||
ExactValue_Invalid,
|
||||
|
||||
ExactValue_Bool,
|
||||
@@ -21,9 +22,9 @@ typedef enum ExactValueKind {
|
||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||
|
||||
ExactValue_Count,
|
||||
} ExactValueKind;
|
||||
};
|
||||
|
||||
typedef struct ExactValue {
|
||||
struct ExactValue {
|
||||
ExactValueKind kind;
|
||||
union {
|
||||
bool value_bool;
|
||||
@@ -34,7 +35,9 @@ typedef struct ExactValue {
|
||||
Complex128 value_complex;
|
||||
AstNode * value_compound;
|
||||
};
|
||||
} ExactValue;
|
||||
};
|
||||
|
||||
gb_global ExactValue const empty_exact_value = {};
|
||||
|
||||
HashKey hash_exact_value(ExactValue v) {
|
||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
||||
@@ -191,7 +194,7 @@ ExactValue exact_value_from_basic_literal(Token token) {
|
||||
case Token_Float: return exact_value_float_from_string(token.string);
|
||||
case Token_Imag: {
|
||||
String str = token.string;
|
||||
Rune last_rune = cast(Rune)str.text[str.len-1];
|
||||
Rune last_rune = cast(Rune)str[str.len-1];
|
||||
str.len--; // Ignore the `i|j|k`
|
||||
f64 imag = float_from_string(str);
|
||||
|
||||
@@ -314,7 +317,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
return v;
|
||||
case ExactValue_Integer: {
|
||||
ExactValue i = v;
|
||||
i.value_integer = i128_neg(i.value_integer);
|
||||
i.value_integer = -i.value_integer;
|
||||
return i;
|
||||
}
|
||||
case ExactValue_Float: {
|
||||
@@ -336,7 +339,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
case ExactValue_Invalid:
|
||||
return v;
|
||||
case ExactValue_Integer:
|
||||
i = i128_not(v.value_integer);
|
||||
i = ~v.value_integer;
|
||||
break;
|
||||
default:
|
||||
goto failure;
|
||||
@@ -346,7 +349,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
// limited to the types precision
|
||||
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
|
||||
if (0 < precision && precision < 128) {
|
||||
i = i128_and(i, i128_not(i128_shl(I128_NEG_ONE, precision)));
|
||||
i = i & ~(I128_NEG_ONE << precision);
|
||||
}
|
||||
|
||||
return exact_value_i128(i);
|
||||
@@ -364,7 +367,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
failure:
|
||||
GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op]));
|
||||
|
||||
ExactValue error_value = {0};
|
||||
ExactValue error_value = {};
|
||||
return error_value;
|
||||
}
|
||||
|
||||
@@ -458,19 +461,19 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
i128 b = y.value_integer;
|
||||
i128 c = I128_ZERO;
|
||||
switch (op) {
|
||||
case Token_Add: c = i128_add(a, b); break;
|
||||
case Token_Sub: c = i128_sub(a, b); break;
|
||||
case Token_Mul: c = i128_mul(a, b); break;
|
||||
case Token_Add: c = a + b; break;
|
||||
case Token_Sub: c = a - b; break;
|
||||
case Token_Mul: c = a * b; break;
|
||||
case Token_Quo: return exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b)));
|
||||
case Token_QuoEq: c = i128_quo(a, b); break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = i128_mod(a, b); break;
|
||||
case Token_ModMod: c = i128_mod(i128_add(i128_mod(a, b), b), b); break;
|
||||
case Token_And: c = i128_and (a, b); break;
|
||||
case Token_Or: c = i128_or (a, b); break;
|
||||
case Token_Xor: c = i128_xor (a, b); break;
|
||||
case Token_AndNot: c = i128_and_not(a, b); break;
|
||||
case Token_Shl: c = i128_shl (a, i128_to_u64(b)); break;
|
||||
case Token_Shr: c = i128_shr (a, i128_to_u64(b)); break;
|
||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = a % b; break;
|
||||
case Token_ModMod: c = ((a % b) + b) % b; break;
|
||||
case Token_And: c = a & b; break;
|
||||
case Token_Or: c = a | b; break;
|
||||
case Token_Xor: c = a ^ b; break;
|
||||
case Token_AndNot: c = i128_and_not(a, b); break;
|
||||
case Token_Shl: c = a << i128_to_u64(b); break;
|
||||
case Token_Shr: c = a >> i128_to_u64(b); break;
|
||||
default: goto error;
|
||||
}
|
||||
|
||||
@@ -523,7 +526,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
|
||||
error:
|
||||
; // MSVC accepts this??? apparently you cannot declare variables immediately after labels...
|
||||
ExactValue error_value = {0};
|
||||
ExactValue error_value = {};
|
||||
// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
|
||||
return error_value;
|
||||
}
|
||||
@@ -557,12 +560,12 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
i128 a = x.value_integer;
|
||||
i128 b = y.value_integer;
|
||||
switch (op) {
|
||||
case Token_CmpEq: return i128_eq(a, b);
|
||||
case Token_NotEq: return i128_ne(a, b);
|
||||
case Token_Lt: return i128_lt(a, b);
|
||||
case Token_LtEq: return i128_le(a, b);
|
||||
case Token_Gt: return i128_gt(a, b);
|
||||
case Token_GtEq: return i128_ge(a, b);
|
||||
case Token_CmpEq: return a == b;
|
||||
case Token_NotEq: return a != b;
|
||||
case Token_Lt: return a < b;
|
||||
case Token_LtEq: return a <= b;
|
||||
case Token_Gt: return a > b;
|
||||
case Token_GtEq: return a >= b;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -593,15 +596,14 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
case ExactValue_String: {
|
||||
String a = x.value_string;
|
||||
String b = y.value_string;
|
||||
isize len = gb_min(a.len, b.len);
|
||||
// TODO(bill): gb_memcompare is used because the strings are UTF-8
|
||||
switch (op) {
|
||||
case Token_CmpEq: return gb_memcompare(a.text, b.text, len) == 0;
|
||||
case Token_NotEq: return gb_memcompare(a.text, b.text, len) != 0;
|
||||
case Token_Lt: return gb_memcompare(a.text, b.text, len) < 0;
|
||||
case Token_LtEq: return gb_memcompare(a.text, b.text, len) <= 0;
|
||||
case Token_Gt: return gb_memcompare(a.text, b.text, len) > 0;
|
||||
case Token_GtEq: return gb_memcompare(a.text, b.text, len) >= 0;
|
||||
case Token_CmpEq: return a == b;
|
||||
case Token_NotEq: return a != b;
|
||||
case Token_Lt: return a < b;
|
||||
case Token_LtEq: return a <= b;
|
||||
case Token_Gt: return a > b;
|
||||
case Token_GtEq: return a >= b;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@@ -1,16 +1,25 @@
|
||||
typedef struct u128 {u64 lo; u64 hi;} u128;
|
||||
typedef struct i128 {u64 lo; i64 hi;} i128;
|
||||
|
||||
#define BIT128_U64_HIGHBIT 0x8000000000000000ul
|
||||
#define BIT128_U64_BITS62 0x7ffffffffffffffful
|
||||
#define BIT128_U64_ALLBITS 0xfffffffffffffffful
|
||||
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
|
||||
#define MSVC_AMD64_INTRINSICS
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_mul128)
|
||||
#endif
|
||||
|
||||
#define BIT128_U64_HIGHBIT 0x8000000000000000ull
|
||||
#define BIT128_U64_BITS62 0x7fffffffffffffffull
|
||||
#define BIT128_U64_ALLBITS 0xffffffffffffffffull
|
||||
|
||||
|
||||
typedef struct u128 { u64 lo; u64 hi; } u128;
|
||||
typedef struct i128 { u64 lo; i64 hi; } i128;
|
||||
|
||||
|
||||
static u128 const U128_ZERO = {0, 0};
|
||||
static u128 const U128_ONE = {1, 0};
|
||||
static i128 const I128_ZERO = {0, 0};
|
||||
static i128 const I128_ONE = {1, 0};
|
||||
static u128 const U128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS};
|
||||
static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS};
|
||||
static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, cast(i64)BIT128_U64_ALLBITS};
|
||||
|
||||
u128 u128_lo_hi (u64 lo, u64 hi);
|
||||
u128 u128_from_u32 (u32 u);
|
||||
@@ -84,6 +93,48 @@ void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem);
|
||||
i128 i128_quo (i128 a, i128 b);
|
||||
i128 i128_mod (i128 a, i128 b);
|
||||
|
||||
bool operator==(u128 a, u128 b) { return u128_eq(a, b); }
|
||||
bool operator!=(u128 a, u128 b) { return u128_ne(a, b); }
|
||||
bool operator< (u128 a, u128 b) { return u128_lt(a, b); }
|
||||
bool operator> (u128 a, u128 b) { return u128_gt(a, b); }
|
||||
bool operator<=(u128 a, u128 b) { return u128_le(a, b); }
|
||||
bool operator>=(u128 a, u128 b) { return u128_ge(a, b); }
|
||||
|
||||
u128 operator+(u128 a, u128 b) { return u128_add(a, b); }
|
||||
u128 operator-(u128 a, u128 b) { return u128_sub(a, b); }
|
||||
u128 operator*(u128 a, u128 b) { return u128_mul(a, b); }
|
||||
u128 operator/(u128 a, u128 b) { return u128_quo(a, b); }
|
||||
u128 operator%(u128 a, u128 b) { return u128_mod(a, b); }
|
||||
u128 operator&(u128 a, u128 b) { return u128_and(a, b); }
|
||||
u128 operator|(u128 a, u128 b) { return u128_or (a, b); }
|
||||
u128 operator^(u128 a, u128 b) { return u128_xor(a, b); }
|
||||
u128 operator~(u128 a) { return u128_not(a); }
|
||||
u128 operator+(u128 a) { return a; }
|
||||
u128 operator-(u128 a) { return u128_neg(a); }
|
||||
u128 operator<<(u128 a, u32 b) { return u128_shl(a, b); }
|
||||
u128 operator>>(u128 a, u32 b) { return u128_shr(a, b); }
|
||||
|
||||
|
||||
bool operator==(i128 a, i128 b) { return i128_eq(a, b); }
|
||||
bool operator!=(i128 a, i128 b) { return i128_ne(a, b); }
|
||||
bool operator< (i128 a, i128 b) { return i128_lt(a, b); }
|
||||
bool operator> (i128 a, i128 b) { return i128_gt(a, b); }
|
||||
bool operator<=(i128 a, i128 b) { return i128_le(a, b); }
|
||||
bool operator>=(i128 a, i128 b) { return i128_ge(a, b); }
|
||||
|
||||
i128 operator+(i128 a, i128 b) { return i128_add(a, b); }
|
||||
i128 operator-(i128 a, i128 b) { return i128_sub(a, b); }
|
||||
i128 operator*(i128 a, i128 b) { return i128_mul(a, b); }
|
||||
i128 operator/(i128 a, i128 b) { return i128_quo(a, b); }
|
||||
i128 operator%(i128 a, i128 b) { return i128_mod(a, b); }
|
||||
i128 operator&(i128 a, i128 b) { return i128_and(a, b); }
|
||||
i128 operator|(i128 a, i128 b) { return i128_or (a, b); }
|
||||
i128 operator^(i128 a, i128 b) { return i128_xor(a, b); }
|
||||
i128 operator~(i128 a) { return i128_not(a); }
|
||||
i128 operator+(i128 a) { return a; }
|
||||
i128 operator-(i128 a) { return i128_neg(a); }
|
||||
i128 operator<<(i128 a, u32 b) { return i128_shl(a, b); }
|
||||
i128 operator>>(i128 a, u32 b) { return i128_shr(a, b); }
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -99,7 +150,7 @@ u64 bit128__digit_value(Rune r) {
|
||||
return 16; // NOTE(bill): Larger than highest possible
|
||||
}
|
||||
|
||||
u128 u128_lo_hi(u64 lo, u64 hi) { return (u128){lo, hi}; }
|
||||
u128 u128_lo_hi(u64 lo, u64 hi) { return u128{lo, hi}; }
|
||||
u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); }
|
||||
u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); }
|
||||
u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
|
||||
@@ -109,8 +160,8 @@ u128 u128_from_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
u64 base = 10;
|
||||
bool has_prefix = false;
|
||||
if (string.len > 2 && string.text[0] == '0') {
|
||||
switch (string.text[1]) {
|
||||
if (string.len > 2 && string[0] == '0') {
|
||||
switch (string[1]) {
|
||||
case 'b': base = 2; has_prefix = true; break;
|
||||
case 'o': base = 8; has_prefix = true; break;
|
||||
case 'd': base = 10; has_prefix = true; break;
|
||||
@@ -160,8 +211,8 @@ i128 i128_from_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
u64 base = 10;
|
||||
bool has_prefix = false;
|
||||
if (string.len > 2 && string.text[0] == '0') {
|
||||
switch (string.text[1]) {
|
||||
if (string.len > 2 && string[0] == '0') {
|
||||
switch (string[1]) {
|
||||
case 'b': base = 2; has_prefix = true; break;
|
||||
case 'o': base = 8; has_prefix = true; break;
|
||||
case 'd': base = 10; has_prefix = true; break;
|
||||
@@ -332,7 +383,11 @@ u128 u128_shl(u128 a, u32 n) {
|
||||
if (n >= 128) {
|
||||
return u128_lo_hi(0, 0);
|
||||
}
|
||||
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.hi = __shiftleft128(a.lo, a.hi, n);
|
||||
a.lo = a.lo << n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.hi = a.lo;
|
||||
@@ -347,13 +402,18 @@ u128 u128_shl(u128 a, u32 n) {
|
||||
a.lo <<= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
u128 u128_shr(u128 a, u32 n) {
|
||||
if (n >= 128) {
|
||||
return u128_lo_hi(0, 0);
|
||||
}
|
||||
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.lo = __shiftright128(a.lo, a.hi, n);
|
||||
a.hi = a.hi >> n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.lo = a.hi;
|
||||
@@ -367,6 +427,7 @@ u128 u128_shr(u128 a, u32 n) {
|
||||
a.hi >>= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -383,6 +444,14 @@ u128 u128_mul(u128 a, u128 b) {
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
#if defined(MSVC_AMD64_INTRINSICS)
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
a.lo = _umul128(a.lo, b.lo, &a.hi);
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
u128 res = {0};
|
||||
u128 t = b;
|
||||
for (u32 i = 0; i < 128; i++) {
|
||||
@@ -396,6 +465,8 @@ u128 u128_mul(u128 a, u128 b) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; }
|
||||
|
||||
void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
||||
if (u128_eq(den, U128_ZERO)) {
|
||||
if (quo) *quo = u128_from_u64(num.lo/den.lo);
|
||||
@@ -406,7 +477,7 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
||||
u128 x = U128_ONE;
|
||||
u128 r = U128_ZERO;
|
||||
|
||||
while (u128_ge(n, d) && ((u128_shr(d, 128-1).lo&1) == 0)) {
|
||||
while (u128_ge(n, d) && !u128_hibit(&d)) {
|
||||
x = u128_shl(x, 1);
|
||||
d = u128_shl(d, 1);
|
||||
}
|
||||
@@ -427,11 +498,18 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
||||
}
|
||||
|
||||
u128 u128_quo(u128 a, u128 b) {
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
return u128_from_u64(a.lo/b.lo);
|
||||
}
|
||||
|
||||
u128 res = {0};
|
||||
u128_divide(a, b, &res, NULL);
|
||||
return res;
|
||||
}
|
||||
u128 u128_mod(u128 a, u128 b) {
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
return u128_from_u64(a.lo%b.lo);
|
||||
}
|
||||
u128 res = {0};
|
||||
u128_divide(a, b, NULL, &res);
|
||||
return res;
|
||||
@@ -491,6 +569,11 @@ i128 i128_shl(i128 a, u32 n) {
|
||||
return i128_lo_hi(0, 0);
|
||||
}
|
||||
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.hi = __shiftleft128(a.lo, a.hi, n);
|
||||
a.lo = a.lo << n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.hi = a.lo;
|
||||
@@ -505,6 +588,7 @@ i128 i128_shl(i128 a, u32 n) {
|
||||
a.lo <<= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
i128 i128_shr(i128 a, u32 n) {
|
||||
@@ -512,6 +596,11 @@ i128 i128_shr(i128 a, u32 n) {
|
||||
return i128_lo_hi(0, 0);
|
||||
}
|
||||
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.lo = __shiftright128(a.lo, a.hi, n);
|
||||
a.hi = a.hi >> n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.lo = a.hi;
|
||||
@@ -525,6 +614,7 @@ i128 i128_shr(i128 a, u32 n) {
|
||||
a.hi >>= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -541,6 +631,13 @@ i128 i128_mul(i128 a, i128 b) {
|
||||
return a;
|
||||
}
|
||||
|
||||
#if defined(MSVC_AMD64_INTRINSICS)
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
a.lo = _mul128(a.lo, b.lo, &a.hi);
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
i128 res = {0};
|
||||
i128 t = b;
|
||||
for (u32 i = 0; i < 128; i++) {
|
||||
+385
-366
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// Optimizations for the IR code
|
||||
|
||||
void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
||||
void ir_opt_add_operands(Array<irValue *> *ops, irInstr *i) {
|
||||
switch (i->kind) {
|
||||
case irInstr_Comment:
|
||||
break;
|
||||
@@ -48,7 +48,7 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
||||
break;
|
||||
case irInstr_Phi:
|
||||
for_array(j, i->Phi.edges) {
|
||||
array_add(ops, i->Phi.edges.e[j]);
|
||||
array_add(ops, i->Phi.edges[j]);
|
||||
}
|
||||
break;
|
||||
case irInstr_Unreachable:
|
||||
@@ -97,24 +97,24 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
||||
|
||||
void ir_opt_block_replace_pred(irBlock *b, irBlock *from, irBlock *to) {
|
||||
for_array(i, b->preds) {
|
||||
irBlock *pred = b->preds.e[i];
|
||||
irBlock *pred = b->preds[i];
|
||||
if (pred == from) {
|
||||
b->preds.e[i] = to;
|
||||
b->preds[i] = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ir_opt_block_replace_succ(irBlock *b, irBlock *from, irBlock *to) {
|
||||
for_array(i, b->succs) {
|
||||
irBlock *succ = b->succs.e[i];
|
||||
irBlock *succ = b->succs[i];
|
||||
if (succ == from) {
|
||||
b->succs.e[i] = to;
|
||||
b->succs[i] = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ir_opt_block_has_phi(irBlock *b) {
|
||||
return b->instrs.e[0]->Instr.kind == irInstr_Phi;
|
||||
return b->instrs[0]->Instr.kind == irInstr_Phi;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,10 +126,10 @@ bool ir_opt_block_has_phi(irBlock *b) {
|
||||
|
||||
|
||||
|
||||
irValueArray ir_get_block_phi_nodes(irBlock *b) {
|
||||
irValueArray phis = {0};
|
||||
Array<irValue *> ir_get_block_phi_nodes(irBlock *b) {
|
||||
Array<irValue *> phis = {0};
|
||||
for_array(i, b->instrs) {
|
||||
irInstr *instr = &b->instrs.e[i]->Instr;
|
||||
irInstr *instr = &b->instrs[i]->Instr;
|
||||
if (instr->kind != irInstr_Phi) {
|
||||
phis = b->instrs;
|
||||
phis.count = i;
|
||||
@@ -140,22 +140,22 @@ irValueArray ir_get_block_phi_nodes(irBlock *b) {
|
||||
}
|
||||
|
||||
void ir_remove_pred(irBlock *b, irBlock *p) {
|
||||
irValueArray phis = ir_get_block_phi_nodes(b);
|
||||
Array<irValue *> phis = ir_get_block_phi_nodes(b);
|
||||
isize i = 0;
|
||||
for_array(j, b->preds) {
|
||||
irBlock *pred = b->preds.e[j];
|
||||
irBlock *pred = b->preds[j];
|
||||
if (pred != p) {
|
||||
b->preds.e[i] = b->preds.e[j];
|
||||
b->preds[i] = b->preds[j];
|
||||
for_array(k, phis) {
|
||||
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
|
||||
phi->edges.e[i] = phi->edges.e[j];
|
||||
irInstrPhi *phi = &phis[k]->Instr.Phi;
|
||||
phi->edges[i] = phi->edges[j];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
b->preds.count = i;
|
||||
for_array(k, phis) {
|
||||
irInstrPhi *phi = &phis.e[k]->Instr.Phi;
|
||||
irInstrPhi *phi = &phis[k]->Instr.Phi;
|
||||
phi->edges.count = i;
|
||||
}
|
||||
|
||||
@@ -164,13 +164,13 @@ void ir_remove_pred(irBlock *b, irBlock *p) {
|
||||
void ir_remove_dead_blocks(irProcedure *proc) {
|
||||
isize j = 0;
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *b = proc->blocks.e[i];
|
||||
irBlock *b = proc->blocks[i];
|
||||
if (b == NULL) {
|
||||
continue;
|
||||
}
|
||||
// NOTE(bill): Swap order
|
||||
b->index = j;
|
||||
proc->blocks.e[j++] = b;
|
||||
proc->blocks[j++] = b;
|
||||
}
|
||||
proc->blocks.count = j;
|
||||
}
|
||||
@@ -180,7 +180,7 @@ void ir_mark_reachable(irBlock *b) {
|
||||
isize const BLACK = -1;
|
||||
b->index = BLACK;
|
||||
for_array(i, b->succs) {
|
||||
irBlock *succ = b->succs.e[i];
|
||||
irBlock *succ = b->succs[i];
|
||||
if (succ->index == WHITE) {
|
||||
ir_mark_reachable(succ);
|
||||
}
|
||||
@@ -191,23 +191,23 @@ void ir_remove_unreachable_blocks(irProcedure *proc) {
|
||||
isize const WHITE = 0;
|
||||
isize const BLACK = -1;
|
||||
for_array(i, proc->blocks) {
|
||||
proc->blocks.e[i]->index = WHITE;
|
||||
proc->blocks[i]->index = WHITE;
|
||||
}
|
||||
|
||||
ir_mark_reachable(proc->blocks.e[0]);
|
||||
ir_mark_reachable(proc->blocks[0]);
|
||||
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *b = proc->blocks.e[i];
|
||||
irBlock *b = proc->blocks[i];
|
||||
if (b->index == WHITE) {
|
||||
for_array(j, b->succs) {
|
||||
irBlock *c = b->succs.e[j];
|
||||
irBlock *c = b->succs[j];
|
||||
if (c->index == BLACK) {
|
||||
ir_remove_pred(c, b);
|
||||
}
|
||||
}
|
||||
// NOTE(bill): Mark as empty but don't actually free it
|
||||
// As it's been allocated with an arena
|
||||
proc->blocks.e[i] = NULL;
|
||||
proc->blocks[i] = NULL;
|
||||
}
|
||||
}
|
||||
ir_remove_dead_blocks(proc);
|
||||
@@ -217,7 +217,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
|
||||
if (a->succs.count != 1) {
|
||||
return false;
|
||||
}
|
||||
irBlock *b = a->succs.e[0];
|
||||
irBlock *b = a->succs[0];
|
||||
if (b->preds.count != 1) {
|
||||
return false;
|
||||
}
|
||||
@@ -228,21 +228,21 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
|
||||
|
||||
array_pop(&a->instrs); // Remove branch at end
|
||||
for_array(i, b->instrs) {
|
||||
array_add(&a->instrs, b->instrs.e[i]);
|
||||
ir_set_instr_parent(b->instrs.e[i], a);
|
||||
array_add(&a->instrs, b->instrs[i]);
|
||||
ir_set_instr_parent(b->instrs[i], a);
|
||||
}
|
||||
|
||||
array_clear(&a->succs);
|
||||
for_array(i, b->succs) {
|
||||
array_add(&a->succs, b->succs.e[i]);
|
||||
array_add(&a->succs, b->succs[i]);
|
||||
}
|
||||
|
||||
// Fix preds links
|
||||
for_array(i, b->succs) {
|
||||
ir_opt_block_replace_pred(b->succs.e[i], b, a);
|
||||
ir_opt_block_replace_pred(b->succs[i], b, a);
|
||||
}
|
||||
|
||||
proc->blocks.e[b->index] = NULL;
|
||||
proc->blocks[b->index] = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ void ir_opt_blocks(irProcedure *proc) {
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *b = proc->blocks.e[i];
|
||||
irBlock *b = proc->blocks[i];
|
||||
if (b == NULL) {
|
||||
continue;
|
||||
}
|
||||
@@ -273,20 +273,20 @@ void ir_opt_blocks(irProcedure *proc) {
|
||||
void ir_opt_build_referrers(irProcedure *proc) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
|
||||
irValueArray ops = {0}; // NOTE(bill): Act as a buffer
|
||||
array_init_reserve(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
|
||||
Array<irValue *> ops = {0}; // NOTE(bill): Act as a buffer
|
||||
array_init(&ops, proc->module->tmp_allocator, 64); // HACK(bill): This _could_ overflow the temp arena
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *b = proc->blocks.e[i];
|
||||
irBlock *b = proc->blocks[i];
|
||||
for_array(j, b->instrs) {
|
||||
irValue *instr = b->instrs.e[j];
|
||||
irValue *instr = b->instrs[j];
|
||||
array_clear(&ops);
|
||||
ir_opt_add_operands(&ops, &instr->Instr);
|
||||
for_array(k, ops) {
|
||||
irValue *op = ops.e[k];
|
||||
irValue *op = ops[k];
|
||||
if (op == NULL) {
|
||||
continue;
|
||||
}
|
||||
irValueArray *refs = ir_value_referrers(op);
|
||||
Array<irValue *> *refs = ir_value_referrers(op);
|
||||
if (refs != NULL) {
|
||||
array_add(refs, instr);
|
||||
}
|
||||
@@ -324,7 +324,7 @@ i32 ir_lt_depth_first_search(irLTState *lt, irBlock *p, i32 i, irBlock **preorde
|
||||
lt->sdom[p->index] = p;
|
||||
ir_lt_link(lt, NULL, p);
|
||||
for_array(index, p->succs) {
|
||||
irBlock *q = p->succs.e[index];
|
||||
irBlock *q = p->succs[index];
|
||||
if (lt->sdom[q->index] == NULL) {
|
||||
lt->parent[q->index] = p;
|
||||
i = ir_lt_depth_first_search(lt, q, i, preorder);
|
||||
@@ -354,7 +354,7 @@ irDomPrePost ir_opt_number_dom_tree(irBlock *v, i32 pre, i32 post) {
|
||||
|
||||
v->dom.pre = pre++;
|
||||
for_array(i, v->dom.children) {
|
||||
result = ir_opt_number_dom_tree(v->dom.children.e[i], result.pre, result.post);
|
||||
result = ir_opt_number_dom_tree(v->dom.children[i], result.pre, result.post);
|
||||
}
|
||||
v->dom.post = post++;
|
||||
|
||||
@@ -381,7 +381,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||
|
||||
irBlock **preorder = &buf[3*n];
|
||||
irBlock **buckets = &buf[4*n];
|
||||
irBlock *root = proc->blocks.e[0];
|
||||
irBlock *root = proc->blocks[0];
|
||||
|
||||
// Step 1 - number vertices
|
||||
i32 pre_num = ir_lt_depth_first_search(<, root, 0, preorder);
|
||||
@@ -403,7 +403,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||
// Step 2 - Compute all sdoms
|
||||
lt.sdom[w->index] = lt.parent[w->index];
|
||||
for_array(pred_index, w->preds) {
|
||||
irBlock *v = w->preds.e[pred_index];
|
||||
irBlock *v = w->preds[pred_index];
|
||||
irBlock *u = ir_lt_eval(<, v);
|
||||
if (lt.sdom[u->index]->dom.pre < lt.sdom[w->index]->dom.pre) {
|
||||
lt.sdom[w->index] = lt.sdom[u->index];
|
||||
@@ -438,7 +438,7 @@ void ir_opt_build_dom_tree(irProcedure *proc) {
|
||||
}
|
||||
|
||||
// Calculate children relation as inverse of idom
|
||||
if (w->dom.idom->dom.children.e == NULL) {
|
||||
if (w->dom.idom->dom.children.data == NULL) {
|
||||
// TODO(bill): Is this good enough for memory allocations?
|
||||
array_init(&w->dom.idom->dom.children, heap_allocator());
|
||||
}
|
||||
@@ -461,7 +461,7 @@ void ir_opt_tree(irGen *s) {
|
||||
s->opt_called = true;
|
||||
|
||||
for_array(member_index, s->module.procs) {
|
||||
irProcedure *proc = s->module.procs.e[member_index];
|
||||
irProcedure *proc = s->module.procs[member_index];
|
||||
if (proc->blocks.count == 0) { // Prototype/external procedure
|
||||
continue;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
typedef struct irFileBuffer {
|
||||
struct irFileBuffer {
|
||||
gbVirtualMemory vm;
|
||||
isize offset;
|
||||
gbFile * output;
|
||||
} irFileBuffer;
|
||||
};
|
||||
|
||||
void ir_file_buffer_init(irFileBuffer *f, gbFile *output) {
|
||||
isize size = 8*gb_virtual_memory_page_size(NULL);
|
||||
@@ -39,7 +39,7 @@ void ir_file_buffer_write(irFileBuffer *f, void *data, isize len) {
|
||||
void ir_fprintf(irFileBuffer *f, char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
char buf[4096] = {0};
|
||||
char buf[4096] = {};
|
||||
isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
|
||||
ir_file_buffer_write(f, buf, len-1);
|
||||
va_end(va);
|
||||
@@ -48,7 +48,7 @@ void ir_fprint_string(irFileBuffer *f, String s) {
|
||||
ir_file_buffer_write(f, s.text, s.len);
|
||||
}
|
||||
void ir_fprint_i128(irFileBuffer *f, i128 i) {
|
||||
char buf[200] = {0};
|
||||
char buf[200] = {};
|
||||
String str = i128_to_string(i, buf, gb_size_of(buf)-1);
|
||||
ir_fprint_string(f, str);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ bool ir_valid_char(u8 c) {
|
||||
void ir_print_escape_string(irFileBuffer *f, String name, bool print_quotes, bool prefix_with_dot) {
|
||||
isize extra = 0;
|
||||
for (isize i = 0; i < name.len; i++) {
|
||||
u8 c = name.text[i];
|
||||
u8 c = name[i];
|
||||
if (!ir_valid_char(c)) {
|
||||
extra += 2;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ void ir_print_escape_string(irFileBuffer *f, String name, bool print_quotes, boo
|
||||
}
|
||||
|
||||
for (isize i = 0; i < name.len; i++) {
|
||||
u8 c = name.text[i];
|
||||
u8 c = name[i];
|
||||
if (ir_valid_char(c)) {
|
||||
buf[j++] = c;
|
||||
} else {
|
||||
@@ -306,7 +306,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
|
||||
case Type_Named:
|
||||
if (is_type_struct(t) || is_type_union(t)) {
|
||||
String *name = map_string_get(&m->entity_names, hash_pointer(t->Named.type_name));
|
||||
String *name = map_get(&m->entity_names, hash_pointer(t->Named.type_name));
|
||||
GB_ASSERT_MSG(name != NULL, "%.*s", LIT(t->Named.name));
|
||||
ir_print_encoded_local(f, *name);
|
||||
} else {
|
||||
@@ -497,7 +497,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
if (i > 0) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[i]);
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[i]);
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||
}
|
||||
@@ -527,7 +527,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_fprintf(f, "][");
|
||||
|
||||
if (elem_count == 1 && type->Vector.count > 1) {
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[0]);
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[0]);
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
|
||||
for (isize i = 0; i < type->Vector.count; i++) {
|
||||
@@ -541,7 +541,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
if (i > 0) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[i]);
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[i]);
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||
}
|
||||
@@ -563,25 +563,25 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ExactValue *values = gb_alloc_array(m->tmp_allocator, ExactValue, value_count);
|
||||
|
||||
|
||||
if (cl->elems.e[0]->kind == AstNode_FieldValue) {
|
||||
if (cl->elems[0]->kind == AstNode_FieldValue) {
|
||||
isize elem_count = cl->elems.count;
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
ast_node(fv, FieldValue, cl->elems.e[i]);
|
||||
ast_node(fv, FieldValue, cl->elems[i]);
|
||||
String name = fv->field->Ident.string;
|
||||
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, fv->value);
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
|
||||
Selection sel = lookup_field(m->allocator, type, name, false);
|
||||
Entity *f = type->Record.fields[sel.index.e[0]];
|
||||
Entity *f = type->Record.fields[sel.index[0]];
|
||||
|
||||
values[f->Variable.field_index] = tav.value;
|
||||
}
|
||||
} else {
|
||||
for (isize i = 0; i < value_count; i++) {
|
||||
Entity *f = type->Record.fields_in_src_order[i];
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems.e[i]);
|
||||
ExactValue val = {0};
|
||||
TypeAndValue tav = type_and_value_of_expr(m->info, cl->elems[i]);
|
||||
ExactValue val = {};
|
||||
if (tav.mode != Addressing_Invalid) {
|
||||
val = tav.value;
|
||||
}
|
||||
@@ -891,11 +891,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, ", ");
|
||||
}
|
||||
|
||||
irValue *edge = instr->Phi.edges.e[i];
|
||||
irValue *edge = instr->Phi.edges[i];
|
||||
irBlock *block = NULL;
|
||||
if (instr->parent != NULL &&
|
||||
i < instr->parent->preds.count) {
|
||||
block = instr->parent->preds.e[i];
|
||||
block = instr->parent->preds[i];
|
||||
}
|
||||
|
||||
ir_fprintf(f, "[ ");
|
||||
@@ -1500,8 +1500,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
ir_fprintf(f, " noalias");
|
||||
}
|
||||
if (proc->body != NULL) {
|
||||
if (!str_eq(e->token.string, str_lit("")) &&
|
||||
!str_eq(e->token.string, str_lit("_"))) {
|
||||
if (e->token.string != "" &&
|
||||
e->token.string != "_") {
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_encoded_local(f, e->token.string);
|
||||
} else {
|
||||
@@ -1523,7 +1523,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
|
||||
if (proc->entity != NULL) {
|
||||
if (proc->body != NULL) {
|
||||
irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
if (di_ != NULL) {
|
||||
irDebugInfo *di = *di_;
|
||||
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
||||
@@ -1538,14 +1538,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
|
||||
ir_fprintf(f, "{\n");
|
||||
for_array(i, proc->blocks) {
|
||||
irBlock *block = proc->blocks.e[i];
|
||||
irBlock *block = proc->blocks[i];
|
||||
|
||||
if (i > 0) ir_fprintf(f, "\n");
|
||||
ir_print_block_name(f, block);
|
||||
ir_fprintf(f, ":\n");
|
||||
|
||||
for_array(j, block->instrs) {
|
||||
irValue *value = block->instrs.e[j];
|
||||
irValue *value = block->instrs[j];
|
||||
ir_print_instr(f, m, value);
|
||||
}
|
||||
}
|
||||
@@ -1555,7 +1555,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
}
|
||||
|
||||
for_array(i, proc->children) {
|
||||
ir_print_proc(f, m, proc->children.e[i]);
|
||||
ir_print_proc(f, m, proc->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1573,7 +1573,7 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
||||
|
||||
void print_llvm_ir(irGen *ir) {
|
||||
irModule *m = &ir->module;
|
||||
irFileBuffer buf = {0}, *f = &buf;
|
||||
irFileBuffer buf = {}, *f = &buf;
|
||||
ir_file_buffer_init(f, &ir->output_file);
|
||||
|
||||
ir_print_encoded_local(f, str_lit("..string"));
|
||||
@@ -1606,7 +1606,7 @@ void print_llvm_ir(irGen *ir) {
|
||||
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapIrValueEntry *entry = &m->members.entries.e[member_index];
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
irValue *v = entry->value;
|
||||
if (v->kind != irValue_TypeName) {
|
||||
continue;
|
||||
@@ -1619,7 +1619,7 @@ void print_llvm_ir(irGen *ir) {
|
||||
bool dll_main_found = false;
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapIrValueEntry *entry = &m->members.entries.e[member_index];
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
irValue *v = entry->value;
|
||||
if (v->kind != irValue_Proc) {
|
||||
continue;
|
||||
@@ -1631,7 +1631,7 @@ void print_llvm_ir(irGen *ir) {
|
||||
}
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapIrValueEntry *entry = &m->members.entries.e[member_index];
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
irValue *v = entry->value;
|
||||
if (v->kind != irValue_Proc) {
|
||||
continue;
|
||||
@@ -1643,7 +1643,7 @@ void print_llvm_ir(irGen *ir) {
|
||||
}
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapIrValueEntry *entry = &m->members.entries.e[member_index];
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
irValue *v = entry->value;
|
||||
if (v->kind != irValue_Global) {
|
||||
continue;
|
||||
@@ -1707,13 +1707,13 @@ void print_llvm_ir(irGen *ir) {
|
||||
ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
|
||||
|
||||
for_array(di_index, m->debug_info.entries) {
|
||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
|
||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries[di_index];
|
||||
irDebugInfo *di = entry->value;
|
||||
ir_fprintf(f, "!%d = ", di->id);
|
||||
|
||||
switch (di->kind) {
|
||||
case irDebugInfo_CompileUnit: {
|
||||
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||
irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||
ir_fprintf(f,
|
||||
"distinct !DICompileUnit("
|
||||
"language: DW_LANG_Go, " // Is this good enough?
|
||||
@@ -1752,7 +1752,7 @@ void print_llvm_ir(irGen *ir) {
|
||||
case irDebugInfo_AllProcs:
|
||||
ir_fprintf(f, "!{");
|
||||
for_array(proc_index, di->AllProcs.procs) {
|
||||
irDebugInfo *p = di->AllProcs.procs.e[proc_index];
|
||||
irDebugInfo *p = di->AllProcs.procs[proc_index];
|
||||
if (proc_index > 0) {ir_fprintf(f, ",");}
|
||||
ir_fprintf(f, "!%d", p->id);
|
||||
}
|
||||
+17
-26
@@ -1,20 +1,15 @@
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define USE_CUSTOM_BACKEND false
|
||||
|
||||
#include "common.c"
|
||||
#include "timings.c"
|
||||
#include "build_settings.c"
|
||||
#include "tokenizer.c"
|
||||
#include "parser.c"
|
||||
#include "checker.c"
|
||||
#include "ssa.c"
|
||||
#include "ir.c"
|
||||
#include "ir_opt.c"
|
||||
#include "ir_print.c"
|
||||
// #include "vm.c"
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
#include "build_settings.cpp"
|
||||
#include "tokenizer.cpp"
|
||||
#include "parser.cpp"
|
||||
#include "checker.cpp"
|
||||
#include "ssa.cpp"
|
||||
#include "ir.cpp"
|
||||
#include "ir_opt.cpp"
|
||||
#include "ir_print.cpp"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
// NOTE(bill): `name` is used in debugging and profiling modes
|
||||
@@ -155,27 +150,27 @@ int main(int argc, char **argv) {
|
||||
char *init_filename = NULL;
|
||||
bool run_output = false;
|
||||
String arg1 = make_string_c(argv[1]);
|
||||
if (str_eq(arg1, str_lit("run"))) {
|
||||
if (arg1 == "run") {
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = argv[2];
|
||||
run_output = true;
|
||||
} else if (str_eq(arg1, str_lit("build_dll"))) {
|
||||
} else if (arg1 == "build_dll") {
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = argv[2];
|
||||
build_context.is_dll = true;
|
||||
} else if (str_eq(arg1, str_lit("build"))) {
|
||||
} else if (arg1 == "build") {
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
init_filename = argv[2];
|
||||
} else if (str_eq(arg1, str_lit("version"))) {
|
||||
} else if (arg1 == "version") {
|
||||
gb_printf("%s version %.*s\n", argv[0], LIT(build_context.ODIN_VERSION));
|
||||
return 0;
|
||||
} else {
|
||||
@@ -314,7 +309,7 @@ int main(int argc, char **argv) {
|
||||
// defer (gb_string_free(lib_str));
|
||||
char lib_str_buf[1024] = {0};
|
||||
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||
String lib = ir_gen.module.foreign_library_paths.e[i];
|
||||
String lib = ir_gen.module.foreign_library_paths[i];
|
||||
// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
|
||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||
" \"%.*s\"", LIT(lib));
|
||||
@@ -376,14 +371,14 @@ int main(int argc, char **argv) {
|
||||
// defer (gb_string_free(lib_str));
|
||||
char lib_str_buf[1024] = {0};
|
||||
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||
String lib = ir_gen.module.foreign_library_paths.e[i];
|
||||
String lib = ir_gen.module.foreign_library_paths[i];
|
||||
|
||||
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
|
||||
// This allows you to specify '-f' in a #foreign_system_library,
|
||||
// without having to implement any new syntax specifically for MacOS.
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
isize len;
|
||||
if(lib.len > 2 && lib.text[0] == '-' && lib.text[1] == 'f') {
|
||||
if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||
" -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
|
||||
} else {
|
||||
@@ -461,7 +456,3 @@ int main(int argc, char **argv) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -1,364 +0,0 @@
|
||||
/*
|
||||
Example of usage:
|
||||
|
||||
#define MAP_TYPE String
|
||||
#define MAP_PROC map_string_
|
||||
#define MAP_NAME MapString
|
||||
#include "map.c"
|
||||
*/
|
||||
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
|
||||
// with the use of the `multi_*` procedures.
|
||||
// TODO(bill): I should probably allow the `multi_*` stuff to be #ifdefed out
|
||||
|
||||
#ifndef MAP_UTIL_STUFF
|
||||
#define MAP_UTIL_STUFF
|
||||
// NOTE(bill): This util stuff is the same for every `Map`
|
||||
typedef struct MapFindResult {
|
||||
isize hash_index;
|
||||
isize entry_prev;
|
||||
isize entry_index;
|
||||
} MapFindResult;
|
||||
|
||||
typedef enum HashKeyKind {
|
||||
HashKey_Default,
|
||||
HashKey_String,
|
||||
HashKey_Pointer,
|
||||
} HashKeyKind;
|
||||
|
||||
typedef struct HashKey {
|
||||
HashKeyKind kind;
|
||||
u64 key;
|
||||
union {
|
||||
String string; // if String, s.len > 0
|
||||
void * ptr;
|
||||
};
|
||||
} HashKey;
|
||||
|
||||
gb_inline HashKey hashing_proc(void const *data, isize len) {
|
||||
HashKey h = {HashKey_Default};
|
||||
h.kind = HashKey_Default;
|
||||
// h.key = gb_murmur64(data, len);
|
||||
h.key = gb_fnv64a(data, len);
|
||||
// h.key = MurmurHash3_128(data, len, 0x3803cb8e);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
gb_inline HashKey hash_string(String s) {
|
||||
HashKey h = hashing_proc(s.text, s.len);
|
||||
h.kind = HashKey_String;
|
||||
h.string = s;
|
||||
return h;
|
||||
}
|
||||
|
||||
gb_inline HashKey hash_pointer(void *ptr) {
|
||||
HashKey h = {HashKey_Default};
|
||||
// h.key = u128_from_u64(cast(u64)cast(uintptr)ptr);
|
||||
h.key = cast(u64)cast(uintptr)ptr;
|
||||
h.ptr = ptr;
|
||||
h.kind = HashKey_Default;
|
||||
return h;
|
||||
}
|
||||
|
||||
bool hash_key_equal(HashKey a, HashKey b) {
|
||||
if (a.key == b.key) {
|
||||
// NOTE(bill): If two string's hashes collide, compare the strings themselves
|
||||
if (a.kind == HashKey_String) {
|
||||
if (b.kind == HashKey_String) {
|
||||
return str_eq(a.string, b.string);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define _J2_IND(a, b) a##b
|
||||
#define _J2(a, b) _J2_IND(a, b)
|
||||
|
||||
/*
|
||||
MAP_TYPE - Entry type
|
||||
MAP_PROC - Function prefix (e.g. entity_map_)
|
||||
MAP_NAME - Name of Map (e.g. EntityMap)
|
||||
*/
|
||||
#define MAP_ENTRY _J2(MAP_NAME,Entry)
|
||||
|
||||
typedef struct MAP_ENTRY {
|
||||
HashKey key;
|
||||
isize next;
|
||||
MAP_TYPE value;
|
||||
} MAP_ENTRY;
|
||||
|
||||
typedef struct MAP_NAME {
|
||||
Array(isize) hashes;
|
||||
Array(MAP_ENTRY) entries;
|
||||
} MAP_NAME;
|
||||
|
||||
void _J2(MAP_PROC,init) (MAP_NAME *h, gbAllocator a);
|
||||
void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity);
|
||||
void _J2(MAP_PROC,destroy) (MAP_NAME *h);
|
||||
MAP_TYPE *_J2(MAP_PROC,get) (MAP_NAME *h, HashKey key);
|
||||
void _J2(MAP_PROC,set) (MAP_NAME *h, HashKey key, MAP_TYPE value);
|
||||
void _J2(MAP_PROC,remove) (MAP_NAME *h, HashKey key);
|
||||
void _J2(MAP_PROC,clear) (MAP_NAME *h);
|
||||
void _J2(MAP_PROC,grow) (MAP_NAME *h);
|
||||
void _J2(MAP_PROC,rehash) (MAP_NAME *h, isize new_count);
|
||||
|
||||
// Mutlivalued map procedure
|
||||
MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key);
|
||||
MAP_ENTRY *_J2(MAP_PROC,multi_find_next) (MAP_NAME *h, MAP_ENTRY *e);
|
||||
|
||||
isize _J2(MAP_PROC,multi_count) (MAP_NAME *h, HashKey key);
|
||||
void _J2(MAP_PROC,multi_get_all) (MAP_NAME *h, HashKey key, MAP_TYPE *items);
|
||||
void _J2(MAP_PROC,multi_insert) (MAP_NAME *h, HashKey key, MAP_TYPE value);
|
||||
void _J2(MAP_PROC,multi_remove) (MAP_NAME *h, HashKey key, MAP_ENTRY *e);
|
||||
void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key);
|
||||
|
||||
|
||||
|
||||
gb_inline void _J2(MAP_PROC,init)(MAP_NAME *h, gbAllocator a) {
|
||||
array_init(&h->hashes, a);
|
||||
array_init(&h->entries, a);
|
||||
}
|
||||
|
||||
gb_inline void _J2(MAP_PROC,init_with_reserve)(MAP_NAME *h, gbAllocator a, isize capacity) {
|
||||
array_init_reserve(&h->hashes, a, capacity);
|
||||
array_init_reserve(&h->entries, a, capacity);
|
||||
}
|
||||
|
||||
gb_inline void _J2(MAP_PROC,destroy)(MAP_NAME *h) {
|
||||
array_free(&h->entries);
|
||||
array_free(&h->hashes);
|
||||
}
|
||||
|
||||
gb_internal isize _J2(MAP_PROC,_add_entry)(MAP_NAME *h, HashKey key) {
|
||||
MAP_ENTRY e = {0};
|
||||
e.key = key;
|
||||
e.next = -1;
|
||||
array_add(&h->entries, e);
|
||||
return h->entries.count-1;
|
||||
}
|
||||
|
||||
gb_internal MapFindResult _J2(MAP_PROC,_find)(MAP_NAME *h, HashKey key) {
|
||||
MapFindResult fr = {-1, -1, -1};
|
||||
if (h->hashes.count > 0) {
|
||||
fr.hash_index = key.key % h->hashes.count;
|
||||
fr.entry_index = h->hashes.e[fr.hash_index];
|
||||
while (fr.entry_index >= 0) {
|
||||
if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = h->entries.e[fr.entry_index].next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
gb_internal MapFindResult _J2(MAP_PROC,_find_from_entry)(MAP_NAME *h, MAP_ENTRY *e) {
|
||||
MapFindResult fr = {-1, -1, -1};
|
||||
if (h->hashes.count > 0) {
|
||||
fr.hash_index = e->key.key % h->hashes.count;
|
||||
fr.entry_index = h->hashes.e[fr.hash_index];
|
||||
while (fr.entry_index >= 0) {
|
||||
if (&h->entries.e[fr.entry_index] == e) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = h->entries.e[fr.entry_index].next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
|
||||
gb_internal b32 _J2(MAP_PROC,_full)(MAP_NAME *h) {
|
||||
return 0.75f * h->hashes.count <= h->entries.count;
|
||||
}
|
||||
|
||||
gb_inline void _J2(MAP_PROC,grow)(MAP_NAME *h) {
|
||||
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
|
||||
_J2(MAP_PROC,rehash)(h, new_count);
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,rehash)(MAP_NAME *h, isize new_count) {
|
||||
isize i, j;
|
||||
MAP_NAME nh = {0};
|
||||
_J2(MAP_PROC,init)(&nh, h->hashes.allocator);
|
||||
array_resize(&nh.hashes, new_count);
|
||||
array_reserve(&nh.entries, h->entries.count);
|
||||
for (i = 0; i < new_count; i++) {
|
||||
nh.hashes.e[i] = -1;
|
||||
}
|
||||
for (i = 0; i < h->entries.count; i++) {
|
||||
MAP_ENTRY *e = &h->entries.e[i];
|
||||
MapFindResult fr;
|
||||
if (nh.hashes.count == 0) {
|
||||
_J2(MAP_PROC,grow)(&nh);
|
||||
}
|
||||
fr = _J2(MAP_PROC,_find)(&nh, e->key);
|
||||
j = _J2(MAP_PROC,_add_entry)(&nh, e->key);
|
||||
if (fr.entry_prev < 0) {
|
||||
nh.hashes.e[fr.hash_index] = j;
|
||||
} else {
|
||||
nh.entries.e[fr.entry_prev].next = j;
|
||||
}
|
||||
nh.entries.e[j].next = fr.entry_index;
|
||||
nh.entries.e[j].value = e->value;
|
||||
if (_J2(MAP_PROC,_full)(&nh)) {
|
||||
_J2(MAP_PROC,grow)(&nh);
|
||||
}
|
||||
}
|
||||
_J2(MAP_PROC,destroy)(h);
|
||||
*h = nh;
|
||||
}
|
||||
|
||||
gb_inline MAP_TYPE *_J2(MAP_PROC,get)(MAP_NAME *h, HashKey key) {
|
||||
isize index = _J2(MAP_PROC,_find)(h, key).entry_index;
|
||||
if (index >= 0) {
|
||||
return &h->entries.e[index].value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,set)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
|
||||
isize index;
|
||||
MapFindResult fr;
|
||||
if (h->hashes.count == 0)
|
||||
_J2(MAP_PROC,grow)(h);
|
||||
fr = _J2(MAP_PROC,_find)(h, key);
|
||||
if (fr.entry_index >= 0) {
|
||||
index = fr.entry_index;
|
||||
} else {
|
||||
index = _J2(MAP_PROC,_add_entry)(h, key);
|
||||
if (fr.entry_prev >= 0) {
|
||||
h->entries.e[fr.entry_prev].next = index;
|
||||
} else {
|
||||
h->hashes.e[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
h->entries.e[index].value = value;
|
||||
|
||||
if (_J2(MAP_PROC,_full)(h)) {
|
||||
_J2(MAP_PROC,grow)(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _J2(MAP_PROC,_erase)(MAP_NAME *h, MapFindResult fr) {
|
||||
MapFindResult last;
|
||||
if (fr.entry_prev < 0) {
|
||||
h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next;
|
||||
} else {
|
||||
h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next;
|
||||
}
|
||||
if (fr.entry_index == h->entries.count-1) {
|
||||
array_pop(&h->entries);
|
||||
return;
|
||||
}
|
||||
h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1];
|
||||
last = _J2(MAP_PROC,_find)(h, h->entries.e[fr.entry_index].key);
|
||||
if (last.entry_prev >= 0) {
|
||||
h->entries.e[last.entry_prev].next = fr.entry_index;
|
||||
} else {
|
||||
h->hashes.e[last.hash_index] = fr.entry_index;
|
||||
}
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,remove)(MAP_NAME *h, HashKey key) {
|
||||
MapFindResult fr = _J2(MAP_PROC,_find)(h, key);
|
||||
if (fr.entry_index >= 0) {
|
||||
_J2(MAP_PROC,_erase)(h, fr);
|
||||
}
|
||||
}
|
||||
|
||||
gb_inline void _J2(MAP_PROC,clear)(MAP_NAME *h) {
|
||||
array_clear(&h->hashes);
|
||||
array_clear(&h->entries);
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
MAP_ENTRY *_J2(MAP_PROC,multi_find_first)(MAP_NAME *h, HashKey key) {
|
||||
isize i = _J2(MAP_PROC,_find)(h, key).entry_index;
|
||||
if (i < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &h->entries.e[i];
|
||||
}
|
||||
|
||||
MAP_ENTRY *_J2(MAP_PROC,multi_find_next)(MAP_NAME *h, MAP_ENTRY *e) {
|
||||
isize i = e->next;
|
||||
while (i >= 0) {
|
||||
if (hash_key_equal(h->entries.e[i].key, e->key)) {
|
||||
return &h->entries.e[i];
|
||||
}
|
||||
i = h->entries.e[i].next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
isize _J2(MAP_PROC,multi_count)(MAP_NAME *h, HashKey key) {
|
||||
isize count = 0;
|
||||
MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key);
|
||||
while (e != NULL) {
|
||||
count++;
|
||||
e = _J2(MAP_PROC,multi_find_next)(h, e);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,multi_get_all)(MAP_NAME *h, HashKey key, MAP_TYPE *items) {
|
||||
isize i = 0;
|
||||
MAP_ENTRY *e = _J2(MAP_PROC,multi_find_first)(h, key);
|
||||
while (e != NULL) {
|
||||
items[i++] = e->value;
|
||||
e = _J2(MAP_PROC,multi_find_next)(h, e);
|
||||
}
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,multi_insert)(MAP_NAME *h, HashKey key, MAP_TYPE value) {
|
||||
MapFindResult fr;
|
||||
isize i;
|
||||
if (h->hashes.count == 0) {
|
||||
_J2(MAP_PROC,grow)(h);
|
||||
}
|
||||
// Make
|
||||
fr = _J2(MAP_PROC,_find)(h, key);
|
||||
i = _J2(MAP_PROC,_add_entry)(h, key);
|
||||
if (fr.entry_prev < 0) {
|
||||
h->hashes.e[fr.hash_index] = i;
|
||||
} else {
|
||||
h->entries.e[fr.entry_prev].next = i;
|
||||
}
|
||||
h->entries.e[i].next = fr.entry_index;
|
||||
h->entries.e[i].value = value;
|
||||
// Grow if needed
|
||||
if (_J2(MAP_PROC,_full)(h)) {
|
||||
_J2(MAP_PROC,grow)(h);
|
||||
}
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,multi_remove)(MAP_NAME *h, HashKey key, MAP_ENTRY *e) {
|
||||
MapFindResult fr = _J2(MAP_PROC,_find_from_entry)(h, e);
|
||||
if (fr.entry_index >= 0) {
|
||||
_J2(MAP_PROC,_erase)(h, fr);
|
||||
}
|
||||
}
|
||||
|
||||
void _J2(MAP_PROC,multi_remove_all)(MAP_NAME *h, HashKey key) {
|
||||
while (_J2(MAP_PROC,get)(h, key) != NULL) {
|
||||
_J2(MAP_PROC,remove)(h, key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#undef _J2
|
||||
#undef MAP_TYPE
|
||||
#undef MAP_PROC
|
||||
#undef MAP_NAME
|
||||
#undef MAP_ENTRY
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
// A `Map` is an unordered hash table which can allow for a key to point to multiple values
|
||||
// with the use of the `multi_*` procedures.
|
||||
// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out
|
||||
|
||||
#ifndef MAP_UTIL_STUFF
|
||||
#define MAP_UTIL_STUFF
|
||||
// NOTE(bill): This util stuff is the same for every `Map`
|
||||
struct MapFindResult {
|
||||
isize hash_index;
|
||||
isize entry_prev;
|
||||
isize entry_index;
|
||||
};
|
||||
|
||||
enum HashKeyKind {
|
||||
HashKey_Default,
|
||||
HashKey_String,
|
||||
HashKey_Pointer,
|
||||
};
|
||||
|
||||
struct HashKey {
|
||||
HashKeyKind kind;
|
||||
// u128 key;
|
||||
u64 key;
|
||||
union {
|
||||
String string; // if String, s.len > 0
|
||||
void * ptr;
|
||||
};
|
||||
};
|
||||
|
||||
gb_inline HashKey hashing_proc(void const *data, isize len) {
|
||||
HashKey h = {HashKey_Default};
|
||||
h.kind = HashKey_Default;
|
||||
// h.key = u128_from_u64(gb_fnv64a(data, len));
|
||||
h.key = gb_fnv64a(data, len);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
gb_inline HashKey hash_string(String s) {
|
||||
HashKey h = hashing_proc(s.text, s.len);
|
||||
h.kind = HashKey_String;
|
||||
h.string = s;
|
||||
return h;
|
||||
}
|
||||
|
||||
gb_inline HashKey hash_pointer(void *ptr) {
|
||||
HashKey h = {HashKey_Default};
|
||||
// h.key = u128_from_u64(cast(u64)cast(uintptr)ptr);
|
||||
h.key = cast(u64)cast(uintptr)ptr;
|
||||
h.ptr = ptr;
|
||||
h.kind = HashKey_Default;
|
||||
return h;
|
||||
}
|
||||
|
||||
bool hash_key_equal(HashKey a, HashKey b) {
|
||||
if (a.key == b.key) {
|
||||
// NOTE(bill): If two string's hashes collide, compare the strings themselves
|
||||
if (a.kind == HashKey_String) {
|
||||
if (b.kind == HashKey_String) {
|
||||
return a.string == b.string;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool operator==(HashKey a, HashKey b) { return hash_key_equal(a, b); }
|
||||
bool operator!=(HashKey a, HashKey b) { return !hash_key_equal(a, b); }
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct MapEntry {
|
||||
HashKey key;
|
||||
isize next;
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Map {
|
||||
Array<isize> hashes;
|
||||
Array<MapEntry<T> > entries;
|
||||
};
|
||||
|
||||
|
||||
template <typename T> void map_init (Map<T> *h, gbAllocator a);
|
||||
template <typename T> void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity);
|
||||
template <typename T> void map_destroy (Map<T> *h);
|
||||
template <typename T> T * map_get (Map<T> *h, HashKey key);
|
||||
template <typename T> void map_set (Map<T> *h, HashKey key, T const &value);
|
||||
template <typename T> void map_remove (Map<T> *h, HashKey key);
|
||||
template <typename T> void map_clear (Map<T> *h);
|
||||
template <typename T> void map_grow (Map<T> *h);
|
||||
template <typename T> void map_rehash (Map<T> *h, isize new_count);
|
||||
|
||||
// Mutlivalued map procedure
|
||||
template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey key);
|
||||
template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
|
||||
|
||||
template <typename T> isize multi_map_count (Map<T> *h, HashKey key);
|
||||
template <typename T> void multi_map_get_all (Map<T> *h, HashKey key, T *items);
|
||||
template <typename T> void multi_map_insert (Map<T> *h, HashKey key, T const &value);
|
||||
template <typename T> void multi_map_remove (Map<T> *h, HashKey key, MapEntry<T> *e);
|
||||
template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key);
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_init(Map<T> *h, gbAllocator a) {
|
||||
array_init(&h->hashes, a);
|
||||
array_init(&h->entries, a);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_init_with_reserve(Map<T> *h, gbAllocator a, isize capacity) {
|
||||
array_init(&h->hashes, a, capacity);
|
||||
array_init(&h->entries, a, capacity);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_destroy(Map<T> *h) {
|
||||
array_free(&h->entries);
|
||||
array_free(&h->hashes);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
|
||||
MapEntry<T> e = {};
|
||||
e.key = key;
|
||||
e.next = -1;
|
||||
array_add(&h->entries, e);
|
||||
return h->entries.count-1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
|
||||
MapFindResult fr = {-1, -1, -1};
|
||||
if (h->hashes.count > 0) {
|
||||
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(h->hashes.count));
|
||||
fr.hash_index = key.key % h->hashes.count;
|
||||
fr.entry_index = h->hashes[fr.hash_index];
|
||||
while (fr.entry_index >= 0) {
|
||||
if (hash_key_equal(h->entries[fr.entry_index].key, key)) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = h->entries[fr.entry_index].next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal MapFindResult map__find_from_entry(Map<T> *h, MapEntry<T> *e) {
|
||||
MapFindResult fr = {-1, -1, -1};
|
||||
if (h->hashes.count > 0) {
|
||||
fr.hash_index = e->key.key % h->hashes.count;
|
||||
fr.entry_index = h->hashes[fr.hash_index];
|
||||
while (fr.entry_index >= 0) {
|
||||
if (&h->entries[fr.entry_index] == e) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = h->entries[fr.entry_index].next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal b32 map__full(Map<T> *h) {
|
||||
return 0.75f * h->hashes.count <= h->entries.count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_grow(Map<T> *h) {
|
||||
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
|
||||
map_rehash(h, new_count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void map_rehash(Map<T> *h, isize new_count) {
|
||||
isize i, j;
|
||||
Map<T> nh = {};
|
||||
map_init(&nh, h->hashes.allocator);
|
||||
array_resize(&nh.hashes, new_count);
|
||||
array_reserve(&nh.entries, h->entries.count);
|
||||
for (i = 0; i < new_count; i++) {
|
||||
nh.hashes[i] = -1;
|
||||
}
|
||||
for (i = 0; i < h->entries.count; i++) {
|
||||
MapEntry<T> *e = &h->entries[i];
|
||||
MapFindResult fr;
|
||||
if (nh.hashes.count == 0) {
|
||||
map_grow(&nh);
|
||||
}
|
||||
fr = map__find(&nh, e->key);
|
||||
j = map__add_entry(&nh, e->key);
|
||||
if (fr.entry_prev < 0) {
|
||||
nh.hashes[fr.hash_index] = j;
|
||||
} else {
|
||||
nh.entries[fr.entry_prev].next = j;
|
||||
}
|
||||
nh.entries[j].next = fr.entry_index;
|
||||
nh.entries[j].value = e->value;
|
||||
if (map__full(&nh)) {
|
||||
map_grow(&nh);
|
||||
}
|
||||
}
|
||||
map_destroy(h);
|
||||
*h = nh;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline T *map_get(Map<T> *h, HashKey key) {
|
||||
isize index = map__find(h, key).entry_index;
|
||||
if (index >= 0) {
|
||||
return &h->entries[index].value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void map_set(Map<T> *h, HashKey key, T const &value) {
|
||||
isize index;
|
||||
MapFindResult fr;
|
||||
if (h->hashes.count == 0)
|
||||
map_grow(h);
|
||||
fr = map__find(h, key);
|
||||
if (fr.entry_index >= 0) {
|
||||
index = fr.entry_index;
|
||||
} else {
|
||||
index = map__add_entry(h, key);
|
||||
if (fr.entry_prev >= 0) {
|
||||
h->entries[fr.entry_prev].next = index;
|
||||
} else {
|
||||
h->hashes[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
h->entries[index].value = value;
|
||||
|
||||
if (map__full(h)) {
|
||||
map_grow(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void map__erase(Map<T> *h, MapFindResult fr) {
|
||||
MapFindResult last;
|
||||
if (fr.entry_prev < 0) {
|
||||
h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
|
||||
} else {
|
||||
h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
|
||||
}
|
||||
if (fr.entry_index == h->entries.count-1) {
|
||||
array_pop(&h->entries);
|
||||
return;
|
||||
}
|
||||
h->entries[fr.entry_index] = h->entries[h->entries.count-1];
|
||||
last = map__find(h, h->entries[fr.entry_index].key);
|
||||
if (last.entry_prev >= 0) {
|
||||
h->entries[last.entry_prev].next = fr.entry_index;
|
||||
} else {
|
||||
h->hashes[last.hash_index] = fr.entry_index;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void map_remove(Map<T> *h, HashKey key) {
|
||||
MapFindResult fr = map__find(h, key);
|
||||
if (fr.entry_index >= 0) {
|
||||
map__erase(h, fr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_clear(Map<T> *h) {
|
||||
array_clear(&h->hashes);
|
||||
array_clear(&h->entries);
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
template <typename T>
|
||||
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
|
||||
isize i = map__find(h, key).entry_index;
|
||||
if (i < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &h->entries[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MapEntry<T> *multi_map_find_next(Map<T> *h, MapEntry<T> *e) {
|
||||
isize i = e->next;
|
||||
while (i >= 0) {
|
||||
if (hash_key_equal(h->entries[i].key, e->key)) {
|
||||
return &h->entries[i];
|
||||
}
|
||||
i = h->entries[i].next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
isize multi_map_count(Map<T> *h, HashKey key) {
|
||||
isize count = 0;
|
||||
MapEntry<T> *e = multi_map_find_first(h, key);
|
||||
while (e != NULL) {
|
||||
count++;
|
||||
e = multi_map_find_next(h, e);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void multi_map_get_all(Map<T> *h, HashKey key, T *items) {
|
||||
isize i = 0;
|
||||
MapEntry<T> *e = multi_map_find_first(h, key);
|
||||
while (e != NULL) {
|
||||
items[i++] = e->value;
|
||||
e = multi_map_find_next(h, e);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void multi_map_insert(Map<T> *h, HashKey key, T const &value) {
|
||||
MapFindResult fr;
|
||||
isize i;
|
||||
if (h->hashes.count == 0) {
|
||||
map_grow(h);
|
||||
}
|
||||
// Make
|
||||
fr = map__find(h, key);
|
||||
i = map__add_entry(h, key);
|
||||
if (fr.entry_prev < 0) {
|
||||
h->hashes[fr.hash_index] = i;
|
||||
} else {
|
||||
h->entries[fr.entry_prev].next = i;
|
||||
}
|
||||
h->entries[i].next = fr.entry_index;
|
||||
h->entries[i].value = value;
|
||||
// Grow if needed
|
||||
if (map__full(h)) {
|
||||
map_grow(h);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void multi_map_remove(Map<T> *h, HashKey key, MapEntry<T> *e) {
|
||||
MapFindResult fr = map__find_from_entry(h, e);
|
||||
if (fr.entry_index >= 0) {
|
||||
map__erase(h, fr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void multi_map_remove_all(Map<T> *h, HashKey key) {
|
||||
while (map_get(h, key) != NULL) {
|
||||
map_remove(h, key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -41,15 +41,15 @@ gb_inline u64 fmix64(u64 k) {
|
||||
return k;
|
||||
}
|
||||
|
||||
gb_inline u32 mm3_getblock32(u32 *const p, isize i) {
|
||||
gb_inline u32 mm3_getblock32(u32 const *p, isize i) {
|
||||
return p[i];
|
||||
}
|
||||
gb_inline u64 mm3_getblock64(u64 *const p, isize i) {
|
||||
gb_inline u64 mm3_getblock64(u64 const *p, isize i) {
|
||||
return p[i];
|
||||
}
|
||||
|
||||
u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
||||
u8 *const data = cast(u8 *const)key;
|
||||
void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) {
|
||||
u8 const * data = cast(u8 const *)key;
|
||||
isize nblocks = len / 16;
|
||||
|
||||
u64 h1 = seed;
|
||||
@@ -58,7 +58,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
||||
u64 const c1 = 0x87c37b91114253d5ULL;
|
||||
u64 const c2 = 0x4cf5ad432745937fULL;
|
||||
|
||||
u64 *const blocks = cast(u64 *const)data;
|
||||
u64 const * blocks = cast(u64 const *)data;
|
||||
|
||||
for (isize i = 0; i < nblocks; i++) {
|
||||
u64 k1 = mm3_getblock64(blocks, i*2 + 0);
|
||||
@@ -70,7 +70,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
||||
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||
}
|
||||
|
||||
u8 *const tail = cast(u8 *const)(data + nblocks*16);
|
||||
u8 const * tail = cast(u8 const *)(data + nblocks*16);
|
||||
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
@@ -108,11 +108,12 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
return u128_lo_hi(h1, h2);
|
||||
((u64 *)out)[0] = h1;
|
||||
((u64 *)out)[1] = h2;
|
||||
}
|
||||
|
||||
u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
||||
u8 *const data = cast(u8 * const)key;
|
||||
void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) {
|
||||
u8 const * data = cast(u8 * const)key;
|
||||
isize nblocks = len / 16;
|
||||
|
||||
u32 h1 = seed;
|
||||
@@ -128,7 +129,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
||||
//----------
|
||||
// body
|
||||
|
||||
u32 *const blocks = cast(u32 *const)(data + nblocks*16);
|
||||
u32 const * blocks = cast(u32 const *)(data + nblocks*16);
|
||||
|
||||
for (isize i = -nblocks; i != 0; i++) {
|
||||
u32 k1 = mm3_getblock32(blocks, i*4 + 0);
|
||||
@@ -156,7 +157,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
||||
//----------
|
||||
// tail
|
||||
|
||||
u8 *const tail = cast(u8 *const)(data + nblocks*16);
|
||||
u8 const * tail = cast(u8 const *)(data + nblocks*16);
|
||||
|
||||
u32 k1 = 0;
|
||||
u32 k2 = 0;
|
||||
@@ -204,17 +205,21 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
||||
h1 += h2; h1 += h3; h1 += h4;
|
||||
h2 += h1; h3 += h1; h4 += h1;
|
||||
|
||||
u64 lo = (u64)h1 | ((u64)h2 << 32);
|
||||
u64 hi = (u64)h3 | ((u64)h4 << 32);
|
||||
return u128_lo_hi(lo, hi);
|
||||
|
||||
((u32 *)out)[0] = h1;
|
||||
((u32 *)out)[1] = h2;
|
||||
((u32 *)out)[2] = h3;
|
||||
((u32 *)out)[3] = h4;
|
||||
}
|
||||
|
||||
gb_inline u128 MurmurHash3_128(void *const key, isize len, u32 seed) {
|
||||
gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
|
||||
u128 res;
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
return MurmurHash3_x64_128(key, len, seed);
|
||||
MurmurHash3_x64_128(key, len, seed, &res);
|
||||
#else
|
||||
return MurmurHash3_x86_128(key, len, seed);
|
||||
MurmurHash3_x86_128(key, len, seed, &res);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+279
-237
File diff suppressed because it is too large
Load Diff
+110
-109
@@ -1,27 +1,21 @@
|
||||
typedef struct ssaModule ssaModule;
|
||||
typedef struct ssaValue ssaValue;
|
||||
typedef struct ssaValueArgs ssaValueArgs;
|
||||
typedef struct ssaDefer ssaDefer;
|
||||
typedef struct ssaBlock ssaBlock;
|
||||
typedef struct ssaProc ssaProc;
|
||||
typedef struct ssaEdge ssaEdge;
|
||||
typedef struct ssaRegister ssaRegister;
|
||||
typedef struct ssaTargetList ssaTargetList;
|
||||
typedef enum ssaBlockKind ssaBlockKind;
|
||||
typedef enum ssaBranchPrediction ssaBranchPrediction;
|
||||
typedef enum ssaDeferExitKind ssaDeferExitKind;
|
||||
struct ssaModule;
|
||||
struct ssaValue;
|
||||
struct ssaValueArgs;
|
||||
struct ssaDefer;
|
||||
struct ssaBlock;
|
||||
struct ssaProc;
|
||||
struct ssaEdge;
|
||||
struct ssaRegister;
|
||||
struct ssaTargetList;
|
||||
enum ssaBlockKind;
|
||||
enum ssaBranchPrediction;
|
||||
enum ssaDeferExitKind;
|
||||
|
||||
|
||||
String ssa_mangle_name(ssaModule *m, String path, Entity *e);
|
||||
|
||||
#define MAP_TYPE ssaValue *
|
||||
#define MAP_PROC map_ssa_value_
|
||||
#define MAP_NAME MapSsaValue
|
||||
#include "map.c"
|
||||
|
||||
typedef Array(ssaValue *) ssaValueArray;
|
||||
|
||||
#include "ssa_op.c"
|
||||
#include "ssa_op.cpp"
|
||||
|
||||
#define SSA_DEFAULT_VALUE_ARG_CAPACITY 8
|
||||
struct ssaValueArgs {
|
||||
@@ -30,6 +24,15 @@ struct ssaValueArgs {
|
||||
isize capacity;
|
||||
ssaValue * backing[SSA_DEFAULT_VALUE_ARG_CAPACITY];
|
||||
gbAllocator allocator;
|
||||
|
||||
ssaValue *&operator[](isize i) {
|
||||
GB_ASSERT(0 <= i && i <= count);
|
||||
return e[i];
|
||||
}
|
||||
ssaValue * const &operator[](isize i) const {
|
||||
GB_ASSERT(0 <= i && i <= count);
|
||||
return e[i];
|
||||
}
|
||||
};
|
||||
|
||||
struct ssaValue {
|
||||
@@ -67,10 +70,10 @@ enum ssaBranchPrediction {
|
||||
ssaBranch_Unlikely = -1,
|
||||
};
|
||||
|
||||
typedef enum ssaDeferKind {
|
||||
enum ssaDeferKind {
|
||||
ssaDefer_Node,
|
||||
ssaDefer_Instr,
|
||||
} ssaDeferKind;
|
||||
};
|
||||
|
||||
struct ssaDefer {
|
||||
ssaDeferKind kind;
|
||||
@@ -97,8 +100,6 @@ struct ssaEdge {
|
||||
isize index;
|
||||
};
|
||||
|
||||
typedef Array(ssaEdge) ssaEdgeArray;
|
||||
|
||||
struct ssaBlock {
|
||||
i32 id; // Unique identifier but the pointer could be used too
|
||||
ssaBlockKind kind;
|
||||
@@ -115,9 +116,9 @@ struct ssaBlock {
|
||||
// - BlockExit will be a memory control value
|
||||
ssaValue *control;
|
||||
|
||||
ssaValueArray values;
|
||||
ssaEdgeArray preds;
|
||||
ssaEdgeArray succs;
|
||||
Array<ssaValue *> values;
|
||||
Array<ssaEdge> preds;
|
||||
Array<ssaEdge> succs;
|
||||
};
|
||||
|
||||
struct ssaTargetList {
|
||||
@@ -134,7 +135,7 @@ struct ssaProc {
|
||||
Entity * entity;
|
||||
DeclInfo * decl_info;
|
||||
|
||||
Array(ssaBlock *) blocks;
|
||||
Array<ssaBlock *> blocks;
|
||||
ssaBlock * entry; // Entry block
|
||||
ssaBlock * exit; // Exit block
|
||||
ssaBlock * curr_block;
|
||||
@@ -143,9 +144,9 @@ struct ssaProc {
|
||||
|
||||
i32 block_id;
|
||||
i32 value_id;
|
||||
MapSsaValue values; // Key: Entity *
|
||||
Map<ssaValue *> values; // Key: Entity *
|
||||
|
||||
Array(ssaDefer) defer_stmts;
|
||||
Array<ssaDefer> defer_stmts;
|
||||
i32 scope_level;
|
||||
};
|
||||
|
||||
@@ -161,10 +162,10 @@ struct ssaModule {
|
||||
gbAllocator tmp_allocator;
|
||||
gbArena tmp_arena;
|
||||
|
||||
MapEntity min_dep_map; // Key: Entity *
|
||||
MapSsaValue values; // Key: Entity *
|
||||
Map<Entity *> min_dep_map; // Key: Entity *
|
||||
Map<ssaValue *> values; // Key: Entity *
|
||||
// List of registers for the specific architecture
|
||||
Array(ssaRegister) registers;
|
||||
Array<ssaRegister> registers;
|
||||
|
||||
ssaProc *proc; // current procedure
|
||||
|
||||
@@ -172,19 +173,19 @@ struct ssaModule {
|
||||
|
||||
u32 stmt_state_flags;
|
||||
|
||||
Array(ssaProc *) procs;
|
||||
ssaValueArray procs_to_generate;
|
||||
Array<ssaProc *> procs;
|
||||
Array<ssaValue *> procs_to_generate;
|
||||
};
|
||||
|
||||
typedef enum ssaAddrKind {
|
||||
enum ssaAddrKind {
|
||||
ssaAddr_Default,
|
||||
ssaAddr_Map,
|
||||
} ssaAddrKind;
|
||||
};
|
||||
|
||||
typedef struct ssaAddr {
|
||||
struct ssaAddr {
|
||||
ssaValue * addr;
|
||||
ssaAddrKind kind;
|
||||
} ssaAddr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -287,7 +288,7 @@ void ssa_add_arg(ssaValueArgs *va, ssaValue *arg) {
|
||||
} else {
|
||||
isize old_cap_size = va->capacity * gb_size_of(ssaValue *);
|
||||
isize new_cap_size = capacity * gb_size_of(ssaValue *);
|
||||
va->e = gb_resize(va->allocator, va->e, old_cap_size, new_cap_size);
|
||||
*(cast(void **)&va->e) = gb_resize(va->allocator, va->e, old_cap_size, new_cap_size);
|
||||
}
|
||||
va->capacity = capacity;
|
||||
}
|
||||
@@ -378,9 +379,9 @@ ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa
|
||||
ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); }
|
||||
ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); }
|
||||
ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); }
|
||||
ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, (ExactValue){0}); }
|
||||
ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, empty_exact_value); }
|
||||
ssaValue *ssa_const_slice (ssaProc *p, Type *t, ExactValue v) { return ssa_const_val(p, ssaOp_ConstSlice, t, v); }
|
||||
ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, (ExactValue){0}); }
|
||||
ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, empty_exact_value); }
|
||||
|
||||
ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
|
||||
switch (8*type_size_of(p->allocator, t)) {
|
||||
@@ -399,21 +400,21 @@ ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
|
||||
ssaAddr ssa_build_addr (ssaProc *p, AstNode *expr);
|
||||
ssaValue *ssa_build_expr (ssaProc *p, AstNode *expr);
|
||||
void ssa_build_stmt (ssaProc *p, AstNode *node);
|
||||
void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes);
|
||||
void ssa_build_stmt_list(ssaProc *p, Array<AstNode *> nodes);
|
||||
ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel);
|
||||
|
||||
|
||||
|
||||
void ssa_reset_value_args(ssaValue *v) {
|
||||
for_array(i, v->args) {
|
||||
v->args.e[i]->uses--;
|
||||
v->args[i]->uses--;
|
||||
}
|
||||
v->args.count = 0;
|
||||
}
|
||||
|
||||
void ssa_reset(ssaValue *v, ssaOp op) {
|
||||
v->op = op;
|
||||
v->exact_value = (ExactValue){0};
|
||||
v->exact_value = empty_exact_value;
|
||||
ssa_reset_value_args(v);
|
||||
}
|
||||
|
||||
@@ -425,7 +426,7 @@ ssaValue *ssa_get_last_value(ssaBlock *b) {
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
ssaValue *v = b->values.e[len-1];
|
||||
ssaValue *v = b->values[len-1];
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -451,7 +452,7 @@ void ssa_build_defer_stmt(ssaProc *p, ssaDefer d) {
|
||||
void ssa_emit_defer_stmts(ssaProc *p, ssaDeferExitKind kind, ssaBlock *b) {
|
||||
isize count = p->defer_stmts.count;
|
||||
for (isize i = count-1; i >= 0; i--) {
|
||||
ssaDefer d = p->defer_stmts.e[i];
|
||||
ssaDefer d = p->defer_stmts[i];
|
||||
if (kind == ssaDeferExit_Default) {
|
||||
gb_printf_err("scope_level %d %d\n", p->scope_level, d.scope_level);
|
||||
if (p->scope_level == d.scope_level &&
|
||||
@@ -579,7 +580,7 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_
|
||||
|
||||
array_init(&p->blocks, heap_allocator());
|
||||
array_init(&p->defer_stmts, heap_allocator());
|
||||
map_ssa_value_init(&p->values, heap_allocator());
|
||||
map_init(&p->values, heap_allocator());
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -592,14 +593,14 @@ ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) {
|
||||
ssaValue *local = ssa_new_value0(p, ssaOp_Local, t);
|
||||
p->curr_block = cb;
|
||||
|
||||
map_ssa_value_set(&p->values, hash_pointer(e), local);
|
||||
map_ssa_value_set(&p->module->values, hash_pointer(e), local);
|
||||
map_set(&p->values, hash_pointer(e), local);
|
||||
map_set(&p->module->values, hash_pointer(e), local);
|
||||
local->comment_string = e->token.string;
|
||||
ssa_new_value1(p, ssaOp_Zero, t, local);
|
||||
return ssa_addr(local);
|
||||
}
|
||||
ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) {
|
||||
Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name));
|
||||
Entity **found = map_get(&p->module->info->definitions, hash_pointer(name));
|
||||
if (found) {
|
||||
Entity *e = *found;
|
||||
return ssa_add_local(p, e, name);
|
||||
@@ -705,7 +706,7 @@ ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) {
|
||||
Entity *parent = e->using_parent;
|
||||
Selection sel = lookup_field(p->allocator, parent->type, name, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
ssaValue **pv = map_ssa_value_get(&p->module->values, hash_pointer(parent));
|
||||
ssaValue **pv = map_get(&p->module->values, hash_pointer(parent));
|
||||
ssaValue *v = NULL;
|
||||
if (pv != NULL) {
|
||||
v = *pv;
|
||||
@@ -721,7 +722,7 @@ ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
|
||||
GB_ASSERT(e != NULL);
|
||||
|
||||
ssaValue *v = NULL;
|
||||
ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e));
|
||||
ssaValue **found = map_get(&p->module->values, hash_pointer(e));
|
||||
if (found) {
|
||||
v = *found;
|
||||
} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
|
||||
@@ -782,7 +783,7 @@ ssaValue *ssa_emit_conv(ssaProc *p, ssaValue *v, Type *t) {
|
||||
// NOTE(bill): Returns NULL if not possible
|
||||
ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
|
||||
if (v->op == ssaOp_Load) {
|
||||
return v->args.e[0];
|
||||
return v->args[0];
|
||||
}
|
||||
ssaAddr addr = ssa_add_local_generated(p, v->type);
|
||||
ssa_new_value2(p, ssaOp_Store, addr.addr->type, addr.addr, v);
|
||||
@@ -863,7 +864,7 @@ ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
|
||||
ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
|
||||
if (s->op == ssaOp_Load) {
|
||||
if (!can_ssa_type(s->type)) {
|
||||
ssaValue *e = ssa_emit_ptr_index(p, s->args.e[0], index);
|
||||
ssaValue *e = ssa_emit_ptr_index(p, s->args[0], index);
|
||||
return ssa_emit_load(p, e);
|
||||
}
|
||||
}
|
||||
@@ -930,7 +931,7 @@ ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel)
|
||||
Type *type = type_deref(e->type);
|
||||
|
||||
for_array(i, sel.index) {
|
||||
i32 index = cast(i32)sel.index.e[i];
|
||||
i32 index = cast(i32)sel.index[i];
|
||||
if (is_type_pointer(type)) {
|
||||
type = type_deref(type);
|
||||
e = ssa_emit_load(p, e);
|
||||
@@ -994,14 +995,14 @@ ssaValue *ssa_emit_deep_field_value_index(ssaProc *p, ssaValue *e, Selection sel
|
||||
Type *type = e->type;
|
||||
if (e->op == ssaOp_Load) {
|
||||
if (!can_ssa_type(e->type)) {
|
||||
ssaValue *ptr = ssa_emit_deep_field_ptr_index(p, e->args.e[0], sel);
|
||||
ssaValue *ptr = ssa_emit_deep_field_ptr_index(p, e->args[0], sel);
|
||||
return ssa_emit_load(p, ptr);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(can_ssa_type(e->type));
|
||||
|
||||
for_array(i, sel.index) {
|
||||
i32 index = cast(i32)sel.index.e[i];
|
||||
i32 index = cast(i32)sel.index[i];
|
||||
if (is_type_pointer(type)) {
|
||||
e = ssa_emit_load(p, e);
|
||||
}
|
||||
@@ -1071,7 +1072,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
|
||||
// GB_ASSERT(e->kind == Entity_Variable);
|
||||
// GB_ASSERT(e->flags & EntityFlag_TypeField);
|
||||
// String name = e->token.string;
|
||||
// if (str_eq(name, str_lit("names"))) {
|
||||
// if (name == "names") {
|
||||
// ssaValue *ti_ptr = ir_type_info(p, type);
|
||||
|
||||
// ssaValue *names_ptr = NULL;
|
||||
@@ -1685,7 +1686,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Ident, expr);
|
||||
Entity *e = *map_entity_get(&p->module->info->uses, hash_pointer(expr));
|
||||
Entity *e = *map_get(&p->module->info->uses, hash_pointer(expr));
|
||||
if (e->kind == Entity_Builtin) {
|
||||
Token token = ast_node_token(expr);
|
||||
GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n"
|
||||
@@ -1697,7 +1698,7 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e));
|
||||
ssaValue **found = map_get(&p->module->values, hash_pointer(e));
|
||||
if (found) {
|
||||
ssaValue *v = *found;
|
||||
if (v->op == ssaOp_Proc) {
|
||||
@@ -1835,9 +1836,9 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
|
||||
|
||||
case_ast_node(ce, CallExpr, expr);
|
||||
if (map_tav_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) {
|
||||
if (map_get(&p->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) {
|
||||
GB_ASSERT(ce->args.count == 1);
|
||||
ssaValue *x = ssa_build_expr(p, ce->args.e[0]);
|
||||
ssaValue *x = ssa_build_expr(p, ce->args[0]);
|
||||
return ssa_emit_conv(p, x, tv.type);
|
||||
}
|
||||
|
||||
@@ -1861,9 +1862,9 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
|
||||
|
||||
|
||||
|
||||
void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes) {
|
||||
void ssa_build_stmt_list(ssaProc *p, Array<AstNode *> nodes) {
|
||||
for_array(i, nodes) {
|
||||
ssa_build_stmt(p, nodes.e[i]);
|
||||
ssa_build_stmt(p, nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1946,7 +1947,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
|
||||
case_ast_node(us, UsingStmt, node);
|
||||
for_array(i, us->list) {
|
||||
AstNode *decl = unparen_expr(us->list.e[i]);
|
||||
AstNode *decl = unparen_expr(us->list[i]);
|
||||
if (decl->kind == AstNode_ValueDecl) {
|
||||
ssa_build_stmt(p, decl);
|
||||
}
|
||||
@@ -1973,19 +1974,19 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
||||
if (vd->values.count == 0) {
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
AstNode *name = vd->names[i];
|
||||
if (!ssa_is_blank_ident(name)) {
|
||||
ssa_add_local_for_ident(p, name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Array(ssaAddr) lvals = {0};
|
||||
ssaValueArray inits = {0};
|
||||
array_init_reserve(&lvals, m->tmp_allocator, vd->names.count);
|
||||
array_init_reserve(&inits, m->tmp_allocator, vd->names.count);
|
||||
Array<ssaAddr> lvals = {0};
|
||||
Array<ssaValue *> inits = {0};
|
||||
array_init(&lvals, m->tmp_allocator, vd->names.count);
|
||||
array_init(&inits, m->tmp_allocator, vd->names.count);
|
||||
|
||||
for_array(i, vd->names) {
|
||||
AstNode *name = vd->names.e[i];
|
||||
AstNode *name = vd->names[i];
|
||||
ssaAddr lval = ssa_addr(NULL);
|
||||
if (!ssa_is_blank_ident(name)) {
|
||||
lval = ssa_add_local_for_ident(p, name);
|
||||
@@ -1995,7 +1996,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
}
|
||||
|
||||
for_array(i, vd->values) {
|
||||
ssaValue *init = ssa_build_expr(p, vd->values.e[i]);
|
||||
ssaValue *init = ssa_build_expr(p, vd->values[i]);
|
||||
if (init == NULL) { // TODO(bill): remove this
|
||||
continue;
|
||||
}
|
||||
@@ -2012,7 +2013,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
}
|
||||
|
||||
for_array(i, inits) {
|
||||
ssa_addr_store(p, lvals.e[i], inits.e[i]);
|
||||
ssa_addr_store(p, lvals[i], inits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2030,11 +2031,11 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
|
||||
switch (as->op.kind) {
|
||||
case Token_Eq: {
|
||||
Array(ssaAddr) lvals = {0};
|
||||
Array<ssaAddr> lvals = {0};
|
||||
array_init(&lvals, m->tmp_allocator);
|
||||
|
||||
for_array(i, as->lhs) {
|
||||
AstNode *lhs = as->lhs.e[i];
|
||||
AstNode *lhs = as->lhs[i];
|
||||
ssaAddr lval = {0};
|
||||
if (!ssa_is_blank_ident(lhs)) {
|
||||
lval = ssa_build_addr(p, lhs);
|
||||
@@ -2044,28 +2045,28 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
|
||||
if (as->lhs.count == as->rhs.count) {
|
||||
if (as->lhs.count == 1) {
|
||||
AstNode *rhs = as->rhs.e[0];
|
||||
AstNode *rhs = as->rhs[0];
|
||||
ssaValue *init = ssa_build_expr(p, rhs);
|
||||
ssa_addr_store(p, lvals.e[0], init);
|
||||
ssa_addr_store(p, lvals[0], init);
|
||||
} else {
|
||||
ssaValueArray inits;
|
||||
array_init_reserve(&inits, m->tmp_allocator, lvals.count);
|
||||
Array<ssaValue *> inits;
|
||||
array_init(&inits, m->tmp_allocator, lvals.count);
|
||||
|
||||
for_array(i, as->rhs) {
|
||||
ssaValue *init = ssa_build_expr(p, as->rhs.e[i]);
|
||||
ssaValue *init = ssa_build_expr(p, as->rhs[i]);
|
||||
array_add(&inits, init);
|
||||
}
|
||||
|
||||
for_array(i, inits) {
|
||||
ssa_addr_store(p, lvals.e[i], inits.e[i]);
|
||||
ssa_addr_store(p, lvals[i], inits[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ssaValueArray inits;
|
||||
array_init_reserve(&inits, m->tmp_allocator, lvals.count);
|
||||
Array<ssaValue *> inits;
|
||||
array_init(&inits, m->tmp_allocator, lvals.count);
|
||||
|
||||
for_array(i, as->rhs) {
|
||||
ssaValue *init = ssa_build_expr(p, as->rhs.e[i]);
|
||||
ssaValue *init = ssa_build_expr(p, as->rhs[i]);
|
||||
Type *t = base_type(init->type);
|
||||
// TODO(bill): refactor for code reuse as this is repeated a bit
|
||||
if (t->kind == Type_Tuple) {
|
||||
@@ -2080,7 +2081,7 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
}
|
||||
|
||||
for_array(i, inits) {
|
||||
ssa_addr_store(p, lvals.e[i], inits.e[i]);
|
||||
ssa_addr_store(p, lvals[i], inits[i]);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -2091,8 +2092,8 @@ void ssa_build_stmt_internal(ssaProc *p, AstNode *node) {
|
||||
// +=, -=, etc
|
||||
i32 op = cast(i32)as->op.kind;
|
||||
op += Token_Add - Token_AddEq; // Convert += to +
|
||||
ssaAddr lhs = ssa_build_addr(p, as->lhs.e[0]);
|
||||
ssaValue *value = ssa_build_expr(p, as->rhs.e[0]);
|
||||
ssaAddr lhs = ssa_build_addr(p, as->lhs[0]);
|
||||
ssaValue *value = ssa_build_expr(p, as->rhs[0]);
|
||||
ssa_build_assign_op(p, lhs, value, cast(TokenKind)op);
|
||||
} break;
|
||||
}
|
||||
@@ -2316,7 +2317,7 @@ void ssa_print_reg_value(gbFile *f, ssaValue *v) {
|
||||
|
||||
for_array(i, v->args) {
|
||||
gb_fprintf(f, " ");
|
||||
ssa_print_value(f, v->args.e[i]);
|
||||
ssa_print_value(f, v->args[i]);
|
||||
}
|
||||
|
||||
if (v->comment_string.len > 0) {
|
||||
@@ -2335,12 +2336,12 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
|
||||
bool *printed = gb_alloc_array(heap_allocator(), bool, p->value_id+1);
|
||||
|
||||
for_array(i, p->blocks) {
|
||||
ssaBlock *b = p->blocks.e[i];
|
||||
ssaBlock *b = p->blocks[i];
|
||||
gb_fprintf(f, " b%d:", b->id);
|
||||
if (b->preds.count > 0) {
|
||||
gb_fprintf(f, " <-");
|
||||
for_array(j, b->preds) {
|
||||
ssaBlock *pred = b->preds.e[j].block;
|
||||
ssaBlock *pred = b->preds[j].block;
|
||||
gb_fprintf(f, " b%d", pred->id);
|
||||
}
|
||||
}
|
||||
@@ -2351,7 +2352,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
|
||||
|
||||
isize n = 0;
|
||||
for_array(j, b->values) {
|
||||
ssaValue *v = b->values.e[j];
|
||||
ssaValue *v = b->values[j];
|
||||
if (v->op != ssaOp_Phi) {
|
||||
continue;
|
||||
}
|
||||
@@ -2363,13 +2364,13 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
|
||||
while (n < b->values.count) {
|
||||
isize m = 0;
|
||||
for_array(j, b->values) {
|
||||
ssaValue *v = b->values.e[j];
|
||||
ssaValue *v = b->values[j];
|
||||
if (printed[v->id]) {
|
||||
continue;
|
||||
}
|
||||
bool skip = false;
|
||||
for_array(k, v->args) {
|
||||
ssaValue *w = v->args.e[k];
|
||||
ssaValue *w = v->args[k];
|
||||
if (w != NULL && w->block == b && !printed[w->id]) {
|
||||
skip = true;
|
||||
break;
|
||||
@@ -2387,7 +2388,7 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
|
||||
if (m == n) {
|
||||
gb_fprintf(f, "!!!!DepCycle!!!!\n");
|
||||
for_array(k, b->values) {
|
||||
ssaValue *v = b->values.e[k];
|
||||
ssaValue *v = b->values[k];
|
||||
if (printed[v->id]) {
|
||||
continue;
|
||||
}
|
||||
@@ -2401,14 +2402,14 @@ void ssa_print_proc(gbFile *f, ssaProc *p) {
|
||||
|
||||
if (b->kind == ssaBlock_Plain) {
|
||||
GB_ASSERT(b->succs.count == 1);
|
||||
ssaBlock *next = b->succs.e[0].block;
|
||||
ssaBlock *next = b->succs[0].block;
|
||||
gb_fprintf(f, " ");
|
||||
gb_fprintf(f, "jump b%d", next->id);
|
||||
gb_fprintf(f, "\n");
|
||||
} else if (b->kind == ssaBlock_If) {
|
||||
GB_ASSERT(b->succs.count == 2);
|
||||
ssaBlock *yes = b->succs.e[0].block;
|
||||
ssaBlock *no = b->succs.e[1].block;
|
||||
ssaBlock *yes = b->succs[0].block;
|
||||
ssaBlock *no = b->succs[1].block;
|
||||
gb_fprintf(f, " ");
|
||||
gb_fprintf(f, "branch v%d, b%d, b%d", b->control->id, yes->id, no->id);
|
||||
gb_fprintf(f, "\n");
|
||||
@@ -2479,7 +2480,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
m.tmp_allocator = gb_arena_allocator(&m.tmp_arena);
|
||||
m.allocator = gb_arena_allocator(&m.arena);
|
||||
|
||||
map_ssa_value_init(&m.values, heap_allocator());
|
||||
map_init(&m.values, heap_allocator());
|
||||
array_init(&m.registers, heap_allocator());
|
||||
array_init(&m.procs, heap_allocator());
|
||||
array_init(&m.procs_to_generate, heap_allocator());
|
||||
@@ -2491,21 +2492,21 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
bool has_win_main = false;
|
||||
|
||||
for_array(i, info->entities.entries) {
|
||||
MapDeclInfoEntry *entry = &info->entities.entries.e[i];
|
||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
||||
auto *entry = &info->entities.entries[i];
|
||||
Entity *e = cast(Entity *)entry->key.ptr;
|
||||
String name = e->token.string;
|
||||
if (e->kind == Entity_Variable) {
|
||||
global_variable_max_count++;
|
||||
} else if (e->kind == Entity_Procedure && !e->scope->is_global) {
|
||||
if (e->scope->is_init && str_eq(name, str_lit("main"))) {
|
||||
if (e->scope->is_init && name == "main") {
|
||||
entry_point = e;
|
||||
}
|
||||
if ((e->Procedure.tags & ProcTag_export) != 0 ||
|
||||
(e->Procedure.link_name.len > 0) ||
|
||||
(e->scope->is_file && e->Procedure.link_name.len > 0)) {
|
||||
if (!has_dll_main && str_eq(name, str_lit("DllMain"))) {
|
||||
if (!has_dll_main && name == "DllMain") {
|
||||
has_dll_main = true;
|
||||
} else if (!has_win_main && str_eq(name, str_lit("WinMain"))) {
|
||||
} else if (!has_win_main && name == "WinMain") {
|
||||
has_win_main = true;
|
||||
}
|
||||
}
|
||||
@@ -2517,7 +2518,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
m.min_dep_map = generate_minimum_dependency_map(info, entry_point);
|
||||
|
||||
for_array(i, info->entities.entries) {
|
||||
MapDeclInfoEntry *entry = &info->entities.entries.e[i];
|
||||
auto *entry = &info->entities.entries[i];
|
||||
Entity *e = cast(Entity *)entry->key.ptr;
|
||||
String name = e->token.string;
|
||||
DeclInfo *decl = entry->value;
|
||||
@@ -2527,7 +2528,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (map_entity_get(&m.min_dep_map, hash_pointer(e)) == NULL) {
|
||||
if (map_get(&m.min_dep_map, hash_pointer(e)) == NULL) {
|
||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
continue;
|
||||
}
|
||||
@@ -2536,7 +2537,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
|
||||
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
|
||||
// Handle later
|
||||
} else if (scope->is_init && e->kind == Entity_Procedure && str_eq(name, str_lit("main"))) {
|
||||
} else if (scope->is_init && e->kind == Entity_Procedure && name == "main") {
|
||||
} else {
|
||||
name = ssa_mangle_name(&m, e->token.pos.file, e);
|
||||
}
|
||||
@@ -2574,8 +2575,8 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
||||
|
||||
// ssa_module_add_value(m, e, p);
|
||||
// HashKey hash_name = hash_string(name);
|
||||
// if (map_ssa_value_get(&m.members, hash_name) == NULL) {
|
||||
// map_ssa_value_set(&m.members, hash_name, p);
|
||||
// if (map_get(&m.members, hash_name) == NULL) {
|
||||
// map_set(&m.members, hash_name, p);
|
||||
// }
|
||||
} break;
|
||||
}
|
||||
@@ -2595,7 +2596,7 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e) {
|
||||
String name = e->token.string;
|
||||
CheckerInfo *info = m->info;
|
||||
gbAllocator a = m->allocator;
|
||||
AstFile *file = *map_ast_file_get(&info->files, hash_string(path));
|
||||
AstFile *file = *map_get(&info->files, hash_string(path));
|
||||
|
||||
char *str = gb_alloc_array(a, char, path.len+1);
|
||||
gb_memmove(str, path.text, path.len);
|
||||
@@ -267,7 +267,6 @@ enum ssaOp {
|
||||
SSA_OPS
|
||||
#undef SSA_OP
|
||||
};
|
||||
typedef enum ssaOp ssaOp;
|
||||
|
||||
String const ssa_op_strings[] = {
|
||||
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
||||
@@ -1,5 +1,5 @@
|
||||
gb_global gbArena string_buffer_arena = {0};
|
||||
gb_global gbAllocator string_buffer_allocator = {0};
|
||||
gb_global gbArena string_buffer_arena = {};
|
||||
gb_global gbAllocator string_buffer_allocator = {};
|
||||
|
||||
void init_string_buffer_memory(void) {
|
||||
// NOTE(bill): This should be enough memory for file systems
|
||||
@@ -9,21 +9,38 @@ void init_string_buffer_memory(void) {
|
||||
|
||||
|
||||
// NOTE(bill): Used for UTF-8 strings
|
||||
typedef struct String {
|
||||
struct String {
|
||||
u8 * text;
|
||||
isize len;
|
||||
} String;
|
||||
|
||||
u8 &operator[](isize i) {
|
||||
GB_ASSERT(0 <= i && i < len);
|
||||
return text[i];
|
||||
}
|
||||
u8 const &operator[](isize i) const {
|
||||
GB_ASSERT(0 <= i && i < len);
|
||||
return text[i];
|
||||
}
|
||||
};
|
||||
// NOTE(bill): used for printf style arguments
|
||||
#define LIT(x) ((int)(x).len), (x).text
|
||||
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
|
||||
#define str_lit(c_str) (String){cast(u8 *)c_str, gb_size_of(c_str)-1}
|
||||
#define str_lit(c_str) String{cast(u8 *)c_str, gb_size_of(c_str)-1}
|
||||
|
||||
|
||||
// NOTE(bill): String16 is only used for Windows due to its file directories
|
||||
typedef struct String16 {
|
||||
struct String16 {
|
||||
wchar_t *text;
|
||||
isize len;
|
||||
} String16;
|
||||
wchar_t &operator[](isize i) {
|
||||
GB_ASSERT(0 <= i && i < len);
|
||||
return text[i];
|
||||
}
|
||||
wchar_t const &operator[](isize i) const {
|
||||
GB_ASSERT(0 <= i && i < len);
|
||||
return text[i];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
gb_inline String make_string(u8 *text, isize len) {
|
||||
@@ -56,8 +73,8 @@ gb_inline bool str_eq_ignore_case(String a, String b) {
|
||||
if (a.len == b.len) {
|
||||
isize i;
|
||||
for (i = 0; i < a.len; i++) {
|
||||
char x = cast(char)a.text[i];
|
||||
char y = cast(char)b.text[i];
|
||||
char x = cast(char)a[i];
|
||||
char y = cast(char)b[i];
|
||||
if (gb_char_to_lower(x) != gb_char_to_lower(y))
|
||||
return false;
|
||||
}
|
||||
@@ -88,16 +105,16 @@ int string_compare(String x, String y) {
|
||||
for (; curr_block < fast; curr_block++) {
|
||||
if (la[curr_block] ^ lb[curr_block]) {
|
||||
for (pos = curr_block*gb_size_of(isize); pos < n; pos++) {
|
||||
if (x.text[pos] ^ y.text[pos]) {
|
||||
return cast(int)x.text[pos] - cast(int)y.text[pos];
|
||||
if (x[pos] ^ y[pos]) {
|
||||
return cast(int)x[pos] - cast(int)y[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; offset < n; offset++) {
|
||||
if (x.text[offset] ^ y.text[offset]) {
|
||||
return cast(int)x.text[offset] - cast(int)y.text[offset];
|
||||
if (x[offset] ^ y[offset]) {
|
||||
return cast(int)x[offset] - cast(int)y[offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,13 +134,29 @@ gb_inline bool str_gt(String a, String b) { return string_compare(a, b) > 0;
|
||||
gb_inline bool str_le(String a, String b) { return string_compare(a, b) <= 0; }
|
||||
gb_inline bool str_ge(String a, String b) { return string_compare(a, b) >= 0; }
|
||||
|
||||
bool operator == (String a, String b) { return str_eq(a, b); }
|
||||
bool operator != (String a, String b) { return str_ne(a, b); }
|
||||
bool operator < (String a, String b) { return str_lt(a, b); }
|
||||
bool operator > (String a, String b) { return str_gt(a, b); }
|
||||
bool operator <= (String a, String b) { return str_le(a, b); }
|
||||
bool operator >= (String a, String b) { return str_ge(a, b); }
|
||||
|
||||
template <isize N> bool operator == (String a, char const (&b)[N]) { return str_eq(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator != (String a, char const (&b)[N]) { return str_ne(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator < (String a, char const (&b)[N]) { return str_lt(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator > (String a, char const (&b)[N]) { return str_gt(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator <= (String a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
|
||||
template <isize N> bool operator >= (String a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
|
||||
|
||||
|
||||
|
||||
gb_inline bool str_has_prefix(String s, String prefix) {
|
||||
isize i;
|
||||
if (prefix.len < s.len) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < prefix.len; i++) {
|
||||
if (s.text[i] != prefix.text[i]) {
|
||||
if (s[i] != prefix[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -135,9 +168,9 @@ gb_inline isize string_extension_position(String str) {
|
||||
isize i = str.len;
|
||||
bool seen_dot = false;
|
||||
while (i --> 0) {
|
||||
if (str.text[i] == GB_PATH_SEPARATOR)
|
||||
if (str[i] == GB_PATH_SEPARATOR)
|
||||
break;
|
||||
if (str.text[i] == '.') {
|
||||
if (str[i] == '.') {
|
||||
dot_pos = i;
|
||||
break;
|
||||
}
|
||||
@@ -147,11 +180,11 @@ gb_inline isize string_extension_position(String str) {
|
||||
}
|
||||
|
||||
String string_trim_whitespace(String str) {
|
||||
while (str.len > 0 && rune_is_whitespace(str.text[str.len-1])) {
|
||||
while (str.len > 0 && rune_is_whitespace(str[str.len-1])) {
|
||||
str.len--;
|
||||
}
|
||||
|
||||
while (str.len > 0 && rune_is_whitespace(str.text[0])) {
|
||||
while (str.len > 0 && rune_is_whitespace(str[0])) {
|
||||
str.text++;
|
||||
str.len--;
|
||||
}
|
||||
@@ -166,7 +199,7 @@ gb_inline bool string_has_extension(String str, String ext) {
|
||||
}
|
||||
isize len = str.len;
|
||||
for (isize i = len-1; i >= 0; i--) {
|
||||
if (str.text[i] == '.') {
|
||||
if (str[i] == '.') {
|
||||
break;
|
||||
}
|
||||
len--;
|
||||
@@ -182,7 +215,7 @@ gb_inline bool string_has_extension(String str, String ext) {
|
||||
bool string_contains_char(String s, u8 c) {
|
||||
isize i;
|
||||
for (i = 0; i < s.len; i++) {
|
||||
if (s.text[i] == c)
|
||||
if (s[i] == c)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -194,8 +227,8 @@ String filename_from_path(String s) {
|
||||
isize j = 0;
|
||||
s.len = i;
|
||||
for (j = i-1; j >= 0; j--) {
|
||||
if (s.text[j] == '/' ||
|
||||
s.text[j] == '\\') {
|
||||
if (s[j] == '/' ||
|
||||
s[j] == '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -315,18 +348,18 @@ String string16_to_string(gbAllocator a, String16 s) {
|
||||
bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
|
||||
u8 c;
|
||||
|
||||
if (s.text[0] == quote &&
|
||||
if (s[0] == quote &&
|
||||
(quote == '\'' || quote == '"')) {
|
||||
return false;
|
||||
} else if (s.text[0] >= 0x80) {
|
||||
} else if (s[0] >= 0x80) {
|
||||
Rune r = -1;
|
||||
isize size = gb_utf8_decode(s.text, s.len, &r);
|
||||
*rune = r;
|
||||
*multiple_bytes = true;
|
||||
*tail_string = make_string(s.text+size, s.len-size);
|
||||
return true;
|
||||
} else if (s.text[0] != '\\') {
|
||||
*rune = s.text[0];
|
||||
} else if (s[0] != '\\') {
|
||||
*rune = s[0];
|
||||
*tail_string = make_string(s.text+1, s.len-1);
|
||||
return true;
|
||||
}
|
||||
@@ -334,7 +367,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
|
||||
if (s.len <= 1) {
|
||||
return false;
|
||||
}
|
||||
c = s.text[1];
|
||||
c = s[1];
|
||||
s = make_string(s.text+2, s.len-2);
|
||||
|
||||
switch (c) {
|
||||
@@ -372,7 +405,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
i32 d = gb_digit_to_int(s.text[i]);
|
||||
i32 d = gb_digit_to_int(s[i]);
|
||||
if (d < 0 || d > 7) {
|
||||
return false;
|
||||
}
|
||||
@@ -400,7 +433,7 @@ bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
i32 d = gb_hex_digit_to_int(s.text[i]);
|
||||
i32 d = gb_hex_digit_to_int(s[i]);
|
||||
if (d < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -433,8 +466,8 @@ i32 unquote_string(gbAllocator a, String *s_) {
|
||||
if (n < 2) {
|
||||
return 0;
|
||||
}
|
||||
quote = s.text[0];
|
||||
if (quote != s.text[n-1]) {
|
||||
quote = s[0];
|
||||
if (quote != s[n-1]) {
|
||||
return 0;
|
||||
}
|
||||
s.text += 1;
|
||||
@@ -471,12 +504,12 @@ i32 unquote_string(gbAllocator a, String *s_) {
|
||||
|
||||
|
||||
{
|
||||
u8 rune_temp[4] = {0};
|
||||
u8 rune_temp[4] = {};
|
||||
isize buf_len = 3*s.len / 2;
|
||||
u8 *buf = gb_alloc_array(a, u8, buf_len);
|
||||
isize offset = 0;
|
||||
while (s.len > 0) {
|
||||
String tail_string = {0};
|
||||
String tail_string = {};
|
||||
Rune r = 0;
|
||||
bool multiple_bytes = false;
|
||||
bool success = unquote_char(s, quote, &r, &multiple_bytes, &tail_string);
|
||||
@@ -1,14 +1,14 @@
|
||||
typedef struct TimeStamp {
|
||||
struct TimeStamp {
|
||||
u64 start;
|
||||
u64 finish;
|
||||
String label;
|
||||
} TimeStamp;
|
||||
};
|
||||
|
||||
typedef struct Timings {
|
||||
struct Timings {
|
||||
TimeStamp total;
|
||||
Array(TimeStamp) sections;
|
||||
Array<TimeStamp> sections;
|
||||
u64 freq;
|
||||
} Timings;
|
||||
};
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -83,7 +83,7 @@ TimeStamp make_time_stamp(String label) {
|
||||
}
|
||||
|
||||
void timings_init(Timings *t, String label, isize buffer_size) {
|
||||
array_init_reserve(&t->sections, heap_allocator(), buffer_size);
|
||||
array_init(&t->sections, heap_allocator(), buffer_size);
|
||||
t->total = make_time_stamp(label);
|
||||
t->freq = time_stamp__freq();
|
||||
}
|
||||
@@ -94,7 +94,7 @@ void timings_destroy(Timings *t) {
|
||||
|
||||
void timings__stop_current_section(Timings *t) {
|
||||
if (t->sections.count > 0) {
|
||||
t->sections.e[t->sections.count-1].finish = time_stamp_time_now();
|
||||
t->sections[t->sections.count-1].finish = time_stamp_time_now();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,14 +110,14 @@ f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
|
||||
|
||||
void timings_print_all(Timings *t) {
|
||||
char const SPACES[] = " ";
|
||||
isize max_len, i;
|
||||
isize max_len;
|
||||
|
||||
timings__stop_current_section(t);
|
||||
t->total.finish = time_stamp_time_now();
|
||||
|
||||
max_len = t->total.label.len;
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections.e[i];
|
||||
TimeStamp ts = t->sections[i];
|
||||
max_len = gb_max(max_len, ts.label.len);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ void timings_print_all(Timings *t) {
|
||||
time_stamp_as_ms(t->total, t->freq));
|
||||
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections.e[i];
|
||||
TimeStamp ts = t->sections[i];
|
||||
gb_printf("%.*s%.*s - %.3f ms\n",
|
||||
LIT(ts.label),
|
||||
cast(int)(max_len-ts.label.len), SPACES,
|
||||
@@ -117,11 +117,11 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
||||
TOKEN_KIND(Token_Count, "")
|
||||
|
||||
typedef enum TokenKind {
|
||||
enum TokenKind {
|
||||
#define TOKEN_KIND(e, s) e
|
||||
TOKEN_KINDS
|
||||
#undef TOKEN_KIND
|
||||
} TokenKind;
|
||||
};
|
||||
|
||||
String const token_strings[] = {
|
||||
#define TOKEN_KIND(e, s) {cast(u8 *)s, gb_size_of(s)-1}
|
||||
@@ -130,11 +130,11 @@ String const token_strings[] = {
|
||||
};
|
||||
|
||||
|
||||
typedef struct TokenPos {
|
||||
struct TokenPos {
|
||||
String file;
|
||||
isize line;
|
||||
isize column;
|
||||
} TokenPos;
|
||||
};
|
||||
|
||||
i32 token_pos_cmp(TokenPos a, TokenPos b) {
|
||||
if (a.line == b.line) {
|
||||
@@ -152,11 +152,11 @@ bool token_pos_eq(TokenPos a, TokenPos b) {
|
||||
return token_pos_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
typedef struct Token {
|
||||
struct Token {
|
||||
TokenKind kind;
|
||||
String string;
|
||||
TokenPos pos;
|
||||
} Token;
|
||||
};
|
||||
|
||||
Token empty_token = {Token_Invalid};
|
||||
Token blank_token = {Token_Ident, {cast(u8 *)"_", 1}};
|
||||
@@ -167,12 +167,12 @@ Token make_token_ident(String s) {
|
||||
}
|
||||
|
||||
|
||||
typedef struct ErrorCollector {
|
||||
struct ErrorCollector {
|
||||
TokenPos prev;
|
||||
i64 count;
|
||||
i64 warning_count;
|
||||
gbMutex mutex;
|
||||
} ErrorCollector;
|
||||
};
|
||||
|
||||
gb_global ErrorCollector global_error_collector;
|
||||
|
||||
@@ -306,7 +306,7 @@ gb_inline bool token_is_shift(TokenKind t) {
|
||||
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
|
||||
|
||||
|
||||
typedef enum TokenizerInitError {
|
||||
enum TokenizerInitError {
|
||||
TokenizerInit_None,
|
||||
|
||||
TokenizerInit_Invalid,
|
||||
@@ -315,18 +315,18 @@ typedef enum TokenizerInitError {
|
||||
TokenizerInit_Empty,
|
||||
|
||||
TokenizerInit_Count,
|
||||
} TokenizerInitError;
|
||||
};
|
||||
|
||||
|
||||
typedef struct TokenizerState {
|
||||
struct TokenizerState {
|
||||
Rune curr_rune; // current character
|
||||
u8 * curr; // character pos
|
||||
u8 * read_curr; // pos from start
|
||||
u8 * line; // current line pos
|
||||
isize line_count;
|
||||
} TokenizerState;
|
||||
};
|
||||
|
||||
typedef struct Tokenizer {
|
||||
struct Tokenizer {
|
||||
String fullpath;
|
||||
u8 *start;
|
||||
u8 *end;
|
||||
@@ -338,12 +338,12 @@ typedef struct Tokenizer {
|
||||
isize line_count;
|
||||
|
||||
isize error_count;
|
||||
Array(String) allocated_strings;
|
||||
} Tokenizer;
|
||||
Array<String> allocated_strings;
|
||||
};
|
||||
|
||||
|
||||
TokenizerState save_tokenizer_state(Tokenizer *t) {
|
||||
TokenizerState state = {0};
|
||||
TokenizerState state = {};
|
||||
state.curr_rune = t->curr_rune;
|
||||
state.curr = t->curr;
|
||||
state.read_curr = t->read_curr;
|
||||
@@ -435,7 +435,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
||||
|
||||
array_init(&t->allocated_strings, heap_allocator());
|
||||
} else {
|
||||
gbFile f = {0};
|
||||
gbFile f = {};
|
||||
gbFileError file_err = gb_file_open(&f, c_str);
|
||||
|
||||
switch (file_err) {
|
||||
@@ -460,7 +460,7 @@ gb_inline void destroy_tokenizer(Tokenizer *t) {
|
||||
gb_free(heap_allocator(), t->start);
|
||||
}
|
||||
for_array(i, t->allocated_strings) {
|
||||
gb_free(heap_allocator(), t->allocated_strings.e[i].text);
|
||||
gb_free(heap_allocator(), t->allocated_strings[i].text);
|
||||
}
|
||||
array_free(&t->allocated_strings);
|
||||
}
|
||||
@@ -492,7 +492,7 @@ gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
|
||||
}
|
||||
|
||||
Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
Token token = {0};
|
||||
Token token = {};
|
||||
token.kind = Token_Integer;
|
||||
token.string = make_string(t->curr, 1);
|
||||
token.pos.file = t->fullpath;
|
||||
@@ -742,7 +742,7 @@ bool tokenizer_find_line_end(Tokenizer *t) {
|
||||
Token tokenizer_get_token(Tokenizer *t) {
|
||||
tokenizer_skip_whitespace(t);
|
||||
|
||||
Token token = {0};
|
||||
Token token = {};
|
||||
token.string = make_string(t->curr, 1);
|
||||
token.pos.file = t->fullpath;
|
||||
token.pos.line = t->line_count;
|
||||
@@ -760,7 +760,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
// NOTE(bill): All keywords are > 1
|
||||
if (token.string.len > 1) {
|
||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||
if (str_eq(token.string, token_strings[k])) {
|
||||
if (token.string == token_strings[k]) {
|
||||
token.kind = cast(TokenKind)k;
|
||||
break;
|
||||
}
|
||||
@@ -963,7 +963,7 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
|
||||
default:
|
||||
if (curr_rune != GB_RUNE_BOM) {
|
||||
u8 str[4] = {0};
|
||||
u8 str[4] = {};
|
||||
int len = cast(int)gb_utf8_encode_rune(str, curr_rune);
|
||||
tokenizer_err(t, "Illegal character: %.*s (%d) ", len, str, curr_rune);
|
||||
}
|
||||
+55
-55
@@ -1,6 +1,6 @@
|
||||
typedef struct Scope Scope;
|
||||
struct Scope;
|
||||
|
||||
typedef enum BasicKind {
|
||||
enum BasicKind {
|
||||
Basic_Invalid,
|
||||
Basic_bool,
|
||||
Basic_i8,
|
||||
@@ -41,9 +41,9 @@ typedef enum BasicKind {
|
||||
Basic_COUNT,
|
||||
|
||||
Basic_byte = Basic_u8,
|
||||
} BasicKind;
|
||||
};
|
||||
|
||||
typedef enum BasicFlag {
|
||||
enum BasicFlag {
|
||||
BasicFlag_Boolean = GB_BIT(0),
|
||||
BasicFlag_Integer = GB_BIT(1),
|
||||
BasicFlag_Unsigned = GB_BIT(2),
|
||||
@@ -57,16 +57,16 @@ typedef enum BasicFlag {
|
||||
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex,
|
||||
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
||||
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
||||
} BasicFlag;
|
||||
};
|
||||
|
||||
typedef struct BasicType {
|
||||
struct BasicType {
|
||||
BasicKind kind;
|
||||
u32 flags;
|
||||
i64 size; // -1 if arch. dep.
|
||||
String name;
|
||||
} BasicType;
|
||||
};
|
||||
|
||||
typedef enum TypeRecordKind {
|
||||
enum TypeRecordKind {
|
||||
TypeRecord_Invalid,
|
||||
|
||||
TypeRecord_Struct,
|
||||
@@ -75,9 +75,9 @@ typedef enum TypeRecordKind {
|
||||
TypeRecord_Enum,
|
||||
|
||||
TypeRecord_Count,
|
||||
} TypeRecordKind;
|
||||
};
|
||||
|
||||
typedef struct TypeRecord {
|
||||
struct TypeRecord {
|
||||
TypeRecordKind kind;
|
||||
|
||||
// All record types
|
||||
@@ -109,7 +109,7 @@ typedef struct TypeRecord {
|
||||
Entity * enum_count;
|
||||
Entity * enum_min_value;
|
||||
Entity * enum_max_value;
|
||||
} TypeRecord;
|
||||
};
|
||||
|
||||
#define TYPE_KINDS \
|
||||
TYPE_KIND(Basic, BasicType) \
|
||||
@@ -164,13 +164,13 @@ typedef struct TypeRecord {
|
||||
|
||||
|
||||
|
||||
typedef enum TypeKind {
|
||||
enum TypeKind {
|
||||
Type_Invalid,
|
||||
#define TYPE_KIND(k, ...) GB_JOIN2(Type_, k),
|
||||
TYPE_KINDS
|
||||
#undef TYPE_KIND
|
||||
Type_Count,
|
||||
} TypeKind;
|
||||
};
|
||||
|
||||
String const type_strings[] = {
|
||||
{cast(u8 *)"Invalid", gb_size_of("Invalid")},
|
||||
@@ -183,7 +183,7 @@ String const type_strings[] = {
|
||||
TYPE_KINDS
|
||||
#undef TYPE_KIND
|
||||
|
||||
typedef struct Type {
|
||||
struct Type {
|
||||
TypeKind kind;
|
||||
union {
|
||||
#define TYPE_KIND(k, ...) GB_JOIN2(Type, k) k;
|
||||
@@ -191,19 +191,19 @@ typedef struct Type {
|
||||
#undef TYPE_KIND
|
||||
};
|
||||
bool failure;
|
||||
} Type;
|
||||
};
|
||||
|
||||
|
||||
// TODO(bill): Should I add extra information here specifying the kind of selection?
|
||||
// e.g. field, constant, vector field, type field, etc.
|
||||
typedef struct Selection {
|
||||
Entity * entity;
|
||||
Array_i32 index;
|
||||
bool indirect; // Set if there was a pointer deref anywhere down the line
|
||||
} Selection;
|
||||
struct Selection {
|
||||
Entity * entity;
|
||||
Array<i32> index;
|
||||
bool indirect; // Set if there was a pointer deref anywhere down the line
|
||||
};
|
||||
Selection empty_selection = {0};
|
||||
|
||||
Selection make_selection(Entity *entity, Array_i32 index, bool indirect) {
|
||||
Selection make_selection(Entity *entity, Array<i32> index, bool indirect) {
|
||||
Selection s = {entity, index, indirect};
|
||||
return s;
|
||||
}
|
||||
@@ -212,10 +212,10 @@ void selection_add_index(Selection *s, isize index) {
|
||||
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
|
||||
// of heap allocation
|
||||
// TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3
|
||||
if (s->index.e == NULL) {
|
||||
if (s->index.data == NULL) {
|
||||
array_init(&s->index, heap_allocator());
|
||||
}
|
||||
array_add(&s->index, index);
|
||||
array_add(&s->index, cast(i32)index);
|
||||
}
|
||||
|
||||
|
||||
@@ -1025,7 +1025,7 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
if (!are_types_identical(xf->type, yf->type)) {
|
||||
return false;
|
||||
}
|
||||
if (str_ne(xf->token.string, yf->token.string)) {
|
||||
if (xf->token.string != yf->token.string) {
|
||||
return false;
|
||||
}
|
||||
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
|
||||
@@ -1039,7 +1039,7 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) {
|
||||
return false;
|
||||
}
|
||||
if (str_ne(x->Record.variants[i]->token.string, y->Record.variants[i]->token.string)) {
|
||||
if (x->Record.variants[i]->token.string != y->Record.variants[i]->token.string) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1199,7 +1199,7 @@ bool is_type_cte_safe(Type *type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef enum ProcTypeOverloadKind {
|
||||
enum ProcTypeOverloadKind {
|
||||
ProcOverload_Identical, // The types are identical
|
||||
|
||||
ProcOverload_CallingConvention,
|
||||
@@ -1211,7 +1211,7 @@ typedef enum ProcTypeOverloadKind {
|
||||
|
||||
ProcOverload_NotProcedure,
|
||||
|
||||
} ProcTypeOverloadKind;
|
||||
};
|
||||
|
||||
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
|
||||
if (x == NULL && y == NULL) return ProcOverload_NotProcedure;
|
||||
@@ -1297,9 +1297,9 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
if (f->kind == Entity_Variable) {
|
||||
if (f->Variable.field_src_index == index) {
|
||||
Array_i32 sel_array = {0};
|
||||
Array<i32> sel_array = {0};
|
||||
array_init_count(&sel_array, a, 1);
|
||||
sel_array.e[0] = i;
|
||||
sel_array[0] = i;
|
||||
return make_selection(f, sel_array, false);
|
||||
}
|
||||
}
|
||||
@@ -1309,18 +1309,18 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
|
||||
for (isize i = 0; i < max_count; i++) {
|
||||
Entity *f = type->Tuple.variables[i];
|
||||
if (i == index) {
|
||||
Array_i32 sel_array = {0};
|
||||
Array<i32> sel_array = {0};
|
||||
array_init_count(&sel_array, a, 1);
|
||||
sel_array.e[0] = i;
|
||||
sel_array[0] = i;
|
||||
return make_selection(f, sel_array, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_BitField: {
|
||||
Array_i32 sel_array = {0};
|
||||
Array<i32> sel_array = {0};
|
||||
array_init_count(&sel_array, a, 1);
|
||||
sel_array.e[0] = cast(i32)index;
|
||||
sel_array[0] = cast(i32)index;
|
||||
return make_selection(type->BitField.fields[index], sel_array, false);
|
||||
} break;
|
||||
|
||||
@@ -1337,7 +1337,7 @@ gb_global Entity *entity__any_type_info = NULL;
|
||||
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) {
|
||||
GB_ASSERT(type_ != NULL);
|
||||
|
||||
if (str_eq(field_name, str_lit("_"))) {
|
||||
if (field_name == "_") {
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
@@ -1362,11 +1362,11 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
entity__any_type_info = make_entity_field(a, NULL, make_token_ident(type_info_str), t_type_info_ptr, false, 1);
|
||||
}
|
||||
|
||||
if (str_eq(field_name, data_str)) {
|
||||
if (field_name == data_str) {
|
||||
selection_add_index(&sel, 0);
|
||||
sel.entity = entity__any_data;;
|
||||
return sel;
|
||||
} else if (str_eq(field_name, type_info_str)) {
|
||||
} else if (field_name == type_info_str) {
|
||||
selection_add_index(&sel, 1);
|
||||
sel.entity = entity__any_type_info;
|
||||
return sel;
|
||||
@@ -1382,7 +1382,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
switch (type->Vector.count) {
|
||||
#define _VECTOR_FIELD_CASE(_length, _name) \
|
||||
case (_length): \
|
||||
if (str_eq(field_name, str_lit(_name))) { \
|
||||
if (field_name == _name) { \
|
||||
selection_add_index(&sel, (_length)-1); \
|
||||
sel.entity = make_entity_vector_elem(a, NULL, make_token_ident(str_lit(_name)), type->Vector.elem, (_length)-1); \
|
||||
return sel; \
|
||||
@@ -1403,7 +1403,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
if (is_type) {
|
||||
if (type->kind == Type_Record) {
|
||||
if (type->Record.names != NULL &&
|
||||
str_eq(field_name, str_lit("names"))) {
|
||||
field_name == "names") {
|
||||
sel.entity = type->Record.names;
|
||||
return sel;
|
||||
}
|
||||
@@ -1415,7 +1415,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
GB_ASSERT(f->kind == Entity_TypeName);
|
||||
String str = f->token.string;
|
||||
|
||||
if (str_eq(str, field_name)) {
|
||||
if (str == field_name) {
|
||||
sel.entity = f;
|
||||
// selection_add_index(&sel, i);
|
||||
return sel;
|
||||
@@ -1424,15 +1424,15 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
} else if (is_type_enum(type)) {
|
||||
// NOTE(bill): These may not have been added yet, so check in case
|
||||
if (type->Record.enum_count != NULL) {
|
||||
if (str_eq(field_name, str_lit("count"))) {
|
||||
if (field_name == "count") {
|
||||
sel.entity = type->Record.enum_count;
|
||||
return sel;
|
||||
}
|
||||
if (str_eq(field_name, str_lit("min_value"))) {
|
||||
if (field_name == "min_value") {
|
||||
sel.entity = type->Record.enum_min_value;
|
||||
return sel;
|
||||
}
|
||||
if (str_eq(field_name, str_lit("max_value"))) {
|
||||
if (field_name == "max_value") {
|
||||
sel.entity = type->Record.enum_max_value;
|
||||
return sel;
|
||||
}
|
||||
@@ -1443,7 +1443,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
GB_ASSERT(f->kind == Entity_Constant);
|
||||
String str = f->token.string;
|
||||
|
||||
if (str_eq(field_name, str)) {
|
||||
if (field_name == str) {
|
||||
sel.entity = f;
|
||||
// selection_add_index(&sel, i);
|
||||
return sel;
|
||||
@@ -1457,7 +1457,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
continue;
|
||||
}
|
||||
String str = f->token.string;
|
||||
if (str_eq(field_name, str)) {
|
||||
if (field_name == str) {
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
@@ -1479,7 +1479,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
}
|
||||
if (type->Record.kind == TypeRecord_Union) {
|
||||
if (str_eq(field_name, str_lit("__tag"))) {
|
||||
if (field_name == "__tag") {
|
||||
Entity *e = type->Record.union__tag;
|
||||
GB_ASSERT(e != NULL);
|
||||
selection_add_index(&sel, -1); // HACK(bill): Leaky memory
|
||||
@@ -1496,7 +1496,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
|
||||
String str = f->token.string;
|
||||
if (str_eq(field_name, str)) {
|
||||
if (field_name == str) {
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
@@ -1508,10 +1508,10 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
|
||||
|
||||
typedef struct TypePath {
|
||||
Array(Type *) path; // Entity_TypeName;
|
||||
struct TypePath {
|
||||
Array<Type *> path; // Entity_TypeName;
|
||||
bool failure;
|
||||
} TypePath;
|
||||
};
|
||||
|
||||
void type_path_init(TypePath *tp) {
|
||||
// TODO(bill): Use an allocator that uses a backing array if it can and then use alternative allocator when exhausted
|
||||
@@ -1526,7 +1526,7 @@ void type_path_print_illegal_cycle(TypePath *tp, isize start_index) {
|
||||
GB_ASSERT(tp != NULL);
|
||||
|
||||
GB_ASSERT(start_index < tp->path.count);
|
||||
Type *t = tp->path.e[start_index];
|
||||
Type *t = tp->path[start_index];
|
||||
GB_ASSERT(t != NULL);
|
||||
|
||||
GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t));
|
||||
@@ -1534,7 +1534,7 @@ void type_path_print_illegal_cycle(TypePath *tp, isize start_index) {
|
||||
error(e->token, "Illegal declaration cycle of `%.*s`", LIT(t->Named.name));
|
||||
// NOTE(bill): Print cycle, if it's deep enough
|
||||
for (isize j = start_index; j < tp->path.count; j++) {
|
||||
Type *t = tp->path.e[j];
|
||||
Type *t = tp->path[j];
|
||||
GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t));
|
||||
Entity *e = t->Named.type_name;
|
||||
error(e->token, "\t%.*s refers to", LIT(t->Named.name));
|
||||
@@ -1549,7 +1549,7 @@ TypePath *type_path_push(TypePath *tp, Type *t) {
|
||||
GB_ASSERT(tp != NULL);
|
||||
|
||||
for (isize i = 0; i < tp->path.count; i++) {
|
||||
if (tp->path.e[i] == t) {
|
||||
if (tp->path[i] == t) {
|
||||
type_path_print_illegal_cycle(tp, i);
|
||||
}
|
||||
}
|
||||
@@ -1617,7 +1617,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
switch (t->kind) {
|
||||
case Type_Basic: {
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
switch (t->kind) {
|
||||
switch (t->Basic.kind) {
|
||||
case Basic_string: return build_context.word_size;
|
||||
case Basic_any: return build_context.word_size;
|
||||
|
||||
@@ -2082,7 +2082,7 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
|
||||
Type *t = type;
|
||||
i64 offset = 0;
|
||||
for_array(i, sel.index) {
|
||||
isize index = sel.index.e[i];
|
||||
isize index = sel.index[i];
|
||||
t = base_type(t);
|
||||
offset += type_offset_of(allocator, t, index);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
@@ -2291,7 +2291,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
if (var->flags&EntityFlag_Ellipsis) {
|
||||
Type *slice = base_type(var->type);
|
||||
str = gb_string_appendc(str, "...");
|
||||
str = gb_string_appendc(str, "..");
|
||||
GB_ASSERT(is_type_slice(var->type));
|
||||
str = write_type_to_string(str, slice->Slice.elem);
|
||||
} else {
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4245)
|
||||
|
||||
extern "C" {
|
||||
// #include "utf8proc/utf8proc.h"
|
||||
#include "utf8proc/utf8proc.c"
|
||||
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
|
||||
+8
-12
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
|
||||
return utf8proc_get_property(c)->category;
|
||||
return cast(utf8proc_category_t)utf8proc_get_property(c)->category;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
|
||||
@@ -393,15 +393,15 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
|
||||
|
||||
#define utf8proc_decompose_lump(replacement_uc) \
|
||||
return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
|
||||
options & ~UTF8PROC_LUMP, last_boundclass)
|
||||
(utf8proc_option_t)(options & ~UTF8PROC_LUMP), last_boundclass)
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
|
||||
const utf8proc_property_t *property;
|
||||
utf8proc_propval_t category;
|
||||
utf8proc_category_t category;
|
||||
utf8proc_int32_t hangul_sindex;
|
||||
if (uc < 0 || uc >= 0x110000) return UTF8PROC_ERROR_NOTASSIGNED;
|
||||
property = unsafe_get_property(uc);
|
||||
category = property->category;
|
||||
category = cast(utf8proc_category_t)property->category;
|
||||
hangul_sindex = uc - UTF8PROC_HANGUL_SBASE;
|
||||
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
|
||||
if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) {
|
||||
@@ -728,28 +728,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_DECOMPOSE);
|
||||
utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_DECOMPOSE));
|
||||
return retval;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_COMPOSE);
|
||||
utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_COMPOSE));
|
||||
return retval;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
|
||||
utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_DECOMPOSE|UTF8PROC_COMPAT));
|
||||
return retval;
|
||||
}
|
||||
|
||||
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
|
||||
utf8proc_uint8_t *retval;
|
||||
utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
|
||||
UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
|
||||
utf8proc_map(str, 0, &retval, cast(utf8proc_option_t)(UTF8PROC_NULLTERM|UTF8PROC_STABLE|UTF8PROC_COMPOSE|UTF8PROC_COMPAT));
|
||||
return retval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user