Преглед на файлове

Add hidden __tag for union variables.

Ginger Bill преди 8 години
родител
ревизия
789b297f32
променени са 10 файла, в които са добавени 205 реда и са изтрити 134 реда
  1. 1 0
      code/demo.odin
  2. 2 1
      core/fmt.odin
  3. 36 2
      core/os.odin
  4. 40 31
      core/os_linux.odin
  5. 53 65
      core/os_windows.odin
  6. 37 29
      core/os_x.odin
  7. 6 0
      src/check_expr.c
  8. 18 5
      src/ir.c
  9. 1 1
      src/parser.c
  10. 11 0
      src/types.c

+ 1 - 0
code/demo.odin

@@ -1,4 +1,5 @@
 #import "fmt.odin";
+#import "os.odin";
 
 main :: proc() {
 	immutable program := "+ + * - /";

+ 2 - 1
core/fmt.odin

@@ -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
core/os.odin

@@ -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
core/os_linux.odin

@@ -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
core/os_windows.odin

@@ -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
core/os_x.odin

@@ -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 - 0
src/check_expr.c

@@ -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
src/ir.c

@@ -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
src/parser.c

@@ -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 - 0
src/types.c

@@ -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;