add support for resolving parameters in function body

This commit is contained in:
Luna 2019-09-27 20:39:16 -03:00
parent 3f48be3420
commit 849bbc0e94
4 changed files with 48 additions and 31 deletions

View file

@ -42,8 +42,8 @@ fn multwo(num: i32, double_flag: bool) i32 {
} }
} }
fn multwo_with_one(b: i32) i32 { fn func_refer_param(b: i32) i32 {
return multwo(b, false) + b; return b * 231 + b;
} }
fn add(a: i32, b: i32) i32 { fn add(a: i32, b: i32) i32 {

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), prettyType(param_kv.value.typ),
); );
} }

View file

@ -31,6 +31,8 @@ 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,
@ -218,7 +220,32 @@ pub const Codegen = struct {
return llvm.LLVMBuildStore(builder, null, assign_expr); return llvm.LLVMBuildStore(builder, null, assign_expr);
}, },
.Variable => @panic("TODO emit variables"), .Variable => |vari| {
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.*));
@ -333,6 +360,7 @@ 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;
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);
@ -347,7 +375,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)); ).?.value.typ));
} }
var llvm_ret_type = llvm.LLVMFunctionType( var llvm_ret_type = llvm.LLVMFunctionType(
@ -372,13 +400,6 @@ pub const Codegen = struct {
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

@ -69,6 +69,13 @@ pub const Scope = struct {
} }
}; };
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
@ -78,24 +85,10 @@ 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: UnderlyingTypeMap, parameters: ParameterMap,
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
@ -264,10 +257,13 @@ pub const CompilationContext = struct {
param_types: TypeList, param_types: TypeList,
scope: *Scope, scope: *Scope,
) !void { ) !void {
var type_map = UnderlyingTypeMap.init(self.allocator); var param_map = ParameterMap.init(self.allocator);
for (decl.params.toSlice()) |param, idx| { for (decl.params.toSlice()) |param, idx| {
_ = try type_map.put(param.name.lexeme, param_types.at(idx)); _ = try param_map.put(param.name.lexeme, Parameter{
.idx = idx,
.typ = param_types.at(idx),
});
} }
const lex = decl.func_name.lexeme; const lex = decl.func_name.lexeme;
@ -276,7 +272,7 @@ pub const CompilationContext = struct {
.Function = FunctionSymbol{ .Function = FunctionSymbol{
.decl = decl, .decl = decl,
.return_type = ret_type, .return_type = ret_type,
.parameters = type_map, .parameters = param_map,
.parameter_list = param_types, .parameter_list = param_types,
.scope = scope, .scope = scope,
}, },
@ -353,7 +349,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); if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value.typ);
} }
std.debug.warn("Unknown name {}\n", name); std.debug.warn("Unknown name {}\n", name);