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

@ -4,452 +4,471 @@ import "core:fmt"
import "core:strconv" import "core:strconv"
Scope :: struct { Scope :: struct {
function_definitions: map[int]^FunctionType, // A map to nodes which are the function definitions function_definitions: map[int]^FunctionType, // A map to nodes which are the function definitions
variable_definitions: map[int]^Type, // A map to types variable_definitions: map[int]^Type, // A map to types
variable_mutability_definitions: map[int]bool, // A map to a variable's mutability variable_mutability_definitions: map[int]bool, // A map to a variable's mutability
function_return_type: ^Type, function_return_type: ^Type,
} }
@(private = "file") @(private = "file")
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:
} else { child.return_type = type_create_array(type_create_integer(32, false), 0)
if parent != nil { case .Character:
parent.return_type = child.return_type child.return_type = type_create_integer(32, false)
} }
} } else {
if parent != nil {
parent.return_type = child.return_type
}
}
} }
@(private = "file") @(private = "file")
is_number :: proc(node: ^Node) -> bool { is_number :: proc(node: ^Node) -> bool {
return node.kind == .Integer || node.kind == .Float return node.kind == .Integer || node.kind == .Float
} }
@(private = "file") @(private = "file")
ast_to_type :: proc(node: ^Node) -> ^Type { ast_to_type :: proc(node: ^Node) -> ^Type {
if node == nil { if node == nil {
return type_create_integer(0, false) return type_create_integer(0, false)
} }
if node.kind == .Identifier { if node.kind == .Identifier {
value := node.value.([dynamic]u8) value := node.value.([dynamic]u8)
if value[0] == 'u' { if value[0] == 'u' {
bit_size, ok := strconv.parse_u64_of_base(string(value[1:]), 10) bit_size, ok := strconv.parse_u64_of_base(string(value[1:]), 10)
if !ok { if !ok {
fmt.panicf("Failed to parse integer: %s", value) fmt.panicf("Failed to parse integer: %s", value)
} }
return type_create_integer(u8(bit_size), false) return type_create_integer(u8(bit_size), false)
} else if value[0] == 'i' { } else if value[0] == 'i' {
bit_size, ok := strconv.parse_u64_of_base(string(value[1:]), 10) bit_size, ok := strconv.parse_u64_of_base(string(value[1:]), 10)
if !ok { if !ok {
fmt.panicf("Failed to parse integer: %s", value) fmt.panicf("Failed to parse integer: %s", value)
} }
return type_create_integer(u8(bit_size), true) return type_create_integer(u8(bit_size), true)
} else if value[0] == 'f' { } else if value[0] == 'f' {
bit_size, ok := strconv.parse_u64_of_base(string(value[1:]), 10) bit_size, ok := strconv.parse_u64_of_base(string(value[1:]), 10)
if !ok { if !ok {
fmt.panicf("Failed to parse integer: %s", value) fmt.panicf("Failed to parse integer: %s", value)
} }
return type_create_float(u8(bit_size)) return type_create_float(u8(bit_size))
} else { } else {
fmt.panicf("Unhandled identifier in ast_to_type: %s", value) fmt.panicf("Unhandled identifier in ast_to_type: %s", value)
} }
} else if node.kind == .Pointer { } else if node.kind == .Pointer {
return type_create_pointer(ast_to_type(node.children[0])) return type_create_pointer(ast_to_type(node.children[0]))
} else if node.kind == .Array { } else if node.kind == .Array {
return type_create_array(ast_to_type(node.children[0]), node.value.(u64)) return type_create_array(ast_to_type(node.children[0]), node.value.(u64))
} else { } else {
fmt.panicf("Unhandled node kind in ast_to_type: {}", node.kind) fmt.panicf("Unhandled node kind in ast_to_type: {}", node.kind)
} }
} }
scope_stack := [dynamic]Scope {} scope_stack := [dynamic]Scope{}
scope_enter :: proc() { scope_enter :: proc() {
append(&scope_stack, Scope{}) append(&scope_stack, Scope{})
scope_stack[len(scope_stack) - 1].function_definitions = make(map[int]^FunctionType) scope_stack[len(scope_stack) - 1].function_definitions = make(map[int]^FunctionType)
scope_stack[len(scope_stack) - 1].variable_definitions = make(map[int]^Type) scope_stack[len(scope_stack) - 1].variable_definitions = make(map[int]^Type)
scope_stack[len(scope_stack) - 1].variable_mutability_definitions = make(map[int]bool) scope_stack[len(scope_stack) - 1].variable_mutability_definitions = make(map[int]bool)
scope_stack[len(scope_stack) - 1].function_return_type = nil scope_stack[len(scope_stack) - 1].function_return_type = nil
} }
scope_leave :: proc() { scope_leave :: proc() {
if len(scope_stack) == 0 { if len(scope_stack) == 0 {
fmt.panicf("Tried to leave scope when there are no scopes") fmt.panicf("Tried to leave scope when there are no scopes")
} }
delete(scope_stack[len(scope_stack) - 1].function_definitions) delete(scope_stack[len(scope_stack) - 1].function_definitions)
delete(scope_stack[len(scope_stack) - 1].variable_definitions) delete(scope_stack[len(scope_stack) - 1].variable_definitions)
pop(&scope_stack) pop(&scope_stack)
} }
scope_variable_lookup :: proc(name: [dynamic]u8) -> ^Type { scope_variable_lookup :: proc(name: [dynamic]u8) -> ^Type {
name_ := name name_ := name
#reverse for &scope in scope_stack { #reverse for &scope in scope_stack {
type, ok := scope.variable_definitions[get_character_sum_of_dyn_arr(&name_)] type, ok := scope.variable_definitions[get_character_sum_of_dyn_arr(&name_)]
if ok { if ok {
return type return type
} }
} }
return nil return nil
} }
scope_variable_lookup_mutable :: proc(name: [dynamic]u8) -> bool { scope_variable_lookup_mutable :: proc(name: [dynamic]u8) -> bool {
name_ := name name_ := name
#reverse for &scope in scope_stack { #reverse for &scope in scope_stack {
type, ok := scope.variable_mutability_definitions[get_character_sum_of_dyn_arr(&name_)] type, ok := scope.variable_mutability_definitions[get_character_sum_of_dyn_arr(&name_)]
if ok { if ok {
return type return type
} }
} }
return false return false
} }
scope_function_lookup :: proc(name: [dynamic]u8) -> ^FunctionType { scope_function_lookup :: proc(name: [dynamic]u8) -> ^FunctionType {
name_ := name name_ := name
#reverse for &scope in scope_stack { #reverse for &scope in scope_stack {
type, ok := scope.function_definitions[get_character_sum_of_dyn_arr(&name_)] type, ok := scope.function_definitions[get_character_sum_of_dyn_arr(&name_)]
if ok { if ok {
return type return type
} }
} }
return nil return nil
} }
scope_function_return_type_lookup :: proc() -> ^Type { scope_function_return_type_lookup :: proc() -> ^Type {
#reverse for &scope in scope_stack { #reverse for &scope in scope_stack {
if scope.function_return_type != nil { if scope.function_return_type != nil {
return scope.function_return_type return scope.function_return_type
} }
} }
return nil return nil
} }
type_check_function_call :: proc(ast: ^Node, parent_ast: ^Node, must_be_function := true) -> ^FunctionType { type_check_function_call :: proc(ast: ^Node, parent_ast: ^Node, must_be_function := true) -> ^FunctionType {
name : [dynamic]u8 name: [dynamic]u8
if ast.kind == .FunctionCall { if ast.kind == .FunctionCall {
name = ast.children[0].value.([dynamic]u8) name = ast.children[0].value.([dynamic]u8)
} else { } else {
name = ast.value.([dynamic]u8) name = ast.value.([dynamic]u8)
} }
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, return nil
fmt.aprintf("Undefined function: %s", name), }
ast.range,
),
)
}
return nil
}
return fn return fn
} }
type_check :: proc(ast: ^Node, parent_ast: ^Node) { type_check :: proc(ast: ^Node, parent_ast: ^Node) {
in_extern := false in_extern := false
if ast == nil { if ast == nil {
return return
} }
#partial switch (ast.kind) { #partial switch (ast.kind) {
case .Integer: fallthrough case .Integer:
case .Float: fallthrough fallthrough
case .String: case .Float:
infer_type(parent_ast, ast) fallthrough
case .Block: case .String:
scope_enter() infer_type(parent_ast, ast)
functions := find_function_definitions(ast) case .Block:
for fn, i in functions { scope_enter()
scope_stack[len(scope_stack) - 1].function_definitions[get_character_sum_of_dyn_arr(&fn.name)] = fn functions := find_function_definitions(ast)
} for fn, i in functions {
for child in ast.children { scope_stack[len(scope_stack) - 1].function_definitions[get_character_sum_of_dyn_arr(&fn.name)] = fn
type_check(child, ast) }
} for child in ast.children {
scope_leave() type_check(child, ast)
case .FunctionCall: }
type := scope_variable_lookup(ast.children[0].value.([dynamic]u8)) scope_leave()
if type != nil { case .FunctionCall:
name := ast.children[0].value.([dynamic]u8) type := scope_variable_lookup(ast.children[0].value.([dynamic]u8))
free(ast.children[0]) if type != nil {
clear(&ast.children) name := ast.children[0].value.([dynamic]u8)
ast.return_type = type free(ast.children[0])
ast.kind = .Identifier clear(&ast.children)
ast.value = name ast.return_type = type
} else { ast.kind = .Identifier
fn := type_check_function_call(ast, parent_ast) ast.value = name
if fn != nil { } else {
if len(fn.parameter_types) != len(ast.children) - 1 { fn := type_check_function_call(ast, parent_ast)
append(&g_message_list, if fn != nil {
message_create( if len(fn.parameter_types) != len(ast.children) - 1 {
.Error, append(
fmt.aprintf("Function call parameter count mismatch for function `%s`: {} and {}", fn.name, len(fn.parameter_types), len(ast.children) - 1), &g_message_list,
ast.range, message_create(
), .Error,
) fmt.aprintf(
break "Function call parameter count mismatch for function `%s`: {} and {}",
} fn.name,
len(fn.parameter_types),
len(ast.children) - 1,
),
ast.range,
),
)
break
}
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(
message_create( &g_message_list,
.Error, message_create(
fmt.aprintf("Type mismatch in function call for `%s`: Wanted {}, got {}", fn.name, param, ast.children[i + 1].return_type), .Error,
ast.range, fmt.aprintf(
), "Type mismatch in function call for `%s`: Wanted {}, got {}",
) fn.name,
} param,
} ast.children[i + 1].return_type,
),
ast.range,
),
)
}
}
ast.return_type = fn.return_type ast.return_type = fn.return_type
} }
} }
case .Identifier: case .Identifier:
type := scope_variable_lookup(ast.value.([dynamic]u8)) type := scope_variable_lookup(ast.value.([dynamic]u8))
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 {
), ast.kind = .FunctionCall
) append(&ast.children, node_create_value(.Identifier, ast.range, ast.value))
} else { ast.value = nil
ast.kind = .FunctionCall ast.return_type = fn.return_type
append(&ast.children, node_create_value(.Identifier, ast.range, ast.value)) }
ast.value = nil }
ast.return_type = fn.return_type ast.return_type = type
} case .BinaryExpression:
} type_check(ast.children[0], ast)
ast.return_type = type type_check(ast.children[1], ast)
case .BinaryExpression:
type_check(ast.children[0], 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(
message_create( &g_message_list,
.Error, message_create(
fmt.aprintf("Type mismatch: {} and {}", ast.children[0].return_type, ast.children[1].return_type), .Error,
ast.range, fmt.aprintf("Type mismatch: {} and {}", ast.children[0].return_type, ast.children[1].return_type),
), ast.range,
) ),
} )
}
ast.return_type = ast.children[0].return_type ast.return_type = ast.children[0].return_type
if ast.value_token_kind == .Assign { if ast.value_token_kind == .Assign {
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(
message_create( &g_message_list,
.Error, message_create(
fmt.aprintf("Variable is not mutable: %s", ast.children[0].value.([dynamic]u8)), .Error,
ast.range, fmt.aprintf("Variable is not mutable: %s", ast.children[0].value.([dynamic]u8)),
), ast.range,
) ),
} )
} else if ast.value_token_kind == .Equals || ast.value_token_kind == .NotEquals || }
ast.value_token_kind == .GreaterThan || ast.value_token_kind == .GreaterThanOrEqual || } else if ast.value_token_kind == .Equals ||
ast.value_token_kind == .LessThan || ast.value_token_kind == .LessThanOrEqual { ast.value_token_kind == .NotEquals ||
ast.return_type = type_create_integer(1, true) 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)
}
// FIXME: Verify that the operation is possible // FIXME: Verify that the operation is possible
case .UnaryExpression: case .UnaryExpression:
// FIXME: Verify that the operation is possible // FIXME: Verify that the operation is possible
type_check(ast.children[0], ast) type_check(ast.children[0], ast)
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 {
), type_check(ast.children[0], ast)
) if !compare_types(function_return_type, ast.children[0].return_type) {
} else { append(
type_check(ast.children[0], ast) &g_message_list,
if !compare_types(function_return_type, ast.children[0].return_type) { message_create(
append(&g_message_list, .Error,
message_create( fmt.aprintf("Type mismatch: {} and {}", function_return_type, ast.children[0].return_type),
.Error, ast.range,
fmt.aprintf("Type mismatch: {} and {}", function_return_type, ast.children[0].return_type), ),
ast.range, )
), }
) }
} case .Cast:
} type_check(ast.children[0], ast)
case .Cast: type_to := ast_to_type(ast.children[1])
type_check(ast.children[0], ast) // FIXME: Check if compatible
type_to := ast_to_type(ast.children[1]) ast.return_type = type_to
// FIXME: Check if compatible case .BitwiseCast:
ast.return_type = type_to type_check(ast.children[0], ast)
case .BitwiseCast: // FIXME: Check if they are both the same bit size
type_check(ast.children[0], ast) ast.return_type = ast_to_type(ast.children[1])
// FIXME: Check if they are both the same bit size case .VariableDeclaration:
ast.return_type = ast_to_type(ast.children[1]) if ast.children[2] != nil {
case .VariableDeclaration: type_check(ast.children[2], ast)
if ast.children[2] != nil { if ast.children[1] == nil {
type_check(ast.children[2], ast) ast.return_type = ast.children[2].return_type
if ast.children[1] == nil { }
ast.return_type = ast.children[2].return_type if !compare_types(ast.return_type, ast.children[2].return_type) {
} append(
if !compare_types(ast.return_type, ast.children[2].return_type) { &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), ast.range,
ast.range, ),
), )
) }
} } 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))] =
scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] = ast.return_type 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) scope_stack[len(scope_stack) - 1].variable_mutability_definitions[get_character_sum_of_dyn_arr(&ast.children[0].value.([dynamic]u8))] =
case .If: !ast.value.(bool)
type_check(ast.children[0], ast) case .If:
if ast.children[0].return_type == nil || ast.children[0].return_type.kind != .Integer { type_check(ast.children[0], ast)
append(&g_message_list, if ast.children[0].return_type == nil || ast.children[0].return_type.kind != .Integer {
message_create( append(
.Error, &g_message_list,
fmt.aprintf("If condition must be a signed/unsigned integer"), message_create(
ast.children[0].range, .Error,
), fmt.aprintf("If condition must be a signed/unsigned integer"),
) ast.children[0].range,
break ),
} )
type_check(ast.children[1], ast) break
if len(ast.children) == 3 { }
type_check(ast.children[2], ast) type_check(ast.children[1], ast)
} if len(ast.children) == 3 {
case .ExternFunction: type_check(ast.children[2], ast)
in_extern = true }
fallthrough case .ExternFunction:
case .Function: in_extern = true
scope_enter() fallthrough
ast.return_type = ast_to_type(ast.children[0]) case .Function:
scope_stack[len(scope_stack) - 1].function_return_type = ast.return_type scope_enter()
for child, i in ast.children { ast.return_type = ast_to_type(ast.children[0])
if in_extern == false { scope_stack[len(scope_stack) - 1].function_return_type = ast.return_type
if i < 2 { for child, i in ast.children {
continue if in_extern == false {
} if i < 2 {
} else { continue
if i < 1 { }
continue } else {
} if i < 1 {
} continue
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_mutability_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] = true type_check(child, ast)
} scope_stack[len(scope_stack) - 1].variable_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] =
if in_extern == false { child.return_type
type_check(ast.children[1], ast) scope_stack[len(scope_stack) - 1].variable_mutability_definitions[get_character_sum_of_dyn_arr(&child.children[0].value.([dynamic]u8))] =
} true
scope_leave() }
case .For: if in_extern == false {
scope_enter() type_check(ast.children[1], ast)
for child, i in ast.children { }
if child == nil { scope_leave()
continue case .For:
} scope_enter()
if i == 1 { for child, i in ast.children {
type_check(child, ast) if child == nil {
should_error := false continue
if child.return_type == nil { }
should_error = true if i == 1 {
} else if child.return_type.kind != .Integer { type_check(child, ast)
should_error = true should_error := false
} if child.return_type == nil {
if should_error { should_error = true
append(&g_message_list, } else if child.return_type.kind != .Integer {
message_create( should_error = true
.Error, }
fmt.aprintf("For condition must be a signed/unsigned integer"), if should_error {
child.range, append(
), &g_message_list,
) message_create(
break .Error,
} fmt.aprintf("For condition must be a signed/unsigned integer"),
} else { child.range,
type_check(child, ast) ),
} )
} break
scope_leave() }
case: } else {
fmt.panicf("Unhandled node kind in type_check: {}", ast.kind) type_check(child, ast)
} }
}
scope_leave()
case:
fmt.panicf("Unhandled node kind in type_check: {}", ast.kind)
}
} }
find_function_definitions :: proc(ast_: ^Node) -> (ret: [dynamic]^FunctionType) { find_function_definitions :: proc(ast_: ^Node) -> (ret: [dynamic]^FunctionType) {
if ast_.kind != .Block { if ast_.kind != .Block {
return return
} }
for ast in ast_.children { for ast in ast_.children {
if ast == nil { if ast == nil {
continue continue
} }
is_extern := false is_extern := false
#partial switch (ast.kind) { #partial switch (ast.kind) {
case .ExternFunction: case .ExternFunction:
is_extern = true is_extern = true
fallthrough fallthrough
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(
message_create( &g_message_list,
.Error, message_create(
fmt.aprintf("Function already defined: {}", ast.value.([dynamic]u8)), .Error,
ast.range, fmt.aprintf("Function already defined: {}", ast.value.([dynamic]u8)),
), ast.range,
) ),
continue )
} continue
} }
fn := function_type_create() }
fn.name = ast.value.([dynamic]u8) fn := function_type_create()
return_type : ^Type fn.name = ast.value.([dynamic]u8)
if ast.children[0] == nil { return_type: ^Type
return_type = type_create_integer(0, false) if ast.children[0] == nil {
} else { return_type = type_create_integer(0, false)
return_type = ast_to_type(ast.children[0]) } else {
} return_type = ast_to_type(ast.children[0])
fn.return_type = return_type }
for decl, i in ast.children { fn.return_type = return_type
if is_extern == false { for decl, i in ast.children {
if i < 2 { if is_extern == false {
continue if i < 2 {
} continue
} else { }
if i < 1 { } else {
continue if i < 1 {
} 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)
} }
append(&ret, fn) append(&ret, fn)
case: case:
} }
} }
return return
} }

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