Compare commits

...

6 Commits

Author SHA1 Message Date
Luna 518d2daeb4 Merge branch 'master' of https://gitdab.com/luna/rayoko 2019-09-28 13:18:28 -03:00
Luna a136a377ce change symbol table to use pointers to heap allocated symbols 2019-09-28 13:17:11 -03:00
Luna 93811c986d codegen: use Parameter.llvm_alloca 2019-09-28 12:46:23 -03:00
Luna 61c8493484 add basics of stack-stored arguments
this requires some changes regarding the const-ability of the passed
nodes into codegen.
2019-09-28 11:40:56 -03:00
Luna 58713b20e3 add llvmvalueref to Parameter 2019-09-28 11:32:36 -03:00
Luna 178acc656f codegen: allow for mutable statements
- ast: add llvm_alloca llvmvalueref pointer in VarDeclStmt
2019-09-28 11:30:21 -03:00
6 changed files with 89 additions and 46 deletions

View File

@ -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;
} }

View File

@ -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;
}, },

View File

@ -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) {

View File

@ -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",

View File

@ -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;

View File

@ -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(