diff --git a/examples/hello.ry b/examples/hello.ry index d3a4e54..0f97d4f 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -32,13 +32,12 @@ fn test_function() B { } fn multwo(num: i32, double_flag: bool) i32 { - // TODO resolve expr variables - if (true) { + if (double_flag) { var truthy = true; - return 1 * 2; + return num * 2; } else { var falsey = false; - return 1; + return num; } } diff --git a/src/analysis.zig b/src/analysis.zig index f5c4897..4081d43 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -458,7 +458,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, "function"); + var scope = try comp.Scope.create(self.allocator, null, name); errdefer scope.deinit(); // we intentionally insert the function so that: diff --git a/src/codegen.zig b/src/codegen.zig index 0e1f0be..b7212eb 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -284,6 +284,8 @@ pub const Codegen = struct { var then_rets = false; var else_rets = false; + self.ctx.setScope(self.ctx.current_scope.?.nextChild()); + for (ifstmt.then_branch.toSlice()) |then_stmt| { // keep emitting until branch has ret @@ -296,6 +298,8 @@ pub const Codegen = struct { } } + self.ctx.dumpScope(); + // only build the br instruction if we didn't ret, because // there can't be any instruction after a terminator // same applies for the else branch @@ -309,6 +313,7 @@ pub const Codegen = struct { // roughly translating to kaleidoscope's // 'Else *ElseV = Else->codegen();' if (ifstmt.else_branch) |else_block| { + self.ctx.setScope(self.ctx.current_scope.?.nextChild()); for (else_block.toSlice()) |else_stmt| { // keep emitting until branch has ret if (!else_rets) @@ -319,6 +324,8 @@ pub const Codegen = struct { else => {}, } } + + self.ctx.dumpScope(); } if (!else_rets) @@ -330,18 +337,30 @@ pub const Codegen = struct { if (then_rets and else_rets) _ = llvm.LLVMBuildUnreachable(builder); - - // phis aren't needed since our ifs arent expressions - - //var phi = llvm.LLVMBuildPhi(builder, llvm.LLVMVoidType(), c"iftmp"); - //var then_bb_val = llvm.LLVMBasicBlockAsValue(then_bb); - //var else_bb_val = llvm.LLVMBasicBlockAsValue(else_bb); - //llvm.LLVMAddIncoming(phi, &then_bb_val, &then_bb, 1); - //llvm.LLVMAddIncoming(phi, &else_bb_val, &else_bb, 1); }, // TODO - .VarDecl => {}, + .VarDecl => |vardecl| { + // we alaready inferred the type of the variable in the + // analyze pass and the current scope contains the variable's + // type(hopefully), so we resolve it + const name = vardecl.name.lexeme; + var var_metadata = try self.ctx.resolveVarType(name); + + var name_cstr = try std.cstr.addNullByte(self.allocator, name); + errdefer self.allocator.free(name_cstr); + + var fn_symbol = self.getFnSymbol(self.current_function_name.?); + + _ = llvm.LLVMBuildAlloca( + builder, + try self.typeToLLVM(var_metadata.typ), + name_cstr.ptr, + ); + + // TODO generate the store for the initializer + //var llvm_expr = try self.emitExpr(vardecl.value); + }, else => { std.debug.warn("Got unexpected stmt {}\n", stmt.*); @@ -350,6 +369,12 @@ pub const Codegen = struct { } } + fn getFnSymbol(self: *@This(), name: []const u8) comp.FunctionSymbol { + var fn_sym_search = self.ctx.symbol_table.get(name).?.value; + std.debug.assert(comp.SymbolType(fn_sym_search) == .Function); + return fn_sym_search.Function; + } + /// Emit LLVM ir for the given node. fn genNode( self: *Codegen, @@ -361,10 +386,9 @@ pub const Codegen = struct { .FnDecl => |decl| { const name = decl.func_name.lexeme; self.current_function_name = name; + std.debug.warn("cgen: genning function '{}'\n", name); - var fn_sym_search = self.ctx.symbol_table.get(name).?.value; - std.debug.assert(comp.SymbolType(fn_sym_search) == .Function); - var fn_sym = fn_sym_search.Function; + var fn_sym = self.getFnSymbol(name); const name_cstr = try std.cstr.addNullByte(self.allocator, name); errdefer self.allocator.free(name_cstr); @@ -396,6 +420,9 @@ pub const Codegen = struct { var builder = llvm.LLVMCreateBuilder(); llvm.LLVMPositionBuilderAtEnd(builder, entry); + self.ctx.setScope(fn_sym.scope); + defer self.ctx.dumpScope(); + for (decl.body.toSlice()) |stmt| { try self.emitStmt(builder, &stmt); } diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index c6d7a37..b22768c 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -39,8 +39,9 @@ pub const Scope = struct { parent: ?*Scope, env: UnderlyingTypeMap, - /// Used for debug information. + /// List of children in the scope. children: ScopeList, + cur_child_idx: usize = 0, allocator: *std.mem.Allocator, id: ?[]const u8 = null, @@ -64,6 +65,12 @@ pub const Scope = struct { return child; } + pub fn nextChild(self: *@This()) *Scope { + var child = self.children.at(self.cur_child_idx); + self.cur_child_idx += 1; + return child; + } + pub fn deinit(self: *const @This()) void { self.env.deinit(); } @@ -184,6 +191,7 @@ pub const CompilationContext = struct { /// Set a given scope as the current scope. pub fn setScope(self: *@This(), scope: *Scope) void { + std.debug.warn("==set== set scope to {}\n", scope.id); self.current_scope = scope; }