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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -4,11 +4,11 @@
#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);

View File

@ -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 <malloc.h>
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);
}

View File

@ -14,3 +14,6 @@ include "io.gsc"
# memory management
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_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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@
#include <set/types.h>
#include <sys/log.h>
#include <mem/cache.h>
#include <llvm/llvm-ir/expr.h>
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);
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);
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(&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,
GHashTable* variables);
BackendError impl_func_call(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
const FunctionCall *call,
LLVMValueRef* return_value);
#endif // LLVM_BACKEND_FUNC_H_

View File

@ -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(&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
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");

View File

@ -6,16 +6,11 @@
#include <set/types.h>
#include <sys/log.h>
#include <set/set.h>
#include <stdlib.h>
#include <mem/cache.h>
#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;

View File

@ -1,11 +1,13 @@
#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/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,
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");

View File

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

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,
"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(&currentNode->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(&currentNode->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,15 +1616,25 @@ 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) {
if (rightType->kind == TypeKindPrimitive) {
CompositeType leftComposite = leftType->impl.composite;
CompositeType rightComposite = 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;
}
@ -1616,14 +1647,17 @@ bool compareTypes(Type *leftType, Type *rightType) {
return TRUE;
}
if (leftType->kind == TypeKindBox) {
return FALSE;
}
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(&currentNode->location, Error, "Unknown function: `%s`", nameNode);
print_diagnostic(&currentNode->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;
}
} else if (currentNode->children->len == 3) {
int signal = createFunDef(function, currentNode);
if (signal) {
break;
case AST_FunDef:
if (createFunDef(function, currentNode)) {
return SEMANTIC_ERROR;
}
} else {
PANIC("function should have 2 or 3 children");
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;
}
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));

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

View File

@ -6,6 +6,7 @@
#include <ast/ast.h>
#include <sys/col.h>
#include <io/files.h>
#include <glib.h>
extern int yylineno;
extern ModuleFile* current_file;
@ -57,6 +58,8 @@
%type <node_ptr> programbody
%type <node_ptr> fundef
%type <node_ptr> fundecl
%type <node_ptr> procdecl
%type <node_ptr> procdef
%type <node_ptr> box
%type <node_ptr> typedef
%type <node_ptr> exprlist
@ -71,6 +74,7 @@
%type <node_ptr> reinterpretcast
%type <node_ptr> program
%type <node_ptr> storage_expr
%type <node_ptr> returnstmt
%token KeyInt
@ -82,6 +86,7 @@
%token <string> Ident
%token <string> ValFloat
%token <string> ValStr
%token <string> ValChar
%token <string> 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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
}