From e6c99cd2892cb34beaedfef0c8a786e2e0ef654e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 4 Nov 2017 10:26:56 +0000 Subject: [PATCH] Cleanup attribute handling --- src/check_decl.cpp | 200 +++++---------------------------------------- src/check_stmt.cpp | 60 ++------------ src/checker.cpp | 170 +++++++++++++++++++++++++++++++------- 3 files changed, 167 insertions(+), 263 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index b38575e24..f8893eb67 100644 --- a/src/check_decl.cpp +++ b/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_require_results = (pl->tags & ProcTag_require_results) != 0; - String link_name = {}; - String link_prefix = e->Procedure.link_prefix; - bool link_prefix_overridden = false; + AttributeContext ac = {}; + ac.link_prefix = e->Procedure.link_prefix; - - 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); - } - - 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 (pt->param_count != 0 || @@ -626,8 +556,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { if (is_foreign) { 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.link_name = name; @@ -662,11 +592,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { } } else { 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; 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; - - 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); - 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"); @@ -827,14 +669,14 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } 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) { 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; HashKey key = hash_string(name); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c0e336149..162a87994 100644 --- a/src/check_stmt.cpp +++ b/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; } - check_foreign_block_decl_attributes(c, fb); + check_decl_attributes(c, fb->attributes, foreign_block_decl_attribute, nullptr); for_array(i, fb->decls) { 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); 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) { AstNode *name = vd->names[i]; @@ -1815,6 +1762,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (e->type == nullptr) { e->type = init_type; } + + + AttributeContext ac = {}; + ac.entity = e; + check_decl_attributes(c, vd->attributes, var_decl_attribute, &ac); } check_arity_match(c, vd); diff --git a/src/checker.cpp b/src/checker.cpp index ffca55ce9..0ef3de9fd 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1858,7 +1858,139 @@ void check_procedure_overloading(Checker *c, Entity *e) { 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 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_type.cpp" @@ -1866,14 +1998,15 @@ void check_foreign_block_decl_attributes(Checker *c, AstNodeForeignBlockDecl *fb #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 attributes, DeclAttributeProc *proc, AttributeContext *ac) { + if (attributes.count == 0) return; StringSet set = {}; string_set_init(&set, heap_allocator()); 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; for_array(j, attr->Attribute.elems) { 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); } - 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)); } } @@ -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) { isize lhs = vd->names.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; } - check_foreign_block_decl_attributes(c, fb); + check_decl_attributes(c, fb->attributes, foreign_block_decl_attribute, nullptr); c->context.collect_delayed_decls = true; check_collect_entities(c, fb->decls);