mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-17 00:11:25 -07:00
Add hidden __tag for union variables.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#import "fmt.odin";
|
||||
#import "os.odin";
|
||||
|
||||
main :: proc() {
|
||||
immutable program := "+ + * - /";
|
||||
|
||||
+2
-1
@@ -194,7 +194,6 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
fi := Fmt_Info{buf = buf};
|
||||
fmt_int(&fi, u64(8*info.size), false, 64, 'd');
|
||||
}
|
||||
|
||||
case Float:
|
||||
match info.size {
|
||||
case 4: write_string(buf, "f32");
|
||||
@@ -212,6 +211,8 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
}
|
||||
case String: write_string(buf, "string");
|
||||
case Boolean: write_string(buf, "bool");
|
||||
case Any:
|
||||
write_string(buf, "any");
|
||||
case Atomic:
|
||||
write_string(buf, "atomic ");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
+36
-2
@@ -1,3 +1,37 @@
|
||||
#load "os_windows.odin" when ODIN_OS == "windows";
|
||||
#load "os_x.odin" when ODIN_OS == "osx";
|
||||
#load "os_linux.odin" when ODIN_OS == "linux";
|
||||
#load "os_x.odin" when ODIN_OS == "osx";
|
||||
#load "os_linux.odin" when ODIN_OS == "linux";
|
||||
|
||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, []byte(str));
|
||||
}
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
fd, err := open(name, O_RDONLY, 0);
|
||||
if err != ERROR_NONE {
|
||||
return nil, false;
|
||||
}
|
||||
defer close(fd);
|
||||
|
||||
length: i64;
|
||||
if length, err = file_size(fd); err != ERROR_NONE {
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return nil, true;
|
||||
}
|
||||
|
||||
data := make([]byte, length);
|
||||
if data == nil {
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
bytes_read, read_err := read(fd, data);
|
||||
if read_err != ERROR_NONE {
|
||||
free(data);
|
||||
return nil, false;
|
||||
}
|
||||
return data[0..<bytes_read], true;
|
||||
}
|
||||
|
||||
|
||||
+40
-31
@@ -179,6 +179,13 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
return res, 0;
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, bool) {
|
||||
prev, _ := seek(fd, 0, SEEK_CUR);
|
||||
size, err := seek(fd, 0, SEEK_END);
|
||||
seek(fd, prev, SEEK_SET);
|
||||
return size, err != 0;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
stdin: Handle = 0;
|
||||
@@ -204,44 +211,46 @@ access :: proc(path: string, mask: int) -> bool #inline {
|
||||
return _unix_access(cstr, mask) == 0;
|
||||
}
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
fd: Handle;
|
||||
err: Errno;
|
||||
size: i64;
|
||||
|
||||
fd, err = open_simple(name, O_RDONLY);
|
||||
if(err != 0) {
|
||||
fmt.println("Failed to open file.");
|
||||
return nil, false;
|
||||
}
|
||||
defer close(fd);
|
||||
|
||||
// We have a file
|
||||
size, err = seek(fd, 0, SEEK_END);
|
||||
if(err != 0) {
|
||||
fmt.println("Failed to seek to end of file.");
|
||||
return nil, false;
|
||||
}
|
||||
// read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
// fd: Handle;
|
||||
// err: Errno;
|
||||
// size: i64;
|
||||
|
||||
_, err = seek(fd, 0, SEEK_SET);
|
||||
if(err != 0) {
|
||||
fmt.println("Failed to seek to beginning of file.");
|
||||
return nil, false;
|
||||
}
|
||||
// fd, err = open_simple(name, O_RDONLY);
|
||||
// if(err != 0) {
|
||||
// fmt.println("Failed to open file.");
|
||||
// return nil, false;
|
||||
// }
|
||||
// defer close(fd);
|
||||
|
||||
// We have a file size!
|
||||
// // We have a file
|
||||
// size, err = seek(fd, 0, SEEK_END);
|
||||
// if(err != 0) {
|
||||
// fmt.println("Failed to seek to end of file.");
|
||||
// return nil, false;
|
||||
// }
|
||||
|
||||
data := make([]u8, size+1);
|
||||
if data == nil {
|
||||
fmt.println("Failed to allocate file buffer.");
|
||||
return nil, false;
|
||||
}
|
||||
// _, err = seek(fd, 0, SEEK_SET);
|
||||
// if(err != 0) {
|
||||
// fmt.println("Failed to seek to beginning of file.");
|
||||
// return nil, false;
|
||||
// }
|
||||
|
||||
read(fd, data);
|
||||
data[size] = 0;
|
||||
// // We have a file size!
|
||||
|
||||
return data, true;
|
||||
}
|
||||
// data := make([]u8, size+1);
|
||||
// if data == nil {
|
||||
// fmt.println("Failed to allocate file buffer.");
|
||||
// return nil, false;
|
||||
// }
|
||||
|
||||
// read(fd, data);
|
||||
// data[size] = 0;
|
||||
|
||||
// return data, true;
|
||||
// }
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
assert(size > 0);
|
||||
|
||||
+53
-65
@@ -109,33 +109,61 @@ close :: proc(fd: Handle) {
|
||||
win32.CloseHandle(win32.Handle(fd));
|
||||
}
|
||||
|
||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, []byte(str));
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE;
|
||||
}
|
||||
bytes_written: i32;
|
||||
e := win32.WriteFile(win32.Handle(fd), &data[0], i32(len(data)), &bytes_written, nil);
|
||||
if e == win32.FALSE {
|
||||
err := win32.GetLastError();
|
||||
return 0, Errno(err);
|
||||
single_write_length: i32;
|
||||
total_write: i64;
|
||||
length := i64(len(data));
|
||||
|
||||
for total_write < length {
|
||||
remaining := length - total_write;
|
||||
to_read: i32;
|
||||
MAX :: 1<<31-1;
|
||||
if remaining <= MAX {
|
||||
to_read = i32(remaining);
|
||||
} else {
|
||||
to_read = MAX;
|
||||
}
|
||||
e := win32.WriteFile(win32.Handle(fd), &data[total_write], to_read, &single_write_length, nil);
|
||||
if single_write_length <= 0 || e == win32.FALSE {
|
||||
err := win32.GetLastError();
|
||||
return int(total_write), Errno(e);
|
||||
}
|
||||
total_write += i64(single_write_length);
|
||||
}
|
||||
return int(bytes_written), ERROR_NONE;
|
||||
return int(total_write), ERROR_NONE;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE;
|
||||
}
|
||||
bytes_read: i32;
|
||||
e := win32.ReadFile(win32.Handle(fd), &data[0], u32(len(data)), &bytes_read, nil);
|
||||
if e == win32.FALSE {
|
||||
err := win32.GetLastError();
|
||||
return 0, Errno(err);
|
||||
|
||||
single_read_length: i32;
|
||||
total_read: i64;
|
||||
length := i64(len(data));
|
||||
|
||||
for total_read < length {
|
||||
remaining := length - total_read;
|
||||
to_read: u32;
|
||||
MAX :: 1<<32-1;
|
||||
if remaining <= MAX {
|
||||
to_read = u32(remaining);
|
||||
} else {
|
||||
to_read = MAX;
|
||||
}
|
||||
|
||||
e := win32.ReadFile(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
|
||||
if single_read_length <= 0 || e == win32.FALSE {
|
||||
err := win32.GetLastError();
|
||||
return int(total_read), Errno(e);
|
||||
}
|
||||
total_read += i64(single_read_length);
|
||||
}
|
||||
return int(bytes_read), ERROR_NONE;
|
||||
return int(total_read), ERROR_NONE;
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
@@ -159,6 +187,16 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
length: i64;
|
||||
err: Errno;
|
||||
if win32.GetFileSizeEx(win32.Handle(fd), &length) == 0 {
|
||||
err = Errno(win32.GetLastError());
|
||||
}
|
||||
return length, err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
stdin := get_std_handle(win32.STD_INPUT_HANDLE);
|
||||
@@ -204,56 +242,6 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
}
|
||||
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
buf: [300]byte;
|
||||
copy(buf[..], []byte(name));
|
||||
|
||||
fd, err := open(name, O_RDONLY, 0);
|
||||
if err != ERROR_NONE {
|
||||
return nil, false;
|
||||
}
|
||||
defer close(fd);
|
||||
|
||||
length: i64;
|
||||
if ok := win32.GetFileSizeEx(win32.Handle(fd), &length) != 0; !ok {
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return nil, true;
|
||||
}
|
||||
|
||||
data := make([]byte, length);
|
||||
if data == nil {
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
single_read_length: i32;
|
||||
total_read: i64;
|
||||
|
||||
for total_read < length {
|
||||
remaining := length - total_read;
|
||||
to_read: u32;
|
||||
MAX :: 1<<32-1;
|
||||
if remaining <= MAX {
|
||||
to_read = u32(remaining);
|
||||
} else {
|
||||
to_read = MAX;
|
||||
}
|
||||
|
||||
win32.ReadFile(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
|
||||
if single_read_length <= 0 {
|
||||
free(data);
|
||||
return nil, false;
|
||||
}
|
||||
|
||||
total_read += i64(single_read_length);
|
||||
}
|
||||
|
||||
return data, true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
|
||||
|
||||
+37
-29
@@ -196,6 +196,14 @@ seek :: proc(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errn
|
||||
return final_offset, 0;
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, bool) {
|
||||
prev, _ := seek(fd, 0, SEEK_CUR);
|
||||
size, err := seek(fd, 0, SEEK_END);
|
||||
seek(fd, prev, SEEK_SET);
|
||||
return size, err != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
|
||||
@@ -221,43 +229,43 @@ access :: proc(path: string, mask: int) -> bool #inline {
|
||||
return unix_access(cstr, mask) == 0;
|
||||
}
|
||||
|
||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
// read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||
|
||||
handle, err := open_simple(name, O_RDONLY);
|
||||
if(err != 0) {
|
||||
fmt.println("Failed to open file.");
|
||||
return nil, false;
|
||||
}
|
||||
defer(close(handle));
|
||||
// handle, err := open_simple(name, O_RDONLY);
|
||||
// if(err != 0) {
|
||||
// fmt.println("Failed to open file.");
|
||||
// return nil, false;
|
||||
// }
|
||||
// defer(close(handle));
|
||||
|
||||
// We have a file!
|
||||
// // We have a file!
|
||||
|
||||
size: AddressSize;
|
||||
size, err = seek(handle, 0, SEEK_END);
|
||||
if(err != 0) {
|
||||
fmt.println("Failed to seek to end of file.");
|
||||
return nil, false;
|
||||
}
|
||||
// size: AddressSize;
|
||||
// size, err = seek(handle, 0, SEEK_END);
|
||||
// if(err != 0) {
|
||||
// fmt.println("Failed to seek to end of file.");
|
||||
// return nil, false;
|
||||
// }
|
||||
|
||||
_, err = seek(handle, 0, SEEK_SET);
|
||||
if(err != 0) {
|
||||
fmt.println("Failed to seek to beginning of file.");
|
||||
return nil, false;
|
||||
}
|
||||
// _, err = seek(handle, 0, SEEK_SET);
|
||||
// if(err != 0) {
|
||||
// fmt.println("Failed to seek to beginning of file.");
|
||||
// return nil, false;
|
||||
// }
|
||||
|
||||
// We have a file size!
|
||||
// // We have a file size!
|
||||
|
||||
data := make([]u8, size+1);
|
||||
if data == nil {
|
||||
fmt.println("Failed to allocate file buffer.");
|
||||
return nil, false;
|
||||
}
|
||||
// data := make([]u8, size+1);
|
||||
// if data == nil {
|
||||
// fmt.println("Failed to allocate file buffer.");
|
||||
// return nil, false;
|
||||
// }
|
||||
|
||||
read(handle, data);
|
||||
data[size] = 0;
|
||||
// read(handle, data);
|
||||
// data[size] = 0;
|
||||
|
||||
return data, true;
|
||||
}
|
||||
// return data, true;
|
||||
// }
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr #inline {
|
||||
assert(size > 0);
|
||||
|
||||
@@ -422,6 +422,8 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
e->identifier = name;
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
fields[field_index++] = e;
|
||||
} else if (str_eq(name_token.string, str_lit("__tag"))) {
|
||||
error_node(name, "`__tag` is a reserved identifier for fields");
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
Entity **found = map_entity_get(&entity_map, key);
|
||||
@@ -660,6 +662,10 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
union_type->Record.field_count = field_count;
|
||||
union_type->Record.are_offsets_set = false;
|
||||
union_type->Record.is_ordered = true;
|
||||
{
|
||||
Entity *__tag = make_entity_field(c->allocator, NULL, make_token_ident(str_lit("__tag")), t_int, false, -1);
|
||||
union_type->Record.union__tag = __tag;
|
||||
}
|
||||
|
||||
for_array(i, ut->variants) {
|
||||
AstNode *variant = ut->variants.e[i];
|
||||
|
||||
@@ -2244,8 +2244,13 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
|
||||
} else if (is_type_union(t)) {
|
||||
type_set_offsets(a, t);
|
||||
GB_ASSERT(t->Record.field_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
result_type = make_type_pointer(a, t->Record.fields[index]->type);
|
||||
if (index == -1) {
|
||||
index = t->Record.field_count+1;
|
||||
result_type = t_int_ptr;
|
||||
} else {
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
result_type = make_type_pointer(a, t->Record.fields[index]->type);
|
||||
}
|
||||
} else if (is_type_tuple(t)) {
|
||||
GB_ASSERT(t->Tuple.variable_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
|
||||
@@ -2316,8 +2321,12 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
|
||||
result_type = t->Record.fields[index]->type;
|
||||
} else if (is_type_union(t)) {
|
||||
type_set_offsets(a, t);
|
||||
GB_ASSERT(t->Record.field_count > 0);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
if (index == -1) {
|
||||
index = t->Record.field_count+1;
|
||||
result_type = t_int_ptr;
|
||||
} else {
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
}
|
||||
result_type = t->Record.fields[index]->type;
|
||||
} else if (is_type_tuple(t)) {
|
||||
GB_ASSERT(t->Tuple.variable_count > 0);
|
||||
@@ -2394,7 +2403,11 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
|
||||
type = type->Record.fields[index]->type;
|
||||
e = ir_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type));
|
||||
} else if (type->kind == Type_Record) {
|
||||
type = type->Record.fields[index]->type;
|
||||
if (index == -1) {
|
||||
type = t_int;
|
||||
} else {
|
||||
type = type->Record.fields[index]->type;
|
||||
}
|
||||
e = ir_emit_struct_ep(proc, e, index);
|
||||
} else if (type->kind == Type_Tuple) {
|
||||
type = type->Tuple.variables[index]->type;
|
||||
|
||||
+1
-1
@@ -1844,7 +1844,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
return ast_proc_lit(f, type, NULL, tags, foreign_library, foreign_name, link_name);
|
||||
}
|
||||
if (tags != 0) {
|
||||
syntax_error(token, "A procedure type cannot have tags");
|
||||
// syntax_error(token, "A procedure type cannot have tags");
|
||||
}
|
||||
|
||||
return type;
|
||||
|
||||
+11
@@ -92,6 +92,8 @@ typedef struct TypeRecord {
|
||||
// Entity_TypeName - union
|
||||
Entity **variants;
|
||||
i32 variant_count;
|
||||
Entity * union__tag;
|
||||
|
||||
|
||||
i64 * offsets;
|
||||
bool are_offsets_set;
|
||||
@@ -1415,6 +1417,15 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
sel.index.count = prev_count;
|
||||
}
|
||||
}
|
||||
if (type->Record.kind == TypeRecord_Union) {
|
||||
if (str_eq(field_name, str_lit("__tag"))) {
|
||||
Entity *e = type->Record.union__tag;
|
||||
GB_ASSERT(e != NULL);
|
||||
selection_add_index(&sel, -1); // HACK(bill): Leaky memory
|
||||
sel.entity = e;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sel;
|
||||
|
||||
Reference in New Issue
Block a user