Add hidden __tag for union variables.

This commit is contained in:
Ginger Bill
2017-05-04 20:34:50 +01:00
parent 3b25f924cb
commit 789b297f32
10 changed files with 205 additions and 134 deletions
+1
View File
@@ -1,4 +1,5 @@
#import "fmt.odin";
#import "os.odin";
main :: proc() {
immutable program := "+ + * - /";
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+6
View File
@@ -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];
+18 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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;