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