Browse Source

Allow for chaining of '#load(path) or_else #load(path)'

gingerBill 3 years ago
parent
commit
cecadce86d
2 changed files with 58 additions and 53 deletions
  1. 29 27
      src/check_builtin.cpp
  2. 29 26
      src/check_expr.cpp

+ 29 - 27
src/check_builtin.cpp

@@ -1163,6 +1163,27 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
 }
 }
 
 
 
 
+bool is_valid_type_for_load(Type *type) {
+	if (type == t_invalid) {
+		return false;
+	} else if (is_type_string(type)) {
+		return true;
+	} else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) {
+		Type *elem = nullptr;
+		Type *bt = base_type(type);
+		if (bt->kind == Type_Slice) {
+			elem = bt->Slice.elem;
+		} else if (bt->kind == Type_Array) {
+			elem = bt->Array.elem;
+		} else if (bt->kind == Type_EnumeratedArray) {
+			elem = bt->EnumeratedArray.elem;
+		}
+		GB_ASSERT(elem != nullptr);
+		return is_type_load_safe(elem);
+	}
+	return false;
+}
+
 LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
 LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
 	ast_node(ce, CallExpr, call);
 	ast_node(ce, CallExpr, call);
 	ast_node(bd, BasicDirective, ce->proc);
 	ast_node(bd, BasicDirective, ce->proc);
@@ -1198,42 +1219,23 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
 
 
 	operand->type = t_u8_slice;
 	operand->type = t_u8_slice;
 	if (ce->args.count == 1) {
 	if (ce->args.count == 1) {
-		if (type_hint && is_type_string(type_hint)) {
+		if (type_hint && is_valid_type_for_load(type_hint)) {
 			operand->type = type_hint;
 			operand->type = type_hint;
 		}
 		}
 	} else if (ce->args.count == 2) {
 	} else if (ce->args.count == 2) {
-		bool failed = false;
 		Ast *arg_type = ce->args[1];
 		Ast *arg_type = ce->args[1];
 		Type *type = check_type(c, arg_type);
 		Type *type = check_type(c, arg_type);
-		if (type != nullptr && type != t_invalid) {
-			if (is_type_string(type)) {
+		if (type != nullptr) {
+			if (is_valid_type_for_load(type)) {
 				operand->type = type;
 				operand->type = type;
-			} else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) {
-				Type *elem = nullptr;
-				Type *bt = base_type(type);
-				if (bt->kind == Type_Slice) {
-					elem = bt->Slice.elem;
-				} else if (bt->kind == Type_Array) {
-					elem = bt->Array.elem;
-				} else if (bt->kind == Type_EnumeratedArray) {
-					elem = bt->EnumeratedArray.elem;
-				}
-				GB_ASSERT(elem != nullptr);
-				if (is_type_load_safe(elem)) {
-					operand->type = type;
-				} else {
-					failed = true;
-				}
 			} else {
 			} else {
-				failed = true;
+				gbString type_str = type_to_string(type);
+				error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str);
+				gb_string_free(type_str);
 			}
 			}
 		}
 		}
-
-		if (failed) {
-			gbString type_str = type_to_string(type);
-			error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str);
-			gb_string_free(type_str);
-		}
+	} else {
+		GB_PANIC("unreachable");
 	}
 	}
 	operand->mode = Addressing_Constant;
 	operand->mode = Addressing_Constant;
 
 

+ 29 - 26
src/check_expr.cpp

@@ -7436,36 +7436,39 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
 	if (is_load_directive_call(arg)) {
 	if (is_load_directive_call(arg)) {
 		LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false);
 		LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false);
 
 
-		bool y_is_diverging = false;
-		check_expr_base(c, &y, default_value, x.type);
-		switch (y.mode) {
-		case Addressing_NoValue:
-			if (is_diverging_expr(y.expr)) {
-				// Allow
-				y.mode = Addressing_Value;
-				y_is_diverging = true;
-			} else {
-				error_operand_no_value(&y);
+		// Allow for chaining of '#load(path) or_else #load(path)'
+		if (!(is_load_directive_call(default_value) && res == LoadDirective_Success)) {
+			bool y_is_diverging = false;
+			check_expr_base(c, &y, default_value, x.type);
+			switch (y.mode) {
+			case Addressing_NoValue:
+				if (is_diverging_expr(y.expr)) {
+					// Allow
+					y.mode = Addressing_Value;
+					y_is_diverging = true;
+				} else {
+					error_operand_no_value(&y);
+					y.mode = Addressing_Invalid;
+				}
+				break;
+			case Addressing_Type:
+				error_operand_not_expression(&y);
 				y.mode = Addressing_Invalid;
 				y.mode = Addressing_Invalid;
+				break;
 			}
 			}
-			break;
-		case Addressing_Type:
-			error_operand_not_expression(&y);
-			y.mode = Addressing_Invalid;
-			break;
-		}
 
 
-		if (y.mode == Addressing_Invalid) {
-			o->mode = Addressing_Value;
-			o->type = t_invalid;
-			o->expr = node;
-			return Expr_Expr;
-		}
+			if (y.mode == Addressing_Invalid) {
+				o->mode = Addressing_Value;
+				o->type = t_invalid;
+				o->expr = node;
+				return Expr_Expr;
+			}
 
 
-		if (!y_is_diverging) {
-			check_assignment(c, &y, x.type, name);
-			if (y.mode != Addressing_Constant) {
-				error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'");
+			if (!y_is_diverging) {
+				check_assignment(c, &y, x.type, name);
+				if (y.mode != Addressing_Constant) {
+					error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'");
+				}
 			}
 			}
 		}
 		}