Browse Source

Initial Demo001 code for tour of language

Ginger Bill 9 years ago
parent
commit
745237459a
7 changed files with 582 additions and 38 deletions
  1. 1 1
      build.bat
  2. 525 0
      examples/demo001.odin
  3. 2 6
      examples/game.odin
  4. 6 3
      src/codegen/print_llvm.cpp
  5. 43 25
      src/codegen/ssa.cpp
  6. 2 0
      src/exact_value.cpp
  7. 3 3
      src/tokenizer.cpp

+ 1 - 1
build.bat

@@ -45,7 +45,7 @@ pushd %build_dir%
 
 	cl %compiler_settings% "..\src\main.cpp" ^
 		/link %linker_settings% -OUT:%exe_name% ^
-	&& odin run ..\examples/main.odin
+	&& odin run ..\examples/demo001.odin
 
 
 	:do_not_compile_exe

+ 525 - 0
examples/demo001.odin

@@ -0,0 +1,525 @@
+#load "basic.odin"
+#load "math.odin"
+// #load "game.odin"
+
+main :: proc() {
+	_ = hellope();
+	procedures();
+	variables();
+	constants();
+	types();
+	data_control();
+	// run_game();
+}
+
+hellope :: proc() -> int {
+	print_string("Hellope, 世界\n");
+	return 1;
+}
+
+apple, banana, carrot: bool;
+box, carboard: bool = true, false;
+hellope_value := hellope();
+
+variables :: proc() {
+	i: int; // initialized with zero value
+	j: int = 1;
+	x, y: int = 1, 2;
+
+	// Type inference
+	apple, banana, carrot := true, 123, "carrot";
+
+
+	// Basic Types of the Language
+	//
+	// bool
+	//
+	// i8 i16 i32 i64 i128
+	// u8 u16 u32 u64 u128
+	//
+	// f32 f64
+	//
+	// int uint (size_of(int) = size_of(rawptr))
+	//
+	// rawptr
+	//
+	// string
+	//
+	// byte - alias for u8
+	// rune - alias for i32 // Unicode Codepoint
+	//
+	// untyped bool      - "untyped" types can implicitly convert to any of the "typed" types
+	// untyped integer
+	// untyped float
+	// untyped pointer
+	// untyped string
+	// untyped rune
+
+
+	// // Zero values
+	zero_numeric := 0;
+	zero_boolean := false;
+	zero_pointer := null;
+	zero_string1 := ""; // Escaped string
+	zero_string2 := ``; // Raw string
+
+	// Unary operators
+	// +a
+	// -a
+	// ~a
+	// !a
+
+	// Binary operators
+	// a + b
+	// a - b
+	// a ~ b
+	// a | b
+
+	// a * b
+	// a / b
+	// a % b
+	// a & b
+	// a &~ b   == a & (~b)
+	// a << b
+	// a >> b
+
+	// a as Type
+	// a transmute Type
+
+	// a == b
+	// a != b
+	// a < b
+	// a > b
+	// a <= b
+	// a >= b
+
+}
+
+procedures :: proc() {
+	add :: proc(x: int, y: int) -> int {
+		return x + y;
+	}
+	print_int(add(3, 4)); // 7
+	print_rune('\n');
+
+	add_v2 :: proc(x, y: int) -> int {
+		return x + y;
+	}
+
+
+	swap_strings :: proc(x, y: string) -> (string, string) {
+		return y, x;
+	}
+	a, b := swap_strings("Hellope\n", "World\n");
+	print_string(a);
+	print_string(b);
+
+	a, b = b, a; // Quirk of grammar the of multiple assignments
+	print_string(a);
+	print_string(b);
+
+	// Not hints, it's mandatory
+	proc1 :: proc(a, b: int) #inline {
+		print_int(a + b);
+	}
+	proc2 :: proc(a, b: int) #no_inline {
+		print_int(a + b);
+	}
+}
+
+
+TAU :: 6.28318530718;
+
+constants :: proc() {
+	TAU :: 6.28318530718; // untyped float
+	WORLD_JAPANESE :: "世界"; // untyped string
+
+	TAU_32 : f32 : 6.28318530718;
+	TAU_AS_32 :: 6.28318530718 as f32;
+}
+
+nl :: proc() { print_rune('\n'); }
+
+types :: proc() {
+
+	x: int = 123;
+	y := x; // y: int = x;
+	// z: f32 = x; // invalid
+	z: f32 = x as f32;
+
+	ptr_z := ^z; // Pascal notation
+	ptr_z^ = 123; // Derefence Notation
+	print_f32(z); nl();
+
+	// ^z - pointer to z
+	// z^ - z from pointer
+
+	f32_array: [12]f32; // Array of 12 f32
+	f32_array[0] = 2;
+	f32_array[1] = 3;
+	// f32_array[-1] = 2; // Error - compile time check
+	// f32_array[13]  = 2; // Error - compile time check
+	f32_array_len := len(f32_array); // builtin procedure
+	f32_array_cap := cap(f32_array); // == len(f32_array)
+
+	api: [2]^f32;
+	papi: ^[2]^f32;
+
+	f32_slice: []f32; // Array reference
+	f32_slice = f32_array[0:5];
+	f32_slice = f32_array[:5];
+	f32_slice = f32_array[:]; // f32_array[0:len(f32_array)-1];
+
+	f32_slice = f32_array[1:5:7]; // low:1, high:5, capacity:7
+
+	append_success := append(^f32_slice, 1);
+	_ = append(^f32_slice, 2);
+
+	_ = copy(f32_array[0:2], f32_array[2:4]); // You can use memcpy/memmove if you want
+
+
+	s := "Hellope World";
+	sub_string := s[5:10];
+
+	v0: {4}f32; // Vector of 4 f32
+	v0[0] = 1;
+	v0[1] = 3;
+	v0[2] = 6;
+	v0[3] = 10;
+
+	v1 := v0 + v0; // Simd Arithmetic
+	v1 = v1 - v0;
+	v1 *= v0; // i.e. hadamard product
+	v1 /= v0;
+
+	// builtin procedure
+	v2 := swizzle(v0, 3, 2, 1, 0); // {10, 6, 3, 1}
+
+	v3: {4}bool = v0 == v2;
+	// LLVM rant?
+
+
+	type Vec4: {4}f32;
+	type Array3Int: [3]int;
+
+	type Vec3: struct {
+		x, y, z: f32
+	}
+
+	type BinaryNode: struct {
+		left, right: ^BinaryNode, // same format as procedure argument
+		data: rawptr,
+	}
+
+	type AddProc: proc(a, b: int) -> int
+
+	type Packed: struct #packed {
+		a: u8,
+		b: u16,
+		c: u32,
+	}
+	static_assert(size_of(Packed) == 7);
+
+
+	{
+		type MyInt: int
+		x: int = 1;
+		y: MyInt = 2;
+		// z := x + y; // Failure - types cannot implicit convert*
+		z := x as MyInt + y; // Type cast using `as`
+	}
+
+
+	{
+		// From: Quake III Arena
+		Q_rsqrt :: proc(number: f32) -> f32 {
+			i: i32;
+			x2, y: f32;
+			THREE_HALFS :: 1.5;
+
+			x2 = number * 0.5;
+			y = number;
+			i = (^y as ^i32)^;                      // evil floating point bit level hacking
+			i = 0x5f3759df - i>>1;                  // what the fuck?
+			y = (^i as ^f32)^;
+			y = y * (THREE_HALFS - (x2 * y *y));    // 1st iteration
+		//	y = y * (THREE_HALFS - (x2 * y *y));    // 2nd iteration, this can be removed
+			return y;
+		}
+
+		Q_rsqrt_v2 :: proc(number: f32) -> f32 {
+			THREE_HALFS :: 1.5;
+
+			x2 := number * 0.5;
+			y := number;
+			i := y transmute i32;                   // evil floating point bit level hacking
+			i = 0x5f3759df - i>>1;                  // what the fuck?
+			y = i transmute f32;
+			y = y * (THREE_HALFS - (x2 * y *y));    // 1st iteration
+		//	y = y * (THREE_HALFS - (x2 * y *y));    // 2nd iteration, this can be removed
+			return y;
+		}
+
+		// transmute only works if the size of the types are equal
+		/{
+			// in C
+			union {
+				i32 i;
+				f32 y;
+			};
+		 }/
+	}
+
+	{ // Compound Literals
+		a := [3]int{1, 2, 3};
+		b := [3]int{};
+		c := [..]int{1, 2, 3};
+
+		d := []int{1, 2, 3}; // slice
+
+		e := {4}f32{1, 2, 3, 4};
+		f := {4}f32{1}; // broadcasts to all
+		// g := {4}f32{1, 2}; // require either 1 or 4 elements
+
+		type Vec2: {2}f32;
+
+		h := Vec2{1, 2};
+
+		i := Vec2{5} * h; // For strong type safety
+		// FORENOTE: 5 * h was originally allowed but it was an edge case in the
+		// compiler I didn't think it was enough to justify have it it.
+
+		print_f32(i[0]); print_rune(',');
+		print_f32(i[1]); print_rune('\n');
+	}
+
+	{
+		do_thing :: proc(p: proc(a, b: int) -> int) {
+			print_int(p(3, 4)); nl();
+		}
+
+		add :: proc(a, b: int) -> int {
+			return a + b;
+		}
+
+
+		add_lambda := proc(a, b: int) -> int {
+			return a - b;
+		}; // note semicolon
+
+		do_thing(add);
+		do_thing(add_lambda);
+		do_thing(proc(a, b: int) -> int {
+			return a * b;
+		});
+	}
+
+	{ // strings and runes
+		escaped := "Hellope World\n";
+		raw     := `Hellope World\n`;
+		print_string(escaped);
+		print_string(raw); nl();
+
+		// Crap shader example
+		shader_string :=
+`#version 410
+
+layout (location = 0) in vec3 a_position;
+layout (location = 1) in vec3 a_normal;
+layout (location = 2) in vec2 a_tex_coord;
+
+out vec3 v_position;
+out vec3 v_normal;
+out vec2 v_tex_coord;
+
+uniform mat4 u_model_view;
+uniform mat3 u_normal;
+uniform mat4 u_proj;
+uniform mat4 u_mvp;
+
+void main() {
+    v_tex_coord = a_tex_coord;
+    v_normal = normalize(u_normal * a_normal);
+    v_position = vec3(u_model_view * vec4(a_position, 1.0));
+
+    gl_Position = u_mvp * vec4(a_position, 1.0);
+}`;
+
+
+		knot1 := '⌘';
+		knot2 := '\u2318';     // 16 bit
+		knot3 := '\U00002318'; // 32 bit
+		knot4 := "\xe2\x8c\x98"; // Note it's a string, should I allow untyped string -> untyped rune casts?
+
+		// String ideas "nicked" from Go, so far. I think I might change how some of it works later.
+	}
+
+
+	{ // size, align, offset
+		type Thing: struct {
+			a: u8,
+			b: u16,
+			c, d, e: u32,
+		}
+
+		s := size_of(Thing);
+		a := align_of(Thing);
+		o := offset_of(Thing, b);
+
+		t: Thing;
+
+		sv := size_of_val(t);
+		av := align_of_val(t);
+		ov := offset_of_val(t.b);
+	}
+}
+
+data_control :: proc() {
+	sum := 0;
+	for i := 0; i < 12; i++ {
+		sum += 1;
+	}
+	print_string("sum = "); print_int(sum); nl();
+
+	sum = 1;
+	for ; sum < 1000000; {
+		sum += sum;
+	}
+	print_string("sum = "); print_int(sum); nl();
+
+	sum = 1;
+	for sum < 1000000 {
+		sum += sum;
+	}
+	print_string("sum = "); print_int(sum); nl();
+
+	// loop
+	// for { } == for true {}
+
+	// Question: Should I separate all these concepts and rename it?
+	//
+	// range - iterable
+	// for   - c style
+	// while
+	// loop  - while true
+
+	// Notes:
+	// conditions _must_ a boolean expression
+	// i++ and i-- are statements, not expressions
+
+
+	x := 2;
+	if x < 3 {
+		print_string("x < 2\n");
+	}
+
+	// Unified initializer syntax - same as for statements
+	if x := 2; x < 3 {
+		print_string("x < 2\n");
+	}
+
+	if x := 4; x < 3 {
+		print_string("Never called\n");
+	} else {
+		print_string("This is called\n");
+	}
+
+	{ // String comparison
+		a := "Hellope";
+		b := "World";
+		if a < b {
+			print_string("a < b\n");
+		}
+		if a != b {
+			print_string("a != b\n");
+		}
+
+	}
+
+
+
+
+	{
+		defer print_string("日本語\n");
+		print_string("Japanese\n");
+	}
+
+	{
+		defer print_string("1\n");
+		defer print_string("2\n");
+		defer print_string("3\n");
+	}
+
+	{
+		// C strings, yuk!
+		to_c_string :: proc(s: string) -> ^u8 {
+			c := heap_alloc(len(s)+1) as ^u8;
+			mem_copy(c, ^s[0], len(s));
+			c[len(s)] = 0;
+			return c;
+		}
+
+		fopen  :: proc(filename, mode: ^u8) -> rawptr #foreign
+		fclose :: proc(f: rawptr) -> i32 #foreign
+
+		filename := to_c_string("../examples/base.odin");
+		mode := to_c_string("rb");
+		defer heap_free(filename);
+		defer heap_free(mode);
+
+		f := fopen(filename, mode);
+		if f == null {
+			// handle error
+		}
+		defer if f != null {
+			_ = fclose(f);
+		}
+
+		// rest of code
+
+		// Better version
+		/{
+			type File: struct { filename: string }
+			type FileError: int
+			open_file :: proc(filename: string) -> (File, FileError) { ... }
+			close_file :: proc(f: ^File) { ... }
+			f, err := open_file("Test");
+			if err != 0 {
+				// handle error
+			}
+			defer close_file(^f);
+
+		}/
+
+
+	}
+
+	for i := 0; i < 100; i++ {
+		blah := heap_alloc(100 * size_of(int)) as ^int;
+		defer {
+			defer print_string("!");
+			defer print_string("heap_free");
+			heap_free(blah);
+		}
+
+		if i == 3 {
+			// defers called
+			continue;
+		}
+
+		if i == 5 {
+			// defers called
+			return;
+		}
+
+		if i == 8 {
+			// defers called
+			break; // never happens
+		}
+	}
+
+	defer print_string("It'll never happen, mate 1");
+	print_string("It'll never happen, mate 2");
+	print_string("It'll never happen, mate 3");
+}
+

+ 2 - 6
examples/main.odin → examples/game.odin

@@ -125,8 +125,7 @@ display_window :: proc(w: ^Window) {
 
 
 
-
-main :: proc() {
+run_game :: proc() {
 	win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
 		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
 			ExitProcess(0);
@@ -134,9 +133,7 @@ main :: proc() {
 		}
 		return DefWindowProcA(hwnd, msg, wparam, lparam);
 	}
-	print_f64(13.37);
-	print_rune('\n');
-/*
+
 	window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
 	if !window_success {
 		return;
@@ -189,5 +186,4 @@ main :: proc() {
 			sleep_ms(ms_to_sleep);
 		}
 	}
-*/
 }

+ 6 - 3
src/codegen/print_llvm.cpp

@@ -196,10 +196,13 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
 }
 
 void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type) {
+	type = get_base_type(type);
 	if (is_type_float(type)) {
 		value = exact_value_to_float(value);
 	} else if (is_type_integer(type)) {
 		value = exact_value_to_integer(value);
+	} else if (is_type_pointer(type)) {
+		value = exact_value_to_integer(value);
 	}
 
 	switch (value.kind) {
@@ -212,7 +215,7 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
 		ssa_fprintf(f, "\"");
 	} break;
 	case ExactValue_Integer: {
-		if (is_type_pointer(get_base_type(type))) {
+		if (is_type_pointer(type)) {
 			if (value.value_integer == 0) {
 				ssa_fprintf(f, "null");
 			} else {
@@ -235,14 +238,14 @@ void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type
 		ssa_fprintf(f, "0x%016llx", u);
 	} break;
 	case ExactValue_Pointer:
-		if (value.value_float == NULL) {
+		if (value.value_pointer == NULL) {
 			ssa_fprintf(f, "null");
 		} else {
 			GB_PANIC("TODO(bill): ExactValue_Pointer");
 		}
 		break;
 	default:
-		GB_PANIC("Invalid ExactValue");
+		GB_PANIC("Invalid ExactValue: %d", value.kind);
 		break;
 	}
 }

+ 43 - 25
src/codegen/ssa.cpp

@@ -908,7 +908,9 @@ ssaValue *ssa_lvalue_store(ssaProcedure *proc, ssaLvalue lval, ssaValue *value)
 		if (lval.is_vector) {
 			// HACK(bill): Fix how lvalues for vectors work
 			ssaValue *v = ssa_emit_load(proc, lval.address);
-			ssaValue *out = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, lval.index));
+			Type *elem_type = get_base_type(ssa_value_type(v))->vector.elem;
+			ssaValue *elem = ssa_emit_conv(proc, value, elem_type);
+			ssaValue *out = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, elem, lval.index));
 			return ssa_emit_store(proc, lval.address, out);
 		}
 		return ssa_emit_store(proc, lval.address, value);
@@ -1401,22 +1403,22 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 		return ssa_emit_load(proc, slice);
 	}
 
-	if (is_type_vector(dst)) {
-		Type *dst_elem = dst->vector.elem;
-		value = ssa_emit_conv(proc, value, dst_elem);
-		ssaValue *v = ssa_add_local_generated(proc, t);
-		v = ssa_emit_load(proc, v);
-		v = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, v_zero32));
-		// NOTE(bill): Broadcast lowest value to all values
-		isize index_count = dst->vector.count;
-		i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
-		for (isize i = 0; i < index_count; i++) {
-			indices[i] = 0;
-		}
+	// if (is_type_vector(dst)) {
+	// 	Type *dst_elem = dst->vector.elem;
+	// 	value = ssa_emit_conv(proc, value, dst_elem);
+	// 	ssaValue *v = ssa_add_local_generated(proc, t);
+	// 	v = ssa_emit_load(proc, v);
+	// 	v = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, v_zero32));
+	// 	// NOTE(bill): Broadcast lowest value to all values
+	// 	isize index_count = dst->vector.count;
+	// 	i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
+	// 	for (isize i = 0; i < index_count; i++) {
+	// 		indices[i] = 0;
+	// 	}
 
-		v = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, v, indices, index_count));
-		return v;
-	}
+	// 	v = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, v, indices, index_count));
+	// 	return v;
+	// }
 
 
 	gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
@@ -1606,10 +1608,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			for (AstNode *elem = cl->elem_list;
 				elem != NULL;
 				elem = elem->next, index++) {
-				ssaValue *field_expr = ssa_build_expr(proc, elem);
-				Type *t = ssa_value_type(field_expr);
+				ssaValue *field_elem = ssa_build_expr(proc, elem);
+				Type *t = ssa_value_type(field_elem);
 				GB_ASSERT(t->kind != Type_Tuple);
-				ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
+				ssaValue *ev = ssa_emit_conv(proc, field_elem, et);
 				ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(index));
 				result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
 			}
@@ -1619,7 +1621,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 				for (isize i = 0; i < index_count; i++) {
 					indices[i] = 0;
 				}
-				return ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, result, indices, index_count));
+				ssaValue *sv = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, result, indices, index_count));
+				ssa_emit_store(proc, v, sv);
+				return ssa_emit_load(proc, v);
 			}
 
 			return result;
@@ -1761,15 +1765,20 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					AstNode *sptr_node = ce->arg_list;
 					AstNode *item_node = ce->arg_list->next;
 					ssaValue *slice = ssa_build_addr(proc, sptr_node).address;
-					ssaValue *item_value = ssa_build_expr(proc, item_node);
-					Type *item_type = ssa_value_type(item_value);
-					ssaValue *item = ssa_add_local_generated(proc, item_type);
-					ssa_emit_store(proc, item, item_value);
 
 					ssaValue *elem = ssa_slice_elem(proc, slice);
 					ssaValue *len = ssa_slice_len(proc, slice);
 					ssaValue *cap = ssa_slice_cap(proc, slice);
 
+					Type *elem_type = type_deref(get_base_type(ssa_value_type(elem)));
+
+					ssaValue *item_value = ssa_build_expr(proc, item_node);
+					item_value = ssa_emit_conv(proc, item_value, elem_type);
+
+					ssaValue *item = ssa_add_local_generated(proc, elem_type);
+					ssa_emit_store(proc, item, item_value);
+
+
 					// NOTE(bill): Check if can append is possible
 					Token lt = {Token_Lt};
 					ssaValue *cond = ssa_emit_comp(proc, lt, len, cap);
@@ -1781,9 +1790,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 					// Add new slice item
 					ssaValue *offset = ssa_emit_ptr_offset(proc, elem, len);
-					i64 item_size = type_size_of(proc->module->sizes, proc->module->allocator, item_type);
+					i64 item_size = type_size_of(proc->module->sizes, proc->module->allocator, elem_type);
 					ssaValue *byte_count = ssa_make_value_constant(proc->module->allocator, t_int,
 					                                               make_exact_value_integer(item_size));
+					offset = ssa_emit_conv(proc, offset, t_rawptr);
+					item = ssa_emit_ptr_offset(proc, item, v_zero);
+					ssa_value_set_type(item, make_type_pointer(proc->module->allocator, ssa_value_type(item)));
+					item = ssa_emit_conv(proc, item, t_rawptr);
 					ssa_emit(proc, ssa_make_instr_copy_memory(proc, offset, item, byte_count, 1, false));
 
 					// Increment slice length
@@ -1847,6 +1860,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 			}
 		}
 
+		auto *pt = &proc_type_->proc.params->tuple;
+		for (isize i = 0; i < arg_count; i++) {
+			args[i] = ssa_emit_conv(proc, args[i], pt->variables[i]->type);
+		}
+
 		ssaValue *call = ssa_make_instr_call(proc, value, args, arg_count, type->results);
 		return ssa_emit(proc, call);
 	case_end;

+ 2 - 0
src/exact_value.cpp

@@ -108,6 +108,8 @@ ExactValue exact_value_to_integer(ExactValue v) {
 		return v;
 	case ExactValue_Float:
 		return make_exact_value_integer(cast(i64)v.value_float);
+	case ExactValue_Pointer:
+		return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
 	}
 	ExactValue r = {ExactValue_Invalid};
 	return r;

+ 3 - 3
src/tokenizer.cpp

@@ -371,18 +371,18 @@ void tokenizer_skip_whitespace(Tokenizer *t) {
 			if (t->read_curr[0] == '/') { // Line comment //
 				while (t->curr_rune != '\n')
 					advance_to_next_rune(t);
-			} else if (t->read_curr[0] == '*') { // (Nested) Block comment /**/
+			} else if (t->read_curr[0] == '{') { // (Nested) Block comment /{}/
 				isize comment_scope = 1;
 				for (;;) {
 					advance_to_next_rune(t);
 					if (t->curr_rune == '/') {
 						advance_to_next_rune(t);
-						if (t->curr_rune == '*') {
+						if (t->curr_rune == '{') {
 							advance_to_next_rune(t);
 							comment_scope++;
 						}
 					}
-					if (t->curr_rune == '*') {
+					if (t->curr_rune == '}') {
 						advance_to_next_rune(t);
 						if (t->curr_rune == '/') {
 							advance_to_next_rune(t);