Browse Source

Fix enum type comparison; Start demo 003 code

Ginger Bill 9 năm trước cách đây
mục cha
commit
664c2cd7a5
11 tập tin đã thay đổi với 356 bổ sung43 xóa
  1. 7 0
      README.md
  2. 279 19
      code/demo.odin
  3. 1 1
      code/game.odin
  4. 4 4
      code/math.odin
  5. 34 1
      code/test.odin
  6. 1 1
      core/win32.odin
  7. 1 1
      src/checker/checker.cpp
  8. 2 6
      src/checker/type.cpp
  9. 1 2
      src/codegen/ssa.cpp
  10. 1 1
      src/main.cpp
  11. 25 7
      src/parser.cpp

+ 7 - 0
README.md

@@ -2,6 +2,13 @@
 
 Odin in an open source programming language that is simple to read, comprehend and reason with.
 
+## Requirements
+
+* x86-64
+* Windows
+* MSVC installed
+* call `vcvarsall.bat` to setup the path
+
 ## Warnings
 
 * This is still highly in development and the language's design is quite volatile.

+ 279 - 19
code/demo.odin

@@ -2,34 +2,294 @@
 #import "os.odin"
 
 
+
 main :: proc() {
-	Fruit :: enum {
-		APPLE,
-		BANANA,
-		GRAPE,
-		MELON,
-		PEACH,
-		TOMATO,
+	// struct_padding()
+	// bounds_checking()
+	// type_introspection()
+	// any_type()
+	crazy_introspection()
+	// namespaces_and_files()
+	// miscellany()
+}
+
+struct_padding :: proc() {
+	{
+		A :: struct {
+			a: u8
+			b: u32
+			c: u16
+		}
+
+		B :: struct {
+			a: [7]u8
+			b: [3]u16
+			c: u8
+			d: u16
+		}
+
+		fmt.println("size_of(A):", size_of(A))
+		fmt.println("size_of(B):", size_of(B))
+
+		// n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
+	}
+	{
+		A :: struct #ordered {
+			a: u8
+			b: u32
+			c: u16
+		}
+
+		B :: struct #ordered {
+			a: [7]u8
+			b: [3]u16
+			c: u8
+			d: u16
+		}
+
+		fmt.println("size_of(A):", size_of(A))
+		fmt.println("size_of(B):", size_of(B))
+
+		// C-style structure layout
+	}
+	{
+		A :: struct #packed {
+			a: u8
+			b: u32
+			c: u16
+		}
+
+		B :: struct #packed {
+			a: [7]u8
+			b: [3]u16
+			c: u8
+			d: u16
+		}
+
+		fmt.println("size_of(A):", size_of(A))
+		fmt.println("size_of(B):", size_of(B))
+
+		// Useful for explicit layout
+	}
+
+	// Member sorting by priority
+	// Alignment desc.
+	// Size desc.
+	// source order asc.
+
+	/*
+		A :: struct {
+			a: u8
+			b: u32
+			c: u16
+		}
+
+		B :: struct {
+			a: [7]u8
+			b: [3]u16
+			c: u8
+			d: u16
+		}
+
+		Equivalent too
+
+		A :: struct #ordered {
+			b: u32
+			c: u16
+			a: u8
+		}
+
+		B :: struct #ordered {
+			b: [3]u16
+			d: u16
+			a: [7]u8
+			c: u8
+		}
+	*/
+}
+
+bounds_checking :: proc() {
+	x: [4]int
+	// x[-1] = 0; // Compile Time
+	// x[4]  = 0; // Compile Time
+
+	/*{
+		a, b := -1, 4;
+		x[a] = 0; // Runtime Time
+		x[b] = 0; // Runtime Time
+	}*/
+
+	// Works for arrays, strings, slices, and related procedures & operations
+
+	{
+		base: [10]int
+		s := base[2:6]
+		a, b := -1, 6
+
+		#no_bounds_check {
+			s[a] = 0;
+			// #bounds_check s[b] = 0;
+		}
+
+	#no_bounds_check
+		if s[a] == 0 {
+			// Do whatever
+		}
+
+		// Bounds checking can be toggled explicit
+		// on a per statement basis.
+		// _any statement_
+	}
+}
+
+type_introspection :: proc() {
+
+	info: ^Type_Info
+	x: int
+
+	info = type_info(int) // by type
+	info = type_info(x) // by value
+	// See: runtime.odin
+
+	match type i : info {
+	case Type_Info.Integer:
+		fmt.println("integer!")
+	case Type_Info.Float:
+		fmt.println("float!")
+	default:
+		fmt.println("potato!")
+	}
+
+	// Unsafe cast
+	integer_info := info as ^Type_Info.Integer
+}
+
+any_type :: proc() {
+	a: any
+
+	x := 123
+	y := 6.28
+	z := "Yo-Yo Ma"
+	// All types can be implicit cast to `any`
+	a = x
+	a = y
+	a = z
+	a = a
+
+	// any has two members
+	// data      - rawptr to the data
+	// type_info - pointer to the type info
+
+	fmt.println(x, y, z)
+	// See: Implementation
+}
+
+crazy_introspection :: proc() {
+	{
+		Fruit :: enum {
+			APPLE,
+			BANANA,
+			GRAPE,
+			MELON,
+			PEACH,
+			TOMATO,
+		}
+
+		s: string
+		s = enum_to_string(Fruit.PEACH)
+		fmt.println(s)
+
+		f := Fruit.GRAPE
+		s = enum_to_string(f)
+		fmt.println(s)
+
+		fmt.println(f)
 	}
 
-	fruit_ti := type_info(Fruit)
-	name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
-	info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
 
-	fmt.printf("% :: enum ", name);
-	fmt.fprint_type(os.stdout, info.base)
-	fmt.printf(" {\n")
-	for i := 0; i < info.values.count; i++ {
-		fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
+	{
+		// NOTE(bill): This is not safe code and I would not recommend this at all
+		// I'd recommend you use `match type` to get the subtype rather than
+		// casting pointers
+
+		Fruit :: enum {
+			APPLE,
+			BANANA,
+			GRAPE,
+			MELON,
+			PEACH,
+			TOMATO,
+		}
+
+		fruit_ti := type_info(Fruit)
+		name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts
+		info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts
+
+		fmt.printf("% :: enum ", name);
+		fmt.fprint_type(os.stdout, info.base)
+		fmt.printf(" {\n")
+		for i := 0; i < info.values.count; i++ {
+			fmt.printf("\t%\t= %,\n", info.names[i], info.values[i])
+		}
+		fmt.printf("}\n")
 	}
-	fmt.printf("}\n")
 
-	Vector3 :: struct {x, y, z: f32}
-	v := Vector3{x = 1, y = 4, z = 9}
-	fmt.println(v)
+	{
+		Vector3 :: struct {x, y, z: f32}
+
+		a := Vector3{x = 1, y = 4, z = 9}
+		fmt.println(a)
+		b := Vector3{x = 9, y = 3, z = 1}
+		fmt.println(b)
+
+		// NOTE(bill): See fmt.odin
+	}
+
+	// n.b. This pretty much "solves" serialization (to strings)
 }
 
 
+namespaces_and_files :: proc() {
+	/*
+		// Non-exporting import
+		#import "file.odin"
+		#import "file.odin" as file
+		#import "file.odin" as .
+		#import "file.odin" as _
+
+		// Exporting import
+		#load "file.odin"
+	*/
+
+	// Talk about scope rules and diagram
+}
+
+miscellany :: proc() {
+	/*
+		win32 `__imp__` prefix
+		#dll_import
+		#dll_export
+
+		Change exported name/symbol for linking
+		#link_name
+
+		Custom calling conventions
+		#stdcall
+		#fastcall
+
+		Runtime stuff
+		#shared_global_scope
+	*/
+
+	// assert(false)
+	// compile_assert(false)
+	// panic("Panic message goes here")
+}
+
+
+
+
+
 // #import "fmt.odin" as fmt
 
 // #foreign_system_library "Ws2_32"

+ 1 - 1
code/game.odin

@@ -206,7 +206,7 @@ run :: proc() {
 		display_window(^window)
 		ms_to_sleep := (16 - 1000*dt) as i32
 		if ms_to_sleep > 0 {
-			sleep_ms(ms_to_sleep)
+			win32.Sleep(ms_to_sleep)
 		}
 	}
 }

+ 4 - 4
code/math.odin

@@ -96,7 +96,7 @@ remainder :: proc(x, y: f32) -> f32 {
 fmod :: proc(x, y: f32) -> f32 {
 	y = abs(y)
 	result := remainder(abs(x), y)
-	if fsign(result) < 0 {
+	if sign32(result) < 0 {
 		result += y
 	}
 	return copy_sign(result, x)
@@ -120,9 +120,9 @@ cross :: proc(x, y: Vec3) -> Vec3 {
 }
 
 
-vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(dot2(v, v)) }
-vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(dot3(v, v)) }
-vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(dot4(v, v)) }
+vec2_mag :: proc(v: Vec2) -> f32 { return sqrt32(dot2(v, v)) }
+vec3_mag :: proc(v: Vec3) -> f32 { return sqrt32(dot3(v, v)) }
+vec4_mag :: proc(v: Vec4) -> f32 { return sqrt32(dot4(v, v)) }
 
 vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} }
 vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} }

+ 34 - 1
code/test.odin

@@ -1,5 +1,38 @@
 #import "fmt.odin"
 
-thing :: proc() #link_name "frankerooney" {
+thing :: proc() {
 	fmt.println("Hello!")
 }
+
+/*
+#import "fmt.odin" as fmt
+
+thing :: proc() {
+	fmt.println("Hello!")
+}
+*/
+
+/*
+#import "fmt.odin" as .
+
+thing :: proc() {
+	println("Hello!")
+}
+*/
+
+/*
+#import "fmt.odin" as _
+
+thing :: proc() {
+	// println("Hello!")
+}
+*/
+
+
+/*
+#load "fmt.odin"
+
+thing :: proc() {
+	println("Hello!")
+}
+*/

+ 1 - 1
core/win32.odin

@@ -22,7 +22,7 @@ INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
 CS_VREDRAW    :: 0x0001
 CS_HREDRAW    :: 0x0002
 CS_OWNDC      :: 0x0020
-CW_USEDEFAULT :: 0x80000000
+CW_USEDEFAULT :: -0x80000000
 
 WS_OVERLAPPED       :: 0
 WS_MAXIMIZEBOX      :: 0x00010000

+ 1 - 1
src/checker/checker.cpp

@@ -418,7 +418,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 
 void check_scope_usage(Checker *c, Scope *scope) {
 	// TODO(bill): Use this?
-#if 1
+#if 0
 	gb_for_array(i, scope->elements.entries) {
 		auto *entry = scope->elements.entries + i;
 		Entity *e = entry->value;

+ 2 - 6
src/checker/type.cpp

@@ -599,12 +599,8 @@ b32 are_types_identical(Type *x, Type *y) {
 					break;
 
 				case TypeRecord_Enum:
-					if (are_types_identical(x->Record.enum_base, y->Record.enum_base)) {
-						if (x->Record.field_count == y->Record.field_count) {
-							return x->Record.fields == y->Record.fields;
-						}
-					}
-					return false;
+					// NOTE(bill): Each enum is unique
+					return x == y;
 				}
 			}
 		}

+ 1 - 2
src/codegen/ssa.cpp

@@ -1348,9 +1348,8 @@ isize ssa_type_info_index(CheckerInfo *info, Type *type) {
 		}
 	}
 	if (entry_index < 0) {
-		gb_printf_err("%s\n", type_to_string(type));
+		compiler_error("Type_Info for `%s` could not be found", type_to_string(type));
 	}
-	GB_ASSERT(entry_index >= 0);
 	return entry_index;
 }
 

+ 1 - 1
src/main.cpp

@@ -22,7 +22,7 @@ i32 win32_exec_command_line_app(char *fmt, ...) {
 	va_end(va);
 
 	if (CreateProcessA(NULL, cmd_line,
-	                   NULL, NULL, true, 0, NULL, NULL,
+                   NULL, NULL, true, 0, NULL, NULL,
 	                   &start_info, &pi)) {
 		WaitForSingleObject(pi.hProcess, INFINITE);
 

+ 25 - 7
src/parser.cpp

@@ -1499,7 +1499,14 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) {
 
 		case Token_OpenBrace: {
 			if (!lhs && is_literal_type(operand) && f->expr_level >= 0) {
-				operand = parse_literal_value(f, operand);
+				if (f->cursor[0].pos.line == f->cursor[-1].pos.line) {
+					// TODO(bill): This is a hack due to optional semicolons
+					// TODO(bill): It's probably much better to solve this by changing
+					// the syntax for struct literals and array literals
+					operand = parse_literal_value(f, operand);
+				} else {
+					loop = false;
+				}
 			} else {
 				loop = false;
 			}
@@ -1553,13 +1560,24 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
 
 			switch (op.kind) {
 			case Token_DoublePrime: {
+				// TODO(bill): Properly define semantic for in-fix and post-fix calls
 				AstNode *proc = parse_identifier(f);
-				AstNode *right = parse_binary_expr(f, false, prec+1);
-				gbArray(AstNode *) args;
-				gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
-				gb_array_append(args, expression);
-				gb_array_append(args, right);
-				expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token);
+				/* if (f->cursor[0].kind == Token_OpenParen) {
+					AstNode *call = parse_call_expr(f, proc);
+					gb_array_append(call->CallExpr.args, expression);
+					for (isize i = gb_array_count(call->CallExpr.args)-1; i > 0; i--) {
+						gb_swap(AstNode *, call->CallExpr.args[i], call->CallExpr.args[i-1]);
+					}
+
+					expression = call;
+				} else  */{
+					AstNode *right = parse_binary_expr(f, false, prec+1);
+					gbArray(AstNode *) args;
+					gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
+					gb_array_append(args, expression);
+					gb_array_append(args, right);
+					expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token);
+				}
 				continue;
 			} break;