Browse Source

Cleanup attribute handling

gingerBill 7 years ago
parent
commit
e6c99cd289
3 changed files with 167 additions and 263 deletions
  1. 21 179
      src/check_decl.cpp
  2. 6 54
      src/check_stmt.cpp
  3. 140 30
      src/checker.cpp

+ 21 - 179
src/check_decl.cpp

@@ -478,85 +478,15 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	bool is_export          = e->Procedure.is_export;
 	bool is_export          = e->Procedure.is_export;
 	bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
 	bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
 
 
-	String link_name = {};
-	String link_prefix = e->Procedure.link_prefix;
-	bool link_prefix_overridden = false;
-
-
-	if (d != nullptr && d->attributes.count > 0) {
-		StringSet set = {};
-		string_set_init(&set, heap_allocator());
-		defer (string_set_destroy(&set));
-
-		for_array(i, d->attributes) {
-			AstNode *attr = d->attributes[i];
-			if (attr->kind != AstNode_Attribute) continue;
-			for_array(j, attr->Attribute.elems) {
-				AstNode *elem = attr->Attribute.elems[j];
-				String name = {};
-				AstNode *value = nullptr;
-
-				switch (elem->kind) {
-				case_ast_node(i, Ident, elem);
-					name = i->token.string;
-				case_end;
-				case_ast_node(fv, FieldValue, elem);
-					GB_ASSERT(fv->field->kind == AstNode_Ident);
-					name = fv->field->Ident.token.string;
-					value = fv->value;
-				case_end;
-				default:
-					error(elem, "Invalid attribute element");
-					continue;
-				}
-
-				ExactValue ev = {};
-				if (value != nullptr) {
-					Operand op = {};
-					check_expr(c, &op, value);
-					if (op.mode != Addressing_Constant) {
-						error(value, "An attribute element must be constant");
-					} else {
-						ev = op.value;
-					}
-				}
-
-				if (string_set_exists(&set, name)) {
-					error(elem, "Previous declaration of `%.*s`", LIT(name));
-				} else {
-					string_set_add(&set, name);
-				}
+	AttributeContext ac = {};
+	ac.link_prefix = e->Procedure.link_prefix;
 
 
-				if (name == "link_name") {
-					if (ev.kind == ExactValue_String) {
-						link_name = ev.value_string;
-						if (!is_foreign_name_valid(link_name)) {
-							error(elem, "Invalid link name: %.*s", LIT(link_name));
-						}
-					} else {
-						error(elem, "Expected a string value for `%.*s`", LIT(name));
-					}
-				} else if (name == "link_prefix") {
-					if (ev.kind == ExactValue_String) {
-						if (link_prefix.len > 0) {
-							link_prefix_overridden = true;
-						}
-						link_prefix = ev.value_string;
-						if (!is_foreign_name_valid(link_prefix)) {
-							error(elem, "Invalid link prefix: %.*s", LIT(link_prefix));
-						}
-					} else {
-						error(elem, "Expected a string value for `%.*s`", LIT(name));
-					}
-				} else {
-					error(elem, "Unknown attribute element name `%.*s`", LIT(name));
-				}
-			}
-		}
+	if (d != nullptr) {
+		check_decl_attributes(c, d->attributes, proc_decl_attribute, &ac);
 	}
 	}
 
 
 
 
-	link_name = handle_link_name(c, e->token, link_name, link_prefix, link_prefix_overridden);
+	ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix, ac.link_prefix_overridden);
 
 
 	if (d->scope->file != nullptr && e->token.string == "main") {
 	if (d->scope->file != nullptr && e->token.string == "main") {
 		if (pt->param_count != 0 ||
 		if (pt->param_count != 0 ||
@@ -626,8 +556,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 
 
 	if (is_foreign) {
 	if (is_foreign) {
 		String name = e->token.string;
 		String name = e->token.string;
-		if (link_name.len > 0) {
-			name = link_name;
+		if (ac.link_name.len > 0) {
+			name = ac.link_name;
 		}
 		}
 		e->Procedure.is_foreign = true;
 		e->Procedure.is_foreign = true;
 		e->Procedure.link_name = name;
 		e->Procedure.link_name = name;
@@ -662,11 +592,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 		}
 		}
 	} else {
 	} else {
 		String name = e->token.string;
 		String name = e->token.string;
-		if (link_name.len > 0) {
-			name = link_name;
+		if (ac.link_name.len > 0) {
+			name = ac.link_name;
 		}
 		}
 
 
-		if (link_name.len > 0 || is_export) {
+		if (ac.link_name.len > 0 || is_export) {
 			auto *fp = &c->info.foreigns;
 			auto *fp = &c->info.foreigns;
 
 
 			e->Procedure.link_name = name;
 			e->Procedure.link_name = name;
@@ -700,105 +630,17 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
 	}
 	}
 	e->flags |= EntityFlag_Visited;
 	e->flags |= EntityFlag_Visited;
 
 
-
-	String link_prefix = e->Variable.link_prefix;
-	String link_name = {};
-	bool link_prefix_overridden = false;
+	AttributeContext ac = {};
+	ac.entity = e;
+	ac.link_prefix = e->Variable.link_prefix;
+	ac.init_expr_list_count = init_expr_list.count;
 
 
 	DeclInfo *decl = decl_info_of_entity(&c->info, e);
 	DeclInfo *decl = decl_info_of_entity(&c->info, e);
-	if (decl != nullptr && decl->attributes.count > 0) {
-		StringSet set = {};
-		string_set_init(&set, heap_allocator());
-		defer (string_set_destroy(&set));
-
-		for_array(i, decl->attributes) {
-			AstNode *attr = decl->attributes[i];
-			if (attr->kind != AstNode_Attribute) continue;
-			for_array(j, attr->Attribute.elems) {
-				AstNode *elem = attr->Attribute.elems[j];
-				String name = {};
-				AstNode *value = nullptr;
-
-				switch (elem->kind) {
-				case_ast_node(i, Ident, elem);
-					name = i->token.string;
-				case_end;
-				case_ast_node(fv, FieldValue, elem);
-					GB_ASSERT(fv->field->kind == AstNode_Ident);
-					name = fv->field->Ident.token.string;
-					value = fv->value;
-				case_end;
-				default:
-					error(elem, "Invalid attribute element");
-					continue;
-				}
-
-				ExactValue ev = {};
-				if (value != nullptr) {
-					Operand op = {};
-					check_expr(c, &op, value);
-					if (op.mode != Addressing_Constant) {
-						error(value, "An attribute element must be constant");
-					} else {
-						ev = op.value;
-					}
-				}
-
-				if (string_set_exists(&set, name)) {
-					error(elem, "Previous declaration of `%.*s`", LIT(name));
-					continue;
-				} else {
-					string_set_add(&set, name);
-				}
-
-				if (name == "link_name") {
-					if (ev.kind == ExactValue_String) {
-						link_name = ev.value_string;
-						if (!is_foreign_name_valid(link_name)) {
-							error(elem, "Invalid link name: %.*s", LIT(link_name));
-						}
-					} else {
-						error(elem, "Expected a string value for `%.*s`", LIT(name));
-					}
-				} else if (name == "thread_local") {
-					if (!e->scope->is_file) {
-						error(elem, "Only a variable at file scope can be thread local");
-					} else if (init_expr_list.count > 0) {
-						error(elem, "A thread local variable declaration cannot have initialization values");
-					} else if (ev.kind == ExactValue_Invalid) {
-						e->Variable.thread_local_model = str_lit("default");
-					} else if (ev.kind == ExactValue_String) {
-						String model = ev.value_string;
-						if (model == "localdynamic" ||
-						    model == "initialexec" ||
-						    model == "localexec") {
-							e->Variable.thread_local_model = model;
-						} else {
-							error(elem, "Invalid thread local model `%.*s`", LIT(model));
-						}
-					} else {
-						error(elem, "Expected either no value or a string for `%.*s`", LIT(name));
-					}
-				} else if (name == "link_prefix") {
-					if (ev.kind == ExactValue_String) {
-						if (link_prefix.len > 0) {
-							link_prefix_overridden = true;
-						}
-						link_prefix = ev.value_string;
-						if (!is_foreign_name_valid(link_prefix)) {
-							error(elem, "Invalid link prefix: %.*s", LIT(link_prefix));
-						}
-					} else {
-						error(elem, "Expected a string value for `%.*s`", LIT(name));
-					}
-				} else {
-					error(elem, "Unknown attribute element name `%.*s`", LIT(name));
-				}
-			}
-		}
+	if (decl != nullptr) {
+		check_decl_attributes(c, decl->attributes, var_decl_attribute, &ac);
 	}
 	}
 
 
-	link_name = handle_link_name(c, e->token, link_name, link_prefix, link_prefix_overridden);
+	ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix, ac.link_prefix_overridden);
 
 
 
 
 	String context_name = str_lit("variable declaration");
 	String context_name = str_lit("variable declaration");
@@ -827,14 +669,14 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
 		}
 		}
 		init_entity_foreign_library(c, e);
 		init_entity_foreign_library(c, e);
 	}
 	}
-	if (link_name.len > 0) {
-		e->Variable.link_name = link_name;
+	if (ac.link_name.len > 0) {
+		e->Variable.link_name = ac.link_name;
 	}
 	}
 
 
 	if (e->Variable.is_foreign || e->Variable.is_export) {
 	if (e->Variable.is_foreign || e->Variable.is_export) {
 		String name = e->token.string;
 		String name = e->token.string;
-		if (link_name.len > 0) {
-			name = link_name;
+		if (e->Variable.link_name.len > 0) {
+			name = e->Variable.link_name;
 		}
 		}
 		auto *fp = &c->info.foreigns;
 		auto *fp = &c->info.foreigns;
 		HashKey key = hash_string(name);
 		HashKey key = hash_string(name);

+ 6 - 54
src/check_stmt.cpp

@@ -1673,7 +1673,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			c->context.foreign_context.default_cc = ProcCC_CDecl;
 			c->context.foreign_context.default_cc = ProcCC_CDecl;
 		}
 		}
 
 
-		check_foreign_block_decl_attributes(c, fb);
+		check_decl_attributes(c, fb->attributes, foreign_block_decl_attribute, nullptr);
 
 
 		for_array(i, fb->decls) {
 		for_array(i, fb->decls) {
 			AstNode *decl = fb->decls[i];
 			AstNode *decl = fb->decls[i];
@@ -1692,59 +1692,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
 		Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
 		isize entity_count = 0;
 		isize entity_count = 0;
 
 
-		if (vd->attributes.count > 0) {
-			StringSet set = {};
-			string_set_init(&set, heap_allocator());
-			defer (string_set_destroy(&set));
-
-			for_array(i, vd->attributes) {
-				AstNode *attr = vd->attributes[i];
-				if (attr->kind != AstNode_Attribute) continue;
-				for_array(j, attr->Attribute.elems) {
-					AstNode *elem = attr->Attribute.elems[j];
-					String name = {};
-					AstNode *value = nullptr;
-
-					switch (elem->kind) {
-					case_ast_node(i, Ident, elem);
-						name = i->token.string;
-					case_end;
-					case_ast_node(fv, FieldValue, elem);
-						GB_ASSERT(fv->field->kind == AstNode_Ident);
-						name = fv->field->Ident.token.string;
-						value = fv->value;
-					case_end;
-					default:
-						error(elem, "Invalid attribute element");
-						continue;
-					}
-
-					ExactValue ev = {};
-					if (value != nullptr) {
-						Operand op = {};
-						check_expr(c, &op, value);
-						if (op.mode != Addressing_Constant) {
-							error(value, "An attribute element must be constant");
-						} else {
-							ev = op.value;
-						}
-					}
-
-					if (string_set_exists(&set, name)) {
-						error(elem, "Previous declaration of `%.*s`", LIT(name));
-						continue;
-					} else {
-						string_set_add(&set, name);
-					}
-
-					if (name == "thread_local") {
-						error(elem, "Variable within a procedure cannot be thread local");
-					} else {
-						error(elem, "Unknown attribute element name `%.*s`", LIT(name));
-					}
-				}
-			}
-		}
 
 
 		for_array(i, vd->names) {
 		for_array(i, vd->names) {
 			AstNode *name = vd->names[i];
 			AstNode *name = vd->names[i];
@@ -1815,6 +1762,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			if (e->type == nullptr) {
 			if (e->type == nullptr) {
 				e->type = init_type;
 				e->type = init_type;
 			}
 			}
+
+
+			AttributeContext ac = {};
+			ac.entity = e;
+			check_decl_attributes(c, vd->attributes, var_decl_attribute, &ac);
 		}
 		}
 
 
 		check_arity_match(c, vd);
 		check_arity_match(c, vd);

+ 140 - 30
src/checker.cpp

@@ -1858,7 +1858,139 @@ void check_procedure_overloading(Checker *c, Entity *e) {
 	gb_temp_arena_memory_end(tmp);
 	gb_temp_arena_memory_end(tmp);
 }
 }
 
 
-void check_foreign_block_decl_attributes(Checker *c, AstNodeForeignBlockDecl *fb);
+
+struct AttributeContext {
+	String  link_name;
+	String  link_prefix;
+	bool    link_prefix_overridden;
+	Entity *entity;
+	isize   init_expr_list_count;
+};
+
+#define DECL_ATTRIBUTE_PROC(_name) bool _name(Checker *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
+typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
+
+
+void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
+
+
+
+DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
+	if (name == "default_calling_convention") {
+		if (value.kind == ExactValue_String) {
+			auto cc = string_to_calling_convention(value.value_string);
+			if (cc == ProcCC_Invalid) {
+				error(elem, "Unknown procedure calling convention: `%.*s`\n", LIT(value.value_string));
+			} else {
+				c->context.foreign_context.default_cc = cc;
+			}
+		} else {
+			error(elem, "Expected a string value for `%.*s`", LIT(name));
+		}
+		return true;
+	} else if (name == "link_prefix") {
+		if (value.kind == ExactValue_String) {
+			String link_prefix = value.value_string;
+			if (!is_foreign_name_valid(link_prefix)) {
+				error(elem, "Invalid link prefix: `%.*s`\n", LIT(link_prefix));
+			} else {
+				c->context.foreign_context.link_prefix = link_prefix;
+			}
+		} else {
+			error(elem, "Expected a string value for `%.*s`", LIT(name));
+		}
+		return true;
+	}
+
+	return false;
+}
+
+
+
+DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
+	if (name == "link_name") {
+		if (value.kind == ExactValue_String) {
+			ac->link_name = value.value_string;
+			if (!is_foreign_name_valid(ac->link_name)) {
+				error(elem, "Invalid link name: %.*s", LIT(ac->link_name));
+			}
+		} else {
+			error(elem, "Expected a string value for `%.*s`", LIT(name));
+		}
+		return true;
+	} else if (name == "link_prefix") {
+		if (value.kind == ExactValue_String) {
+			if (ac->link_prefix.len > 0) {
+				ac->link_prefix_overridden = true;
+			}
+			ac->link_prefix = value.value_string;
+			if (!is_foreign_name_valid(ac->link_prefix)) {
+				error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix));
+			}
+		} else {
+			error(elem, "Expected a string value for `%.*s`", LIT(name));
+		}
+		return true;
+	}
+	return false;
+}
+
+DECL_ATTRIBUTE_PROC(var_decl_attribute) {
+	GB_ASSERT(ac->entity != nullptr);
+	Entity *e = ac->entity;
+	GB_ASSERT(e->kind == Entity_Variable);
+
+	if (!e->scope->is_file) {
+		error(elem, "Only a variable at file scope can have a `%.*s`", LIT(name));
+		return true;
+	}
+
+	if (name == "link_name") {
+		if (value.kind == ExactValue_String) {
+			ac->link_name = value.value_string;
+			if (!is_foreign_name_valid(ac->link_name)) {
+				error(elem, "Invalid link name: %.*s", LIT(ac->link_name));
+			}
+		} else {
+			error(elem, "Expected a string value for `%.*s`", LIT(name));
+		}
+		return true;
+	} else if (name == "link_prefix") {
+		if (value.kind == ExactValue_String) {
+			if (ac->link_prefix.len > 0) {
+				ac->link_prefix_overridden = true;
+			}
+			ac->link_prefix = value.value_string;
+			if (!is_foreign_name_valid(ac->link_prefix)) {
+				error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix));
+			}
+		} else {
+			error(elem, "Expected a string value for `%.*s`", LIT(name));
+		}
+		return true;
+	} else if (name == "thread_local") {
+		if (ac->init_expr_list_count > 0) {
+			error(elem, "A thread local variable declaration cannot have initialization values");
+		} else if (value.kind == ExactValue_Invalid) {
+			e->Variable.thread_local_model = str_lit("default");
+		} else if (value.kind == ExactValue_String) {
+			String model = value.value_string;
+			if (model == "localdynamic" ||
+			    model == "initialexec" ||
+			    model == "localexec") {
+				e->Variable.thread_local_model = model;
+			} else {
+				error(elem, "Invalid thread local model `%.*s`", LIT(model));
+			}
+		} else {
+			error(elem, "Expected either no value or a string for `%.*s`", LIT(name));
+		}
+		return true;
+	}
+	return false;
+}
+
+
 
 
 #include "check_expr.cpp"
 #include "check_expr.cpp"
 #include "check_type.cpp"
 #include "check_type.cpp"
@@ -1866,14 +1998,15 @@ void check_foreign_block_decl_attributes(Checker *c, AstNodeForeignBlockDecl *fb
 #include "check_stmt.cpp"
 #include "check_stmt.cpp"
 
 
 
 
-void check_foreign_block_decl_attributes(Checker *c, AstNodeForeignBlockDecl *fb) {
-	if (fb->attributes.count == 0) return;
+
+void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac) {
+	if (attributes.count == 0) return;
 	StringSet set = {};
 	StringSet set = {};
 	string_set_init(&set, heap_allocator());
 	string_set_init(&set, heap_allocator());
 	defer (string_set_destroy(&set));
 	defer (string_set_destroy(&set));
 
 
-	for_array(i, fb->attributes) {
-		AstNode *attr = fb->attributes[i];
+	for_array(i, attributes) {
+		AstNode *attr = attributes[i];
 		if (attr->kind != AstNode_Attribute) continue;
 		if (attr->kind != AstNode_Attribute) continue;
 		for_array(j, attr->Attribute.elems) {
 		for_array(j, attr->Attribute.elems) {
 			AstNode *elem = attr->Attribute.elems[j];
 			AstNode *elem = attr->Attribute.elems[j];
@@ -1912,29 +2045,7 @@ void check_foreign_block_decl_attributes(Checker *c, AstNodeForeignBlockDecl *fb
 				string_set_add(&set, name);
 				string_set_add(&set, name);
 			}
 			}
 
 
-			if (name == "default_calling_convention") {
-				if (ev.kind == ExactValue_String) {
-					auto cc = string_to_calling_convention(ev.value_string);
-					if (cc == ProcCC_Invalid) {
-						error(elem, "Unknown procedure calling convention: `%.*s`\n", LIT(ev.value_string));
-					} else {
-						c->context.foreign_context.default_cc = cc;
-					}
-				} else {
-					error(elem, "Expected a string value for `%.*s`", LIT(name));
-				}
-			} else if (name == "link_prefix") {
-				if (ev.kind == ExactValue_String) {
-					String link_prefix = ev.value_string;
-					if (!is_foreign_name_valid(link_prefix)) {
-						error(elem, "Invalid link prefix: `%.*s`\n", LIT(link_prefix));
-					} else {
-						c->context.foreign_context.link_prefix = link_prefix;
-					}
-				} else {
-					error(elem, "Expected a string value for `%.*s`", LIT(name));
-				}
-			} else {
+			if (!proc(c, elem, name, ev, ac)) {
 				error(elem, "Unknown attribute element name `%.*s`", LIT(name));
 				error(elem, "Unknown attribute element name `%.*s`", LIT(name));
 			}
 			}
 		}
 		}
@@ -1942,7 +2053,6 @@ void check_foreign_block_decl_attributes(Checker *c, AstNodeForeignBlockDecl *fb
 }
 }
 
 
 
 
-
 bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global) {
 bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global) {
 	isize lhs = vd->names.count;
 	isize lhs = vd->names.count;
 	isize rhs = vd->values.count;
 	isize rhs = vd->values.count;
@@ -2194,7 +2304,7 @@ void check_add_foreign_block_decl(Checker *c, AstNode *decl) {
 		c->context.foreign_context.curr_library = nullptr;
 		c->context.foreign_context.curr_library = nullptr;
 	}
 	}
 
 
-	check_foreign_block_decl_attributes(c, fb);
+	check_decl_attributes(c, fb->attributes, foreign_block_decl_attribute, nullptr);
 
 
 	c->context.collect_delayed_decls = true;
 	c->context.collect_delayed_decls = true;
 	check_collect_entities(c, fb->decls);
 	check_collect_entities(c, fb->decls);