diff --git a/CMakeLists.txt b/CMakeLists.txt index f5eabfe..d5de47b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 3.15...3.25) # └─ test.c project(gemstone - VERSION 0.1.0 + VERSION 0.2.6 DESCRIPTION "programming language compiler" LANGUAGES C) @@ -44,6 +44,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(LEX_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/lex/lexer.l) set(LEX_GENERATED_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/lex/lexer.ll.c) +file(REMOVE ${LEX_GENERATED_SOURCE_FILE}) + add_custom_command(OUTPUT ${LEX_GENERATED_SOURCE_FILE} COMMAND lex ARGS -o ${LEX_GENERATED_SOURCE_FILE} ${LEX_SOURCE_FILE} @@ -62,6 +64,8 @@ endif() set(YACC_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.y) set(YACC_GENERATED_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.tab.c) +file(REMOVE ${YACC_GENERATED_SOURCE_FILE}) + add_custom_command(OUTPUT ${YACC_GENERATED_SOURCE_FILE} COMMAND bison ARGS -Wno-yacc -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 097546c..69002ea 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -24,8 +24,12 @@ add_library(gscmem ${STDLIB_MEM_SOURCE_FILES}) file(GLOB_RECURSE STDLIB_OS_SOURCE_FILES src/os/*.c) add_library(gscos ${STDLIB_OS_SOURCE_FILES}) +file(GLOB_RECURSE STDLIB_MATH_SOURCE_FILES src/math/*.c) +add_library(gscmath ${STDLIB_MATH_SOURCE_FILES}) + # Complete standard library add_library(gscstd ${STDLIB_IO_SOURCE_FILES} ${STDLIB_MEM_SOURCE_FILES} - ${STDLIB_OS_SOURCE_FILES}) + ${STDLIB_OS_SOURCE_FILES} + ${STDLIB_MATH_SOURCE_FILES}) diff --git a/lib/src/io.gsc b/lib/src/io.gsc index c729644..d57b1f9 100644 --- a/lib/src/io.gsc +++ b/lib/src/io.gsc @@ -14,37 +14,41 @@ include "def.gsc" # which can lead to errors and undefined behavior type ptr: handle +# NULL handle representing an invalid handle on +# all platforms +handle: nullHandle = 0 as handle + # Returns a handle to this processes standard input I/O handle # -- Implementation note # On Linux this will return 0 as is it convention under UNIX (see: https://www.man7.org/linux/man-pages/man3/stdin.3.html) # On Windows the library will call `GetStdHandle(STD_INPUT_HANDLE)` -fun getStdinHandle(out handle: stdin) +fun handle:getStdinHandle() # Returns a handle to this processes standard input I/O handle # -- Implementation note # On Linux this will return 1 as is it convention under UNIX (see: https://www.man7.org/linux/man-pages/man3/stdout.3.html) # On Windows the library will call `GetStdHandle(STD_OUTPUT_HANDLE)` -fun getStdoutHandle(out handle: stdout) +fun handle:getStdoutHandle() # Returns a handle to this processes standard input I/O handle # -- Implementation note # On Linux this will return 1 as is it convention under UNIX (see: https://www.man7.org/linux/man-pages/man3/stderr.3.html) # On Windows the library will call `GetStdHandle(STD_OUTPUT_HANDLE)` -fun getStderrHandle(out handle: stderr) +fun handle:getStderrHandle() # Write `len` number of bytes from `buf` into the I/O resource specified # by `dev`. Returns the number of bytes written. # -- Implementation note # On Linux this will use the syscall write # On Windows this will use the WriteFile function -fun writeBytes(in handle: dev, in ref u8: buf, in u32: len)(out u32: written) +fun u32:writeBytes(in handle: dev, in ref u8: buf, in u32: len) # Read atmost `len` bytes to `buf` from the I/O resource specified by `dev` # Returns the number of read bytes in `written` # -- Implementation note # On Linux this will use the syscall read # On Windows this will use the ReadFile function -fun readBytes(in handle: dev, in ref u8: buf, in u32: len)(out u32: read) +fun u32:readBytes(in handle: dev, in ref u8: buf, in u32: len) # Flushes the buffers of the I/O resource specified by `dev` # -- Implementation note diff --git a/lib/src/io/api.h b/lib/src/io/api.h index c642185..0064b9a 100644 --- a/lib/src/io/api.h +++ b/lib/src/io/api.h @@ -6,15 +6,15 @@ typedef ptr handle; -void getStdinHandle(handle* stdin); +handle getStdinHandle(); -void getStdoutHandle(handle* stdout); +handle getStdoutHandle(); -void getStderrHandle(handle* stderr); +handle getStderrHandle(); -void writeBytes(handle dev, u8* buf, u32 len, u32* written); +u32 writeBytes(handle dev, u8* buf, u32 len); -void readBytes(handle dev, u8* buf, u32 len, u32* read); +u32 readBytes(handle dev, u8* buf, u32 len); void flush(handle dev); diff --git a/lib/src/io/impl.c b/lib/src/io/impl.c index 4de453b..5879375 100644 --- a/lib/src/io/impl.c +++ b/lib/src/io/impl.c @@ -11,24 +11,28 @@ // FIXME: error in case GetStdHandle return INVALID_HANDLE_VALUE // FIXME: error in case functions return 0 -void getStdinHandle(handle* stdin) { - *stdin = (handle) GetStdHandle(STD_INPUT_HANDLE); +handle getStdinHandle(handle* stdin) { + return GetStdHandle(STD_INPUT_HANDLE); } -void getStdoutHandle(handle* stdout) { - *stdout = (handle) GetStdHandle(STD_OUTPUT_HANDLE); +handle getStdoutHandle(handle* stdout) { + return GetStdHandle(STD_OUTPUT_HANDLE); } -void getStderrHandle(handle* stderr) { - *stderr = (handle) GetStdHandle(STD_ERROR_HANDLE); +handle getStderrHandle(handle* stderr) { + return GetStdHandle(STD_ERROR_HANDLE); } -void writeBytes(handle dev, u8* buf, u32 len, u32* bytesWritten) { - WriteFile((HANDLE) dev, buf, len, bytesRead, NULL); +u32 writeBytes(handle dev, u8* buf, u32 len) { + u32 bytesWritten = 0; + WriteFile((HANDLE) dev, buf, len, &bytesWritten, NULL); + return bytesWritten; } -void readBytes(handle dev, u8* buf, u32 len, u32* bytesRead) { - ReadFile((HANDLE) dev, buf, len, bytesRead, NULL); +u32 readBytes(handle dev, u8* buf, u32 len) { + u32 bytesRead = 0; + ReadFile((HANDLE) dev, buf, len, &bytesRead, NULL); + return bytesRead; } void flush(handle dev) { @@ -47,24 +51,24 @@ void flush(handle dev) { // which are stored as 64-bit by zero extending #define TO_INT(x) ((int)(long int)(x)) -void getStdinHandle(handle* stdin) { - *stdin = (handle) STDIN_FILENO; +handle getStdinHandle() { + return (handle) STDIN_FILENO; } -void getStdoutHandle(handle* stdout) { - *stdout = (handle) STDOUT_FILENO; +handle getStdoutHandle() { + return (handle) STDOUT_FILENO; } -void getStderrHandle(handle* stderr) { - *stderr = (handle) STDERR_FILENO; +handle getStderrHandle() { + return (handle) STDERR_FILENO; } -void writeBytes(handle dev, u8* buf, u32 len, u32* bytesWritten) { - *bytesWritten = write(TO_INT(dev), buf, len); +u32 writeBytes(handle dev, u8* buf, u32 len) { + return write(TO_INT(dev), buf, len); } -void readBytes(handle dev, u8* buf, u32 len, u32* bytesRead) { - *bytesRead = read(TO_INT(dev), buf, len); +u32 readBytes(handle dev, u8* buf, u32 len) { + return read(TO_INT(dev), buf, len); } void flush(handle dev) { diff --git a/lib/src/math.gsc b/lib/src/math.gsc new file mode 100644 index 0000000..0af7470 --- /dev/null +++ b/lib/src/math.gsc @@ -0,0 +1,12 @@ +# Author: Sven Vogel +# Edited: 01.08.2024 +# License: GPL-2.0 + +# ,----------------------------------------. +# | Mathematical utilities | +# `----------------------------------------` + +include "def.gsc" + +# Compute the module of a by base b and store the result in c +fun mod(in u32: a, in u32: b)(out u32: c) diff --git a/lib/src/math/api.h b/lib/src/math/api.h new file mode 100644 index 0000000..5bf5ab4 --- /dev/null +++ b/lib/src/math/api.h @@ -0,0 +1,9 @@ + +#ifndef GEMSTONE_STD_LIB_MATH_H_ +#define GEMSTONE_STD_LIB_MATH_H_ + +#include + +void mod(u32 a, u32 b, u32* c); + +#endif //GEMSTONE_STD_LIB_MATH_H_ diff --git a/lib/src/math/impl.c b/lib/src/math/impl.c new file mode 100644 index 0000000..277fd21 --- /dev/null +++ b/lib/src/math/impl.c @@ -0,0 +1,10 @@ +// +// Created by servostar on 01.08.24. +// + +#include +#include + +void mod(u32 a, u32 b, u32* c) { + c[0] = a % b; +} diff --git a/lib/src/mem.gsc b/lib/src/mem.gsc index b9df686..0060323 100644 --- a/lib/src/mem.gsc +++ b/lib/src/mem.gsc @@ -10,14 +10,14 @@ include "def.gsc" # Allocate `len` bytes of heap memory # Returns a pointer to the memory as `ptr` -fun heap_alloc(in u32: len)(out ref u8: ptr) +fun heapAlloc(in u32: len)(out ref u8: ptr) # Rellocate `len` bytes of heap memory # Returns a pointer to the memory as `ptr` -fun heap_realloc(in u32: len, in out ref u8: ptr) +fun heapRealloc(in u32: len, in out ref u8: ptr) # Free a block of memory -fun heap_free(in ref u8: ptr) +fun heapFree(in ref u8: ptr) # Copy `len` bytes from `dst` into `src` fun copy(in ref u8: dst, in ref u8: src, in u32: len) diff --git a/lib/src/mem/api.h b/lib/src/mem/api.h index 8ca69c0..00f1577 100644 --- a/lib/src/mem/api.h +++ b/lib/src/mem/api.h @@ -4,11 +4,11 @@ #include -void heap_alloc(u32 len, u8** ptr); +void heapAlloc(u32 len, u8** ptr); -void heap_realloc(u32 len, u8** ptr); +void heapRealloc(u32 len, u8** ptr); -void heap_free(u8* ptr); +void heapFree(u8* ptr); void copy(u8* dst, u8* src, u32 len); diff --git a/lib/src/mem/impl.c b/lib/src/mem/impl.c index 9d384a8..aad36d0 100644 --- a/lib/src/mem/impl.c +++ b/lib/src/mem/impl.c @@ -8,17 +8,17 @@ #define HEAP_API_GLOBAL_FLAGS HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS -void heap_alloc(u32 len, u8** ptr) { +void heapAlloc(u32 len, u8** ptr) { HANDLE heap = GetProcessHeap(); *ptr = HeapAlloc(heap, HEAP_API_GLOBAL_FLAGS, len); } -void heap_realloc(u32 len, u8** ptr) { +void heapRealloc(u32 len, u8** ptr) { HANDLE heap = GetProcessHeap(); *ptr = HeapReAlloc(heap, HEAP_API_GLOBAL_FLAGS, *ptr, len); } -void heap_free(u8* ptr) { +void heapFree(u8* ptr) { HANDLE heap = GetProcessHeap(); HeapFree(heap, ptr); } @@ -27,15 +27,15 @@ void heap_free(u8* ptr) { #include -void heap_alloc(u32 len, u8** ptr) { +void heapAlloc(u32 len, u8** ptr) { *ptr = malloc(len); } -void heap_realloc(u32 len, u8** ptr) { +void heapRealloc(u32 len, u8** ptr) { *ptr = realloc(*ptr, len); } -void heap_free(u8* ptr) { +void heapFree(u8* ptr) { free(ptr); } diff --git a/lib/src/std.gsc b/lib/src/std.gsc index 36d6a75..89a2e02 100644 --- a/lib/src/std.gsc +++ b/lib/src/std.gsc @@ -14,3 +14,6 @@ include "io.gsc" # memory management include "mem.gsc" + +# mathematical utilities +include "math.gsc" \ No newline at end of file diff --git a/src/ast/ast.c b/src/ast/ast.c index 9f00f56..aa88e1d 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -67,7 +67,10 @@ void AST_init() { lookup_table[AST_Typedef] = "typedef"; lookup_table[AST_Box] = "box"; - lookup_table[AST_Fun] = "fun"; + lookup_table[AST_FunDecl] = "fun"; + lookup_table[AST_FunDef] = "fun"; + lookup_table[AST_ProcDecl] = "fun"; + lookup_table[AST_ProcDef] = "fun"; lookup_table[AST_Call] = "funcall"; lookup_table[AST_Typecast] = "typecast"; @@ -86,6 +89,7 @@ void AST_init() { lookup_table[AST_AddressOf] = "address of"; lookup_table[AST_Dereference] = "deref"; lookup_table[AST_Reference] = "ref"; + lookup_table[AST_Return] = "ret"; } const char* AST_node_to_string(const struct AST_Node_t* node) { @@ -96,6 +100,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node) { switch(node->kind) { case AST_Int: + case AST_Char: case AST_Float: case AST_String: case AST_Ident: diff --git a/src/ast/ast.h b/src/ast/ast.h index a7be0be..256eb96 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -57,7 +57,10 @@ enum AST_SyntaxElement_t { // Defintions AST_Typedef, AST_Box, - AST_Fun, + AST_FunDecl, + AST_FunDef, + AST_ProcDecl, + AST_ProcDef, AST_Import, // amount of variants // in this enums @@ -80,6 +83,8 @@ enum AST_SyntaxElement_t { AST_Dereference, AST_Reference, AST_Include, + AST_Char, + AST_Return, AST_ELEMENT_COUNT }; diff --git a/src/compiler.c b/src/compiler.c index a515009..e8d3462 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -145,21 +145,21 @@ static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) { g_free(path); } -static void run_backend_codegen(const Module* module, const TargetConfig* target) { +static int run_backend_codegen(const Module* module, const TargetConfig* target) { DEBUG("initializing LLVM codegen backend..."); llvm_backend_init(); DEBUG("initiializing backend for codegen..."); BackendError err = init_backend(); if (err.kind != Success) { - return; + return EXIT_FAILURE; } DEBUG("generating code..."); err = generate_code(module, target); if (err.kind != Success) { print_message(Error, "Backend failed: %s", err.impl.message); - return; + return EXIT_FAILURE; } print_message(Info, "Compilation finished successfully"); @@ -167,7 +167,10 @@ static void run_backend_codegen(const Module* module, const TargetConfig* target err = deinit_backend(); if (err.kind != Success) { ERROR("Unable to deinit backend: %s", err.impl.message); + return EXIT_FAILURE; } + + return EXIT_SUCCESS; } const char* get_absolute_import_path(const TargetConfig* config, const char* import_target_name) { @@ -255,21 +258,27 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f * @param unit * @param target */ -static void build_target(ModuleFileStack *unit, const TargetConfig *target) { +static int build_target(ModuleFileStack *unit, const TargetConfig *target) { + int err = EXIT_SUCCESS; + print_message(Info, "Building target: %s", target->name); ModuleFile *file = push_file(unit, target->root_module); AST_NODE_PTR root_module = AST_new_node(empty_location(file), AST_Module, NULL); - if (compile_module_with_dependencies(unit, file, target, root_module) == EXIT_SUCCESS) { + err = compile_module_with_dependencies(unit, file, target, root_module); + if (err == EXIT_SUCCESS) { if (root_module != NULL) { - if (setup_target_environment(target) == 0) { + err = setup_target_environment(target); + if (err == 0) { print_ast_to_file(root_module, target); Module *module = create_set(root_module); if (module != NULL) { - run_backend_codegen(module, target); + err = run_backend_codegen(module, target); + } else { + err = EXIT_FAILURE; } } @@ -282,6 +291,8 @@ static void build_target(ModuleFileStack *unit, const TargetConfig *target) { mem_purge_namespace(MemoryNamespaceSet); print_file_statistics(file); + + return err; } /** @@ -289,7 +300,7 @@ static void build_target(ModuleFileStack *unit, const TargetConfig *target) { * Creates a single target by the given command line arguments. * @param unit */ -static void compile_file(ModuleFileStack *unit) { +static int compile_file(ModuleFileStack *unit) { INFO("compiling basic files..."); TargetConfig *target = default_target_config_from_args(); @@ -297,12 +308,14 @@ static void compile_file(ModuleFileStack *unit) { if (target->root_module == NULL) { print_message(Error, "No input file specified."); delete_target_config(target); - return; + return EXIT_FAILURE; } - build_target(unit, target); + int err = build_target(unit, target); delete_target_config(target); + + return err; } /** @@ -310,7 +323,9 @@ static void compile_file(ModuleFileStack *unit) { * @param unit * @param config */ -static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *config) { +static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *config) { + int err = EXIT_SUCCESS; + if (is_option_set("all")) { // build all targets in the project GHashTableIter iter; @@ -320,9 +335,9 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co char *key; TargetConfig *val; while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) { - build_target(unit, val); + err = build_target(unit, val); } - return; + return err; } // build all targets given in the arguments @@ -333,7 +348,7 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co const char *target_name = g_array_index(targets, const char*, i); if (g_hash_table_contains(config->targets, target_name)) { - build_target(unit, g_hash_table_lookup(config->targets, target_name)); + err = build_target(unit, g_hash_table_lookup(config->targets, target_name)); } else { print_message(Error, "Unknown target: %s", target_name); } @@ -343,39 +358,46 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co } else { print_message(Error, "No targets specified."); } + + return err; } /** * @brief Build targets from project. Configuration is provided by command line arguments. * @param unit File storage */ -static void build_project(ModuleFileStack *unit) { +static int build_project(ModuleFileStack *unit) { ProjectConfig *config = default_project_config(); int err = load_project_config(config); if (err == PROJECT_OK) { - build_project_targets(unit, config); + err = build_project_targets(unit, config); } delete_project_config(config); + return err; } -void run_compiler() { +int run_compiler() { ModuleFileStack files = new_file_stack(); + int status = EXIT_SUCCESS; + if (is_option_set("build")) { - build_project(&files); + status = build_project(&files); } else if (is_option_set("compile")) { - compile_file(&files); + status = compile_file(&files); } else { print_message(Error, "Invalid mode of operation. Rerun with --help."); } if (files.files == NULL) { print_message(Error, "No input files, nothing to do."); - exit(1); + } else { + print_unit_statistics(&files); } - print_unit_statistics(&files); delete_files(&files); + + return status; } diff --git a/src/compiler.h b/src/compiler.h index a82a38f..ceaa34b 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -7,7 +7,8 @@ /** * @brief Run the gemstone compiler with the provided command arguments. + * @return status of compilation */ -void run_compiler(); +int run_compiler(); #endif //GEMSTONE_COMPILER_H diff --git a/src/lex/lexer.l b/src/lex/lexer.l index e955b0e..9902ea4 100644 --- a/src/lex/lexer.l +++ b/src/lex/lexer.l @@ -90,11 +90,19 @@ "funname" {DEBUG("\"%s\" tokenized with \'FunFunname\'", yytext); return(FunFunname);}; "lineno" {DEBUG("\"%s\" tokenized with \'FunLineno\'", yytext); return(FunLineno);}; "extsupport" {DEBUG("\"%s\" tokenized with \'FunExtsupport\'", yytext); return(FunExtsupport);}; +"ret" {DEBUG("\"%s\" tokenized with \'Return\'", yytext); return(KeyReturn);}; [0-9]+ {DEBUG("\"%s\" tokenized with \'ValInt\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(ValInt); }; [0-9]*\.[0-9]+ {DEBUG("\"%s\" tokenized with \'ValFloat\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(ValFloat);}; [a-zA-Z_0-9]+ {DEBUG("\"%s\" tokenized with \'Ident\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(Ident); }; +'.' { + DEBUG("\"%s\" tokenized with \'Char\'", yytext); + yylval.string = mem_strdup(MemoryNamespaceLex, yytext + 1); + long int len = strlen(yytext); + yylval.string[len - 2] = '\0'; + return(ValChar); +} \"([^\"\n])*\" { yytext = yytext +1; yytext[yyleng - 2] = 0; diff --git a/src/llvm/llvm-ir/expr.c b/src/llvm/llvm-ir/expr.c index d3a3c66..eef1cef 100644 --- a/src/llvm/llvm-ir/expr.c +++ b/src/llvm/llvm-ir/expr.c @@ -20,14 +20,14 @@ BackendError impl_bitwise_operation(LLVMBackendCompileUnit *unit, if (operation->impl.bitwise == BitwiseNot) { // single operand rhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); } else { // two operands lhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, lhs, FALSE, &llvm_lhs); + impl_expr(unit, scope, builder, lhs, FALSE, 0, &llvm_lhs); rhs = g_array_index(operation->operands, Expression*, 1); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); } switch (operation->impl.bitwise) { @@ -80,14 +80,14 @@ BackendError impl_logical_operation(LLVMBackendCompileUnit *unit, if (operation->impl.logical == LogicalNot) { // single operand rhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); } else { // two operands lhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, lhs, FALSE, &llvm_lhs); + impl_expr(unit, scope, builder, lhs, FALSE, 0, &llvm_lhs); rhs = g_array_index(operation->operands, Expression*, 1); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); } switch (operation->impl.logical) { @@ -144,10 +144,10 @@ BackendError impl_relational_operation(LLVMBackendCompileUnit *unit, // two operands lhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, lhs, FALSE, &llvm_lhs); + impl_expr(unit, scope, builder, lhs, FALSE, 0, &llvm_lhs); rhs = g_array_index(operation->operands, Expression*, 1); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); if (is_integral(rhs->result)) { // integral type @@ -206,14 +206,14 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit, if (operation->impl.arithmetic == Negate) { // single operand rhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); } else { // two operands lhs = g_array_index(operation->operands, Expression*, 0); - impl_expr(unit, scope, builder, lhs, FALSE, &llvm_lhs); + impl_expr(unit, scope, builder, lhs, FALSE, 0, &llvm_lhs); rhs = g_array_index(operation->operands, Expression*, 1); - impl_expr(unit, scope, builder, rhs, FALSE, &llvm_rhs); + impl_expr(unit, scope, builder, rhs, FALSE, 0, &llvm_rhs); } if (is_integral(rhs->result)) { @@ -297,7 +297,7 @@ BackendError impl_transmute(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMValueRef *llvm_result) { LLVMValueRef operand = NULL; - impl_expr(unit, scope, builder, transmute->operand, FALSE, &operand); + impl_expr(unit, scope, builder, transmute->operand, FALSE, 0, &operand); LLVMTypeRef target_type = NULL; BackendError err = get_type_impl(unit, scope->func_scope->global_scope, @@ -324,9 +324,10 @@ static LLVMBool is_type_signed(const Type *type) { BackendError impl_typecast(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMBuilderRef builder, TypeCast *typecast, + bool reference, LLVMValueRef *llvm_result) { LLVMValueRef operand = NULL; - impl_expr(unit, scope, builder, typecast->operand, FALSE, &operand); + impl_expr(unit, scope, builder, typecast->operand, reference, 0, &operand); LLVMTypeRef target_type = NULL; BackendError err = get_type_impl(unit, scope->func_scope->global_scope, @@ -434,7 +435,7 @@ BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope LLVMBuilderRef builder, AddressOf* addressOf, LLVMValueRef *llvm_result) { - BackendError err = impl_expr(unit, scope, builder, addressOf->variable, FALSE, llvm_result); + BackendError err = impl_expr(unit, scope, builder, addressOf->variable, TRUE, 0, llvm_result); if (err.kind != Success) { return err; @@ -445,11 +446,13 @@ BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMBuilderRef builder, Dereference* dereference, + bool reference, + uint32_t deref_depth, LLVMValueRef *llvm_result) { BackendError err; LLVMValueRef llvm_pointer = NULL; - err = impl_expr(unit, scope, builder, dereference->variable, TRUE, &llvm_pointer); + err = impl_expr(unit, scope, builder, dereference->variable, false, deref_depth + 1, &llvm_pointer); if (err.kind != Success) { return err; } @@ -461,14 +464,16 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, } LLVMValueRef* index = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef)); - err = impl_expr(unit, scope, builder, dereference->index, FALSE, index); + err = impl_expr(unit, scope, builder, dereference->index, FALSE, deref_depth + 1, index); if (err.kind != Success) { return err; } *llvm_result = LLVMBuildGEP2(builder, llvm_deref_type, llvm_pointer, index, 1, "expr.deref.gep2"); - *llvm_result = LLVMBuildLoad2(builder, llvm_deref_type, *llvm_result, "expr.deref.load"); + if (!reference || deref_depth > 0) { + *llvm_result = LLVMBuildLoad2(builder, llvm_deref_type, *llvm_result, "expr.deref.load"); + } return err; } @@ -476,6 +481,7 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMBuilderRef builder, Expression *expr, LLVMBool reference, + uint32_t deref_depth, LLVMValueRef *llvm_result) { DEBUG("implementing expression: %ld", expr->kind); BackendError err = SUCCESS; @@ -491,6 +497,7 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, break; case ExpressionKindTypeCast: err = impl_typecast(unit, scope, builder, &expr->impl.typecast, + reference, llvm_result); break; case ExpressionKindOperation: @@ -513,8 +520,13 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, break; case ExpressionKindDereference: err = impl_deref(unit, scope, builder, &expr->impl.dereference, + reference, + deref_depth, llvm_result); break; + case ExpressionKindFunctionCall: + err = impl_func_call(unit, builder, scope, expr->impl.call, llvm_result); + break; default: err = new_backend_impl_error(Implementation, NULL, "unknown expression"); break; diff --git a/src/llvm/llvm-ir/expr.h b/src/llvm/llvm-ir/expr.h index 354fa16..7df2d39 100644 --- a/src/llvm/llvm-ir/expr.h +++ b/src/llvm/llvm-ir/expr.h @@ -13,6 +13,7 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMBuilderRef builder, Expression *expr, LLVMBool reference, + uint32_t deref_depth, LLVMValueRef *llvm_result); #endif // LLVM_BACKEND_EXPR_H diff --git a/src/llvm/llvm-ir/func.c b/src/llvm/llvm-ir/func.c index 032aa3b..09eb2b5 100644 --- a/src/llvm/llvm-ir/func.c +++ b/src/llvm/llvm-ir/func.c @@ -10,6 +10,7 @@ #include #include #include +#include LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) { LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope)); @@ -127,8 +128,19 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit, DEBUG("implemented %ld parameter", llvm_params->len); + LLVMTypeRef llvm_return_type = LLVMVoidTypeInContext(unit->context); + if (func->kind == FunctionDeclarationKind) { + if (func->impl.declaration.return_value != NULL) { + err = get_type_impl(unit, scope, func->impl.declaration.return_value, &llvm_return_type); + } + } else { + if (func->impl.definition.return_value != NULL) { + err = get_type_impl(unit, scope, func->impl.definition.return_value, &llvm_return_type); + } + } + LLVMTypeRef llvm_fun_type = - LLVMFunctionType(LLVMVoidTypeInContext(unit->context), + LLVMFunctionType(llvm_return_type, (LLVMTypeRef*)llvm_params->data, llvm_params->len, 0); *llvm_fun = LLVMAddFunction(unit->module, func->name, llvm_fun_type); @@ -180,14 +192,39 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit, LLVMPositionBuilderAtEnd(builder, entry); LLVMBuildBr(builder, llvm_start_body_block); - // insert returning end block - LLVMBasicBlockRef end_block = - LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.end"); - LLVMPositionBuilderAtEnd(builder, end_block); - LLVMBuildRetVoid(builder); + LLVMValueRef terminator = LLVMGetBasicBlockTerminator(llvm_end_body_block); + if (terminator == NULL) { + // insert returning end block + LLVMBasicBlockRef end_block = + LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.end"); + LLVMPositionBuilderAtEnd(builder, end_block); - LLVMPositionBuilderAtEnd(builder, llvm_end_body_block); - LLVMBuildBr(builder, end_block); + LLVMValueRef llvm_return = NULL; + if (func->kind == FunctionDeclarationKind) { + if (func->impl.declaration.return_value != NULL) { + err = get_type_default_value(unit, global_scope, func->impl.declaration.return_value, &llvm_return); + if (err.kind != Success) { + return err; + } + LLVMBuildRet(builder, llvm_return); + }else { + LLVMBuildRetVoid(builder); + } + } else { + if (func->impl.definition.return_value != NULL) { + err = get_type_default_value(unit, global_scope, func->impl.definition.return_value, &llvm_return); + if (err.kind != Success) { + return err; + } + LLVMBuildRet(builder, llvm_return); + } else { + LLVMBuildRetVoid(builder); + } + } + + LLVMPositionBuilderAtEnd(builder, llvm_end_body_block); + LLVMBuildBr(builder, end_block); + } LLVMDisposeBuilder(builder); } @@ -247,3 +284,83 @@ BackendError impl_functions(LLVMBackendCompileUnit* unit, return err; } + +gboolean is_parameter_out(Parameter *param) { + gboolean is_out = FALSE; + + if (param->kind == ParameterDeclarationKind) { + is_out = param->impl.declaration.qualifier == Out || param->impl.declaration.qualifier == InOut; + } else { + is_out = param->impl.definiton.declaration.qualifier == Out || + param->impl.definiton.declaration.qualifier == InOut; + } + + return is_out; +} + +BackendError impl_func_call(LLVMBackendCompileUnit *unit, + LLVMBuilderRef builder, LLVMLocalScope *scope, + const FunctionCall *call, + LLVMValueRef* return_value) { + DEBUG("implementing function call..."); + BackendError err = SUCCESS; + + LLVMValueRef* arguments = NULL; + + // prevent memory allocation when number of bytes would be zero + // avoid going of assertion in memory cache + if (call->expressions->len > 0) { + arguments = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef) * call->expressions->len); + + for (size_t i = 0; i < call->expressions->len; i++) { + Expression *arg = g_array_index(call->expressions, Expression*, i); + + GArray* param_list; + if (call->function->kind == FunctionDeclarationKind) { + param_list = call->function->impl.definition.parameter; + } else { + param_list = call->function->impl.declaration.parameter; + } + + Parameter param = g_array_index(param_list, Parameter, i); + + LLVMValueRef llvm_arg = NULL; + err = impl_expr(unit, scope, builder, arg, is_parameter_out(¶m), 0, &llvm_arg); + + if (err.kind != Success) { + break; + } + + if (is_parameter_out(¶m)) { + if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) { + LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false); + LLVMTypeRef llvm_type = NULL; + get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type); + llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, ""); + } + } + + arguments[i] = llvm_arg; + } + } + + if (err.kind == Success) { + LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, call->function->name); + + if (llvm_func == NULL) { + return new_backend_impl_error(Implementation, NULL, "no declared function"); + } + + LLVMTypeRef llvm_func_type = g_hash_table_lookup(scope->func_scope->global_scope->functions, call->function->name); + + LLVMValueRef value = LLVMBuildCall2(builder, llvm_func_type, llvm_func, arguments, call->expressions->len, + ""); + + if (NULL != return_value) { + *return_value = value; + } + } + + return err; +} + diff --git a/src/llvm/llvm-ir/func.h b/src/llvm/llvm-ir/func.h index 349135a..a3f47ac 100644 --- a/src/llvm/llvm-ir/func.h +++ b/src/llvm/llvm-ir/func.h @@ -40,4 +40,9 @@ BackendError impl_functions(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, GHashTable* variables); +BackendError impl_func_call(LLVMBackendCompileUnit *unit, + LLVMBuilderRef builder, LLVMLocalScope *scope, + const FunctionCall *call, + LLVMValueRef* return_value); + #endif // LLVM_BACKEND_FUNC_H_ diff --git a/src/llvm/llvm-ir/stmt.c b/src/llvm/llvm-ir/stmt.c index 9f20c20..b8cf81f 100644 --- a/src/llvm/llvm-ir/stmt.c +++ b/src/llvm/llvm-ir/stmt.c @@ -55,7 +55,7 @@ BackendError impl_storage_expr( case StorageExprKindDereference: LLVMValueRef index = NULL; - err = impl_expr(unit, scope, builder, expr->impl.dereference.index, false, &index); + err = impl_expr(unit, scope, builder, expr->impl.dereference.index, false, 0, &index); if (err.kind != Success) { return err; } @@ -73,7 +73,7 @@ BackendError impl_storage_expr( } } - if (expr->impl.dereference.array->kind == StorageExprKindDereference) { + if (true) { LLVMTypeRef deref_type = NULL; err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type); if (err.kind != Success) { @@ -111,7 +111,7 @@ BackendError impl_assign_stmt( DEBUG("implementing assignment for variable: %p", assignment); LLVMValueRef llvm_value = NULL; - err = impl_expr(unit, scope, builder, assignment->value, false, &llvm_value); + err = impl_expr(unit, scope, builder, assignment->value, false, 0, &llvm_value); if (err.kind != Success) { return err; } @@ -141,6 +141,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit, LLVMBasicBlockRef end_previous_block = *llvm_start_block; + bool terminated = false; + for (size_t i = 0; i < block->statemnts->len; i++) { DEBUG("building block statement %d of %d", i, block->statemnts->len); Statement* stmt = g_array_index(block->statemnts, Statement*, i); @@ -152,12 +154,20 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit, return err; } - if (llvm_next_end_block != NULL) { + terminated = LLVMGetBasicBlockTerminator(end_previous_block); + if (llvm_next_end_block != NULL && !terminated) { LLVMPositionBuilderAtEnd(builder, end_previous_block); LLVMBuildBr(builder, llvm_next_start_block); + LLVMPositionBuilderAtEnd(builder, llvm_next_end_block); end_previous_block = llvm_next_end_block; } + + if (terminated) { + end_previous_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, + "ret.after"); + LLVMPositionBuilderAtEnd(builder, end_previous_block); + } } *llvm_end_block = end_previous_block; @@ -182,7 +192,7 @@ BackendError impl_while(LLVMBackendCompileUnit *unit, LLVMPositionBuilderAtEnd(builder, while_cond_block); // Resolve condition in block to a variable LLVMValueRef cond_result = NULL; - err = impl_expr(unit, scope, builder, (Expression *) while_stmt->conditon, FALSE, &cond_result); + err = impl_expr(unit, scope, builder, (Expression *) while_stmt->conditon, FALSE, 0, &cond_result); if (err.kind != Success) { return err; } @@ -213,74 +223,6 @@ BackendError impl_while(LLVMBackendCompileUnit *unit, return err; } -gboolean is_parameter_out(Parameter *param) { - gboolean is_out = FALSE; - - if (param->kind == ParameterDeclarationKind) { - is_out = param->impl.declaration.qualifier == Out || param->impl.declaration.qualifier == InOut; - } else { - is_out = param->impl.definiton.declaration.qualifier == Out || - param->impl.definiton.declaration.qualifier == InOut; - } - - return is_out; -} - -BackendError impl_func_call(LLVMBackendCompileUnit *unit, - LLVMBuilderRef builder, LLVMLocalScope *scope, - const FunctionCall *call) { - DEBUG("implementing function call..."); - BackendError err = SUCCESS; - - LLVMValueRef* arguments = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef) * call->expressions->len); - - for (size_t i = 0; i < call->expressions->len; i++) { - Expression *arg = g_array_index(call->expressions, Expression*, i); - - GArray* param_list; - if (call->function->kind == FunctionDeclarationKind) { - param_list = call->function->impl.definition.parameter; - } else { - param_list = call->function->impl.declaration.parameter; - } - - Parameter param = g_array_index(param_list, Parameter, i); - - LLVMValueRef llvm_arg = NULL; - err = impl_expr(unit, scope, builder, arg, is_parameter_out(¶m), &llvm_arg); - - if (err.kind != Success) { - break; - } - - if (is_parameter_out(¶m)) { - if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) { - LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false); - LLVMTypeRef llvm_type = NULL; - get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type); - llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, ""); - } - } - - arguments[i] = llvm_arg; - } - - if (err.kind == Success) { - LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, call->function->name); - - if (llvm_func == NULL) { - return new_backend_impl_error(Implementation, NULL, "no declared function"); - } - - LLVMTypeRef llvm_func_type = g_hash_table_lookup(scope->func_scope->global_scope->functions, call->function->name); - - LLVMBuildCall2(builder, llvm_func_type, llvm_func, arguments, call->expressions->len, - ""); - } - - return err; -} - BackendError impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Expression *cond, const Block *block, LLVMBasicBlockRef *cond_block, LLVMBasicBlockRef *start_body_block, LLVMBasicBlockRef *end_body_block, @@ -291,7 +233,7 @@ impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalS "stmt.branch.cond"); LLVMPositionBuilderAtEnd(builder, *cond_block); // Resolve condition in block to a variable - err = impl_expr(unit, scope, builder, cond, FALSE, llvm_cond); + err = impl_expr(unit, scope, builder, cond, FALSE, 0, llvm_cond); if (err.kind == Success) { // build body of loop err = impl_basic_block(unit, builder, scope, block, start_body_block, end_body_block); @@ -426,6 +368,23 @@ BackendError impl_decl(LLVMBackendCompileUnit *unit, return err; } +BackendError impl_return(LLVMBackendCompileUnit *unit, + LLVMBuilderRef builder, + LLVMLocalScope *scope, + Return *returnStmt) { + BackendError err = SUCCESS; + + LLVMValueRef expr = NULL; + err = impl_expr(unit, scope, builder, returnStmt->value, false, 0, &expr); + if (err.kind != Success) { + return err; + } + + LLVMBuildRet(builder, expr); + + return err; +} + BackendError impl_def(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, @@ -441,7 +400,7 @@ BackendError impl_def(LLVMBackendCompileUnit *unit, } LLVMValueRef initial_value = NULL; - err = impl_expr(unit, scope, builder, def->initializer, FALSE, &initial_value); + err = impl_expr(unit, scope, builder, def->initializer, FALSE, 0, &initial_value); if (err.kind != Success) { return err; } @@ -496,7 +455,10 @@ BackendError impl_stmt(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLV err = impl_while(unit, builder, scope, llvm_start_block, llvm_end_block, &stmt->impl.whileLoop); break; case StatementKindFunctionCall: - err = impl_func_call(unit, builder, scope, &stmt->impl.call); + err = impl_func_call(unit, builder, scope, &stmt->impl.call, NULL); + break; + case StatementKindReturn: + err = impl_return(unit, builder, scope, &stmt->impl.returnStmt); break; default: err = new_backend_impl_error(Implementation, NULL, "Unexpected statement kind"); diff --git a/src/llvm/llvm-ir/types.c b/src/llvm/llvm-ir/types.c index c64ed6e..1d0005e 100644 --- a/src/llvm/llvm-ir/types.c +++ b/src/llvm/llvm-ir/types.c @@ -6,16 +6,11 @@ #include #include #include -#include #include #define BASE_BYTES 4 #define BITS_PER_BYTE 8 -char* guid() { - return "uuid"; -} - static BackendError get_const_primitive_value(PrimitiveType primitive, LLVMTypeRef llvm_type, const char* value, @@ -27,6 +22,10 @@ static BackendError get_const_primitive_value(PrimitiveType primitive, case Float: *llvm_value = LLVMConstRealOfString(llvm_type, value); break; + case Char: + gunichar codepoint = g_utf8_get_char(value); + *llvm_value = LLVMConstInt(llvm_type, codepoint, false); + break; } return SUCCESS; @@ -42,7 +41,7 @@ static BackendError get_const_composite_value(CompositeType composite, BackendError impl_reference_const(LLVMBackendCompileUnit* unit, TypeValue* value, LLVMValueRef* llvm_value) { BackendError err = SUCCESS; - if (value->type->kind == TypeKindReference && compareTypes(value->type, (Type*) &StringLiteralType)) { + if (compareTypes(value->type, (Type*) &StringLiteralType)) { // is string literal LLVMValueRef string_value = LLVMConstString(value->value, strlen(value->value), false); @@ -55,7 +54,11 @@ BackendError impl_reference_const(LLVMBackendCompileUnit* unit, TypeValue* value LLVMSetUnnamedAddress(string_global, LLVMGlobalUnnamedAddr); LLVMSetAlignment(string_global, 1); - *llvm_value = string_global; + // Cast the global variable to a pointer type if needed + LLVMTypeRef i8_ptr_type = LLVMPointerType(LLVMInt8TypeInContext(unit->context), 0); + LLVMValueRef global_str_ptr = LLVMConstBitCast(string_global, i8_ptr_type); + + *llvm_value = global_str_ptr; } else { err = new_backend_impl_error(Implementation, value->nodePtr, "reference initializer can only be string literals"); } @@ -112,9 +115,12 @@ BackendError impl_primtive_type(LLVMBackendCompileUnit* unit, DEBUG("implementing primtive float type..."); *llvm_type = LLVMFloatTypeInContext(unit->context); break; + case Char: + DEBUG("implementing primitive codepoint type..."); + *llvm_type = LLVMInt32TypeInContext(unit->context); + break; default: PANIC("invalid primitive type"); - break; } return SUCCESS; diff --git a/src/llvm/llvm-ir/variables.c b/src/llvm/llvm-ir/variables.c index f5bac19..2765fed 100644 --- a/src/llvm/llvm-ir/variables.c +++ b/src/llvm/llvm-ir/variables.c @@ -1,11 +1,13 @@ #include -#include -#include -#include #include #include #include +#include +#include +#include + +#include "expr.h" BackendError impl_global_declaration(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, @@ -54,8 +56,7 @@ BackendError impl_global_definiton(LLVMBackendCompileUnit* unit, // FIXME: resolve initializer expression! LLVMValueRef initial_value = NULL; - err = get_type_default_value(unit, scope, def->declaration.type, - &initial_value); + err = get_const_type_value(unit, scope, &def->initializer->impl.constant, &initial_value); if (err.kind == Success) { DEBUG("setting default value"); diff --git a/src/main.c b/src/main.c index 0367f8b..5c457ef 100644 --- a/src/main.c +++ b/src/main.c @@ -74,11 +74,11 @@ int main(int argc, char *argv[]) { exit(0); } - run_compiler(); + int status = run_compiler(); if (is_option_set("print-gc-stats")) { print_memory_statistics(); } - return 0; + return status; } diff --git a/src/set/set.c b/src/set/set.c index 0d41b2e..9c16aa2 100644 --- a/src/set/set.c +++ b/src/set/set.c @@ -302,7 +302,7 @@ int set_get_type_impl(AST_NODE_PTR currentNode, Type **type) { } print_diagnostic(&AST_get_last_node(currentNode)->location, Error, - "Expected either primitive or composite type"); + "Expected either primitive or composite type: `%s`", AST_get_last_node(currentNode)->value); return SEMANTIC_ERROR; } @@ -332,14 +332,14 @@ int addVarToScope(Variable *variable); int createRef(AST_NODE_PTR currentNode, Type **reftype) { assert(currentNode != NULL); assert(currentNode->children->len == 1); - assert(AST_get_node(currentNode, 0)->kind == AST_Type); Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); referenceType->kind = TypeKindReference; referenceType->nodePtr = currentNode; - int signal = set_get_type_impl(AST_get_node(currentNode, 0), &type); + AST_NODE_PTR ast_type = AST_get_node(currentNode, 0); + int signal = set_get_type_impl(ast_type, &type); if (signal) { return SEMANTIC_ERROR; } @@ -496,8 +496,10 @@ char *type_to_string(Type *type) { case TypeKindPrimitive: if (type->impl.primitive == Int) { string = mem_strdup(MemoryNamespaceSet, "int"); - } else { + } else if (type->impl.primitive == Float){ string = mem_strdup(MemoryNamespaceSet, "float"); + } else if (type->impl.primitive == Char){ + string = mem_strdup(MemoryNamespaceSet, "codepoint"); } break; case TypeKindComposite: { @@ -637,6 +639,14 @@ TypeValue createTypeValue(AST_NODE_PTR currentNode) { case AST_Float: type->impl.primitive = Float; break; + case AST_Char: + // validate we have a single UTF-8 codepoint + if (g_utf8_strlen(currentNode->value, 4) != 1) { + print_diagnostic(¤tNode->location, Error, "Character must be UTF-8 codepoint"); + } + + type->impl.primitive = Char; + break; default: PANIC("Node is not an expression but from kind: %i", currentNode->kind); break; @@ -1331,13 +1341,13 @@ int createTypeCast(Expression *ParentExpression, AST_NODE_PTR currentNode) { && ParentExpression->impl.typecast.operand->result->kind != TypeKindPrimitive && ParentExpression->impl.typecast.operand->result->kind != TypeKindReference) { + print_diagnostic(¤tNode->location, Error, "cannot cast type: `%s`", type_to_string(ParentExpression->impl.typecast.operand->result)); return SEMANTIC_ERROR; } Type *target = mem_alloc(MemoryNamespaceSet, sizeof(Type)); int status = set_get_type_impl(AST_get_node(currentNode, 1), &target); if (status) { - print_diagnostic(&AST_get_node(currentNode, 1)->location, Error, "Unknown type"); return SEMANTIC_ERROR; } ParentExpression->impl.typecast.targetType = target; @@ -1453,6 +1463,8 @@ IO_Qualifier getParameterQualifier(Parameter *parameter) { } } +int createfuncall(FunctionCall* funcall, AST_NODE_PTR currentNode); + Expression *createExpression(AST_NODE_PTR currentNode) { DEBUG("create Expression"); Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); @@ -1461,6 +1473,7 @@ Expression *createExpression(AST_NODE_PTR currentNode) { switch (currentNode->kind) { case AST_Int: case AST_Float: + case AST_Char: expression->kind = ExpressionKindConstant; expression->impl.constant = createTypeValue(currentNode); expression->result = expression->impl.constant.type; @@ -1584,6 +1597,14 @@ Expression *createExpression(AST_NODE_PTR currentNode) { return NULL; } break; + case AST_Call: + expression->kind = ExpressionKindFunctionCall; + expression->impl.call = mem_alloc(MemoryNamespaceSet, sizeof(FunctionCall)); + if (createfuncall(expression->impl.call, currentNode) == SEMANTIC_ERROR) { + return NULL; + } + expression->result = SET_function_get_return_type(expression->impl.call->function); + break; default: PANIC("Node is not an expression but from kind: %i", currentNode->kind); break; @@ -1595,35 +1616,48 @@ Expression *createExpression(AST_NODE_PTR currentNode) { } bool compareTypes(Type *leftType, Type *rightType) { - if (leftType->kind != rightType->kind) { - return FALSE; - } - if (leftType->kind == TypeKindPrimitive) { + if (leftType->kind == TypeKindPrimitive && rightType->kind == TypeKindPrimitive) { return leftType->impl.primitive == rightType->impl.primitive; } + if (leftType->kind == TypeKindComposite) { - CompositeType leftComposite = leftType->impl.composite; - CompositeType rightComposite = leftType->impl.composite; - if (leftComposite.primitive != rightComposite.primitive) { + if (rightType->kind == TypeKindPrimitive) { + CompositeType leftComposite = leftType->impl.composite; + + if (leftComposite.scale == 1 && leftComposite.sign == Signed) { + return leftComposite.primitive == rightType->impl.primitive; + } + return FALSE; + + } else if (rightType->kind == TypeKindComposite) { + // Compare composites + + CompositeType leftComposite = leftType->impl.composite; + CompositeType rightComposite = rightType->impl.composite; + if (leftComposite.primitive != rightComposite.primitive) { + return FALSE; + } + if (leftComposite.sign != rightComposite.sign) { + return FALSE; + } + if (leftComposite.scale != rightComposite.scale) { + return FALSE; + } + return TRUE; } - if (leftComposite.sign != rightComposite.sign) { - return FALSE; - } - if (leftComposite.scale != rightComposite.scale) { - return FALSE; - } - return TRUE; + + return FALSE; } - if (leftType->kind == TypeKindBox) { + if (leftType->kind == TypeKindBox && rightType->kind == TypeKindBox) { if (leftType->impl.box != rightType->impl.box) { return FALSE; } return TRUE; } - if (leftType->kind == TypeKindReference) { + if (leftType->kind == TypeKindReference && rightType->kind == TypeKindReference) { bool result = compareTypes(leftType->impl.reference, rightType->impl.reference); return result; } @@ -1869,19 +1903,26 @@ int createBranch(Statement *ParentStatement, AST_NODE_PTR currentNode) { int getFunction(const char *name, Function **function); -int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) { +Parameter get_param_from_func(Function* func, size_t index) { + if (func->kind == FunctionDeclarationKind) { + return g_array_index(func->impl.declaration.parameter, Parameter, index); + } else { + return g_array_index(func->impl.definition.parameter, Parameter, index); + } +} + +int createfuncall(FunctionCall* funcall, AST_NODE_PTR currentNode) { assert(currentNode != NULL); assert(currentNode->children->len == 2); AST_NODE_PTR argsListNode = AST_get_node(currentNode, 1); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); - FunctionCall funcall; Function *fun = NULL; if (nameNode->kind == AST_Ident) { int result = getFunction(nameNode->value, &fun); if (result == SEMANTIC_ERROR) { - print_diagnostic(¤tNode->location, Error, "Unknown function: `%s`", nameNode); + print_diagnostic(¤tNode->location, Error, "Unknown function: `%s`", nameNode->value); return SEMANTIC_ERROR; } } @@ -1902,8 +1943,8 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) { } } - funcall.function = fun; - funcall.nodePtr = currentNode; + funcall->function = fun; + funcall->nodePtr = currentNode; size_t paramCount = 0; if (fun->kind == FunctionDeclarationKind) { @@ -1935,13 +1976,20 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) { return SEMANTIC_ERROR; } + Parameter param = get_param_from_func(fun, i + currentExprList->children->len - j - 1); + + if (!compareTypes(expr->result, param.impl.declaration.type)) { + print_diagnostic(&expr_node->location, Error, + "parameter and argument `%s` type mismatch, expected `%s` got `%s`", + param.name, type_to_string(param.impl.declaration.type), type_to_string(expr->result)); + + return SEMANTIC_ERROR; + } + g_array_append_val(expressions, expr); } } - funcall.expressions = expressions; - - parentStatement->kind = StatementKindFunctionCall; - parentStatement->impl.call = funcall; + funcall->expressions = expressions; return SEMANTIC_OK; } @@ -2017,18 +2065,37 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) { g_array_append_val(Parentblock->statemnts, statement); } break; - case AST_Call: + case AST_Call: { Statement *statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindFunctionCall; - int result = createfuncall(statement, currentNode); + int result = createfuncall(&statement->impl.call, currentNode); if (result == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_append_val(Parentblock->statemnts, statement); break; + } + case AST_Return: { + Statement *statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); + statement->nodePtr = currentNode; + statement->kind = StatementKindReturn; + + AST_NODE_PTR expr_node = AST_get_node(currentNode, 0); + statement->impl.returnStmt.value = createExpression(expr_node); + statement->impl.returnStmt.nodePtr = currentNode; + + if (statement->impl.returnStmt.value == NULL) { + return SEMANTIC_ERROR; + } + + // TODO: compare result and function return type + + g_array_append_val(Parentblock->statemnts, statement); + break; + } default: - PANIC("Node is not a statement"); + PANIC("Node is not a statement: %s", AST_node_to_string(currentNode)); break; } @@ -2087,8 +2154,9 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) { int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) { DEBUG("start fundef"); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); - AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); - AST_NODE_PTR statementlist = AST_get_node(currentNode, 2); + AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1); + AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2); + AST_NODE_PTR statementlist = AST_get_node(currentNode, 3); FunctionDefinition fundef; @@ -2096,6 +2164,12 @@ int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) { fundef.name = nameNode->value; fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); + fundef.return_value = NULL; + + if (set_get_type_impl(return_value_node, &fundef.return_value) == SEMANTIC_ERROR) { + print_diagnostic(&return_value_node->location, Error, "Unknown return value type"); + return SEMANTIC_ERROR; + } DEBUG("paramlistlist child count: %i", paramlistlist->children->len); for (size_t i = 0; i < paramlistlist->children->len; i++) { @@ -2195,7 +2269,49 @@ int getFunction(const char *name, Function **function) { return SEMANTIC_ERROR; } -int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) { +int createProcDef(Function *Parentfunction, AST_NODE_PTR currentNode) { + DEBUG("start fundef"); + AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); + AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); + AST_NODE_PTR statementlist = AST_get_node(currentNode, 2); + + FunctionDefinition fundef; + + fundef.nodePtr = currentNode; + fundef.name = nameNode->value; + fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); + fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); + fundef.return_value = NULL; + + DEBUG("paramlistlist child count: %i", paramlistlist->children->len); + for (size_t i = 0; i < paramlistlist->children->len; i++) { + + //all parameterlists + AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i); + DEBUG("paramlist child count: %i", paramlist->children->len); + for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) { + + DEBUG("param child count: %i", AST_get_node(paramlist, j)->children->len); + + if (createParam(fundef.parameter, AST_get_node(paramlist, j))) { + return SEMANTIC_ERROR; + } + } + DEBUG("End of Paramlist"); + } + + if (fillBlock(fundef.body, statementlist)) { + return SEMANTIC_ERROR; + } + + Parentfunction->nodePtr = currentNode; + Parentfunction->kind = FunctionDefinitionKind; + Parentfunction->impl.definition = fundef; + Parentfunction->name = fundef.name; + return SEMANTIC_OK; +} + +int createProcDecl(Function *Parentfunction, AST_NODE_PTR currentNode) { DEBUG("start fundecl"); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); @@ -2205,6 +2321,46 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) { fundecl.nodePtr = currentNode; fundecl.name = nameNode->value; fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); + fundecl.return_value = NULL; + + for (size_t i = 0; i < paramlistlist->children->len; i++) { + + //all parameter lists + AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i); + + for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) { + AST_NODE_PTR param = AST_get_node(paramlist, j); + if (createParam(fundecl.parameter, param)) { + return SEMANTIC_ERROR; + } + } + } + + Parentfunction->nodePtr = currentNode; + Parentfunction->kind = FunctionDeclarationKind; + Parentfunction->impl.declaration = fundecl; + Parentfunction->name = fundecl.name; + + return SEMANTIC_OK; +} + +int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) { + DEBUG("start fundecl"); + AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); + AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1); + AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2); + + FunctionDeclaration fundecl; + + fundecl.nodePtr = currentNode; + fundecl.name = nameNode->value; + fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); + fundecl.return_value = NULL; + + if (set_get_type_impl(return_value_node, &fundecl.return_value) == SEMANTIC_ERROR) { + print_diagnostic(&return_value_node->location, Error, "Unknown return value type"); + return SEMANTIC_ERROR; + } for (size_t i = 0; i < paramlistlist->children->len; i++) { @@ -2228,21 +2384,32 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) { } int createFunction(Function *function, AST_NODE_PTR currentNode) { - assert(currentNode->kind == AST_Fun); functionParameter = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); - if (currentNode->children->len == 2) { - int signal = createFunDecl(function, currentNode); - if (signal) { + switch (currentNode->kind) { + case AST_FunDecl: + if (createFunDecl(function, currentNode)) { + return SEMANTIC_ERROR; + } + break; + case AST_FunDef: + if (createFunDef(function, currentNode)) { + return SEMANTIC_ERROR; + } + break; + case AST_ProcDecl: + if (createProcDecl(function, currentNode)) { + return SEMANTIC_ERROR; + } + break; + case AST_ProcDef: + if (createProcDef(function, currentNode)) { + return SEMANTIC_ERROR; + } + break; + default: + ERROR("invalid AST node type: %s", AST_node_to_string(currentNode)); return SEMANTIC_ERROR; - } - } else if (currentNode->children->len == 3) { - int signal = createFunDef(function, currentNode); - if (signal) { - return SEMANTIC_ERROR; - } - } else { - PANIC("function should have 2 or 3 children"); } mem_free(functionParameter); @@ -2358,7 +2525,7 @@ int createBox(GHashTable *boxes, AST_NODE_PTR currentNode) { return SEMANTIC_ERROR; } break; - case AST_Fun: { + case AST_FunDef: { int result = createBoxFunction(boxName, boxType, AST_get_node(boxMemberList, i)); if (result == SEMANTIC_ERROR) { return SEMANTIC_ERROR; @@ -2481,7 +2648,10 @@ Module *create_set(AST_NODE_PTR currentNode) { DEBUG("created Box successfully"); break; } - case AST_Fun: { + case AST_FunDef: + case AST_FunDecl: + case AST_ProcDef: + case AST_ProcDecl: { DEBUG("start function"); Function *function = mem_alloc(MemoryNamespaceSet, sizeof(Function)); diff --git a/src/set/types.c b/src/set/types.c new file mode 100644 index 0000000..50dbe3e --- /dev/null +++ b/src/set/types.c @@ -0,0 +1,30 @@ +// +// Created by servostar on 8/4/24. +// + +#include +#include +#include + +Type* SET_function_get_return_type(Function* function) { + assert(NULL != function); + + Type* return_type = NULL; + + switch (function->kind) { + case FunctionDeclarationKind: + return_type = function->impl.declaration.return_value; + break; + case FunctionDefinitionKind: + return_type = function->impl.definition.return_value; + break; + default: + PANIC("invalid function kind: %d", function->kind); + } + + if (NULL == return_type) { + ERROR("Function return type is nullptr"); + } + + return return_type; +} diff --git a/src/set/types.h b/src/set/types.h index 828f14e..d4f2169 100644 --- a/src/set/types.h +++ b/src/set/types.h @@ -16,7 +16,9 @@ typedef enum PrimitiveType_t { // 4 byte signed integer in two's complement Int =0, // 4 byte IEEE-754 single precision - Float =1 + Float =1, + // 4 byte encoded UTF-8 codepoint + Char = 2, } PrimitiveType; /** @@ -211,6 +213,7 @@ typedef struct FunctionDefinition_t { // hashtable of parameters // associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) GArray* parameter; // Parameter + Type* return_value; AST_NODE_PTR nodePtr; // body of function Block *body; @@ -223,6 +226,7 @@ typedef struct FunctionDeclaration_t { // associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) GArray* parameter; // Parameter AST_NODE_PTR nodePtr; + Type* return_value; const char* name; } FunctionDeclaration; @@ -236,6 +240,8 @@ typedef struct Function_t { const char * name; } Function; +Parameter get_param_from_func(Function* func, size_t index); + // .------------------------------------------------. // | Variables | // '------------------------------------------------' @@ -435,8 +441,11 @@ typedef enum ExpressionKind_t { ExpressionKindParameter, ExpressionKindDereference, ExpressionKindAddressOf, + ExpressionKindFunctionCall, } ExpressionKind; +typedef struct FunctionCall_t FunctionCall; + typedef struct Expression_t { ExpressionKind kind; // type of resulting data @@ -450,6 +459,7 @@ typedef struct Expression_t { Parameter* parameter; Dereference dereference; AddressOf addressOf; + FunctionCall* call; } impl; AST_NODE_PTR nodePtr; } Expression; @@ -550,6 +560,11 @@ typedef struct Assignment_t { AST_NODE_PTR nodePtr; } Assignment; +typedef struct Return_t { + Expression* value; + AST_NODE_PTR nodePtr; +} Return; + typedef enum StatementKind_t { StatementKindFunctionCall, StatementKindFunctionBoxCall, @@ -557,7 +572,8 @@ typedef enum StatementKind_t { StatementKindBranch, StatementKindAssignment, StatementKindDeclaration, - StatementKindDefinition + StatementKindDefinition, + StatementKindReturn } StatementKind; typedef struct Statement_t { @@ -569,6 +585,7 @@ typedef struct Statement_t { Branch branch; Assignment assignment; Variable *variable; + Return returnStmt; } impl; AST_NODE_PTR nodePtr; } Statement; @@ -587,6 +604,11 @@ typedef struct Module_t { GArray* includes; } Module; +// .------------------------------------------------. +// | Utility | +// '------------------------------------------------' + +Type* SET_function_get_return_type(Function* function); // .------------------------------------------------. // | Cleanup Code | diff --git a/src/yacc/parser.y b/src/yacc/parser.y index 29dd70c..2b43040 100644 --- a/src/yacc/parser.y +++ b/src/yacc/parser.y @@ -6,6 +6,7 @@ #include #include #include + #include extern int yylineno; extern ModuleFile* current_file; @@ -57,6 +58,8 @@ %type programbody %type fundef %type fundecl +%type procdecl +%type procdef %type box %type typedef %type exprlist @@ -71,6 +74,7 @@ %type reinterpretcast %type program %type storage_expr +%type returnstmt %token KeyInt @@ -82,6 +86,7 @@ %token Ident %token ValFloat %token ValStr +%token ValChar %token ValMultistr %token KeyShort %token KeyLong @@ -120,6 +125,7 @@ %token FunLineno %token FunExtsupport %token Invalid +%token KeyReturn /* Operator associativity */ /* Operators at lower line number have lower precedence */ @@ -147,6 +153,8 @@ programbody: moduleimport {$$ = $1;} | moduleinclude {$$ = $1;} | fundef{$$ = $1;} | fundecl{$$ = $1;} + | procdecl{$$ = $1;} + | procdef{$$ = $1;} | box{$$ = $1;} | definition{$$ = $1;} | decl{$$ = $1;} @@ -156,6 +164,7 @@ programbody: moduleimport {$$ = $1;} expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);} | ValInt {$$ = AST_new_node(new_loc(), AST_Int, $1);} + | ValChar {$$ = AST_new_node(new_loc(), AST_Char, $1);} | ValMultistr {$$ = AST_new_node(new_loc(), AST_String, $1);} | ValStr {$$ = AST_new_node(new_loc(), AST_String, $1);} | Ident {$$ = AST_new_node(new_loc(), AST_Ident, $1);} @@ -165,6 +174,7 @@ expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);} | typecast{$$ = $1;} | reinterpretcast{$$ = $1;} | '(' expr ')' {$$=$2;} + | funcall {$$=$1;} | KeyRef Ident {AST_NODE_PTR addrof = AST_new_node(new_loc(), AST_AddressOf, NULL); AST_push_node(addrof, AST_new_node(new_loc(), AST_Ident, $2)); $$ = addrof;} @@ -189,21 +199,40 @@ argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3); $$ = list;}; -fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_Fun, NULL); +procdef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_ProcDef, NULL); AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2); AST_push_node(fun, ident); AST_push_node(fun, $3); AST_push_node(fun, $5); $$ = fun; - DEBUG("Function");}; + DEBUG("Function");} -fundecl: KeyFun Ident paramlist {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_Fun, NULL); +procdecl: KeyFun Ident paramlist {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_ProcDecl, NULL); AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2); AST_push_node(fun, ident); AST_push_node(fun, $3); $$ = fun; DEBUG("Function");}; +fundef: KeyFun type ':' Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_FunDef, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4); + AST_push_node(fun, ident); + AST_push_node(fun, $2); + AST_push_node(fun, $5); + AST_push_node(fun, $7); + $$ = fun; + DEBUG("Function");} + +fundecl: KeyFun type ':' Ident paramlist {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_FunDecl, NULL); + AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4); + AST_push_node(fun, ident); + AST_push_node(fun, $2); + AST_push_node(fun, $5); + $$ = fun; + DEBUG("Function");}; + + + paramlist: paramlist '(' params ')' {AST_push_node($1, $3); $$ = $1;} | paramlist '(' ')'{$$ = $1;} @@ -345,9 +374,14 @@ statement: assign {$$ = $1;} | definition {$$ = $1;} | while {$$ = $1;} | branchfull {$$ = $1;} + | returnstmt {$$ = $1;} | funcall {$$ = $1;} | boxcall{$$ = $1;}; +returnstmt: KeyReturn expr { AST_NODE_PTR return_stmt = AST_new_node(new_loc(), AST_Return, NULL); + AST_push_node(return_stmt, $2); + $$ = return_stmt; }; + branchif: KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_If, NULL); AST_push_node(branch, $2); AST_push_node(branch, $4); diff --git a/tests/ast/test_ast.py b/tests/ast/test_ast.py index b153c33..38f1327 100644 --- a/tests/ast/test_ast.py +++ b/tests/ast/test_ast.py @@ -65,26 +65,31 @@ def run_check_print_node(): 34 typedef 35 box 36 fun -37 value -38 list -39 expr list -40 arg list -41 param list -42 stmt list -43 ident list -44 value -45 type -46 value +37 fun +38 fun +39 fun +40 value +41 list +42 expr list +43 arg list +44 param list +45 stmt list +46 ident list 47 value -48 value -49 - -50 parameter +48 type +49 value +50 value 51 value -52 parameter-declaration -53 address of -54 deref -55 ref -56 value +52 - +53 parameter +54 value +55 parameter-declaration +56 address of +57 deref +58 ref +59 value +60 value +61 ret """ == p.stdout @@ -94,7 +99,7 @@ def run_check_print_graphviz(): info("creating temporary folder...") if not os.path.exists("tmp"): - os.mkdir("tmp") + os.makedirs("tmp", exist_ok=True) info("cleaning temporary folder...") diff --git a/tests/driver/clang/main.gsc b/tests/driver/clang/main.gsc index 70314a2..5d776cf 100644 --- a/tests/driver/clang/main.gsc +++ b/tests/driver/clang/main.gsc @@ -1,28 +1,27 @@ import "std" -fun cstrlen(in cstr: str)(out u32: len) { +fun u32:cstrlen(in cstr: str) { u32: idx = 0 as u32 while !(str[idx] == 0) { - idx = idx + 1 + idx = idx + 1 as u32 } - len = idx + ret idx } fun printcstr(in cstr: msg) { - u32: len = 0 - cstrlen(msg)(len) + u32: len = cstrlen(msg) - handle: stdout = 0 - getStdoutHandle()(stdout) + handle: stdout = getStdoutHandle() - u32: written = 0 - writeBytes(stdout, msg, len)(written) + writeBytes(stdout, msg, len) } -fun main() { +fun int:main() { cstr: msg = "Hello, world!\n" printcstr(msg) + + ret 0 } diff --git a/tests/driver/gcc/main.gsc b/tests/driver/gcc/main.gsc index 70314a2..5d776cf 100644 --- a/tests/driver/gcc/main.gsc +++ b/tests/driver/gcc/main.gsc @@ -1,28 +1,27 @@ import "std" -fun cstrlen(in cstr: str)(out u32: len) { +fun u32:cstrlen(in cstr: str) { u32: idx = 0 as u32 while !(str[idx] == 0) { - idx = idx + 1 + idx = idx + 1 as u32 } - len = idx + ret idx } fun printcstr(in cstr: msg) { - u32: len = 0 - cstrlen(msg)(len) + u32: len = cstrlen(msg) - handle: stdout = 0 - getStdoutHandle()(stdout) + handle: stdout = getStdoutHandle() - u32: written = 0 - writeBytes(stdout, msg, len)(written) + writeBytes(stdout, msg, len) } -fun main() { +fun int:main() { cstr: msg = "Hello, world!\n" printcstr(msg) + + ret 0 } diff --git a/tests/hello_world/main.gsc b/tests/hello_world/main.gsc index 70314a2..e3dc0df 100644 --- a/tests/hello_world/main.gsc +++ b/tests/hello_world/main.gsc @@ -1,28 +1,25 @@ import "std" -fun cstrlen(in cstr: str)(out u32: len) { +fun u32:cstrlen(in cstr: str) { u32: idx = 0 as u32 while !(str[idx] == 0) { - idx = idx + 1 + idx = idx + 1 as u32 } - len = idx + ret idx } fun printcstr(in cstr: msg) { - u32: len = 0 - cstrlen(msg)(len) + u32: len = cstrlen(msg) - handle: stdout = 0 - getStdoutHandle()(stdout) + handle: stdout = getStdoutHandle() - u32: written = 0 - writeBytes(stdout, msg, len)(written) + writeBytes(stdout, msg, len) } -fun main() { - cstr: msg = "Hello, world!\n" - printcstr(msg) +fun int:main() { + printcstr("Hello, world!\n") + ret 0 } diff --git a/tests/input_file/test.gsc b/tests/input_file/test.gsc index 3479ad3..c47d447 100644 --- a/tests/input_file/test.gsc +++ b/tests/input_file/test.gsc @@ -1,4 +1,4 @@ -fun main(out int: ret) { - ret = 56 as int +fun int:main() { + ret 56 as int } diff --git a/tests/input_file/test_input_file.py b/tests/input_file/test_input_file.py index 550f3f4..6804bf2 100644 --- a/tests/input_file/test_input_file.py +++ b/tests/input_file/test_input_file.py @@ -22,7 +22,7 @@ def check_abort(): logging.basicConfig(level=logging.INFO) - p = subprocess.run(["./gsc", "compile"], capture_output=True, text=True) + p = subprocess.run(["./gsc", "compile", "foo.gsc"], capture_output=True, text=True) assert p.returncode == 1 diff --git a/tests/project/CMakeLists.txt b/tests/project/CMakeLists.txt index 281ec1b..2a8d3d6 100644 --- a/tests/project/CMakeLists.txt +++ b/tests/project/CMakeLists.txt @@ -4,6 +4,6 @@ include(CTest) # CTEST 1 # test if the program successfully reads the project config -#add_test(NAME project_build -# WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/project -# COMMAND python ${GEMSTONE_TEST_DIR}/project/test_project.py) +add_test(NAME project_build + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/project + COMMAND python ${GEMSTONE_TEST_DIR}/project/test_project.py) diff --git a/tests/stdlib/build.toml b/tests/stdlib/build.toml new file mode 100644 index 0000000..749e8fa --- /dev/null +++ b/tests/stdlib/build.toml @@ -0,0 +1,33 @@ +[project] +name = "Stdlib tests" +version = "0.1.0" +description = "Test applications for the GSC standard library." +license = "GPL-2.0" +authors = [ "Sven Vogel " ] + +[target.echo] +link-paths = [ "../../bin/std" ] +import-paths = [ "../../lib/src" ] +root = "src/echo.gsc" +mode = "application" +output = "bin" +archive = "archive" +print_ir = true + +[target.letters] +link-paths = [ "../../bin/std" ] +import-paths = [ "../../lib/src" ] +root = "src/letters.gsc" +mode = "application" +output = "bin" +archive = "archive" +print_ir = true + +[target.matrix] +link-paths = [ "../../bin/std" ] +import-paths = [ "../../lib/src" ] +root = "src/matrix.gsc" +mode = "application" +output = "bin" +archive = "archive" +print_ir = true \ No newline at end of file diff --git a/tests/stdlib/src/echo.gsc b/tests/stdlib/src/echo.gsc new file mode 100644 index 0000000..9253222 --- /dev/null +++ b/tests/stdlib/src/echo.gsc @@ -0,0 +1,25 @@ + +import "std" + +cstr: EOL = "\n" + +fun main() { + + handle: stdin = nullHandle + getStdinHandle(stdin) + + handle: stdout = nullHandle + getStdoutHandle(stdout) + + ref u8: buffer = 0 as ref u8 + heapAlloc(256)(buffer) + + u32: bytesRead = 0 as u32 + readBytes(stdin, buffer, 8)(bytesRead) + + u32: bytesWritten = 0 as u32 + writeBytes(stdout, buffer, bytesRead)(bytesWritten) + writeBytes(stdout, EOL, 1)(bytesWritten) + + heapFree(buffer) +} diff --git a/tests/stdlib/src/letters.gsc b/tests/stdlib/src/letters.gsc new file mode 100644 index 0000000..ffdee3c --- /dev/null +++ b/tests/stdlib/src/letters.gsc @@ -0,0 +1,27 @@ + +import "std" + +cstr: EOL = "\n" + +fun main() { + + handle: stdin = nullHandle + getStdinHandle(stdin) + + handle: stdout = nullHandle + getStdoutHandle(stdout) + + ref u8: buffer = 0 as ref u8 + heapAlloc(256)(buffer) + + u32: bytesRead = 0 as u32 + readBytes(stdin, buffer, 8)(bytesRead) + + buffer[0] = 'a' as u8 + + u32: bytesWritten = 0 as u32 + writeBytes(stdout, buffer, bytesRead)(bytesWritten) + writeBytes(stdout, EOL, 1)(bytesWritten) + + heapFree(buffer) +} diff --git a/tests/stdlib/src/matrix.gsc b/tests/stdlib/src/matrix.gsc new file mode 100644 index 0000000..0569dd9 --- /dev/null +++ b/tests/stdlib/src/matrix.gsc @@ -0,0 +1,95 @@ + +import "std" + +fun u32:ulog10(in u32: num) +{ + u32: base = 1 as u32 + u32: count = 0 as u32 + + while base < num + { + base = base * 10 as u32 + count = count + 1 as u32 + } + + if count == 0 as u32 { + count = 1 as u32 + } + + ret count +} + +fun u32ToCstr(in u32: number)(out cstr: result, out u32: len) +{ + u32: bytes = ulog10(number) + + cstr: buf = 0 as cstr + heapAlloc(bytes)(buf as ref u8) + + u32: idx = bytes - 1 as u32 + u32: tmp = number + while (idx > 0 || idx == 0) + { + u32: digit = 0 as u32 + mod(tmp, 10 as u32, digit) + + buf[idx] = (digit + '0') as u8 + + tmp = tmp / 10 as u32 + idx = idx - 1 as u32 + } + + len = bytes + result = buf +} + +fun printU32(in u32: val) +{ + cstr: str = 0 as cstr + u32: len = 0 as u32 + + u32ToCstr(val)(str, len) + + handle: stdout = getStdoutHandle() + + writeBytes(stdout, str, len) + + heapFree(str) + + writeBytes(stdout, " ", 1 as u32) +} + +fun test_matrix() +{ + ref ref u32: matrix + heapAlloc((8 * 4) as u32)(matrix as ref u8) + + u32: written = 0 as u32 + handle: stdout = getStdoutHandle() + + u32: idx = 0 as u32 + while idx < 4 { + heapAlloc((4 * 4) as u32)(matrix[idx] as ref u8) + + u32: idy = 0 as u32 + while idy < 4 { + matrix[idx][idy] = idy + + printU32(matrix[idx][idy]) + + idy = idy + 1 as u32 + } + writeBytes(stdout, "\n", 1 as u32) + + heapFree(matrix[idx] as ref u8) + idx = idx + 1 as u32 + } + + heapFree(matrix as ref u8) +} + +fun i32:main() +{ + test_matrix() + ret 0 +}