ast_printer: fix children printing

- add scope ids for debug purposes
 - add children to parent on Scope.createChild
 - types: add validation of if's condition expr type
 - types: add scopes to ifs
This commit is contained in:
Luna 2019-09-26 21:36:26 -03:00
parent fc9f5d9ce0
commit 093a8003b6
3 changed files with 39 additions and 22 deletions

View file

@ -370,7 +370,7 @@ fn prettyType(typ: SymbolUnderlyingType) []const u8 {
}
pub fn printScope(scope: *Scope, ident: usize) void {
print(ident, "scope at addr {}\n", &scope);
print(ident, "scope '{}' at addr {}\n", scope.id, &scope);
var it = scope.env.iterator();
while (it.next()) |kv| {
@ -378,7 +378,7 @@ pub fn printScope(scope: *Scope, ident: usize) void {
}
for (scope.children.toSlice()) |child| {
printScope(scope, ident + 1);
printScope(child, ident + 1);
}
}

View file

@ -39,8 +39,9 @@ pub const Scope = struct {
children: ScopeList,
allocator: *std.mem.Allocator,
id: ?[]const u8 = null,
pub fn create(allocator: *std.mem.Allocator, parent: ?*Scope) !*Scope {
pub fn create(allocator: *std.mem.Allocator, parent: ?*Scope, id: ?[]const u8) !*Scope {
var scope = try allocator.create(Scope);
scope.* = Scope{
@ -48,12 +49,15 @@ pub const Scope = struct {
.env = Environment.init(allocator),
.children = ScopeList.init(allocator),
.allocator = allocator,
.id = id,
};
return scope;
}
pub fn createChild(self: *@This()) !*Scope {
return try @This().create(self.allocator, self);
pub fn createChild(self: *@This(), id: ?[]const u8) !*Scope {
var child = try @This().create(self.allocator, self, id);
try self.children.append(child);
return child;
}
pub fn deinit(self: *const @This()) void {
@ -135,12 +139,14 @@ 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 {
pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void {
if (self.current_scope == null) {
@panic("can't bump scope from null");
}
var child = try self.current_scope.?.createChild();
std.debug.warn("==scope bump== '{}'\n", scope_id);
var child = try self.current_scope.?.createChild(scope_id);
self.current_scope = child;
}
@ -155,6 +161,14 @@ pub const CompilationContext = struct {
@panic("can't dump scope from null");
}
const parent_id: ?[]const u8 = if (self.current_scope.?.parent == null) null else self.current_scope.?.parent.?.id;
std.debug.warn(
"==scope dump== {} to {}\n",
self.current_scope.?.id,
parent_id,
);
self.current_scope = self.current_scope.?.parent;
}

View file

@ -88,6 +88,14 @@ pub const TypeSolver = struct {
}
}
pub fn expectSymUnType(self: *@This(), symbol_type: comp.SymbolUnderlyingType, wanted_type: comp.SymbolUnderlyingTypeEnum) !void {
var actual_type = comp.SymbolUnderlyingTypeEnum(symbol_type);
if (actual_type != wanted_type) {
std.debug.warn("Expected {}, got {}\n", wanted_type, actual_type);
return CompileError.TypeError;
}
}
// TODO make return type optional and so, skip exprs that
// fail to be fully resolved, instead of returning CompileError
pub fn resolveExprType(
@ -235,17 +243,21 @@ pub const TypeSolver = struct {
// If create two scopes for each branch of the if
.If => |ifstmt| {
_ = try self.resolveExprType(ctx, ifstmt.condition);
var cond_type = try self.resolveExprType(ctx, ifstmt.condition);
try self.expectSymUnType(cond_type, .Bool);
// TODO assert condition's type is bool
try ctx.bumpScope("if_then");
// TODO bump-dump scope
for (ifstmt.then_branch.toSlice()) |then_stmt| {
try self.stmtPass(ctx, then_stmt);
}
ctx.dumpScope();
if (ifstmt.else_branch) |else_branch| {
// TODO bump-dump scope
try ctx.bumpScope("if_else");
defer ctx.dumpScope();
for (else_branch.toSlice()) |else_stmt| {
try self.stmtPass(ctx, else_stmt);
}
@ -287,7 +299,7 @@ pub const TypeSolver = struct {
self.setErrContext("function {}", decl.func_name.lexeme);
var ret_type = self.resolveGlobalType(ctx, decl.return_type.lexeme);
std.debug.warn("resolved fn {} type: {}\n", decl.func_name.lexeme, ret_type);
std.debug.warn("start analysis of fn {} ret_type: {}\n", decl.func_name.lexeme, ret_type);
var parameters = comp.TypeList.init(self.allocator);
for (decl.params.toSlice()) |param| {
@ -298,7 +310,7 @@ pub const TypeSolver = struct {
// 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);
var scope = try comp.Scope.create(self.allocator, null, "function");
errdefer scope.deinit();
// we must always start from a null current scope,
@ -314,15 +326,6 @@ pub const TypeSolver = struct {
ctx.dumpScope();
std.debug.assert(ctx.current_scope == null);
// TODO scopes: down scope
// TODO symbols and scope resolution, that's
// its own can of worms
var symbols = comp.SymbolTable.init(self.allocator);
// TODO go through body, resolve statements, expressions
// and everything else
if (ret_type != null and parameters.len == decl.params.len) {
try ctx.insertFn(decl, ret_type.?, parameters, scope);
}