Compare commits
6 commits
81fd718403
...
518d2daeb4
Author | SHA1 | Date | |
---|---|---|---|
518d2daeb4 | |||
a136a377ce | |||
93811c986d | |||
61c8493484 | |||
58713b20e3 | |||
178acc656f |
6 changed files with 89 additions and 46 deletions
|
@ -31,6 +31,10 @@ fn test_function() B {
|
||||||
return B.b;
|
return B.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn func_refer_param(b: i32) i32 {
|
||||||
|
return b * 231 + b;
|
||||||
|
}
|
||||||
|
|
||||||
fn multwo(num: i32, double_flag: bool) i32 {
|
fn multwo(num: i32, double_flag: bool) i32 {
|
||||||
if (double_flag) {
|
if (double_flag) {
|
||||||
var truthy = true;
|
var truthy = true;
|
||||||
|
@ -41,10 +45,6 @@ fn multwo(num: i32, double_flag: bool) i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn func_refer_param(b: i32) i32 {
|
|
||||||
return b * 231 + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add(a: i32, b: i32) i32 {
|
fn add(a: i32, b: i32) i32 {
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub const TypeSolver = struct {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return switch (sym.?.value) {
|
return switch (sym.?.value.*) {
|
||||||
.Struct => SymbolUnderlyingType{ .Struct = val },
|
.Struct => SymbolUnderlyingType{ .Struct = val },
|
||||||
.Enum => SymbolUnderlyingType{ .Enum = val },
|
.Enum => SymbolUnderlyingType{ .Enum = val },
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ pub const TypeSolver = struct {
|
||||||
self.doError(
|
self.doError(
|
||||||
"expected struct or enum for '{}', got {}",
|
"expected struct or enum for '{}', got {}",
|
||||||
val,
|
val,
|
||||||
@tagName(comp.SymbolType(sym.?.value)),
|
@tagName(comp.SymbolType(sym.?.value.*)),
|
||||||
);
|
);
|
||||||
break :blk null;
|
break :blk null;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const tokens = @import("tokens.zig");
|
const tokens = @import("tokens.zig");
|
||||||
|
const llvm = @import("llvm.zig");
|
||||||
const Token = tokens.Token;
|
const Token = tokens.Token;
|
||||||
|
|
||||||
pub const NodeList = std.ArrayList(Node);
|
pub const NodeList = std.ArrayList(Node);
|
||||||
|
@ -184,6 +185,7 @@ pub const ForStmt = struct {
|
||||||
pub const VarDeclStmt = struct {
|
pub const VarDeclStmt = struct {
|
||||||
name: Token,
|
name: Token,
|
||||||
value: *Expr,
|
value: *Expr,
|
||||||
|
llvm_alloca: ?llvm.LLVMValueRef = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Stmt = union(enum) {
|
pub const Stmt = union(enum) {
|
||||||
|
|
|
@ -388,7 +388,7 @@ pub fn printContext(ctx: CompilationContext) void {
|
||||||
var it = ctx.symbol_table.iterator();
|
var it = ctx.symbol_table.iterator();
|
||||||
|
|
||||||
while (it.next()) |kv| {
|
while (it.next()) |kv| {
|
||||||
switch (kv.value) {
|
switch (kv.value.*) {
|
||||||
.Function => |fn_sym| {
|
.Function => |fn_sym| {
|
||||||
std.debug.warn(
|
std.debug.warn(
|
||||||
"function {} returns {}\n",
|
"function {} returns {}\n",
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub const Codegen = struct {
|
||||||
|
|
||||||
.Struct, .Enum => |lex| blk: {
|
.Struct, .Enum => |lex| blk: {
|
||||||
var sym_data = self.ctx.symbol_table.get(lex).?.value;
|
var sym_data = self.ctx.symbol_table.get(lex).?.value;
|
||||||
break :blk switch (sym_data) {
|
break :blk switch (sym_data.*) {
|
||||||
.Struct => unreachable,
|
.Struct => unreachable,
|
||||||
.Enum => llvm.LLVMInt32Type(),
|
.Enum => llvm.LLVMInt32Type(),
|
||||||
else => {
|
else => {
|
||||||
|
@ -74,7 +74,7 @@ pub const Codegen = struct {
|
||||||
fn emitForVariableType(self: *@This(), vari: var, get: var, kv: var) !llvm.LLVMValueRef {
|
fn emitForVariableType(self: *@This(), vari: var, get: var, kv: var) !llvm.LLVMValueRef {
|
||||||
var sym = kv.value;
|
var sym = kv.value;
|
||||||
|
|
||||||
switch (sym) {
|
switch (sym.*) {
|
||||||
.Enum => |map| {
|
.Enum => |map| {
|
||||||
var val = map.get(get.name.lexeme);
|
var val = map.get(get.name.lexeme);
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
|
@ -89,7 +89,7 @@ pub const Codegen = struct {
|
||||||
|
|
||||||
.Struct => @panic("TODO handle struct"),
|
.Struct => @panic("TODO handle struct"),
|
||||||
else => {
|
else => {
|
||||||
std.debug.warn("Invalid get target: {}\n", comp.SymbolType(sym));
|
std.debug.warn("Invalid get target: {}\n", comp.SymbolType(sym.*));
|
||||||
return CompileError.EmitError;
|
return CompileError.EmitError;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -236,11 +236,11 @@ pub const Codegen = struct {
|
||||||
return switch (metadata.using) {
|
return switch (metadata.using) {
|
||||||
.Function => blk: {
|
.Function => blk: {
|
||||||
var param = metadata.from_function.?.parameters.get(vari.lexeme).?.value;
|
var param = metadata.from_function.?.parameters.get(vari.lexeme).?.value;
|
||||||
var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value;
|
// var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value;
|
||||||
|
// break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx));
|
||||||
|
|
||||||
// may i thank all the demons in hell for giving me
|
std.debug.warn("fn param alloca {} {}\n", param.name, param.llvm_alloca);
|
||||||
// good energies to make this work
|
break :blk param.llvm_alloca.?;
|
||||||
break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.Scope => @panic("TODO local variables"),
|
.Scope => @panic("TODO local variables"),
|
||||||
|
@ -254,7 +254,7 @@ pub const Codegen = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emitStmt(self: *Codegen, builder: var, stmt: *const ast.Stmt) anyerror!void {
|
fn emitStmt(self: *Codegen, builder: var, stmt: *ast.Stmt) anyerror!void {
|
||||||
switch (stmt.*) {
|
switch (stmt.*) {
|
||||||
.Expr => |expr| _ = try self.emitExpr(builder, expr),
|
.Expr => |expr| _ = try self.emitExpr(builder, expr),
|
||||||
|
|
||||||
|
@ -286,13 +286,16 @@ pub const Codegen = struct {
|
||||||
|
|
||||||
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
|
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
|
||||||
|
|
||||||
for (ifstmt.then_branch.toSlice()) |then_stmt| {
|
var then_branch = ifstmt.then_branch.toSlice();
|
||||||
|
for (then_branch) |_, idx| {
|
||||||
// keep emitting until branch has ret
|
// keep emitting until branch has ret
|
||||||
if (!then_rets)
|
var then_stmt = &then_branch[idx];
|
||||||
try self.emitStmt(builder, &then_stmt);
|
|
||||||
|
|
||||||
switch (then_stmt) {
|
if (!then_rets)
|
||||||
|
try self.emitStmt(builder, then_stmt);
|
||||||
|
|
||||||
|
// TODO break? lol
|
||||||
|
switch (then_stmt.*) {
|
||||||
.Return => then_rets = true,
|
.Return => then_rets = true,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
@ -314,12 +317,16 @@ pub const Codegen = struct {
|
||||||
// 'Else *ElseV = Else->codegen();'
|
// 'Else *ElseV = Else->codegen();'
|
||||||
if (ifstmt.else_branch) |else_block| {
|
if (ifstmt.else_branch) |else_block| {
|
||||||
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
|
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
|
||||||
for (else_block.toSlice()) |else_stmt| {
|
|
||||||
// keep emitting until branch has ret
|
|
||||||
if (!else_rets)
|
|
||||||
try self.emitStmt(builder, &else_stmt);
|
|
||||||
|
|
||||||
switch (else_stmt) {
|
var else_slice = else_block.toSlice();
|
||||||
|
for (else_slice) |_, idx| {
|
||||||
|
// keep emitting until branch has ret
|
||||||
|
var else_stmt = &else_slice[idx];
|
||||||
|
|
||||||
|
if (!else_rets)
|
||||||
|
try self.emitStmt(builder, else_stmt);
|
||||||
|
|
||||||
|
switch (else_stmt.*) {
|
||||||
.Return => else_rets = true,
|
.Return => else_rets = true,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
@ -335,6 +342,8 @@ pub const Codegen = struct {
|
||||||
|
|
||||||
llvm.LLVMPositionBuilderAtEnd(builder, merge_bb);
|
llvm.LLVMPositionBuilderAtEnd(builder, merge_bb);
|
||||||
|
|
||||||
|
// if both of the branches return, we should put
|
||||||
|
// the merge branch as unreachable.
|
||||||
if (then_rets and else_rets)
|
if (then_rets and else_rets)
|
||||||
_ = llvm.LLVMBuildUnreachable(builder);
|
_ = llvm.LLVMBuildUnreachable(builder);
|
||||||
},
|
},
|
||||||
|
@ -351,13 +360,14 @@ pub const Codegen = struct {
|
||||||
|
|
||||||
var fn_symbol = self.getFnSymbol(self.current_function_name.?);
|
var fn_symbol = self.getFnSymbol(self.current_function_name.?);
|
||||||
|
|
||||||
// TODO add llvm value ref to var metadata as well
|
|
||||||
var variable = llvm.LLVMBuildAlloca(
|
var variable = llvm.LLVMBuildAlloca(
|
||||||
builder,
|
builder,
|
||||||
try self.typeToLLVM(var_metadata.typ),
|
try self.typeToLLVM(var_metadata.typ),
|
||||||
name_cstr.ptr,
|
name_cstr.ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
stmt.*.VarDecl.llvm_alloca = variable;
|
||||||
|
|
||||||
var llvm_expr = try self.emitExpr(builder, vardecl.value);
|
var llvm_expr = try self.emitExpr(builder, vardecl.value);
|
||||||
_ = llvm.LLVMBuildStore(builder, llvm_expr, variable);
|
_ = llvm.LLVMBuildStore(builder, llvm_expr, variable);
|
||||||
},
|
},
|
||||||
|
@ -369,17 +379,17 @@ pub const Codegen = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getFnSymbol(self: *@This(), name: []const u8) comp.FunctionSymbol {
|
fn getFnSymbol(self: *@This(), name: []const u8) *comp.FunctionSymbol {
|
||||||
var fn_sym_search = self.ctx.symbol_table.get(name).?.value;
|
var fn_sym_search = self.ctx.symbol_table.get(name).?.value;
|
||||||
std.debug.assert(comp.SymbolType(fn_sym_search) == .Function);
|
std.debug.assert(comp.SymbolType(fn_sym_search.*) == .Function);
|
||||||
return fn_sym_search.Function;
|
return &fn_sym_search.Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit LLVM ir for the given node.
|
/// Emit LLVM ir for the given node.
|
||||||
fn genNode(
|
fn genNode(
|
||||||
self: *Codegen,
|
self: *Codegen,
|
||||||
mod: llvm.LLVMModuleRef,
|
mod: llvm.LLVMModuleRef,
|
||||||
node: *const ast.Node,
|
node: *ast.Node,
|
||||||
) !void {
|
) !void {
|
||||||
switch (node.*) {
|
switch (node.*) {
|
||||||
.Root => @panic("Should not have gotten Root"),
|
.Root => @panic("Should not have gotten Root"),
|
||||||
|
@ -420,11 +430,30 @@ pub const Codegen = struct {
|
||||||
var builder = llvm.LLVMCreateBuilder();
|
var builder = llvm.LLVMCreateBuilder();
|
||||||
llvm.LLVMPositionBuilderAtEnd(builder, entry);
|
llvm.LLVMPositionBuilderAtEnd(builder, entry);
|
||||||
|
|
||||||
|
// to have the ability to mutate parameters, we must allocate them on
|
||||||
|
// the stack
|
||||||
|
var params_slice = decl.params.toSlice();
|
||||||
|
for (params_slice) |param_node, idx| {
|
||||||
|
var param = fn_sym.parameters.get(param_node.name.lexeme).?.value;
|
||||||
|
|
||||||
|
const param_name_cstr = try std.cstr.addNullByte(self.allocator, param_node.name.lexeme);
|
||||||
|
errdefer self.allocator.free(param_name_cstr);
|
||||||
|
|
||||||
|
var alloca = llvm.LLVMBuildAlloca(builder, try self.typeToLLVM(param.typ), param_name_cstr.ptr);
|
||||||
|
|
||||||
|
std.debug.warn("SET PARAM LLVM ALLOCA {} to {}\n", param_node.name.lexeme, alloca);
|
||||||
|
param.llvm_alloca = alloca;
|
||||||
|
|
||||||
|
// TODO store register into stack param
|
||||||
|
// llvm.LLVMBuildStore(builder, null, assign_expr);
|
||||||
|
}
|
||||||
|
|
||||||
self.ctx.setScope(fn_sym.scope);
|
self.ctx.setScope(fn_sym.scope);
|
||||||
defer self.ctx.dumpScope();
|
defer self.ctx.dumpScope();
|
||||||
|
|
||||||
for (decl.body.toSlice()) |stmt| {
|
var body_slice = decl.body.toSlice();
|
||||||
try self.emitStmt(builder, &stmt);
|
for (body_slice) |_, idx| {
|
||||||
|
try self.emitStmt(builder, &body_slice[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std.debug.warn("cgen: generated function '{}'\n", name);
|
std.debug.warn("cgen: generated function '{}'\n", name);
|
||||||
|
@ -469,9 +498,9 @@ pub const Codegen = struct {
|
||||||
var mod = llvm.LLVMModuleCreateWithName(c"awoo").?;
|
var mod = llvm.LLVMModuleCreateWithName(c"awoo").?;
|
||||||
defer llvm.LLVMDisposeModule(mod);
|
defer llvm.LLVMDisposeModule(mod);
|
||||||
|
|
||||||
for (root.Root.toSlice()) |child| {
|
var root_slice = root.Root.toSlice();
|
||||||
std.debug.warn("cgen: gen {}\n", @tagName(child));
|
for (root_slice) |_, idx| {
|
||||||
try self.genNode(mod, &child);
|
try self.genNode(mod, &root_slice[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var err: ?[*]u8 = null;
|
var err: ?[*]u8 = null;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ast = @import("ast.zig");
|
const ast = @import("ast.zig");
|
||||||
|
const llvm = @import("llvm.zig");
|
||||||
|
|
||||||
pub const CompilationError = error{
|
pub const CompilationError = error{
|
||||||
TypeError,
|
TypeError,
|
||||||
UnknownName,
|
UnknownName,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const SymbolTable = std.hash_map.StringHashMap(SymbolData);
|
pub const SymbolTable = std.hash_map.StringHashMap(*SymbolData);
|
||||||
pub const TypeList = std.ArrayList(SymbolUnderlyingType);
|
pub const TypeList = std.ArrayList(SymbolUnderlyingType);
|
||||||
|
|
||||||
pub const SymbolUnderlyingTypeEnum = enum {
|
pub const SymbolUnderlyingTypeEnum = enum {
|
||||||
|
@ -78,7 +79,10 @@ pub const Scope = struct {
|
||||||
|
|
||||||
pub const Parameter = struct {
|
pub const Parameter = struct {
|
||||||
idx: usize,
|
idx: usize,
|
||||||
|
name: []const u8,
|
||||||
typ: SymbolUnderlyingType,
|
typ: SymbolUnderlyingType,
|
||||||
|
|
||||||
|
llvm_alloca: llvm.LLVMValueRef = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ParameterMap = std.StringHashMap(Parameter);
|
pub const ParameterMap = std.StringHashMap(Parameter);
|
||||||
|
@ -255,7 +259,9 @@ pub const CompilationContext = struct {
|
||||||
_ = try type_map.put(field.name.lexeme, field_types.at(idx));
|
_ = try type_map.put(field.name.lexeme, field_types.at(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = try self.symbol_table.put(struc.name.lexeme, SymbolData{ .Struct = type_map });
|
var symbol = try self.allocator.create(SymbolData);
|
||||||
|
symbol.* = SymbolData{ .Struct = type_map };
|
||||||
|
_ = try self.symbol_table.put(struc.name.lexeme, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insertFn(
|
pub fn insertFn(
|
||||||
|
@ -269,6 +275,7 @@ pub const CompilationContext = struct {
|
||||||
|
|
||||||
for (decl.params.toSlice()) |param, idx| {
|
for (decl.params.toSlice()) |param, idx| {
|
||||||
_ = try param_map.put(param.name.lexeme, Parameter{
|
_ = try param_map.put(param.name.lexeme, Parameter{
|
||||||
|
.name = param.name.lexeme,
|
||||||
.idx = idx,
|
.idx = idx,
|
||||||
.typ = param_types.at(idx),
|
.typ = param_types.at(idx),
|
||||||
});
|
});
|
||||||
|
@ -276,7 +283,8 @@ pub const CompilationContext = struct {
|
||||||
|
|
||||||
const lex = decl.func_name.lexeme;
|
const lex = decl.func_name.lexeme;
|
||||||
|
|
||||||
_ = try self.symbol_table.put(lex, SymbolData{
|
var symbol = try self.allocator.create(SymbolData);
|
||||||
|
symbol.* = SymbolData{
|
||||||
.Function = FunctionSymbol{
|
.Function = FunctionSymbol{
|
||||||
.decl = decl,
|
.decl = decl,
|
||||||
.return_type = ret_type,
|
.return_type = ret_type,
|
||||||
|
@ -284,7 +292,9 @@ pub const CompilationContext = struct {
|
||||||
.parameter_list = param_types,
|
.parameter_list = param_types,
|
||||||
.scope = scope,
|
.scope = scope,
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
|
_ = try self.symbol_table.put(lex, symbol);
|
||||||
|
|
||||||
var kv = self.symbol_table.get(lex);
|
var kv = self.symbol_table.get(lex);
|
||||||
self.cur_function = &kv.?.value.Function;
|
self.cur_function = &kv.?.value.Function;
|
||||||
|
@ -299,20 +309,22 @@ pub const CompilationContext = struct {
|
||||||
_ = try ident_map.put(token.lexeme, @intCast(u32, idx));
|
_ = try ident_map.put(token.lexeme, @intCast(u32, idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = try self.symbol_table.put(enu.name.lexeme, SymbolData{
|
var symbol = try self.allocator.create(SymbolData);
|
||||||
.Enum = ident_map,
|
symbol.* = SymbolData{ .Enum = ident_map };
|
||||||
});
|
_ = try self.symbol_table.put(enu.name.lexeme, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insertConst(self: *@This(), constdecl: ast.SingleConst, typ: SymbolUnderlyingType) !void {
|
pub fn insertConst(self: *@This(), constdecl: ast.SingleConst, typ: SymbolUnderlyingType) !void {
|
||||||
_ = try self.symbol_table.put(constdecl.name.lexeme, SymbolData{ .Const = typ });
|
var symbol = try self.allocator.create(SymbolData);
|
||||||
|
symbol.* = SymbolData{ .Const = typ };
|
||||||
|
_ = try self.symbol_table.put(constdecl.name.lexeme, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetchGlobalSymbol(
|
pub fn fetchGlobalSymbol(
|
||||||
self: *@This(),
|
self: *@This(),
|
||||||
identifier: []const u8,
|
identifier: []const u8,
|
||||||
typ: SymbolType,
|
typ: SymbolType,
|
||||||
) !SymbolData {
|
) !*SymbolData {
|
||||||
var sym_kv = self.symbol_table.get(identifier);
|
var sym_kv = self.symbol_table.get(identifier);
|
||||||
if (sym_kv == null) {
|
if (sym_kv == null) {
|
||||||
std.debug.warn("Unknown {} '{}'\n", typ, identifier);
|
std.debug.warn("Unknown {} '{}'\n", typ, identifier);
|
||||||
|
@ -320,14 +332,14 @@ pub const CompilationContext = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = sym_kv.?.value;
|
var value = sym_kv.?.value;
|
||||||
var sym_typ = SymbolType(value);
|
|
||||||
|
|
||||||
|
var sym_typ = SymbolType(value.*);
|
||||||
if (sym_typ != typ) {
|
if (sym_typ != typ) {
|
||||||
std.debug.warn("Expected {}, got {}\n", sym_typ, typ);
|
std.debug.warn("Expected {}, got {}\n", sym_typ, typ);
|
||||||
return CompilationError.TypeError;
|
return CompilationError.TypeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sym_kv.?.value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveVarTypeInScope(
|
fn resolveVarTypeInScope(
|
||||||
|
|
Loading…
Reference in a new issue