Browse Source

Define where `#bounds_check`/`#no_bounds_check` can be applied

gingerBill 4 years ago
parent
commit
d5e3f72a0b
2 changed files with 72 additions and 44 deletions
  1. 72 42
      src/parser.cpp
  2. 0 2
      src/parser.hpp

+ 72 - 42
src/parser.cpp

@@ -1932,6 +1932,73 @@ Ast *parse_force_inlining_operand(AstFile *f, Token token) {
 }
 }
 
 
 
 
+Ast *parse_check_directive_for_statement(Ast *s, Token const &tag_token, u16 state_flag) {
+	String name = tag_token.string;
+
+	if (s == nullptr) {
+		syntax_error(tag_token, "Invalid operand for #%.*s", LIT(name));
+		return nullptr;
+	}
+
+	if (s != nullptr && s->kind == Ast_EmptyStmt) {
+		if (s->EmptyStmt.token.string == "\n") {
+			syntax_error(tag_token, "#%.*s cannot be followed by a newline", LIT(name));
+		} else {
+			syntax_error(tag_token, "#%.*s cannot be applied to an empty statement ';'", LIT(name));
+		}
+	}
+
+	if (s->state_flags & state_flag) {
+		syntax_error(tag_token, "#%.*s has been applied multiple times", LIT(name));
+	}
+	s->state_flags |= state_flag;
+
+	switch (state_flag) {
+	case StateFlag_bounds_check:
+		if ((s->state_flags & StateFlag_no_bounds_check) != 0) {
+			syntax_error(tag_token, "#bounds_check and #no_bounds_check cannot be applied together");
+		}
+		break;
+	case StateFlag_no_bounds_check:
+		if ((s->state_flags & StateFlag_bounds_check) != 0) {
+			syntax_error(tag_token, "#bounds_check and #no_bounds_check cannot be applied together");
+		}
+		break;
+	}
+
+	switch (state_flag) {
+	case StateFlag_bounds_check:
+	case StateFlag_no_bounds_check:
+		switch (s->kind) {
+		case Ast_BlockStmt:
+		case Ast_IfStmt:
+		case Ast_WhenStmt:
+		case Ast_ForStmt:
+		case Ast_RangeStmt:
+		case Ast_UnrollRangeStmt:
+		case Ast_SwitchStmt:
+		case Ast_TypeSwitchStmt:
+		case Ast_ReturnStmt:
+		case Ast_DeferStmt:
+			// Okay
+			break;
+
+		case Ast_ValueDecl:
+			if (!s->ValueDecl.is_mutable) {
+				syntax_error(tag_token, "#%.*s may only be applied to a variable declaration, and not a constant value declaration", LIT(name));
+			}
+			break;
+		default:
+			syntax_error(tag_token, "#%.*s may only be applied to the following statements: '{}', 'if', 'when', 'for', 'switch', 'return', 'defer', variable declaration", LIT(name));
+			break;
+		}
+		break;
+	}
+
+	return s;
+}
+
+
 Ast *parse_operand(AstFile *f, bool lhs) {
 Ast *parse_operand(AstFile *f, bool lhs) {
 	Ast *operand = nullptr; // Operand
 	Ast *operand = nullptr; // Operand
 	switch (f->curr_token.kind) {
 	switch (f->curr_token.kind) {
@@ -2040,26 +2107,10 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 			return original_type;
 			return original_type;
 		} else if (name.string == "bounds_check") {
 		} else if (name.string == "bounds_check") {
 			Ast *operand = parse_expr(f, lhs);
 			Ast *operand = parse_expr(f, lhs);
-			if (operand == nullptr) {
-				syntax_error(token, "Invalid expresssion for #%.*s", LIT(name.string));
-				return nullptr;
-			}
-			operand->state_flags |= StateFlag_bounds_check;
-			if ((operand->state_flags & StateFlag_no_bounds_check) != 0) {
-				syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
-			}
-			return operand;
+			return parse_check_directive_for_statement(operand, name, StateFlag_bounds_check);
 		} else if (name.string == "no_bounds_check") {
 		} else if (name.string == "no_bounds_check") {
 			Ast *operand = parse_expr(f, lhs);
 			Ast *operand = parse_expr(f, lhs);
-			if (operand == nullptr) {
-				syntax_error(token, "Invalid expresssion for #%.*s", LIT(name.string));
-				return nullptr;
-			}
-			operand->state_flags |= StateFlag_no_bounds_check;
-			if ((operand->state_flags & StateFlag_bounds_check) != 0) {
-				syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
-			}
-			return operand;
+			return parse_check_directive_for_statement(operand, name, StateFlag_no_bounds_check);
 		} else if (name.string == "relative") {
 		} else if (name.string == "relative") {
 			Ast *tag = ast_basic_directive(f, token, name);
 			Ast *tag = ast_basic_directive(f, token, name);
 			tag = parse_call_expr(f, tag);
 			tag = parse_call_expr(f, tag);
@@ -4369,16 +4420,6 @@ Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) {
 	return ast_unroll_range_stmt(f, unroll_token, for_token, val0, val1, in_token, expr, body);
 	return ast_unroll_range_stmt(f, unroll_token, for_token, val0, val1, in_token, expr, body);
 }
 }
 
 
-void parse_check_directive_for_empty_statement(Ast *s, Token const &name) {
-	if (s != nullptr && s->kind == Ast_EmptyStmt) {
-		if (s->EmptyStmt.token.string == "\n") {
-			syntax_error(name, "#%.*s cannot be followed by a newline", LIT(name.string));
-		} else {
-			syntax_error(name, "#%.*s cannot be applied to an empty statement ';'", LIT(name.string));
-		}
-	}
-}
-
 Ast *parse_stmt(AstFile *f) {
 Ast *parse_stmt(AstFile *f) {
 	Ast *s = nullptr;
 	Ast *s = nullptr;
 	Token token = f->curr_token;
 	Token token = f->curr_token;
@@ -4485,20 +4526,10 @@ Ast *parse_stmt(AstFile *f) {
 
 
 		if (tag == "bounds_check") {
 		if (tag == "bounds_check") {
 			s = parse_stmt(f);
 			s = parse_stmt(f);
-			parse_check_directive_for_empty_statement(s, name);
-			s->state_flags |= StateFlag_bounds_check;
-			if ((s->state_flags & StateFlag_no_bounds_check) != 0) {
-				syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
-			}
-			return s;
+			return parse_check_directive_for_statement(s, name, StateFlag_bounds_check);
 		} else if (tag == "no_bounds_check") {
 		} else if (tag == "no_bounds_check") {
 			s = parse_stmt(f);
 			s = parse_stmt(f);
-			parse_check_directive_for_empty_statement(s, name);
-			s->state_flags |= StateFlag_no_bounds_check;
-			if ((s->state_flags & StateFlag_bounds_check) != 0) {
-				syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
-			}
-			return s;
+			return parse_check_directive_for_statement(s, name, StateFlag_no_bounds_check);
 		} else if (tag == "partial") {
 		} else if (tag == "partial") {
 			s = parse_stmt(f);
 			s = parse_stmt(f);
 			switch (s->kind) {
 			switch (s->kind) {
@@ -4509,8 +4540,7 @@ Ast *parse_stmt(AstFile *f) {
 				s->TypeSwitchStmt.partial = true;
 				s->TypeSwitchStmt.partial = true;
 				break;
 				break;
 			case Ast_EmptyStmt:
 			case Ast_EmptyStmt:
-				parse_check_directive_for_empty_statement(s, name);
-				break;
+				return parse_check_directive_for_statement(s, name, 0);
 			default:
 			default:
 				syntax_error(token, "#partial can only be applied to a switch statement");
 				syntax_error(token, "#partial can only be applied to a switch statement");
 				break;
 				break;

+ 0 - 2
src/parser.hpp

@@ -259,8 +259,6 @@ enum StateFlag : u16 {
 	StateFlag_bounds_check    = 1<<0,
 	StateFlag_bounds_check    = 1<<0,
 	StateFlag_no_bounds_check = 1<<1,
 	StateFlag_no_bounds_check = 1<<1,
 
 
-	StateFlag_no_deferred = 1<<5,
-
 	StateFlag_BeenHandled = 1<<15,
 	StateFlag_BeenHandled = 1<<15,
 };
 };