From a240a3d14660f6b33f839a3ebf142e20aac3e80a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 28 Dec 2018 13:31:06 +0000 Subject: [PATCH] `static` variable declarations (Experimental) --- src/check_stmt.cpp | 16 ++++++++++++++++ src/checker.cpp | 12 ++++++++++++ src/entity.cpp | 1 + src/ir.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 2 ++ src/parser.cpp | 32 ++++++++++++++++++++++++++++---- src/parser.hpp | 1 + src/tokenizer.cpp | 2 +- 8 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 811f59907..b6e0a7f58 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1667,6 +1667,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (!is_blank_ident(str)) { found = scope_lookup_current(ctx->scope, str); new_name_count += 1; + } else if (vd->is_static) { + error(name, "'static' is now allowed to be applied to '_'"); } if (found == nullptr) { entity = alloc_entity_variable(ctx->scope, token, nullptr, false); @@ -1678,6 +1680,9 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { entity->Variable.is_foreign = true; entity->Variable.foreign_library_ident = fl; } + if (vd->is_static) { + entity->flags |= EntityFlag_Static; + } } else { TokenPos pos = found->token.pos; error(token, @@ -1780,6 +1785,17 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } else { map_set(fp, key, e); } + } else if (e->flags & EntityFlag_Static) { + if (vd->values.count > 0) { + if (entity_count != vd->values.count) { + error(e->token, "A static variable declaration with a default value must be constant"); + } else { + Ast *value = vd->values[i]; + if (value->tav.mode != Addressing_Constant) { + error(e->token, "A static variable declaration with a default value must be constant"); + } + } + } } add_entity(ctx->checker, ctx->scope, e->identifier, e); } diff --git a/src/checker.cpp b/src/checker.cpp index 7f56770b9..c2318e499 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2282,6 +2282,10 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { e->flags |= EntityFlag_NotExported; } + if (vd->is_static) { + e->flags |= EntityFlag_Static; + } + if (vd->is_using) { vd->is_using = false; // NOTE(bill): This error will be only caught once error(name, "'using' is not allowed at the file scope"); @@ -2386,6 +2390,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { e->flags |= EntityFlag_NotExported; } + if (vd->is_static) { + if (e->kind == Entity_Constant) { + e->flags |= EntityFlag_Static; + } else { + error(name, "'static' is not allowed on this constant value declaration"); + } + } + if (vd->is_using) { if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) { d->is_using = true; diff --git a/src/entity.cpp b/src/entity.cpp index f4bc99247..c9dc966ec 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -47,6 +47,7 @@ enum EntityFlag { EntityFlag_PolyConst = 1<<13, EntityFlag_NotExported = 1<<14, + EntityFlag_Static = 1<<16, EntityFlag_CVarArg = 1<<20, EntityFlag_AutoCast = 1<<21, diff --git a/src/ir.cpp b/src/ir.cpp index 540347724..c94b2ec59 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -405,6 +405,7 @@ struct irValueGlobal { bool is_constant; bool is_export; bool is_private; + bool is_internal; String thread_local_model; bool is_foreign; bool is_unnamed_addr; @@ -7941,6 +7942,44 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { case_ast_node(vd, ValueDecl, node); if (vd->is_mutable) { irModule *m = proc->module; + + if (vd->is_static) { + for_array(i, vd->names) { + irValue *value = nullptr; + if (vd->values.count > 0) { + GB_ASSERT(vd->names.count == vd->values.count); + Ast *ast_value = vd->values[i]; + GB_ASSERT(ast_value->tav.mode == Addressing_Constant || + ast_value->tav.mode == Addressing_Invalid); + + value = ir_add_module_constant(m, ast_value->tav.type, ast_value->tav.value); + } + + Ast *ident = vd->names[i]; + GB_ASSERT(!is_blank_ident(ident)); + Entity *e = entity_of_ident(ident); + GB_ASSERT(e->flags & EntityFlag_Static); + String name = e->token.string; + HashKey key = hash_string(name); + + String mangled_name = {}; + { + gbString str = gb_string_make_length(heap_allocator(), proc->name.text, proc->name.len); + str = gb_string_appendc(str, "-"); + str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); + mangled_name.text = cast(u8 *)str; + mangled_name.len = gb_string_length(str); + } + + irValue *g = ir_value_global(e, value); + g->Global.name = mangled_name; + g->Global.is_internal = true; + ir_module_add_value(proc->module, e, g); + map_set(&proc->module->members, key, g); + } + return; + } + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); defer (gb_temp_arena_memory_end(tmp)); @@ -10143,6 +10182,10 @@ void ir_gen_tree(irGen *s) { ir_add_foreign_library_path(m, fl); } + if (e->flags & EntityFlag_Static) { + var->var->Global.is_internal = true; + } + if (var->init != nullptr) { Type *t = type_deref(ir_type(var->var)); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 74da92bf0..3da15607c 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2233,6 +2233,8 @@ void print_llvm_ir(irGen *ir) { if (g->is_private) { ir_write_string(f, str_lit("private ")); + } else if (g->is_internal) { + ir_write_string(f, str_lit("internal ")); } if (g->is_constant) { if (g->is_unnamed_addr) { diff --git a/src/parser.cpp b/src/parser.cpp index 85943fa00..9eeb6ea8c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3810,6 +3810,34 @@ Ast *parse_stmt(AstFile *f) { return s; } + case Token_static: { + CommentGroup *docs = f->lead_comment; + Token token = expect_token(f, Token_static); + + Ast *decl = nullptr; + Array list = parse_lhs_expr_list(f); + if (list.count == 0) { + syntax_error(token, "Illegal use of 'static' statement"); + expect_semicolon(f, nullptr); + return ast_bad_stmt(f, token, f->curr_token); + } + + expect_token_after(f, Token_Colon, "identifier list"); + decl = parse_value_decl(f, list, docs); + + if (decl != nullptr && decl->kind == Ast_ValueDecl) { + if (decl->ValueDecl.is_mutable) { + decl->ValueDecl.is_static = true; + } else { + error(token, "'static' may only be currently used with variable declaration"); + } + return decl; + } + + syntax_error(token, "Illegal use of 'static' statement"); + return ast_bad_stmt(f, token, f->curr_token); + } break; + case Token_using: { CommentGroup *docs = f->lead_comment; Token token = expect_token(f, Token_using); @@ -3833,10 +3861,6 @@ Ast *parse_stmt(AstFile *f) { decl = parse_value_decl(f, list, docs); if (decl != nullptr && decl->kind == Ast_ValueDecl) { - // if (!decl->ValueDecl.is_mutable) { - // syntax_error(token, "'using' may only be applied to variable declarations"); - // return decl; - // } decl->ValueDecl.is_using = true; return decl; } diff --git a/src/parser.hpp b/src/parser.hpp index f48e230ff..7f069d591 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -374,6 +374,7 @@ AST_KIND(_DeclBegin, "", bool) \ Array attributes; \ CommentGroup *docs; \ CommentGroup *comment; \ + bool is_static; \ bool is_using; \ bool is_mutable; \ }) \ diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index fc93dda76..02770e371 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -108,7 +108,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_bit_field, "bit_field"), \ TOKEN_KIND(Token_bit_set, "bit_set"), \ TOKEN_KIND(Token_map, "map"), \ - TOKEN_KIND(Token_static, "static"), \ + TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_auto_cast, "auto_cast"), \ TOKEN_KIND(Token_cast, "cast"), \