Browse Source

Fix procedure's scope

gingerBill 9 years ago
parent
commit
aaecb18c8f
5 changed files with 61 additions and 33 deletions
  1. 14 8
      examples/demo.odin
  2. 25 11
      src/checker/checker.cpp
  3. 0 1
      src/checker/entity.cpp
  4. 2 7
      src/checker/expr.cpp
  5. 20 6
      src/checker/stmt.cpp

+ 14 - 8
examples/demo.odin

@@ -124,6 +124,14 @@ procedures :: proc() {
 		return x + y;
 		return x + y;
 	}
 	}
 
 
+	fibonacci :: proc(n: int) -> int {
+		if n < 2 {
+			return n;
+		}
+		return fibonacci(n-1) + fibonacci(n-2);
+	}
+	print_int(fibonacci(12)); nl();
+
 
 
 	swap_strings :: proc(x, y: string) -> (string, string) {
 	swap_strings :: proc(x, y: string) -> (string, string) {
 		return y, x;
 		return y, x;
@@ -554,19 +562,17 @@ data_control :: proc() {
 		context.allocator = __default_allocator();
 		context.allocator = __default_allocator();
 		defer context.allocator = prev_allocator;
 		defer context.allocator = prev_allocator;
 
 
-	/*
-		type File: struct { filename: string }
-		type FileError: int
-		open_file  :: proc(filename: string) -> (File, FileError) { ... }
-		close_file :: proc(f: ^File) { ... }
+		File :: type struct { filename: string };
+		FileError :: type int;
+		open_file  :: proc(filename: string) -> (File, FileError) {
+			return File{}, 0;
+		}
+		close_file :: proc(f: ^File) {}
 		f, err := open_file("Test");
 		f, err := open_file("Test");
 		if err != 0 {
 		if err != 0 {
 			// handle error
 			// handle error
 		}
 		}
 		defer close_file(^f);
 		defer close_file(^f);
-	*/
-
-
 	}
 	}
 
 
 	for i := 0; i < 100; i++ {
 	for i := 0; i < 100; i++ {

+ 25 - 11
src/checker/checker.cpp

@@ -89,14 +89,15 @@ ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type,
 }
 }
 
 
 struct ProcedureInfo {
 struct ProcedureInfo {
-	AstFile *file;
-	Token            token;
+	AstFile * file;
+	Token     token;
 	DeclInfo *decl;
 	DeclInfo *decl;
-	Type *           type; // Type_Procedure
-	AstNode *        body; // AstNode_BlockStatement
+	Type *    type; // Type_Procedure
+	AstNode * body; // AstNode_BlockStatement
 };
 };
 
 
 struct Scope {
 struct Scope {
+	b32 is_proc;
 	Scope *parent;
 	Scope *parent;
 	Scope *prev, *next;
 	Scope *prev, *next;
 	Scope *first_child, *last_child;
 	Scope *first_child, *last_child;
@@ -231,6 +232,9 @@ void check_open_scope(Checker *c, AstNode *stmt) {
 	GB_ASSERT(is_ast_node_stmt(stmt) || stmt->kind == AstNode_ProcType);
 	GB_ASSERT(is_ast_node_stmt(stmt) || stmt->kind == AstNode_ProcType);
 	Scope *scope = make_scope(c->context.scope, c->allocator);
 	Scope *scope = make_scope(c->context.scope, c->allocator);
 	add_scope(c, stmt, scope);
 	add_scope(c, stmt, scope);
+	if (stmt->kind == AstNode_ProcType) {
+		scope->is_proc = true;
+	}
 	c->context.scope = scope;
 	c->context.scope = scope;
 }
 }
 
 
@@ -238,23 +242,36 @@ void check_close_scope(Checker *c) {
 	c->context.scope = c->context.scope->parent;
 	c->context.scope = c->context.scope->parent;
 }
 }
 
 
-void scope_lookup_parent_entity(Scope *s, String name, Scope **scope, Entity **entity) {
+void scope_lookup_parent_entity(Checker *c, Scope *s, String name, Scope **scope, Entity **entity) {
+	b32 gone_thru_proc = false;
 	HashKey key = hash_string(name);
 	HashKey key = hash_string(name);
 	for (; s != NULL; s = s->parent) {
 	for (; s != NULL; s = s->parent) {
+
 		Entity **found = map_get(&s->elements, key);
 		Entity **found = map_get(&s->elements, key);
 		if (found) {
 		if (found) {
-			if (entity) *entity = *found;
+			Entity *e = *found;
+			if (gone_thru_proc) {
+				if (e->kind == Entity_Variable && e->parent != c->global_scope) {
+					continue;
+				}
+			}
+
+			if (entity) *entity = e;
 			if (scope) *scope = s;
 			if (scope) *scope = s;
 			return;
 			return;
 		}
 		}
+
+		if (s->is_proc) {
+			gone_thru_proc = true;
+		}
 	}
 	}
 	if (entity) *entity = NULL;
 	if (entity) *entity = NULL;
 	if (scope) *scope = NULL;
 	if (scope) *scope = NULL;
 }
 }
 
 
-Entity *scope_lookup_entity(Scope *s, String name) {
+Entity *scope_lookup_entity(Checker *c, Scope *s, String name) {
 	Entity *entity = NULL;
 	Entity *entity = NULL;
-	scope_lookup_parent_entity(s, name, NULL, &entity);
+	scope_lookup_parent_entity(c, s, name, NULL, &entity);
 	return entity;
 	return entity;
 }
 }
 
 
@@ -500,7 +517,6 @@ void add_file_entity(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) {
 
 
 	add_entity(c, c->global_scope, identifier, e);
 	add_entity(c, c->global_scope, identifier, e);
 	map_set(&c->info.entities, hash_pointer(e), d);
 	map_set(&c->info.entities, hash_pointer(e), d);
-	e->order = gb_array_count(c->info.entities.entries);
 }
 }
 
 
 
 
@@ -637,8 +653,6 @@ void check_parsed_files(Checker *c) {
 				DeclInfo *d = make_declaration_info(c->allocator, e->parent);
 				DeclInfo *d = make_declaration_info(c->allocator, e->parent);
 				d->proc_decl = decl;
 				d->proc_decl = decl;
 				map_set(&c->info.entities, hash_pointer(e), d);
 				map_set(&c->info.entities, hash_pointer(e), d);
-				e->order = gb_array_count(c->info.entities.entries);
-
 			case_end;
 			case_end;
 
 
 			case_ast_node(ld, LoadDecl, decl);
 			case_ast_node(ld, LoadDecl, decl);

+ 0 - 1
src/checker/entity.cpp

@@ -34,7 +34,6 @@ struct Entity {
 	Scope *parent;
 	Scope *parent;
 	Token token;
 	Token token;
 	Type *type;
 	Type *type;
-	isize order;
 
 
 	union {
 	union {
 		struct { ExactValue value; } Constant;
 		struct { ExactValue value; } Constant;

+ 2 - 7
src/checker/expr.cpp

@@ -202,7 +202,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
 	o->mode = Addressing_Invalid;
 	o->mode = Addressing_Invalid;
 	o->expr = n;
 	o->expr = n;
 	ast_node(i, Ident, n);
 	ast_node(i, Ident, n);
-	Entity *e = scope_lookup_entity(c->context.scope, i->token.string);
+	Entity *e = scope_lookup_entity(c, c->context.scope, i->token.string);
 	if (e == NULL) {
 	if (e == NULL) {
 		error(&c->error_collector, i->token,
 		error(&c->error_collector, i->token,
 		    "Undeclared type or identifier `%.*s`", LIT(i->token.string));
 		    "Undeclared type or identifier `%.*s`", LIT(i->token.string));
@@ -1959,14 +1959,9 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 	case_end;
 	case_end;
 
 
 	case_ast_node(pl, ProcLit, node);
 	case_ast_node(pl, ProcLit, node);
-		auto curr_context = c->context;
-		c->context.scope = c->global_scope;
 		check_open_scope(c, pl->type);
 		check_open_scope(c, pl->type);
 		c->context.decl = make_declaration_info(c->allocator, c->context.scope);
 		c->context.decl = make_declaration_info(c->allocator, c->context.scope);
-		defer ({
-			check_close_scope(c);
-			c->context = curr_context;
-		});
+		defer (check_close_scope(c));
 		Type *proc_type = check_type(c, pl->type);
 		Type *proc_type = check_type(c, pl->type);
 		if (proc_type != NULL) {
 		if (proc_type != NULL) {
 			check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);
 			check_proc_body(c, empty_token, c->context.decl, proc_type, pl->body);

+ 20 - 6
src/checker/stmt.cpp

@@ -190,7 +190,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 	b32 used = false;
 	b32 used = false;
 	if (node->kind == AstNode_Ident) {
 	if (node->kind == AstNode_Ident) {
 		ast_node(i, Ident, node);
 		ast_node(i, Ident, node);
-		e = scope_lookup_entity(c->context.scope, i->token.string);
+		e = scope_lookup_entity(c, c->context.scope, i->token.string);
 		if (e != NULL && e->kind == Entity_Variable) {
 		if (e != NULL && e->kind == Entity_Variable) {
 			used = e->Variable.used; // TODO(bill): Make backup just in case
 			used = e->Variable.used; // TODO(bill): Make backup just in case
 		}
 		}
@@ -398,20 +398,34 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 	e->type = proc_type;
 	e->type = proc_type;
 	ast_node(pd, ProcDecl, d->proc_decl);
 	ast_node(pd, ProcDecl, d->proc_decl);
 
 
-	Scope *original_curr_scope = c->context.scope;
-	c->context.scope = c->global_scope;
 	check_open_scope(c, pd->type);
 	check_open_scope(c, pd->type);
 	defer ({
 	defer ({
 		check_close_scope(c);
 		check_close_scope(c);
-		c->context.scope = original_curr_scope;
 	});
 	});
 
 
 
 
 	check_procedure_type(c, proc_type, pd->type);
 	check_procedure_type(c, proc_type, pd->type);
-	b32 is_foreign   = (pd->tags & ProcTag_foreign) != 0;
-	b32 is_inline    = (pd->tags & ProcTag_inline) != 0;
+	b32 is_foreign   = (pd->tags & ProcTag_foreign)   != 0;
+	b32 is_inline    = (pd->tags & ProcTag_inline)    != 0;
 	b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
 	b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
 
 
+
+
+	if (d->scope == c->global_scope &&
+	    are_strings_equal(e->token.string, make_string("main"))) {
+		if (proc_type != NULL) {
+			auto *pt = &proc_type->proc;
+			if (pt->param_count != 0 ||
+			    pt->result_count) {
+				gbString str = type_to_string(proc_type);
+				defer (gb_string_free(str));
+
+				error(&c->error_collector, e->token,
+				      "Procedure type of `main` was expected to be `proc()`, got %s", str);
+			}
+		}
+	}
+
 	if (is_inline && is_no_inline) {
 	if (is_inline && is_no_inline) {
 		error(&c->error_collector, ast_node_token(pd->type),
 		error(&c->error_collector, ast_node_token(pd->type),
 		      "You cannot apply both `inline` and `no_inline` to a procedure");
 		      "You cannot apply both `inline` and `no_inline` to a procedure");