add the rest of (currently nonfunctional) emitting of if stmts
- add compilation context and basics of type solver
This commit is contained in:
parent
1bb1fb813d
commit
c1d6939c43
4 changed files with 202 additions and 8 deletions
|
@ -98,7 +98,7 @@ pub const Codegen = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emitStmt(self: *Codegen, builder: var, stmt: *const ast.Stmt) !void {
|
fn emitStmt(self: *Codegen, builder: var, stmt: *const ast.Stmt) anyerror!void {
|
||||||
switch (stmt.*) {
|
switch (stmt.*) {
|
||||||
.Expr => |expr| _ = try self.emitExpr(builder, expr),
|
.Expr => |expr| _ = try self.emitExpr(builder, expr),
|
||||||
|
|
||||||
|
@ -111,6 +111,50 @@ pub const Codegen = struct {
|
||||||
var cond = try self.emitExpr(builder, ifstmt.condition);
|
var cond = try self.emitExpr(builder, ifstmt.condition);
|
||||||
var zero = mkLLVMBool(false);
|
var zero = mkLLVMBool(false);
|
||||||
var icmp = llvm.LLVMBuildICmp(builder, llvm.LLVMIntPredicate.LLVMIntNE, cond, zero, c"ifcond");
|
var icmp = llvm.LLVMBuildICmp(builder, llvm.LLVMIntPredicate.LLVMIntNE, cond, zero, c"ifcond");
|
||||||
|
|
||||||
|
var insert = llvm.LLVMGetInsertBlock(builder);
|
||||||
|
var function = llvm.LLVMGetBasicBlockParent(insert);
|
||||||
|
var global_ctx = llvm.LLVMGetGlobalContext();
|
||||||
|
|
||||||
|
var then_bb = llvm.LLVMAppendBasicBlock(function, c"then");
|
||||||
|
var else_bb = llvm.LLVMCreateBasicBlockInContext(global_ctx, c"else");
|
||||||
|
var merge_bb = llvm.LLVMCreateBasicBlockInContext(global_ctx, c"ifcont");
|
||||||
|
|
||||||
|
var condbr = llvm.LLVMBuildCondBr(builder, icmp, then_bb, else_bb);
|
||||||
|
|
||||||
|
llvm.LLVMPositionBuilderAtEnd(builder, then_bb);
|
||||||
|
|
||||||
|
// roughly translating to kaleidoscope's
|
||||||
|
// 'Value *ThenV = Then->codegen();'
|
||||||
|
for (ifstmt.then_branch.toSlice()) |then_stmt| {
|
||||||
|
try self.emitStmt(builder, &then_stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = llvm.LLVMBuildBr(builder, merge_bb);
|
||||||
|
then_bb = llvm.LLVMGetInsertBlock(builder);
|
||||||
|
|
||||||
|
llvm.LLVMPositionBuilderAtEnd(builder, else_bb);
|
||||||
|
|
||||||
|
// roughly translating to kaleidoscope's
|
||||||
|
// 'Else *ElseV = Else->codegen();'
|
||||||
|
if (ifstmt.else_branch) |else_block| {
|
||||||
|
for (else_block.toSlice()) |else_stmt| {
|
||||||
|
try self.emitStmt(builder, &else_stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = llvm.LLVMBuildBr(builder, merge_bb);
|
||||||
|
else_bb = llvm.LLVMGetInsertBlock(builder);
|
||||||
|
|
||||||
|
llvm.LLVMPositionBuilderAtEnd(builder, merge_bb);
|
||||||
|
|
||||||
|
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);
|
||||||
},
|
},
|
||||||
|
|
||||||
else => {
|
else => {
|
||||||
|
@ -120,6 +164,16 @@ pub const Codegen = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emitBlock(self: *Codegen, builder: var, block: ast.Block) !llvm.LLVMValueRef {
|
||||||
|
var entry = llvm.LLVMAppendBasicBlock(func, entry_lbl_cstr.ptr);
|
||||||
|
|
||||||
|
var builder = llvm.LLVMCreateBuilder();
|
||||||
|
llvm.LLVMPositionBuilderAtEnd(builder, entry);
|
||||||
|
for (block.toSlice()) |stmt| {
|
||||||
|
try self.emitStmt(builder, &stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn genNode(
|
fn genNode(
|
||||||
self: *Codegen,
|
self: *Codegen,
|
||||||
mod: llvm.LLVMModuleRef,
|
mod: llvm.LLVMModuleRef,
|
||||||
|
@ -173,6 +227,7 @@ pub const Codegen = struct {
|
||||||
|
|
||||||
std.debug.warn("cgen: generated function '{}'\n", name);
|
std.debug.warn("cgen: generated function '{}'\n", name);
|
||||||
},
|
},
|
||||||
|
|
||||||
else => {
|
else => {
|
||||||
std.debug.warn("got unhandled Node {}\n", node.*);
|
std.debug.warn("got unhandled Node {}\n", node.*);
|
||||||
unreachable;
|
unreachable;
|
||||||
|
|
87
src/comp_ctx.zig
Normal file
87
src/comp_ctx.zig
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const CompilationError = error{TypeError};
|
||||||
|
|
||||||
|
pub const SymbolTable = std.hash_map.StringHashMap(SymbolData);
|
||||||
|
|
||||||
|
pub const SymbolUnderlyingTypeEnum = enum {
|
||||||
|
Integer32,
|
||||||
|
Integer64,
|
||||||
|
Bool,
|
||||||
|
CustomType,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SymbolUnderlyingType = union(SymbolUnderlyingTypeEnum) {
|
||||||
|
Integer32: void,
|
||||||
|
Integer64: void,
|
||||||
|
Bool: void,
|
||||||
|
CustomType: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
// functions, for our purposes, other than symbols, have:
|
||||||
|
// - a return type
|
||||||
|
// - TODO parameters
|
||||||
|
pub const FunctionSymbol = struct {
|
||||||
|
return_type: SymbolUnderlyingType,
|
||||||
|
symbols: SymbolTable,
|
||||||
|
};
|
||||||
|
|
||||||
|
// structs are hashmaps pointing to SymbolUnderlyingType
|
||||||
|
pub const UnderlyingTypeMap = std.hash_map.StringHashMap(SymbolUnderlyingType);
|
||||||
|
|
||||||
|
// enums have lists of identifiers
|
||||||
|
pub const IdentifierList = std.ArrayList([]const u8);
|
||||||
|
|
||||||
|
// TODO const
|
||||||
|
pub const SymbolType = enum {
|
||||||
|
Function,
|
||||||
|
Struct,
|
||||||
|
Enum,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SymbolData = union(SymbolType) {
|
||||||
|
Function: FunctionSymbol,
|
||||||
|
Struct: UnderlyingTypeMap,
|
||||||
|
Enum: IdentifierList,
|
||||||
|
};
|
||||||
|
|
||||||
|
const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" };
|
||||||
|
|
||||||
|
const builtin_types = [_]SymbolUnderlyingTypeEnum{ .Integer32, .Integer64, .Bool };
|
||||||
|
|
||||||
|
pub const CompilationContext = struct {
|
||||||
|
allocator: *std.mem.Allocator,
|
||||||
|
symbol_table: SymbolTable,
|
||||||
|
|
||||||
|
pub fn init(allocator: *std.mem.Allocator) CompilationContext {
|
||||||
|
return CompilationContext{
|
||||||
|
.allocator = allocator,
|
||||||
|
.symbol_table = SymbolTable.init(allocator),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn solveTypeEnum(
|
||||||
|
self: *@This(),
|
||||||
|
typ_ident: []const u8,
|
||||||
|
) SymbolUnderlyingTypeEnum {
|
||||||
|
inline for (builtin_type_identifiers) |typ, idx| {
|
||||||
|
if (std.mem.eql(u8, typ, typ_ident)) return builtin_types[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return .CustomType;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn solveType(
|
||||||
|
self: *@This(),
|
||||||
|
typ_ident: []const u8,
|
||||||
|
) SymbolUnderlyingType {
|
||||||
|
const typ_enum_val = self.solveTypeEnum(typ_ident);
|
||||||
|
|
||||||
|
return switch (typ_enum_val) {
|
||||||
|
.Integer32 => SymbolUnderlyingType{ .Integer32 = {} },
|
||||||
|
.Integer64 => SymbolUnderlyingType{ .Integer64 = {} },
|
||||||
|
.Bool => SymbolUnderlyingType{ .Bool = {} },
|
||||||
|
.CustomType => SymbolUnderlyingType{ .CustomType = typ_ident },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
18
src/main.zig
18
src/main.zig
|
@ -4,6 +4,7 @@ const scanners = @import("scanners.zig");
|
||||||
const parsers = @import("parsers.zig");
|
const parsers = @import("parsers.zig");
|
||||||
const printer = @import("ast_printer.zig");
|
const printer = @import("ast_printer.zig");
|
||||||
const codegen = @import("codegen.zig");
|
const codegen = @import("codegen.zig");
|
||||||
|
const types = @import("types.zig");
|
||||||
|
|
||||||
pub const Result = enum {
|
pub const Result = enum {
|
||||||
Ok,
|
Ok,
|
||||||
|
@ -38,19 +39,22 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
|
||||||
scan.reset();
|
scan.reset();
|
||||||
|
|
||||||
var parser = parsers.Parser.init(allocator, &scan);
|
var parser = parsers.Parser.init(allocator, &scan);
|
||||||
var root = try parser.parse();
|
var root_opt = try parser.parse();
|
||||||
if (root == null) {
|
|
||||||
|
if (root_opt == null) {
|
||||||
return Result.ParseError;
|
return Result.ParseError;
|
||||||
}
|
}
|
||||||
|
|
||||||
std.debug.warn("parse tree\n");
|
var root = root_opt.?;
|
||||||
printer.printNode(root.?, 0);
|
|
||||||
|
|
||||||
// TODO type pass
|
std.debug.warn("parse tree\n");
|
||||||
// TODO variable pass
|
printer.printNode(root, 0);
|
||||||
|
|
||||||
|
var solver = types.TypeSolver.init(allocator);
|
||||||
|
var ctx = solver.pass(root);
|
||||||
|
|
||||||
var cgen = codegen.Codegen.init(allocator);
|
var cgen = codegen.Codegen.init(allocator);
|
||||||
try cgen.gen(root.?);
|
try cgen.gen(root);
|
||||||
|
|
||||||
return Result.Ok;
|
return Result.Ok;
|
||||||
}
|
}
|
||||||
|
|
48
src/types.zig
Normal file
48
src/types.zig
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const ast = @import("ast.zig");
|
||||||
|
|
||||||
|
const comp = @import("comp_ctx.zig");
|
||||||
|
|
||||||
|
pub const TypeSolver = struct {
|
||||||
|
allocator: *std.mem.Allocator,
|
||||||
|
|
||||||
|
pub fn init(allocator: *std.mem.Allocator) TypeSolver {
|
||||||
|
return TypeSolver{ .allocator = allocator };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nodePass(
|
||||||
|
self: *@This(),
|
||||||
|
ctx: *comp.CompilationContext,
|
||||||
|
node: *ast.Node,
|
||||||
|
) void {
|
||||||
|
switch (node.*) {
|
||||||
|
.Root => unreachable,
|
||||||
|
.FnDecl => |decl| {
|
||||||
|
var ret_type = ctx.solveType(decl.return_type.lexeme);
|
||||||
|
|
||||||
|
// TODO maybe solve when custom?
|
||||||
|
|
||||||
|
std.debug.warn("fn {} type: {}\n", decl.func_name.lexeme, ret_type);
|
||||||
|
|
||||||
|
// ctx.insertFn(decl.name.lexeme, ret_type);
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO infer type of expr in const
|
||||||
|
//.ConstDecl => {},
|
||||||
|
//.Struct => {},
|
||||||
|
//.Enum => {},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pass(self: *@This(), root: *ast.Node) comp.CompilationContext {
|
||||||
|
var ctx = comp.CompilationContext.init(self.allocator);
|
||||||
|
|
||||||
|
var slice = root.Root.toSlice();
|
||||||
|
for (slice) |_, idx| {
|
||||||
|
self.nodePass(&ctx, &slice[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue