Compare commits

..

No commits in common. "81fd7184037889b2ee175d56229b7d2189d591ce" and "3f48be3420facca86bb527ab2b4ae4126ccf1a5c" have entirely different histories.

7 changed files with 52 additions and 116 deletions

View file

@ -1,6 +1,6 @@
# rayoko # rayoko
a toy programming language and compiler a programming language
this time it'll work i promise it wont be like vig plrease this time it'll work i promise it wont be like vig plrease
@ -11,11 +11,3 @@ git clone https://gitdab.com/luna/rayoko
cd rayoko cd rayoko
zig build install --prefix ~/.local/ zig build install --prefix ~/.local/
``` ```
# use
```
rayoko examples/hello.ry # outputs to outpath.o
gcc outpath.o examples/hello.c -o hello
./hello
```

View file

@ -1,5 +0,0 @@
#include <stdio.h>
int main(void) {
printf("add(2, 2) = %d\n", add(2, 2));
}

View file

@ -32,21 +32,22 @@ fn test_function() B {
} }
fn multwo(num: i32, double_flag: bool) i32 { fn multwo(num: i32, double_flag: bool) i32 {
if (double_flag) { // TODO resolve expr variables
if (true) {
var truthy = true; var truthy = true;
return num * 2; return 1 * 2;
} else { } else {
var falsey = false; var falsey = false;
return num; return 1;
} }
} }
fn func_refer_param(b: i32) i32 { fn multwo_with_one(b: i32) i32 {
return b * 231 + b; return multwo(b, false) + b;
} }
fn add(a: i32, b: i32) i32 { fn add(a: i32, b: i32) i32 {
return a + b; return 69 + 69;
} }
fn and_fn() bool { fn and_fn() bool {

View file

@ -458,7 +458,7 @@ pub const TypeSolver = struct {
// for a function, we always create a new root scope for it // for a function, we always create a new root scope for it
// and force-set it into the current context // and force-set it into the current context
var scope = try comp.Scope.create(self.allocator, null, name); var scope = try comp.Scope.create(self.allocator, null, "function");
errdefer scope.deinit(); errdefer scope.deinit();
// we intentionally insert the function so that: // we intentionally insert the function so that:

View file

@ -401,7 +401,7 @@ pub fn printContext(ctx: CompilationContext) void {
std.debug.warn( std.debug.warn(
"\tparameter {} typ {}\n", "\tparameter {} typ {}\n",
param_kv.key, param_kv.key,
prettyType(param_kv.value.typ), prettyType(param_kv.value),
); );
} }

View file

@ -31,8 +31,6 @@ pub const Codegen = struct {
ctx: *comp.CompilationContext, ctx: *comp.CompilationContext,
llvm_table: LLVMTable, llvm_table: LLVMTable,
current_function_name: ?[]const u8 = null,
pub fn init(allocator: *std.mem.Allocator, ctx: *comp.CompilationContext) Codegen { pub fn init(allocator: *std.mem.Allocator, ctx: *comp.CompilationContext) Codegen {
return Codegen{ return Codegen{
.allocator = allocator, .allocator = allocator,
@ -220,32 +218,7 @@ pub const Codegen = struct {
return llvm.LLVMBuildStore(builder, null, assign_expr); return llvm.LLVMBuildStore(builder, null, assign_expr);
}, },
.Variable => |vari| { .Variable => @panic("TODO emit variables"),
var kv_opt = self.ctx.metadata_map.get(expr);
if (kv_opt == null) {
std.debug.warn("variable {} not fully analyzed\n", vari);
return CompileError.EmitError;
}
// we have metadata, which means we can check if the variable
// is coming from the scope or from the function
var metadata = kv_opt.?.value;
return switch (metadata.using) {
.Function => blk: {
var param = metadata.from_function.?.parameters.get(vari.lexeme).?.value;
var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value;
// may i thank all the demons in hell for giving me
// good energies to make this work
break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx));
},
.Scope => @panic("TODO local variables"),
};
},
else => { else => {
std.debug.warn("Got unexpected expr {}\n", ast.ExprType(expr.*)); std.debug.warn("Got unexpected expr {}\n", ast.ExprType(expr.*));
@ -284,8 +257,6 @@ pub const Codegen = struct {
var then_rets = false; var then_rets = false;
var else_rets = false; var else_rets = false;
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
for (ifstmt.then_branch.toSlice()) |then_stmt| { for (ifstmt.then_branch.toSlice()) |then_stmt| {
// keep emitting until branch has ret // keep emitting until branch has ret
@ -298,8 +269,6 @@ pub const Codegen = struct {
} }
} }
self.ctx.dumpScope();
// only build the br instruction if we didn't ret, because // only build the br instruction if we didn't ret, because
// there can't be any instruction after a terminator // there can't be any instruction after a terminator
// same applies for the else branch // same applies for the else branch
@ -313,7 +282,6 @@ pub const Codegen = struct {
// roughly translating to kaleidoscope's // roughly translating to kaleidoscope's
// '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());
for (else_block.toSlice()) |else_stmt| { for (else_block.toSlice()) |else_stmt| {
// keep emitting until branch has ret // keep emitting until branch has ret
if (!else_rets) if (!else_rets)
@ -324,8 +292,6 @@ pub const Codegen = struct {
else => {}, else => {},
} }
} }
self.ctx.dumpScope();
} }
if (!else_rets) if (!else_rets)
@ -337,30 +303,18 @@ pub const Codegen = struct {
if (then_rets and else_rets) if (then_rets and else_rets)
_ = llvm.LLVMBuildUnreachable(builder); _ = llvm.LLVMBuildUnreachable(builder);
// phis aren't needed since our ifs arent expressions
//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);
}, },
.VarDecl => |vardecl| { // TODO
// we alaready inferred the type of the variable in the .VarDecl => {},
// analyze pass and the current scope contains the variable's
// type(hopefully), so we resolve it
const name = vardecl.name.lexeme;
var var_metadata = try self.ctx.resolveVarType(name);
var name_cstr = try std.cstr.addNullByte(self.allocator, name);
errdefer self.allocator.free(name_cstr);
var fn_symbol = self.getFnSymbol(self.current_function_name.?);
// TODO add llvm value ref to var metadata as well
var variable = llvm.LLVMBuildAlloca(
builder,
try self.typeToLLVM(var_metadata.typ),
name_cstr.ptr,
);
var llvm_expr = try self.emitExpr(builder, vardecl.value);
_ = llvm.LLVMBuildStore(builder, llvm_expr, variable);
},
else => { else => {
std.debug.warn("Got unexpected stmt {}\n", stmt.*); std.debug.warn("Got unexpected stmt {}\n", stmt.*);
@ -369,12 +323,6 @@ pub const Codegen = struct {
} }
} }
fn getFnSymbol(self: *@This(), name: []const u8) comp.FunctionSymbol {
var fn_sym_search = self.ctx.symbol_table.get(name).?.value;
std.debug.assert(comp.SymbolType(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,
@ -385,10 +333,10 @@ 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;
self.current_function_name = name;
std.debug.warn("cgen: genning function '{}'\n", name);
var fn_sym = self.getFnSymbol(name); 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);
@ -399,7 +347,7 @@ pub const Codegen = struct {
for (decl.params.toSlice()) |param| { for (decl.params.toSlice()) |param| {
try param_types.append(try self.typeToLLVM(fn_sym.parameters.get( try param_types.append(try self.typeToLLVM(fn_sym.parameters.get(
param.name.lexeme, param.name.lexeme,
).?.value.typ)); ).?.value));
} }
var llvm_ret_type = llvm.LLVMFunctionType( var llvm_ret_type = llvm.LLVMFunctionType(
@ -420,13 +368,17 @@ pub const Codegen = struct {
var builder = llvm.LLVMCreateBuilder(); var builder = llvm.LLVMCreateBuilder();
llvm.LLVMPositionBuilderAtEnd(builder, entry); llvm.LLVMPositionBuilderAtEnd(builder, entry);
self.ctx.setScope(fn_sym.scope);
defer self.ctx.dumpScope();
for (decl.body.toSlice()) |stmt| { for (decl.body.toSlice()) |stmt| {
try self.emitStmt(builder, &stmt); try self.emitStmt(builder, &stmt);
} }
//var tmp = llvm.LLVMBuildAdd(
// builder,
// llvm.LLVMGetParam(func, 0),
// llvm.LLVMGetParam(func, 1),
// c"tmp",
//);
std.debug.warn("cgen: generated function '{}'\n", name); std.debug.warn("cgen: generated function '{}'\n", name);
}, },

View file

@ -39,9 +39,8 @@ pub const Scope = struct {
parent: ?*Scope, parent: ?*Scope,
env: UnderlyingTypeMap, env: UnderlyingTypeMap,
/// List of children in the scope. /// Used for debug information.
children: ScopeList, children: ScopeList,
cur_child_idx: usize = 0,
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
id: ?[]const u8 = null, id: ?[]const u8 = null,
@ -65,24 +64,11 @@ pub const Scope = struct {
return child; return child;
} }
pub fn nextChild(self: *@This()) *Scope {
var child = self.children.at(self.cur_child_idx);
self.cur_child_idx += 1;
return child;
}
pub fn deinit(self: *const @This()) void { pub fn deinit(self: *const @This()) void {
self.env.deinit(); self.env.deinit();
} }
}; };
pub const Parameter = struct {
idx: usize,
typ: SymbolUnderlyingType,
};
pub const ParameterMap = std.StringHashMap(Parameter);
// functions, for our purposes, other than symbols, have: // functions, for our purposes, other than symbols, have:
// - a return type // - a return type
// - parameters // - parameters
@ -92,10 +78,24 @@ pub const FunctionSymbol = struct {
/// Parameters for a function are also a table instead of an ArrayList /// Parameters for a function are also a table instead of an ArrayList
/// because we want to resolve identifiers to them. /// because we want to resolve identifiers to them.
parameters: ParameterMap, parameters: UnderlyingTypeMap,
parameter_list: TypeList, parameter_list: TypeList,
scope: *Scope, scope: *Scope,
/// Find a given identifier in the function. Can resolve to either a parameter
pub fn findSymbol(self: *const @This(), identifier: []const u8) ?SymbolData {
// try to find it on overall variable symbols
// TODO
//var var_sym = self.symbols.get(identifier);
//if (var_sym != null) return var_sym.?.value;
//var param_sym = self.parameters.get(identifier);
//if (param_sym != null) return param_sym.?.value;
return null;
}
}; };
// structs are hashmaps pointing to SymbolUnderlyingType // structs are hashmaps pointing to SymbolUnderlyingType
@ -191,7 +191,6 @@ pub const CompilationContext = struct {
/// Set a given scope as the current scope. /// Set a given scope as the current scope.
pub fn setScope(self: *@This(), scope: *Scope) void { pub fn setScope(self: *@This(), scope: *Scope) void {
std.debug.warn("==set== set scope to {}\n", scope.id);
self.current_scope = scope; self.current_scope = scope;
} }
@ -265,13 +264,10 @@ pub const CompilationContext = struct {
param_types: TypeList, param_types: TypeList,
scope: *Scope, scope: *Scope,
) !void { ) !void {
var param_map = ParameterMap.init(self.allocator); var type_map = UnderlyingTypeMap.init(self.allocator);
for (decl.params.toSlice()) |param, idx| { for (decl.params.toSlice()) |param, idx| {
_ = try param_map.put(param.name.lexeme, Parameter{ _ = try type_map.put(param.name.lexeme, param_types.at(idx));
.idx = idx,
.typ = param_types.at(idx),
});
} }
const lex = decl.func_name.lexeme; const lex = decl.func_name.lexeme;
@ -280,7 +276,7 @@ pub const CompilationContext = struct {
.Function = FunctionSymbol{ .Function = FunctionSymbol{
.decl = decl, .decl = decl,
.return_type = ret_type, .return_type = ret_type,
.parameters = param_map, .parameters = type_map,
.parameter_list = param_types, .parameter_list = param_types,
.scope = scope, .scope = scope,
}, },
@ -357,7 +353,7 @@ pub const CompilationContext = struct {
if (self.cur_function) |cur_function| { if (self.cur_function) |cur_function| {
var kv_opt = cur_function.parameters.get(name); var kv_opt = cur_function.parameters.get(name);
if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value.typ); if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value);
} }
std.debug.warn("Unknown name {}\n", name); std.debug.warn("Unknown name {}\n", name);