Browse Source

`static` variable declarations (Experimental)

gingerBill 6 years ago
parent
commit
a240a3d146
8 changed files with 104 additions and 5 deletions
  1. 16 0
      src/check_stmt.cpp
  2. 12 0
      src/checker.cpp
  3. 1 0
      src/entity.cpp
  4. 43 0
      src/ir.cpp
  5. 2 0
      src/ir_print.cpp
  6. 28 4
      src/parser.cpp
  7. 1 0
      src/parser.hpp
  8. 1 1
      src/tokenizer.cpp

+ 16 - 0
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);
 			}

+ 12 - 0
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;

+ 1 - 0
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,

+ 43 - 0
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));
 

+ 2 - 0
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) {

+ 28 - 4
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<Ast *> 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;
 		}

+ 1 - 0
src/parser.hpp

@@ -374,6 +374,7 @@ AST_KIND(_DeclBegin,      "", bool) \
 		Array<Ast *> attributes;  \
 		CommentGroup *docs;       \
 		CommentGroup *comment;    \
+		bool          is_static;  \
 		bool          is_using;   \
 		bool          is_mutable; \
 	}) \

+ 1 - 1
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"),        \