Browse Source

Add `@(link_suffix=<string>)`

gingerBill 1 năm trước cách đây
mục cha
commit
75f40b4078
5 tập tin đã thay đổi với 79 bổ sung9 xóa
  1. 25 6
      src/check_decl.cpp
  2. 2 2
      src/check_stmt.cpp
  3. 46 0
      src/checker.cpp
  4. 4 1
      src/checker.hpp
  5. 2 0
      src/entity.cpp

+ 25 - 6
src/check_decl.cpp

@@ -724,9 +724,10 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e)
 	return nullptr;
 }
 
-gb_internal String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
+gb_internal String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix, String link_suffix) {
+	String original_link_name = link_name;
 	if (link_prefix.len > 0) {
-		if (link_name.len > 0) {
+		if (original_link_name.len > 0) {
 			error(token, "'link_name' and 'link_prefix' cannot be used together");
 		} else {
 			isize len = link_prefix.len + token.string.len;
@@ -738,6 +739,24 @@ gb_internal String handle_link_name(CheckerContext *ctx, Token token, String lin
 			link_name = make_string(name, len);
 		}
 	}
+
+	if (link_suffix.len > 0) {
+		if (original_link_name.len > 0) {
+			error(token, "'link_name' and 'link_suffix' cannot be used together");
+		} else {
+			String new_name = token.string;
+			if (link_name != original_link_name) {
+				new_name = link_name;
+			}
+
+			isize len = new_name.len + link_suffix.len;
+			u8 *name = gb_alloc_array(permanent_allocator(), u8, len+1);
+			gb_memmove(name, &new_name[0], new_name.len);
+			gb_memmove(name+new_name.len, &link_suffix[0], link_suffix.len);
+			name[len] = 0;
+			link_name = make_string(name, len);
+		}
+	}
 	return link_name;
 }
 
@@ -862,7 +881,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 	}
 
 	TypeProc *pt = &proc_type->Proc;
-	AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
+	AttributeContext ac = make_attribute_context(e->Procedure.link_prefix, e->Procedure.link_suffix);
 
 	if (d != nullptr) {
 		check_decl_attributes(ctx, d->attributes, proc_decl_attribute, &ac);
@@ -995,7 +1014,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 
 	e->deprecated_message = ac.deprecated_message;
 	e->warning_message = ac.warning_message;
-	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
+	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix, ac.link_suffix);
 	if (ac.has_disabled_proc) {
 		if (ac.disabled_proc) {
 			e->flags |= EntityFlag_Disabled;
@@ -1203,7 +1222,7 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast
 	}
 	e->flags |= EntityFlag_Visited;
 
-	AttributeContext ac = make_attribute_context(e->Variable.link_prefix);
+	AttributeContext ac = make_attribute_context(e->Variable.link_prefix, e->Variable.link_suffix);
 	ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
 
 	DeclInfo *decl = decl_info_of_entity(e);
@@ -1224,7 +1243,7 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast
 	if (ac.is_static) {
 		error(e->token, "@(static) is not supported for global variables, nor required");
 	}
-	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
+	ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix, ac.link_suffix);
 
 	if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
 		e->Variable.thread_local_model.len = 0;

+ 2 - 2
src/check_stmt.cpp

@@ -1871,7 +1871,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
 
 
 	// TODO NOTE(bill): This technically checks things multple times
-	AttributeContext ac = make_attribute_context(ctx->foreign_context.link_prefix);
+	AttributeContext ac = make_attribute_context(ctx->foreign_context.link_prefix, ctx->foreign_context.link_suffix);
 	check_decl_attributes(ctx, vd->attributes, var_decl_attribute, &ac);
 
 	for (isize i = 0; i < entity_count; i++) {
@@ -1888,7 +1888,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
 			e->type = init_type;
 			e->state = EntityState_Resolved;
 		}
-		ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
+		ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix, ac.link_suffix);
 
 		if (ac.link_name.len > 0) {
 			e->Variable.link_name = ac.link_name;

+ 46 - 0
src/checker.cpp

@@ -3067,6 +3067,18 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
 			error(elem, "Expected a string value for '%.*s'", LIT(name));
 		}
 		return true;
+	} else if (name == "link_suffix") {
+		if (ev.kind == ExactValue_String) {
+			String link_suffix = ev.value_string;
+			if (!is_foreign_name_valid(link_suffix)) {
+				error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix));
+			} else {
+				c->foreign_context.link_suffix = link_suffix;
+			}
+		} else {
+			error(elem, "Expected a string value for '%.*s'", LIT(name));
+		}
+		return true;
 	} else if (name == "private") {
 		EntityVisiblityKind kind = EntityVisiblity_PrivateToPackage;
 		if (ev.kind == ExactValue_Invalid) {
@@ -3360,6 +3372,18 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 			error(elem, "Expected a string value for '%.*s'", LIT(name));
 		}
 		return true;
+	} else if (name == "link_suffix") {
+		ExactValue ev = check_decl_attribute_value(c, value);
+
+		if (ev.kind == ExactValue_String) {
+			ac->link_suffix = ev.value_string;
+			if (!is_foreign_name_valid(ac->link_suffix)) {
+				error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
+			}
+		} else {
+			error(elem, "Expected a string value for '%.*s'", LIT(name));
+		}
+		return true;
 	} else if (name == "deprecated") {
 		ExactValue ev = check_decl_attribute_value(c, value);
 
@@ -3638,6 +3662,17 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
 			error(elem, "Expected a string value for '%.*s'", LIT(name));
 		}
 		return true;
+	} else if (name == "link_suffix") {
+		ExactValue ev = check_decl_attribute_value(c, value);
+		if (ev.kind == ExactValue_String) {
+			ac->link_suffix = ev.value_string;
+			if (!is_foreign_name_valid(ac->link_suffix)) {
+				error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
+			}
+		} else {
+			error(elem, "Expected a string value for '%.*s'", LIT(name));
+		}
+		return true;
 	} else if (name == "link_section") {
 		ExactValue ev = check_decl_attribute_value(c, value);
 		if (ev.kind == ExactValue_String) {
@@ -3702,8 +3737,10 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
 	if (attributes.count == 0) return;
 
 	String original_link_prefix = {};
+	String original_link_suffix = {};
 	if (ac) {
 		original_link_prefix = ac->link_prefix;
+		original_link_suffix = ac->link_suffix;
 	}
 
 	StringSet set = {};
@@ -3777,6 +3814,13 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
 				ac->link_prefix.len  = 0;
 			}
 		}
+
+		if (ac->link_suffix.text == original_link_suffix.text) {
+			if (ac->link_name.len > 0) {
+				ac->link_suffix.text = nullptr;
+				ac->link_suffix.len  = 0;
+			}
+		}
 	}
 }
 
@@ -4068,6 +4112,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 				e->Variable.foreign_library_ident = fl;
 
 				e->Variable.link_prefix = c->foreign_context.link_prefix;
+				e->Variable.link_suffix = c->foreign_context.link_suffix;
 			}
 
 			Ast *init_expr = value;
@@ -4142,6 +4187,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 						}
 					}
 					e->Procedure.link_prefix = c->foreign_context.link_prefix;
+					e->Procedure.link_suffix = c->foreign_context.link_suffix;
 
 					GB_ASSERT(cc != ProcCC_Invalid);
 					pl->type->ProcType.calling_convention = cc;

+ 4 - 1
src/checker.hpp

@@ -112,6 +112,7 @@ enum InstrumentationFlag : i32 {
 struct AttributeContext {
 	String  link_name;
 	String  link_prefix;
+	String  link_suffix;
 	String  link_section;
 	String  linkage;
 	isize   init_expr_list_count;
@@ -146,9 +147,10 @@ struct AttributeContext {
 	String enable_target_feature;  // will be enabled for the procedure only
 };
 
-gb_internal gb_inline AttributeContext make_attribute_context(String link_prefix) {
+gb_internal gb_inline AttributeContext make_attribute_context(String link_prefix, String link_suffix) {
 	AttributeContext ac = {};
 	ac.link_prefix = link_prefix;
+	ac.link_suffix = link_suffix;
 	return ac;
 }
 
@@ -302,6 +304,7 @@ struct ForeignContext {
 	Ast *                 curr_library;
 	ProcCallingConvention default_cc;
 	String                link_prefix;
+	String                link_suffix;
 	EntityVisiblityKind   visibility_kind;
 };
 

+ 2 - 0
src/entity.cpp

@@ -224,6 +224,7 @@ struct Entity {
 			Ast *      foreign_library_ident;
 			String     link_name;
 			String     link_prefix;
+			String     link_suffix;
 			String     link_section;
 			CommentGroup *docs;
 			CommentGroup *comment;
@@ -243,6 +244,7 @@ struct Entity {
 			Ast *   foreign_library_ident;
 			String  link_name;
 			String  link_prefix;
+			String  link_suffix;
 			DeferredProcedure deferred_procedure;
 
 			struct GenProcsData *gen_procs;