Compare commits
No commits in common. "5188dac3c0419a1c6dc2f0e359cd4dd3b4857604" and "6b3d54aed7f8b43da84e925c967dbb1e39ea1c12" have entirely different histories.
5188dac3c0
...
6b3d54aed7
7 changed files with 50 additions and 100 deletions
|
@ -1,13 +1,16 @@
|
||||||
// import std;
|
// import std;
|
||||||
|
|
||||||
enum B {
|
struct B {
|
||||||
a
|
field i32
|
||||||
b
|
|
||||||
c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_function() B {
|
struct Awoo {
|
||||||
return B.a;
|
b B
|
||||||
|
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 {
|
||||||
|
|
|
@ -280,9 +280,6 @@ 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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -351,7 +351,8 @@ 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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,21 +395,7 @@ 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;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
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 "";
|
||||||
|
@ -15,6 +13,19 @@ 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);
|
||||||
|
@ -25,40 +36,9 @@ 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, ctx: *comp.CompilationContext) Codegen {
|
pub fn init(allocator: *std.mem.Allocator) Codegen {
|
||||||
return Codegen{ .allocator = allocator, .ctx = ctx };
|
return Codegen{ .allocator = allocator };
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -211,7 +191,16 @@ pub const Codegen = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit LLVM ir for the given node.
|
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,
|
||||||
|
@ -221,25 +210,21 @@ 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| {
|
||||||
try param_types.append(try self.typeToLLVM(fn_sym.parameters.get(
|
// TODO better type resolution
|
||||||
param.name.lexeme,
|
try param_types.append(try basicTypeToLLVM(param.typ.lexeme));
|
||||||
).?.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var llvm_ret_type = llvm.LLVMFunctionType(
|
var llvm_ret_type = llvm.LLVMFunctionType(
|
||||||
try self.typeToLLVM(fn_sym.return_type),
|
try basicTypeToLLVM(fn_ret_type),
|
||||||
param_types.toSlice().ptr,
|
param_types.toSlice().ptr,
|
||||||
@intCast(c_uint, param_types.len),
|
@intCast(c_uint, param_types.len),
|
||||||
0,
|
0,
|
||||||
|
@ -270,12 +255,9 @@ 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.*));
|
||||||
return;
|
unreachable;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 maps from fields to u32s
|
// enums have lists of identifiers
|
||||||
pub const IdentifierMap = std.StringHashMap(u32);
|
pub const IdentifierList = std.ArrayList([]const u8);
|
||||||
|
|
||||||
// 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: IdentifierMap,
|
Enum: IdentifierList,
|
||||||
|
|
||||||
// variables (parameters and variables), for the type system
|
// variables (parameters and variables), for the type system
|
||||||
// only have types
|
// only have types
|
||||||
|
@ -161,18 +161,4 @@ 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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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, &ctx);
|
var cgen = codegen.Codegen.init(allocator);
|
||||||
try cgen.gen(root);
|
try cgen.gen(root);
|
||||||
|
|
||||||
return Result.Ok;
|
return Result.Ok;
|
||||||
|
|
|
@ -143,18 +143,13 @@ pub const TypeSolver = struct {
|
||||||
try ctx.insertStruct(struc, types);
|
try ctx.insertStruct(struc, types);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO change enums to u32
|
// TODO enums are u32
|
||||||
.Enum => |enu| {
|
//.Enum => {},
|
||||||
try ctx.insertEnum(enu);
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO infer type of expr in const
|
// TODO infer type of expr in const
|
||||||
//.ConstDecl => {},
|
//.ConstDecl => {},
|
||||||
|
|
||||||
else => {
|
else => unreachable,
|
||||||
std.debug.warn("TODO type analysis of {}\n", node.*);
|
|
||||||
return CompileError.TypeError;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue