mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-21 21:24:59 -07:00
This commit is contained in:
+10
-5
@@ -5,18 +5,22 @@
|
||||
#import "mem.odin";
|
||||
#import "opengl.odin";
|
||||
#import "os.odin";
|
||||
#import "utf8.odin";
|
||||
|
||||
// #import "halloc.odin";
|
||||
|
||||
main :: proc() {
|
||||
x: f32 = false ? 123 : 55;
|
||||
fmt.println("Ternary:", x);
|
||||
m: map[int]int;
|
||||
m[123] = 312;
|
||||
fmt.println(m[123]);
|
||||
delete(m, 123);
|
||||
fmt.println(m[123]);
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Version 0.1.1
|
||||
|
||||
Added:
|
||||
* Dynamic Arrays [dynamic]Type`
|
||||
* Dynamic Arrays `[dynamic]Type`
|
||||
* Dynamic Maps `map[Key]Value`
|
||||
* Dynamic array and map literals
|
||||
* Custom struct alignemnt `struct #align 8 { bar: i8 }`
|
||||
@@ -29,6 +33,7 @@ main :: proc() {
|
||||
* immutable variables are "completely immutable" - rules need a full explanation
|
||||
* `slice_to_bytes` - convert any slice to a slice of bytes
|
||||
* `union_cast` allows for optional ok check
|
||||
* ?: ternary operator
|
||||
|
||||
Removed:
|
||||
* Maybe/option types
|
||||
|
||||
+44
-1
@@ -37,6 +37,7 @@ Calling_Convention :: enum {
|
||||
FAST = 3,
|
||||
}
|
||||
|
||||
/*
|
||||
Type_Info :: union {
|
||||
Named: struct #ordered {
|
||||
name: string,
|
||||
@@ -96,6 +97,48 @@ Type_Info :: union {
|
||||
count: int, // == 0 if dynamic
|
||||
},
|
||||
}
|
||||
*/
|
||||
Type_Info :: union {
|
||||
Named{name: string, base: ^Type_Info},
|
||||
Integer{size: int, signed: bool},
|
||||
Float{size: int},
|
||||
String{},
|
||||
Boolean{},
|
||||
Any{},
|
||||
Pointer{
|
||||
elem: ^Type_Info, // nil -> rawptr
|
||||
},
|
||||
Procedure{
|
||||
params: ^Type_Info, // Type_Info.Tuple
|
||||
results: ^Type_Info, // Type_Info.Tuple
|
||||
variadic: bool,
|
||||
convention: Calling_Convention,
|
||||
},
|
||||
Array{
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
count: int,
|
||||
},
|
||||
Dynamic_Array{elem: ^Type_Info, elem_size: int},
|
||||
Slice {elem: ^Type_Info, elem_size: int},
|
||||
Vector {elem: ^Type_Info, elem_size, count, align: int},
|
||||
Tuple {using record: Type_Info_Record}, // Only really used for procedures
|
||||
Struct {using record: Type_Info_Record},
|
||||
Union {using record: Type_Info_Record},
|
||||
Raw_Union {using record: Type_Info_Record},
|
||||
Enum{
|
||||
base: ^Type_Info,
|
||||
names: []string,
|
||||
values: []Type_Info_Enum_Value,
|
||||
},
|
||||
Map{
|
||||
key: ^Type_Info,
|
||||
value: ^Type_Info,
|
||||
generated_struct: ^Type_Info,
|
||||
count: int, // == 0 if dynamic
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// // NOTE(bill): only the ones that are needed (not all types)
|
||||
// // This will be set by the compiler
|
||||
@@ -633,7 +676,7 @@ __dynamic_map_add_entry :: proc(using h: __Map_Header, key: __Map_Key) -> int {
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_remove :: proc(using h: __Map_Header, key: __Map_Key) {
|
||||
__dynamic_map_delete :: proc(using h: __Map_Header, key: __Map_Key) {
|
||||
fr := __dynamic_map_find(h, key);
|
||||
if fr.entry_index >= 0 {
|
||||
__dynamic_map_erase(h, fr);
|
||||
|
||||
+9
-12
@@ -116,11 +116,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
||||
case ti == type_info(int): buffer_write_string(buf, "int");
|
||||
case ti == type_info(uint): buffer_write_string(buf, "uint");
|
||||
default:
|
||||
if info.signed {
|
||||
buffer_write_string(buf, "i");
|
||||
} else {
|
||||
buffer_write_string(buf, "u");
|
||||
}
|
||||
buffer_write_string(buf, info.signed ? "i" : "u");
|
||||
fi := Fmt_Info{buf = buf};
|
||||
fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
|
||||
}
|
||||
@@ -297,7 +293,7 @@ sprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
|
||||
|
||||
|
||||
|
||||
parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
|
||||
parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
|
||||
is_digit :: proc(r: rune) -> bool #inline {
|
||||
return '0' <= r && r <= '9';
|
||||
}
|
||||
@@ -320,7 +316,12 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
|
||||
return result, offset+i, i != 0;
|
||||
}
|
||||
|
||||
_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) {
|
||||
_arg_number :: proc(fi: ^Fmt_Info,
|
||||
arg_index: int,
|
||||
format: string,
|
||||
offset: int,
|
||||
arg_count: int,
|
||||
) -> (index: int, offset: int, ok: bool) {
|
||||
parse_arg_number :: proc(format: string) -> (int, int, bool) {
|
||||
if format.count < 3 {
|
||||
return 0, 1, false;
|
||||
@@ -396,11 +397,7 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
|
||||
fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
|
||||
match verb {
|
||||
case 't', 'v':
|
||||
if b {
|
||||
buffer_write_string(buf, "true");
|
||||
} else {
|
||||
buffer_write_string(buf, "false");
|
||||
}
|
||||
buffer_write_string(buf, b ? "true" : "false");
|
||||
default:
|
||||
fmt_bad_verb(fi, verb);
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
#foreign_system_library lib "opengl32.lib" when ODIN_OS == "windows";
|
||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
#import "sys/wgl.odin" when ODIN_OS == "windows";
|
||||
#load "opengl_constants.odin";
|
||||
|
||||
Clear :: proc(mask: u32) #foreign lib "glClear";
|
||||
@@ -35,7 +36,7 @@ _libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
|
||||
|
||||
GetProcAddress :: proc(name: string) -> proc() #cc_c {
|
||||
assert(name[name.count-1] == 0);
|
||||
res := win32.wglGetProcAddress(name.data);
|
||||
res := wgl.GetProcAddress(name.data);
|
||||
if res == nil {
|
||||
res = win32.GetProcAddress(_libgl, name.data);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
|
||||
#import . "windows.odin";
|
||||
|
||||
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||
CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||
CONTEXT_FLAGS_ARB :: 0x2094;
|
||||
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
||||
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
|
||||
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
||||
|
||||
HGLRC :: HANDLE;
|
||||
COLORREF :: u32;
|
||||
|
||||
LAYERPLANEDESCRIPTOR :: struct #ordered {
|
||||
size: u16,
|
||||
version: u16,
|
||||
flags: u32,
|
||||
pixel_type: byte,
|
||||
color_bits: byte,
|
||||
red_bits: byte,
|
||||
red_shift: byte,
|
||||
green_bits: byte,
|
||||
green_shift: byte,
|
||||
blue_bits: byte,
|
||||
blue_shift: byte,
|
||||
alpha_bits: byte,
|
||||
alpha_shift: byte,
|
||||
accum_bits: byte,
|
||||
accum_red_bits: byte,
|
||||
accum_green_bits: byte,
|
||||
accum_blue_bits: byte,
|
||||
accum_alpha_bits: byte,
|
||||
depth_bits: byte,
|
||||
stencil_bits: byte,
|
||||
aux_buffers: byte,
|
||||
layer_type: byte,
|
||||
reserved: byte,
|
||||
transparent: COLORREF,
|
||||
}
|
||||
|
||||
POINTFLOAT :: struct #ordered {
|
||||
x, y: f32,
|
||||
}
|
||||
|
||||
GLYPHMETRICSFLOAT :: struct #ordered {
|
||||
black_box_x: f32,
|
||||
black_box_y: f32,
|
||||
glyph_origin: POINTFLOAT,
|
||||
cell_inc_x: f32,
|
||||
cell_inc_y: f32,
|
||||
}
|
||||
|
||||
CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||
ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
|
||||
|
||||
|
||||
CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
|
||||
MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
|
||||
GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
|
||||
DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
|
||||
CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
|
||||
CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
|
||||
DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
|
||||
GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
|
||||
GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
|
||||
GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
|
||||
RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
|
||||
SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
|
||||
ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
|
||||
SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
|
||||
UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
|
||||
UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
|
||||
+6
-17
@@ -2,7 +2,6 @@
|
||||
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
|
||||
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
|
||||
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
|
||||
#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
|
||||
|
||||
HANDLE :: rawptr;
|
||||
HWND :: HANDLE;
|
||||
@@ -168,6 +167,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) ->
|
||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
|
||||
GetActiveWindow :: proc() -> HWND #foreign user32;
|
||||
|
||||
DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
|
||||
DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
|
||||
|
||||
|
||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||
r: i64;
|
||||
@@ -360,10 +362,6 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||
|
||||
HGLRC :: HANDLE;
|
||||
PROC :: #type proc() #cc_c;
|
||||
wglCreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
||||
|
||||
|
||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
size,
|
||||
@@ -396,23 +394,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
damage_mask: u32,
|
||||
}
|
||||
|
||||
GetDC :: proc(h: HANDLE) -> HDC #foreign user32;
|
||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign gdi32;
|
||||
GetDC :: proc(h: HWND) -> HDC #foreign user32;
|
||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
|
||||
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
|
||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
|
||||
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
|
||||
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001;
|
||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
|
||||
|
||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32;
|
||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
|
||||
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32;
|
||||
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32;
|
||||
|
||||
PROC :: #type proc() #cc_c;
|
||||
|
||||
|
||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
|
||||
|
||||
+265
-74
@@ -183,10 +183,7 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
|
||||
|
||||
// TODO(bill): Should I allow this implicit conversion at all?!
|
||||
// rawptr <- ^T
|
||||
if (is_type_rawptr(dst) && is_type_pointer(src)) {
|
||||
if (dst != type) {
|
||||
return -1;
|
||||
}
|
||||
if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) {
|
||||
return 5;
|
||||
}
|
||||
#endif
|
||||
@@ -358,7 +355,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
|
||||
Token name_token = name->Ident;
|
||||
|
||||
if (str_eq(name_token.string, str_lit(""))) {
|
||||
if (str_eq(name_token.string, str_lit("names"))) {
|
||||
error(name_token, "`names` is a reserved identifier for unions");
|
||||
continue;
|
||||
}
|
||||
@@ -599,22 +596,76 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
GB_ASSERT(is_type_union(union_type));
|
||||
ast_node(ut, UnionType, node);
|
||||
|
||||
isize field_count = 1;
|
||||
for_array(field_index, ut->fields) {
|
||||
AstNode *field = ut->fields.e[field_index];
|
||||
switch (field->kind) {
|
||||
case_ast_node(f, Field, field);
|
||||
field_count += f->names.count;
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
isize field_count = ut->fields.count+1;
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
MapEntity entity_map = {0};
|
||||
map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*field_count);
|
||||
|
||||
Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count);
|
||||
|
||||
check_fields(c, node, ut->fields, fields, field_count, str_lit("union"));
|
||||
isize field_index = 0;
|
||||
fields[field_index++] = make_entity_type_name(c->allocator, c->context.scope, empty_token, NULL);
|
||||
|
||||
union_type->Record.fields = fields;
|
||||
union_type->Record.field_count = field_count;
|
||||
for_array(i, ut->fields) {
|
||||
AstNode *field = ut->fields.e[i];
|
||||
if (field->kind != AstNode_UnionField) {
|
||||
continue;
|
||||
}
|
||||
ast_node(f, UnionField, ut->fields.e[i]);
|
||||
Token name_token = f->name->Ident;
|
||||
|
||||
if (str_eq(name_token.string, str_lit("names"))) {
|
||||
error(name_token, "`names` is a reserved identifier for unions");
|
||||
continue;
|
||||
}
|
||||
|
||||
Type *base_type = make_type_struct(c->allocator);
|
||||
{
|
||||
ast_node(fl, FieldList, f->list);
|
||||
isize field_count = 0;
|
||||
for_array(j, fl->list) {
|
||||
ast_node(f, Field, fl->list.e[j]);
|
||||
field_count += f->names.count;
|
||||
}
|
||||
|
||||
Token token = name_token;
|
||||
token.kind = Token_struct;
|
||||
AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, fl->list, field_count,
|
||||
false, true, NULL);
|
||||
|
||||
check_open_scope(c, dummy_struct);
|
||||
check_struct_type(c, base_type, dummy_struct);
|
||||
check_close_scope(c);
|
||||
base_type->Record.node = dummy_struct;
|
||||
}
|
||||
|
||||
Type *type = make_type_named(c->allocator, name_token.string, base_type, NULL);
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type);
|
||||
type->Named.type_name = e;
|
||||
add_entity(c, c->context.scope, f->name, e);
|
||||
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
error(name_token, "`_` cannot be used a union subtype");
|
||||
continue;
|
||||
}
|
||||
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(&entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(&entity_map, key, e);
|
||||
fields[field_index++] = e;
|
||||
}
|
||||
add_entity_use(c, f->name, e);
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
union_type->Record.fields = fields;
|
||||
union_type->Record.field_count = field_index;
|
||||
union_type->Record.names = make_names_field_for_record(c, c->context.scope);
|
||||
}
|
||||
|
||||
@@ -798,7 +849,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
}
|
||||
|
||||
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) {
|
||||
if (_params == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ast_node(field_list, FieldList, _params);
|
||||
AstNodeArray params = field_list->list;
|
||||
|
||||
if (params.count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -808,7 +865,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
|
||||
AstNode *field = params.e[i];
|
||||
if (ast_node_expect(field, AstNode_Field)) {
|
||||
ast_node(f, Field, field);
|
||||
variable_count += f->names.count;
|
||||
variable_count += max(f->names.count, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,26 +934,73 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
|
||||
return tuple;
|
||||
}
|
||||
|
||||
Type *check_get_results(Checker *c, Scope *scope, AstNodeArray results) {
|
||||
Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
if (_results == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ast_node(field_list, FieldList, _results);
|
||||
AstNodeArray results = field_list->list;
|
||||
|
||||
if (results.count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
Type *tuple = make_type_tuple(c->allocator);
|
||||
|
||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, results.count);
|
||||
isize variable_count = 0;
|
||||
for_array(i, results) {
|
||||
AstNode *field = results.e[i];
|
||||
if (ast_node_expect(field, AstNode_Field)) {
|
||||
ast_node(f, Field, field);
|
||||
variable_count += max(f->names.count, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
|
||||
isize variable_index = 0;
|
||||
for_array(i, results) {
|
||||
AstNode *item = results.e[i];
|
||||
Type *type = check_type(c, item);
|
||||
Token token = ast_node_token(item);
|
||||
token.string = str_lit(""); // NOTE(bill): results are not named
|
||||
// TODO(bill): Should I have named results?
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
// NOTE(bill): No need to record
|
||||
variables[variable_index++] = param;
|
||||
ast_node(field, Field, results.e[i]);
|
||||
Type *type = check_type(c, field->type);
|
||||
if (field->names.count == 0) {
|
||||
Token token = ast_node_token(field->type);
|
||||
token.string = str_lit("");
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
variables[variable_index++] = param;
|
||||
} else {
|
||||
for_array(j, field->names) {
|
||||
Token token = ast_node_token(field->type);
|
||||
token.string = str_lit("");
|
||||
|
||||
AstNode *name = field->names.e[j];
|
||||
if (name->kind != AstNode_Ident) {
|
||||
error_node(name, "Expected an identifer for as the field name");
|
||||
} else {
|
||||
token = name->Ident;
|
||||
}
|
||||
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
variables[variable_index++] = param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (isize i = 0; i < variable_index; i++) {
|
||||
String x = variables[i]->token.string;
|
||||
if (x.len == 0 || str_eq(x, str_lit("_"))) {
|
||||
continue;
|
||||
}
|
||||
for (isize j = i+1; j < variable_index; j++) {
|
||||
String y = variables[j]->token.string;
|
||||
if (y.len == 0 || str_eq(y, str_lit("_"))) {
|
||||
continue;
|
||||
}
|
||||
if (str_eq(x, y)) {
|
||||
error(variables[j]->token, "Duplicate return value name `%.*s`", LIT(y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tuple->Tuple.variables = variables;
|
||||
tuple->Tuple.variable_count = results.count;
|
||||
tuple->Tuple.variable_count = variable_index;
|
||||
|
||||
return tuple;
|
||||
}
|
||||
@@ -2514,6 +2618,39 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
|
||||
return true;
|
||||
}
|
||||
|
||||
isize entity_overload_count(Scope *s, String name) {
|
||||
Entity *e = scope_lookup_entity(s, name);
|
||||
if (e == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (e->kind == Entity_Procedure) {
|
||||
// NOTE(bill): Overloads are only allowed with the same scope
|
||||
return map_entity_multi_count(&s->elements, hash_string(e->token.string));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool check_is_field_exported(Checker *c, Entity *field) {
|
||||
if (field == NULL) {
|
||||
// NOTE(bill): Just incase
|
||||
return true;
|
||||
}
|
||||
if (field->kind != Entity_Variable) {
|
||||
return true;
|
||||
}
|
||||
Scope *file_scope = field->scope;
|
||||
if (file_scope == NULL) {
|
||||
return true;
|
||||
}
|
||||
while (!file_scope->is_file) {
|
||||
file_scope = file_scope->parent;
|
||||
}
|
||||
if (!is_entity_exported(field) && file_scope != c->context.file_scope) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
|
||||
ast_node(se, SelectorExpr, node);
|
||||
|
||||
@@ -2535,8 +2672,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
}
|
||||
|
||||
if (op_expr->kind == AstNode_Ident) {
|
||||
String name = op_expr->Ident.string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
String op_name = op_expr->Ident.string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, op_name);
|
||||
|
||||
add_entity_use(c, op_expr, e);
|
||||
expr_entity = e;
|
||||
@@ -2545,38 +2682,31 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
|
||||
// It pretty much needs to be in this order and this way
|
||||
// If you can clean this up, please do but be really careful
|
||||
|
||||
String sel_name = selector->Ident.string;
|
||||
String import_name = op_name;
|
||||
Scope *import_scope = e->ImportName.scope;
|
||||
String entity_name = selector->Ident.string;
|
||||
|
||||
check_op_expr = false;
|
||||
entity = scope_lookup_entity(e->ImportName.scope, sel_name);
|
||||
entity = scope_lookup_entity(import_scope, entity_name);
|
||||
bool is_declared = entity != NULL;
|
||||
if (is_declared) {
|
||||
if (entity->kind == Entity_Builtin) {
|
||||
// NOTE(bill): Builtin's are in the universe scope which is part of every scopes hierarchy
|
||||
// This means that we should just ignore the found result through it
|
||||
is_declared = false;
|
||||
} else if (entity->scope->is_global && !e->ImportName.scope->is_global) {
|
||||
} else if (entity->scope->is_global && !import_scope->is_global) {
|
||||
is_declared = false;
|
||||
}
|
||||
}
|
||||
if (!is_declared) {
|
||||
error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name));
|
||||
error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(entity_name), LIT(import_name));
|
||||
goto error;
|
||||
}
|
||||
check_entity_decl(c, entity, NULL, NULL);
|
||||
GB_ASSERT(entity->type != 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;
|
||||
}
|
||||
}
|
||||
isize overload_count = entity_overload_count(import_scope, entity_name);
|
||||
bool is_overloaded = overload_count > 1;
|
||||
|
||||
bool implicit_is_found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity)) != NULL;
|
||||
bool is_not_exported = !is_entity_exported(entity);
|
||||
@@ -2588,28 +2718,28 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
|
||||
if (is_not_exported) {
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(name));
|
||||
error_node(op_expr, "`%s` is not exported by `%.*s`", sel_str, LIT(import_name));
|
||||
gb_string_free(sel_str);
|
||||
// NOTE(bill): Not really an error so don't goto error
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (is_overloaded) {
|
||||
Scope *s = entity->scope;
|
||||
HashKey key = hash_string(entity_name);
|
||||
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; /**/) {
|
||||
map_entity_multi_get_all(&import_scope->elements, key, procs);
|
||||
for (isize i = 0; i < overload_count; i++) {
|
||||
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]))) {
|
||||
if (map_bool_get(&import_scope->implicit, hash_pointer(procs[i]))) {
|
||||
gb_swap(Entity *, procs[i], procs[overload_count-1]);
|
||||
overload_count--;
|
||||
i--; // NOTE(bill): Counteract the post event
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2623,8 +2753,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (overload_count > 0 && !skip) {
|
||||
@@ -2648,7 +2776,13 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
||||
|
||||
|
||||
if (entity == NULL && selector->kind == AstNode_Ident) {
|
||||
sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type);
|
||||
String field_name = selector->Ident.string;
|
||||
sel = lookup_field(c->allocator, operand->type, field_name, operand->mode == Addressing_Type);
|
||||
|
||||
if (operand->mode != Addressing_Type && !check_is_field_exported(c, sel.entity)) {
|
||||
error_node(op_expr, "`%.*s` is an unexported field", LIT(field_name));
|
||||
goto error;
|
||||
}
|
||||
entity = sel.entity;
|
||||
|
||||
// NOTE(bill): Add type info needed for fields like `names`
|
||||
@@ -2913,7 +3047,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
||||
} break;
|
||||
|
||||
case BuiltinProc_append: {
|
||||
// append :: proc([dynamic]Type, item: ...Type) {
|
||||
// append :: proc([dynamic]Type, item: ...Type)
|
||||
Type *type = operand->type;
|
||||
type = base_type(type);
|
||||
if (!is_type_dynamic_array(type)) {
|
||||
@@ -2943,6 +3077,37 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
||||
operand->type = t_int;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_delete: {
|
||||
// delete :: proc(map[Key]Value, key: Key)
|
||||
Type *type = operand->type;
|
||||
if (!is_type_map(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error_node(operand->expr, "Expected a map, got `%s`", str);
|
||||
gb_string_free(str);
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *key = base_type(type)->Map.key;
|
||||
Operand x = {Addressing_Invalid};
|
||||
AstNode *key_node = ce->args.e[1];
|
||||
Operand op = {0};
|
||||
check_expr(c, &op, key_node);
|
||||
if (op.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_is_assignable_to(c, &op, key)) {
|
||||
gbString kt = type_to_string(key);
|
||||
gbString ot = type_to_string(op.type);
|
||||
error_node(operand->expr, "Expected a key of type `%s`, got `%s`", key, ot);
|
||||
gb_string_free(ot);
|
||||
gb_string_free(kt);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_NoValue;
|
||||
} break;
|
||||
|
||||
|
||||
case BuiltinProc_size_of: {
|
||||
// size_of :: proc(Type) -> untyped int
|
||||
@@ -4381,10 +4546,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
String name = fv->field->Ident.string;
|
||||
|
||||
Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
bool is_unknown = sel.entity == NULL;
|
||||
if (is_unknown) {
|
||||
error_node(elem, "Unknown field `%.*s` in structure literal", LIT(name));
|
||||
continue;
|
||||
}
|
||||
if (!is_unknown && !check_is_field_exported(c, sel.entity)) {
|
||||
error_node(elem, "Cannot assign to an unexported field `%.*s` in structure literal", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (sel.index.count > 1) {
|
||||
error_node(elem, "Cannot assign to an anonymous field `%.*s` in a structure literal (at the moment)", LIT(name));
|
||||
@@ -4427,6 +4598,14 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
break;
|
||||
}
|
||||
|
||||
if (!check_is_field_exported(c, field)) {
|
||||
gbString t = type_to_string(type);
|
||||
error_node(o->expr, "Implicit assignment to an unexported field `%.*s` in `%s` literal",
|
||||
LIT(field->token.string), t);
|
||||
gb_string_free(t);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (base_type(field->type) == t_any) {
|
||||
is_constant = false;
|
||||
}
|
||||
@@ -5126,16 +5305,6 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) {
|
||||
|
||||
gbString write_expr_to_string(gbString str, AstNode *node);
|
||||
|
||||
gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
|
||||
for_array(i, params) {
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, sep);
|
||||
}
|
||||
str = write_expr_to_string(str, params.e[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
gbString write_record_fields_to_string(gbString str, AstNodeArray params) {
|
||||
for_array(i, params) {
|
||||
if (i > 0) {
|
||||
@@ -5301,6 +5470,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
if (f->flags&FieldFlag_using) {
|
||||
str = gb_string_appendc(str, "using ");
|
||||
}
|
||||
if (f->flags&FieldFlag_immutable) {
|
||||
str = gb_string_appendc(str, "immutable ");
|
||||
}
|
||||
if (f->flags&FieldFlag_no_alias) {
|
||||
str = gb_string_appendc(str, "no_alias ");
|
||||
}
|
||||
|
||||
for_array(i, f->names) {
|
||||
AstNode *name = f->names.e[i];
|
||||
if (i > 0) {
|
||||
@@ -5308,14 +5484,24 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
}
|
||||
str = write_expr_to_string(str, name);
|
||||
}
|
||||
|
||||
str = gb_string_appendc(str, ": ");
|
||||
if (f->names.count > 0) {
|
||||
str = gb_string_appendc(str, ": ");
|
||||
}
|
||||
if (f->flags&FieldFlag_ellipsis) {
|
||||
str = gb_string_appendc(str, "...");
|
||||
}
|
||||
str = write_expr_to_string(str, f->type);
|
||||
case_end;
|
||||
|
||||
case_ast_node(f, FieldList, node);
|
||||
for_array(i, f->list) {
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = write_expr_to_string(str, f->list.e[i]);
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CallExpr, node);
|
||||
str = write_expr_to_string(str, ce->proc);
|
||||
str = gb_string_appendc(str, "(");
|
||||
@@ -5332,7 +5518,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
|
||||
case_ast_node(pt, ProcType, node);
|
||||
str = gb_string_appendc(str, "proc(");
|
||||
str = write_params_to_string(str, pt->params, ", ");
|
||||
str = write_expr_to_string(str, pt->params);
|
||||
str = gb_string_appendc(str, ")");
|
||||
case_end;
|
||||
|
||||
@@ -5366,7 +5552,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_appendc(str, " ");
|
||||
}
|
||||
str = gb_string_appendc(str, "{");
|
||||
str = write_params_to_string(str, et->fields, ", ");
|
||||
for_array(i, et->fields) {
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = write_expr_to_string(str, et->fields.e[i]);
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef enum BuiltinProcId {
|
||||
BuiltinProc_reserve,
|
||||
BuiltinProc_clear,
|
||||
BuiltinProc_append,
|
||||
BuiltinProc_delete,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_size_of_val,
|
||||
@@ -73,6 +74,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT("reserve"), 2, false, Expr_Stmt},
|
||||
{STR_LIT("clear"), 1, false, Expr_Stmt},
|
||||
{STR_LIT("append"), 1, true, Expr_Expr},
|
||||
{STR_LIT("delete"), 2, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("size_of_val"), 1, false, Expr_Expr},
|
||||
@@ -259,6 +261,7 @@ typedef struct DelayedDecl {
|
||||
} DelayedDecl;
|
||||
|
||||
typedef struct CheckerContext {
|
||||
Scope * file_scope;
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
u32 stmt_state_flags;
|
||||
@@ -1016,6 +1019,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
|
||||
c->curr_ast_file = file;
|
||||
c->context.decl = file->decl_info;
|
||||
c->context.scope = file->scope;
|
||||
c->context.file_scope = file->scope;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,6 +1246,9 @@ void check_procedure_overloading(Checker *c, Entity *e) {
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
switch (kind) {
|
||||
case ProcOverload_Identical:
|
||||
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_CallingConvention:
|
||||
error(p->token, "Overloaded procedure `%.*s` as the same type as another procedure in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
@@ -1746,6 +1753,8 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
|
||||
|
||||
add_entity(c, parent_scope, NULL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ bool is_entity_kind_exported(EntityKind kind) {
|
||||
}
|
||||
|
||||
bool is_entity_exported(Entity *e) {
|
||||
// TODO(bill): Determine the actual exportation rules for imports of entities
|
||||
GB_ASSERT(e != NULL);
|
||||
if (!is_entity_kind_exported(e->kind)) {
|
||||
return false;
|
||||
|
||||
+1
-1
@@ -705,7 +705,7 @@ extern "C++" {
|
||||
#endif
|
||||
|
||||
#ifndef gb_is_between
|
||||
#define gb_is_between(x, lower, upper) (((x) >= (lower)) && ((x) <= (upper)))
|
||||
#define gb_is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
|
||||
#endif
|
||||
|
||||
#ifndef gb_abs
|
||||
|
||||
@@ -15,13 +15,14 @@ typedef Array(irValue *) irValueArray;
|
||||
#define MAP_NAME MapIrDebugInfo
|
||||
#include "map.c"
|
||||
|
||||
|
||||
typedef struct irModule {
|
||||
CheckerInfo * info;
|
||||
gbArena arena;
|
||||
gbArena tmp_arena;
|
||||
gbAllocator allocator;
|
||||
gbAllocator tmp_allocator;
|
||||
bool generate_debug_info;
|
||||
// bool generate_debug_info;
|
||||
|
||||
u32 stmt_state_flags;
|
||||
|
||||
@@ -29,20 +30,20 @@ typedef struct irModule {
|
||||
String layout;
|
||||
// String triple;
|
||||
|
||||
MapEntity min_dep_map; // Key: Entity *
|
||||
MapIrValue values; // Key: Entity *
|
||||
MapIrValue members; // Key: String
|
||||
MapString type_names; // Key: Type *
|
||||
MapIrDebugInfo debug_info; // Key: Unique pointer
|
||||
i32 global_string_index;
|
||||
i32 global_array_index; // For ConstantSlice
|
||||
MapEntity min_dep_map; // Key: Entity *
|
||||
MapIrValue values; // Key: Entity *
|
||||
MapIrValue members; // Key: String
|
||||
MapString type_names; // Key: Type *
|
||||
MapIrDebugInfo debug_info; // Key: Unique pointer
|
||||
i32 global_string_index;
|
||||
i32 global_array_index; // For ConstantSlice
|
||||
|
||||
Entity * entry_point_entity;
|
||||
Entity * entry_point_entity;
|
||||
|
||||
Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies
|
||||
irValueArray procs_to_generate; // NOTE(bill): Procedures to generate
|
||||
Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies
|
||||
irValueArray procs_to_generate; // NOTE(bill): Procedures to generate
|
||||
|
||||
Array(String) foreign_library_paths; // Only the ones that were used
|
||||
Array(String) foreign_library_paths; // Only the ones that were used
|
||||
} irModule;
|
||||
|
||||
// NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory)
|
||||
@@ -121,6 +122,7 @@ struct irProcedure {
|
||||
irTargetList * target_list;
|
||||
irValueArray referrers;
|
||||
|
||||
|
||||
i32 local_count;
|
||||
i32 instr_count;
|
||||
i32 block_count;
|
||||
@@ -134,90 +136,99 @@ struct irProcedure {
|
||||
|
||||
|
||||
#define IR_INSTR_KINDS \
|
||||
IR_INSTR_KIND(Comment, struct { String text; }) \
|
||||
IR_INSTR_KIND(Local, struct { \
|
||||
Entity * entity; \
|
||||
Type * type; \
|
||||
bool zero_initialized; \
|
||||
irValueArray referrers; \
|
||||
}) \
|
||||
IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \
|
||||
IR_INSTR_KIND(Store, struct { irValue *address, *value; }) \
|
||||
IR_INSTR_KIND(Comment, struct { String text; }) \
|
||||
IR_INSTR_KIND(Local, struct { \
|
||||
Entity * entity; \
|
||||
Type * type; \
|
||||
bool zero_initialized; \
|
||||
irValueArray referrers; \
|
||||
}) \
|
||||
IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \
|
||||
IR_INSTR_KIND(Store, struct { irValue *address, *value; }) \
|
||||
IR_INSTR_KIND(Load, struct { Type *type; irValue *address; }) \
|
||||
IR_INSTR_KIND(PtrOffset, struct { \
|
||||
irValue *address; \
|
||||
irValue *offset; \
|
||||
IR_INSTR_KIND(PtrOffset, struct { \
|
||||
irValue *address; \
|
||||
irValue *offset; \
|
||||
}) \
|
||||
IR_INSTR_KIND(ArrayElementPtr, struct { \
|
||||
irValue *address; \
|
||||
Type * result_type; \
|
||||
irValue *elem_index; \
|
||||
}) \
|
||||
IR_INSTR_KIND(StructElementPtr, struct { \
|
||||
irValue *address; \
|
||||
Type * result_type; \
|
||||
i32 elem_index; \
|
||||
}) \
|
||||
IR_INSTR_KIND(StructExtractValue, struct { \
|
||||
irValue *address; \
|
||||
Type * result_type; \
|
||||
i32 index; \
|
||||
}) \
|
||||
IR_INSTR_KIND(UnionTagPtr, struct { \
|
||||
irValue *address; \
|
||||
Type *type; /* ^int */ \
|
||||
}) \
|
||||
IR_INSTR_KIND(UnionTagValue, struct { \
|
||||
irValue *address; \
|
||||
Type *type; /* int */ \
|
||||
}) \
|
||||
IR_INSTR_KIND(Conv, struct { \
|
||||
irConvKind kind; \
|
||||
irValue *value; \
|
||||
Type *from, *to; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Jump, struct { irBlock *block; }) \
|
||||
IR_INSTR_KIND(If, struct { \
|
||||
irValue *cond; \
|
||||
irBlock *true_block; \
|
||||
irBlock *false_block; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Return, struct { irValue *value; }) \
|
||||
IR_INSTR_KIND(Select, struct { \
|
||||
irValue *cond; \
|
||||
irValue *true_value; \
|
||||
irValue *false_value; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \
|
||||
IR_INSTR_KIND(Unreachable, i32) \
|
||||
IR_INSTR_KIND(UnaryOp, struct { \
|
||||
Type * type; \
|
||||
TokenKind op; \
|
||||
irValue * expr; \
|
||||
}) \
|
||||
IR_INSTR_KIND(BinaryOp, struct { \
|
||||
Type * type; \
|
||||
TokenKind op; \
|
||||
irValue * left, *right; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Call, struct { \
|
||||
Type * type; /* return type */ \
|
||||
irValue * value; \
|
||||
irValue **args; \
|
||||
isize arg_count; \
|
||||
}) \
|
||||
IR_INSTR_KIND(StartupRuntime, i32) \
|
||||
IR_INSTR_KIND(BoundsCheck, struct { \
|
||||
TokenPos pos; \
|
||||
irValue *index; \
|
||||
irValue *len; \
|
||||
}) \
|
||||
IR_INSTR_KIND(SliceBoundsCheck, struct { \
|
||||
TokenPos pos; \
|
||||
irValue *low; \
|
||||
irValue *high; \
|
||||
bool is_substring; \
|
||||
}) \
|
||||
IR_INSTR_KIND(DebugDeclare, struct { \
|
||||
irDebugInfo *debug_info; \
|
||||
AstNode * expr; \
|
||||
Entity * entity; \
|
||||
bool is_addr; \
|
||||
irValue * value; \
|
||||
}) \
|
||||
IR_INSTR_KIND(ArrayElementPtr, struct { \
|
||||
irValue *address; \
|
||||
Type * result_type; \
|
||||
irValue *elem_index; \
|
||||
}) \
|
||||
IR_INSTR_KIND(StructElementPtr, struct { \
|
||||
irValue *address; \
|
||||
Type * result_type; \
|
||||
i32 elem_index; \
|
||||
}) \
|
||||
IR_INSTR_KIND(StructExtractValue, struct { \
|
||||
irValue *address; \
|
||||
Type * result_type; \
|
||||
i32 index; \
|
||||
}) \
|
||||
IR_INSTR_KIND(UnionTagPtr, struct { \
|
||||
irValue *address; \
|
||||
Type *type; /* ^int */ \
|
||||
}) \
|
||||
IR_INSTR_KIND(UnionTagValue, struct { \
|
||||
irValue *address; \
|
||||
Type *type; /* int */ \
|
||||
}) \
|
||||
IR_INSTR_KIND(Conv, struct { \
|
||||
irConvKind kind; \
|
||||
irValue *value; \
|
||||
Type *from, *to; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Jump, struct { irBlock *block; }) \
|
||||
IR_INSTR_KIND(If, struct { \
|
||||
irValue *cond; \
|
||||
irBlock *true_block; \
|
||||
irBlock *false_block; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Return, struct { irValue *value; }) \
|
||||
IR_INSTR_KIND(Select, struct { \
|
||||
irValue *cond; \
|
||||
irValue *true_value; \
|
||||
irValue *false_value; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Phi, struct { irValueArray edges; Type *type; }) \
|
||||
IR_INSTR_KIND(Unreachable, i32) \
|
||||
IR_INSTR_KIND(UnaryOp, struct { \
|
||||
Type * type; \
|
||||
TokenKind op; \
|
||||
irValue *expr; \
|
||||
}) \
|
||||
IR_INSTR_KIND(BinaryOp, struct { \
|
||||
Type * type; \
|
||||
TokenKind op; \
|
||||
irValue *left, *right; \
|
||||
}) \
|
||||
IR_INSTR_KIND(Call, struct { \
|
||||
Type * type; /* return type */ \
|
||||
irValue *value; \
|
||||
irValue **args; \
|
||||
isize arg_count; \
|
||||
}) \
|
||||
IR_INSTR_KIND(StartupRuntime, i32) \
|
||||
IR_INSTR_KIND(BoundsCheck, struct { \
|
||||
TokenPos pos; \
|
||||
irValue *index; \
|
||||
irValue *len; \
|
||||
}) \
|
||||
IR_INSTR_KIND(SliceBoundsCheck, struct { \
|
||||
TokenPos pos; \
|
||||
irValue *low; \
|
||||
irValue *high; \
|
||||
bool is_substring; \
|
||||
})
|
||||
|
||||
|
||||
|
||||
#define IR_CONV_KINDS \
|
||||
IR_CONV_KIND(trunc) \
|
||||
@@ -394,7 +405,6 @@ irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *m
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
typedef enum irDebugEncoding {
|
||||
irDebugBasicEncoding_Invalid = 0,
|
||||
|
||||
@@ -519,14 +529,19 @@ struct irDebugInfo {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct irGen {
|
||||
irModule module;
|
||||
gbFile output_file;
|
||||
bool opt_called;
|
||||
gbFile output_file;
|
||||
bool opt_called;
|
||||
} irGen;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Type *ir_type(irValue *value);
|
||||
Type *ir_instr_type(irInstr *instr) {
|
||||
switch (instr->kind) {
|
||||
@@ -948,6 +963,16 @@ irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue
|
||||
v->Instr.SliceBoundsCheck.is_substring = is_substring;
|
||||
return v;
|
||||
}
|
||||
irValue *ir_make_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) {
|
||||
irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare);
|
||||
v->Instr.DebugDeclare.debug_info = debug_info;
|
||||
v->Instr.DebugDeclare.expr = expr;
|
||||
v->Instr.DebugDeclare.entity = entity;
|
||||
v->Instr.DebugDeclare.is_addr = is_addr;
|
||||
v->Instr.DebugDeclare.value = value;
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -967,6 +992,23 @@ irValue *ir_make_value_constant_slice(gbAllocator a, Type *type, irValue *backin
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
irValue *ir_emit(irProcedure *proc, irValue *instr) {
|
||||
GB_ASSERT(instr->kind == irValue_Instr);
|
||||
irBlock *b = proc->curr_block;
|
||||
instr->Instr.parent = b;
|
||||
if (b != NULL) {
|
||||
irInstr *i = ir_get_last_instr(b);
|
||||
if (!ir_is_instr_terminating(i)) {
|
||||
array_add(&b->instrs, instr);
|
||||
}
|
||||
}
|
||||
return instr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
irValue *ir_make_const_int(gbAllocator a, i64 i) {
|
||||
return ir_make_value_constant(a, t_int, make_exact_value_integer(i));
|
||||
}
|
||||
@@ -1060,13 +1102,6 @@ void ir_add_block_to_proc(irProcedure *proc, irBlock *b) {
|
||||
b->index = proc->block_count++;
|
||||
}
|
||||
|
||||
|
||||
// irBlock *ir_add_block(irProcedure *proc, AstNode *node, char *label) {
|
||||
// irBlock *block = ir_new_block(proc, node, label);
|
||||
// ir_add_block_to_proc(proc, block);
|
||||
// return block;
|
||||
// }
|
||||
|
||||
void ir_start_block(irProcedure *proc, irBlock *block) {
|
||||
proc->curr_block = block;
|
||||
if (block != NULL) {
|
||||
@@ -1166,7 +1201,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
|
||||
|
||||
|
||||
|
||||
irValue *ir_add_local(irProcedure *proc, Entity *e) {
|
||||
irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) {
|
||||
irBlock *b = proc->decl_block; // all variables must be in the first block
|
||||
irValue *instr = ir_make_instr_local(proc, e, true);
|
||||
instr->Instr.parent = b;
|
||||
@@ -1178,6 +1213,11 @@ irValue *ir_add_local(irProcedure *proc, Entity *e) {
|
||||
ir_emit_zero_init(proc, instr);
|
||||
// }
|
||||
|
||||
if (expr != NULL) {
|
||||
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
ir_emit(proc, ir_make_instr_debug_declare(proc, di, expr, e, true, instr));
|
||||
}
|
||||
|
||||
return instr;
|
||||
}
|
||||
|
||||
@@ -1186,7 +1226,7 @@ irValue *ir_add_local_for_identifier(irProcedure *proc, AstNode *name, bool zero
|
||||
if (found) {
|
||||
Entity *e = *found;
|
||||
ir_emit_comment(proc, e->token.string);
|
||||
return ir_add_local(proc, e);
|
||||
return ir_add_local(proc, e, name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -1202,14 +1242,14 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type) {
|
||||
scope,
|
||||
empty_token,
|
||||
type, false);
|
||||
return ir_add_local(proc, e);
|
||||
return ir_add_local(proc, e, NULL);
|
||||
}
|
||||
|
||||
|
||||
irValue *ir_add_param(irProcedure *proc, Entity *e) {
|
||||
irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr) {
|
||||
irValue *v = ir_make_value_param(proc->module->allocator, proc, e);
|
||||
#if 1
|
||||
irValue *l = ir_add_local(proc, e);
|
||||
irValue *l = ir_add_local(proc, e, expr);
|
||||
ir_emit_store(proc, l, v);
|
||||
|
||||
#else
|
||||
@@ -1227,9 +1267,9 @@ irValue *ir_add_param(irProcedure *proc, Entity *e) {
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
|
||||
if (!proc->module->generate_debug_info) {
|
||||
return NULL;
|
||||
}
|
||||
// if (!proc->module->generate_debug_info) {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
GB_ASSERT(file != NULL);
|
||||
irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_File);
|
||||
@@ -1259,9 +1299,9 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
|
||||
|
||||
|
||||
irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) {
|
||||
if (!proc->module->generate_debug_info) {
|
||||
return NULL;
|
||||
}
|
||||
// if (!proc->module->generate_debug_info) {
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
GB_ASSERT(entity != NULL);
|
||||
irDebugInfo *di = ir_alloc_debug_info(proc->module->allocator, irDebugInfo_Proc);
|
||||
@@ -1281,18 +1321,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
irValue *ir_emit(irProcedure *proc, irValue *instr) {
|
||||
GB_ASSERT(instr->kind == irValue_Instr);
|
||||
irBlock *b = proc->curr_block;
|
||||
instr->Instr.parent = b;
|
||||
if (b != NULL) {
|
||||
irInstr *i = ir_get_last_instr(b);
|
||||
if (!ir_is_instr_terminating(i)) {
|
||||
array_add(&b->instrs, instr);
|
||||
}
|
||||
}
|
||||
return instr;
|
||||
}
|
||||
|
||||
irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
|
||||
#if 1
|
||||
// NOTE(bill): Sanity check
|
||||
@@ -3215,7 +3244,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
args[3] = capacity;
|
||||
return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
|
||||
} else if (is_type_dynamic_map(type)) {
|
||||
irValue **args = gb_alloc_array(a, irValue *, 4);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 2);
|
||||
args[0] = ir_gen_map_header(proc, ptr, type);
|
||||
args[1] = capacity;
|
||||
return ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
|
||||
@@ -3331,6 +3360,23 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
|
||||
} break;
|
||||
|
||||
case BuiltinProc_delete: {
|
||||
ir_emit_comment(proc, str_lit("delete"));
|
||||
irValue *map = ir_build_expr(proc, ce->args.e[0]);
|
||||
irValue *key = ir_build_expr(proc, ce->args.e[1]);
|
||||
Type *map_type = ir_type(map);
|
||||
GB_ASSERT(is_type_dynamic_map(map_type));
|
||||
Type *key_type = base_type(map_type)->Map.key;
|
||||
|
||||
irValue *addr = ir_address_from_load_or_generate_local(proc, map);
|
||||
|
||||
gbAllocator a = proc->module->allocator;
|
||||
irValue **args = gb_alloc_array(a, irValue *, 2);
|
||||
args[0] = ir_gen_map_header(proc, addr, map_type);
|
||||
args[1] = ir_gen_map_key(proc, key, key_type);
|
||||
return ir_emit_global_call(proc, "__dynamic_map_delete", args, 2);
|
||||
} break;
|
||||
|
||||
|
||||
case BuiltinProc_assert: {
|
||||
ir_emit_comment(proc, str_lit("assert"));
|
||||
@@ -5357,7 +5403,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
|
||||
irValue *tag_var = NULL;
|
||||
if (tag_var_entity != NULL) {
|
||||
tag_var = ir_add_local(proc, tag_var_entity);
|
||||
tag_var = ir_add_local(proc, tag_var_entity, NULL);
|
||||
} else {
|
||||
tag_var = ir_add_local_generated(proc, tag_var_type);
|
||||
}
|
||||
@@ -5385,7 +5431,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
|
||||
irValue *tag_var = NULL;
|
||||
if (tag_var_entity != NULL) {
|
||||
tag_var = ir_add_local(proc, tag_var_entity);
|
||||
tag_var = ir_add_local(proc, tag_var_entity, NULL);
|
||||
} else {
|
||||
tag_var = ir_add_local_generated(proc, tag_var_type);
|
||||
}
|
||||
@@ -5558,12 +5604,26 @@ void ir_begin_procedure_body(irProcedure *proc) {
|
||||
ir_start_block(proc, proc->entry_block);
|
||||
|
||||
if (proc->type->Proc.params != NULL) {
|
||||
ast_node(pt, ProcType, proc->type_expr);
|
||||
isize param_index = 0;
|
||||
isize q_index = 0;
|
||||
|
||||
TypeTuple *params = &proc->type->Proc.params->Tuple;
|
||||
for (isize i = 0; i < params->variable_count; i++) {
|
||||
ast_node(fl, FieldList, pt->params);
|
||||
GB_ASSERT(fl->list.count > 0);
|
||||
GB_ASSERT(fl->list.e[0]->kind == AstNode_Field);
|
||||
if (q_index == fl->list.e[param_index]->Field.names.count) {
|
||||
q_index = 0;
|
||||
param_index++;
|
||||
}
|
||||
ast_node(field, Field, fl->list.e[param_index]);
|
||||
AstNode *name = field->names.e[q_index++];
|
||||
|
||||
Entity *e = params->variables[i];
|
||||
if (!str_eq(e->token.string, str_lit("")) &&
|
||||
!str_eq(e->token.string, str_lit("_"))) {
|
||||
irValue *param = ir_add_param(proc, e);
|
||||
irValue *param = ir_add_param(proc, e, name);
|
||||
array_add(&proc->params, param);
|
||||
}
|
||||
}
|
||||
@@ -5790,7 +5850,7 @@ bool ir_gen_init(irGen *s, Checker *c) {
|
||||
}
|
||||
|
||||
ir_init_module(&s->module, c);
|
||||
s->module.generate_debug_info = false;
|
||||
// s->module.generate_debug_info = false;
|
||||
|
||||
// TODO(bill): generate appropriate output name
|
||||
int pos = cast(int)string_extension_position(c->parser->init_fullpath);
|
||||
@@ -6025,7 +6085,9 @@ void ir_gen_tree(irGen *s) {
|
||||
name = pd->link_name;
|
||||
}
|
||||
|
||||
irValue *p = ir_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
|
||||
AstNode *type_expr = decl->proc_lit->ProcLit.type;
|
||||
|
||||
irValue *p = ir_make_value_procedure(a, m, e, e->type, type_expr, body, name);
|
||||
p->Proc.tags = pd->tags;
|
||||
|
||||
ir_module_add_value(m, e, p);
|
||||
@@ -6067,7 +6129,6 @@ void ir_gen_tree(irGen *s) {
|
||||
for_array(i, m->debug_info.entries) {
|
||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i];
|
||||
irDebugInfo *di = entry->value;
|
||||
di->id = i;
|
||||
if (di->kind == irDebugInfo_Proc) {
|
||||
array_add(&all_procs->AllProcs.procs, di);
|
||||
}
|
||||
@@ -6406,10 +6467,11 @@ void ir_gen_tree(irGen *s) {
|
||||
case Type_Tuple: {
|
||||
ir_emit_comment(proc, str_lit("Type_Info_Tuple"));
|
||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr);
|
||||
irValue *record = ir_emit_struct_ep(proc, tag, 0);
|
||||
|
||||
{
|
||||
irValue *align = ir_make_const_int(a, type_align_of(a, t));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
|
||||
}
|
||||
|
||||
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index);
|
||||
@@ -6429,14 +6491,15 @@ void ir_gen_tree(irGen *s) {
|
||||
}
|
||||
}
|
||||
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
} break;
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct: {
|
||||
ir_emit_comment(proc, str_lit("Type_Info_Struct"));
|
||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr);
|
||||
irValue *record = ir_emit_struct_ep(proc, tag, 0);
|
||||
|
||||
{
|
||||
irValue *size = ir_make_const_int(a, type_size_of(a, t));
|
||||
@@ -6444,11 +6507,11 @@ void ir_gen_tree(irGen *s) {
|
||||
irValue *packed = ir_make_const_bool(a, t->Record.struct_is_packed);
|
||||
irValue *ordered = ir_make_const_bool(a, t->Record.struct_is_ordered);
|
||||
irValue *custom_align = ir_make_const_bool(a, t->Record.custom_align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), packed);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), ordered);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), custom_align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), packed);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 6), ordered);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 7), custom_align);
|
||||
}
|
||||
|
||||
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index);
|
||||
@@ -6475,28 +6538,52 @@ void ir_gen_tree(irGen *s) {
|
||||
ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
|
||||
}
|
||||
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
|
||||
} break;
|
||||
case TypeRecord_Union:
|
||||
case TypeRecord_Union: {
|
||||
ir_emit_comment(proc, str_lit("Type_Info_Union"));
|
||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr);
|
||||
irValue *record = ir_emit_struct_ep(proc, tag, 0);
|
||||
{
|
||||
irValue *size = ir_make_const_int(a, type_size_of(a, t));
|
||||
irValue *align = ir_make_const_int(a, type_align_of(a, t));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
|
||||
}
|
||||
break;
|
||||
|
||||
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index);
|
||||
irValue *memory_names = ir_type_info_member_offset(proc, type_info_member_names, t->Record.field_count, &type_info_member_names_index);
|
||||
|
||||
for (isize source_index = 1; source_index < t->Record.field_count; source_index++) {
|
||||
// TODO(bill): Order fields in source order not layout order
|
||||
Entity *f = t->Record.fields[source_index];
|
||||
irValue *tip = ir_get_type_info_ptr(proc, type_info_data, f->type);
|
||||
irValue *index = ir_make_const_int(a, source_index);
|
||||
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
|
||||
|
||||
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
|
||||
if (f->token.string.len > 0) {
|
||||
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
|
||||
ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
|
||||
}
|
||||
}
|
||||
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
|
||||
} break;
|
||||
case TypeRecord_RawUnion: {
|
||||
ir_emit_comment(proc, str_lit("Type_Info_RawUnion"));
|
||||
tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr);
|
||||
irValue *record = ir_emit_struct_ep(proc, tag, 0);
|
||||
|
||||
{
|
||||
irValue *size = ir_make_const_int(a, type_size_of(a, t));
|
||||
irValue *align = ir_make_const_int(a, type_align_of(a, t));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
|
||||
}
|
||||
|
||||
irValue *memory_types = ir_type_info_member_offset(proc, type_info_member_types, t->Record.field_count, &type_info_member_types_index);
|
||||
@@ -6516,9 +6603,9 @@ void ir_gen_tree(irGen *s) {
|
||||
}
|
||||
}
|
||||
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
|
||||
} break;
|
||||
case TypeRecord_Enum:
|
||||
ir_emit_comment(proc, str_lit("Type_Info_Enum"));
|
||||
@@ -6607,7 +6694,7 @@ void ir_gen_tree(irGen *s) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
GB_ASSERT(found);
|
||||
GB_ASSERT_MSG(found, "%s", type_to_string(tag_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6619,6 +6706,13 @@ void ir_gen_tree(irGen *s) {
|
||||
ir_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent);
|
||||
}
|
||||
|
||||
// Number debug info
|
||||
for_array(i, m->debug_info.entries) {
|
||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[i];
|
||||
irDebugInfo *di = entry->value;
|
||||
di->id = i;
|
||||
}
|
||||
|
||||
|
||||
// m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
|
||||
}
|
||||
|
||||
+45
-9
@@ -1254,6 +1254,29 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_fprintf(f, ")\n");
|
||||
} break;
|
||||
|
||||
case irInstr_DebugDeclare: {
|
||||
/* irInstrDebugDeclare *dd = &instr->DebugDeclare;
|
||||
Type *vt = ir_type(dd->value);
|
||||
irDebugInfo *di = dd->debug_info;
|
||||
Entity *e = dd->entity;
|
||||
String name = e->token.string;
|
||||
TokenPos pos = e->token.pos;
|
||||
// gb_printf("debug_declare %.*s\n", LIT(dd->entity->token.string));
|
||||
ir_fprintf(f, "call void @llvm.dbg.declare(");
|
||||
ir_fprintf(f, "metadata ");
|
||||
ir_print_type(f, m, vt);
|
||||
ir_fprintf(f, " ");
|
||||
ir_print_value(f, m, dd->value, vt);
|
||||
ir_fprintf(f, ", metadata !DILocalVariable(name: \"");
|
||||
ir_print_escape_string(f, name, false);
|
||||
ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line);
|
||||
ir_fprintf(f, ", metadata !DIExpression()");
|
||||
ir_fprintf(f, ")");
|
||||
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
|
||||
|
||||
ir_fprintf(f, "\n"); */
|
||||
} break;
|
||||
|
||||
|
||||
default: {
|
||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||
@@ -1326,11 +1349,14 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
}
|
||||
|
||||
|
||||
if (proc->module->generate_debug_info && proc->entity != NULL) {
|
||||
if (proc->entity != NULL) {
|
||||
if (proc->body != NULL) {
|
||||
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
||||
ir_fprintf(f, "!dbg !%d ", di->id);
|
||||
irDebugInfo **di_ = map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
|
||||
if (di_ != NULL) {
|
||||
irDebugInfo *di = *di_;
|
||||
GB_ASSERT(di->kind == irDebugInfo_Proc);
|
||||
// ir_fprintf(f, "!dbg !%d ", di->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1396,6 +1422,8 @@ void print_llvm_ir(irGen *ir) {
|
||||
ir_print_type(f, m, t_rawptr);
|
||||
ir_fprintf(f, "} ; Basic_any\n");
|
||||
|
||||
ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
|
||||
|
||||
|
||||
for_array(member_index, m->members.entries) {
|
||||
MapIrValueEntry *entry = &m->members.entries.e[member_index];
|
||||
@@ -1482,9 +1510,18 @@ void print_llvm_ir(irGen *ir) {
|
||||
|
||||
|
||||
#if 0
|
||||
if (m->generate_debug_info) {
|
||||
// if (m->generate_debug_info) {
|
||||
{
|
||||
ir_fprintf(f, "\n");
|
||||
|
||||
i32 diec = m->debug_info.entries.count;
|
||||
|
||||
ir_fprintf(f, "!llvm.dbg.cu = !{!0}\n");
|
||||
ir_fprintf(f, "!llvm.ident = !{!%d}\n", diec+3);
|
||||
ir_fprintf(f, "!%d = !{i32 2, !\"Dwarf Version\", i32 4}\n", diec+0);
|
||||
ir_fprintf(f, "!%d = !{i32 2, !\"Debug Info Version\", i32 3}\n", diec+1);
|
||||
ir_fprintf(f, "!%d = !{i32 1, !\"PIC Level\", i32 2}\n", diec+2);
|
||||
ir_fprintf(f, "!%d = !{!\"clang version 3.9.0 (branches/release_39)\"}\n", diec+3);
|
||||
|
||||
for_array(di_index, m->debug_info.entries) {
|
||||
MapIrDebugInfoEntry *entry = &m->debug_info.entries.e[di_index];
|
||||
@@ -1493,19 +1530,18 @@ void print_llvm_ir(irGen *ir) {
|
||||
|
||||
switch (di->kind) {
|
||||
case irDebugInfo_CompileUnit: {
|
||||
auto *cu = &di->CompileUnit;
|
||||
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(cu->file));
|
||||
irDebugInfo *file = *map_ir_debug_info_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||
ir_fprintf(f,
|
||||
"distinct !DICompileUnit("
|
||||
"language: DW_LANG_Go, " // Is this good enough?
|
||||
"file: !%d, "
|
||||
"producer: \"%.*s\", "
|
||||
"producer: \"clang version 3.9.0 (branches/release_39)\", "
|
||||
"flags: \"\", "
|
||||
"runtimeVersion: 0, "
|
||||
"isOptimized: false, "
|
||||
"emissionKind: FullDebug"
|
||||
")",
|
||||
file->id, LIT(cu->producer));
|
||||
file->id);
|
||||
|
||||
} break;
|
||||
case irDebugInfo_File:
|
||||
|
||||
+5
-4
@@ -2,6 +2,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include "common.c"
|
||||
#include "timings.c"
|
||||
#include "build_settings.c"
|
||||
@@ -223,10 +224,10 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssa_generate(&checker.info, &build_context);
|
||||
#endif
|
||||
#if 1
|
||||
|
||||
if (!ssa_generate(&checker.info)) {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
irGen ir_gen = {0};
|
||||
if (!ir_gen_init(&ir_gen, &checker)) {
|
||||
return 1;
|
||||
|
||||
+135
-140
@@ -302,16 +302,24 @@ AST_NODE_KIND(_DeclEnd, "", i32) \
|
||||
AstNode * type; \
|
||||
u32 flags; \
|
||||
}) \
|
||||
AST_NODE_KIND(FieldList, "field list", struct { \
|
||||
Token token; \
|
||||
AstNodeArray list; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionField, "union field", struct { \
|
||||
AstNode *name; \
|
||||
AstNode *list; \
|
||||
}) \
|
||||
AST_NODE_KIND(_TypeBegin, "", i32) \
|
||||
AST_NODE_KIND(HelperType, "type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcType, "procedure type", struct { \
|
||||
Token token; \
|
||||
AstNodeArray params; \
|
||||
AstNodeArray results; \
|
||||
u64 tags; \
|
||||
Token token; \
|
||||
AstNode *params; \
|
||||
AstNode *results; \
|
||||
u64 tags; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
}) \
|
||||
AST_NODE_KIND(PointerType, "pointer type", struct { \
|
||||
@@ -478,11 +486,16 @@ Token ast_node_token(AstNode *node) {
|
||||
case AstNode_ImportDecl: return node->ImportDecl.token;
|
||||
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
|
||||
|
||||
|
||||
case AstNode_Field:
|
||||
if (node->Field.names.count > 0) {
|
||||
return ast_node_token(node->Field.names.e[0]);
|
||||
}
|
||||
return ast_node_token(node->Field.type);
|
||||
case AstNode_FieldList:
|
||||
return node->FieldList.token;
|
||||
case AstNode_UnionField:
|
||||
return ast_node_token(node->UnionField.name);
|
||||
|
||||
case AstNode_HelperType: return node->HelperType.token;
|
||||
case AstNode_ProcType: return node->ProcType.token;
|
||||
@@ -952,6 +965,19 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) {
|
||||
AstNode *result = make_ast_node(f, AstNode_FieldList);
|
||||
result->FieldList.token = token;
|
||||
result->FieldList.list = list;
|
||||
return result;
|
||||
}
|
||||
AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
|
||||
AstNode *result = make_ast_node(f, AstNode_UnionField);
|
||||
result->UnionField.name = name;
|
||||
result->UnionField.list = list;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
|
||||
AstNode *result = make_ast_node(f, AstNode_HelperType);
|
||||
@@ -961,7 +987,7 @@ AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
|
||||
}
|
||||
|
||||
|
||||
AstNode *ast_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
|
||||
AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) {
|
||||
AstNode *result = make_ast_node(f, AstNode_ProcType);
|
||||
result->ProcType.token = token;
|
||||
result->ProcType.params = params;
|
||||
@@ -1002,7 +1028,7 @@ AstNode *ast_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
|
||||
}
|
||||
|
||||
AstNode *ast_struct_type(AstFile *f, Token token, AstNodeArray fields, isize field_count,
|
||||
bool is_packed, bool is_ordered, AstNode *align) {
|
||||
bool is_packed, bool is_ordered, AstNode *align) {
|
||||
AstNode *result = make_ast_node(f, AstNode_StructType);
|
||||
result->StructType.token = token;
|
||||
result->StructType.fields = fields;
|
||||
@@ -1308,7 +1334,6 @@ AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *fore
|
||||
AstNodeArray parse_stmt_list(AstFile *f);
|
||||
AstNode * parse_stmt(AstFile *f);
|
||||
AstNode * parse_body(AstFile *f);
|
||||
void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
|
||||
|
||||
|
||||
|
||||
@@ -1949,19 +1974,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_Question:
|
||||
if (!lhs && operand != NULL && f->expr_level >= 0) {
|
||||
AstNode *cond = operand;
|
||||
Token token_q = expect_token(f, Token_Question);
|
||||
AstNode *x = parse_expr(f, false);
|
||||
Token token_c = expect_token(f, Token_Colon);
|
||||
AstNode *y = parse_expr(f, false);
|
||||
operand = ast_ternary_expr(f, cond, x, y);
|
||||
} else {
|
||||
loop = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
loop = false;
|
||||
break;
|
||||
@@ -2016,22 +2028,24 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
||||
// NOTE(bill): result == priority
|
||||
i32 token_precedence(TokenKind t) {
|
||||
switch (t) {
|
||||
case Token_CmpOr:
|
||||
case Token_Question:
|
||||
return 1;
|
||||
case Token_CmpAnd:
|
||||
case Token_CmpOr:
|
||||
return 2;
|
||||
case Token_CmpAnd:
|
||||
return 3;
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
case Token_Lt:
|
||||
case Token_Gt:
|
||||
case Token_LtEq:
|
||||
case Token_GtEq:
|
||||
return 3;
|
||||
return 4;
|
||||
case Token_Add:
|
||||
case Token_Sub:
|
||||
case Token_Or:
|
||||
case Token_Xor:
|
||||
return 4;
|
||||
return 5;
|
||||
case Token_Mul:
|
||||
case Token_Quo:
|
||||
case Token_Mod:
|
||||
@@ -2039,51 +2053,42 @@ i32 token_precedence(TokenKind t) {
|
||||
case Token_AndNot:
|
||||
case Token_Shl:
|
||||
case Token_Shr:
|
||||
return 5;
|
||||
// case Token_as:
|
||||
// case Token_transmute:
|
||||
// case Token_down_cast:
|
||||
// case Token_union_cast:
|
||||
// return 6;
|
||||
return 6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
AstNode *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
|
||||
AstNode *expression = parse_unary_expr(f, lhs);
|
||||
AstNode *expr = parse_unary_expr(f, lhs);
|
||||
for (i32 prec = token_precedence(f->curr_token.kind); prec >= prec_in; prec--) {
|
||||
for (;;) {
|
||||
AstNode *right;
|
||||
Token op = f->curr_token;
|
||||
i32 op_prec = token_precedence(op.kind);
|
||||
if (op_prec != prec) {
|
||||
// NOTE(bill): This will also catch operators that are not valid "binary" operators
|
||||
break;
|
||||
}
|
||||
expect_operator(f); // NOTE(bill): error checks too
|
||||
if (lhs) {
|
||||
// TODO(bill): error checking
|
||||
lhs = false;
|
||||
}
|
||||
|
||||
switch (op.kind) {
|
||||
/* case Token_as:
|
||||
case Token_transmute:
|
||||
case Token_down_cast:
|
||||
case Token_union_cast:
|
||||
right = parse_type(f);
|
||||
break; */
|
||||
|
||||
default:
|
||||
right = parse_binary_expr(f, false, prec+1);
|
||||
if (op.kind == Token_Question) {
|
||||
AstNode *cond = expr;
|
||||
// Token_Question
|
||||
AstNode *x = parse_expr(f, lhs);
|
||||
Token token_c = expect_token(f, Token_Colon);
|
||||
AstNode *y = parse_expr(f, lhs);
|
||||
expr = ast_ternary_expr(f, cond, x, y);
|
||||
} else {
|
||||
AstNode *right = parse_binary_expr(f, false, prec+1);
|
||||
if (!right) {
|
||||
syntax_error(op, "Expected expression on the right hand side of the binary operator");
|
||||
syntax_error(op, "Expected expression on the right-hand side of the binary operator");
|
||||
}
|
||||
break;
|
||||
expr = ast_binary_expr(f, op, expr, right);
|
||||
}
|
||||
expression = ast_binary_expr(f, op, expression, right);
|
||||
|
||||
lhs = false;
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
return expr;
|
||||
}
|
||||
|
||||
AstNode *parse_expr(AstFile *f, bool lhs) {
|
||||
@@ -2278,15 +2283,39 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
|
||||
return parse_body(f);
|
||||
}
|
||||
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
|
||||
|
||||
|
||||
AstNode *parse_results(AstFile *f) {
|
||||
if (!allow_token(f, Token_ArrowRight)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (f->curr_token.kind != Token_OpenParen) {
|
||||
Token begin_token = f->curr_token;
|
||||
AstNodeArray empty_names = {0};
|
||||
AstNodeArray list = make_ast_node_array(f);
|
||||
AstNode *type = parse_type(f);
|
||||
array_add(&list, ast_field(f, empty_names, type, 0));
|
||||
return ast_field_list(f, begin_token, list);
|
||||
}
|
||||
|
||||
AstNode *list = NULL;
|
||||
expect_token(f, Token_OpenParen);
|
||||
list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
return list;
|
||||
}
|
||||
|
||||
AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
|
||||
AstNodeArray params = {0};
|
||||
AstNodeArray results = {0};
|
||||
AstNode *params = {0};
|
||||
AstNode *results = {0};
|
||||
|
||||
Token proc_token = expect_token(f, Token_proc);
|
||||
parse_proc_signature(f, ¶ms, &results);
|
||||
expect_token(f, Token_OpenParen);
|
||||
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
results = parse_results(f);
|
||||
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
@@ -2424,8 +2453,9 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
|
||||
return idents;
|
||||
}
|
||||
|
||||
AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||
TokenKind separator, TokenKind follow) {
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
|
||||
Token start_token = f->curr_token;
|
||||
|
||||
AstNodeArray params = make_ast_node_array(f);
|
||||
AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill):
|
||||
isize total_name_count = 0;
|
||||
@@ -2485,7 +2515,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||
}
|
||||
|
||||
if (name_count_) *name_count_ = total_name_count;
|
||||
return params;
|
||||
return ast_field_list(f, start_token, params);
|
||||
}
|
||||
|
||||
for_array(i, list) {
|
||||
@@ -2503,11 +2533,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
|
||||
}
|
||||
|
||||
if (name_count_) *name_count_ = total_name_count;
|
||||
return params;
|
||||
return ast_field_list(f, start_token, params);
|
||||
}
|
||||
|
||||
|
||||
AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
|
||||
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
|
||||
return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
|
||||
}
|
||||
|
||||
@@ -2637,29 +2667,59 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
|
||||
AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
AstNodeArray decls = {0};
|
||||
if (fields != NULL) {
|
||||
GB_ASSERT(fields->kind == AstNode_FieldList);
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
|
||||
} break;
|
||||
|
||||
case Token_union: {
|
||||
Token token = expect_token(f, Token_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "union");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union"));
|
||||
AstNodeArray variants = make_ast_node_array(f);
|
||||
|
||||
while (f->curr_token.kind != Token_CloseBrace &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
AstNode *name = parse_ident(f);
|
||||
Token open = expect_token(f, Token_OpenBrace);
|
||||
isize decl_count = 0;
|
||||
AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
array_add(&variants, ast_union_field(f, name, list));
|
||||
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
break;
|
||||
}
|
||||
next_token(f);
|
||||
}
|
||||
|
||||
// AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return ast_union_type(f, token, decls, decl_count);
|
||||
|
||||
return ast_union_type(f, token, variants, variants.count);
|
||||
}
|
||||
|
||||
case Token_raw_union: {
|
||||
Token token = expect_token(f, Token_raw_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
|
||||
AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
AstNodeArray decls = {0};
|
||||
if (fields != NULL) {
|
||||
GB_ASSERT(fields->kind == AstNode_FieldList);
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_raw_union_type(f, token, decls, decl_count);
|
||||
}
|
||||
|
||||
@@ -2699,39 +2759,6 @@ AstNode *parse_type_or_ident(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
AstNodeArray parse_results(AstFile *f) {
|
||||
AstNodeArray results = make_ast_node_array(f);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
if (f->curr_token.kind == Token_OpenParen) {
|
||||
expect_token(f, Token_OpenParen);
|
||||
while (f->curr_token.kind != Token_CloseParen &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
array_add(&results, parse_type(f));
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
break;
|
||||
}
|
||||
next_token(f);
|
||||
}
|
||||
expect_token(f, Token_CloseParen);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
array_add(&results, parse_type(f));
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void parse_proc_signature(AstFile *f,
|
||||
AstNodeArray *params,
|
||||
AstNodeArray *results) {
|
||||
expect_token(f, Token_OpenParen);
|
||||
*params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
*results = parse_results(f);
|
||||
}
|
||||
|
||||
AstNode *parse_body(AstFile *f) {
|
||||
AstNodeArray stmts = {0};
|
||||
Token open, close;
|
||||
@@ -2747,48 +2774,6 @@ AstNode *parse_body(AstFile *f) {
|
||||
return ast_block_stmt(f, stmts, open, close);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
AstNode *parse_proc_decl(AstFile *f) {
|
||||
if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
|
||||
// NOTE(bill): It's an anonymous procedure
|
||||
// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
|
||||
// but is that a problem in practice?
|
||||
return ast_expr_stmt(f, parse_expr(f, true));
|
||||
}
|
||||
|
||||
AstNodeArray params = {0};
|
||||
AstNodeArray results = {0};
|
||||
|
||||
Token proc_token = expect_token(f, Token_proc);
|
||||
AstNode *name = parse_ident(f);
|
||||
parse_proc_signature(f, ¶ms, &results);
|
||||
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
ProcCallingConvention cc = ProcCC_Odin;
|
||||
|
||||
parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
|
||||
|
||||
AstNode *proc_type = ast_proc_type(f, proc_token, params, results, tags, cc);
|
||||
AstNode *body = NULL;
|
||||
|
||||
if (f->curr_token.kind == Token_OpenBrace) {
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
AstNode *curr_proc = f->curr_proc;
|
||||
f->curr_proc = proc_type;
|
||||
body = parse_body(f);
|
||||
f->curr_proc = curr_proc;
|
||||
} else if ((tags & ProcTag_foreign) == 0) {
|
||||
syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
|
||||
}
|
||||
|
||||
return ast_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
|
||||
} */
|
||||
|
||||
AstNode *parse_if_stmt(AstFile *f) {
|
||||
if (f->curr_proc == NULL) {
|
||||
syntax_error(f->curr_token, "You cannot use an if statement in the file scope");
|
||||
@@ -3458,8 +3443,18 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
}
|
||||
|
||||
expect_semicolon(f, s);
|
||||
return ast_tag_stmt(f, hash_token, name, parse_stmt(f));
|
||||
|
||||
if (str_eq(tag, str_lit("include"))) {
|
||||
syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
|
||||
s = ast_bad_stmt(f, token, f->curr_token);
|
||||
} else {
|
||||
syntax_error(token, "Unknown tag used: `%.*s`", LIT(tag));
|
||||
s = ast_bad_stmt(f, token, f->curr_token);
|
||||
}
|
||||
|
||||
fix_advance_to_next_stmt(f);
|
||||
|
||||
return s;
|
||||
} break;
|
||||
|
||||
case Token_OpenBrace:
|
||||
|
||||
+22
-14
@@ -888,7 +888,7 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
|
||||
case Type_Named:
|
||||
if (y->kind == Type_Named) {
|
||||
return x->Named.base == y->Named.base;
|
||||
return x->Named.type_name == y->Named.type_name;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -923,7 +923,6 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1023,41 +1022,50 @@ typedef enum ProcTypeOverloadKind {
|
||||
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
|
||||
if (!is_type_proc(x)) return ProcOverload_NotProcedure;
|
||||
if (!is_type_proc(y)) return ProcOverload_NotProcedure;
|
||||
TypeProc *px = &base_type(x)->Proc;
|
||||
TypeProc *py = &base_type(y)->Proc;
|
||||
TypeProc px = base_type(x)->Proc;
|
||||
TypeProc py = base_type(y)->Proc;
|
||||
|
||||
if (px->calling_convention != py->calling_convention) {
|
||||
if (px.calling_convention != py.calling_convention) {
|
||||
return ProcOverload_CallingConvention;
|
||||
}
|
||||
|
||||
if (px->param_count != py->param_count) {
|
||||
if (px.param_count != py.param_count) {
|
||||
return ProcOverload_ParamCount;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < px->param_count; i++) {
|
||||
Entity *ex = px->params->Tuple.variables[i];
|
||||
Entity *ey = py->params->Tuple.variables[i];
|
||||
for (isize i = 0; i < px.param_count; i++) {
|
||||
Entity *ex = px.params->Tuple.variables[i];
|
||||
Entity *ey = py.params->Tuple.variables[i];
|
||||
if (!are_types_identical(ex->type, ey->type)) {
|
||||
return ProcOverload_ParamTypes;
|
||||
}
|
||||
}
|
||||
// IMPORTANT TODO(bill): Determine the rules for overloading procedures with variadic parameters
|
||||
if (px->variadic != py->variadic) {
|
||||
if (px.variadic != py.variadic) {
|
||||
return ProcOverload_ParamVariadic;
|
||||
}
|
||||
|
||||
if (px->result_count != py->result_count) {
|
||||
if (px.result_count != py.result_count) {
|
||||
return ProcOverload_ResultCount;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < px->result_count; i++) {
|
||||
Entity *ex = px->results->Tuple.variables[i];
|
||||
Entity *ey = py->results->Tuple.variables[i];
|
||||
for (isize i = 0; i < px.result_count; i++) {
|
||||
Entity *ex = px.results->Tuple.variables[i];
|
||||
Entity *ey = py.results->Tuple.variables[i];
|
||||
if (!are_types_identical(ex->type, ey->type)) {
|
||||
return ProcOverload_ResultTypes;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Entity *ex = px.params->Tuple.variables[0];
|
||||
Entity *ey = py.params->Tuple.variables[0];
|
||||
bool ok = are_types_identical(ex->type, ey->type);
|
||||
if (ok) {
|
||||
gb_printf_err("Here\n");
|
||||
}
|
||||
}
|
||||
|
||||
return ProcOverload_Identical;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user