Merge pull request #130 from Servostar/129-test-standard-library

129 test standard library
This commit is contained in:
servostar 2024-08-05 21:24:08 +02:00 committed by GitHub
commit ed728c8042
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 927 additions and 296 deletions

View File

@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 3.15...3.25)
# test.c # test.c
project(gemstone project(gemstone
VERSION 0.1.0 VERSION 0.2.6
DESCRIPTION "programming language compiler" DESCRIPTION "programming language compiler"
LANGUAGES C) 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_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/lex/lexer.l)
set(LEX_GENERATED_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/lex/lexer.ll.c) 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} add_custom_command(OUTPUT ${LEX_GENERATED_SOURCE_FILE}
COMMAND lex COMMAND lex
ARGS -o ${LEX_GENERATED_SOURCE_FILE} ${LEX_SOURCE_FILE} 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_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.y)
set(YACC_GENERATED_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.tab.c) 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} add_custom_command(OUTPUT ${YACC_GENERATED_SOURCE_FILE}
COMMAND bison COMMAND bison
ARGS -Wno-yacc -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE} ARGS -Wno-yacc -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE}

View File

@ -24,8 +24,12 @@ add_library(gscmem ${STDLIB_MEM_SOURCE_FILES})
file(GLOB_RECURSE STDLIB_OS_SOURCE_FILES src/os/*.c) file(GLOB_RECURSE STDLIB_OS_SOURCE_FILES src/os/*.c)
add_library(gscos ${STDLIB_OS_SOURCE_FILES}) 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 # Complete standard library
add_library(gscstd add_library(gscstd
${STDLIB_IO_SOURCE_FILES} ${STDLIB_IO_SOURCE_FILES}
${STDLIB_MEM_SOURCE_FILES} ${STDLIB_MEM_SOURCE_FILES}
${STDLIB_OS_SOURCE_FILES}) ${STDLIB_OS_SOURCE_FILES}
${STDLIB_MATH_SOURCE_FILES})

View File

@ -14,37 +14,41 @@ include "def.gsc"
# which can lead to errors and undefined behavior # which can lead to errors and undefined behavior
type ptr: handle 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 # Returns a handle to this processes standard input I/O handle
# -- Implementation note # -- 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 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)` # 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 # Returns a handle to this processes standard input I/O handle
# -- Implementation note # -- 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 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)` # 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 # Returns a handle to this processes standard input I/O handle
# -- Implementation note # -- 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 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)` # 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 # Write `len` number of bytes from `buf` into the I/O resource specified
# by `dev`. Returns the number of bytes written. # by `dev`. Returns the number of bytes written.
# -- Implementation note # -- Implementation note
# On Linux this will use the syscall write # On Linux this will use the syscall write
# On Windows this will use the WriteFile function # 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` # Read atmost `len` bytes to `buf` from the I/O resource specified by `dev`
# Returns the number of read bytes in `written` # Returns the number of read bytes in `written`
# -- Implementation note # -- Implementation note
# On Linux this will use the syscall read # On Linux this will use the syscall read
# On Windows this will use the ReadFile function # 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` # Flushes the buffers of the I/O resource specified by `dev`
# -- Implementation note # -- Implementation note

View File

@ -6,15 +6,15 @@
typedef ptr handle; 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); void flush(handle dev);

View File

@ -11,24 +11,28 @@
// FIXME: error in case GetStdHandle return INVALID_HANDLE_VALUE // FIXME: error in case GetStdHandle return INVALID_HANDLE_VALUE
// FIXME: error in case functions return 0 // FIXME: error in case functions return 0
void getStdinHandle(handle* stdin) { handle getStdinHandle(handle* stdin) {
*stdin = (handle) GetStdHandle(STD_INPUT_HANDLE); return GetStdHandle(STD_INPUT_HANDLE);
} }
void getStdoutHandle(handle* stdout) { handle getStdoutHandle(handle* stdout) {
*stdout = (handle) GetStdHandle(STD_OUTPUT_HANDLE); return GetStdHandle(STD_OUTPUT_HANDLE);
} }
void getStderrHandle(handle* stderr) { handle getStderrHandle(handle* stderr) {
*stderr = (handle) GetStdHandle(STD_ERROR_HANDLE); return GetStdHandle(STD_ERROR_HANDLE);
} }
void writeBytes(handle dev, u8* buf, u32 len, u32* bytesWritten) { u32 writeBytes(handle dev, u8* buf, u32 len) {
WriteFile((HANDLE) dev, buf, len, bytesRead, NULL); u32 bytesWritten = 0;
WriteFile((HANDLE) dev, buf, len, &bytesWritten, NULL);
return bytesWritten;
} }
void readBytes(handle dev, u8* buf, u32 len, u32* bytesRead) { u32 readBytes(handle dev, u8* buf, u32 len) {
ReadFile((HANDLE) dev, buf, len, bytesRead, NULL); u32 bytesRead = 0;
ReadFile((HANDLE) dev, buf, len, &bytesRead, NULL);
return bytesRead;
} }
void flush(handle dev) { void flush(handle dev) {
@ -47,24 +51,24 @@ void flush(handle dev) {
// which are stored as 64-bit by zero extending // which are stored as 64-bit by zero extending
#define TO_INT(x) ((int)(long int)(x)) #define TO_INT(x) ((int)(long int)(x))
void getStdinHandle(handle* stdin) { handle getStdinHandle() {
*stdin = (handle) STDIN_FILENO; return (handle) STDIN_FILENO;
} }
void getStdoutHandle(handle* stdout) { handle getStdoutHandle() {
*stdout = (handle) STDOUT_FILENO; return (handle) STDOUT_FILENO;
} }
void getStderrHandle(handle* stderr) { handle getStderrHandle() {
*stderr = (handle) STDERR_FILENO; return (handle) STDERR_FILENO;
} }
void writeBytes(handle dev, u8* buf, u32 len, u32* bytesWritten) { u32 writeBytes(handle dev, u8* buf, u32 len) {
*bytesWritten = write(TO_INT(dev), buf, len); return write(TO_INT(dev), buf, len);
} }
void readBytes(handle dev, u8* buf, u32 len, u32* bytesRead) { u32 readBytes(handle dev, u8* buf, u32 len) {
*bytesRead = read(TO_INT(dev), buf, len); return read(TO_INT(dev), buf, len);
} }
void flush(handle dev) { void flush(handle dev) {

12
lib/src/math.gsc Normal file
View File

@ -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)

9
lib/src/math/api.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef GEMSTONE_STD_LIB_MATH_H_
#define GEMSTONE_STD_LIB_MATH_H_
#include <def/api.h>
void mod(u32 a, u32 b, u32* c);
#endif //GEMSTONE_STD_LIB_MATH_H_

10
lib/src/math/impl.c Normal file
View File

@ -0,0 +1,10 @@
//
// Created by servostar on 01.08.24.
//
#include <math/api.h>
#include <capi.h>
void mod(u32 a, u32 b, u32* c) {
c[0] = a % b;
}

View File

@ -10,14 +10,14 @@ include "def.gsc"
# Allocate `len` bytes of heap memory # Allocate `len` bytes of heap memory
# Returns a pointer to the memory as `ptr` # 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 # Rellocate `len` bytes of heap memory
# Returns a pointer to the memory as `ptr` # 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 # 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` # Copy `len` bytes from `dst` into `src`
fun copy(in ref u8: dst, in ref u8: src, in u32: len) fun copy(in ref u8: dst, in ref u8: src, in u32: len)

View File

@ -4,11 +4,11 @@
#include <def/api.h> #include <def/api.h>
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); void copy(u8* dst, u8* src, u32 len);

View File

@ -8,17 +8,17 @@
#define HEAP_API_GLOBAL_FLAGS HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS #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(); HANDLE heap = GetProcessHeap();
*ptr = HeapAlloc(heap, HEAP_API_GLOBAL_FLAGS, len); *ptr = HeapAlloc(heap, HEAP_API_GLOBAL_FLAGS, len);
} }
void heap_realloc(u32 len, u8** ptr) { void heapRealloc(u32 len, u8** ptr) {
HANDLE heap = GetProcessHeap(); HANDLE heap = GetProcessHeap();
*ptr = HeapReAlloc(heap, HEAP_API_GLOBAL_FLAGS, *ptr, len); *ptr = HeapReAlloc(heap, HEAP_API_GLOBAL_FLAGS, *ptr, len);
} }
void heap_free(u8* ptr) { void heapFree(u8* ptr) {
HANDLE heap = GetProcessHeap(); HANDLE heap = GetProcessHeap();
HeapFree(heap, ptr); HeapFree(heap, ptr);
} }
@ -27,15 +27,15 @@ void heap_free(u8* ptr) {
#include <malloc.h> #include <malloc.h>
void heap_alloc(u32 len, u8** ptr) { void heapAlloc(u32 len, u8** ptr) {
*ptr = malloc(len); *ptr = malloc(len);
} }
void heap_realloc(u32 len, u8** ptr) { void heapRealloc(u32 len, u8** ptr) {
*ptr = realloc(*ptr, len); *ptr = realloc(*ptr, len);
} }
void heap_free(u8* ptr) { void heapFree(u8* ptr) {
free(ptr); free(ptr);
} }

View File

@ -14,3 +14,6 @@ include "io.gsc"
# memory management # memory management
include "mem.gsc" include "mem.gsc"
# mathematical utilities
include "math.gsc"

View File

@ -67,7 +67,10 @@ void AST_init() {
lookup_table[AST_Typedef] = "typedef"; lookup_table[AST_Typedef] = "typedef";
lookup_table[AST_Box] = "box"; 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_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast"; lookup_table[AST_Typecast] = "typecast";
@ -86,6 +89,7 @@ void AST_init() {
lookup_table[AST_AddressOf] = "address of"; lookup_table[AST_AddressOf] = "address of";
lookup_table[AST_Dereference] = "deref"; lookup_table[AST_Dereference] = "deref";
lookup_table[AST_Reference] = "ref"; lookup_table[AST_Reference] = "ref";
lookup_table[AST_Return] = "ret";
} }
const char* AST_node_to_string(const struct AST_Node_t* node) { 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) { switch(node->kind) {
case AST_Int: case AST_Int:
case AST_Char:
case AST_Float: case AST_Float:
case AST_String: case AST_String:
case AST_Ident: case AST_Ident:

View File

@ -57,7 +57,10 @@ enum AST_SyntaxElement_t {
// Defintions // Defintions
AST_Typedef, AST_Typedef,
AST_Box, AST_Box,
AST_Fun, AST_FunDecl,
AST_FunDef,
AST_ProcDecl,
AST_ProcDef,
AST_Import, AST_Import,
// amount of variants // amount of variants
// in this enums // in this enums
@ -80,6 +83,8 @@ enum AST_SyntaxElement_t {
AST_Dereference, AST_Dereference,
AST_Reference, AST_Reference,
AST_Include, AST_Include,
AST_Char,
AST_Return,
AST_ELEMENT_COUNT AST_ELEMENT_COUNT
}; };

View File

@ -145,21 +145,21 @@ static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) {
g_free(path); 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..."); DEBUG("initializing LLVM codegen backend...");
llvm_backend_init(); llvm_backend_init();
DEBUG("initiializing backend for codegen..."); DEBUG("initiializing backend for codegen...");
BackendError err = init_backend(); BackendError err = init_backend();
if (err.kind != Success) { if (err.kind != Success) {
return; return EXIT_FAILURE;
} }
DEBUG("generating code..."); DEBUG("generating code...");
err = generate_code(module, target); err = generate_code(module, target);
if (err.kind != Success) { if (err.kind != Success) {
print_message(Error, "Backend failed: %s", err.impl.message); print_message(Error, "Backend failed: %s", err.impl.message);
return; return EXIT_FAILURE;
} }
print_message(Info, "Compilation finished successfully"); print_message(Info, "Compilation finished successfully");
@ -167,7 +167,10 @@ static void run_backend_codegen(const Module* module, const TargetConfig* target
err = deinit_backend(); err = deinit_backend();
if (err.kind != Success) { if (err.kind != Success) {
ERROR("Unable to deinit backend: %s", err.impl.message); 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) { 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 unit
* @param target * @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); print_message(Info, "Building target: %s", target->name);
ModuleFile *file = push_file(unit, target->root_module); ModuleFile *file = push_file(unit, target->root_module);
AST_NODE_PTR root_module = AST_new_node(empty_location(file), AST_Module, NULL); 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 (root_module != NULL) {
if (setup_target_environment(target) == 0) { err = setup_target_environment(target);
if (err == 0) {
print_ast_to_file(root_module, target); print_ast_to_file(root_module, target);
Module *module = create_set(root_module); Module *module = create_set(root_module);
if (module != NULL) { 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); mem_purge_namespace(MemoryNamespaceSet);
print_file_statistics(file); 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. * Creates a single target by the given command line arguments.
* @param unit * @param unit
*/ */
static void compile_file(ModuleFileStack *unit) { static int compile_file(ModuleFileStack *unit) {
INFO("compiling basic files..."); INFO("compiling basic files...");
TargetConfig *target = default_target_config_from_args(); TargetConfig *target = default_target_config_from_args();
@ -297,12 +308,14 @@ static void compile_file(ModuleFileStack *unit) {
if (target->root_module == NULL) { if (target->root_module == NULL) {
print_message(Error, "No input file specified."); print_message(Error, "No input file specified.");
delete_target_config(target); delete_target_config(target);
return; return EXIT_FAILURE;
} }
build_target(unit, target); int err = build_target(unit, target);
delete_target_config(target); delete_target_config(target);
return err;
} }
/** /**
@ -310,7 +323,9 @@ static void compile_file(ModuleFileStack *unit) {
* @param unit * @param unit
* @param config * @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")) { if (is_option_set("all")) {
// build all targets in the project // build all targets in the project
GHashTableIter iter; GHashTableIter iter;
@ -320,9 +335,9 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co
char *key; char *key;
TargetConfig *val; TargetConfig *val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &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 // 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); const char *target_name = g_array_index(targets, const char*, i);
if (g_hash_table_contains(config->targets, target_name)) { 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 { } else {
print_message(Error, "Unknown target: %s", target_name); print_message(Error, "Unknown target: %s", target_name);
} }
@ -343,39 +358,46 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co
} else { } else {
print_message(Error, "No targets specified."); print_message(Error, "No targets specified.");
} }
return err;
} }
/** /**
* @brief Build targets from project. Configuration is provided by command line arguments. * @brief Build targets from project. Configuration is provided by command line arguments.
* @param unit File storage * @param unit File storage
*/ */
static void build_project(ModuleFileStack *unit) { static int build_project(ModuleFileStack *unit) {
ProjectConfig *config = default_project_config(); ProjectConfig *config = default_project_config();
int err = load_project_config(config); int err = load_project_config(config);
if (err == PROJECT_OK) { if (err == PROJECT_OK) {
build_project_targets(unit, config); err = build_project_targets(unit, config);
} }
delete_project_config(config); delete_project_config(config);
return err;
} }
void run_compiler() { int run_compiler() {
ModuleFileStack files = new_file_stack(); ModuleFileStack files = new_file_stack();
int status = EXIT_SUCCESS;
if (is_option_set("build")) { if (is_option_set("build")) {
build_project(&files); status = build_project(&files);
} else if (is_option_set("compile")) { } else if (is_option_set("compile")) {
compile_file(&files); status = compile_file(&files);
} else { } else {
print_message(Error, "Invalid mode of operation. Rerun with --help."); print_message(Error, "Invalid mode of operation. Rerun with --help.");
} }
if (files.files == NULL) { if (files.files == NULL) {
print_message(Error, "No input files, nothing to do."); print_message(Error, "No input files, nothing to do.");
exit(1); } else {
print_unit_statistics(&files);
} }
print_unit_statistics(&files);
delete_files(&files); delete_files(&files);
return status;
} }

View File

@ -7,7 +7,8 @@
/** /**
* @brief Run the gemstone compiler with the provided command arguments. * @brief Run the gemstone compiler with the provided command arguments.
* @return status of compilation
*/ */
void run_compiler(); int run_compiler();
#endif //GEMSTONE_COMPILER_H #endif //GEMSTONE_COMPILER_H

View File

@ -90,11 +90,19 @@
"funname" {DEBUG("\"%s\" tokenized with \'FunFunname\'", yytext); return(FunFunname);}; "funname" {DEBUG("\"%s\" tokenized with \'FunFunname\'", yytext); return(FunFunname);};
"lineno" {DEBUG("\"%s\" tokenized with \'FunLineno\'", yytext); return(FunLineno);}; "lineno" {DEBUG("\"%s\" tokenized with \'FunLineno\'", yytext); return(FunLineno);};
"extsupport" {DEBUG("\"%s\" tokenized with \'FunExtsupport\'", yytext); return(FunExtsupport);}; "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]+ {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);}; [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); }; [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])*\" { \"([^\"\n])*\" {
yytext = yytext +1; yytext = yytext +1;
yytext[yyleng - 2] = 0; yytext[yyleng - 2] = 0;

View File

@ -20,14 +20,14 @@ BackendError impl_bitwise_operation(LLVMBackendCompileUnit *unit,
if (operation->impl.bitwise == BitwiseNot) { if (operation->impl.bitwise == BitwiseNot) {
// single operand // single operand
rhs = g_array_index(operation->operands, Expression*, 0); 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 { } else {
// two operands // two operands
lhs = g_array_index(operation->operands, Expression*, 0); 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); 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) { switch (operation->impl.bitwise) {
@ -80,14 +80,14 @@ BackendError impl_logical_operation(LLVMBackendCompileUnit *unit,
if (operation->impl.logical == LogicalNot) { if (operation->impl.logical == LogicalNot) {
// single operand // single operand
rhs = g_array_index(operation->operands, Expression*, 0); 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 { } else {
// two operands // two operands
lhs = g_array_index(operation->operands, Expression*, 0); 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); 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) { switch (operation->impl.logical) {
@ -144,10 +144,10 @@ BackendError impl_relational_operation(LLVMBackendCompileUnit *unit,
// two operands // two operands
lhs = g_array_index(operation->operands, Expression*, 0); 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); 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)) { if (is_integral(rhs->result)) {
// integral type // integral type
@ -206,14 +206,14 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
if (operation->impl.arithmetic == Negate) { if (operation->impl.arithmetic == Negate) {
// single operand // single operand
rhs = g_array_index(operation->operands, Expression*, 0); 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 { } else {
// two operands // two operands
lhs = g_array_index(operation->operands, Expression*, 0); 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); 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)) { if (is_integral(rhs->result)) {
@ -297,7 +297,7 @@ BackendError impl_transmute(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMValueRef *llvm_result) { LLVMValueRef *llvm_result) {
LLVMValueRef operand = NULL; 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; LLVMTypeRef target_type = NULL;
BackendError err = get_type_impl(unit, scope->func_scope->global_scope, 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, BackendError impl_typecast(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, TypeCast *typecast, LLVMBuilderRef builder, TypeCast *typecast,
bool reference,
LLVMValueRef *llvm_result) { LLVMValueRef *llvm_result) {
LLVMValueRef operand = NULL; 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; LLVMTypeRef target_type = NULL;
BackendError err = get_type_impl(unit, scope->func_scope->global_scope, 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, LLVMBuilderRef builder, AddressOf* addressOf,
LLVMValueRef *llvm_result) { 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) { if (err.kind != Success) {
return err; return err;
@ -445,11 +446,13 @@ BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope
BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Dereference* dereference, LLVMBuilderRef builder, Dereference* dereference,
bool reference,
uint32_t deref_depth,
LLVMValueRef *llvm_result) { LLVMValueRef *llvm_result) {
BackendError err; BackendError err;
LLVMValueRef llvm_pointer = NULL; 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) { if (err.kind != Success) {
return err; return err;
} }
@ -461,14 +464,16 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
} }
LLVMValueRef* index = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef)); 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) { if (err.kind != Success) {
return err; return err;
} }
*llvm_result = LLVMBuildGEP2(builder, llvm_deref_type, llvm_pointer, index, 1, "expr.deref.gep2"); *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; return err;
} }
@ -476,6 +481,7 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Expression *expr, LLVMBuilderRef builder, Expression *expr,
LLVMBool reference, LLVMBool reference,
uint32_t deref_depth,
LLVMValueRef *llvm_result) { LLVMValueRef *llvm_result) {
DEBUG("implementing expression: %ld", expr->kind); DEBUG("implementing expression: %ld", expr->kind);
BackendError err = SUCCESS; BackendError err = SUCCESS;
@ -491,6 +497,7 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break; break;
case ExpressionKindTypeCast: case ExpressionKindTypeCast:
err = impl_typecast(unit, scope, builder, &expr->impl.typecast, err = impl_typecast(unit, scope, builder, &expr->impl.typecast,
reference,
llvm_result); llvm_result);
break; break;
case ExpressionKindOperation: case ExpressionKindOperation:
@ -513,8 +520,13 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break; break;
case ExpressionKindDereference: case ExpressionKindDereference:
err = impl_deref(unit, scope, builder, &expr->impl.dereference, err = impl_deref(unit, scope, builder, &expr->impl.dereference,
reference,
deref_depth,
llvm_result); llvm_result);
break; break;
case ExpressionKindFunctionCall:
err = impl_func_call(unit, builder, scope, expr->impl.call, llvm_result);
break;
default: default:
err = new_backend_impl_error(Implementation, NULL, "unknown expression"); err = new_backend_impl_error(Implementation, NULL, "unknown expression");
break; break;

View File

@ -13,6 +13,7 @@
BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Expression *expr, LLVMBuilderRef builder, Expression *expr,
LLVMBool reference, LLVMBool reference,
uint32_t deref_depth,
LLVMValueRef *llvm_result); LLVMValueRef *llvm_result);
#endif // LLVM_BACKEND_EXPR_H #endif // LLVM_BACKEND_EXPR_H

View File

@ -10,6 +10,7 @@
#include <set/types.h> #include <set/types.h>
#include <sys/log.h> #include <sys/log.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <llvm/llvm-ir/expr.h>
LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) { LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) {
LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope)); LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope));
@ -127,8 +128,19 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
DEBUG("implemented %ld parameter", llvm_params->len); 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 = LLVMTypeRef llvm_fun_type =
LLVMFunctionType(LLVMVoidTypeInContext(unit->context), LLVMFunctionType(llvm_return_type,
(LLVMTypeRef*)llvm_params->data, llvm_params->len, 0); (LLVMTypeRef*)llvm_params->data, llvm_params->len, 0);
*llvm_fun = LLVMAddFunction(unit->module, func->name, llvm_fun_type); *llvm_fun = LLVMAddFunction(unit->module, func->name, llvm_fun_type);
@ -180,14 +192,39 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit,
LLVMPositionBuilderAtEnd(builder, entry); LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuildBr(builder, llvm_start_body_block); LLVMBuildBr(builder, llvm_start_body_block);
// insert returning end block LLVMValueRef terminator = LLVMGetBasicBlockTerminator(llvm_end_body_block);
LLVMBasicBlockRef end_block = if (terminator == NULL) {
LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.end"); // insert returning end block
LLVMPositionBuilderAtEnd(builder, end_block); LLVMBasicBlockRef end_block =
LLVMBuildRetVoid(builder); LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.end");
LLVMPositionBuilderAtEnd(builder, end_block);
LLVMPositionBuilderAtEnd(builder, llvm_end_body_block); LLVMValueRef llvm_return = NULL;
LLVMBuildBr(builder, end_block); 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); LLVMDisposeBuilder(builder);
} }
@ -247,3 +284,83 @@ BackendError impl_functions(LLVMBackendCompileUnit* unit,
return err; 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(&param), 0, &llvm_arg);
if (err.kind != Success) {
break;
}
if (is_parameter_out(&param)) {
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;
}

View File

@ -40,4 +40,9 @@ BackendError impl_functions(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope, LLVMGlobalScope* scope,
GHashTable* variables); GHashTable* variables);
BackendError impl_func_call(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
const FunctionCall *call,
LLVMValueRef* return_value);
#endif // LLVM_BACKEND_FUNC_H_ #endif // LLVM_BACKEND_FUNC_H_

View File

@ -55,7 +55,7 @@ BackendError impl_storage_expr(
case StorageExprKindDereference: case StorageExprKindDereference:
LLVMValueRef index = NULL; 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) { if (err.kind != Success) {
return err; return err;
} }
@ -73,7 +73,7 @@ BackendError impl_storage_expr(
} }
} }
if (expr->impl.dereference.array->kind == StorageExprKindDereference) { if (true) {
LLVMTypeRef deref_type = NULL; LLVMTypeRef deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type); err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type);
if (err.kind != Success) { if (err.kind != Success) {
@ -111,7 +111,7 @@ BackendError impl_assign_stmt(
DEBUG("implementing assignment for variable: %p", assignment); DEBUG("implementing assignment for variable: %p", assignment);
LLVMValueRef llvm_value = NULL; 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) { if (err.kind != Success) {
return err; return err;
} }
@ -141,6 +141,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
LLVMBasicBlockRef end_previous_block = *llvm_start_block; LLVMBasicBlockRef end_previous_block = *llvm_start_block;
bool terminated = false;
for (size_t i = 0; i < block->statemnts->len; i++) { for (size_t i = 0; i < block->statemnts->len; i++) {
DEBUG("building block statement %d of %d", i, block->statemnts->len); DEBUG("building block statement %d of %d", i, block->statemnts->len);
Statement* stmt = g_array_index(block->statemnts, Statement*, i); Statement* stmt = g_array_index(block->statemnts, Statement*, i);
@ -152,12 +154,20 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
return err; 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); LLVMPositionBuilderAtEnd(builder, end_previous_block);
LLVMBuildBr(builder, llvm_next_start_block); LLVMBuildBr(builder, llvm_next_start_block);
LLVMPositionBuilderAtEnd(builder, llvm_next_end_block); LLVMPositionBuilderAtEnd(builder, llvm_next_end_block);
end_previous_block = 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; *llvm_end_block = end_previous_block;
@ -182,7 +192,7 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
LLVMPositionBuilderAtEnd(builder, while_cond_block); LLVMPositionBuilderAtEnd(builder, while_cond_block);
// Resolve condition in block to a variable // Resolve condition in block to a variable
LLVMValueRef cond_result = NULL; 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) { if (err.kind != Success) {
return err; return err;
} }
@ -213,74 +223,6 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
return err; 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(&param), &llvm_arg);
if (err.kind != Success) {
break;
}
if (is_parameter_out(&param)) {
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 BackendError
impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Expression *cond, 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, 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"); "stmt.branch.cond");
LLVMPositionBuilderAtEnd(builder, *cond_block); LLVMPositionBuilderAtEnd(builder, *cond_block);
// Resolve condition in block to a variable // 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) { if (err.kind == Success) {
// build body of loop // build body of loop
err = impl_basic_block(unit, builder, scope, block, start_body_block, end_body_block); 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; 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, BackendError impl_def(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMBuilderRef builder,
LLVMLocalScope *scope, LLVMLocalScope *scope,
@ -441,7 +400,7 @@ BackendError impl_def(LLVMBackendCompileUnit *unit,
} }
LLVMValueRef initial_value = NULL; 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) { if (err.kind != Success) {
return err; 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); err = impl_while(unit, builder, scope, llvm_start_block, llvm_end_block, &stmt->impl.whileLoop);
break; break;
case StatementKindFunctionCall: 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; break;
default: default:
err = new_backend_impl_error(Implementation, NULL, "Unexpected statement kind"); err = new_backend_impl_error(Implementation, NULL, "Unexpected statement kind");

View File

@ -6,16 +6,11 @@
#include <set/types.h> #include <set/types.h>
#include <sys/log.h> #include <sys/log.h>
#include <set/set.h> #include <set/set.h>
#include <stdlib.h>
#include <mem/cache.h> #include <mem/cache.h>
#define BASE_BYTES 4 #define BASE_BYTES 4
#define BITS_PER_BYTE 8 #define BITS_PER_BYTE 8
char* guid() {
return "uuid";
}
static BackendError get_const_primitive_value(PrimitiveType primitive, static BackendError get_const_primitive_value(PrimitiveType primitive,
LLVMTypeRef llvm_type, LLVMTypeRef llvm_type,
const char* value, const char* value,
@ -27,6 +22,10 @@ static BackendError get_const_primitive_value(PrimitiveType primitive,
case Float: case Float:
*llvm_value = LLVMConstRealOfString(llvm_type, value); *llvm_value = LLVMConstRealOfString(llvm_type, value);
break; break;
case Char:
gunichar codepoint = g_utf8_get_char(value);
*llvm_value = LLVMConstInt(llvm_type, codepoint, false);
break;
} }
return SUCCESS; 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 impl_reference_const(LLVMBackendCompileUnit* unit, TypeValue* value, LLVMValueRef* llvm_value) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
if (value->type->kind == TypeKindReference && compareTypes(value->type, (Type*) &StringLiteralType)) { if (compareTypes(value->type, (Type*) &StringLiteralType)) {
// is string literal // is string literal
LLVMValueRef string_value = LLVMConstString(value->value, strlen(value->value), false); 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); LLVMSetUnnamedAddress(string_global, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(string_global, 1); 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 { } else {
err = new_backend_impl_error(Implementation, value->nodePtr, "reference initializer can only be string literals"); 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..."); DEBUG("implementing primtive float type...");
*llvm_type = LLVMFloatTypeInContext(unit->context); *llvm_type = LLVMFloatTypeInContext(unit->context);
break; break;
case Char:
DEBUG("implementing primitive codepoint type...");
*llvm_type = LLVMInt32TypeInContext(unit->context);
break;
default: default:
PANIC("invalid primitive type"); PANIC("invalid primitive type");
break;
} }
return SUCCESS; return SUCCESS;

View File

@ -1,11 +1,13 @@
#include <codegen/backend.h> #include <codegen/backend.h>
#include <set/types.h>
#include <sys/log.h>
#include <llvm/llvm-ir/variables.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm-c/Types.h> #include <llvm-c/Types.h>
#include <llvm/llvm-ir/types.h> #include <llvm/llvm-ir/types.h>
#include <llvm/llvm-ir/variables.h>
#include <set/types.h>
#include <sys/log.h>
#include "expr.h"
BackendError impl_global_declaration(LLVMBackendCompileUnit* unit, BackendError impl_global_declaration(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope, LLVMGlobalScope* scope,
@ -54,8 +56,7 @@ BackendError impl_global_definiton(LLVMBackendCompileUnit* unit,
// FIXME: resolve initializer expression! // FIXME: resolve initializer expression!
LLVMValueRef initial_value = NULL; LLVMValueRef initial_value = NULL;
err = get_type_default_value(unit, scope, def->declaration.type, err = get_const_type_value(unit, scope, &def->initializer->impl.constant, &initial_value);
&initial_value);
if (err.kind == Success) { if (err.kind == Success) {
DEBUG("setting default value"); DEBUG("setting default value");

View File

@ -74,11 +74,11 @@ int main(int argc, char *argv[]) {
exit(0); exit(0);
} }
run_compiler(); int status = run_compiler();
if (is_option_set("print-gc-stats")) { if (is_option_set("print-gc-stats")) {
print_memory_statistics(); print_memory_statistics();
} }
return 0; return status;
} }

View File

@ -302,7 +302,7 @@ int set_get_type_impl(AST_NODE_PTR currentNode, Type **type) {
} }
print_diagnostic(&AST_get_last_node(currentNode)->location, Error, 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; return SEMANTIC_ERROR;
} }
@ -332,14 +332,14 @@ int addVarToScope(Variable *variable);
int createRef(AST_NODE_PTR currentNode, Type **reftype) { int createRef(AST_NODE_PTR currentNode, Type **reftype) {
assert(currentNode != NULL); assert(currentNode != NULL);
assert(currentNode->children->len == 1); assert(currentNode->children->len == 1);
assert(AST_get_node(currentNode, 0)->kind == AST_Type);
Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type));
Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type));
referenceType->kind = TypeKindReference; referenceType->kind = TypeKindReference;
referenceType->nodePtr = currentNode; 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) { if (signal) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
@ -496,8 +496,10 @@ char *type_to_string(Type *type) {
case TypeKindPrimitive: case TypeKindPrimitive:
if (type->impl.primitive == Int) { if (type->impl.primitive == Int) {
string = mem_strdup(MemoryNamespaceSet, "int"); string = mem_strdup(MemoryNamespaceSet, "int");
} else { } else if (type->impl.primitive == Float){
string = mem_strdup(MemoryNamespaceSet, "float"); string = mem_strdup(MemoryNamespaceSet, "float");
} else if (type->impl.primitive == Char){
string = mem_strdup(MemoryNamespaceSet, "codepoint");
} }
break; break;
case TypeKindComposite: { case TypeKindComposite: {
@ -637,6 +639,14 @@ TypeValue createTypeValue(AST_NODE_PTR currentNode) {
case AST_Float: case AST_Float:
type->impl.primitive = Float; type->impl.primitive = Float;
break; break;
case AST_Char:
// validate we have a single UTF-8 codepoint
if (g_utf8_strlen(currentNode->value, 4) != 1) {
print_diagnostic(&currentNode->location, Error, "Character must be UTF-8 codepoint");
}
type->impl.primitive = Char;
break;
default: default:
PANIC("Node is not an expression but from kind: %i", currentNode->kind); PANIC("Node is not an expression but from kind: %i", currentNode->kind);
break; 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 != TypeKindPrimitive
&& ParentExpression->impl.typecast.operand->result->kind != TypeKindReference) { && ParentExpression->impl.typecast.operand->result->kind != TypeKindReference) {
print_diagnostic(&currentNode->location, Error, "cannot cast type: `%s`", type_to_string(ParentExpression->impl.typecast.operand->result));
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
Type *target = mem_alloc(MemoryNamespaceSet, sizeof(Type)); Type *target = mem_alloc(MemoryNamespaceSet, sizeof(Type));
int status = set_get_type_impl(AST_get_node(currentNode, 1), &target); int status = set_get_type_impl(AST_get_node(currentNode, 1), &target);
if (status) { if (status) {
print_diagnostic(&AST_get_node(currentNode, 1)->location, Error, "Unknown type");
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
ParentExpression->impl.typecast.targetType = target; 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) { Expression *createExpression(AST_NODE_PTR currentNode) {
DEBUG("create Expression"); DEBUG("create Expression");
Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression));
@ -1461,6 +1473,7 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
switch (currentNode->kind) { switch (currentNode->kind) {
case AST_Int: case AST_Int:
case AST_Float: case AST_Float:
case AST_Char:
expression->kind = ExpressionKindConstant; expression->kind = ExpressionKindConstant;
expression->impl.constant = createTypeValue(currentNode); expression->impl.constant = createTypeValue(currentNode);
expression->result = expression->impl.constant.type; expression->result = expression->impl.constant.type;
@ -1584,6 +1597,14 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
return NULL; return NULL;
} }
break; 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: default:
PANIC("Node is not an expression but from kind: %i", currentNode->kind); PANIC("Node is not an expression but from kind: %i", currentNode->kind);
break; break;
@ -1595,35 +1616,48 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
} }
bool compareTypes(Type *leftType, Type *rightType) { bool compareTypes(Type *leftType, Type *rightType) {
if (leftType->kind != rightType->kind) { if (leftType->kind == TypeKindPrimitive && rightType->kind == TypeKindPrimitive) {
return FALSE;
}
if (leftType->kind == TypeKindPrimitive) {
return leftType->impl.primitive == rightType->impl.primitive; return leftType->impl.primitive == rightType->impl.primitive;
} }
if (leftType->kind == TypeKindComposite) { if (leftType->kind == TypeKindComposite) {
CompositeType leftComposite = leftType->impl.composite; if (rightType->kind == TypeKindPrimitive) {
CompositeType rightComposite = leftType->impl.composite; CompositeType leftComposite = leftType->impl.composite;
if (leftComposite.primitive != rightComposite.primitive) {
if (leftComposite.scale == 1 && leftComposite.sign == Signed) {
return leftComposite.primitive == rightType->impl.primitive;
}
return FALSE; 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; return FALSE;
}
if (leftComposite.scale != rightComposite.scale) {
return FALSE;
}
return TRUE;
} }
if (leftType->kind == TypeKindBox) { if (leftType->kind == TypeKindBox && rightType->kind == TypeKindBox) {
if (leftType->impl.box != rightType->impl.box) { if (leftType->impl.box != rightType->impl.box) {
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
if (leftType->kind == TypeKindReference) { if (leftType->kind == TypeKindReference && rightType->kind == TypeKindReference) {
bool result = compareTypes(leftType->impl.reference, rightType->impl.reference); bool result = compareTypes(leftType->impl.reference, rightType->impl.reference);
return result; return result;
} }
@ -1869,19 +1903,26 @@ int createBranch(Statement *ParentStatement, AST_NODE_PTR currentNode) {
int getFunction(const char *name, Function **function); 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 != NULL);
assert(currentNode->children->len == 2); assert(currentNode->children->len == 2);
AST_NODE_PTR argsListNode = AST_get_node(currentNode, 1); AST_NODE_PTR argsListNode = AST_get_node(currentNode, 1);
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
FunctionCall funcall;
Function *fun = NULL; Function *fun = NULL;
if (nameNode->kind == AST_Ident) { if (nameNode->kind == AST_Ident) {
int result = getFunction(nameNode->value, &fun); int result = getFunction(nameNode->value, &fun);
if (result == SEMANTIC_ERROR) { if (result == SEMANTIC_ERROR) {
print_diagnostic(&currentNode->location, Error, "Unknown function: `%s`", nameNode); print_diagnostic(&currentNode->location, Error, "Unknown function: `%s`", nameNode->value);
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
} }
@ -1902,8 +1943,8 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) {
} }
} }
funcall.function = fun; funcall->function = fun;
funcall.nodePtr = currentNode; funcall->nodePtr = currentNode;
size_t paramCount = 0; size_t paramCount = 0;
if (fun->kind == FunctionDeclarationKind) { if (fun->kind == FunctionDeclarationKind) {
@ -1935,13 +1976,20 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) {
return SEMANTIC_ERROR; 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); g_array_append_val(expressions, expr);
} }
} }
funcall.expressions = expressions; funcall->expressions = expressions;
parentStatement->kind = StatementKindFunctionCall;
parentStatement->impl.call = funcall;
return SEMANTIC_OK; return SEMANTIC_OK;
} }
@ -2017,18 +2065,37 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) {
g_array_append_val(Parentblock->statemnts, statement); g_array_append_val(Parentblock->statemnts, statement);
} }
break; break;
case AST_Call: case AST_Call: {
Statement *statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); Statement *statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement));
statement->nodePtr = currentNode; statement->nodePtr = currentNode;
statement->kind = StatementKindFunctionCall; statement->kind = StatementKindFunctionCall;
int result = createfuncall(statement, currentNode); int result = createfuncall(&statement->impl.call, currentNode);
if (result == SEMANTIC_ERROR) { if (result == SEMANTIC_ERROR) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
g_array_append_val(Parentblock->statemnts, statement); g_array_append_val(Parentblock->statemnts, statement);
break; 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: default:
PANIC("Node is not a statement"); PANIC("Node is not a statement: %s", AST_node_to_string(currentNode));
break; break;
} }
@ -2087,8 +2154,9 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) {
int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) { int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
DEBUG("start fundef"); DEBUG("start fundef");
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1);
AST_NODE_PTR statementlist = AST_get_node(currentNode, 2); AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2);
AST_NODE_PTR statementlist = AST_get_node(currentNode, 3);
FunctionDefinition fundef; FunctionDefinition fundef;
@ -2096,6 +2164,12 @@ int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
fundef.name = nameNode->value; fundef.name = nameNode->value;
fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block));
fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); 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); DEBUG("paramlistlist child count: %i", paramlistlist->children->len);
for (size_t i = 0; i < paramlistlist->children->len; i++) { for (size_t i = 0; i < paramlistlist->children->len; i++) {
@ -2195,7 +2269,49 @@ int getFunction(const char *name, Function **function) {
return SEMANTIC_ERROR; 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"); DEBUG("start fundecl");
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); 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.nodePtr = currentNode;
fundecl.name = nameNode->value; fundecl.name = nameNode->value;
fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); 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++) { 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) { 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); functionParameter = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
if (currentNode->children->len == 2) { switch (currentNode->kind) {
int signal = createFunDecl(function, currentNode); case AST_FunDecl:
if (signal) { 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; 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); mem_free(functionParameter);
@ -2358,7 +2525,7 @@ int createBox(GHashTable *boxes, AST_NODE_PTR currentNode) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
break; break;
case AST_Fun: { case AST_FunDef: {
int result = createBoxFunction(boxName, boxType, AST_get_node(boxMemberList, i)); int result = createBoxFunction(boxName, boxType, AST_get_node(boxMemberList, i));
if (result == SEMANTIC_ERROR) { if (result == SEMANTIC_ERROR) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
@ -2481,7 +2648,10 @@ Module *create_set(AST_NODE_PTR currentNode) {
DEBUG("created Box successfully"); DEBUG("created Box successfully");
break; break;
} }
case AST_Fun: { case AST_FunDef:
case AST_FunDecl:
case AST_ProcDef:
case AST_ProcDecl: {
DEBUG("start function"); DEBUG("start function");
Function *function = mem_alloc(MemoryNamespaceSet, sizeof(Function)); Function *function = mem_alloc(MemoryNamespaceSet, sizeof(Function));

30
src/set/types.c Normal file
View File

@ -0,0 +1,30 @@
//
// Created by servostar on 8/4/24.
//
#include <assert.h>
#include <set/types.h>
#include <sys/log.h>
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;
}

View File

@ -16,7 +16,9 @@ typedef enum PrimitiveType_t {
// 4 byte signed integer in two's complement // 4 byte signed integer in two's complement
Int =0, Int =0,
// 4 byte IEEE-754 single precision // 4 byte IEEE-754 single precision
Float =1 Float =1,
// 4 byte encoded UTF-8 codepoint
Char = 2,
} PrimitiveType; } PrimitiveType;
/** /**
@ -211,6 +213,7 @@ typedef struct FunctionDefinition_t {
// hashtable of parameters // hashtable of parameters
// associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) // associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration)
GArray* parameter; // Parameter GArray* parameter; // Parameter
Type* return_value;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
// body of function // body of function
Block *body; Block *body;
@ -223,6 +226,7 @@ typedef struct FunctionDeclaration_t {
// associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) // associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration)
GArray* parameter; // Parameter GArray* parameter; // Parameter
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
Type* return_value;
const char* name; const char* name;
} FunctionDeclaration; } FunctionDeclaration;
@ -236,6 +240,8 @@ typedef struct Function_t {
const char * name; const char * name;
} Function; } Function;
Parameter get_param_from_func(Function* func, size_t index);
// .------------------------------------------------. // .------------------------------------------------.
// | Variables | // | Variables |
// '------------------------------------------------' // '------------------------------------------------'
@ -435,8 +441,11 @@ typedef enum ExpressionKind_t {
ExpressionKindParameter, ExpressionKindParameter,
ExpressionKindDereference, ExpressionKindDereference,
ExpressionKindAddressOf, ExpressionKindAddressOf,
ExpressionKindFunctionCall,
} ExpressionKind; } ExpressionKind;
typedef struct FunctionCall_t FunctionCall;
typedef struct Expression_t { typedef struct Expression_t {
ExpressionKind kind; ExpressionKind kind;
// type of resulting data // type of resulting data
@ -450,6 +459,7 @@ typedef struct Expression_t {
Parameter* parameter; Parameter* parameter;
Dereference dereference; Dereference dereference;
AddressOf addressOf; AddressOf addressOf;
FunctionCall* call;
} impl; } impl;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Expression; } Expression;
@ -550,6 +560,11 @@ typedef struct Assignment_t {
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Assignment; } Assignment;
typedef struct Return_t {
Expression* value;
AST_NODE_PTR nodePtr;
} Return;
typedef enum StatementKind_t { typedef enum StatementKind_t {
StatementKindFunctionCall, StatementKindFunctionCall,
StatementKindFunctionBoxCall, StatementKindFunctionBoxCall,
@ -557,7 +572,8 @@ typedef enum StatementKind_t {
StatementKindBranch, StatementKindBranch,
StatementKindAssignment, StatementKindAssignment,
StatementKindDeclaration, StatementKindDeclaration,
StatementKindDefinition StatementKindDefinition,
StatementKindReturn
} StatementKind; } StatementKind;
typedef struct Statement_t { typedef struct Statement_t {
@ -569,6 +585,7 @@ typedef struct Statement_t {
Branch branch; Branch branch;
Assignment assignment; Assignment assignment;
Variable *variable; Variable *variable;
Return returnStmt;
} impl; } impl;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Statement; } Statement;
@ -587,6 +604,11 @@ typedef struct Module_t {
GArray* includes; GArray* includes;
} Module; } Module;
// .------------------------------------------------.
// | Utility |
// '------------------------------------------------'
Type* SET_function_get_return_type(Function* function);
// .------------------------------------------------. // .------------------------------------------------.
// | Cleanup Code | // | Cleanup Code |

View File

@ -6,6 +6,7 @@
#include <ast/ast.h> #include <ast/ast.h>
#include <sys/col.h> #include <sys/col.h>
#include <io/files.h> #include <io/files.h>
#include <glib.h>
extern int yylineno; extern int yylineno;
extern ModuleFile* current_file; extern ModuleFile* current_file;
@ -57,6 +58,8 @@
%type <node_ptr> programbody %type <node_ptr> programbody
%type <node_ptr> fundef %type <node_ptr> fundef
%type <node_ptr> fundecl %type <node_ptr> fundecl
%type <node_ptr> procdecl
%type <node_ptr> procdef
%type <node_ptr> box %type <node_ptr> box
%type <node_ptr> typedef %type <node_ptr> typedef
%type <node_ptr> exprlist %type <node_ptr> exprlist
@ -71,6 +74,7 @@
%type <node_ptr> reinterpretcast %type <node_ptr> reinterpretcast
%type <node_ptr> program %type <node_ptr> program
%type <node_ptr> storage_expr %type <node_ptr> storage_expr
%type <node_ptr> returnstmt
%token KeyInt %token KeyInt
@ -82,6 +86,7 @@
%token <string> Ident %token <string> Ident
%token <string> ValFloat %token <string> ValFloat
%token <string> ValStr %token <string> ValStr
%token <string> ValChar
%token <string> ValMultistr %token <string> ValMultistr
%token KeyShort %token KeyShort
%token KeyLong %token KeyLong
@ -120,6 +125,7 @@
%token FunLineno %token FunLineno
%token FunExtsupport %token FunExtsupport
%token Invalid %token Invalid
%token KeyReturn
/* Operator associativity */ /* Operator associativity */
/* Operators at lower line number have lower precedence */ /* Operators at lower line number have lower precedence */
@ -147,6 +153,8 @@ programbody: moduleimport {$$ = $1;}
| moduleinclude {$$ = $1;} | moduleinclude {$$ = $1;}
| fundef{$$ = $1;} | fundef{$$ = $1;}
| fundecl{$$ = $1;} | fundecl{$$ = $1;}
| procdecl{$$ = $1;}
| procdef{$$ = $1;}
| box{$$ = $1;} | box{$$ = $1;}
| definition{$$ = $1;} | definition{$$ = $1;}
| decl{$$ = $1;} | decl{$$ = $1;}
@ -156,6 +164,7 @@ programbody: moduleimport {$$ = $1;}
expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);} expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);}
| ValInt {$$ = AST_new_node(new_loc(), AST_Int, $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);} | ValMultistr {$$ = AST_new_node(new_loc(), AST_String, $1);}
| ValStr {$$ = 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);} | 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;} | typecast{$$ = $1;}
| reinterpretcast{$$ = $1;} | reinterpretcast{$$ = $1;}
| '(' expr ')' {$$=$2;} | '(' expr ')' {$$=$2;}
| funcall {$$=$1;}
| KeyRef Ident {AST_NODE_PTR addrof = AST_new_node(new_loc(), AST_AddressOf, NULL); | 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)); AST_push_node(addrof, AST_new_node(new_loc(), AST_Ident, $2));
$$ = addrof;} $$ = addrof;}
@ -189,21 +199,40 @@ argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3);
$$ = list;}; $$ = 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_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2);
AST_push_node(fun, ident); AST_push_node(fun, ident);
AST_push_node(fun, $3); AST_push_node(fun, $3);
AST_push_node(fun, $5); AST_push_node(fun, $5);
$$ = fun; $$ = 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_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2);
AST_push_node(fun, ident); AST_push_node(fun, ident);
AST_push_node(fun, $3); AST_push_node(fun, $3);
$$ = fun; $$ = fun;
DEBUG("Function");}; 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); paramlist: paramlist '(' params ')' {AST_push_node($1, $3);
$$ = $1;} $$ = $1;}
| paramlist '(' ')'{$$ = $1;} | paramlist '(' ')'{$$ = $1;}
@ -345,9 +374,14 @@ statement: assign {$$ = $1;}
| definition {$$ = $1;} | definition {$$ = $1;}
| while {$$ = $1;} | while {$$ = $1;}
| branchfull {$$ = $1;} | branchfull {$$ = $1;}
| returnstmt {$$ = $1;}
| funcall {$$ = $1;} | funcall {$$ = $1;}
| boxcall{$$ = $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); 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, $2);
AST_push_node(branch, $4); AST_push_node(branch, $4);

View File

@ -65,26 +65,31 @@ def run_check_print_node():
34 typedef 34 typedef
35 box 35 box
36 fun 36 fun
37 value 37 fun
38 list 38 fun
39 expr list 39 fun
40 arg list 40 value
41 param list 41 list
42 stmt list 42 expr list
43 ident list 43 arg list
44 value 44 param list
45 type 45 stmt list
46 value 46 ident list
47 value 47 value
48 value 48 type
49 - 49 value
50 parameter 50 value
51 value 51 value
52 parameter-declaration 52 -
53 address of 53 parameter
54 deref 54 value
55 ref 55 parameter-declaration
56 value 56 address of
57 deref
58 ref
59 value
60 value
61 ret
""" == p.stdout """ == p.stdout
@ -94,7 +99,7 @@ def run_check_print_graphviz():
info("creating temporary folder...") info("creating temporary folder...")
if not os.path.exists("tmp"): if not os.path.exists("tmp"):
os.mkdir("tmp") os.makedirs("tmp", exist_ok=True)
info("cleaning temporary folder...") info("cleaning temporary folder...")

View File

@ -1,28 +1,27 @@
import "std" import "std"
fun cstrlen(in cstr: str)(out u32: len) { fun u32:cstrlen(in cstr: str) {
u32: idx = 0 as u32 u32: idx = 0 as u32
while !(str[idx] == 0) { while !(str[idx] == 0) {
idx = idx + 1 idx = idx + 1 as u32
} }
len = idx ret idx
} }
fun printcstr(in cstr: msg) { fun printcstr(in cstr: msg) {
u32: len = 0 u32: len = cstrlen(msg)
cstrlen(msg)(len)
handle: stdout = 0 handle: stdout = getStdoutHandle()
getStdoutHandle()(stdout)
u32: written = 0 writeBytes(stdout, msg, len)
writeBytes(stdout, msg, len)(written)
} }
fun main() { fun int:main() {
cstr: msg = "Hello, world!\n" cstr: msg = "Hello, world!\n"
printcstr(msg) printcstr(msg)
ret 0
} }

View File

@ -1,28 +1,27 @@
import "std" import "std"
fun cstrlen(in cstr: str)(out u32: len) { fun u32:cstrlen(in cstr: str) {
u32: idx = 0 as u32 u32: idx = 0 as u32
while !(str[idx] == 0) { while !(str[idx] == 0) {
idx = idx + 1 idx = idx + 1 as u32
} }
len = idx ret idx
} }
fun printcstr(in cstr: msg) { fun printcstr(in cstr: msg) {
u32: len = 0 u32: len = cstrlen(msg)
cstrlen(msg)(len)
handle: stdout = 0 handle: stdout = getStdoutHandle()
getStdoutHandle()(stdout)
u32: written = 0 writeBytes(stdout, msg, len)
writeBytes(stdout, msg, len)(written)
} }
fun main() { fun int:main() {
cstr: msg = "Hello, world!\n" cstr: msg = "Hello, world!\n"
printcstr(msg) printcstr(msg)
ret 0
} }

View File

@ -1,28 +1,25 @@
import "std" import "std"
fun cstrlen(in cstr: str)(out u32: len) { fun u32:cstrlen(in cstr: str) {
u32: idx = 0 as u32 u32: idx = 0 as u32
while !(str[idx] == 0) { while !(str[idx] == 0) {
idx = idx + 1 idx = idx + 1 as u32
} }
len = idx ret idx
} }
fun printcstr(in cstr: msg) { fun printcstr(in cstr: msg) {
u32: len = 0 u32: len = cstrlen(msg)
cstrlen(msg)(len)
handle: stdout = 0 handle: stdout = getStdoutHandle()
getStdoutHandle()(stdout)
u32: written = 0 writeBytes(stdout, msg, len)
writeBytes(stdout, msg, len)(written)
} }
fun main() { fun int:main() {
cstr: msg = "Hello, world!\n" printcstr("Hello, world!\n")
printcstr(msg) ret 0
} }

View File

@ -1,4 +1,4 @@
fun main(out int: ret) { fun int:main() {
ret = 56 as int ret 56 as int
} }

View File

@ -22,7 +22,7 @@ def check_abort():
logging.basicConfig(level=logging.INFO) 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 assert p.returncode == 1

View File

@ -4,6 +4,6 @@ include(CTest)
# CTEST 1 # CTEST 1
# test if the program successfully reads the project config # test if the program successfully reads the project config
#add_test(NAME project_build add_test(NAME project_build
# WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/project WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/project
# COMMAND python ${GEMSTONE_TEST_DIR}/project/test_project.py) COMMAND python ${GEMSTONE_TEST_DIR}/project/test_project.py)

33
tests/stdlib/build.toml Normal file
View File

@ -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 <sven.vogel123@web.de>" ]
[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

25
tests/stdlib/src/echo.gsc Normal file
View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}