Browse Source

Add `#+feature dynamic-literals`

gingerBill 7 months ago
parent
commit
2efe4c2d68
4 changed files with 88 additions and 2 deletions
  1. 12 0
      src/build_settings.cpp
  2. 8 2
      src/check_expr.cpp
  3. 66 0
      src/parser.cpp
  4. 2 0
      src/parser.hpp

+ 12 - 0
src/build_settings.cpp

@@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) {
 	return VetFlag_NONE;
 }
 
+enum OptInFeatureFlags : u64 {
+	OptInFeatureFlag_NONE            = 0,
+	OptInFeatureFlag_DynamicLiterals = 1u<<0,
+};
+
+u64 get_feature_flag_from_name(String const &name) {
+	if (name == "dynamic-literals") {
+		return OptInFeatureFlag_DynamicLiterals;
+	}
+	return OptInFeatureFlag_NONE;
+}
+
 
 enum SanitizerFlags : u32 {
 	SanitizerFlag_NONE = 0,

+ 8 - 2
src/check_expr.cpp

@@ -9730,8 +9730,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 
 
 		if (t->kind == Type_DynamicArray) {
-			if (build_context.no_dynamic_literals && cl->elems.count) {
+			if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) {
+				ERROR_BLOCK();
 				error(node, "Compound literals of dynamic types have been disabled");
+				error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n");
+				error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n");
 			}
 		}
 
@@ -10120,8 +10123,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 			}
 		}
 
-		if (build_context.no_dynamic_literals && cl->elems.count) {
+		if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) {
+			ERROR_BLOCK();
 			error(node, "Compound literals of dynamic types have been disabled");
+			error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n");
+			error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n");
 		} else {
 			add_map_reserve_dependencies(c);
 			add_map_set_dependencies(c);

+ 66 - 0
src/parser.cpp

@@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
 			syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
 			error_line("\tExpected one of the following\n");
 			error_line("\tunused\n");
+			error_line("\tunused-variables\n");
+			error_line("\tunused-imports\n");
+			error_line("\tunused-procedures\n");
 			error_line("\tshadowing\n");
 			error_line("\tusing-stmt\n");
 			error_line("\tusing-param\n");
+			error_line("\tstyle\n");
 			error_line("\textra\n");
+			error_line("\tcast\n");
+			error_line("\ttabs\n");
 			return build_context.vet_flags;
 		}
 	}
@@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
 	return vet_flags &~ vet_not_flags;
 }
 
+gb_internal u64 parse_feature_tag(Token token_for_pos, String s) {
+	String const prefix = str_lit("feature");
+	GB_ASSERT(string_starts_with(s, prefix));
+	s = string_trim_whitespace(substring(s, prefix.len, s.len));
+
+	if (s.len == 0) {
+		return OptInFeatureFlag_NONE;
+	}
+
+	u64 feature_flags = 0;
+	u64 feature_not_flags = 0;
+
+	while (s.len > 0) {
+		String p = string_trim_whitespace(vet_tag_get_token(s, &s));
+		if (p.len == 0) {
+			break;
+		}
+
+		bool is_notted = false;
+		if (p[0] == '!') {
+			is_notted = true;
+			p = substring(p, 1, p.len);
+			if (p.len == 0) {
+				syntax_error(token_for_pos, "Expected a feature flag name after '!'");
+				return OptInFeatureFlag_NONE;
+			}
+		}
+
+		u64 flag = get_vet_flag_from_name(p);
+		if (flag != OptInFeatureFlag_NONE) {
+			if (is_notted) {
+				feature_not_flags |= flag;
+			} else {
+				feature_flags     |= flag;
+			}
+		} else {
+			ERROR_BLOCK();
+			syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p));
+			error_line("\tExpected one of the following\n");
+			error_line("\tdynamic-literals\n");
+			return OptInFeatureFlag_NONE;
+		}
+	}
+
+	if (feature_flags == 0 && feature_not_flags == 0) {
+		return OptInFeatureFlag_NONE;
+	}
+	if (feature_flags == 0 && feature_not_flags != 0) {
+		return OptInFeatureFlag_NONE &~ feature_not_flags;
+	}
+	if (feature_flags != 0 && feature_not_flags == 0) {
+		return feature_flags;
+	}
+	GB_ASSERT(feature_flags != 0 && feature_not_flags != 0);
+	return feature_flags &~ feature_not_flags;
+}
+
 gb_internal String dir_from_path(String path) {
 	String base_dir = path;
 	for (isize i = path.len-1; i >= 0; i--) {
@@ -6409,6 +6472,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f)
 		}
 	} else if (lc == "no-instrumentation") {
 		f->flags |= AstFile_NoInstrumentation;
+	} else if (string_starts_with(lc, str_lit("feature"))) {
+		f->feature_flags = parse_feature_tag(tok, lc);
+		f->feature_flags_set = true;
 	} else {
 		error(tok, "Unknown tag '%.*s'", LIT(lc));
 	}

+ 2 - 0
src/parser.hpp

@@ -108,7 +108,9 @@ struct AstFile {
 	String       package_name;
 
 	u64          vet_flags;
+	u64          feature_flags;
 	bool         vet_flags_set;
+	bool         feature_flags_set;
 
 	// >= 0: In Expression
 	// <  0: In Control Clause