Merge pull request #130 from Servostar/129-test-standard-library
129 test standard library
This commit is contained in:
commit
ed728c8042
|
@ -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}
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,3 +14,6 @@ include "io.gsc"
|
|||
|
||||
# memory management
|
||||
include "mem.gsc"
|
||||
|
||||
# mathematical utilities
|
||||
include "math.gsc"
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(¶m), 0, &llvm_arg);
|
||||
|
||||
if (err.kind != Success) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_parameter_out(¶m)) {
|
||||
if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) {
|
||||
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false);
|
||||
LLVMTypeRef llvm_type = NULL;
|
||||
get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type);
|
||||
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
arguments[i] = llvm_arg;
|
||||
}
|
||||
}
|
||||
|
||||
if (err.kind == Success) {
|
||||
LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, call->function->name);
|
||||
|
||||
if (llvm_func == NULL) {
|
||||
return new_backend_impl_error(Implementation, NULL, "no declared function");
|
||||
}
|
||||
|
||||
LLVMTypeRef llvm_func_type = g_hash_table_lookup(scope->func_scope->global_scope->functions, call->function->name);
|
||||
|
||||
LLVMValueRef value = LLVMBuildCall2(builder, llvm_func_type, llvm_func, arguments, call->expressions->len,
|
||||
"");
|
||||
|
||||
if (NULL != return_value) {
|
||||
*return_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -55,7 +55,7 @@ BackendError impl_storage_expr(
|
|||
case StorageExprKindDereference:
|
||||
|
||||
LLVMValueRef index = NULL;
|
||||
err = impl_expr(unit, scope, builder, expr->impl.dereference.index, false, &index);
|
||||
err = impl_expr(unit, scope, builder, expr->impl.dereference.index, false, 0, &index);
|
||||
if (err.kind != Success) {
|
||||
return err;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ BackendError impl_storage_expr(
|
|||
}
|
||||
}
|
||||
|
||||
if (expr->impl.dereference.array->kind == StorageExprKindDereference) {
|
||||
if (true) {
|
||||
LLVMTypeRef deref_type = NULL;
|
||||
err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type);
|
||||
if (err.kind != Success) {
|
||||
|
@ -111,7 +111,7 @@ BackendError impl_assign_stmt(
|
|||
DEBUG("implementing assignment for variable: %p", assignment);
|
||||
|
||||
LLVMValueRef llvm_value = NULL;
|
||||
err = impl_expr(unit, scope, builder, assignment->value, false, &llvm_value);
|
||||
err = impl_expr(unit, scope, builder, assignment->value, false, 0, &llvm_value);
|
||||
if (err.kind != Success) {
|
||||
return err;
|
||||
}
|
||||
|
@ -141,6 +141,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
|
|||
|
||||
LLVMBasicBlockRef end_previous_block = *llvm_start_block;
|
||||
|
||||
bool terminated = false;
|
||||
|
||||
for (size_t i = 0; i < block->statemnts->len; i++) {
|
||||
DEBUG("building block statement %d of %d", i, block->statemnts->len);
|
||||
Statement* stmt = g_array_index(block->statemnts, Statement*, i);
|
||||
|
@ -152,12 +154,20 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (llvm_next_end_block != NULL) {
|
||||
terminated = LLVMGetBasicBlockTerminator(end_previous_block);
|
||||
if (llvm_next_end_block != NULL && !terminated) {
|
||||
LLVMPositionBuilderAtEnd(builder, end_previous_block);
|
||||
LLVMBuildBr(builder, llvm_next_start_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(builder, llvm_next_end_block);
|
||||
end_previous_block = llvm_next_end_block;
|
||||
}
|
||||
|
||||
if (terminated) {
|
||||
end_previous_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
|
||||
"ret.after");
|
||||
LLVMPositionBuilderAtEnd(builder, end_previous_block);
|
||||
}
|
||||
}
|
||||
|
||||
*llvm_end_block = end_previous_block;
|
||||
|
@ -182,7 +192,7 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
|
|||
LLVMPositionBuilderAtEnd(builder, while_cond_block);
|
||||
// Resolve condition in block to a variable
|
||||
LLVMValueRef cond_result = NULL;
|
||||
err = impl_expr(unit, scope, builder, (Expression *) while_stmt->conditon, FALSE, &cond_result);
|
||||
err = impl_expr(unit, scope, builder, (Expression *) while_stmt->conditon, FALSE, 0, &cond_result);
|
||||
if (err.kind != Success) {
|
||||
return err;
|
||||
}
|
||||
|
@ -213,74 +223,6 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
|
|||
return err;
|
||||
}
|
||||
|
||||
gboolean is_parameter_out(Parameter *param) {
|
||||
gboolean is_out = FALSE;
|
||||
|
||||
if (param->kind == ParameterDeclarationKind) {
|
||||
is_out = param->impl.declaration.qualifier == Out || param->impl.declaration.qualifier == InOut;
|
||||
} else {
|
||||
is_out = param->impl.definiton.declaration.qualifier == Out ||
|
||||
param->impl.definiton.declaration.qualifier == InOut;
|
||||
}
|
||||
|
||||
return is_out;
|
||||
}
|
||||
|
||||
BackendError impl_func_call(LLVMBackendCompileUnit *unit,
|
||||
LLVMBuilderRef builder, LLVMLocalScope *scope,
|
||||
const FunctionCall *call) {
|
||||
DEBUG("implementing function call...");
|
||||
BackendError err = SUCCESS;
|
||||
|
||||
LLVMValueRef* arguments = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef) * call->expressions->len);
|
||||
|
||||
for (size_t i = 0; i < call->expressions->len; i++) {
|
||||
Expression *arg = g_array_index(call->expressions, Expression*, i);
|
||||
|
||||
GArray* param_list;
|
||||
if (call->function->kind == FunctionDeclarationKind) {
|
||||
param_list = call->function->impl.definition.parameter;
|
||||
} else {
|
||||
param_list = call->function->impl.declaration.parameter;
|
||||
}
|
||||
|
||||
Parameter param = g_array_index(param_list, Parameter, i);
|
||||
|
||||
LLVMValueRef llvm_arg = NULL;
|
||||
err = impl_expr(unit, scope, builder, arg, is_parameter_out(¶m), &llvm_arg);
|
||||
|
||||
if (err.kind != Success) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_parameter_out(¶m)) {
|
||||
if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) {
|
||||
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false);
|
||||
LLVMTypeRef llvm_type = NULL;
|
||||
get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type);
|
||||
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
arguments[i] = llvm_arg;
|
||||
}
|
||||
|
||||
if (err.kind == Success) {
|
||||
LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, call->function->name);
|
||||
|
||||
if (llvm_func == NULL) {
|
||||
return new_backend_impl_error(Implementation, NULL, "no declared function");
|
||||
}
|
||||
|
||||
LLVMTypeRef llvm_func_type = g_hash_table_lookup(scope->func_scope->global_scope->functions, call->function->name);
|
||||
|
||||
LLVMBuildCall2(builder, llvm_func_type, llvm_func, arguments, call->expressions->len,
|
||||
"");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
BackendError
|
||||
impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Expression *cond,
|
||||
const Block *block, LLVMBasicBlockRef *cond_block, LLVMBasicBlockRef *start_body_block, LLVMBasicBlockRef *end_body_block,
|
||||
|
@ -291,7 +233,7 @@ impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalS
|
|||
"stmt.branch.cond");
|
||||
LLVMPositionBuilderAtEnd(builder, *cond_block);
|
||||
// Resolve condition in block to a variable
|
||||
err = impl_expr(unit, scope, builder, cond, FALSE, llvm_cond);
|
||||
err = impl_expr(unit, scope, builder, cond, FALSE, 0, llvm_cond);
|
||||
if (err.kind == Success) {
|
||||
// build body of loop
|
||||
err = impl_basic_block(unit, builder, scope, block, start_body_block, end_body_block);
|
||||
|
@ -426,6 +368,23 @@ BackendError impl_decl(LLVMBackendCompileUnit *unit,
|
|||
return err;
|
||||
}
|
||||
|
||||
BackendError impl_return(LLVMBackendCompileUnit *unit,
|
||||
LLVMBuilderRef builder,
|
||||
LLVMLocalScope *scope,
|
||||
Return *returnStmt) {
|
||||
BackendError err = SUCCESS;
|
||||
|
||||
LLVMValueRef expr = NULL;
|
||||
err = impl_expr(unit, scope, builder, returnStmt->value, false, 0, &expr);
|
||||
if (err.kind != Success) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LLVMBuildRet(builder, expr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
BackendError impl_def(LLVMBackendCompileUnit *unit,
|
||||
LLVMBuilderRef builder,
|
||||
LLVMLocalScope *scope,
|
||||
|
@ -441,7 +400,7 @@ BackendError impl_def(LLVMBackendCompileUnit *unit,
|
|||
}
|
||||
|
||||
LLVMValueRef initial_value = NULL;
|
||||
err = impl_expr(unit, scope, builder, def->initializer, FALSE, &initial_value);
|
||||
err = impl_expr(unit, scope, builder, def->initializer, FALSE, 0, &initial_value);
|
||||
if (err.kind != Success) {
|
||||
return err;
|
||||
}
|
||||
|
@ -496,7 +455,10 @@ BackendError impl_stmt(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLV
|
|||
err = impl_while(unit, builder, scope, llvm_start_block, llvm_end_block, &stmt->impl.whileLoop);
|
||||
break;
|
||||
case StatementKindFunctionCall:
|
||||
err = impl_func_call(unit, builder, scope, &stmt->impl.call);
|
||||
err = impl_func_call(unit, builder, scope, &stmt->impl.call, NULL);
|
||||
break;
|
||||
case StatementKindReturn:
|
||||
err = impl_return(unit, builder, scope, &stmt->impl.returnStmt);
|
||||
break;
|
||||
default:
|
||||
err = new_backend_impl_error(Implementation, NULL, "Unexpected statement kind");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
246
src/set/set.c
246
src/set/set.c
|
@ -302,7 +302,7 @@ int set_get_type_impl(AST_NODE_PTR currentNode, Type **type) {
|
|||
}
|
||||
|
||||
print_diagnostic(&AST_get_last_node(currentNode)->location, Error,
|
||||
"Expected either primitive or composite type");
|
||||
"Expected either primitive or composite type: `%s`", AST_get_last_node(currentNode)->value);
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
|
@ -332,14 +332,14 @@ int addVarToScope(Variable *variable);
|
|||
int createRef(AST_NODE_PTR currentNode, Type **reftype) {
|
||||
assert(currentNode != NULL);
|
||||
assert(currentNode->children->len == 1);
|
||||
assert(AST_get_node(currentNode, 0)->kind == AST_Type);
|
||||
|
||||
Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type));
|
||||
Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type));
|
||||
referenceType->kind = TypeKindReference;
|
||||
referenceType->nodePtr = currentNode;
|
||||
|
||||
int signal = set_get_type_impl(AST_get_node(currentNode, 0), &type);
|
||||
AST_NODE_PTR ast_type = AST_get_node(currentNode, 0);
|
||||
int signal = set_get_type_impl(ast_type, &type);
|
||||
if (signal) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
@ -496,8 +496,10 @@ char *type_to_string(Type *type) {
|
|||
case TypeKindPrimitive:
|
||||
if (type->impl.primitive == Int) {
|
||||
string = mem_strdup(MemoryNamespaceSet, "int");
|
||||
} else {
|
||||
} else if (type->impl.primitive == Float){
|
||||
string = mem_strdup(MemoryNamespaceSet, "float");
|
||||
} else if (type->impl.primitive == Char){
|
||||
string = mem_strdup(MemoryNamespaceSet, "codepoint");
|
||||
}
|
||||
break;
|
||||
case TypeKindComposite: {
|
||||
|
@ -637,6 +639,14 @@ TypeValue createTypeValue(AST_NODE_PTR currentNode) {
|
|||
case AST_Float:
|
||||
type->impl.primitive = Float;
|
||||
break;
|
||||
case AST_Char:
|
||||
// validate we have a single UTF-8 codepoint
|
||||
if (g_utf8_strlen(currentNode->value, 4) != 1) {
|
||||
print_diagnostic(¤tNode->location, Error, "Character must be UTF-8 codepoint");
|
||||
}
|
||||
|
||||
type->impl.primitive = Char;
|
||||
break;
|
||||
default:
|
||||
PANIC("Node is not an expression but from kind: %i", currentNode->kind);
|
||||
break;
|
||||
|
@ -1331,13 +1341,13 @@ int createTypeCast(Expression *ParentExpression, AST_NODE_PTR currentNode) {
|
|||
&& ParentExpression->impl.typecast.operand->result->kind != TypeKindPrimitive
|
||||
&& ParentExpression->impl.typecast.operand->result->kind != TypeKindReference) {
|
||||
|
||||
print_diagnostic(¤tNode->location, Error, "cannot cast type: `%s`", type_to_string(ParentExpression->impl.typecast.operand->result));
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
Type *target = mem_alloc(MemoryNamespaceSet, sizeof(Type));
|
||||
int status = set_get_type_impl(AST_get_node(currentNode, 1), &target);
|
||||
if (status) {
|
||||
print_diagnostic(&AST_get_node(currentNode, 1)->location, Error, "Unknown type");
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
ParentExpression->impl.typecast.targetType = target;
|
||||
|
@ -1453,6 +1463,8 @@ IO_Qualifier getParameterQualifier(Parameter *parameter) {
|
|||
}
|
||||
}
|
||||
|
||||
int createfuncall(FunctionCall* funcall, AST_NODE_PTR currentNode);
|
||||
|
||||
Expression *createExpression(AST_NODE_PTR currentNode) {
|
||||
DEBUG("create Expression");
|
||||
Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression));
|
||||
|
@ -1461,6 +1473,7 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
|
|||
switch (currentNode->kind) {
|
||||
case AST_Int:
|
||||
case AST_Float:
|
||||
case AST_Char:
|
||||
expression->kind = ExpressionKindConstant;
|
||||
expression->impl.constant = createTypeValue(currentNode);
|
||||
expression->result = expression->impl.constant.type;
|
||||
|
@ -1584,6 +1597,14 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
|
|||
return NULL;
|
||||
}
|
||||
break;
|
||||
case AST_Call:
|
||||
expression->kind = ExpressionKindFunctionCall;
|
||||
expression->impl.call = mem_alloc(MemoryNamespaceSet, sizeof(FunctionCall));
|
||||
if (createfuncall(expression->impl.call, currentNode) == SEMANTIC_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
expression->result = SET_function_get_return_type(expression->impl.call->function);
|
||||
break;
|
||||
default:
|
||||
PANIC("Node is not an expression but from kind: %i", currentNode->kind);
|
||||
break;
|
||||
|
@ -1595,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(¤tNode->location, Error, "Unknown function: `%s`", nameNode);
|
||||
print_diagnostic(¤tNode->location, Error, "Unknown function: `%s`", nameNode->value);
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -1902,8 +1943,8 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) {
|
|||
}
|
||||
}
|
||||
|
||||
funcall.function = fun;
|
||||
funcall.nodePtr = currentNode;
|
||||
funcall->function = fun;
|
||||
funcall->nodePtr = currentNode;
|
||||
|
||||
size_t paramCount = 0;
|
||||
if (fun->kind == FunctionDeclarationKind) {
|
||||
|
@ -1935,13 +1976,20 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) {
|
|||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
Parameter param = get_param_from_func(fun, i + currentExprList->children->len - j - 1);
|
||||
|
||||
if (!compareTypes(expr->result, param.impl.declaration.type)) {
|
||||
print_diagnostic(&expr_node->location, Error,
|
||||
"parameter and argument `%s` type mismatch, expected `%s` got `%s`",
|
||||
param.name, type_to_string(param.impl.declaration.type), type_to_string(expr->result));
|
||||
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
g_array_append_val(expressions, expr);
|
||||
}
|
||||
}
|
||||
funcall.expressions = expressions;
|
||||
|
||||
parentStatement->kind = StatementKindFunctionCall;
|
||||
parentStatement->impl.call = funcall;
|
||||
funcall->expressions = expressions;
|
||||
return SEMANTIC_OK;
|
||||
}
|
||||
|
||||
|
@ -2017,18 +2065,37 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) {
|
|||
g_array_append_val(Parentblock->statemnts, statement);
|
||||
}
|
||||
break;
|
||||
case AST_Call:
|
||||
case AST_Call: {
|
||||
Statement *statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement));
|
||||
statement->nodePtr = currentNode;
|
||||
statement->kind = StatementKindFunctionCall;
|
||||
int result = createfuncall(statement, currentNode);
|
||||
int result = createfuncall(&statement->impl.call, currentNode);
|
||||
if (result == SEMANTIC_ERROR) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
g_array_append_val(Parentblock->statemnts, statement);
|
||||
break;
|
||||
}
|
||||
case AST_Return: {
|
||||
Statement *statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement));
|
||||
statement->nodePtr = currentNode;
|
||||
statement->kind = StatementKindReturn;
|
||||
|
||||
AST_NODE_PTR expr_node = AST_get_node(currentNode, 0);
|
||||
statement->impl.returnStmt.value = createExpression(expr_node);
|
||||
statement->impl.returnStmt.nodePtr = currentNode;
|
||||
|
||||
if (statement->impl.returnStmt.value == NULL) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
// TODO: compare result and function return type
|
||||
|
||||
g_array_append_val(Parentblock->statemnts, statement);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PANIC("Node is not a statement");
|
||||
PANIC("Node is not a statement: %s", AST_node_to_string(currentNode));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2087,8 +2154,9 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) {
|
|||
int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
||||
DEBUG("start fundef");
|
||||
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
|
||||
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1);
|
||||
AST_NODE_PTR statementlist = AST_get_node(currentNode, 2);
|
||||
AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1);
|
||||
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2);
|
||||
AST_NODE_PTR statementlist = AST_get_node(currentNode, 3);
|
||||
|
||||
FunctionDefinition fundef;
|
||||
|
||||
|
@ -2096,6 +2164,12 @@ int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
|||
fundef.name = nameNode->value;
|
||||
fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block));
|
||||
fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter));
|
||||
fundef.return_value = NULL;
|
||||
|
||||
if (set_get_type_impl(return_value_node, &fundef.return_value) == SEMANTIC_ERROR) {
|
||||
print_diagnostic(&return_value_node->location, Error, "Unknown return value type");
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
DEBUG("paramlistlist child count: %i", paramlistlist->children->len);
|
||||
for (size_t i = 0; i < paramlistlist->children->len; i++) {
|
||||
|
@ -2195,7 +2269,49 @@ int getFunction(const char *name, Function **function) {
|
|||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
||||
int createProcDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
||||
DEBUG("start fundef");
|
||||
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
|
||||
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1);
|
||||
AST_NODE_PTR statementlist = AST_get_node(currentNode, 2);
|
||||
|
||||
FunctionDefinition fundef;
|
||||
|
||||
fundef.nodePtr = currentNode;
|
||||
fundef.name = nameNode->value;
|
||||
fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block));
|
||||
fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter));
|
||||
fundef.return_value = NULL;
|
||||
|
||||
DEBUG("paramlistlist child count: %i", paramlistlist->children->len);
|
||||
for (size_t i = 0; i < paramlistlist->children->len; i++) {
|
||||
|
||||
//all parameterlists
|
||||
AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i);
|
||||
DEBUG("paramlist child count: %i", paramlist->children->len);
|
||||
for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) {
|
||||
|
||||
DEBUG("param child count: %i", AST_get_node(paramlist, j)->children->len);
|
||||
|
||||
if (createParam(fundef.parameter, AST_get_node(paramlist, j))) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
}
|
||||
DEBUG("End of Paramlist");
|
||||
}
|
||||
|
||||
if (fillBlock(fundef.body, statementlist)) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
Parentfunction->nodePtr = currentNode;
|
||||
Parentfunction->kind = FunctionDefinitionKind;
|
||||
Parentfunction->impl.definition = fundef;
|
||||
Parentfunction->name = fundef.name;
|
||||
return SEMANTIC_OK;
|
||||
}
|
||||
|
||||
int createProcDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
||||
DEBUG("start fundecl");
|
||||
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
|
||||
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1);
|
||||
|
@ -2205,6 +2321,46 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
|||
fundecl.nodePtr = currentNode;
|
||||
fundecl.name = nameNode->value;
|
||||
fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter));
|
||||
fundecl.return_value = NULL;
|
||||
|
||||
for (size_t i = 0; i < paramlistlist->children->len; i++) {
|
||||
|
||||
//all parameter lists
|
||||
AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i);
|
||||
|
||||
for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) {
|
||||
AST_NODE_PTR param = AST_get_node(paramlist, j);
|
||||
if (createParam(fundecl.parameter, param)) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Parentfunction->nodePtr = currentNode;
|
||||
Parentfunction->kind = FunctionDeclarationKind;
|
||||
Parentfunction->impl.declaration = fundecl;
|
||||
Parentfunction->name = fundecl.name;
|
||||
|
||||
return SEMANTIC_OK;
|
||||
}
|
||||
|
||||
int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
||||
DEBUG("start fundecl");
|
||||
AST_NODE_PTR nameNode = AST_get_node(currentNode, 0);
|
||||
AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1);
|
||||
AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2);
|
||||
|
||||
FunctionDeclaration fundecl;
|
||||
|
||||
fundecl.nodePtr = currentNode;
|
||||
fundecl.name = nameNode->value;
|
||||
fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter));
|
||||
fundecl.return_value = NULL;
|
||||
|
||||
if (set_get_type_impl(return_value_node, &fundecl.return_value) == SEMANTIC_ERROR) {
|
||||
print_diagnostic(&return_value_node->location, Error, "Unknown return value type");
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < paramlistlist->children->len; i++) {
|
||||
|
||||
|
@ -2228,21 +2384,32 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
|
|||
}
|
||||
|
||||
int createFunction(Function *function, AST_NODE_PTR currentNode) {
|
||||
assert(currentNode->kind == AST_Fun);
|
||||
functionParameter = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
|
||||
|
||||
if (currentNode->children->len == 2) {
|
||||
int signal = createFunDecl(function, currentNode);
|
||||
if (signal) {
|
||||
switch (currentNode->kind) {
|
||||
case AST_FunDecl:
|
||||
if (createFunDecl(function, currentNode)) {
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
} 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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 |
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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...")
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
fun main(out int: ret) {
|
||||
ret = 56 as int
|
||||
fun int:main() {
|
||||
ret 56 as int
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue