From cb59c1cf0805166d8b3230fea47d8674dacf157a Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 17 Jan 2017 18:47:38 +0000 Subject: [PATCH] Comma for all field separators; Overloaded procedures follow exportation rules --- code/demo.odin | 17 +-- core/_preload.odin | 112 +++++++++---------- core/fmt.odin | 36 +++---- core/mem.odin | 14 +-- core/sync.odin | 36 +++---- core/sys/windows.odin | 94 ++++++++-------- core/utf8.odin | 4 +- src/check_expr.c | 116 +++++++++++++++----- src/check_stmt.c | 16 +-- src/checker.c | 12 +-- src/entity.c | 5 +- src/parser.c | 244 +++++++++++++++++++++++++++++------------- src/tokenizer.c | 6 +- src/types.c | 12 ++- 14 files changed, 439 insertions(+), 285 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 9133e036d..1602450a1 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,23 +1,29 @@ #import "atomic.odin"; #import "fmt.odin"; +#import "hash.odin"; #import "math.odin"; #import "mem.odin"; +#import "opengl.odin"; +#import "os.odin"; +#import "sync.odin"; +#import "utf8.odin"; main :: proc() { - foo :: proc(x: ^int) { + foo :: proc(x: ^i32) { fmt.println("^int"); } foo :: proc(x: rawptr) { fmt.println("rawptr"); } - a: ^int; - b: ^f32; + a: i32; + b: f32; c: rawptr; - foo(a); - foo(b); + foo(^a); + foo(^b); foo(c); // foo(nil); + atomic.store(^a, 1); foo :: proc() { fmt.printf("Zero args\n"); @@ -32,7 +38,6 @@ main :: proc() { THINGI :: 14451; THINGF :: 14451.1; - foo(); foo(THINGI as int); foo(int(THINGI)); diff --git a/core/_preload.odin b/core/_preload.odin index 3edca3f48..bed8c953d 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -14,20 +14,20 @@ // IMPORTANT NOTE(bill): Do not change the order of any of this data // The compiler relies upon this _exact_ order Type_Info_Member :: struct #ordered { - name: string; // can be empty if tuple - type_info: ^Type_Info; - offset: int; // offsets are not used in tuples + name: string, // can be empty if tuple + type_info: ^Type_Info, + offset: int, // offsets are not used in tuples } Type_Info_Record :: struct #ordered { - fields: []Type_Info_Member; - size: int; // in bytes - align: int; // in bytes - packed: bool; - ordered: bool; + fields: []Type_Info_Member, + size: int, // in bytes + align: int, // in bytes + packed: bool, + ordered: bool, } Type_Info_Enum_Value :: raw_union { - f: f64; - i: i64; + f: f64, + i: i64, } // NOTE(bill): This much the same as the compiler's @@ -40,55 +40,55 @@ Calling_Convention :: enum { Type_Info :: union { Named: struct #ordered { - name: string; - base: ^Type_Info; // This will _not_ be a Type_Info.Named - }; + name: string, + base: ^Type_Info, // This will _not_ be a Type_Info.Named + }, Integer: struct #ordered { - size: int; // in bytes - signed: bool; - }; + size: int, // in bytes + signed: bool, + }, Float: struct #ordered { - size: int; // in bytes - }; - Any: struct #ordered {}; - String: struct #ordered {}; - Boolean: struct #ordered {}; + size: int, // in bytes + }, + Any: struct #ordered {}, + String: struct #ordered {}, + Boolean: struct #ordered {}, Pointer: struct #ordered { - elem: ^Type_Info; // nil -> rawptr - }; + elem: ^Type_Info, // nil -> rawptr + }, Maybe: struct #ordered { - elem: ^Type_Info; - }; + elem: ^Type_Info, + }, Procedure: struct #ordered { - params: ^Type_Info; // Type_Info.Tuple - results: ^Type_Info; // Type_Info.Tuple - variadic: bool; - convention: Calling_Convention; - }; + params: ^Type_Info, // Type_Info.Tuple + results: ^Type_Info, // Type_Info.Tuple + variadic: bool, + convention: Calling_Convention, + }, Array: struct #ordered { - elem: ^Type_Info; - elem_size: int; - count: int; - }; + elem: ^Type_Info, + elem_size: int, + count: int, + }, Slice: struct #ordered { - elem: ^Type_Info; - elem_size: int; - }; + elem: ^Type_Info, + elem_size: int, + }, Vector: struct #ordered { - elem: ^Type_Info; - elem_size: int; - count: int; - align: int; - }; - Tuple: Type_Info_Record; - Struct: Type_Info_Record; - Union: Type_Info_Record; - Raw_Union: Type_Info_Record; + elem: ^Type_Info, + elem_size: int, + count: int, + align: int, + }, + Tuple: Type_Info_Record, + Struct: Type_Info_Record, + Union: Type_Info_Record, + Raw_Union: Type_Info_Record, Enum: struct #ordered { - base: ^Type_Info; - names: []string; - values: []Type_Info_Enum_Value; - }; + base: ^Type_Info, + names: []string, + values: []Type_Info_Enum_Value, + }, } type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { @@ -137,17 +137,17 @@ Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64) -> rawptr; Allocator :: struct #ordered { - procedure: Allocator_Proc; - data: rawptr; + procedure: Allocator_Proc, + data: rawptr, } Context :: struct #ordered { - thread_id: int; + thread_id: int, - allocator: Allocator; + allocator: Allocator, - user_data: rawptr; - user_index: int; + user_data: rawptr, + user_index: int, } #thread_local __context: Context; diff --git a/core/fmt.odin b/core/fmt.odin index 47802abf1..46cffb90b 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -5,8 +5,8 @@ DEFAULT_BUFFER_SIZE :: 1<<12; Buffer :: struct { - data: []byte; - length: int; + data: []byte, + length: int, } buffer_write :: proc(buf: ^Buffer, b: []byte) { @@ -38,22 +38,22 @@ buffer_write_rune :: proc(buf: ^Buffer, r: rune) { } Fmt_Info :: struct { - minus: bool; - plus: bool; - space: bool; - zero: bool; - hash: bool; - width_set: bool; - prec_set: bool; + minus: bool, + plus: bool, + space: bool, + zero: bool, + hash: bool, + width_set: bool, + prec_set: bool, - width: int; - prec: int; + width: int, + prec: int, - reordered: bool; - good_arg_index: bool; + reordered: bool, + good_arg_index: bool, - buf: ^Buffer; - arg: any; // Temporary + buf: ^Buffer, + arg: any, // Temporary } @@ -827,9 +827,9 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6 generic_ftoa :: proc(buf: []byte, val: f64, verb: rune, prec, bit_size: int) -> []byte { Float_Info :: struct { - mantbits: uint; - expbits: uint; - bias: int; + mantbits: uint, + expbits: uint, + bias: int, }; f32info := Float_Info{23, 8, -127}; f64info := Float_Info{52, 11, -1023}; diff --git a/core/mem.odin b/core/mem.odin index ee358fef4..a8a38bc90 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -68,7 +68,7 @@ align_forward :: proc(ptr: rawptr, align: int) -> rawptr { Allocation_Header :: struct { - size: int; + size: int, } allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) { @@ -94,15 +94,15 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header { // Custom allocators Arena :: struct { - backing: Allocator; - offset: int; - memory: []byte; - temp_count: int; + backing: Allocator, + offset: int, + memory: []byte, + temp_count: int, } Arena_Temp_Memory :: struct { - arena: ^Arena; - original_count: int; + arena: ^Arena, + original_count: int, } diff --git a/core/sync.odin b/core/sync.odin index de13eec5e..ec223446e 100644 --- a/core/sync.odin +++ b/core/sync.odin @@ -2,14 +2,14 @@ #import "atomic.odin"; Semaphore :: struct { - handle: win32.HANDLE; + handle: win32.HANDLE, } Mutex :: struct { - semaphore: Semaphore; - counter: i32; - owner: i32; - recursion: i32; + semaphore: Semaphore, + counter: i32, + owner: i32, + recursion: i32, } current_thread_id :: proc() -> i32 { @@ -36,8 +36,8 @@ semaphore_wait :: proc(s: ^Semaphore) { mutex_init :: proc(m: ^Mutex) { - atomic.store32(^m.counter, 0); - atomic.store32(^m.owner, current_thread_id()); + atomic.store(^m.counter, 0); + atomic.store(^m.owner, current_thread_id()); semaphore_init(^m.semaphore); m.recursion = 0; } @@ -46,27 +46,27 @@ mutex_destroy :: proc(m: ^Mutex) { } mutex_lock :: proc(m: ^Mutex) { thread_id := current_thread_id(); - if atomic.fetch_add32(^m.counter, 1) > 0 { - if thread_id != atomic.load32(^m.owner) { + if atomic.fetch_add(^m.counter, 1) > 0 { + if thread_id != atomic.load(^m.owner) { semaphore_wait(^m.semaphore); } } - atomic.store32(^m.owner, thread_id); + atomic.store(^m.owner, thread_id); m.recursion += 1; } mutex_try_lock :: proc(m: ^Mutex) -> bool { thread_id := current_thread_id(); - if atomic.load32(^m.owner) == thread_id { - atomic.fetch_add32(^m.counter, 1); + if atomic.load(^m.owner) == thread_id { + atomic.fetch_add(^m.counter, 1); } else { expected: i32 = 0; - if atomic.load32(^m.counter) != 0 { + if atomic.load(^m.counter) != 0 { return false; } - if atomic.compare_exchange32(^m.counter, expected, 1) == 0 { + if atomic.compare_exchange(^m.counter, expected, 1) == 0 { return false; } - atomic.store32(^m.owner, thread_id); + atomic.store(^m.owner, thread_id); } m.recursion += 1; return true; @@ -74,15 +74,15 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool { mutex_unlock :: proc(m: ^Mutex) { recursion: i32; thread_id := current_thread_id(); - assert(thread_id == atomic.load32(^m.owner)); + assert(thread_id == atomic.load(^m.owner)); m.recursion -= 1; recursion = m.recursion; if recursion == 0 { - atomic.store32(^m.owner, thread_id); + atomic.store(^m.owner, thread_id); } - if atomic.fetch_add32(^m.counter, -1) > 1 { + if atomic.fetch_add(^m.counter, -1) > 1 { if recursion == 0 { semaphore_release(^m.semaphore); } diff --git a/core/sys/windows.odin b/core/sys/windows.odin index c5355b91c..959f96a54 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -16,7 +16,7 @@ LPARAM :: int; LRESULT :: int; ATOM :: i16; BOOL :: i32; -WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT; +WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE; @@ -56,61 +56,61 @@ SW_SHOW :: 5; POINT :: struct #ordered { - x, y: i32; + x, y: i32, } WNDCLASSEXA :: struct #ordered { - size, style: u32; - wnd_proc: WNDPROC; - cls_extra, wnd_extra: i32; - instance: HINSTANCE; - icon: HICON; - cursor: HCURSOR; - background: HBRUSH; - menu_name, class_name: ^u8; - sm: HICON; + size, style: u32, + wnd_proc: WNDPROC, + cls_extra, wnd_extra: i32, + instance: HINSTANCE, + icon: HICON, + cursor: HCURSOR, + background: HBRUSH, + menu_name, class_name: ^u8, + sm: HICON, } MSG :: struct #ordered { - hwnd: HWND; - message: u32; - wparam: WPARAM; - lparam: LPARAM; - time: u32; - pt: POINT; + hwnd: HWND, + message: u32, + wparam: WPARAM, + lparam: LPARAM, + time: u32, + pt: POINT, } RECT :: struct #ordered { - left: i32; - top: i32; - right: i32; - bottom: i32; + left: i32, + top: i32, + right: i32, + bottom: i32, } FILETIME :: struct #ordered { - lo, hi: u32; + lo, hi: u32, } BY_HANDLE_FILE_INFORMATION :: struct #ordered { - file_attributes: u32; + file_attributes: u32, creation_time, last_access_time, - last_write_time: FILETIME; + last_write_time: FILETIME, volume_serial_number, file_size_high, file_size_low, number_of_links, file_index_high, - file_index_low: u32; + file_index_low: u32, } FILE_ATTRIBUTE_DATA :: struct #ordered { - file_attributes: u32; + file_attributes: u32, creation_time, last_access_time, - last_write_time: FILETIME; + last_write_time: FILETIME, file_size_high, - file_size_low: u32; + file_size_low: u32, } GET_FILEEX_INFO_LEVELS :: i32; @@ -249,9 +249,9 @@ HEAP_ZERO_MEMORY :: 0x00000008; // Synchronization SECURITY_ATTRIBUTES :: struct #ordered { - length: u32; - security_descriptor: rawptr; - inherit_handle: BOOL; + length: u32, + security_descriptor: rawptr, + inherit_handle: BOOL, } INFINITE :: 0xffffffff; @@ -281,25 +281,23 @@ ReadBarrier :: proc() #foreign // GDI BITMAPINFOHEADER :: struct #ordered { - size: u32; - width, height: i32; - planes, bit_count: i16; - compression: u32; - size_image: u32; - x_pels_per_meter: i32; - y_pels_per_meter: i32; - clr_used: u32; - clr_important: u32; + size: u32, + width, height: i32, + planes, bit_count: i16, + compression: u32, + size_image: u32, + x_pels_per_meter: i32, + y_pels_per_meter: i32, + clr_used: u32, + clr_important: u32, } BITMAPINFO :: struct #ordered { - using header: BITMAPINFOHEADER; - colors: [1]RGBQUAD; + using header: BITMAPINFOHEADER, + colors: [1]RGBQUAD, } -RGBQUAD :: struct #ordered { - blue, green, red, reserved: byte; -} +RGBQUAD :: struct #ordered { blue, green, red, reserved: byte } BI_RGB :: 0; DIB_RGB_COLORS :: 0x00; @@ -354,7 +352,7 @@ wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribLi PIXELFORMATDESCRIPTOR :: struct #ordered { size, version, - flags: u32; + flags: u32, pixel_type, color_bits, @@ -375,11 +373,11 @@ PIXELFORMATDESCRIPTOR :: struct #ordered { stencil_bits, aux_buffers, layer_type, - reserved: byte; + reserved: byte, layer_mask, visible_mask, - damage_mask: u32; + damage_mask: u32, } GetDC :: proc(h: HANDLE) -> HDC #foreign diff --git a/core/utf8.odin b/core/utf8.odin index fca660e91..9bcc237a2 100644 --- a/core/utf8.odin +++ b/core/utf8.odin @@ -8,9 +8,7 @@ UTF_MAX :: 4; SURROGATE_MIN :: 0xd800; SURROGATE_MAX :: 0xdfff; -Accept_Range :: struct { - lo, hi: u8; -} +Accept_Range :: struct { lo, hi: u8 } accept_ranges := [5]Accept_Range{ {0x80, 0xbf}, diff --git a/src/check_expr.c b/src/check_expr.c index 7ee10f8e9..bd8183069 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -5,7 +5,7 @@ ExprKind check_expr_base (Checker *c, Operand *operand, AstNode * Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type); Type * check_type (Checker *c, AstNode *expression); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); -Entity * check_selector (Checker *c, Operand *operand, AstNode *node); +Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint); void check_not_tuple (Checker *c, Operand *operand); void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level); gbString expr_to_string (AstNode *expression); @@ -757,6 +757,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v p->flags &= ~FieldFlag_no_alias; // Remove the flag } } + for_array(j, p->names) { AstNode *name = p->names.e[j]; if (ast_node_expect(name, AstNode_Ident)) { @@ -779,6 +780,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v // Custom Calling convention for variadic parameters Entity *end = variables[variable_count-1]; end->type = make_type_slice(c->allocator, end->type); + end->flags |= EntityFlag_Ellipsis; } Type *tuple = make_type_tuple(c->allocator); @@ -874,10 +876,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type Scope *s = e->scope; bool skip = false; + Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); + map_entity_multi_get_all(&s->elements, key, procs); if (type_hint != NULL) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - Entity **procs = gb_alloc_array(c->tmp_allocator, Entity *, overload_count); - map_entity_multi_get_all(&s->elements, key, procs); // NOTE(bill): These should be done for (isize i = 0; i < overload_count; i++) { Type *t = base_type(procs[i]->type); @@ -899,12 +901,13 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type } if (!skip) { - o->mode = Addressing_Overload; - o->type = t_invalid; - o->overload_count = overload_count; - o->initial_overload_entity = e; + o->mode = Addressing_Overload; + o->type = t_invalid; + o->overload_count = overload_count; + o->overload_entities = procs; return; } + gb_free(heap_allocator(), procs); } add_entity_use(c, n, e); @@ -1040,7 +1043,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { case_ast_node(se, SelectorExpr, e); Operand o = {0}; - check_selector(c, &o, e); + check_selector(c, &o, e, NULL); switch (o.mode) { case Addressing_Invalid: @@ -2461,7 +2464,7 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val return true; } -Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { +Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) { ast_node(se, SelectorExpr, node); bool check_op_expr = true; @@ -2480,31 +2483,88 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { } if (op_expr->kind == AstNode_Ident) { + b32 is_not_exported = true; String name = op_expr->Ident.string; Entity *e = scope_lookup_entity(c->context.scope, name); + add_entity_use(c, op_expr, e); expr_entity = e; + if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) { String sel_name = selector->Ident.string; + check_op_expr = false; entity = scope_lookup_entity(e->ImportName.scope, sel_name); if (entity == NULL) { error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name)); goto error; } - if (entity->type == NULL) { // Not setup yet - check_entity_decl(c, entity, NULL, NULL); - } + check_entity_decl(c, entity, NULL, NULL); GB_ASSERT(entity->type != NULL); - b32 is_not_exported = true; - Entity **found = map_entity_get(&e->ImportName.scope->implicit, hash_string(sel_name)); - if (found == NULL) { + bool is_overloaded = false; + isize overload_count = 0; + HashKey key = {0}; + if (entity->kind == Entity_Procedure) { + key = hash_string(entity->token.string); + // NOTE(bill): Overloads are only allowed with the same scope + Scope *s = entity->scope; + overload_count = map_entity_multi_count(&s->elements, key); + if (overload_count > 1) { + is_overloaded = true; + } + } + + if (is_overloaded) { + Scope *s = entity->scope; + bool skip = false; + + Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); + map_entity_multi_get_all(&s->elements, key, procs); + for (isize i = 0; i < overload_count; /**/) { + Type *t = base_type(procs[i]->type); + if (t == t_invalid) { + continue; + } + + // NOTE(bill): Check to see if it's imported + if (map_bool_get(&e->ImportName.scope->implicit, hash_pointer(procs[i]))) { + gb_swap(Entity *, procs[i], procs[overload_count-1]); + overload_count--; + continue; + } + + Operand x = {0}; + x.mode = Addressing_Value; + x.type = t; + if (type_hint != NULL) { + if (check_is_assignable_to(c, &x, type_hint)) { + entity = procs[i]; + skip = true; + break; + } + } + + i++; + } + + if (overload_count > 0 && !skip) { + operand->mode = Addressing_Overload; + operand->type = t_invalid; + operand->expr = node; + operand->overload_count = overload_count; + operand->overload_entities = procs; + return procs[0]; + } + } + + bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)); + + if (!found) { is_not_exported = false; } else { - Entity *f = *found; - if (f->kind == Entity_ImportName) { + if (entity->kind == Entity_ImportName) { is_not_exported = true; } } @@ -2515,8 +2575,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { gb_string_free(sel_str); // NOTE(bill): Not really an error so don't goto error } - - add_entity_use(c, selector, entity); } } if (check_op_expr) { @@ -3606,16 +3664,15 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod if (operand->mode == Addressing_Overload) { - Scope *s = operand->initial_overload_entity->scope; - String name = operand->initial_overload_entity->token.string; - HashKey key = hash_string(name); + GB_ASSERT(operand->overload_entities != NULL && + operand->overload_count > 0); isize overload_count = operand->overload_count; - Entity ** procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); + Entity ** procs = operand->overload_entities; ValidProcAndScore *valids = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count); isize valid_count = 0; - map_entity_multi_get_all(&s->elements, key, procs); + String name = procs[0]->token.string; for (isize i = 0; i < overload_count; i++) { Entity *e = procs[i]; @@ -3666,9 +3723,13 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod } proc_type = t_invalid; } else { - GB_ASSERT(operand->expr->kind == AstNode_Ident); + AstNode *expr = operand->expr; + while (expr->kind == AstNode_SelectorExpr) { + expr = expr->SelectorExpr.selector; + } + GB_ASSERT(expr->kind == AstNode_Ident); Entity *e = procs[valids[0].index]; - add_entity_use(c, operand->expr, e); + add_entity_use(c, expr, e); proc_type = e->type; i64 score = 0; CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, true, &score); @@ -4473,7 +4534,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(se, SelectorExpr, node); - check_selector(c, o, node); + check_selector(c, o, node, type_hint); case_end; @@ -4763,7 +4824,6 @@ gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) { if (i > 0) { str = gb_string_appendc(str, sep); } - str = write_expr_to_string(str, params.e[i]); } return str; diff --git a/src/check_stmt.c b/src/check_stmt.c index e956bff81..b1f2a6d97 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -215,14 +215,9 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { if (op_a->mode == Addressing_Overload) { isize overload_count = op_a->overload_count; - Entity *entity = op_a->initial_overload_entity; - String name = entity->token.string; - Scope *s = entity->scope; - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - Entity **procs = gb_alloc_array(c->tmp_allocator, Entity *, overload_count); + Entity **procs = op_a->overload_entities; + GB_ASSERT(procs != NULL && overload_count > 0); - HashKey key = hash_string(name); - map_entity_multi_get_all(&s->elements, key, procs); // NOTE(bill): These should be done for (isize i = 0; i < overload_count; i++) { Type *t = base_type(procs[i]->type); @@ -238,15 +233,14 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { break; } } - gb_temp_arena_memory_end(tmp); if (e != NULL) { + // HACK TODO(bill): Should the entities be freed as it's technically a leak op_a->mode = Addressing_Value; op_a->type = e->type; op_a->overload_count = 0; - op_a->initial_overload_entity = NULL; + op_a->overload_entities = NULL; } - } else { if (node->kind == AstNode_Ident) { ast_node(i, Ident, node); @@ -1085,7 +1079,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { e = scope_lookup_entity(c->context.scope, name); } else if (expr->kind == AstNode_SelectorExpr) { Operand o = {0}; - e = check_selector(c, &o, expr); + e = check_selector(c, &o, expr, NULL); is_selector = true; } diff --git a/src/checker.c b/src/checker.c index 32e204c10..a3a6b63f4 100644 --- a/src/checker.c +++ b/src/checker.c @@ -28,7 +28,7 @@ typedef struct Operand { AstNode * expr; BuiltinProcId builtin_id; isize overload_count; - Entity * initial_overload_entity; + Entity ** overload_entities; } Operand; typedef struct TypeAndValue { @@ -93,7 +93,7 @@ typedef struct Scope { Scope * first_child; Scope * last_child; MapEntity elements; // Key: String - MapEntity implicit; // Key: String + MapBool implicit; // Key: Entity * Array(Scope *) shared; Array(Scope *) imported; @@ -344,7 +344,7 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) { Scope *s = gb_alloc_item(allocator, Scope); s->parent = parent; map_entity_init(&s->elements, heap_allocator()); - map_entity_init(&s->implicit, heap_allocator()); + map_bool_init(&s->implicit, heap_allocator()); array_init(&s->shared, heap_allocator()); array_init(&s->imported, heap_allocator()); @@ -371,7 +371,7 @@ void destroy_scope(Scope *scope) { } map_entity_destroy(&scope->elements); - map_entity_destroy(&scope->implicit); + map_bool_destroy(&scope->implicit); array_free(&scope->shared); array_free(&scope->imported); @@ -540,6 +540,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) { return NULL; } + void check_scope_usage(Checker *c, Scope *scope) { // TODO(bill): Use this? } @@ -1601,8 +1602,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { // NOTE(bill): Do not add other imported entities bool ok = add_entity(c, parent_scope, NULL, e); if (ok && id->is_import) { // `#import`ed entities don't get exported - HashKey key = hash_string(e->token.string); - map_entity_set(&parent_scope->implicit, key, e); + map_bool_set(&parent_scope->implicit, hash_pointer(e), true); } } } else { diff --git a/src/entity.c b/src/entity.c index 8cb43f5c2..449c25eeb 100644 --- a/src/entity.c +++ b/src/entity.c @@ -34,8 +34,9 @@ typedef enum EntityFlag { EntityFlag_Anonymous = 1<<2, EntityFlag_Field = 1<<3, EntityFlag_Param = 1<<4, - EntityFlag_VectorElem = 1<<5, - EntityFlag_NoAlias = 1<<6, + EntityFlag_Ellipsis = 1<<5, + EntityFlag_VectorElem = 1<<6, + EntityFlag_NoAlias = 1<<7, } EntityFlag; typedef enum OverloadKind { diff --git a/src/parser.c b/src/parser.c index fb386d0ee..3e5486a64 100644 --- a/src/parser.c +++ b/src/parser.c @@ -432,7 +432,10 @@ Token ast_node_token(AstNode *node) { case AstNode_CallExpr: return ast_node_token(node->CallExpr.proc); case AstNode_SelectorExpr: - return ast_node_token(node->SelectorExpr.selector); + if (node->SelectorExpr.selector != NULL) { + return ast_node_token(node->SelectorExpr.selector); + } + return node->SelectorExpr.token; case AstNode_IndexExpr: return node->IndexExpr.open; case AstNode_SliceExpr: @@ -1851,10 +1854,14 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { case Token_Ident: operand = make_selector_expr(f, token, operand, parse_identifier(f)); break; + case Token_Integer: + operand = make_selector_expr(f, token, operand, parse_expr(f, lhs)); + break; default: { syntax_error(f->curr_token, "Expected a selector"); next_token(f); - operand = make_selector_expr(f, f->curr_token, operand, NULL); + operand = make_bad_expr(f, ast_node_token(operand), f->curr_token); + // operand = make_selector_expr(f, f->curr_token, operand, NULL); } break; } } break; @@ -2046,7 +2053,7 @@ AstNodeArray parse_rhs_expr_list(AstFile *f) { return parse_expr_list(f, false); } -AstNodeArray parse_identifier_list(AstFile *f) { +AstNodeArray parse_ident_list(AstFile *f) { AstNodeArray list = make_ast_node_array(f); do { @@ -2227,106 +2234,189 @@ AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) return make_proc_type(f, proc_token, params, results, tags, cc); } +void parse_field_prefixes(AstFile *f, u32 flags, i32 *using_count, i32 *no_alias_count) { + while (f->curr_token.kind == Token_using || + f->curr_token.kind == Token_no_alias) { + if (allow_token(f, Token_using)) { + *using_count += 1; + } + if (allow_token(f, Token_no_alias)) { + *no_alias_count += 1; + } + } + if (*using_count > 1) { + syntax_error(f->curr_token, "Multiple `using` in this field list"); + *using_count = 1; + } + if (*no_alias_count > 1) { + syntax_error(f->curr_token, "Multiple `no_alias` in this field list"); + *no_alias_count = 1; + } +} + +bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) { + if (separator == Token_Semicolon) { + expect_semicolon(f, param); + } else { + if (!allow_token(f, separator)) { + return true; + } + } + return false; +} + +AstNodeArray convert_to_ident_list(AstFile *f, AstNodeArray list) { + AstNodeArray idents = {0}; + array_init_reserve(&idents, heap_allocator(), list.count); + // Convert to ident list + for_array(i, list) { + AstNode *ident = list.e[i]; + switch (ident->kind) { + case AstNode_Ident: + case AstNode_BadExpr: + break; + default: + error_node(ident, "Expected an identifier"); + ident = make_ident(f, blank_token); + break; + } + array_add(&idents, ident); + } + return idents; +} + +AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) { + if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) { + Token tok = f->curr_token; + next_token(f); + AstNode *type = parse_identifier_or_type(f); + if (type == NULL) { + error(tok, "variadic field missing type after `...`"); + type = make_bad_expr(f, tok, f->curr_token); + } + return make_ellipsis(f, tok, type); + } + AstNode *type = parse_type_attempt(f); + if (type == NULL) { + Token tok = f->curr_token; + error(tok, "Expected a type"); + type = make_bad_expr(f, tok, f->curr_token); + } + return type; +} + +void check_field_prefixes(AstFile *f, AstNodeArray names, u32 flags, i32 *using_count, i32 *no_alias_count) { + if (names.count > 1 && *using_count > 0) { + syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type"); + *using_count = 0; + } + + if ((flags&FieldFlag_using) == 0 && *using_count > 0) { + syntax_error(f->curr_token, "`using` is not allowed within this field list"); + *using_count = 0; + } + if ((flags&FieldFlag_no_alias) == 0 && *no_alias_count > 0) { + syntax_error(f->curr_token, "`no_alias` is not allowed within this field list"); + *no_alias_count = 0; + } + +} + +u32 field_prefixes_to_flags(i32 using_count, i32 no_alias_count) { + u32 field_flags = 0; + if (using_count > 0) field_flags |= FieldFlag_using; + if (no_alias_count > 0) field_flags |= FieldFlag_no_alias; + return field_flags; +} + AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags, TokenKind separator, TokenKind follow) { AstNodeArray params = make_ast_node_array(f); - isize name_count = 0; + AstNodeArray list = make_ast_node_array(f); + isize name_count = 0; + bool allow_ellipsis = flags&FieldFlag_ellipsis; + // TODO(bill): Allow for just a list of types + i32 using_count = 0; + i32 no_alias_count = 0; + parse_field_prefixes(f, flags, &using_count, &no_alias_count); while (f->curr_token.kind != follow && + f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { - i32 using_count = 0; - i32 no_alias_count = 0; - while (f->curr_token.kind == Token_using || - f->curr_token.kind == Token_no_alias) { - if (allow_token(f, Token_using)) { - using_count++; - } - if (allow_token(f, Token_no_alias)) { - no_alias_count++; - } - } - - - AstNodeArray names = parse_identifier_list(f); - if (names.count == 0) { - syntax_error(f->curr_token, "Empty field declaration"); + AstNode *param = parse_var_type(f, allow_ellipsis); + array_add(&list, param); + if (f->curr_token.kind != Token_Comma) { break; } + next_token(f); + } - if (names.count > 1 && using_count > 0) { - syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type"); - using_count = 0; + if (f->curr_token.kind == Token_Colon) { + AstNodeArray names = convert_to_ident_list(f, list); // Copy for semantic reasons + if (names.count == 0) { + syntax_error(f->curr_token, "Empty field declaration"); } - - if ((flags&FieldFlag_using) == 0 && using_count > 0) { - syntax_error(f->curr_token, "`using` is not allowed within this field list"); - using_count = 0; - } - if ((flags&FieldFlag_no_alias) == 0 && no_alias_count > 0) { - syntax_error(f->curr_token, "`no_alias` is not allowed within this field list"); - no_alias_count = 0; - } - if (using_count > 1) { - syntax_error(f->curr_token, "Multiple `using` in this field list"); - using_count = 1; - } - if (no_alias_count > 1) { - syntax_error(f->curr_token, "Multiple `no_alias` in this field list"); - no_alias_count = 1; - } - + check_field_prefixes(f, names, flags, &using_count, &no_alias_count); name_count += names.count; expect_token_after(f, Token_Colon, "field list"); - - AstNode *type = NULL; - if ((flags&FieldFlag_ellipsis) != 0 && f->curr_token.kind == Token_Ellipsis) { - Token ellipsis = f->curr_token; - next_token(f); - type = parse_type_attempt(f); - if (type == NULL) { - syntax_error(f->curr_token, "variadic field is missing a type after `..`"); - type = make_bad_expr(f, ellipsis, f->curr_token); - } else { - if (names.count > 1) { - syntax_error(f->curr_token, "mutliple variadic fields, only `..`"); - } else { - type = make_ellipsis(f, ellipsis, type); - } - } - } else { - type = parse_type_attempt(f); - } - - - if (type == NULL) { - syntax_error(f->curr_token, "Expected a type for this field declaration"); - } - - u32 flags = 0; - if (using_count > 0) flags |= FieldFlag_using; - if (no_alias_count > 0) flags |= FieldFlag_no_alias; - AstNode *param = make_field(f, names, type, flags); + AstNode *type = parse_var_type(f, allow_ellipsis); + AstNode *param = make_field(f, names, type, field_prefixes_to_flags(using_count, no_alias_count)); array_add(¶ms, param); - if (separator == Token_Semicolon) { - expect_semicolon(f, param); - } else { - if (!allow_token(f, separator)) { + parse_expect_separator(f, separator, type); + + while (f->curr_token.kind != follow && + f->curr_token.kind != Token_EOF) { + i32 using_count = 0; + i32 no_alias_count = 0; + parse_field_prefixes(f, flags, &using_count, &no_alias_count); + + AstNodeArray names = parse_ident_list(f); + if (names.count == 0) { + syntax_error(f->curr_token, "Empty field declaration"); + break; + } + check_field_prefixes(f, names, flags, &using_count, &no_alias_count); + name_count += names.count; + + expect_token_after(f, Token_Colon, "field list"); + AstNode *type = parse_var_type(f, allow_ellipsis); + + AstNode *param = make_field(f, names, type, field_prefixes_to_flags(using_count, no_alias_count)); + array_add(¶ms, param); + + if (parse_expect_separator(f, separator, param)) { break; } } + + if (name_count_) *name_count_ = name_count; + return params; + } + + check_field_prefixes(f, list, flags, &using_count, &no_alias_count); + for_array(i, list) { + AstNodeArray names = {0}; + AstNode *type = list.e[i]; + Token token = blank_token; + + array_init_count(&names, heap_allocator(), 1); + token.pos = ast_node_token(type).pos; + names.e[0] = make_ident(f, token); + + AstNode *param = make_field(f, names, list.e[i], field_prefixes_to_flags(using_count, no_alias_count)); + array_add(¶ms, param); } if (name_count_) *name_count_ = name_count; - return params; } AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) { - return parse_field_list(f, field_count_, flags, Token_Semicolon, Token_CloseBrace); + return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace); } AstNode *parse_identifier_or_type(AstFile *f) { @@ -2753,7 +2843,7 @@ AstNode *parse_for_stmt(AstFile *f) { } Token token = expect_token(f, Token_for); - AstNodeArray names = parse_identifier_list(f); + AstNodeArray names = parse_ident_list(f); parse_check_name_list_for_reserves(f, names); Token colon = expect_token_after(f, Token_Colon, "for name list"); diff --git a/src/tokenizer.c b/src/tokenizer.c index 2fb53e1e3..9c7a12ea3 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -529,7 +529,7 @@ fraction: // HACK(bill): This may be inefficient TokenizerState state = save_tokenizer_state(t); advance_to_next_rune(t); - if (t->curr_rune == '.') { + if (digit_value(t->curr_rune) >= 10) { // TODO(bill): Clean up this shit restore_tokenizer_state(t, &state); goto end; @@ -837,9 +837,9 @@ Token tokenizer_get_token(Tokenizer *t) { case '.': token.kind = Token_Period; // Default - if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number + /* if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number token = scan_number_to_token(t, true); - } else if (t->curr_rune == '.') { // Could be an ellipsis + } else */ if (t->curr_rune == '.') { // Could be an ellipsis advance_to_next_rune(t); if (t->curr_rune == '.') { advance_to_next_rune(t); diff --git a/src/types.c b/src/types.c index eb547256e..9981b197d 100644 --- a/src/types.c +++ b/src/types.c @@ -1759,9 +1759,17 @@ gbString write_type_to_string(gbString str, Type *type) { Entity *var = type->Tuple.variables[i]; if (var != NULL) { GB_ASSERT(var->kind == Entity_Variable); - if (i > 0) + if (i > 0) { str = gb_string_appendc(str, ", "); - str = write_type_to_string(str, var->type); + } + if (var->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(var->type); + str = gb_string_appendc(str, "..."); + GB_ASSERT(is_type_slice(var->type)); + str = write_type_to_string(str, slice->Slice.elem); + } else { + str = write_type_to_string(str, var->type); + } } } }