Compare commits

..

2 commits

Author SHA1 Message Date
5188dac3c0 add type analysis of enums 2019-09-25 11:59:36 -03:00
0b0a8896bb add basic resolution of enums to llvm types
- pass ctx to codegen
 - add better type solver error for unhandled nodes
2019-09-25 11:29:47 -03:00
7 changed files with 100 additions and 50 deletions

View file

@ -1,16 +1,13 @@
// import std; // import std;
struct B { enum B {
field i32 a
b
c
} }
struct Awoo { fn test_function() B {
b B return B.a;
other_field i32
}
fn test_function() Awoo {
return 1;
} }
fn multwo(num: i32, double_flag: bool) i32 { fn multwo(num: i32, double_flag: bool) i32 {

View file

@ -280,6 +280,9 @@ pub const Struct = struct {
pub const Enum = struct { pub const Enum = struct {
name: Token, name: Token,
// TODO allow custom values for the enum fields
// just like c enums can skip values
fields: TokenList, fields: TokenList,
}; };

View file

@ -351,8 +351,7 @@ fn prettyType(typ: SymbolUnderlyingType) []const u8 {
.OpaqueType => |ident| retWithName("opaque", ident), .OpaqueType => |ident| retWithName("opaque", ident),
.Struct => |ident| retWithName("struct", ident), .Struct => |ident| retWithName("struct", ident),
.Enum => |ident| retWithName("enum", ident),
else => unreachable,
}; };
} }
@ -395,7 +394,21 @@ pub fn printContext(ctx: CompilationContext) void {
kv.key, kv.key,
kv.value, kv.value,
), ),
else => unreachable,
.Enum => |identmap| {
std.debug.warn("enum {}:", kv.key);
var mapit = identmap.iterator();
while (mapit.next()) |field_kv| {
std.debug.warn("\t{} => {}\n", field_kv.key, field_kv.value);
}
},
else => {
std.debug.warn("TODO handle print of {}\n", kv.value);
unreachable;
},
} }
} }
} }

View file

@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const ast = @import("ast.zig"); const ast = @import("ast.zig");
const llvm = @import("llvm.zig"); const llvm = @import("llvm.zig");
const comp = @import("comp_ctx.zig");
const types = @import("types.zig");
fn sliceify(non_slice: ?[*]const u8) []const u8 { fn sliceify(non_slice: ?[*]const u8) []const u8 {
if (non_slice == null) return ""; if (non_slice == null) return "";
@ -13,19 +15,6 @@ pub const CompileError = error{
TypeError, TypeError,
}; };
/// Does not account for custom types e.g structs, better type resolution
/// should be found
fn basicTypeToLLVM(ret_type: []const u8) !llvm.LLVMTypeRef {
if (std.mem.eql(u8, ret_type, "i32")) {
return llvm.LLVMInt32Type();
} else if (std.mem.eql(u8, ret_type, "bool")) {
return llvm.LLVMInt1Type();
} else {
std.debug.warn("Invalid return type: {}\n", ret_type);
return CompileError.TypeError;
}
}
fn mkLLVMBool(val: bool) llvm.LLVMValueRef { fn mkLLVMBool(val: bool) llvm.LLVMValueRef {
if (val) { if (val) {
return llvm.LLVMConstInt(llvm.LLVMInt1Type(), 1, 1); return llvm.LLVMConstInt(llvm.LLVMInt1Type(), 1, 1);
@ -36,9 +25,40 @@ fn mkLLVMBool(val: bool) llvm.LLVMValueRef {
pub const Codegen = struct { pub const Codegen = struct {
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
ctx: *comp.CompilationContext,
pub fn init(allocator: *std.mem.Allocator) Codegen { pub fn init(allocator: *std.mem.Allocator, ctx: *comp.CompilationContext) Codegen {
return Codegen{ .allocator = allocator }; return Codegen{ .allocator = allocator, .ctx = ctx };
}
fn typeToLLVM(self: *@This(), typ: comp.SymbolUnderlyingType) !llvm.LLVMTypeRef {
return switch (typ) {
.Integer32 => llvm.LLVMInt32Type(),
.Integer64 => llvm.LLVMInt64Type(),
.Bool => llvm.LLVMInt1Type(),
.OpaqueType => |val| {
std.debug.warn("Invalid return type: {}\n", val);
return CompileError.TypeError;
},
.Struct, .Enum => |lex| blk: {
var sym_data = self.ctx.symbol_table.get(lex).?.value;
break :blk switch (sym_data) {
.Struct => unreachable,
.Enum => llvm.LLVMInt32Type(),
else => {
std.debug.warn("Function {} is not a type\n", lex);
return CompileError.TypeError;
},
};
},
else => {
std.debug.warn("TODO handle {}\n", typ);
return CompileError.TypeError;
},
};
} }
fn emitExpr(self: *Codegen, builder: var, expr: *const ast.Expr) anyerror!llvm.LLVMValueRef { fn emitExpr(self: *Codegen, builder: var, expr: *const ast.Expr) anyerror!llvm.LLVMValueRef {
@ -191,16 +211,7 @@ pub const Codegen = struct {
} }
} }
fn emitBlock(self: *Codegen, builder: var, block: ast.Block) !llvm.LLVMValueRef { /// Emit LLVM ir for the given node.
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,
@ -210,21 +221,25 @@ pub const Codegen = struct {
.Root => @panic("Should not have gotten Root"), .Root => @panic("Should not have gotten Root"),
.FnDecl => |decl| { .FnDecl => |decl| {
const name = decl.func_name.lexeme; const name = decl.func_name.lexeme;
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;
const name_cstr = try std.cstr.addNullByte(self.allocator, name); const name_cstr = try std.cstr.addNullByte(self.allocator, name);
errdefer self.allocator.free(name_cstr); errdefer self.allocator.free(name_cstr);
const fn_ret_type = decl.return_type.lexeme;
var param_types = llvm.LLVMTypeList.init(self.allocator); var param_types = llvm.LLVMTypeList.init(self.allocator);
errdefer param_types.deinit(); errdefer param_types.deinit();
for (decl.params.toSlice()) |param| { for (decl.params.toSlice()) |param| {
// TODO better type resolution try param_types.append(try self.typeToLLVM(fn_sym.parameters.get(
try param_types.append(try basicTypeToLLVM(param.typ.lexeme)); param.name.lexeme,
).?.value));
} }
var llvm_ret_type = llvm.LLVMFunctionType( var llvm_ret_type = llvm.LLVMFunctionType(
try basicTypeToLLVM(fn_ret_type), try self.typeToLLVM(fn_sym.return_type),
param_types.toSlice().ptr, param_types.toSlice().ptr,
@intCast(c_uint, param_types.len), @intCast(c_uint, param_types.len),
0, 0,
@ -255,9 +270,12 @@ pub const Codegen = struct {
std.debug.warn("cgen: generated function '{}'\n", name); std.debug.warn("cgen: generated function '{}'\n", name);
}, },
// NOTE: enums don't have specific llvm ir code generated for them
.Enum => {},
else => { else => {
std.debug.warn("TODO handle node type {}\n", @tagName(node.*)); std.debug.warn("TODO handle node type {}\n", @tagName(node.*));
unreachable; return;
}, },
} }
} }

View file

@ -59,8 +59,8 @@ pub const FunctionSymbol = struct {
// structs are hashmaps pointing to SymbolUnderlyingType // structs are hashmaps pointing to SymbolUnderlyingType
pub const UnderlyingTypeMap = std.hash_map.StringHashMap(SymbolUnderlyingType); pub const UnderlyingTypeMap = std.hash_map.StringHashMap(SymbolUnderlyingType);
// enums have lists of identifiers // enums have maps from fields to u32s
pub const IdentifierList = std.ArrayList([]const u8); pub const IdentifierMap = std.StringHashMap(u32);
// TODO const // TODO const
pub const SymbolType = enum { pub const SymbolType = enum {
@ -73,7 +73,7 @@ pub const SymbolType = enum {
pub const SymbolData = union(SymbolType) { pub const SymbolData = union(SymbolType) {
Function: FunctionSymbol, Function: FunctionSymbol,
Struct: UnderlyingTypeMap, Struct: UnderlyingTypeMap,
Enum: IdentifierList, Enum: IdentifierMap,
// variables (parameters and variables), for the type system // variables (parameters and variables), for the type system
// only have types // only have types
@ -161,4 +161,18 @@ pub const CompilationContext = struct {
}, },
}); });
} }
pub fn insertEnum(self: *@This(), enu: ast.Enum) !void {
var ident_map = IdentifierMap.init(self.allocator);
errdefer ident_map.deinit();
// TODO change this when enums get support for custom values
for (enu.fields.toSlice()) |token, idx| {
_ = try ident_map.put(token.lexeme, @intCast(u32, idx));
}
_ = try self.symbol_table.put(enu.name.lexeme, SymbolData{
.Enum = ident_map,
});
}
}; };

View file

@ -56,7 +56,7 @@ pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result {
std.debug.warn("symbol table\n"); std.debug.warn("symbol table\n");
printer.printContext(ctx); printer.printContext(ctx);
var cgen = codegen.Codegen.init(allocator); var cgen = codegen.Codegen.init(allocator, &ctx);
try cgen.gen(root); try cgen.gen(root);
return Result.Ok; return Result.Ok;

View file

@ -143,13 +143,18 @@ pub const TypeSolver = struct {
try ctx.insertStruct(struc, types); try ctx.insertStruct(struc, types);
}, },
// TODO enums are u32 // TODO change enums to u32
//.Enum => {}, .Enum => |enu| {
try ctx.insertEnum(enu);
},
// TODO infer type of expr in const // TODO infer type of expr in const
//.ConstDecl => {}, //.ConstDecl => {},
else => unreachable, else => {
std.debug.warn("TODO type analysis of {}\n", node.*);
return CompileError.TypeError;
},
} }
} }