From 484d1a6e2c52f27e324b0252fcfe5041ad996171 Mon Sep 17 00:00:00 2001 From: Slendi Date: Thu, 29 Feb 2024 09:29:21 +0200 Subject: [PATCH] Add support or extern function Signed-off-by: Slendi --- src/ast.odin | 22 +++++++ src/lexer.odin | 3 - src/main.odin | 139 ++++++++++++++++++++++-------------------- src/parser.odin | 5 +- src/type_checker.odin | 18 +++++- test_type_checker.cat | 4 ++ 6 files changed, 119 insertions(+), 72 deletions(-) diff --git a/src/ast.odin b/src/ast.odin index 3c7c736..7987f23 100644 --- a/src/ast.odin +++ b/src/ast.odin @@ -25,6 +25,7 @@ NodeKind :: enum { Ret, // + ExternFunction, Function, Struct, Enum, @@ -154,6 +155,27 @@ node_create_function_call :: proc( return } +node_create_extern_function :: proc( + range: TextRange, + name: [dynamic]u8, + return_type: ^Node, + args: [dynamic]^Node, +) -> ( + ret: ^Node, +) { + ret = new(Node) + ret^ = { + kind = .ExternFunction, + range = range, + children = {return_type}, + value = name, + } + for arg in args { + append(&ret.children, arg) + } + return +} + node_create_function :: proc( range: TextRange, name: [dynamic]u8, diff --git a/src/lexer.odin b/src/lexer.odin index 67cd78c..6bb7443 100644 --- a/src/lexer.odin +++ b/src/lexer.odin @@ -55,9 +55,6 @@ lexer_should_not_emit_semicolon :: proc(lexer: ^Lexer) -> bool { lexer.last_token_kind == .OpenParen || lexer.last_token_kind == .OpenBrace || lexer.last_token_kind == .OpenBracket || - lexer.last_token_kind == .CloseParen || - lexer.last_token_kind == .CloseBrace || - lexer.last_token_kind == .CloseBracket || lexer.last_token_kind == .Add || lexer.last_token_kind == .Subtract || lexer.last_token_kind == .Multiply || diff --git a/src/main.odin b/src/main.odin index 82d19a4..a57b8e5 100644 --- a/src/main.odin +++ b/src/main.odin @@ -4,79 +4,86 @@ import "core:fmt" import "core:os" main :: proc() { - ctx := LLVMContextCreate() - defer LLVMContextDispose(ctx) - module := LLVMModuleCreateWithNameInContext("hello", ctx) - defer LLVMDisposeModule(module) - builder := LLVMCreateBuilderInContext(ctx) + // ctx := LLVMContextCreate() + // defer LLVMContextDispose(ctx) + // module := LLVMModuleCreateWithNameInContext("hello", ctx) + // defer LLVMDisposeModule(module) + // builder := LLVMCreateBuilderInContext(ctx) - int_8_type := LLVMInt8TypeInContext(ctx) - int_8_type_ptr := LLVMPointerType(int_8_type, 0) - int_32_type := LLVMInt32TypeInContext(ctx) + // int_8_type := LLVMInt8TypeInContext(ctx) + // int_8_type_ptr := LLVMPointerType(int_8_type, 0) + // int_32_type := LLVMInt32TypeInContext(ctx) - puts_function_args_type := []LLVMTypeRef{ - int_8_type_ptr, + // puts_function_args_type := []LLVMTypeRef{ + // int_8_type_ptr, + // } + + // puts_function_type := LLVMFunctionType(int_32_type, raw_data(puts_function_args_type), 1, LLVMBool(0)) + // puts_function := LLVMAddFunction(module, "puts", puts_function_type) + + // main_function_type := LLVMFunctionType(int_32_type, nil, 0, LLVMBool(0)) + // main_function := LLVMAddFunction(module, "main", main_function_type) + + // entry := LLVMAppendBasicBlockInContext(ctx, main_function, "entry") + // LLVMPositionBuilderAtEnd(builder, entry) + + // puts_function_args := []LLVMValueRef { + // LLVMBuildPointerCast( + // builder, + // LLVMBuildGlobalString(builder, "Hello world!\n", "hello"), + // int_8_type_ptr, + // "0", + // ), + // } + + // LLVMBuildCall2(builder, puts_function_type, puts_function, raw_data(puts_function_args), len(puts_function_args), "i") + // LLVMBuildRet(builder, LLVMConstInt(int_32_type, 0, LLVMBool(0))) + + // LLVMPrintModuleToFile(module, "hello.ll", nil) + + handle: os.Handle + if len(os.args) >= 2 { + errno: os.Errno + handle, errno = os.open(os.args[1]) + if errno != 0 { + fmt.printf("Error opening file\n", errno) + return + } + } else { + handle = os.stdin + } + defer os.close(handle) + + data, err := os.read_entire_file_from_handle(handle) + if !err { + fmt.printf("Error reading file\n", err) + return } - puts_function_type := LLVMFunctionType(int_32_type, raw_data(puts_function_args_type), 1, LLVMBool(0)) - puts_function := LLVMAddFunction(module, "puts", puts_function_type) - - main_function_type := LLVMFunctionType(int_32_type, nil, 0, LLVMBool(0)) - main_function := LLVMAddFunction(module, "main", main_function_type) - - entry := LLVMAppendBasicBlockInContext(ctx, main_function, "entry") - LLVMPositionBuilderAtEnd(builder, entry) - - puts_function_args := []LLVMValueRef { - LLVMBuildPointerCast( - builder, - LLVMBuildGlobalString(builder, "Hello world!\n", "hello"), - int_8_type_ptr, - "0", - ), + u8_arr : [dynamic]u8 + for ch in data { + append(&u8_arr, u8(ch)) } - LLVMBuildCall2(builder, puts_function_type, puts_function, raw_data(puts_function_args), len(puts_function_args), "i") - LLVMBuildRet(builder, LLVMConstInt(int_32_type, 0, LLVMBool(0))) + lexer := lexer_create(&u8_arr) + parser := parser_create(lexer) - LLVMPrintModuleToFile(module, "hello.ll", nil) + ast := parser_parse(&parser) + if len(g_message_list) > 0 { + for msg in g_message_list { + fmt.printf("%s\n", msg) + } + return + } + clear(&g_message_list) + type_check(ast, nil) + if len(g_message_list) > 0 { + for msg in g_message_list { + fmt.printf("%s\n", msg) + } + return + } - //handle: os.Handle - //if len(os.args) >= 2 { - // errno: os.Errno - // handle, errno = os.open(os.args[1]) - // if errno != 0 { - // fmt.printf("Error opening file\n", errno) - // return - // } - //} else { - // handle = os.stdin - //} - //defer os.close(handle) - - //data, err := os.read_entire_file_from_handle(handle) - //if !err { - // fmt.printf("Error reading file\n", err) - // return - //} - - //u8_arr : [dynamic]u8 - //for ch in data { - // append(&u8_arr, u8(ch)) - //} - - //lexer := lexer_create(&u8_arr) - //parser := parser_create(lexer) - - //ast := parser_parse(&parser) - //type_check(ast, nil) - //if len(g_message_list) > 0 { - // for msg in g_message_list { - // fmt.printf("%s\n", msg) - // } - // return - //} - - //node_print(ast) + node_print(ast) } diff --git a/src/parser.odin b/src/parser.odin index e4b4932..d8416e0 100644 --- a/src/parser.odin +++ b/src/parser.odin @@ -185,9 +185,12 @@ parser_parse_function_definition :: proc(parser: ^Parser) -> ^Node { } type: ^Node = nil - if parser.tok.kind != .OpenBrace { + if parser.tok.kind != .OpenBrace && parser.tok.kind != .Semicolon { type = parser_parse_type(parser) } + if parser.tok.kind == .Semicolon { + return node_create_extern_function(parser.tok.range, name, type, params) + } expect(parser, .OpenBrace) body := parser_parse_block(parser, .CloseBrace) return node_create_function(parser.tok.range, name, type, body, params) diff --git a/src/type_checker.odin b/src/type_checker.odin index f06d7f4..e61bfba 100644 --- a/src/type_checker.odin +++ b/src/type_checker.odin @@ -310,6 +310,9 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) { } type_check(ast.children[1], ast) scope_leave() + case .ExternFunction: + ast.return_type = ast_to_type(ast.children[0]) + scope_stack[len(scope_stack) - 1].function_return_type = ast.return_type case: fmt.panicf("Unhandled node kind in type_check: {}", ast.kind) } @@ -323,7 +326,11 @@ find_function_definitions :: proc(ast_: ^Node) -> (ret: [dynamic]^FunctionType) if ast == nil { continue } + is_extern := false #partial switch (ast.kind) { + case .ExternFunction: + is_extern := true + fallthrough case .Function: for fn in ret { if compare_dyn_arrs(&fn.name, &ast.value.([dynamic]u8)) { @@ -346,8 +353,15 @@ find_function_definitions :: proc(ast_: ^Node) -> (ret: [dynamic]^FunctionType) return_type = ast_to_type(ast.children[0]) } for decl, i in ast.children { - if i < 2 { - continue + if is_extern == false { + if i < 2 { + continue + } + } else { + if i < 1 { + continue + } + } type := ast_to_type(decl.children[1]) append(&fn.parameter_types, type) diff --git a/test_type_checker.cat b/test_type_checker.cat index 93bea5d..b8121ee 100644 --- a/test_type_checker.cat +++ b/test_type_checker.cat @@ -5,6 +5,10 @@ fn name(a b: f32) i32 { ret (a + b) as i32 } +fn put_32(str: []u32) + name 123.0 456.0 let arr: []i32, arr2: [69]u8, ptr: ^i32 + +put_32("Hello")