mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Minor Style Fixes
This commit is contained in:
+1
-19
@@ -1,25 +1,7 @@
|
|||||||
#import "fmt.odin"
|
#import "fmt.odin"
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
Entity :: union {
|
|
||||||
Apple: int
|
|
||||||
Banana: f32
|
|
||||||
Goat: struct {
|
|
||||||
x, y: int
|
|
||||||
z, w: f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a := 123 as Entity.Apple
|
|
||||||
e: Entity = a
|
|
||||||
fmt.println(a)
|
|
||||||
|
|
||||||
if apple, ok := ^e union_cast ^Entity.Apple; ok {
|
|
||||||
apple^ = 321
|
|
||||||
e = apple^
|
|
||||||
}
|
|
||||||
|
|
||||||
apple, ok := e union_cast Entity.Apple
|
|
||||||
fmt.println(apple)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -46,9 +46,12 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
|||||||
w: Window
|
w: Window
|
||||||
w.width, w.height = msg, height
|
w.width, w.height = msg, height
|
||||||
|
|
||||||
class_name := "Win32-Odin-Window\x00"
|
c_class_name := "Win32-Odin-Window\x00".data
|
||||||
c_class_name := class_name.data
|
if title[title.count-1] != 0 {
|
||||||
w.c_title = to_c_string(title)
|
w.c_title = to_c_string(title)
|
||||||
|
} else {
|
||||||
|
w.c_title = title as []u8
|
||||||
|
}
|
||||||
|
|
||||||
instance := GetModuleHandleA(nil)
|
instance := GetModuleHandleA(nil)
|
||||||
|
|
||||||
@@ -190,6 +193,7 @@ run :: proc() {
|
|||||||
|
|
||||||
draw_rect :: proc(x, y, w, h: f32) {
|
draw_rect :: proc(x, y, w, h: f32) {
|
||||||
gl.Begin(gl.TRIANGLES)
|
gl.Begin(gl.TRIANGLES)
|
||||||
|
defer gl.End()
|
||||||
|
|
||||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
||||||
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0)
|
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0)
|
||||||
@@ -198,8 +202,6 @@ run :: proc() {
|
|||||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0)
|
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0)
|
||||||
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0)
|
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0)
|
||||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0)
|
||||||
|
|
||||||
gl.End()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_rect(pos[0], pos[1], 50, 50)
|
draw_rect(pos[0], pos[1], 50, 50)
|
||||||
|
|||||||
+14
-15
@@ -88,6 +88,7 @@ align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AllocationHeader :: struct {
|
AllocationHeader :: struct {
|
||||||
size: int
|
size: int
|
||||||
}
|
}
|
||||||
@@ -109,21 +110,25 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Custom allocators
|
// Custom allocators
|
||||||
|
|
||||||
Arena :: struct {
|
Arena :: struct {
|
||||||
backing: Allocator
|
backing: Allocator
|
||||||
memory: []u8
|
memory: []byte
|
||||||
temp_count: int
|
temp_count: int
|
||||||
}
|
|
||||||
|
|
||||||
Temp_Arena_Memory :: struct {
|
Temp_Memory :: struct {
|
||||||
arena: ^Arena
|
arena: ^Arena
|
||||||
original_count: int
|
original_count: int
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||||
backing = Allocator{}
|
backing = Allocator{}
|
||||||
memory = data[:0]
|
memory = data[:0]
|
||||||
@@ -132,16 +137,10 @@ init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
|||||||
|
|
||||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||||
backing = context.allocator
|
backing = context.allocator
|
||||||
memory = new_slice(u8, 0, size)
|
memory = new_slice(byte, 0, size)
|
||||||
temp_count = 0
|
temp_count = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
init_sub_arena :: proc(sub, parent: ^Arena, size: int) {
|
|
||||||
push_allocator arena_allocator(parent) {
|
|
||||||
init_arena_from_context(sub, size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_arena :: proc(using a: ^Arena) {
|
free_arena :: proc(using a: ^Arena) {
|
||||||
if backing.procedure != nil {
|
if backing.procedure != nil {
|
||||||
push_allocator backing {
|
push_allocator backing {
|
||||||
@@ -181,7 +180,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
|||||||
|
|
||||||
case FREE:
|
case FREE:
|
||||||
// NOTE(bill): Free all at once
|
// NOTE(bill): Free all at once
|
||||||
// Use Temp_Arena_Memory if you want to free a block
|
// Use Arena.Temp_Memory if you want to free a block
|
||||||
|
|
||||||
case FREE_ALL:
|
case FREE_ALL:
|
||||||
arena.memory.count = 0
|
arena.memory.count = 0
|
||||||
@@ -193,15 +192,15 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_temp_arena_memory :: proc(a: ^Arena) -> Temp_Arena_Memory {
|
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena.Temp_Memory {
|
||||||
tmp: Temp_Arena_Memory
|
tmp: Arena.Temp_Memory
|
||||||
tmp.arena = a
|
tmp.arena = a
|
||||||
tmp.original_count = a.memory.count
|
tmp.original_count = a.memory.count
|
||||||
a.temp_count++
|
a.temp_count++
|
||||||
return tmp
|
return tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
end_temp_arena_memory :: proc(using tmp: Temp_Arena_Memory) {
|
end_arena_temp_memory :: proc(using tmp: Arena.Temp_Memory) {
|
||||||
assert(arena.memory.count >= original_count)
|
assert(arena.memory.count >= original_count)
|
||||||
assert(arena.temp_count > 0)
|
assert(arena.temp_count > 0)
|
||||||
arena.memory.count = original_count
|
arena.memory.count = original_count
|
||||||
@@ -232,7 +231,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
|||||||
case Pointer:
|
case Pointer:
|
||||||
return WORD_SIZE
|
return WORD_SIZE
|
||||||
case Maybe:
|
case Maybe:
|
||||||
return align_of_type_info(info.elem)
|
return max(align_of_type_info(info.elem), 1)
|
||||||
case Procedure:
|
case Procedure:
|
||||||
return WORD_SIZE
|
return WORD_SIZE
|
||||||
case Array:
|
case Array:
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ File_Standard :: type enum {
|
|||||||
COUNT,
|
COUNT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Uses startup to initialize it
|
||||||
__std_files := [..]File{
|
__std_files := [..]File{
|
||||||
File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
|
File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
|
||||||
File{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
|
File{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
RUNE_ERROR :: #rune "\ufffd"
|
RUNE_ERROR :: #rune "\ufffd"
|
||||||
RUNE_SELF :: 0x80
|
RUNE_SELF :: 0x80
|
||||||
|
RUNE_BOM :: 0xfeff
|
||||||
|
RUNE_EOF :: ~(0 as rune)
|
||||||
MAX_RUNE :: #rune "\U0010ffff"
|
MAX_RUNE :: #rune "\U0010ffff"
|
||||||
UTF_MAX :: 4
|
UTF_MAX :: 4
|
||||||
|
|
||||||
|
|
||||||
SURROGATE_MIN :: 0xd800
|
SURROGATE_MIN :: 0xd800
|
||||||
SURROGATE_MAX :: 0xdfff
|
SURROGATE_MAX :: 0xdfff
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
call devenv.exe odin.sln
|
start devenv.exe odin.sln
|
||||||
|
|||||||
+22
-16
@@ -26,18 +26,15 @@ String const addressing_mode_strings[] = {
|
|||||||
|
|
||||||
struct Operand {
|
struct Operand {
|
||||||
AddressingMode mode;
|
AddressingMode mode;
|
||||||
Type *type;
|
Type * type;
|
||||||
ExactValue value;
|
ExactValue value;
|
||||||
AstNode *expr;
|
AstNode * expr;
|
||||||
BuiltinProcId builtin_id;
|
BuiltinProcId builtin_id;
|
||||||
};
|
};
|
||||||
b32 is_operand_nil(Operand *o) {
|
|
||||||
return o->mode == Addressing_Value && o->type == t_untyped_nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TypeAndValue {
|
struct TypeAndValue {
|
||||||
AddressingMode mode;
|
AddressingMode mode;
|
||||||
Type *type;
|
Type * type;
|
||||||
ExactValue value;
|
ExactValue value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,12 +52,10 @@ struct DeclInfo {
|
|||||||
Map<b32> deps; // Key: Entity *
|
Map<b32> deps; // Key: Entity *
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct ExpressionInfo {
|
struct ExpressionInfo {
|
||||||
b32 is_lhs; // Debug info
|
b32 is_lhs; // Debug info
|
||||||
AddressingMode mode;
|
AddressingMode mode;
|
||||||
Type *type; // Type_Basic
|
Type * type; // Type_Basic
|
||||||
ExactValue value;
|
ExactValue value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -213,10 +208,9 @@ struct CheckerInfo {
|
|||||||
Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
|
Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
|
||||||
Map<DeclInfo *> entities; // Key: Entity *
|
Map<DeclInfo *> entities; // Key: Entity *
|
||||||
Map<Entity *> foreign_procs; // Key: String
|
Map<Entity *> foreign_procs; // Key: String
|
||||||
|
Map<AstFile *> files; // Key: String (full path)
|
||||||
Map<isize> type_info_map; // Key: Type *
|
Map<isize> type_info_map; // Key: Type *
|
||||||
Map<AstFile *> files; // Key: String
|
|
||||||
isize type_info_index;
|
isize type_info_index;
|
||||||
|
|
||||||
Entity * implicit_values[ImplicitValue_Count];
|
Entity * implicit_values[ImplicitValue_Count];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -282,13 +276,15 @@ void destroy_declaration_info(DeclInfo *d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b32 decl_info_has_init(DeclInfo *d) {
|
b32 decl_info_has_init(DeclInfo *d) {
|
||||||
if (d->init_expr != NULL)
|
if (d->init_expr != NULL) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (d->proc_decl != NULL) {
|
if (d->proc_decl != NULL) {
|
||||||
ast_node(pd, ProcDecl, d->proc_decl);
|
ast_node(pd, ProcDecl, d->proc_decl);
|
||||||
if (pd->body != NULL)
|
if (pd->body != NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -629,13 +625,15 @@ Entity *entity_of_ident(CheckerInfo *i, AstNode *identifier) {
|
|||||||
|
|
||||||
Type *type_of_expr(CheckerInfo *i, AstNode *expression) {
|
Type *type_of_expr(CheckerInfo *i, AstNode *expression) {
|
||||||
TypeAndValue *found = type_and_value_of_expression(i, expression);
|
TypeAndValue *found = type_and_value_of_expression(i, expression);
|
||||||
if (found)
|
if (found) {
|
||||||
return found->type;
|
return found->type;
|
||||||
|
}
|
||||||
if (expression->kind == AstNode_Ident) {
|
if (expression->kind == AstNode_Ident) {
|
||||||
Entity *entity = entity_of_ident(i, expression);
|
Entity *entity = entity_of_ident(i, expression);
|
||||||
if (entity)
|
if (entity) {
|
||||||
return entity->type;
|
return entity->type;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -647,8 +645,9 @@ void add_untyped(CheckerInfo *i, AstNode *expression, b32 lhs, AddressingMode mo
|
|||||||
|
|
||||||
void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) {
|
void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) {
|
||||||
GB_ASSERT(expression != NULL);
|
GB_ASSERT(expression != NULL);
|
||||||
if (mode == Addressing_Invalid)
|
if (mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == Addressing_Constant) {
|
if (mode == Addressing_Constant) {
|
||||||
if (is_type_constant_type(type)) {
|
if (is_type_constant_type(type)) {
|
||||||
@@ -1145,6 +1144,12 @@ void check_parsed_files(Checker *c) {
|
|||||||
auto found = map_get(&file_scopes, key);
|
auto found = map_get(&file_scopes, key);
|
||||||
GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath));
|
GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath));
|
||||||
Scope *scope = *found;
|
Scope *scope = *found;
|
||||||
|
|
||||||
|
if (scope->is_global) {
|
||||||
|
error(id->token, "Importing a #shared_global_scope is disallowed and unnecessary");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
b32 previously_added = false;
|
b32 previously_added = false;
|
||||||
for_array(import_index, file_scope->imported) {
|
for_array(import_index, file_scope->imported) {
|
||||||
Scope *prev = file_scope->imported[import_index];
|
Scope *prev = file_scope->imported[import_index];
|
||||||
@@ -1153,6 +1158,7 @@ void check_parsed_files(Checker *c) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!previously_added) {
|
if (!previously_added) {
|
||||||
array_add(&file_scope->imported, scope);
|
array_add(&file_scope->imported, scope);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
|
|||||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||||
entity->using_parent = parent;
|
entity->using_parent = parent;
|
||||||
entity->Variable.anonymous = true;
|
entity->Variable.anonymous = true;
|
||||||
|
entity->Variable.anonymous = true;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+87
-29
@@ -79,7 +79,7 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (type_has_nil(dst)) {
|
if (type_has_nil(dst)) {
|
||||||
return is_operand_nil(operand);
|
return operand->mode == Addressing_Value && operand->type == t_untyped_nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,8 +156,9 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
|||||||
PROF_PROC();
|
PROF_PROC();
|
||||||
|
|
||||||
check_not_tuple(c, operand);
|
check_not_tuple(c, operand);
|
||||||
if (operand->mode == Addressing_Invalid)
|
if (operand->mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_type_untyped(operand->type)) {
|
if (is_type_untyped(operand->type)) {
|
||||||
Type *target_type = type;
|
Type *target_type = type;
|
||||||
@@ -1379,10 +1380,12 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (is_type_pointer(type)) {
|
} else if (is_type_pointer(type)) {
|
||||||
if (in_value.kind == ExactValue_Pointer)
|
if (in_value.kind == ExactValue_Pointer) {
|
||||||
return true;
|
return true;
|
||||||
if (in_value.kind == ExactValue_Integer)
|
}
|
||||||
|
if (in_value.kind == ExactValue_Integer) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (out_value) *out_value = in_value;
|
if (out_value) *out_value = in_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1492,8 +1495,9 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
|
|||||||
o->value = exact_unary_operator_value(op, o->value, precision);
|
o->value = exact_unary_operator_value(op, o->value, precision);
|
||||||
|
|
||||||
if (is_type_typed(type)) {
|
if (is_type_typed(type)) {
|
||||||
if (node != NULL)
|
if (node != NULL) {
|
||||||
o->expr = node;
|
o->expr = node;
|
||||||
|
}
|
||||||
check_is_expressible(c, o, type);
|
check_is_expressible(c, o, type);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1509,8 +1513,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
|||||||
defer (gb_temp_arena_memory_end(tmp));
|
defer (gb_temp_arena_memory_end(tmp));
|
||||||
|
|
||||||
gbString err_str = NULL;
|
gbString err_str = NULL;
|
||||||
defer ({
|
defer (if (err_str != NULL) {
|
||||||
if (err_str != NULL)
|
|
||||||
gb_string_free(err_str);
|
gb_string_free(err_str);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1520,13 +1523,13 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
|||||||
switch (op.kind) {
|
switch (op.kind) {
|
||||||
case Token_CmpEq:
|
case Token_CmpEq:
|
||||||
case Token_NotEq:
|
case Token_NotEq:
|
||||||
defined = is_type_comparable(base_type(x->type));
|
defined = is_type_comparable(get_enum_base_type(base_type(x->type)));
|
||||||
break;
|
break;
|
||||||
case Token_Lt:
|
case Token_Lt:
|
||||||
case Token_Gt:
|
case Token_Gt:
|
||||||
case Token_LtEq:
|
case Token_LtEq:
|
||||||
case Token_GtEq: {
|
case Token_GtEq: {
|
||||||
defined = is_type_ordered(base_type(x->type));
|
defined = is_type_ordered(get_enum_base_type(base_type(x->type)));
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1546,7 +1549,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err_str != NULL) {
|
if (err_str != NULL) {
|
||||||
error(op, "Cannot compare expression, %s", err_str);
|
error(ast_node_token(x->expr), "Cannot compare expression, %s", err_str);
|
||||||
x->type = t_untyped_bool;
|
x->type = t_untyped_bool;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1682,15 +1685,17 @@ b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
|||||||
|
|
||||||
// Cast between booleans and integers
|
// Cast between booleans and integers
|
||||||
if (is_type_boolean(xb) || is_type_integer(xb)) {
|
if (is_type_boolean(xb) || is_type_integer(xb)) {
|
||||||
if (is_type_boolean(yb) || is_type_integer(yb))
|
if (is_type_boolean(yb) || is_type_integer(yb)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cast between numbers
|
// Cast between numbers
|
||||||
if (is_type_integer(xb) || is_type_float(xb)) {
|
if (is_type_integer(xb) || is_type_float(xb)) {
|
||||||
if (is_type_integer(yb) || is_type_float(yb))
|
if (is_type_integer(yb) || is_type_float(yb)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cast between pointers
|
// Cast between pointers
|
||||||
if (is_type_pointer(xb) && is_type_pointer(yb)) {
|
if (is_type_pointer(xb) && is_type_pointer(yb)) {
|
||||||
@@ -1747,11 +1752,12 @@ String check_down_cast_name(Type *dst_, Type *src_) {
|
|||||||
|
|
||||||
if (!is_type_pointer(f->type)) {
|
if (!is_type_pointer(f->type)) {
|
||||||
result = check_down_cast_name(f->type, src_);
|
result = check_down_cast_name(f->type, src_);
|
||||||
if (result.len > 0)
|
if (result.len > 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1808,8 +1814,9 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
|||||||
if (be->op.kind == Token_as) {
|
if (be->op.kind == Token_as) {
|
||||||
check_expr(c, x, be->left);
|
check_expr(c, x, be->left);
|
||||||
Type *type = check_type(c, be->right);
|
Type *type = check_type(c, be->right);
|
||||||
if (x->mode == Addressing_Invalid)
|
if (x->mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
b32 is_const_expr = x->mode == Addressing_Constant;
|
b32 is_const_expr = x->mode == Addressing_Constant;
|
||||||
b32 can_convert = false;
|
b32 can_convert = false;
|
||||||
@@ -1854,8 +1861,9 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
|||||||
} else if (be->op.kind == Token_transmute) {
|
} else if (be->op.kind == Token_transmute) {
|
||||||
check_expr(c, x, be->left);
|
check_expr(c, x, be->left);
|
||||||
Type *type = check_type(c, be->right);
|
Type *type = check_type(c, be->right);
|
||||||
if (x->mode == Addressing_Invalid)
|
if (x->mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (x->mode == Addressing_Constant) {
|
if (x->mode == Addressing_Constant) {
|
||||||
gbString expr_str = expr_to_string(x->expr);
|
gbString expr_str = expr_to_string(x->expr);
|
||||||
@@ -2160,8 +2168,9 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
|||||||
}
|
}
|
||||||
x->value = exact_binary_operator_value(op, a, b);
|
x->value = exact_binary_operator_value(op, a, b);
|
||||||
if (is_type_typed(type)) {
|
if (is_type_typed(type)) {
|
||||||
if (node != NULL)
|
if (node != NULL) {
|
||||||
x->expr = node;
|
x->expr = node;
|
||||||
|
}
|
||||||
check_is_expressible(c, x, type);
|
check_is_expressible(c, x, type);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -2176,19 +2185,22 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) {
|
|||||||
|
|
||||||
HashKey key = hash_pointer(e);
|
HashKey key = hash_pointer(e);
|
||||||
ExpressionInfo *found = map_get(&c->info.untyped, key);
|
ExpressionInfo *found = map_get(&c->info.untyped, key);
|
||||||
if (found == NULL)
|
if (found == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case_ast_node(ue, UnaryExpr, e);
|
case_ast_node(ue, UnaryExpr, e);
|
||||||
if (found->value.kind != ExactValue_Invalid)
|
if (found->value.kind != ExactValue_Invalid) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
update_expr_type(c, ue->expr, type, final);
|
update_expr_type(c, ue->expr, type, final);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(be, BinaryExpr, e);
|
case_ast_node(be, BinaryExpr, e);
|
||||||
if (found->value.kind != ExactValue_Invalid)
|
if (found->value.kind != ExactValue_Invalid) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (!token_is_comparison(be->op)) {
|
if (!token_is_comparison(be->op)) {
|
||||||
if (token_is_shift(be->op)) {
|
if (token_is_shift(be->op)) {
|
||||||
update_expr_type(c, be->left, type, final);
|
update_expr_type(c, be->left, type, final);
|
||||||
@@ -2222,8 +2234,9 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) {
|
|||||||
|
|
||||||
void update_expr_value(Checker *c, AstNode *e, ExactValue value) {
|
void update_expr_value(Checker *c, AstNode *e, ExactValue value) {
|
||||||
ExpressionInfo *found = map_get(&c->info.untyped, hash_pointer(e));
|
ExpressionInfo *found = map_get(&c->info.untyped, hash_pointer(e));
|
||||||
if (found)
|
if (found) {
|
||||||
found->value = value;
|
found->value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) {
|
void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) {
|
||||||
@@ -2389,10 +2402,10 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
|||||||
ast_node(se, SelectorExpr, node);
|
ast_node(se, SelectorExpr, node);
|
||||||
|
|
||||||
b32 check_op_expr = true;
|
b32 check_op_expr = true;
|
||||||
|
Entity *expr_entity = NULL;
|
||||||
Entity *entity = NULL;
|
Entity *entity = NULL;
|
||||||
Selection sel = {}; // NOTE(bill): Not used if it's an import name
|
Selection sel = {}; // NOTE(bill): Not used if it's an import name
|
||||||
|
|
||||||
|
|
||||||
AstNode *op_expr = se->expr;
|
AstNode *op_expr = se->expr;
|
||||||
AstNode *selector = unparen_expr(se->selector);
|
AstNode *selector = unparen_expr(se->selector);
|
||||||
if (selector == NULL) {
|
if (selector == NULL) {
|
||||||
@@ -2401,10 +2414,12 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
|||||||
|
|
||||||
GB_ASSERT(selector->kind == AstNode_Ident);
|
GB_ASSERT(selector->kind == AstNode_Ident);
|
||||||
|
|
||||||
|
|
||||||
if (op_expr->kind == AstNode_Ident) {
|
if (op_expr->kind == AstNode_Ident) {
|
||||||
String name = op_expr->Ident.string;
|
String name = op_expr->Ident.string;
|
||||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||||
add_entity_use(c, op_expr, e);
|
add_entity_use(c, op_expr, e);
|
||||||
|
expr_entity = e;
|
||||||
if (e != NULL && e->kind == Entity_ImportName) {
|
if (e != NULL && e->kind == Entity_ImportName) {
|
||||||
String sel_name = selector->Ident.string;
|
String sel_name = selector->Ident.string;
|
||||||
check_op_expr = false;
|
check_op_expr = false;
|
||||||
@@ -2459,6 +2474,17 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expr_entity != NULL && expr_entity->kind == Entity_Constant && entity->kind != Entity_Constant) {
|
||||||
|
gbString op_str = expr_to_string(op_expr);
|
||||||
|
gbString type_str = type_to_string(operand->type);
|
||||||
|
gbString sel_str = expr_to_string(selector);
|
||||||
|
defer (gb_string_free(op_str));
|
||||||
|
defer (gb_string_free(type_str));
|
||||||
|
defer (gb_string_free(sel_str));
|
||||||
|
error(ast_node_token(op_expr), "Cannot access non-constant field `%s` from `%s`", sel_str, op_str);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
add_entity_use(c, selector, entity);
|
add_entity_use(c, selector, entity);
|
||||||
|
|
||||||
@@ -2570,8 +2596,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_expr(c, &op, len);
|
check_expr(c, &op, len);
|
||||||
if (op.mode == Addressing_Invalid)
|
if (op.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (!is_type_integer(op.type)) {
|
if (!is_type_integer(op.type)) {
|
||||||
gbString type_str = type_to_string(operand->type);
|
gbString type_str = type_to_string(operand->type);
|
||||||
defer (gb_string_free(type_str));
|
defer (gb_string_free(type_str));
|
||||||
@@ -2583,8 +2610,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
|
|
||||||
if (cap != NULL) {
|
if (cap != NULL) {
|
||||||
check_expr(c, &op, cap);
|
check_expr(c, &op, cap);
|
||||||
if (op.mode == Addressing_Invalid)
|
if (op.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (!is_type_integer(op.type)) {
|
if (!is_type_integer(op.type)) {
|
||||||
gbString type_str = type_to_string(operand->type);
|
gbString type_str = type_to_string(operand->type);
|
||||||
defer (gb_string_free(type_str));
|
defer (gb_string_free(type_str));
|
||||||
@@ -2709,8 +2737,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
ast_node(s, SelectorExpr, arg);
|
ast_node(s, SelectorExpr, arg);
|
||||||
|
|
||||||
check_expr(c, operand, s->expr);
|
check_expr(c, operand, s->expr);
|
||||||
if (operand->mode == Addressing_Invalid)
|
if (operand->mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *type = operand->type;
|
Type *type = operand->type;
|
||||||
if (base_type(type)->kind == Type_Pointer) {
|
if (base_type(type)->kind == Type_Pointer) {
|
||||||
@@ -2750,8 +2779,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
case BuiltinProc_type_of_val:
|
case BuiltinProc_type_of_val:
|
||||||
// type_of_val :: proc(val: Type) -> type(Type)
|
// type_of_val :: proc(val: Type) -> type(Type)
|
||||||
check_assignment(c, operand, NULL, make_string("argument of `type_of_val`"));
|
check_assignment(c, operand, NULL, make_string("argument of `type_of_val`"));
|
||||||
if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin)
|
if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
operand->mode = Addressing_Type;
|
operand->mode = Addressing_Type;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3140,8 +3170,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
Operand a = *operand;
|
Operand a = *operand;
|
||||||
Operand b = {};
|
Operand b = {};
|
||||||
check_expr(c, &b, other_arg);
|
check_expr(c, &b, other_arg);
|
||||||
if (b.mode == Addressing_Invalid)
|
if (b.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (!is_type_comparable(b.type) || !is_type_numeric(type)) {
|
if (!is_type_comparable(b.type) || !is_type_numeric(type)) {
|
||||||
gbString type_str = type_to_string(b.type);
|
gbString type_str = type_to_string(b.type);
|
||||||
defer (gb_string_free(type_str));
|
defer (gb_string_free(type_str));
|
||||||
@@ -3151,7 +3182,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (a.mode == Addressing_Constant &&
|
if (a.mode == Addressing_Constant &&
|
||||||
b.mode == Addressing_Constant) {
|
b.mode == Addressing_Constant) {
|
||||||
ExactValue x = a.value;
|
ExactValue x = a.value;
|
||||||
@@ -3170,6 +3200,15 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
operand->mode = Addressing_Value;
|
operand->mode = Addressing_Value;
|
||||||
operand->type = type;
|
operand->type = type;
|
||||||
|
|
||||||
|
convert_to_typed(c, &a, b.type);
|
||||||
|
if (a.mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
convert_to_typed(c, &b, a.type);
|
||||||
|
if (b.mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!are_types_identical(operand->type, b.type)) {
|
if (!are_types_identical(operand->type, b.type)) {
|
||||||
gbString type_a = type_to_string(a.type);
|
gbString type_a = type_to_string(a.type);
|
||||||
gbString type_b = type_to_string(b.type);
|
gbString type_b = type_to_string(b.type);
|
||||||
@@ -3200,8 +3239,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
Operand a = *operand;
|
Operand a = *operand;
|
||||||
Operand b = {};
|
Operand b = {};
|
||||||
check_expr(c, &b, other_arg);
|
check_expr(c, &b, other_arg);
|
||||||
if (b.mode == Addressing_Invalid)
|
if (b.mode == Addressing_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (!is_type_comparable(b.type) || !is_type_numeric(type)) {
|
if (!is_type_comparable(b.type) || !is_type_numeric(type)) {
|
||||||
gbString type_str = type_to_string(b.type);
|
gbString type_str = type_to_string(b.type);
|
||||||
defer (gb_string_free(type_str));
|
defer (gb_string_free(type_str));
|
||||||
@@ -3211,7 +3251,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (a.mode == Addressing_Constant &&
|
if (a.mode == Addressing_Constant &&
|
||||||
b.mode == Addressing_Constant) {
|
b.mode == Addressing_Constant) {
|
||||||
ExactValue x = a.value;
|
ExactValue x = a.value;
|
||||||
@@ -3230,6 +3269,15 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
operand->mode = Addressing_Value;
|
operand->mode = Addressing_Value;
|
||||||
operand->type = type;
|
operand->type = type;
|
||||||
|
|
||||||
|
convert_to_typed(c, &a, b.type);
|
||||||
|
if (a.mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
convert_to_typed(c, &b, a.type);
|
||||||
|
if (b.mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!are_types_identical(operand->type, b.type)) {
|
if (!are_types_identical(operand->type, b.type)) {
|
||||||
gbString type_a = type_to_string(a.type);
|
gbString type_a = type_to_string(a.type);
|
||||||
gbString type_b = type_to_string(b.type);
|
gbString type_b = type_to_string(b.type);
|
||||||
@@ -3847,6 +3895,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type *t = base_type(type_deref(o->type));
|
Type *t = base_type(type_deref(o->type));
|
||||||
|
b32 is_const = o->mode == Addressing_Constant;
|
||||||
|
|
||||||
|
|
||||||
auto set_index_data = [](Operand *o, Type *t, i64 *max_count) -> b32 {
|
auto set_index_data = [](Operand *o, Type *t, i64 *max_count) -> b32 {
|
||||||
t = base_type(type_deref(t));
|
t = base_type(type_deref(t));
|
||||||
@@ -3894,6 +3944,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
i64 max_count = -1;
|
i64 max_count = -1;
|
||||||
b32 valid = set_index_data(o, t, &max_count);
|
b32 valid = set_index_data(o, t, &max_count);
|
||||||
|
|
||||||
|
if (is_const) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
|
if (!valid && (is_type_struct(t) || is_type_raw_union(t))) {
|
||||||
Entity *found = find_using_index_expr(t);
|
Entity *found = find_using_index_expr(t);
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
@@ -3903,7 +3957,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
gbString str = expr_to_string(o->expr);
|
gbString str = expr_to_string(o->expr);
|
||||||
|
if (is_const) {
|
||||||
|
error(ast_node_token(o->expr), "Cannot index a constant `%s`", str);
|
||||||
|
} else {
|
||||||
error(ast_node_token(o->expr), "Cannot index `%s`", str);
|
error(ast_node_token(o->expr), "Cannot index `%s`", str);
|
||||||
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-15
@@ -983,7 +983,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
isize rhs_count = operands.count;
|
isize rhs_count = operands.count;
|
||||||
|
|
||||||
isize operand_index = 0;
|
isize operand_index = 0;
|
||||||
for_array(i, as->lhs) {
|
for_array(i, operands) {
|
||||||
AstNode *lhs = as->lhs[i];
|
AstNode *lhs = as->lhs[i];
|
||||||
check_assignment_variable(c, &operands[i], lhs);
|
check_assignment_variable(c, &operands[i], lhs);
|
||||||
}
|
}
|
||||||
@@ -1400,16 +1400,19 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
Token token = bs->token;
|
Token token = bs->token;
|
||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
case Token_break:
|
case Token_break:
|
||||||
if ((flags & Stmt_BreakAllowed) == 0)
|
if ((flags & Stmt_BreakAllowed) == 0) {
|
||||||
error(token, "`break` only allowed in `for` or `match` statements");
|
error(token, "`break` only allowed in `for` or `match` statements");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Token_continue:
|
case Token_continue:
|
||||||
if ((flags & Stmt_ContinueAllowed) == 0)
|
if ((flags & Stmt_ContinueAllowed) == 0) {
|
||||||
error(token, "`continue` only allowed in `for` statements");
|
error(token, "`continue` only allowed in `for` statements");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Token_fallthrough:
|
case Token_fallthrough:
|
||||||
if ((flags & Stmt_FallthroughAllowed) == 0)
|
if ((flags & Stmt_FallthroughAllowed) == 0) {
|
||||||
error(token, "`fallthrough` statement in illegal position");
|
error(token, "`fallthrough` statement in illegal position");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(token, "Invalid AST: Branch Statement `%.*s`", LIT(token.string));
|
error(token, "Invalid AST: Branch Statement `%.*s`", LIT(token.string));
|
||||||
@@ -1432,7 +1435,6 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
e = scope_lookup_entity(c->context.scope, name);
|
e = scope_lookup_entity(c->context.scope, name);
|
||||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
check_expr_base(c, &o, expr->SelectorExpr.expr);
|
|
||||||
e = check_selector(c, &o, expr);
|
e = check_selector(c, &o, expr);
|
||||||
is_selector = true;
|
is_selector = true;
|
||||||
}
|
}
|
||||||
@@ -1499,15 +1501,6 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Entity_Constant:
|
|
||||||
error(us->token, "`using` cannot be applied to a constant");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Entity_Procedure:
|
|
||||||
case Entity_Builtin:
|
|
||||||
error(us->token, "`using` cannot be applied to a procedure");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Entity_Variable: {
|
case Entity_Variable: {
|
||||||
Type *t = base_type(type_deref(e->type));
|
Type *t = base_type(type_deref(e->type));
|
||||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||||
@@ -1533,8 +1526,29 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case Entity_Constant:
|
||||||
|
error(us->token, "`using` cannot be applied to a constant");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Entity_Procedure:
|
||||||
|
case Entity_Builtin:
|
||||||
|
error(us->token, "`using` cannot be applied to a procedure");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Entity_ImplicitValue:
|
||||||
|
error(us->token, "`using` cannot be applied to an implicit value");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Entity_Nil:
|
||||||
|
error(us->token, "`using` cannot be applied to `nil`");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Entity_Invalid:
|
||||||
|
error(us->token, "`using` cannot be applied to an invalid entity");
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("TODO(bill): using other expressions?");
|
GB_PANIC("TODO(bill): `using` other expressions?");
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ struct ssaGen {
|
|||||||
};
|
};
|
||||||
|
|
||||||
b32 ssa_gen_init(ssaGen *s, Checker *c) {
|
b32 ssa_gen_init(ssaGen *s, Checker *c) {
|
||||||
if (global_error_collector.count != 0)
|
if (global_error_collector.count != 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
isize tc = c->parser->total_token_count;
|
isize tc = c->parser->total_token_count;
|
||||||
if (tc < 2) {
|
if (tc < 2) {
|
||||||
@@ -43,7 +44,7 @@ String ssa_mangle_name(ssaGen *s, String path, String name) {
|
|||||||
AstFile *file = *map_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);
|
char *str = gb_alloc_array(a, char, path.len+1);
|
||||||
gb_memcopy(str, path.text, path.len);
|
gb_memmove(str, path.text, path.len);
|
||||||
str[path.len] = 0;
|
str[path.len] = 0;
|
||||||
for (isize i = 0; i < path.len; i++) {
|
for (isize i = 0; i < path.len; i++) {
|
||||||
if (str[i] == '\\') {
|
if (str[i] == '\\') {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ void ssa_file_buffer_write(ssaFileBuffer *f, void *data, isize len) {
|
|||||||
f->offset = 0;
|
f->offset = 0;
|
||||||
}
|
}
|
||||||
u8 *cursor = cast(u8 *)f->vm.data + f->offset;
|
u8 *cursor = cast(u8 *)f->vm.data + f->offset;
|
||||||
gb_memcopy(cursor, data, len);
|
gb_memmove(cursor, data, len);
|
||||||
f->offset += len;
|
f->offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-10
@@ -21,7 +21,7 @@ struct ssaDebugInfo {
|
|||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
AstFile *file;
|
AstFile * file;
|
||||||
String producer;
|
String producer;
|
||||||
ssaDebugInfo *all_procs;
|
ssaDebugInfo *all_procs;
|
||||||
} CompileUnit;
|
} CompileUnit;
|
||||||
@@ -112,7 +112,7 @@ enum ssaDeferKind {
|
|||||||
struct ssaDefer {
|
struct ssaDefer {
|
||||||
ssaDeferKind kind;
|
ssaDeferKind kind;
|
||||||
isize scope_index;
|
isize scope_index;
|
||||||
ssaBlock *block;
|
ssaBlock * block;
|
||||||
union {
|
union {
|
||||||
AstNode *stmt;
|
AstNode *stmt;
|
||||||
// NOTE(bill): `instr` will be copied every time to create a new one
|
// NOTE(bill): `instr` will be copied every time to create a new one
|
||||||
@@ -121,7 +121,7 @@ struct ssaDefer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ssaProcedure {
|
struct ssaProcedure {
|
||||||
ssaProcedure *parent;
|
ssaProcedure * parent;
|
||||||
Array<ssaProcedure *> children;
|
Array<ssaProcedure *> children;
|
||||||
|
|
||||||
Entity * entity;
|
Entity * entity;
|
||||||
@@ -1422,7 +1422,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
|
|||||||
proc->curr_block = proc->decl_block;
|
proc->curr_block = proc->decl_block;
|
||||||
ssa_emit_jump(proc, proc->entry_block);
|
ssa_emit_jump(proc, proc->entry_block);
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
ssa_optimize_blocks(proc);
|
ssa_optimize_blocks(proc);
|
||||||
ssa_build_referrers(proc);
|
ssa_build_referrers(proc);
|
||||||
ssa_build_dom_tree(proc);
|
ssa_build_dom_tree(proc);
|
||||||
@@ -2243,7 +2243,6 @@ ssaValue *ssa_emit_union_cast(ssaProcedure *proc, ssaValue *value, Type *tuple)
|
|||||||
}
|
}
|
||||||
GB_ASSERT(dst_tag != NULL);
|
GB_ASSERT(dst_tag != NULL);
|
||||||
|
|
||||||
|
|
||||||
ssaBlock *ok_block = ssa_add_block(proc, NULL, "union_cast.ok");
|
ssaBlock *ok_block = ssa_add_block(proc, NULL, "union_cast.ok");
|
||||||
ssaBlock *end_block = ssa_add_block(proc, NULL, "union_cast.end");
|
ssaBlock *end_block = ssa_add_block(proc, NULL, "union_cast.end");
|
||||||
ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag, dst_tag);
|
ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag, dst_tag);
|
||||||
@@ -3647,10 +3646,10 @@ void ssa_mangle_sub_type_name(ssaModule *m, Entity *field, String parent) {
|
|||||||
child.text = gb_alloc_array(m->allocator, u8, len);
|
child.text = gb_alloc_array(m->allocator, u8, len);
|
||||||
|
|
||||||
isize i = 0;
|
isize i = 0;
|
||||||
gb_memcopy(child.text+i, parent.text, parent.len);
|
gb_memmove(child.text+i, parent.text, parent.len);
|
||||||
i += parent.len;
|
i += parent.len;
|
||||||
child.text[i++] = '.';
|
child.text[i++] = '.';
|
||||||
gb_memcopy(child.text+i, cn.text, cn.len);
|
gb_memmove(child.text+i, cn.text, cn.len);
|
||||||
|
|
||||||
map_set(&m->type_names, hash_pointer(field->type), child);
|
map_set(&m->type_names, hash_pointer(field->type), child);
|
||||||
ssa_gen_global_type_name(m, field, child);
|
ssa_gen_global_type_name(m, field, child);
|
||||||
@@ -4301,8 +4300,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// TODO(bill): Handle fallthrough scope exit correctly
|
|
||||||
// if (block != NULL && bs->token.kind != Token_fallthrough) {
|
|
||||||
if (block != NULL) {
|
if (block != NULL) {
|
||||||
ssa_emit_defer_stmts(proc, ssaDeferExit_Branch, block);
|
ssa_emit_defer_stmts(proc, ssaDeferExit_Branch, block);
|
||||||
}
|
}
|
||||||
@@ -4695,7 +4692,7 @@ void ssa_build_dom_tree(ssaProcedure *proc) {
|
|||||||
|
|
||||||
// Step 1 - number vertices
|
// Step 1 - number vertices
|
||||||
i32 pre_num = ssa_lt_depth_first_search(<, root, 0, preorder);
|
i32 pre_num = ssa_lt_depth_first_search(<, root, 0, preorder);
|
||||||
gb_memcopy(buckets, preorder, n*gb_size_of(preorder[0]));
|
gb_memmove(buckets, preorder, n*gb_size_of(preorder[0]));
|
||||||
|
|
||||||
for (i32 i = n-1; i > 0; i--) {
|
for (i32 i = n-1; i > 0; i--) {
|
||||||
ssaBlock *w = preorder[i];
|
ssaBlock *w = preorder[i];
|
||||||
|
|||||||
+27
-18
@@ -1,4 +1,3 @@
|
|||||||
// #define GB_NO_WINDOWS_H
|
|
||||||
#define GB_IMPLEMENTATION
|
#define GB_IMPLEMENTATION
|
||||||
#include "gb/gb.h"
|
#include "gb/gb.h"
|
||||||
|
|
||||||
@@ -36,9 +35,8 @@ String get_module_dir() {
|
|||||||
|
|
||||||
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
|
||||||
|
|
||||||
String16 str = {text, len};
|
|
||||||
GetModuleFileNameW(NULL, text, len);
|
GetModuleFileNameW(NULL, text, len);
|
||||||
String path = string16_to_string(gb_heap_allocator(), str);
|
String path = string16_to_string(gb_heap_allocator(), make_string16(text, len));
|
||||||
for (isize i = path.len-1; i >= 0; i--) {
|
for (isize i = path.len-1; i >= 0; i--) {
|
||||||
u8 c = path.text[i];
|
u8 c = path.text[i];
|
||||||
if (c == '/' || c == '\\') {
|
if (c == '/' || c == '\\') {
|
||||||
@@ -85,18 +83,22 @@ struct BlockTimer {
|
|||||||
|
|
||||||
|
|
||||||
// Hasing
|
// Hasing
|
||||||
|
enum HashKeyKind {
|
||||||
|
HashKey_Default,
|
||||||
|
HashKey_String,
|
||||||
|
};
|
||||||
|
|
||||||
struct HashKey {
|
struct HashKey {
|
||||||
union {
|
HashKeyKind kind;
|
||||||
u64 key;
|
u64 key;
|
||||||
void *ptr;
|
union {
|
||||||
};
|
|
||||||
b32 is_string;
|
|
||||||
String string; // if String, s.len > 0
|
String string; // if String, s.len > 0
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
gb_inline HashKey hashing_proc(void const *data, isize len) {
|
gb_inline HashKey hashing_proc(void const *data, isize len) {
|
||||||
HashKey h = {};
|
HashKey h = {};
|
||||||
|
h.kind = HashKey_Default;
|
||||||
// h.key = gb_murmur64(data, len);
|
// h.key = gb_murmur64(data, len);
|
||||||
h.key = gb_fnv64a(data, len);
|
h.key = gb_fnv64a(data, len);
|
||||||
return h;
|
return h;
|
||||||
@@ -104,22 +106,24 @@ gb_inline HashKey hashing_proc(void const *data, isize len) {
|
|||||||
|
|
||||||
gb_inline HashKey hash_string(String s) {
|
gb_inline HashKey hash_string(String s) {
|
||||||
HashKey h = hashing_proc(s.text, s.len);
|
HashKey h = hashing_proc(s.text, s.len);
|
||||||
h.is_string = true;
|
h.kind = HashKey_String;
|
||||||
h.string = s;
|
h.string = s;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline HashKey hash_pointer(void *ptr) {
|
gb_inline HashKey hash_pointer(void *ptr) {
|
||||||
uintptr p = cast(uintptr)ptr;
|
HashKey h = {};
|
||||||
HashKey h = {cast(u64)p};
|
h.key = cast(u64)cast(uintptr)ptr;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 hash_key_equal(HashKey a, HashKey b) {
|
b32 hash_key_equal(HashKey a, HashKey b) {
|
||||||
if (a.key == b.key) {
|
if (a.key == b.key) {
|
||||||
// NOTE(bill): If two string's hashes collide, compare the strings themselves
|
// NOTE(bill): If two string's hashes collide, compare the strings themselves
|
||||||
if (a.is_string) {
|
if (a.kind == HashKey_String) {
|
||||||
if (b.is_string) return a.string == b.string;
|
if (b.kind == HashKey_String) {
|
||||||
|
return a.string == b.string;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -156,7 +160,6 @@ i64 prev_pow2(i64 n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define gb_for_array(index_, array_) for (isize index_ = 0; (array_) != NULL && index_ < gb_array_count(array_); index_++)
|
|
||||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||||
|
|
||||||
|
|
||||||
@@ -169,10 +172,11 @@ i64 prev_pow2(i64 n) {
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
|
#define DLIST_APPEND(root_element, curr_element, next_element) do { \
|
||||||
if ((root_element) == NULL) \
|
if ((root_element) == NULL) { \
|
||||||
(root_element) = (curr_element) = (next_element); \
|
(root_element) = (curr_element) = (next_element); \
|
||||||
else \
|
} else { \
|
||||||
DLIST_SET(curr_element, next_element); \
|
DLIST_SET(curr_element, next_element); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
@@ -309,15 +313,17 @@ void map_rehash(Map<T> *h, isize new_count) {
|
|||||||
}
|
}
|
||||||
fr = map__find(&nh, e->key);
|
fr = map__find(&nh, e->key);
|
||||||
j = map__add_entry(&nh, e->key);
|
j = map__add_entry(&nh, e->key);
|
||||||
if (fr.entry_prev < 0)
|
if (fr.entry_prev < 0) {
|
||||||
nh.hashes[fr.hash_index] = j;
|
nh.hashes[fr.hash_index] = j;
|
||||||
else
|
} else {
|
||||||
nh.entries[fr.entry_prev].next = j;
|
nh.entries[fr.entry_prev].next = j;
|
||||||
|
}
|
||||||
nh.entries[j].next = fr.entry_index;
|
nh.entries[j].next = fr.entry_index;
|
||||||
nh.entries[j].value = e->value;
|
nh.entries[j].value = e->value;
|
||||||
if (map__full(&nh))
|
if (map__full(&nh)) {
|
||||||
map_grow(&nh);
|
map_grow(&nh);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
map_destroy(h);
|
map_destroy(h);
|
||||||
*h = nh;
|
*h = nh;
|
||||||
}
|
}
|
||||||
@@ -467,3 +473,6 @@ void multi_map_remove_all(Map<T> *h, HashKey key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -12,8 +12,8 @@ enum ExactValueKind {
|
|||||||
ExactValue_String,
|
ExactValue_String,
|
||||||
ExactValue_Integer,
|
ExactValue_Integer,
|
||||||
ExactValue_Float,
|
ExactValue_Float,
|
||||||
ExactValue_Pointer, // TODO(bill): Handle ExactValue_Pointer correctly
|
ExactValue_Pointer,
|
||||||
ExactValue_Compound,
|
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||||
|
|
||||||
ExactValue_Count,
|
ExactValue_Count,
|
||||||
};
|
};
|
||||||
|
|||||||
+25
-3
@@ -1,3 +1,5 @@
|
|||||||
|
#define VERSION_STRING "v0.0.3"
|
||||||
|
|
||||||
#include "common.cpp"
|
#include "common.cpp"
|
||||||
#include "profiler.cpp"
|
#include "profiler.cpp"
|
||||||
#include "unicode.cpp"
|
#include "unicode.cpp"
|
||||||
@@ -88,9 +90,20 @@ ArchData make_arch_data(ArchKind kind) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usage(char *argv0) {
|
||||||
|
gb_printf_err("%s is a tool for managing Odin source code\n", argv0);
|
||||||
|
gb_printf_err("Usage:");
|
||||||
|
gb_printf_err("\n\t%s command [arguments]\n", argv0);
|
||||||
|
gb_printf_err("Commands:");
|
||||||
|
gb_printf_err("\n\tbuild compile .odin file");
|
||||||
|
gb_printf_err("\n\trun compile and run .odin file");
|
||||||
|
gb_printf_err("\n\tversion print Odin version");
|
||||||
|
gb_printf_err("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
gb_printf_err("using: %s [run] <filename> \n", argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
prof_init();
|
prof_init();
|
||||||
@@ -104,11 +117,20 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
init_universal_scope();
|
init_universal_scope();
|
||||||
|
|
||||||
char *init_filename = argv[1];
|
char *init_filename = NULL;
|
||||||
b32 run_output = false;
|
b32 run_output = false;
|
||||||
if (gb_strncmp(argv[1], "run", 3) == 0) {
|
String arg1 = make_string(argv[1]);
|
||||||
|
if (arg1 == "run") {
|
||||||
run_output = true;
|
run_output = true;
|
||||||
init_filename = argv[2];
|
init_filename = argv[2];
|
||||||
|
} else if (arg1 == "build") {
|
||||||
|
init_filename = argv[2];
|
||||||
|
} else if (arg1 == "version") {
|
||||||
|
gb_printf("%s version %s", argv[0], VERSION_STRING);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
Parser parser = {0};
|
Parser parser = {0};
|
||||||
|
|
||||||
|
|||||||
+6
-12
@@ -37,10 +37,9 @@ struct AstFile {
|
|||||||
AstNode * curr_proc;
|
AstNode * curr_proc;
|
||||||
isize scope_level;
|
isize scope_level;
|
||||||
Scope * scope; // NOTE(bill): Created in checker
|
Scope * scope; // NOTE(bill): Created in checker
|
||||||
DeclInfo *decl_info; // NOTE(bill): Created in checker
|
DeclInfo * decl_info; // NOTE(bill): Created in checker
|
||||||
|
|
||||||
// TODO(bill): Error recovery
|
// TODO(bill): Error recovery
|
||||||
// NOTE(bill): Error recovery
|
|
||||||
#define PARSER_MAX_FIX_COUNT 6
|
#define PARSER_MAX_FIX_COUNT 6
|
||||||
isize fix_count;
|
isize fix_count;
|
||||||
TokenPos fix_prev_pos;
|
TokenPos fix_prev_pos;
|
||||||
@@ -483,11 +482,6 @@ Token ast_node_token(AstNode *node) {
|
|||||||
return empty_token;
|
return empty_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashKey hash_token(Token t) {
|
|
||||||
return hash_string(t.string);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++
|
// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++
|
||||||
AstNode *make_node(AstFile *f, AstNodeKind kind) {
|
AstNode *make_node(AstFile *f, AstNodeKind kind) {
|
||||||
gbArena *arena = &f->arena;
|
gbArena *arena = &f->arena;
|
||||||
@@ -2969,8 +2963,8 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
|||||||
defer (gb_free(gb_heap_allocator(), str));
|
defer (gb_free(gb_heap_allocator(), str));
|
||||||
|
|
||||||
isize i = 0;
|
isize i = 0;
|
||||||
gb_memcopy(str+i, base_dir.text, base_dir.len); i += base_dir.len;
|
gb_memmove(str+i, base_dir.text, base_dir.len); i += base_dir.len;
|
||||||
gb_memcopy(str+i, path.text, path.len);
|
gb_memmove(str+i, path.text, path.len);
|
||||||
str[str_len] = '\0';
|
str[str_len] = '\0';
|
||||||
return path_to_fullpath(a, make_string(str, str_len));
|
return path_to_fullpath(a, make_string(str, str_len));
|
||||||
}
|
}
|
||||||
@@ -2985,9 +2979,9 @@ String get_fullpath_core(gbAllocator a, String path) {
|
|||||||
u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
|
u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
|
||||||
defer (gb_free(gb_heap_allocator(), str));
|
defer (gb_free(gb_heap_allocator(), str));
|
||||||
|
|
||||||
gb_memcopy(str, module_dir.text, module_dir.len);
|
gb_memmove(str, module_dir.text, module_dir.len);
|
||||||
gb_memcopy(str+module_dir.len, core, core_len);
|
gb_memmove(str+module_dir.len, core, core_len);
|
||||||
gb_memcopy(str+module_dir.len+core_len, path.text, path.len);
|
gb_memmove(str+module_dir.len+core_len, path.text, path.len);
|
||||||
str[str_len] = '\0';
|
str[str_len] = '\0';
|
||||||
|
|
||||||
return path_to_fullpath(a, make_string(str, str_len));
|
return path_to_fullpath(a, make_string(str, str_len));
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
gb_global gbArena string_buffer_arena = {};
|
gb_global gbArena string_buffer_arena = {};
|
||||||
gb_global gbAllocator string_buffer_allocator = {};
|
gb_global gbAllocator string_buffer_allocator = {};
|
||||||
|
|
||||||
void init_string_buffer_memory() {
|
void init_string_buffer_memory(void) {
|
||||||
// NOTE(bill): This should be enough memory for file systems
|
// NOTE(bill): This should be enough memory for file systems
|
||||||
gb_arena_init_from_allocator(&string_buffer_arena, gb_heap_allocator(), gb_megabytes(1));
|
gb_arena_init_from_allocator(&string_buffer_arena, gb_heap_allocator(), gb_megabytes(1));
|
||||||
string_buffer_allocator = gb_arena_allocator(&string_buffer_arena);
|
string_buffer_allocator = gb_arena_allocator(&string_buffer_arena);
|
||||||
@@ -404,7 +404,7 @@ i32 unquote_string(gbAllocator a, String *s_) {
|
|||||||
buf[offset++] = cast(u8)r;
|
buf[offset++] = cast(u8)r;
|
||||||
} else {
|
} else {
|
||||||
isize size = gb_utf8_encode_rune(rune_temp, r);
|
isize size = gb_utf8_encode_rune(rune_temp, r);
|
||||||
gb_memcopy(buf+offset, rune_temp, size);
|
gb_memmove(buf+offset, rune_temp, size);
|
||||||
offset += size;
|
offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-14
@@ -158,8 +158,7 @@ Token empty_token = {Token_Invalid};
|
|||||||
Token blank_token = {Token_Identifier, {cast(u8 *)"_", 1}};
|
Token blank_token = {Token_Identifier, {cast(u8 *)"_", 1}};
|
||||||
|
|
||||||
Token make_token_ident(String s) {
|
Token make_token_ident(String s) {
|
||||||
Token t = {Token_Identifier};
|
Token t = {Token_Identifier, s};
|
||||||
t.string = s;
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +355,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
defer (gb_free(gb_heap_allocator(), c_str));
|
defer (gb_free(gb_heap_allocator(), c_str));
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(bill): Memory map rather than copy contents
|
||||||
gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);
|
gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);
|
||||||
gb_zero_item(t);
|
gb_zero_item(t);
|
||||||
if (fc.data != NULL) {
|
if (fc.data != NULL) {
|
||||||
@@ -368,8 +368,9 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
t->line_count = 1;
|
t->line_count = 1;
|
||||||
|
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == GB_RUNE_BOM)
|
if (t->curr_rune == GB_RUNE_BOM) {
|
||||||
advance_to_next_rune(t); // Ignore BOM at file beginning
|
advance_to_next_rune(t); // Ignore BOM at file beginning
|
||||||
|
}
|
||||||
|
|
||||||
array_init(&t->allocated_strings, gb_heap_allocator());
|
array_init(&t->allocated_strings, gb_heap_allocator());
|
||||||
|
|
||||||
@@ -389,9 +390,9 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
|
|||||||
return TokenizerInit_Permission;
|
return TokenizerInit_Permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb_file_size(&f) == 0)
|
if (gb_file_size(&f) == 0) {
|
||||||
return TokenizerInit_Empty;
|
return TokenizerInit_Empty;
|
||||||
|
}
|
||||||
|
|
||||||
return TokenizerInit_None;
|
return TokenizerInit_None;
|
||||||
}
|
}
|
||||||
@@ -413,12 +414,13 @@ void tokenizer_skip_whitespace(Tokenizer *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gb_inline i32 digit_value(Rune r) {
|
gb_inline i32 digit_value(Rune r) {
|
||||||
if (gb_char_is_digit(cast(char)r))
|
if (gb_char_is_digit(cast(char)r)) {
|
||||||
return r - '0';
|
return r - '0';
|
||||||
if (gb_is_between(cast(char)r, 'a', 'f'))
|
} else if (gb_is_between(cast(char)r, 'a', 'f')) {
|
||||||
return r - 'a' + 10;
|
return r - 'a' + 10;
|
||||||
if (gb_is_between(cast(char)r, 'A', 'F'))
|
} else if (gb_is_between(cast(char)r, 'A', 'F')) {
|
||||||
return r - 'A' + 10;
|
return r - 'A' + 10;
|
||||||
|
}
|
||||||
return 16; // NOTE(bill): Larger than highest possible
|
return 16; // NOTE(bill): Larger than highest possible
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,22 +428,21 @@ gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
|
|||||||
// TODO(bill): Allow for underscores in numbers as a number separator
|
// TODO(bill): Allow for underscores in numbers as a number separator
|
||||||
// TODO(bill): Is this a good idea?
|
// TODO(bill): Is this a good idea?
|
||||||
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
|
// while (digit_value(t->curr_rune) < base || t->curr_rune == '_')
|
||||||
while (digit_value(t->curr_rune) < base)
|
while (digit_value(t->curr_rune) < base) {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Token scan_number_to_token(Tokenizer *t, b32 seen_decimal_point) {
|
Token scan_number_to_token(Tokenizer *t, b32 seen_decimal_point) {
|
||||||
Token token = {};
|
Token token = {};
|
||||||
u8 *start_curr = t->curr;
|
|
||||||
token.kind = Token_Integer;
|
token.kind = Token_Integer;
|
||||||
token.string = make_string(start_curr, 1);
|
token.string = make_string(t->curr, 1);
|
||||||
token.pos.file = t->fullpath;
|
token.pos.file = t->fullpath;
|
||||||
token.pos.line = t->line_count;
|
token.pos.line = t->line_count;
|
||||||
token.pos.column = t->curr-t->line+1;
|
token.pos.column = t->curr-t->line+1;
|
||||||
|
|
||||||
if (seen_decimal_point) {
|
if (seen_decimal_point) {
|
||||||
start_curr--;
|
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
goto exponent;
|
goto exponent;
|
||||||
@@ -497,8 +498,9 @@ exponent:
|
|||||||
if (t->curr_rune == 'e' || t->curr_rune == 'E') {
|
if (t->curr_rune == 'e' || t->curr_rune == 'E') {
|
||||||
token.kind = Token_Float;
|
token.kind = Token_Float;
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == '-' || t->curr_rune == '+')
|
if (t->curr_rune == '-' || t->curr_rune == '+') {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,8 +625,9 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
curr_rune = t->curr_rune;
|
curr_rune = t->curr_rune;
|
||||||
if (rune_is_letter(curr_rune)) {
|
if (rune_is_letter(curr_rune)) {
|
||||||
token.kind = Token_Identifier;
|
token.kind = Token_Identifier;
|
||||||
while (rune_is_letter(t->curr_rune) || rune_is_digit(t->curr_rune))
|
while (rune_is_letter(t->curr_rune) || rune_is_digit(t->curr_rune)) {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
|
}
|
||||||
|
|
||||||
token.string.len = t->curr - token.string.text;
|
token.string.len = t->curr - token.string.text;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
// TODO(bill): Unicode support
|
|
||||||
b32 rune_is_letter(Rune r) {
|
b32 rune_is_letter(Rune r) {
|
||||||
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
|
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
|
||||||
r == '_') {
|
r == '_') {
|
||||||
@@ -24,8 +23,9 @@ b32 rune_is_letter(Rune r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b32 rune_is_digit(Rune r) {
|
b32 rune_is_digit(Rune r) {
|
||||||
if (r < 0x80 && gb_is_between(r, '0', '9'))
|
if (r < 0x80 && gb_is_between(r, '0', '9')) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return utf8proc_category(r) == UTF8PROC_CATEGORY_ND;
|
return utf8proc_category(r) == UTF8PROC_CATEGORY_ND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user