Comma for all field separators; Overloaded procedures follow exportation rules

This commit is contained in:
Ginger Bill
2017-01-17 18:47:38 +00:00
parent 383f5b55ad
commit cb59c1cf08
14 changed files with 439 additions and 285 deletions
+11 -6
View File
@@ -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));
+56 -56
View File
@@ -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;
+18 -18
View File
@@ -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};
+7 -7
View File
@@ -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,
}
+18 -18
View File
@@ -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);
}
+46 -48
View File
@@ -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
+1 -3
View File
@@ -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},
+88 -28
View File
@@ -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;
+5 -11
View File
@@ -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;
}
+6 -6
View File
@@ -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 {
+3 -2
View File
@@ -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 {
+167 -77
View File
@@ -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(&params, 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(&params, 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(&params, 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");
+3 -3
View File
@@ -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);
+10 -2
View File
@@ -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);
}
}
}
}