From 97c2437d975f225784e0d6c16a737403c5a2fb47 Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 26 Sep 2019 16:04:11 -0300 Subject: [PATCH] add basic business logic for scopes --- src/comp_ctx.zig | 67 +++++++++++++++++++++++++++++++++++++++--------- src/types.zig | 16 ++++++++++-- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index ddb8e89..0668e8a 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -29,10 +29,31 @@ pub const SymbolUnderlyingType = union(SymbolUnderlyingTypeEnum) { Enum: []const u8, }; -pub const Scope = std.StringHashMap(SymbolUnderlyingType); -pub const Environment = struct { - parent: *Environment, - scope: Scope, +pub const Environment = std.StringHashMap(SymbolUnderlyingType); +pub const Scope = struct { + parent: ?*Scope, + env: Environment, + + allocator: *std.mem.Allocator, + + pub fn create(allocator: *std.mem.Allocator, parent: ?*Scope) !*Scope { + var scope = try allocator.create(Scope); + + scope.* = Scope{ + .parent = scope, + .env = Environment.init(allocator), + .allocator = allocator, + }; + return scope; + } + + pub fn createChild(self: *@This()) !*Scope { + return try @This().create(self.allocator, self); + } + + pub fn deinit(self: *const @This()) void { + self.env.deinit(); + } }; // functions, for our purposes, other than symbols, have: @@ -45,12 +66,7 @@ pub const FunctionSymbol = struct { /// Parameters for a function are also a table instead of an ArrayList /// because we want to resolve identifiers to them. parameters: UnderlyingTypeMap, - - // TODO rm - symbols: SymbolTable, - - // use this instead - //env: *Environment, + scope: *Scope, /// Find a given identifier in the function. Can resolve to either a parameter pub fn findSymbol(self: *const @This(), identifier: []const u8) ?SymbolData { @@ -103,6 +119,9 @@ pub const CompilationContext = struct { allocator: *std.mem.Allocator, symbol_table: SymbolTable, + current_function: ?*FunctionSymbol = null, + current_scope: ?*Scope = null, + pub fn init(allocator: *std.mem.Allocator) CompilationContext { return CompilationContext{ .allocator = allocator, @@ -110,6 +129,30 @@ pub const CompilationContext = struct { }; } + /// Create a new scope out of the current one and set it as the current. + pub fn bumpScope(self: *@This()) !void { + if (self.current_scope == null) { + @panic("can't bump scope from null"); + } + + var child = try self.current_scope.?.createChild(); + self.current_scope = child; + } + + /// Set a given scope as the current scope. + pub fn setScope(self: *@This(), scope: *Scope) void { + self.current_scope = scope; + } + + /// "dump" the current scope, making the new current scope be its parent. + pub fn dumpScope(self: *@This()) void { + if (self.current_scope == null) { + @panic("can't dump scope from null"); + } + + self.current_scope = self.current_scope.?.parent; + } + /// Solve a given type as a string into a SymbolUnderlyingTypeEnum /// This does not help if you want a full SymbolUnderlyingType, use /// solveType() for that. @@ -157,7 +200,7 @@ pub const CompilationContext = struct { decl: ast.FnDecl, ret_type: SymbolUnderlyingType, param_types: TypeList, - symbols: SymbolTable, + scope: *Scope, ) !void { var type_map = UnderlyingTypeMap.init(self.allocator); @@ -170,7 +213,7 @@ pub const CompilationContext = struct { .decl = decl, .return_type = ret_type, .parameters = type_map, - .symbols = symbols, + .scope = scope, }, }); } diff --git a/src/types.zig b/src/types.zig index f5f031e..1d5cae0 100644 --- a/src/types.zig +++ b/src/types.zig @@ -262,12 +262,24 @@ pub const TypeSolver = struct { try parameters.append(param_type.?); } - // TODO scopes: bump scope + // for a function, we always create a new root scope for it + // and force-set it into the current context + var scope = try comp.Scope.create(self.allocator, null); + errdefer scope.deinit(); + + // we must always start from a null current scope, + // functions inside functions are not allowed + std.debug.assert(ctx.current_scope == null); + ctx.setScope(scope); for (decl.body.toSlice()) |stmt| { try self.stmtPass(ctx, stmt); } + // it should be null when we dump from a function. always + ctx.dumpScope(); + std.debug.assert(ctx.current_scope == null); + // TODO scopes: down scope // TODO symbols and scope resolution, that's @@ -278,7 +290,7 @@ pub const TypeSolver = struct { // and everything else if (ret_type != null and parameters.len == decl.params.len) { - try ctx.insertFn(decl, ret_type.?, parameters, symbols); + try ctx.insertFn(decl, ret_type.?, parameters, scope); } },