Merge remote-tracking branch 'origin/main' into 6-add-mechanism-to-read-and-globally-save-options
# Conflicts: # CMakeLists.txt # src/main.c
This commit is contained in:
commit
0c722f3635
|
@ -1,14 +1,14 @@
|
|||
name: "Build check gemstone in SDK"
|
||||
run-name: SDK build check to ${{ inputs.deploy_target }} by @${{ github.actor }}
|
||||
on: [push, pull_request]
|
||||
env:
|
||||
SDK: 0.2.3-alpine-3.19.1
|
||||
jobs:
|
||||
build-check-sdk:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup repository
|
||||
run: git submodule init && git submodule update
|
||||
- name: Setup SDK
|
||||
run: docker pull servostar/gemstone:sdk-"$SDK" && docker build --tag gemstone:devkit-"$SDK" .
|
||||
run: source ./.env && docker pull servostar/gemstone:sdk-"$SDK"
|
||||
- name: Compile
|
||||
run: docker run gemstone:devkit-"$SDK" sh run-check-test.sh
|
||||
run: set -a && source ./.env && sh run-docker-build.sh
|
||||
|
|
|
@ -61,11 +61,18 @@ set(YACC_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.y)
|
|||
set(YACC_GENERATED_SOURCE_FILE ${PROJECT_SOURCE_DIR}/src/yacc/parser.tab.c)
|
||||
|
||||
add_custom_command(OUTPUT ${YACC_GENERATED_SOURCE_FILE}
|
||||
COMMAND yacc
|
||||
COMMAND bison
|
||||
ARGS -Wno-yacc -Wcounterexamples -d -o ${YACC_GENERATED_SOURCE_FILE} ${YACC_SOURCE_FILE}
|
||||
COMMENT "generate C source file for parser"
|
||||
VERBATIM)
|
||||
|
||||
# ------------------------------------------------ #
|
||||
# Setup Glib 2.0 #
|
||||
# ------------------------------------------------ #
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
|
||||
# ------------------------------------------------ #
|
||||
# TOML-C99 #
|
||||
# ------------------------------------------------ #
|
||||
|
@ -84,17 +91,21 @@ set_target_properties(tomlc99
|
|||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dep/tomlc99)
|
||||
|
||||
|
||||
# ------------------------------------------------ #
|
||||
# Source #
|
||||
# ------------------------------------------------ #
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES src/*.c)
|
||||
|
||||
# define default compile flags
|
||||
if (MSVC)
|
||||
set(FLAGS /Wall /W3 /permissive)
|
||||
else()
|
||||
set(FLAGS -Wall -Wextra -Wconversion -Wpedantic)
|
||||
set(FLAGS -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------ #
|
||||
|
@ -111,6 +122,8 @@ set_target_properties(release
|
|||
OUTPUT_NAME "gsc"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/release)
|
||||
|
||||
target_link_libraries(release PkgConfig::GLIB)
|
||||
|
||||
target_link_libraries(release tomlc99)
|
||||
|
||||
# FIXME: cannot compile with /O2 because of /RTC1 flag
|
||||
|
@ -145,6 +158,8 @@ set_target_properties(debug
|
|||
OUTPUT_NAME "gsc"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/debug)
|
||||
|
||||
target_link_libraries(debug PkgConfig::GLIB)
|
||||
|
||||
target_link_libraries(debug tomlc99)
|
||||
|
||||
if (MSVC)
|
||||
|
@ -176,6 +191,8 @@ set_target_properties(check
|
|||
OUTPUT_NAME "gsc"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/check)
|
||||
|
||||
target_link_libraries(check PkgConfig::GLIB)
|
||||
|
||||
target_link_libraries(check tomlc99)
|
||||
|
||||
if (MSVC)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
FROM servostar/gemstone:sdk-0.2.3-alpine-3.19.1
|
||||
FROM servostar/gemstone:sdk-0.2.4-alpine-3.19.1
|
||||
LABEL authors="servostar"
|
||||
LABEL version="0.2.3"
|
||||
LABEL version="0.2.4"
|
||||
LABEL description="docker image for setting up the build pipeline on SDK"
|
||||
LABEL website="https://github.com/Servostar/gemstone"
|
||||
|
||||
|
@ -8,5 +8,7 @@ COPY --chown=lorang src /home/lorang/src
|
|||
COPY --chown=lorang tests /home/lorang/tests
|
||||
COPY --chown=lorang CMakeLists.txt /home/lorang/
|
||||
COPY --chown=lorang run-check-test.sh /home/lorang/
|
||||
COPY --chown=lorang .env /home/lorang/
|
||||
COPY --chown=lorang run-docker-build.sh /home/lorang/
|
||||
|
||||
RUN cmake .
|
||||
|
|
|
@ -9,6 +9,8 @@ echo "+--------------------------------------+"
|
|||
echo "| BUILDING all TARGETS |"
|
||||
echo "+--------------------------------------+"
|
||||
|
||||
cmake .
|
||||
|
||||
make -B
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "===> failed to build targets"
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Sven Vogel
|
||||
# Created: 17.05.2024
|
||||
# Description: Builds the Dockerfile for SDK and DEVKIT
|
||||
|
||||
echo "+--------------------------------------+"
|
||||
echo "| CHECKING prelude |"
|
||||
echo "+--------------------------------------+"
|
||||
|
||||
if [ -z "$SDK" ]; then
|
||||
echo "no SDK specified, sourcing .env"
|
||||
source ./.env
|
||||
|
||||
if [ -z "$SDK" ]; then
|
||||
echo "no SDK specified"
|
||||
exit 1
|
||||
else
|
||||
echo "using SDK $SDK"
|
||||
fi
|
||||
|
||||
else
|
||||
echo "using SDK $SDK"
|
||||
fi
|
||||
|
||||
echo "+--------------------------------------+"
|
||||
echo "| BUILDING SDK |"
|
||||
echo "+--------------------------------------+"
|
||||
|
||||
docker build --tag servostar/gemstone:sdk-"$SDK" sdk/.
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "===> failed to build sdk"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "+--------------------------------------+"
|
||||
echo "| BUILDING DEVKIT |"
|
||||
echo "+--------------------------------------+"
|
||||
|
||||
docker build --tag servostar/gemstone:devkit-"$SDK" .
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "===> failed to build devkit"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "+--------------------------------------+"
|
||||
echo "| RUNNING check test |"
|
||||
echo "+--------------------------------------+"
|
||||
|
||||
docker run servostar/gemstone:devkit-"$SDK" sh run-check-test.sh
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "===> failed to run build or checks"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "+--------------------------------------+"
|
||||
echo "| DONE |"
|
||||
echo "+--------------------------------------+"
|
|
@ -1,11 +1,11 @@
|
|||
FROM alpine:3.19.1
|
||||
LABEL authors="servostar"
|
||||
LABEL version="0.2.3"
|
||||
LABEL version="0.2.4"
|
||||
LABEL description="base image for building the gemstone programming language compiler"
|
||||
LABEL website="https://github.com/Servostar/gemstone"
|
||||
|
||||
# install dependencies
|
||||
RUN apk add build-base gcc make cmake bison flex git python3 graphviz
|
||||
RUN apk add build-base gcc make cmake bison flex git python3 graphviz glib glib-dev
|
||||
|
||||
# create user for build
|
||||
RUN adduser --disabled-password lorang
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <sys/log.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value) {
|
||||
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) {
|
||||
DEBUG("creating new AST node: %d \"%s\"", kind, value);
|
||||
assert(kind < AST_ELEMENT_COUNT);
|
||||
|
||||
|
@ -23,6 +23,7 @@ struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value
|
|||
node->child_count = 0;
|
||||
node->kind = kind;
|
||||
node->value = value;
|
||||
node->location = location;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -33,8 +34,8 @@ void AST_init() {
|
|||
DEBUG("initializing global syntax tree...");
|
||||
|
||||
INFO("filling lookup table...");
|
||||
|
||||
lookup_table[AST_Stmt] = "stmt";
|
||||
lookup_table[AST_Module] = "module";
|
||||
lookup_table[AST_Expr] = "expr";
|
||||
|
||||
lookup_table[AST_Add] = "+";
|
||||
|
@ -69,9 +70,20 @@ void AST_init() {
|
|||
lookup_table[AST_Box] = "box";
|
||||
lookup_table[AST_Fun] = "fun";
|
||||
|
||||
lookup_table[AST_Typecast] = "cast";
|
||||
lookup_table[AST_Transmute] = "as";
|
||||
lookup_table[AST_Call] = "funcall";
|
||||
lookup_table[AST_Typecast] = "typecast";
|
||||
lookup_table[AST_Transmute] = "transmute";
|
||||
lookup_table[AST_Condition] = "condition";
|
||||
lookup_table[AST_List] = "list";
|
||||
lookup_table[AST_ExprList] = "expr list";
|
||||
lookup_table[AST_ArgList] = "arg list";
|
||||
lookup_table[AST_ParamList] = "param list";
|
||||
lookup_table[AST_StmtList] = "stmt list";
|
||||
lookup_table[AST_IdentList] = "ident list";
|
||||
lookup_table[AST_Type] = "type";
|
||||
lookup_table[AST_Negate] = "-";
|
||||
lookup_table[AST_Parameter] = "parameter";
|
||||
lookup_table[AST_ParamDecl] = "parameter-declaration";
|
||||
}
|
||||
|
||||
const char* AST_node_to_string(const struct AST_Node_t* node) {
|
||||
|
@ -87,7 +99,11 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
|
|||
case AST_Ident:
|
||||
case AST_Macro:
|
||||
case AST_Import:
|
||||
case AST_Call:
|
||||
case AST_Storage:
|
||||
case AST_Typekind:
|
||||
case AST_Sign:
|
||||
case AST_Scale:
|
||||
case AST_Qualifyier:
|
||||
string = node->value;
|
||||
break;
|
||||
default:
|
||||
|
@ -99,6 +115,14 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
|
|||
return string;
|
||||
}
|
||||
|
||||
static inline unsigned long int min(unsigned long int a, unsigned long int b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
static inline unsigned long int max(unsigned long int a, unsigned long int b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
|
||||
DEBUG("Adding new node %p to %p", child, owner);
|
||||
assert(owner != NULL);
|
||||
|
@ -119,6 +143,12 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
|
|||
PANIC("failed to allocate children array of AST node");
|
||||
}
|
||||
|
||||
owner->location.col_end = max(owner->location.col_end, child->location.col_end);
|
||||
owner->location.line_end = max(owner->location.line_end, child->location.line_end);
|
||||
|
||||
owner->location.col_start = min(owner->location.col_start, child->location.col_start);
|
||||
owner->location.line_start = min(owner->location.line_start, child->location.line_start);
|
||||
|
||||
assert(owner->children != NULL);
|
||||
|
||||
owner->children[owner->child_count++] = child;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define _AST_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <io/files.h>
|
||||
|
||||
/**
|
||||
* @brief The type of a AST node
|
||||
|
@ -12,6 +13,7 @@
|
|||
*/
|
||||
enum AST_SyntaxElement_t {
|
||||
AST_Stmt = 0,
|
||||
AST_Module,
|
||||
AST_Expr,
|
||||
// Literals
|
||||
AST_Int,
|
||||
|
@ -58,7 +60,22 @@ enum AST_SyntaxElement_t {
|
|||
AST_Fun,
|
||||
AST_Import,
|
||||
// amount of variants
|
||||
// in this enum
|
||||
// in this enums
|
||||
AST_List,
|
||||
AST_ExprList,
|
||||
AST_ArgList,
|
||||
AST_ParamList,
|
||||
AST_StmtList,
|
||||
AST_IdentList,
|
||||
AST_Storage,
|
||||
AST_Type,
|
||||
AST_Typekind,
|
||||
AST_Sign,
|
||||
AST_Scale,
|
||||
AST_Negate,
|
||||
AST_Parameter,
|
||||
AST_Qualifyier,
|
||||
AST_ParamDecl,
|
||||
AST_ELEMENT_COUNT
|
||||
};
|
||||
|
||||
|
@ -78,6 +95,8 @@ struct AST_Node_t {
|
|||
// optional value: integer literal, string literal, ...
|
||||
const char* value;
|
||||
|
||||
TokenLocation location;
|
||||
|
||||
// number of child nodes ownd by this node
|
||||
// length of children array
|
||||
size_t child_count;
|
||||
|
@ -117,7 +136,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node);
|
|||
[[maybe_unused]]
|
||||
[[nodiscard("pointer must be freed")]]
|
||||
[[gnu::returns_nonnull]]
|
||||
struct AST_Node_t *AST_new_node(enum AST_SyntaxElement_t kind, const char* value);
|
||||
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value);
|
||||
|
||||
/**
|
||||
* @brief Deallocate this node and all of its children.
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
//
|
||||
// Created by servostar on 5/30/24.
|
||||
//
|
||||
|
||||
#include <io/files.h>
|
||||
#include <sys/log.h>
|
||||
#include <assert.h>
|
||||
#include <sys/col.h>
|
||||
|
||||
ModuleFile *push_file(ModuleFileStack *stack, const char *path) {
|
||||
assert(stack != NULL);
|
||||
|
||||
// lazy init of heap stack
|
||||
if (stack->files == NULL) {
|
||||
stack->files = g_array_new(FALSE, FALSE, sizeof(ModuleFile));
|
||||
}
|
||||
|
||||
ModuleFile new_file = {
|
||||
.path = path,
|
||||
.handle = NULL
|
||||
};
|
||||
|
||||
g_array_append_val(stack->files, new_file);
|
||||
|
||||
return ((ModuleFile *) stack->files->data) + stack->files->len - 1;
|
||||
}
|
||||
|
||||
void delete_files(ModuleFileStack *stack) {
|
||||
for (size_t i = 0; i < stack->files->len; i++) {
|
||||
ModuleFile *file = ((ModuleFile *) stack->files->data) + i;
|
||||
|
||||
if (file->handle != NULL) {
|
||||
DEBUG("closing file: %s", file->path);
|
||||
fclose(file->handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
g_array_free(stack->files, TRUE);
|
||||
DEBUG("deleted module file stack");
|
||||
}
|
||||
|
||||
#define SEEK_BUF_BYTES 256
|
||||
|
||||
static inline unsigned long int min(unsigned long int a, unsigned long int b) {
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
// behaves like fgets except that it has defined behavior when n == 1
|
||||
static void custom_fgets(char *buffer, size_t n, FILE *stream) {
|
||||
if (n == 1) {
|
||||
buffer[0] = (char) fgetc(stream);
|
||||
buffer[1] = 0;
|
||||
} else {
|
||||
fgets(buffer, (int) n, stream);
|
||||
}
|
||||
}
|
||||
|
||||
void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message) {
|
||||
assert(file->handle != NULL);
|
||||
assert(location != NULL);
|
||||
assert(message != NULL);
|
||||
|
||||
// reset to start
|
||||
rewind(file->handle);
|
||||
|
||||
char *buffer = alloca(SEEK_BUF_BYTES);
|
||||
unsigned long int line_count = 1;
|
||||
|
||||
// seek to first line
|
||||
while (line_count < location->line_start && fgets(buffer, SEEK_BUF_BYTES, file->handle) != NULL) {
|
||||
line_count += strchr(buffer, '\n') != NULL;
|
||||
}
|
||||
|
||||
const char *accent_color = RESET;
|
||||
const char *kind_text = "unknown";
|
||||
switch (kind) {
|
||||
case Info:
|
||||
kind_text = "info";
|
||||
accent_color = CYAN;
|
||||
file->statistics.info_count++;
|
||||
break;
|
||||
case Warning:
|
||||
kind_text = "warning";
|
||||
accent_color = YELLOW;
|
||||
file->statistics.warning_count++;
|
||||
break;
|
||||
case Error:
|
||||
kind_text = "error";
|
||||
accent_color = RED;
|
||||
file->statistics.error_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
char absolute_path[PATH_MAX];
|
||||
realpath(file->path, absolute_path);
|
||||
|
||||
printf("%s%s:%ld:%s %s%s:%s %s\n", BOLD, absolute_path, location->line_start, RESET, accent_color, kind_text, RESET,
|
||||
message);
|
||||
|
||||
size_t lines = location->line_end - location->line_start + 1;
|
||||
|
||||
for (size_t l = 0; l < lines; l++) {
|
||||
printf(" %4ld | ", location->line_start + l);
|
||||
|
||||
size_t limit;
|
||||
size_t chars = 0;
|
||||
|
||||
// print line before token group start
|
||||
limit = min(location->col_start, SEEK_BUF_BYTES);
|
||||
while (limit > 1) {
|
||||
custom_fgets(buffer, (int) limit, file->handle);
|
||||
chars += printf("%s", buffer);
|
||||
limit = min(location->col_start - chars, SEEK_BUF_BYTES);
|
||||
|
||||
if (strchr(buffer, '\n') != NULL) {
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s", accent_color);
|
||||
|
||||
chars = 0;
|
||||
limit = min(location->col_end - location->col_start + 1, SEEK_BUF_BYTES);
|
||||
while (limit > 0) {
|
||||
custom_fgets(buffer, (int) limit, file->handle);
|
||||
chars += printf("%s", buffer);
|
||||
limit = min(location->col_end - location->col_start + 1 - chars, SEEK_BUF_BYTES);
|
||||
|
||||
if (strchr(buffer, '\n') != NULL) {
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s", RESET);
|
||||
|
||||
// print rest of the line
|
||||
do {
|
||||
custom_fgets(buffer, SEEK_BUF_BYTES, file->handle);
|
||||
printf("%s", buffer);
|
||||
} while (strchr(buffer, '\n') == NULL);
|
||||
|
||||
cont:
|
||||
printf("%s", RESET);
|
||||
}
|
||||
|
||||
printf(" | ");
|
||||
for (size_t i = 1; i < location->col_start; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf("%s", accent_color);
|
||||
printf("^");
|
||||
for (size_t i = 0; i < location->col_end - location->col_start; i++) {
|
||||
printf("~");
|
||||
}
|
||||
|
||||
printf("%s\n\n", RESET);
|
||||
}
|
||||
|
||||
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end,
|
||||
unsigned long int col_end) {
|
||||
TokenLocation location;
|
||||
|
||||
location.line_start = line_start;
|
||||
location.line_end = line_end;
|
||||
location.col_start = col_start;
|
||||
location.col_end = col_end;
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
TokenLocation empty_location(void) {
|
||||
TokenLocation location;
|
||||
|
||||
location.line_start = 0;
|
||||
location.line_end = 0;
|
||||
location.col_start = 0;
|
||||
location.col_end = 0;
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
void print_file_statistics(ModuleFile *file) {
|
||||
if (file->statistics.info_count + file->statistics.warning_count + file->statistics.error_count < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("File %s generated ", file->path);
|
||||
|
||||
if (file->statistics.info_count > 0) {
|
||||
printf("%ld notice(s) ", file->statistics.info_count);
|
||||
}
|
||||
|
||||
if (file->statistics.warning_count > 0) {
|
||||
printf("%ld warning(s) ", file->statistics.warning_count);
|
||||
}
|
||||
|
||||
if (file->statistics.error_count > 0) {
|
||||
printf("%ld error(s) ", file->statistics.error_count);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void print_unit_statistics(ModuleFileStack *file_stack) {
|
||||
FileDiagnosticStatistics stats;
|
||||
stats.info_count = 0;
|
||||
stats.warning_count = 0;
|
||||
stats.error_count = 0;
|
||||
|
||||
for (size_t i = 0; i < file_stack->files->len; i++) {
|
||||
ModuleFile *file = (ModuleFile *) file_stack->files->data;
|
||||
|
||||
stats.info_count += file->statistics.warning_count;
|
||||
stats.warning_count += file->statistics.warning_count;
|
||||
stats.error_count += file->statistics.error_count;
|
||||
}
|
||||
|
||||
printf("%d files generated ", file_stack->files->len);
|
||||
|
||||
if (stats.info_count > 0) {
|
||||
printf("%ld notice(s) ", stats.info_count);
|
||||
}
|
||||
|
||||
if (stats.warning_count > 0) {
|
||||
printf("%ld warning(s) ", stats.warning_count);
|
||||
}
|
||||
|
||||
if (stats.error_count > 0) {
|
||||
printf("%ld error(s) ", stats.error_count);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// Created by servostar on 5/30/24.
|
||||
//
|
||||
|
||||
#ifndef GEMSTONE_FILES_H
|
||||
#define GEMSTONE_FILES_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct FileDiagnosticStatistics_t {
|
||||
size_t error_count;
|
||||
size_t warning_count;
|
||||
size_t info_count;
|
||||
} FileDiagnosticStatistics;
|
||||
|
||||
typedef struct ModuleFile_t {
|
||||
const char *path;
|
||||
FILE *handle;
|
||||
FileDiagnosticStatistics statistics;
|
||||
} ModuleFile;
|
||||
|
||||
typedef struct ModuleFileStack_t {
|
||||
GArray *files;
|
||||
} ModuleFileStack;
|
||||
|
||||
typedef enum Message_t {
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
} Message;
|
||||
|
||||
typedef struct TokenLocation_t {
|
||||
unsigned long int line_start;
|
||||
unsigned long int col_start;
|
||||
unsigned long int line_end;
|
||||
unsigned long int col_end;
|
||||
} TokenLocation;
|
||||
|
||||
/**
|
||||
* @brief Add a new file to the file stack.
|
||||
* @attention The file handle returned will be invalid
|
||||
* @param stack
|
||||
* @param path
|
||||
* @return A new file module
|
||||
*/
|
||||
[[gnu::nonnull(1), gnu::nonnull(2)]]
|
||||
ModuleFile *push_file(ModuleFileStack *stack, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Delete all files in the stack and the stack itself
|
||||
* @param stack
|
||||
*/
|
||||
[[gnu::nonnull(1)]]
|
||||
void delete_files(ModuleFileStack *stack);
|
||||
|
||||
/**
|
||||
* Create a new token location
|
||||
* @param line_start
|
||||
* @param col_start
|
||||
* @param line_end
|
||||
* @param col_end
|
||||
* @return
|
||||
*/
|
||||
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end,
|
||||
unsigned long int col_end);
|
||||
|
||||
TokenLocation empty_location(void);
|
||||
|
||||
[[gnu::nonnull(1), gnu::nonnull(2)]]
|
||||
void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message);
|
||||
|
||||
[[gnu::nonnull(1)]]
|
||||
void print_file_statistics(ModuleFile *file);
|
||||
|
||||
[[gnu::nonnull(1)]]
|
||||
void print_unit_statistics(ModuleFileStack *file_stack);
|
||||
|
||||
#endif //GEMSTONE_FILES_H
|
|
@ -52,6 +52,7 @@
|
|||
"float" {DEBUG("\"%s\" tokenized with \'KeyFloat\'", yytext); return(KeyFloat);};
|
||||
"self" {DEBUG("\"%s\" tokenized with \'KeySelf\'", yytext); return(KeySelf);};
|
||||
"as" {DEBUG("\"%s\" tokenized with \'KeyAs'", yytext); return (KeyAs);};
|
||||
"to" {DEBUG("\"%s\" tokenized with \'KeyTo'", yytext); return (KeyTo);};
|
||||
"short" {DEBUG("\"%s\" tokenized with \'KeyShort\'", yytext); return(KeyShort);};
|
||||
"long" {DEBUG("\"%s\" tokenized with \'KeyLong\'", yytext); return(KeyLong);};
|
||||
"half" {DEBUG("\"%s\" tokenized with \'KeyHalf\'", yytext); return(KeyHalf);};
|
||||
|
@ -91,8 +92,17 @@
|
|||
[0-9]+ {DEBUG("\"%s\" tokenized with \'ValInt\'", yytext); yylval.string = strdup(yytext); return(ValInt); };
|
||||
[0-9]*\.[0-9]+ {DEBUG("\"%s\" tokenized with \'ValFloat\'", yytext); yylval.string = strdup(yytext); return(ValFloat);};
|
||||
[a-zA-Z_0-9]+ {DEBUG("\"%s\" tokenized with \'Ident\'", yytext); yylval.string = strdup(yytext); return(Ident); };
|
||||
\"([^\"\n])*\" {DEBUG("\"%s\" tokenized with \'ValStr\'", yytext); yylval.string = strdup(yytext); return(ValStr);};
|
||||
\"\"\"([^\"\n]|\\\n)*\"\"\" {DEBUG("\"%s\" tokenized with \'ValMultistr\'", yytext); yylval.string = strdup(yytext); return(ValMultistr);};
|
||||
|
||||
\"([^\"\n])*\" {
|
||||
yytext = yytext +1;
|
||||
yytext[yyleng - 2] = 0;
|
||||
|
||||
DEBUG("\"%s\" tokenized with \'ValStr\'", yytext); yylval.string = strdup(yytext); return(ValStr);};
|
||||
\"\"\"([^\"\n]|\\\n)*\"\"\" {
|
||||
yytext = yytext +3;
|
||||
yytext[yyleng - 4] = 0;
|
||||
|
||||
DEBUG("\"%s\" tokenized with \'ValMultistr\'", yytext); yylval.string = strdup(yytext); return(ValMultistr);};
|
||||
[ \r\t] { /* ignore whitespace */ };
|
||||
. { return yytext[0]; /* passthrough unknown token, let parser handle the error */ };
|
||||
%%
|
||||
|
|
|
@ -25,6 +25,16 @@ void lex_init(void) {
|
|||
atexit(lex_deinit);
|
||||
}
|
||||
|
||||
void lex_reset(void) {
|
||||
eof = 0;
|
||||
nRow = 0;
|
||||
nBuffer = 0;
|
||||
lBuffer = 0;
|
||||
nTokenStart = 0;
|
||||
nTokenLength = 0;
|
||||
nTokenNextStart = 0;
|
||||
}
|
||||
|
||||
void beginToken(char *t) {
|
||||
nTokenStart = nTokenNextStart;
|
||||
nTokenLength = (int) strlen(t);
|
||||
|
|
|
@ -16,6 +16,8 @@ extern char* buffer;
|
|||
*/
|
||||
void lex_init(void);
|
||||
|
||||
void lex_reset(void);
|
||||
|
||||
/**
|
||||
* @brief Begin counting a new token. This will fill the global struct yylloc.
|
||||
* @param t the text of the token. Must be null terminated
|
||||
|
|
119
src/main.c
119
src/main.c
|
@ -4,10 +4,52 @@
|
|||
#include <yacc/parser.tab.h>
|
||||
#include <sys/col.h>
|
||||
#include <lex/util.h>
|
||||
#include <io/files.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_DEBUG
|
||||
extern void yyrestart(FILE *);
|
||||
|
||||
extern FILE *yyin;
|
||||
[[maybe_unused]]
|
||||
AST_NODE_PTR root;
|
||||
[[maybe_unused]]
|
||||
ModuleFile *current_file;
|
||||
|
||||
/**
|
||||
* @brief Compile the specified file into AST
|
||||
* @param ast
|
||||
* @param file
|
||||
* @return EXIT_SUCCESS in case the parsing was success full anything lese if not
|
||||
*/
|
||||
[[nodiscard("AST may be in invalid state")]]
|
||||
[[gnu::nonnull(1), gnu::nonnull(1)]]
|
||||
static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
|
||||
assert(file->path != NULL);
|
||||
assert(ast != NULL);
|
||||
|
||||
file->handle = fopen(file->path, "r");
|
||||
|
||||
if (file->handle == NULL) {
|
||||
INFO("unable to open file: %s", file->path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG("parsing file: %s", file->path);
|
||||
// setup global state
|
||||
root = ast;
|
||||
current_file = file;
|
||||
yyin = file->handle;
|
||||
yyrestart(yyin);
|
||||
lex_reset();
|
||||
|
||||
yyparse();
|
||||
|
||||
// clean up global state
|
||||
// current_file = NULL;
|
||||
root = NULL;
|
||||
yyin = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Log a debug message to inform about beginning exit procedures
|
||||
|
@ -15,16 +57,15 @@ extern FILE *yyin;
|
|||
*/
|
||||
void notify_exit(void) { DEBUG("Exiting gemstone..."); }
|
||||
|
||||
|
||||
/**
|
||||
* @brief Closes File after compiling.
|
||||
*
|
||||
*/
|
||||
|
||||
void close_file(void) {
|
||||
if (NULL != yyin) {
|
||||
fclose(yyin);
|
||||
}
|
||||
if (NULL != yyin) {
|
||||
fclose(yyin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,46 +73,62 @@ void close_file(void) {
|
|||
*
|
||||
*/
|
||||
void setup(void) {
|
||||
// setup preample
|
||||
log_init();
|
||||
DEBUG("starting gemstone...");
|
||||
// setup preample
|
||||
|
||||
log_init();
|
||||
DEBUG("starting gemstone...");
|
||||
|
||||
#if LOG_LEVEL <= LOG_LEVEL_DEBUG
|
||||
atexit(¬ify_exit);
|
||||
atexit(¬ify_exit);
|
||||
#endif
|
||||
|
||||
// actual setup
|
||||
AST_init();
|
||||
// actual setup
|
||||
AST_init();
|
||||
|
||||
col_init();
|
||||
col_init();
|
||||
|
||||
lex_init();
|
||||
lex_init();
|
||||
|
||||
DEBUG("finished starting up gemstone...");
|
||||
DEBUG("finished starting up gemstone...");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
setup();
|
||||
atexit(close_file);
|
||||
setup();
|
||||
atexit(close_file);
|
||||
|
||||
// Check for file input as argument
|
||||
if (2 != argc) {
|
||||
INFO("Usage: %s <filename>\n", argv[0]);
|
||||
PANIC("No File could be found");
|
||||
}
|
||||
ModuleFileStack files;
|
||||
files.files = NULL;
|
||||
|
||||
// filename as first argument
|
||||
char *filename = argv[1];
|
||||
for (int i = 1; i < argc; i++) {
|
||||
printf("Compiling file: %s\n\n", argv[i]);
|
||||
|
||||
FILE *file = fopen(filename, "r");
|
||||
TokenLocation location = {
|
||||
.line_start = 0,
|
||||
.line_end = 0,
|
||||
.col_start = 0,
|
||||
.col_end = 0
|
||||
};
|
||||
AST_NODE_PTR ast = AST_new_node(location, AST_Module, NULL);
|
||||
ModuleFile *file = push_file(&files, argv[i]);
|
||||
|
||||
if (NULL == file) {
|
||||
PANIC("File couldn't be opened!");
|
||||
}
|
||||
yyin = file;
|
||||
if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) {
|
||||
// TODO: parse AST to semantic values
|
||||
// TODO: backend codegen
|
||||
}
|
||||
|
||||
yyparse();
|
||||
AST_delete_node(ast);
|
||||
|
||||
return 0;
|
||||
print_file_statistics(file);
|
||||
}
|
||||
|
||||
if (files.files == NULL) {
|
||||
printf("No input files, nothing to do.\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print_unit_statistics(&files);
|
||||
|
||||
delete_files(&files);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
%locations
|
||||
%define parse.error verbose
|
||||
|
||||
%{
|
||||
%code requires {
|
||||
#include <sys/log.h>
|
||||
#include <ast/ast.h>
|
||||
#include <sys/col.h>
|
||||
#include <io/files.h>
|
||||
extern int yylineno;
|
||||
extern ModuleFile* current_file;
|
||||
|
||||
int yyerror(const char*);
|
||||
|
||||
|
@ -11,16 +15,66 @@
|
|||
extern int yylineno;
|
||||
|
||||
extern int yylex();
|
||||
%}
|
||||
extern AST_NODE_PTR root;
|
||||
|
||||
#define new_loc() new_location(yylloc.first_line, yylloc.first_column, yylloc.last_line, yylloc.last_column)
|
||||
}
|
||||
|
||||
%union {
|
||||
char *string;
|
||||
AST_NODE_PTR node_ptr;
|
||||
}
|
||||
|
||||
%type <node_ptr> operation
|
||||
%type <node_ptr> boxaccess
|
||||
%type <node_ptr> boxselfaccess
|
||||
%type <node_ptr> statement
|
||||
%type <node_ptr> statementlist
|
||||
%type <node_ptr> assign
|
||||
%type <node_ptr> oparith
|
||||
%type <node_ptr> decl
|
||||
%type <node_ptr> definition
|
||||
%type <node_ptr> while
|
||||
%type <node_ptr> funcall
|
||||
%type <node_ptr> boxcall
|
||||
%type <node_ptr> branchhalf
|
||||
%type <node_ptr> branchfull
|
||||
%type <node_ptr> branchelse
|
||||
%type <node_ptr> branchelseif
|
||||
%type <node_ptr> branchif
|
||||
%type <node_ptr> type
|
||||
%type <node_ptr> identlist
|
||||
%type <node_ptr> storagequalifier
|
||||
%type <node_ptr> typekind
|
||||
%type <node_ptr> scale
|
||||
%type <node_ptr> sign
|
||||
%type <node_ptr> expr
|
||||
%type <node_ptr> oplogic
|
||||
%type <node_ptr> opbool
|
||||
%type <node_ptr> opbit
|
||||
%type <node_ptr> moduleimport
|
||||
%type <node_ptr> programbody
|
||||
%type <node_ptr> fundef
|
||||
%type <node_ptr> box
|
||||
%type <node_ptr> typedef
|
||||
%type <node_ptr> exprlist
|
||||
%type <node_ptr> argumentlist
|
||||
%type <node_ptr> paramlist
|
||||
%type <node_ptr> params
|
||||
%type <node_ptr> IOqualifyier
|
||||
%type <node_ptr> paramdecl
|
||||
%type <node_ptr> boxbody
|
||||
%type <node_ptr> boxcontent
|
||||
%type <node_ptr> typecast
|
||||
%type <node_ptr> reinterpretcast
|
||||
%type <node_ptr> program
|
||||
|
||||
|
||||
%token KeyInt
|
||||
%token KeyFloat
|
||||
%token KeySelf
|
||||
%token KeyAs
|
||||
%token KeyTo
|
||||
%token <string> ValInt
|
||||
%token <string> Ident
|
||||
%token <string> ValFloat
|
||||
|
@ -64,235 +118,412 @@
|
|||
%token Invalid
|
||||
|
||||
/* Operator associativity */
|
||||
/* Operators at lower line number have lower precedence */
|
||||
/* Operators in same line have same precedence */
|
||||
%right '='
|
||||
%left '+' '-' '*' '/'
|
||||
%left OpEquals OpNot '<' '>'
|
||||
%left OpAnd OpOr OpXor
|
||||
%left OpBitand OpBitor OpBitxor OpBitnot
|
||||
%left OpOr
|
||||
%left OpXor
|
||||
%left OpAnd
|
||||
%left OpBitor
|
||||
%left OpBitxor
|
||||
%left OpBitand
|
||||
%left OpEquals '<' '>'
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
%left OpNot OpBitnot
|
||||
%left KeyAs KeyTo
|
||||
%left '(' ')'
|
||||
|
||||
%%
|
||||
program: program programbody
|
||||
| programbody;
|
||||
program: program programbody {AST_push_node(root, $2);}
|
||||
| programbody {AST_push_node(root, $1);};
|
||||
|
||||
programbody: moduleimport
|
||||
| fundef
|
||||
| box
|
||||
| definition
|
||||
| decl
|
||||
| typedef;
|
||||
programbody: moduleimport {$$ = $1;}
|
||||
| fundef{$$ = $1;}
|
||||
| box{$$ = $1;}
|
||||
| definition{$$ = $1;}
|
||||
| decl{$$ = $1;}
|
||||
| typedef{$$ = $1;};
|
||||
|
||||
|
||||
|
||||
expr: ValFloat
|
||||
| ValInt
|
||||
| ValMultistr
|
||||
| ValStr
|
||||
| Ident
|
||||
| operation
|
||||
| boxaccess
|
||||
| boxselfaccess;
|
||||
expr: ValFloat {$$ = AST_new_node(new_loc(), AST_Float, $1);}
|
||||
| ValInt {$$ = AST_new_node(new_loc(), AST_Int, $1);}
|
||||
| ValMultistr {$$ = AST_new_node(new_loc(), AST_String, $1);}
|
||||
| ValStr {$$ = AST_new_node(new_loc(), AST_String, $1);}
|
||||
| Ident {$$ = AST_new_node(new_loc(), AST_Ident, $1);}
|
||||
| operation {$$ = $1;}
|
||||
| boxaccess {$$ = $1;}
|
||||
| boxselfaccess{$$ = $1;}
|
||||
| typecast{$$ = $1;}
|
||||
| reinterpretcast{$$ = $1;}
|
||||
| '(' expr ')' {$$=$2;}
|
||||
|
||||
exprlist: expr ',' exprlist
|
||||
| expr;
|
||||
exprlist: expr ',' exprlist {AST_push_node($3, $1);
|
||||
$$ = $3;}
|
||||
| expr {AST_NODE_PTR list = AST_new_node(new_loc(), AST_ExprList, NULL);
|
||||
AST_push_node(list, $1);
|
||||
$$ = list;};
|
||||
|
||||
argumentlist: argumentlist '(' exprlist ')'
|
||||
| ;
|
||||
argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3);
|
||||
$$ = $1;}
|
||||
| '(' exprlist ')'{AST_NODE_PTR list = AST_new_node(new_loc(), AST_ArgList, NULL);
|
||||
AST_push_node(list, $2);
|
||||
$$ = list;}
|
||||
| argumentlist '(' ')'
|
||||
| '(' ')'{AST_NODE_PTR list = AST_new_node(new_loc(), AST_ArgList, NULL);
|
||||
$$ = list;};
|
||||
|
||||
|
||||
fundef: KeyFun Ident paramlist '{' statementlist'}' { DEBUG("Function");};
|
||||
fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(new_loc(), AST_Fun, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $2);
|
||||
AST_push_node(fun, ident);
|
||||
AST_push_node(fun, $3);
|
||||
AST_push_node(fun, $5);
|
||||
$$ = fun;
|
||||
DEBUG("Function");};
|
||||
|
||||
paramlist: paramlist '(' params ')'
|
||||
| paramlist '(' ')'
|
||||
| '(' params ')'
|
||||
| '(' ')';
|
||||
paramlist: paramlist '(' params ')' {AST_push_node($1, $3);
|
||||
$$ = $1;}
|
||||
| paramlist '(' ')'{$$ = $1;}
|
||||
| '(' params ')' {AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_push_node(list, $2);
|
||||
$$ = list;}
|
||||
| '(' ')' {$$ = AST_new_node(new_loc(), AST_List, NULL);};
|
||||
|
||||
params: IOqualifyier paramdecl ',' params
|
||||
| IOqualifyier paramdecl;
|
||||
params: IOqualifyier paramdecl ',' params {AST_NODE_PTR parameter = AST_new_node(new_loc(), AST_Parameter, NULL);
|
||||
AST_push_node(parameter, $1);
|
||||
AST_push_node(parameter, $2);
|
||||
AST_push_node($4, parameter);
|
||||
$$ = $4;}
|
||||
| IOqualifyier paramdecl {AST_NODE_PTR list = AST_new_node(new_loc(), AST_ParamList, NULL);
|
||||
AST_NODE_PTR parameter = AST_new_node(new_loc(), AST_Parameter, NULL);
|
||||
AST_push_node(parameter, $1);
|
||||
AST_push_node(parameter, $2);
|
||||
AST_push_node(list, parameter);
|
||||
$$ = list;};
|
||||
|
||||
IOqualifyier: KeyIn
|
||||
| KeyOut
|
||||
| KeyIn KeyOut
|
||||
| KeyOut KeyIn
|
||||
| ;
|
||||
IOqualifyier: KeyIn { AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in");
|
||||
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_push_node(list, in);
|
||||
$$ = list;}
|
||||
| KeyOut{ AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out");
|
||||
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_push_node(list, out);
|
||||
$$ = list;}
|
||||
| KeyIn KeyOut{ AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in");
|
||||
AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out");
|
||||
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_push_node(list, in);
|
||||
AST_push_node(list, out);
|
||||
$$ = list;}
|
||||
| KeyOut KeyIn{ AST_NODE_PTR in = AST_new_node(new_loc(), AST_Qualifyier, "in");
|
||||
AST_NODE_PTR out = AST_new_node(new_loc(), AST_Qualifyier, "out");
|
||||
AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_push_node(list, in);
|
||||
AST_push_node(list, out);
|
||||
$$ = list;}
|
||||
| {$$ = AST_new_node(new_loc(), AST_List, NULL);};
|
||||
|
||||
paramdecl: type ':' Ident { DEBUG("Param-Declaration"); };
|
||||
paramdecl: type ':' Ident { AST_NODE_PTR paramdecl = AST_new_node(new_loc(), AST_ParamDecl, NULL);
|
||||
AST_push_node(paramdecl, $1);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $3);
|
||||
AST_push_node(paramdecl, ident);
|
||||
$$ = paramdecl;
|
||||
DEBUG("Param-Declaration"); };
|
||||
|
||||
box: KeyType KeyBox ':' Ident '{' boxbody '}' { DEBUG("Box"); }
|
||||
| KeyType KeyBox ':' Ident '{' '}';
|
||||
box: KeyType KeyBox ':' Ident '{' boxbody '}' {AST_NODE_PTR box = AST_new_node(new_loc(), AST_Box, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4);
|
||||
AST_push_node(box, ident);
|
||||
AST_push_node(box, $6);
|
||||
$$ = box;
|
||||
DEBUG("Box"); }
|
||||
| KeyType KeyBox ':' Ident '{' '}' {AST_NODE_PTR box = AST_new_node(new_loc(), AST_Box, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4);
|
||||
AST_push_node(box, ident);
|
||||
$$ = box;};
|
||||
|
||||
boxbody: boxbody boxcontent
|
||||
| boxcontent;
|
||||
boxbody: boxbody boxcontent {AST_push_node($1, $2);
|
||||
$$ = $1;}
|
||||
| boxcontent {AST_NODE_PTR list = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_push_node(list, $1);
|
||||
$$ = list;};
|
||||
|
||||
boxcontent: decl { DEBUG("Box decl Content"); }
|
||||
| definition { DEBUG("Box def Content"); }
|
||||
| fundef { DEBUG("Box fun Content"); };
|
||||
boxcontent: decl { $$ = $1;DEBUG("Box decl Content"); }
|
||||
| definition { $$ = $1;DEBUG("Box def Content"); }
|
||||
| fundef { $$ = $1;DEBUG("Box fun Content"); };
|
||||
|
||||
boxselfaccess: KeySelf '.' Ident
|
||||
| KeySelf '.' boxaccess;
|
||||
boxselfaccess: KeySelf '.' Ident {AST_NODE_PTR boxselfaccess = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_NODE_PTR self = AST_new_node(new_loc(), AST_Ident, "self");
|
||||
AST_push_node(boxselfaccess, self);
|
||||
AST_NODE_PTR identlist = AST_new_node(new_loc(), AST_IdentList, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $3);
|
||||
AST_push_node(identlist,ident);
|
||||
AST_push_node(boxselfaccess, identlist);
|
||||
$$ = boxselfaccess;}
|
||||
| KeySelf '.' boxaccess {AST_NODE_PTR boxselfaccess = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_NODE_PTR self = AST_new_node(new_loc(), AST_Ident, "self");
|
||||
AST_push_node(boxselfaccess, self);
|
||||
AST_push_node(boxselfaccess, $3);
|
||||
$$ = boxselfaccess;};
|
||||
|
||||
boxaccess: Ident '.' Ident
|
||||
| Ident '.' boxaccess;
|
||||
boxaccess: Ident '.' Ident {AST_NODE_PTR identlist = AST_new_node(new_loc(), AST_IdentList, NULL);
|
||||
AST_NODE_PTR ident1 = AST_new_node(new_loc(), AST_Ident, $1);
|
||||
AST_NODE_PTR ident2 = AST_new_node(new_loc(), AST_Ident, $3);
|
||||
AST_push_node(identlist,ident1);
|
||||
AST_push_node(identlist,ident2);
|
||||
$$ = identlist;}
|
||||
| Ident '.' boxaccess {AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
|
||||
AST_push_node($3,ident);
|
||||
$$ = $3;};
|
||||
|
||||
boxcall: boxaccess argumentlist
|
||||
| boxselfaccess argumentlist;
|
||||
|
||||
funcall: Ident argumentlist { DEBUG("Function call"); };
|
||||
|
||||
moduleimport: KeyImport ValStr { DEBUG("Module-Import"); };
|
||||
|
||||
statementlist: statement statementlist
|
||||
| statement;
|
||||
|
||||
statement: assign
|
||||
| decl
|
||||
| definition
|
||||
| while
|
||||
| branch
|
||||
| funcall
|
||||
| boxcall;
|
||||
|
||||
branchif: KeyIf expr '{' statementlist '}' { DEBUG("if"); };
|
||||
branchelse: KeyElse '{' statementlist '}' { DEBUG("if-else"); };
|
||||
branchelseif: KeyElse KeyIf expr '{' statementlist '}' { DEBUG("else-if"); };
|
||||
|
||||
branchelseifs: branchelseifs branchelseif
|
||||
| branchelseif;
|
||||
|
||||
branch: branchif branchelseifs
|
||||
| branchif branchelseifs branchelse;
|
||||
|
||||
while: KeyWhile expr '{' statementlist '}' { DEBUG("while"); };
|
||||
|
||||
identlist: Ident ',' identlist
|
||||
| Ident;
|
||||
|
||||
decl: type ':' identlist
|
||||
| storagequalifier type ':' identlist
|
||||
boxcall: boxaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(new_loc(), AST_Call, NULL);
|
||||
AST_push_node(boxcall, $1);
|
||||
AST_push_node(boxcall, $2);
|
||||
$$ = boxcall;}
|
||||
| boxselfaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(new_loc(), AST_Call, NULL);
|
||||
AST_push_node(boxcall, $1);
|
||||
AST_push_node(boxcall, $2);
|
||||
$$ = boxcall;};
|
||||
|
||||
|
||||
definition: decl '=' expr { DEBUG("Definition"); };
|
||||
typecast: expr KeyAs type %prec KeyAs {AST_NODE_PTR cast = AST_new_node(new_loc(), AST_Typecast, NULL);
|
||||
AST_push_node(cast, $1);
|
||||
AST_push_node(cast, $3);
|
||||
$$ = cast;
|
||||
DEBUG("Type-Cast"); };
|
||||
|
||||
storagequalifier: KeyGlobal
|
||||
| KeyStatic
|
||||
| KeyLocal;
|
||||
reinterpretcast: expr KeyTo type %prec KeyTo { AST_NODE_PTR cast = AST_new_node(new_loc(), AST_Transmute, NULL);
|
||||
AST_push_node(cast, $1);
|
||||
AST_push_node(cast, $3);
|
||||
$$ = cast;
|
||||
DEBUG("Reinterpret-Cast"); };
|
||||
|
||||
|
||||
funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(new_loc(), AST_Call, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
|
||||
AST_push_node(funcall, ident);
|
||||
AST_push_node(funcall, $2);
|
||||
$$ = funcall;
|
||||
DEBUG("Function call"); };
|
||||
|
||||
moduleimport: KeyImport ValStr {$$ = AST_new_node(new_loc(), AST_Import, $2);
|
||||
DEBUG("Module-Import"); };
|
||||
|
||||
statementlist: statementlist statement {AST_push_node($1, $2);
|
||||
$$ = $1;}
|
||||
| statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL);
|
||||
AST_push_node(list, $1);
|
||||
$$ = list;};
|
||||
|
||||
statement: assign {$$ = $1;}
|
||||
| decl {$$ = $1;}
|
||||
| definition {$$ = $1;}
|
||||
| while {$$ = $1;}
|
||||
| branchfull {$$ = $1;}
|
||||
| funcall {$$ = $1;}
|
||||
| boxcall{$$ = $1;};
|
||||
|
||||
branchif: KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_If, NULL);
|
||||
AST_push_node(branch, $2);
|
||||
AST_push_node(branch, $4);
|
||||
$$ = branch; };
|
||||
|
||||
branchelse: KeyElse '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_Else, NULL);
|
||||
AST_push_node(branch, $3);
|
||||
$$ = branch; };
|
||||
|
||||
branchelseif: KeyElse KeyIf expr '{' statementlist '}' { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_IfElse, NULL);
|
||||
AST_push_node(branch, $3);
|
||||
AST_push_node(branch, $5);
|
||||
$$ = branch; };
|
||||
|
||||
branchfull: branchhalf { $$ = $1;};
|
||||
|branchhalf branchelse { AST_push_node($1 , $2);
|
||||
$$ = $1; }
|
||||
branchhalf: branchif { AST_NODE_PTR branch = AST_new_node(new_loc(), AST_Stmt, NULL);
|
||||
AST_push_node(branch, $1);
|
||||
$$ = branch; }
|
||||
| branchhalf branchelseif { AST_push_node($1 , $2);
|
||||
$$ = $1; };
|
||||
|
||||
|
||||
while: KeyWhile expr '{' statementlist '}' {AST_NODE_PTR whilenode = AST_new_node(new_loc(), AST_While, NULL);
|
||||
AST_push_node(whilenode, $2);
|
||||
AST_push_node(whilenode, $4);
|
||||
$$ = whilenode;};
|
||||
|
||||
identlist: Ident ',' identlist {AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
|
||||
AST_push_node($3, ident);
|
||||
$$ = $3;}
|
||||
| Ident {AST_NODE_PTR list = AST_new_node(new_loc(), AST_IdentList, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
|
||||
AST_push_node(list, ident);
|
||||
$$ = list;};
|
||||
|
||||
decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(new_loc(), AST_Decl, NULL);
|
||||
AST_push_node(decl, $1);
|
||||
AST_push_node(decl, $3);
|
||||
$$ = decl;}
|
||||
| storagequalifier type ':' identlist {AST_NODE_PTR decl = AST_new_node(new_loc(), AST_Decl, NULL);
|
||||
AST_push_node(decl, $1);
|
||||
AST_push_node(decl, $2);
|
||||
AST_push_node(decl, $4);
|
||||
$$ = decl;}
|
||||
|
||||
|
||||
definition: decl '=' expr { AST_NODE_PTR def = AST_new_node(new_loc(), AST_Def, NULL);
|
||||
AST_push_node(def, $1);
|
||||
AST_push_node(def, $3);
|
||||
$$ = def;
|
||||
DEBUG("Definition"); };
|
||||
|
||||
storagequalifier: KeyGlobal {$$ = AST_new_node(new_loc(), AST_Storage, "global");}
|
||||
| KeyStatic {$$ = AST_new_node(new_loc(), AST_Storage, "static");}
|
||||
| KeyLocal {$$ = AST_new_node(new_loc(), AST_Storage, "local");};
|
||||
|
||||
assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(new_loc(), AST_Assign, NULL);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $1);
|
||||
AST_push_node(assign, ident);
|
||||
AST_push_node(assign, $3);
|
||||
$$ = assign;
|
||||
DEBUG("Assignment"); }
|
||||
|
||||
assign: Ident '=' expr { DEBUG("Assignment"); }
|
||||
| boxaccess '=' expr
|
||||
| boxselfaccess '=' expr ;
|
||||
|
||||
sign: KeySigned
|
||||
| KeyUnsigned;
|
||||
sign: KeySigned {$$ = AST_new_node(new_loc(), AST_Sign, "signed");}
|
||||
| KeyUnsigned{$$ = AST_new_node(new_loc(), AST_Sign, "unsigned");};
|
||||
|
||||
typedef: KeyType type':' Ident;
|
||||
typedef: KeyType type':' Ident {AST_NODE_PTR typeDef = AST_new_node(new_loc(), AST_Typedef, NULL);
|
||||
AST_push_node(typeDef, $2);
|
||||
AST_NODE_PTR ident = AST_new_node(new_loc(), AST_Ident, $4);
|
||||
AST_push_node(typeDef, ident);
|
||||
$$ = typeDef;};
|
||||
|
||||
scale: scale KeyShort
|
||||
| scale KeyHalf
|
||||
| scale KeyLong
|
||||
| scale KeyDouble
|
||||
| KeyShort
|
||||
| KeyHalf
|
||||
| KeyLong
|
||||
| KeyDouble;
|
||||
scale: scale KeyShort {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "short");
|
||||
AST_push_node($1, shortnode);
|
||||
$$ = $1;}
|
||||
| scale KeyHalf {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "half");
|
||||
AST_push_node($1, shortnode);
|
||||
$$ = $1;}
|
||||
| scale KeyLong {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "long");
|
||||
AST_push_node($1, shortnode);
|
||||
$$ = $1;}
|
||||
| scale KeyDouble {AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "double");
|
||||
AST_push_node($1, shortnode);
|
||||
$$ = $1;}
|
||||
| KeyShort {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "short");
|
||||
AST_push_node(scale, shortnode);
|
||||
$$ = scale;}
|
||||
| KeyHalf {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "half");
|
||||
AST_push_node(scale, shortnode);
|
||||
$$ = scale;}
|
||||
| KeyLong {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "long");
|
||||
AST_push_node(scale, shortnode);
|
||||
$$ = scale;}
|
||||
| KeyDouble {AST_NODE_PTR scale = AST_new_node(new_loc(), AST_List, NULL);
|
||||
AST_NODE_PTR shortnode = AST_new_node(new_loc(), AST_Scale, "double");
|
||||
AST_push_node(scale, shortnode);
|
||||
$$ = scale;};
|
||||
|
||||
typekind: Ident
|
||||
| KeyInt
|
||||
| KeyFloat;
|
||||
typekind: Ident {$$ = AST_new_node(new_loc(), AST_Typekind, $1);}
|
||||
| KeyInt {$$ = AST_new_node(new_loc(), AST_Typekind, "int");}
|
||||
| KeyFloat {$$ = AST_new_node(new_loc(), AST_Typekind, "float");};
|
||||
|
||||
type: typekind
|
||||
| scale typekind
|
||||
| sign typekind
|
||||
| sign scale typekind;
|
||||
type: typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
|
||||
AST_push_node(type, $1);
|
||||
$$ = type;}
|
||||
| scale typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
|
||||
AST_push_node(type, $1);
|
||||
AST_push_node(type, $2);
|
||||
$$ = type;}
|
||||
| sign typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
|
||||
AST_push_node(type, $1);
|
||||
AST_push_node(type, $2);
|
||||
$$ = type;}
|
||||
| sign scale typekind {AST_NODE_PTR type = AST_new_node(new_loc(), AST_Type, NULL);
|
||||
AST_push_node(type, $1);
|
||||
AST_push_node(type, $2);
|
||||
AST_push_node(type, $3);
|
||||
$$ = type;};
|
||||
|
||||
operation: oparith
|
||||
| oplogic
|
||||
| opbool
|
||||
| opbit;
|
||||
operation: oparith {$$ = $1;}
|
||||
| oplogic {$$ = $1;}
|
||||
| opbool {$$ = $1;}
|
||||
| opbit {$$ = $1;};
|
||||
|
||||
oparith: expr '+' expr
|
||||
| expr '-' expr
|
||||
| expr '*' expr
|
||||
| expr '/' expr
|
||||
| '-' expr %prec '*';
|
||||
oparith: expr '+' expr {AST_NODE_PTR add = AST_new_node(new_loc(), AST_Add, NULL);
|
||||
AST_push_node(add, $1);
|
||||
AST_push_node(add, $3);
|
||||
$$ = add;}
|
||||
| expr '-' expr {AST_NODE_PTR subtract = AST_new_node(new_loc(), AST_Sub, NULL);
|
||||
AST_push_node(subtract, $1);
|
||||
AST_push_node(subtract, $3);
|
||||
$$ = subtract;}
|
||||
| expr '*' expr {AST_NODE_PTR mul = AST_new_node(new_loc(), AST_Mul, NULL);
|
||||
AST_push_node(mul, $1);
|
||||
AST_push_node(mul, $3);
|
||||
$$ = mul;}
|
||||
| expr '/' expr {AST_NODE_PTR div = AST_new_node(new_loc(), AST_Div, NULL);
|
||||
AST_push_node(div, $1);
|
||||
AST_push_node(div, $3);
|
||||
$$ = div;}
|
||||
| '-' expr %prec '*'{AST_NODE_PTR negator = AST_new_node(new_loc(), AST_Negate, NULL);
|
||||
AST_push_node(negator, $2);
|
||||
$$ = negator;};
|
||||
|
||||
oplogic: expr OpEquals expr
|
||||
| expr '<' expr
|
||||
| expr '>' expr;
|
||||
oplogic: expr OpEquals expr {AST_NODE_PTR equals = AST_new_node(new_loc(), AST_Eq, NULL);
|
||||
AST_push_node(equals, $1);
|
||||
AST_push_node(equals, $3);
|
||||
$$ = equals;}
|
||||
| expr '<' expr {AST_NODE_PTR less = AST_new_node(new_loc(), AST_Less, NULL);
|
||||
AST_push_node(less, $1);
|
||||
AST_push_node(less, $3);
|
||||
$$ = less;}
|
||||
| expr '>' expr{AST_NODE_PTR greater = AST_new_node(new_loc(), AST_Greater, NULL);
|
||||
AST_push_node(greater, $1);
|
||||
AST_push_node(greater, $3);
|
||||
$$ = greater;};
|
||||
|
||||
opbool: expr OpAnd expr
|
||||
| expr OpOr expr
|
||||
| expr OpXor expr
|
||||
| OpNot expr %prec OpAnd;
|
||||
opbool: expr OpAnd expr {AST_NODE_PTR and = AST_new_node(new_loc(), AST_BoolAnd, NULL);
|
||||
AST_push_node(and, $1);
|
||||
AST_push_node(and, $3);
|
||||
$$ = and;}
|
||||
| expr OpOr expr{AST_NODE_PTR or = AST_new_node(new_loc(), AST_BoolOr, NULL);
|
||||
AST_push_node(or, $1);
|
||||
AST_push_node(or, $3);
|
||||
$$ = or;}
|
||||
| expr OpXor expr{AST_NODE_PTR xor = AST_new_node(new_loc(), AST_BoolXor, NULL);
|
||||
AST_push_node(xor, $1);
|
||||
AST_push_node(xor, $3);
|
||||
$$ = xor;}
|
||||
| OpNot expr %prec OpAnd{AST_NODE_PTR not = AST_new_node(new_loc(), AST_BoolNot, NULL);
|
||||
AST_push_node(not, $2);
|
||||
$$ = not;};
|
||||
|
||||
opbit: expr OpBitand expr
|
||||
| expr OpBitor expr
|
||||
| expr OpBitxor expr
|
||||
| OpBitnot expr %prec OpBitand;
|
||||
opbit: expr OpBitand expr {AST_NODE_PTR and = AST_new_node(new_loc(), AST_BitAnd, NULL);
|
||||
AST_push_node(and, $1);
|
||||
AST_push_node(and, $3);
|
||||
$$ = and;}
|
||||
| expr OpBitor expr{AST_NODE_PTR or = AST_new_node(new_loc(), AST_BitOr, NULL);
|
||||
AST_push_node(or, $1);
|
||||
AST_push_node(or, $3);
|
||||
$$ = or;}
|
||||
| expr OpBitxor expr{AST_NODE_PTR xor = AST_new_node(new_loc(), AST_BitXor, NULL);
|
||||
AST_push_node(xor, $1);
|
||||
AST_push_node(xor, $3);
|
||||
$$ = xor;}
|
||||
| OpBitnot expr %prec OpBitand{AST_NODE_PTR not = AST_new_node(new_loc(), AST_BitNot, NULL);
|
||||
AST_push_node(not, $2);
|
||||
$$ = not;};
|
||||
%%
|
||||
|
||||
|
||||
const char* ERROR = "error";
|
||||
const char* WARNING = "warning";
|
||||
const char* NOTE = "note";
|
||||
|
||||
int print_message(const char* kind, const char* message) {
|
||||
// number of characters written
|
||||
int char_count = 0;
|
||||
// highlight to use
|
||||
char* HIGHLIGHT = CYAN;
|
||||
|
||||
// convert message kind into color
|
||||
if (kind == ERROR) {
|
||||
HIGHLIGHT = RED;
|
||||
} else if (kind == WARNING) {
|
||||
HIGHLIGHT = YELLOW;
|
||||
}
|
||||
|
||||
// print message
|
||||
char_count += printf("%sfilename:%d:%d%s:%s%s %s: %s%s\n", BOLD, yylloc.first_line, yylloc.first_column, RESET, HIGHLIGHT, BOLD, kind, RESET, message);
|
||||
|
||||
// print line in which error occurred
|
||||
|
||||
char_count += printf(" %4d | ", yylloc.first_line);
|
||||
|
||||
for (int i = 0; i < yylloc.first_column - 1; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
break;
|
||||
}
|
||||
printf("%c", buffer[i]);
|
||||
}
|
||||
|
||||
char_count += printf("%s%s", BOLD, HIGHLIGHT);
|
||||
|
||||
for (int i = yylloc.first_column - 1; i < yylloc.last_column; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
break;
|
||||
}
|
||||
char_count += printf("%c", buffer[i]);
|
||||
}
|
||||
|
||||
char_count += printf("%s", RESET);
|
||||
|
||||
for (int i = yylloc.last_column; buffer[i] != '\0' && buffer[i] != '\n'; i++) {
|
||||
printf("%c", buffer[i]);
|
||||
}
|
||||
|
||||
char_count += printf("\n | ");
|
||||
|
||||
for (int i = 0; i < yylloc.first_column - 1; i++) {
|
||||
char_count += printf(" ");
|
||||
}
|
||||
|
||||
char_count += printf("%s^", HIGHLIGHT);
|
||||
|
||||
for (int i = 0; i < yylloc.last_column - yylloc.first_column; i++) {
|
||||
printf("~");
|
||||
}
|
||||
|
||||
char_count += printf("%s\n\n", RESET);
|
||||
|
||||
return char_count;
|
||||
}
|
||||
|
||||
int yyerror(const char *s) {
|
||||
return print_message(ERROR, s);
|
||||
TokenLocation location = new_loc();
|
||||
print_diagnostic(current_file, &location, Error, s);
|
||||
return 0;
|
||||
}
|
|
@ -9,3 +9,4 @@ set(CTEST_BINARY_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
|
|||
add_subdirectory(logging)
|
||||
add_subdirectory(input_file)
|
||||
add_subdirectory(ast)
|
||||
add_subdirectory(glib)
|
|
@ -2,6 +2,14 @@ include(CTest)
|
|||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
# ------------------------------------------------ #
|
||||
# Setup Glib 2.0 #
|
||||
# ------------------------------------------------ #
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
# CTEST 1
|
||||
# test building the syntax tree
|
||||
|
@ -9,11 +17,14 @@ include_directories(${PROJECT_SOURCE_DIR}/src)
|
|||
add_executable(ast_build_tree
|
||||
${PROJECT_SOURCE_DIR}/src/ast/ast.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/io/files.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
build_tree.c)
|
||||
set_target_properties(ast_build_tree
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "build_tree"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/ast)
|
||||
target_link_libraries(ast_build_tree PkgConfig::GLIB)
|
||||
add_test(NAME ast_build_tree
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMAND python ${GEMSTONE_TEST_DIR}/ast/test_ast.py check_build_tree)
|
||||
|
@ -25,11 +36,14 @@ add_test(NAME ast_build_tree
|
|||
add_executable(ast_print_node
|
||||
${PROJECT_SOURCE_DIR}/src/ast/ast.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/io/files.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
print_node.c)
|
||||
set_target_properties(ast_print_node
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "print_node"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/ast)
|
||||
target_link_libraries(ast_print_node PkgConfig::GLIB)
|
||||
add_test(NAME ast_print_node
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMAND python ${GEMSTONE_TEST_DIR}/ast/test_ast.py check_print_node)
|
||||
|
@ -41,11 +55,14 @@ add_test(NAME ast_print_node
|
|||
add_executable(ast_graphviz
|
||||
${PROJECT_SOURCE_DIR}/src/ast/ast.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/io/files.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
print_graphviz.c)
|
||||
set_target_properties(ast_graphviz
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "print_graphviz"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/ast)
|
||||
target_link_libraries(ast_graphviz PkgConfig::GLIB)
|
||||
add_test(NAME ast_graphviz
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMAND python ${GEMSTONE_TEST_DIR}/ast/test_ast.py check_print_graphviz)
|
||||
|
|
|
@ -6,22 +6,22 @@
|
|||
#include <sys/log.h>
|
||||
|
||||
void generate_statement(const AST_NODE_PTR stmt) {
|
||||
const AST_NODE_PTR add = AST_new_node(AST_Add, NULL);
|
||||
const AST_NODE_PTR add = AST_new_node(empty_location(), AST_Add, NULL);
|
||||
|
||||
AST_push_node(add, AST_new_node(AST_Int, "3"));
|
||||
AST_push_node(add, AST_new_node(AST_Int, "6"));
|
||||
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "3"));
|
||||
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "6"));
|
||||
|
||||
AST_push_node(stmt, add);
|
||||
}
|
||||
|
||||
void generate_branch(const AST_NODE_PTR stmt) {
|
||||
const AST_NODE_PTR branch = AST_new_node(AST_If, NULL);
|
||||
const AST_NODE_PTR gt = AST_new_node(AST_Greater, NULL);
|
||||
const AST_NODE_PTR branch = AST_new_node(empty_location(), AST_If, NULL);
|
||||
const AST_NODE_PTR gt = AST_new_node(empty_location(), AST_Greater, NULL);
|
||||
|
||||
AST_push_node(branch, gt);
|
||||
|
||||
AST_push_node(gt, AST_new_node(AST_Float, "2.3"));
|
||||
AST_push_node(gt, AST_new_node(AST_Float, "0.79"));
|
||||
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "2.3"));
|
||||
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "0.79"));
|
||||
|
||||
AST_push_node(stmt, branch);
|
||||
|
||||
|
@ -30,7 +30,7 @@ void generate_branch(const AST_NODE_PTR stmt) {
|
|||
|
||||
int main(void) {
|
||||
|
||||
const AST_NODE_PTR root = AST_new_node(AST_Stmt, NULL);
|
||||
const AST_NODE_PTR root = AST_new_node(empty_location(), AST_Stmt, NULL);
|
||||
|
||||
generate_branch(root);
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
|
||||
int main(void) {
|
||||
|
||||
struct AST_Node_t* node = AST_new_node(AST_If, NULL);
|
||||
struct AST_Node_t* node = AST_new_node(empty_location(), AST_If, NULL);
|
||||
|
||||
struct AST_Node_t* child = AST_new_node(AST_Add, NULL);
|
||||
AST_push_node(child, AST_new_node(AST_Int, "43"));
|
||||
AST_push_node(child, AST_new_node(AST_Int, "9"));
|
||||
struct AST_Node_t* child = AST_new_node(empty_location(), AST_Add, NULL);
|
||||
AST_push_node(child, AST_new_node(empty_location(), AST_Int, "43"));
|
||||
AST_push_node(child, AST_new_node(empty_location(), AST_Int, "9"));
|
||||
|
||||
AST_push_node(node, child);
|
||||
AST_push_node(node, AST_new_node(AST_Expr, NULL));
|
||||
AST_push_node(node, AST_new_node(AST_Expr, NULL));
|
||||
AST_push_node(node, AST_new_node(empty_location(), AST_Expr, NULL));
|
||||
AST_push_node(node, AST_new_node(empty_location(), AST_Expr, NULL));
|
||||
|
||||
FILE* out = fopen("ast.gv", "w+");
|
||||
// convert this file ^^^^^^
|
||||
|
|
|
@ -6,22 +6,22 @@
|
|||
#include <sys/log.h>
|
||||
|
||||
void generate_statement(const AST_NODE_PTR stmt) {
|
||||
const AST_NODE_PTR add = AST_new_node(AST_Add, NULL);
|
||||
const AST_NODE_PTR add = AST_new_node(empty_location(), AST_Add, NULL);
|
||||
|
||||
AST_push_node(add, AST_new_node(AST_Int, "3"));
|
||||
AST_push_node(add, AST_new_node(AST_Int, "6"));
|
||||
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "3"));
|
||||
AST_push_node(add, AST_new_node(empty_location(), AST_Int, "6"));
|
||||
|
||||
AST_push_node(stmt, add);
|
||||
}
|
||||
|
||||
void generate_branch(const AST_NODE_PTR stmt) {
|
||||
const AST_NODE_PTR branch = AST_new_node(AST_If, NULL);
|
||||
const AST_NODE_PTR gt = AST_new_node(AST_Greater, NULL);
|
||||
const AST_NODE_PTR branch = AST_new_node(empty_location(), AST_If, NULL);
|
||||
const AST_NODE_PTR gt = AST_new_node(empty_location(), AST_Greater, NULL);
|
||||
|
||||
AST_push_node(branch, gt);
|
||||
|
||||
AST_push_node(gt, AST_new_node(AST_Float, "2.3"));
|
||||
AST_push_node(gt, AST_new_node(AST_Float, "0.79"));
|
||||
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "2.3"));
|
||||
AST_push_node(gt, AST_new_node(empty_location(), AST_Float, "0.79"));
|
||||
|
||||
AST_push_node(stmt, branch);
|
||||
|
||||
|
@ -32,7 +32,7 @@ int main(void) {
|
|||
|
||||
AST_init();
|
||||
|
||||
const AST_NODE_PTR root = AST_new_node(AST_Stmt, NULL);
|
||||
const AST_NODE_PTR root = AST_new_node(empty_location(), AST_Stmt, NULL);
|
||||
|
||||
generate_branch(root);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ int main(void) {
|
|||
|
||||
AST_init();
|
||||
|
||||
const AST_NODE_PTR node = AST_new_node(0, "value");
|
||||
const AST_NODE_PTR node = AST_new_node(empty_location(), 0, "value");
|
||||
|
||||
for (size_t i = 0; i < AST_ELEMENT_COUNT; i++) {
|
||||
// set kind
|
||||
|
|
|
@ -29,42 +29,58 @@ def run_check_print_node():
|
|||
assert p.returncode == 0
|
||||
|
||||
assert """0 stmt
|
||||
1 expr
|
||||
2 value
|
||||
1 module
|
||||
2 expr
|
||||
3 value
|
||||
4 value
|
||||
5 while
|
||||
6 if
|
||||
7 else if
|
||||
8 else
|
||||
9 condition
|
||||
10 decl
|
||||
11 assign
|
||||
12 def
|
||||
13 value
|
||||
14 +
|
||||
15 -
|
||||
16 *
|
||||
17 /
|
||||
18 &
|
||||
19 |
|
||||
20 ^
|
||||
21 !
|
||||
22 &&
|
||||
23 ||
|
||||
24 ^^
|
||||
25 !!
|
||||
26 ==
|
||||
27 >
|
||||
28 <
|
||||
29 cast
|
||||
30 as
|
||||
31 value
|
||||
32 value
|
||||
33 typedef
|
||||
34 box
|
||||
35 fun
|
||||
36 value
|
||||
5 value
|
||||
6 while
|
||||
7 if
|
||||
8 else if
|
||||
9 else
|
||||
10 condition
|
||||
11 decl
|
||||
12 assign
|
||||
13 def
|
||||
14 value
|
||||
15 +
|
||||
16 -
|
||||
17 *
|
||||
18 /
|
||||
19 &
|
||||
20 |
|
||||
21 ^
|
||||
22 !
|
||||
23 &&
|
||||
24 ||
|
||||
25 ^^
|
||||
26 !!
|
||||
27 ==
|
||||
28 >
|
||||
29 <
|
||||
30 typecast
|
||||
31 transmute
|
||||
32 funcall
|
||||
33 value
|
||||
34 typedef
|
||||
35 box
|
||||
36 fun
|
||||
37 value
|
||||
38 list
|
||||
39 expr list
|
||||
40 arg list
|
||||
41 param list
|
||||
42 stmt list
|
||||
43 ident list
|
||||
44 value
|
||||
45 type
|
||||
46 value
|
||||
47 value
|
||||
48 value
|
||||
49 -
|
||||
50 parameter
|
||||
51 value
|
||||
52 parameter-declaration
|
||||
""" == p.stdout
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
include(CTest)
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
# CTEST 1
|
||||
# test Glib's hashmap
|
||||
|
||||
add_executable(glib_hashmap
|
||||
glib_hashmap.c)
|
||||
set_target_properties(glib_hashmap
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "glib_hashmap"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/glib)
|
||||
target_link_libraries(glib_hashmap PkgConfig::GLIB)
|
||||
add_test(NAME glib_hashmap
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMAND ${GEMSTONE_BINARY_DIR}/tests/glib/glib_hashmap)
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
#include <glib.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
GHashTable* map = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
int* index = malloc(sizeof(int));
|
||||
|
||||
*index = i;
|
||||
|
||||
g_hash_table_insert(map, argv[i], index);
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
int* index = (int*) g_hash_table_lookup(map, argv[i]);
|
||||
|
||||
g_hash_table_remove(map, argv[i]);
|
||||
|
||||
free(index);
|
||||
}
|
||||
|
||||
g_hash_table_destroy(map);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -2,12 +2,20 @@ include(CTest)
|
|||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
# ------------------------------------------------ #
|
||||
# Setup Glib 2.0 #
|
||||
# ------------------------------------------------ #
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
# CTEST 1
|
||||
# test the default output of the logger
|
||||
|
||||
add_executable(logging_output
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
output.c)
|
||||
set_target_properties(logging_output
|
||||
PROPERTIES
|
||||
|
@ -23,6 +31,7 @@ add_test(NAME logging_output
|
|||
|
||||
add_executable(logging_panic
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
panic.c)
|
||||
set_target_properties(logging_panic
|
||||
PROPERTIES
|
||||
|
@ -38,6 +47,7 @@ add_test(NAME logging_panic
|
|||
|
||||
add_executable(logging_streams
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
streams.c)
|
||||
set_target_properties(logging_streams
|
||||
PROPERTIES
|
||||
|
@ -53,6 +63,7 @@ add_test(NAME logging_streams
|
|||
|
||||
add_executable(logging_level
|
||||
${PROJECT_SOURCE_DIR}/src/sys/log.c
|
||||
${PROJECT_SOURCE_DIR}/src/sys/col.c
|
||||
level.c)
|
||||
set_target_properties(logging_level
|
||||
PROPERTIES
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
//
|
||||
|
||||
#include "sys/log.h"
|
||||
#include <sys/col.h>
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_WARNING
|
||||
|
||||
int main(void) {
|
||||
log_init();
|
||||
col_init();
|
||||
|
||||
DEBUG("logging some debug...");
|
||||
INFO("logging some info...");
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
//
|
||||
|
||||
#include "sys/log.h"
|
||||
#include <sys/col.h>
|
||||
|
||||
int main(void) {
|
||||
log_init();
|
||||
col_init();
|
||||
|
||||
DEBUG("logging some debug...");
|
||||
INFO("logging some info...");
|
||||
|
|
Loading…
Reference in New Issue