Add support for function declarations

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
Slendi 2024-03-10 01:30:46 +02:00
parent e4289d577a
commit 453689642c
4 changed files with 476 additions and 399 deletions

View File

@ -185,6 +185,54 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil
LLVMBool(0), LLVMBool(0),
) )
value = LLVMAddFunction(mod, strings.clone_to_cstring(string(fn.value.([dynamic]u8)[:])), type) value = LLVMAddFunction(mod, strings.clone_to_cstring(string(fn.value.([dynamic]u8)[:])), type)
current_position := LLVMGetInsertBlock(builder)
// Switch to function's basic block
basic_block := LLVMAppendBasicBlockInContext(ctx, value, "entry")
LLVMPositionBuilderAtEnd(builder, basic_block)
llvm_scope_enter("function", basic_block)
scope_number^ += 1
// Add function arguments to the scope
arg_index: uint = 0
for arg in fn.children {
if arg.kind != .VariableDeclaration {
continue
}
arg_name := strings.clone_to_cstring(string(arg.children[0].value.([dynamic]u8)[:]))
arg_value := LLVMGetParam(value, arg_index)
LLVMSetValueName2(arg_value, arg_name, u64(len(arg_name)))
llvm_top_scope().definitions[get_character_sum_of_dyn_arr(&arg.children[0].value.([dynamic]u8))] =
arg_value
llvm_top_scope().types[get_character_sum_of_dyn_arr(&arg.children[0].value.([dynamic]u8))] =
function_args_type[arg_index]
arg_index += 1
}
// Generate function body
arg_index = 0
for &arg in fn.children {
if arg.kind != .VariableDeclaration {
continue
}
arg_name := strings.clone_to_cstring(string(arg.children[0].value.([dynamic]u8)[:]))
arg_value :=
llvm_top_scope().definitions[get_character_sum_of_dyn_arr(&arg.children[0].value.([dynamic]u8))]
alloca := LLVMBuildAlloca(builder, function_args_type[arg_index], arg_name)
LLVMBuildStore(builder, arg_value, alloca)
llvm_top_scope().definitions[get_character_sum_of_dyn_arr(&arg.children[0].value.([dynamic]u8))] = alloca
arg_index += 1
}
generate_llvm_scope(ctx, mod, builder, value, fn.children[1], scope_number, basic_block)
llvm_scope_leave()
// Switch back to the previous position
LLVMPositionBuilderAtEnd(builder, current_position)
return return
} }
@ -577,6 +625,9 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil
generate_llvm_if(ctx, mod, builder, function, node, scope_number) generate_llvm_if(ctx, mod, builder, function, node, scope_number)
case .For: case .For:
generate_llvm_for(ctx, mod, builder, function, node, scope_number) generate_llvm_for(ctx, mod, builder, function, node, scope_number)
case .Ret:
value := generate_llvm_expression(ctx, mod, builder, node.children[0])
LLVMBuildRet(builder, value)
case: case:
fmt.panicf("FIXME: Implement other node kinds. Got: {}", node.kind) fmt.panicf("FIXME: Implement other node kinds. Got: {}", node.kind)
} }

View File

@ -173,4 +173,7 @@ foreign llvmc {
LLVMDisposeBuilder :: proc(Builder: LLVMBuilderRef) --- LLVMDisposeBuilder :: proc(Builder: LLVMBuilderRef) ---
LLVMDisposeModule :: proc(M: LLVMModuleRef) --- LLVMDisposeModule :: proc(M: LLVMModuleRef) ---
LLVMContextDispose :: proc(C: LLVMContextRef) --- LLVMContextDispose :: proc(C: LLVMContextRef) ---
LLVMGetParam :: proc(Fn: LLVMValueRef, Index: uint) -> LLVMValueRef ---
LLVMSetValueName2 :: proc(Val: LLVMValueRef, Name: cstring, Length: u64) ---
} }

View File

@ -14,10 +14,14 @@ Scope :: struct {
infer_type :: proc(parent: ^Node, child: ^Node) { infer_type :: proc(parent: ^Node, child: ^Node) {
if child.return_type == nil { if child.return_type == nil {
#partial switch child.kind { #partial switch child.kind {
case .Integer: child.return_type = type_create_integer(32, true) case .Integer:
case .Float: child.return_type = type_create_float(32) child.return_type = type_create_integer(32, true)
case .String: child.return_type = type_create_array(type_create_integer(32, false), 0) case .Float:
case .Character: child.return_type = type_create_integer(32, false) child.return_type = type_create_float(32)
case .String:
child.return_type = type_create_array(type_create_integer(32, false), 0)
case .Character:
child.return_type = type_create_integer(32, false)
} }
} else { } else {
if parent != nil { if parent != nil {
@ -139,13 +143,7 @@ type_check_function_call :: proc(ast: ^Node, parent_ast: ^Node, must_be_function
fn := scope_function_lookup(name) fn := scope_function_lookup(name)
if fn == nil { if fn == nil {
if must_be_function { if must_be_function {
append(&g_message_list, append(&g_message_list, message_create(.Error, fmt.aprintf("Undefined function: %s", name), ast.range))
message_create(
.Error,
fmt.aprintf("Undefined function: %s", name),
ast.range,
),
)
} }
return nil return nil
} }
@ -161,8 +159,10 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
} }
#partial switch (ast.kind) { #partial switch (ast.kind) {
case .Integer: fallthrough case .Integer:
case .Float: fallthrough fallthrough
case .Float:
fallthrough
case .String: case .String:
infer_type(parent_ast, ast) infer_type(parent_ast, ast)
case .Block: case .Block:
@ -188,10 +188,16 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
fn := type_check_function_call(ast, parent_ast) fn := type_check_function_call(ast, parent_ast)
if fn != nil { if fn != nil {
if len(fn.parameter_types) != len(ast.children) - 1 { if len(fn.parameter_types) != len(ast.children) - 1 {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Function call parameter count mismatch for function `%s`: {} and {}", fn.name, len(fn.parameter_types), len(ast.children) - 1), fmt.aprintf(
"Function call parameter count mismatch for function `%s`: {} and {}",
fn.name,
len(fn.parameter_types),
len(ast.children) - 1,
),
ast.range, ast.range,
), ),
) )
@ -201,10 +207,16 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
for param, i in fn.parameter_types { for param, i in fn.parameter_types {
type_check(ast.children[i + 1], ast) type_check(ast.children[i + 1], ast)
if !compare_types(param, ast.children[i + 1].return_type) { if !compare_types(param, ast.children[i + 1].return_type) {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Type mismatch in function call for `%s`: Wanted {}, got {}", fn.name, param, ast.children[i + 1].return_type), fmt.aprintf(
"Type mismatch in function call for `%s`: Wanted {}, got {}",
fn.name,
param,
ast.children[i + 1].return_type,
),
ast.range, ast.range,
), ),
) )
@ -219,12 +231,9 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
if type == nil { if type == nil {
fn := type_check_function_call(ast, parent_ast, false) fn := type_check_function_call(ast, parent_ast, false)
if fn == nil { if fn == nil {
append(&g_message_list, append(
message_create( &g_message_list,
.Error, message_create(.Error, fmt.aprintf("Undefined variable: %s", ast.value.([dynamic]u8)), ast.range),
fmt.aprintf("Undefined variable: %s", ast.value.([dynamic]u8)),
ast.range,
),
) )
} else { } else {
ast.kind = .FunctionCall ast.kind = .FunctionCall
@ -239,7 +248,8 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
type_check(ast.children[1], ast) type_check(ast.children[1], ast)
if !compare_types(ast.children[0].return_type, ast.children[1].return_type) { if !compare_types(ast.children[0].return_type, ast.children[1].return_type) {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Type mismatch: {} and {}", ast.children[0].return_type, ast.children[1].return_type), fmt.aprintf("Type mismatch: {} and {}", ast.children[0].return_type, ast.children[1].return_type),
@ -254,7 +264,8 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
ast.return_type = nil ast.return_type = nil
if !scope_variable_lookup_mutable(ast.children[0].value.([dynamic]u8)) { if !scope_variable_lookup_mutable(ast.children[0].value.([dynamic]u8)) {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Variable is not mutable: %s", ast.children[0].value.([dynamic]u8)), fmt.aprintf("Variable is not mutable: %s", ast.children[0].value.([dynamic]u8)),
@ -262,9 +273,12 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
), ),
) )
} }
} else if ast.value_token_kind == .Equals || ast.value_token_kind == .NotEquals || } else if ast.value_token_kind == .Equals ||
ast.value_token_kind == .GreaterThan || ast.value_token_kind == .GreaterThanOrEqual || ast.value_token_kind == .NotEquals ||
ast.value_token_kind == .LessThan || ast.value_token_kind == .LessThanOrEqual { ast.value_token_kind == .GreaterThan ||
ast.value_token_kind == .GreaterThanOrEqual ||
ast.value_token_kind == .LessThan ||
ast.value_token_kind == .LessThanOrEqual {
ast.return_type = type_create_integer(1, true) ast.return_type = type_create_integer(1, true)
} }
@ -275,17 +289,15 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
case .Ret: case .Ret:
function_return_type := scope_function_return_type_lookup() function_return_type := scope_function_return_type_lookup()
if function_return_type == nil { if function_return_type == nil {
append(&g_message_list, append(
message_create( &g_message_list,
.Error, message_create(.Error, fmt.aprintf("Return statement outside of function"), ast.range),
fmt.aprintf("Return statement outside of function"),
ast.range,
),
) )
} else { } else {
type_check(ast.children[0], ast) type_check(ast.children[0], ast)
if !compare_types(function_return_type, ast.children[0].return_type) { if !compare_types(function_return_type, ast.children[0].return_type) {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Type mismatch: {} and {}", function_return_type, ast.children[0].return_type), fmt.aprintf("Type mismatch: {} and {}", function_return_type, ast.children[0].return_type),
@ -310,7 +322,8 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
ast.return_type = ast.children[2].return_type ast.return_type = ast.children[2].return_type
} }
if !compare_types(ast.return_type, ast.children[2].return_type) { if !compare_types(ast.return_type, ast.children[2].return_type) {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Type mismatch: {} and {}", ast.return_type, ast.children[2].return_type), fmt.aprintf("Type mismatch: {} and {}", ast.return_type, ast.children[2].return_type),
@ -321,12 +334,15 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
} else { } else {
ast.return_type = ast_to_type(ast.children[1]) ast.return_type = ast_to_type(ast.children[1])
} }
scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] = ast.return_type scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] =
scope_stack[len(scope_stack) - 1].variable_mutability_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] = !ast.value.(bool) ast.return_type
scope_stack[len(scope_stack) - 1].variable_mutability_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] =
!ast.value.(bool)
case .If: case .If:
type_check(ast.children[0], ast) type_check(ast.children[0], ast)
if ast.children[0].return_type == nil || ast.children[0].return_type.kind != .Integer { if ast.children[0].return_type == nil || ast.children[0].return_type.kind != .Integer {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("If condition must be a signed/unsigned integer"), fmt.aprintf("If condition must be a signed/unsigned integer"),
@ -357,8 +373,10 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
} }
} }
type_check(child, ast) type_check(child, ast)
scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] = child.return_type scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] =
scope_stack[len(scope_stack) - 1].variable_mutability_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] = true child.return_type
scope_stack[len(scope_stack) - 1].variable_mutability_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] =
true
} }
if in_extern == false { if in_extern == false {
type_check(ast.children[1], ast) type_check(ast.children[1], ast)
@ -379,7 +397,8 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
should_error = true should_error = true
} }
if should_error { if should_error {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("For condition must be a signed/unsigned integer"), fmt.aprintf("For condition must be a signed/unsigned integer"),
@ -414,7 +433,8 @@ find_function_definitions :: proc(ast_: ^Node) -> (ret: [dynamic]^FunctionType)
case .Function: case .Function:
for fn in ret { for fn in ret {
if compare_dyn_arrs(&fn.name, &ast.value.([dynamic]u8)) { if compare_dyn_arrs(&fn.name, &ast.value.([dynamic]u8)) {
append(&g_message_list, append(
&g_message_list,
message_create( message_create(
.Error, .Error,
fmt.aprintf("Function already defined: {}", ast.value.([dynamic]u8)), fmt.aprintf("Function already defined: {}", ast.value.([dynamic]u8)),
@ -442,7 +462,6 @@ find_function_definitions :: proc(ast_: ^Node) -> (ret: [dynamic]^FunctionType)
if i < 1 { if i < 1 {
continue continue
} }
} }
type := ast_to_type(decl.children[1]) type := ast_to_type(decl.children[1])
append(&fn.parameter_types, type) append(&fn.parameter_types, type)

View File

@ -29,9 +29,13 @@ if a == 5 {
meow 420 meow 420
} }
fn add(a b: i32) i32 {
ret a + b
}
for a != 0 { for a != 0 {
meow (1 << a) >> 1 meow (1 << a) >> 1
a = a - 1 a = a - 1
} }
meow 69 -> meow (meow (add 60 9)) -> meow