Browse Source

Merge remote-tracking branch 'origin/master'

Brendan Punsky 7 years ago
parent
commit
f6c45fc68a

+ 1 - 1
core/atomics.odin

@@ -4,7 +4,7 @@
 when ODIN_OS == "windows" {
 	import win32 "core:sys/windows.odin"
 }
-_ :: compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
+#assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
 
 
 yield_thread :: proc() { win32.mm_pause(); }

+ 1 - 1
core/c.odin

@@ -29,7 +29,7 @@ c_double         :: f64;
 c_complex_float  :: complex64;
 c_complex_double :: complex128;
 
-_ :: compile_assert(size_of(uintptr) == size_of(int));
+#assert(size_of(uintptr) == size_of(int));
 
 c_size_t    :: uint;
 c_ssize_t   :: int;

+ 1 - 1
core/opengl.odin

@@ -8,7 +8,7 @@ when ODIN_OS == "windows" {
 
 export "core:opengl_constants.odin"
 
-_ := compile_assert(ODIN_OS != "osx");
+(ODIN_OS != "osx");
 
 @(default_calling_convention="c", link_prefix="gl")
 foreign lib {

+ 1 - 1
core/thread.odin

@@ -1,4 +1,4 @@
-_ :: compile_assert(ODIN_OS == "windows");
+#assert(ODIN_OS == "windows");
 
 when ODIN_OS == "windows" {
 	import win32 "core:sys/windows.odin"

+ 4 - 3
examples/demo.odin

@@ -101,13 +101,13 @@ general_stuff :: proc() {
 		// If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct.
 
 		Int32 :: i32;
-		compile_assert(Int32 == i32);
+		#assert(Int32 == i32);
 
 		My_Int32 :: distinct i32;
-		compile_assert(My_Int32 != i32);
+		#assert(My_Int32 != i32);
 
 		My_Struct :: struct{x: int};
-		compile_assert(My_Struct != struct{x: int});
+		#assert(My_Struct != struct{x: int});
 	}
 }
 
@@ -760,6 +760,7 @@ complete_switch :: proc() {
 	}
 }
 
+
 main :: proc() {
 	when true {
 		general_stuff();

+ 1 - 1
examples/old_demos/demo001.odin

@@ -328,7 +328,7 @@ miscellany :: proc() {
 	*/
 
 	// assert(false)
-	// compile_assert(false)
+	// #assert(false)
 	// panic("Panic message goes here")
 }
 

+ 2 - 2
examples/old_demos/demo002.odin

@@ -171,8 +171,8 @@ new_builtins :: proc() {
 	{
 		// Compile time assert
 		COND :: true;
-		compile_assert(COND);
-		// compile_assert(!COND)
+		#assert(COND);
+		// #assert(!COND)
 
 		// Runtime assert
 		x := true;

+ 2 - 2
examples/old_demos/demo005.odin

@@ -43,7 +43,7 @@ syntax :: proc() {
 	Thing2 :: struct {x: f32, y: int, z: ^[]int};
 
 	// Slice interals are now just a `ptr+len+cap`
-	slice: []int; compile_assert(size_of(slice) == 3*size_of(int));
+	slice: []int; #assert(size_of(slice) == 3*size_of(int));
 
 	// Helper type - Help the reader understand what it is quicker
 	My_Int  :: #type int;
@@ -218,7 +218,7 @@ loops :: proc() {
 	name := "你好,世界";
 	fmt.println(name);
 	for r in name {
-		compile_assert(type_of(r) == rune);
+		#assert(type_of(r) == rune);
 		fmt.printf("%r\n", r);
 	}
 

+ 3 - 3
examples/old_demos/demo006.odin

@@ -24,7 +24,7 @@ when true {
 	 * ..< and ... removed and replace with .. (half-closed range)
 
 	Changed:
-	 * `compile_assert` and `assert` return the value of the condition for semantic reasons
+	 * `#assert` and `assert` return the value of the condition for semantic reasons
 	 * thread_local -> #thread_local
 	 * #include -> #load
 	 * Files only get checked if they are actually used
@@ -159,8 +159,8 @@ when true {
 			fmt.println(i);
 		}
 
-		compile_assert(size_of([vector 7]bool) >= size_of([7]bool));
-		compile_assert(size_of([vector 7]i32) >= size_of([7]i32));
+		#assert(size_of([vector 7]bool) >= size_of([7]bool));
+		#assert(size_of([vector 7]i32) >= size_of([7]i32));
 		// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
 	}
 

+ 1 - 1
examples/old_demos/old_runtime.odin

@@ -46,7 +46,7 @@ memory_copy :: proc(dst, src: rawptr, n: int) #inline {
 	}
 
 	v128b :: type {4}u32
-	compile_assert(align_of(v128b) == 16)
+	#assert(align_of(v128b) == 16)
 
 	d, s: ^byte = dst, src
 

+ 3 - 3
examples/old_stuff/demo_backup.odin

@@ -50,9 +50,9 @@ general_stuff :: proc() {
 	foo := Foo{123, 0.513, "A string"};
 	x, y, z := expand_to_tuple(foo);
 	fmt.println(x, y, z);
-	compile_assert(type_of(x) == int);
-	compile_assert(type_of(y) == f32);
-	compile_assert(type_of(z) == string);
+	#assert(type_of(x) == int);
+	#assert(type_of(y) == f32);
+	#assert(type_of(z) == string);
 
 
 	// By default, all variables are zeroed

+ 1 - 1
examples/punity.odin

@@ -10,7 +10,7 @@ CANVAS_SCALE  :: 3;
 FRAME_TIME    :: 1.0/30.0;
 WINDOW_TITLE  :: "Punity\x00";
 
-_ :: compile_assert(CANVAS_WIDTH % 16 == 0);
+#assert(CANVAS_WIDTH % 16 == 0);
 
 
 WINDOW_WIDTH  :: CANVAS_WIDTH  * CANVAS_SCALE;

+ 47 - 42
src/check_expr.cpp

@@ -2813,27 +2813,48 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 	case BuiltinProc_DIRECTIVE: {
 		ast_node(bd, BasicDirective, ce->proc);
 		String name = bd->name;
-		GB_ASSERT(name == "location");
-		if (ce->args.count > 1) {
-			error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count);
-		}
-		if (ce->args.count > 0) {
-			AstNode *arg = ce->args[0];
-			Entity *e = nullptr;
-			Operand o = {};
-			if (arg->kind == AstNode_Ident) {
-				e = check_ident(c, &o, arg, nullptr, nullptr, true);
-			} else if (arg->kind == AstNode_SelectorExpr) {
-				e = check_selector(c, &o, arg, nullptr);
+		if (name == "location") {
+			if (ce->args.count > 1) {
+				error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count);
 			}
-			if (e == nullptr) {
-				error(ce->args[0], "'#location' expected a valid entity name");
+			if (ce->args.count > 0) {
+				AstNode *arg = ce->args[0];
+				Entity *e = nullptr;
+				Operand o = {};
+				if (arg->kind == AstNode_Ident) {
+					e = check_ident(c, &o, arg, nullptr, nullptr, true);
+				} else if (arg->kind == AstNode_SelectorExpr) {
+					e = check_selector(c, &o, arg, nullptr);
+				}
+				if (e == nullptr) {
+					error(ce->args[0], "'#location' expected a valid entity name");
+				}
 			}
-		}
 
+			operand->type = t_source_code_location;
+			operand->mode = Addressing_Value;
+		} else if (name == "assert") {
+			if (ce->args.count != 1) {
+				error(call, "'#assert' expects at 1 argument, got %td", ce->args.count);
+				return false;
+			}
+			if (!is_type_boolean(operand->type) && operand->mode != Addressing_Constant) {
+				gbString str = expr_to_string(ce->args[0]);
+				error(call, "'%s' is not a constant boolean", str);
+				gb_string_free(str);
+				return false;
+			}
+			if (!operand->value.value_bool) {
+				gbString arg = expr_to_string(ce->args[0]);
+				error(call, "Compile time assertion: %s", arg);
+				gb_string_free(arg);
+			}
 
-		operand->type = t_source_code_location;
-		operand->mode = Addressing_Value;
+			operand->type = t_untyped_bool;
+			operand->mode = Addressing_Constant;
+		} else {
+			GB_PANIC("Unhandled #%.*s", LIT(name));
+		}
 
 		break;
 	}
@@ -3321,25 +3342,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		break;
 	}
 
-	case BuiltinProc_compile_assert:
-		// proc compile_assert(cond: bool) -> bool
-
-		if (!is_type_boolean(operand->type) && operand->mode != Addressing_Constant) {
-			gbString str = expr_to_string(ce->args[0]);
-			error(call, "'%s' is not a constant boolean", str);
-			gb_string_free(str);
-			return false;
-		}
-		if (!operand->value.value_bool) {
-			gbString str = expr_to_string(ce->args[0]);
-			error(call, "Compile time assertion: '%s'", str);
-			gb_string_free(str);
-		}
-
-		operand->mode = Addressing_Constant;
-		operand->type = t_untyped_bool;
-		break;
-
 	case BuiltinProc_swizzle: {
 		// proc swizzle(v: [N]T, ...int) -> [M]T
 		Type *type = base_type(operand->type);
@@ -4805,12 +4807,15 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
 	    ce->proc->kind == AstNode_BasicDirective) {
 		ast_node(bd, BasicDirective, ce->proc);
 		String name = bd->name;
-		GB_ASSERT(name == "location");
-		operand->mode = Addressing_Builtin;
-		operand->builtin_id = BuiltinProc_DIRECTIVE;
-		operand->expr = ce->proc;
-		operand->type = t_invalid;
-		add_type_and_value(&c->info, ce->proc, operand->mode, operand->type, operand->value);
+		if (name == "location" || name == "assert") {
+			operand->mode = Addressing_Builtin;
+			operand->builtin_id = BuiltinProc_DIRECTIVE;
+			operand->expr = ce->proc;
+			operand->type = t_invalid;
+			add_type_and_value(&c->info, ce->proc, operand->mode, operand->type, operand->value);
+		} else {
+			GB_PANIC("Unhandled #%.*s", LIT(name));
+		}
 	} else {
 		check_expr_or_type(c, operand, ce->proc);
 	}

+ 12 - 0
src/checker.cpp

@@ -1,6 +1,8 @@
 #include "entity.cpp"
 #include "types.cpp"
 
+void check_expr(Checker *c, Operand *operand, AstNode *expression);
+
 
 bool is_operand_value(Operand o) {
 	switch (o.mode) {
@@ -272,6 +274,7 @@ void destroy_scope(Scope *scope) {
 	map_destroy(&scope->elements);
 	array_free(&scope->shared);
 	array_free(&scope->delayed_file_decls);
+	array_free(&scope->delayed_asserts);
 	ptr_set_destroy(&scope->implicit);
 	ptr_set_destroy(&scope->imported);
 	ptr_set_destroy(&scope->exported);
@@ -444,6 +447,7 @@ GB_COMPARE_PROC(entity_variable_pos_cmp) {
 	return token_pos_cmp(x->token.pos, y->token.pos);
 }
 
+
 void check_scope_usage(Checker *c, Scope *scope) {
 	// TODO(bill): Use this?
 #if 0
@@ -2678,6 +2682,14 @@ bool collect_file_decls(Checker *c, Array<AstNode *> decls) {
 				}
 			}
 		case_end;
+
+		case_ast_node(ce, CallExpr, decl);
+			if (ce->proc->kind == AstNode_BasicDirective &&
+			    ce->proc->BasicDirective.name == "assert") {
+				Operand o = {};
+				check_expr(c, &o, decl);
+			}
+		case_end;
 		}
 	}
 

+ 1 - 4
src/checker.hpp

@@ -90,8 +90,6 @@ enum BuiltinProcId {
 	BuiltinProc_type_of,
 	BuiltinProc_type_info_of,
 
-	BuiltinProc_compile_assert,
-
 	BuiltinProc_swizzle,
 
 	BuiltinProc_complex,
@@ -134,8 +132,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("type_of"),          1, false, Expr_Expr},
 	{STR_LIT("type_info_of"),     1, false, Expr_Expr},
 
-	{STR_LIT("compile_assert"),   1, false, Expr_Expr},
-
 	{STR_LIT("swizzle"),          1, true,  Expr_Expr},
 
 	{STR_LIT("complex"),          2, false, Expr_Expr},
@@ -221,6 +217,7 @@ struct Scope {
 
 	Array<Scope *>   shared;
 	Array<AstNode *> delayed_file_decls;
+	Array<AstNode *> delayed_asserts;
 	PtrSet<Scope *>  imported;
 	PtrSet<Scope *>  exported; // NOTE(bhall): Contains 'using import' too
 	bool             is_proc;

+ 0 - 2
src/entity.cpp

@@ -303,8 +303,6 @@ Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
 	return entity;
 }
 
-
-
 Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
 	token.string = str_lit("_");
 	return make_entity_variable(a, scope, token, nullptr, false);

+ 16 - 6
src/parser.cpp

@@ -1358,6 +1358,7 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 			switch (f->curr_token.kind) {
 			case Token_CloseBrace:
 			case Token_CloseParen:
+			case Token_else:
 				return;
 			}
 		}
@@ -1658,6 +1659,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		} else if (name.string == "location") {
 			AstNode *tag = ast_basic_directive(f, token, name.string);
 			return parse_call_expr(f, tag);
+		} else if (name.string == "assert") {
+			AstNode *tag = ast_basic_directive(f, token, name.string);
+			return parse_call_expr(f, tag);
 		} else {
 			operand = ast_tag_expr(f, token, name, parse_expr(f, false));
 		}
@@ -3175,7 +3179,7 @@ AstNode *parse_when_stmt(AstFile *f) {
 			break;
 		case Token_do: {
 			Token arrow = expect_token(f, Token_do);
-			body = convert_stmt_to_body(f, parse_stmt(f));
+			else_stmt = convert_stmt_to_body(f, parse_stmt(f));
 		} break;
 		default:
 			syntax_error(f->curr_token, "Expected when statement block statement");
@@ -3184,11 +3188,6 @@ AstNode *parse_when_stmt(AstFile *f) {
 		}
 	}
 
-	// if (f->curr_proc == nullptr && f->when_level > 1) {
-	// 	syntax_error(token, "Nested when statements are not currently supported at the file scope");
-	// 	return ast_bad_stmt(f, token, f->curr_token);
-	// }
-
 	return ast_when_stmt(f, token, cond, body, else_stmt);
 }
 
@@ -3739,6 +3738,9 @@ AstNode *parse_stmt(AstFile *f) {
 				break;
 			}
 			return s;
+		} else if (tag == "assert") {
+			AstNode *t = ast_basic_directive(f, hash_token, tag);
+			return parse_call_expr(f, t);
 		}
 
 		if (tag == "include") {
@@ -4062,6 +4064,14 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNod
 		    node->kind != AstNode_EmptyStmt &&
 		    node->kind != AstNode_WhenStmt) {
 			// NOTE(bill): Sanity check
+
+			if (node->kind == AstNode_CallExpr &&
+			    node->CallExpr.proc->kind == AstNode_BasicDirective &&
+			    node->CallExpr.proc->BasicDirective.name == "assert") {
+				// NOTE(bill): Okay!
+				continue;
+			}
+
 			syntax_error(node, "Only declarations are allowed at file scope, got %.*s", LIT(ast_node_strings[node->kind]));
 		} else if (node->kind == AstNode_ImportDecl) {
 			ast_node(id, ImportDecl, node);