From 372c14c575014129bd213140f0aab2d978d4d575 Mon Sep 17 00:00:00 2001 From: servostar Date: Wed, 10 Jul 2024 20:21:12 +0200 Subject: [PATCH 01/25] fixed: assignment of multidimensional arrays --- src/llvm/link/lld.c | 59 +++-------------------------------------- src/llvm/llvm-ir/stmt.c | 16 ++++++++--- src/llvm/parser.c | 8 ++++-- 3 files changed, 22 insertions(+), 61 deletions(-) diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index e1a2175..8c063d2 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -65,12 +65,6 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t g_array_append_val(config->object_file_names, target_object); INFO("resolved path of target object: %s", target_object); - // if it is an app, add entrypoint library - if (target_config->mode == Application) { - char* entrypoint = g_strdup("libentrypoint.a"); - g_array_append_val(module->imports, entrypoint); - } - // resolve absolute paths to dependent library object files DEBUG("resolving target dependencies..."); for (guint i = 0; i < module->imports->len; i++) { @@ -78,9 +72,9 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t const char* dependency_object = get_absolute_link_path(target_config, dependency); if (dependency_object == NULL) { - ERROR("failed to resolve path to dependency object: %s", dependency); - lld_delete_link_config(config); - return NULL; + INFO("failed to resolve path to dependency object: %s", dependency); + print_message(Warning, "failed to resolve path to dependency object: %s", dependency); + continue; } g_array_append_val(config->object_file_names, dependency_object); INFO("resolved path of target object: %s", dependency_object); @@ -91,53 +85,8 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t return config; } -GArray* lld_create_lld_arguments(TargetLinkConfig* config) { - GArray* argv = g_array_new(TRUE, FALSE, sizeof(char*)); - - gchar* arg = g_strdup("ld.lld"); - g_array_append_val(argv, arg); - - if (config->fatal_warnings) { - arg = g_strdup("--fatal-warnings"); - g_array_append_val(argv, arg); - } - - if (config->colorize) { - arg = g_strdup("--color-diagnostics=always"); - g_array_append_val(argv, arg); - } - - { - arg = g_strjoin("", "-o", config->output_file, NULL); - g_array_append_val(argv, arg); - } - - for (guint i = 0; i < config->object_file_names->len; i++) { - char* object_file_path = g_array_index(config->object_file_names, char*, i); - arg = g_strjoin("", object_file_path, NULL); - g_array_append_val(argv, arg); - } - - return argv; -} - BackendError lld_link_target(TargetLinkConfig* config) { - DEBUG("linking target..."); - BackendError err = SUCCESS; - - GArray* argv = lld_create_lld_arguments(config); - - INFO("Linking target..."); - - char* arguments = g_strjoinv(" ", (char**) argv->data); - print_message(Info, "%s", arguments); - g_free(arguments); - - INFO("done linking target..."); - - g_array_free(argv, TRUE); - - return err; + return SUCCESS; } void lld_delete_link_config(TargetLinkConfig* config) { diff --git a/src/llvm/llvm-ir/stmt.c b/src/llvm/llvm-ir/stmt.c index 6a3f41a..c3f8fa2 100644 --- a/src/llvm/llvm-ir/stmt.c +++ b/src/llvm/llvm-ir/stmt.c @@ -41,16 +41,22 @@ BackendError impl_storage_expr( return err; } + if (expr->impl.dereference.array->kind == StorageExprKindDereference) { + LLVMTypeRef deref_type = NULL; + err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type); + if (err.kind != Success) { + return err; + } + + array = LLVMBuildLoad2(builder, deref_type, array, "strg.deref.indirect-load"); + } + LLVMTypeRef deref_type = NULL; err = get_type_impl(unit, scope->func_scope->global_scope, expr->target_type, &deref_type); if (err.kind != Success) { return err; } - if (expr->target_type->kind == TypeKindReference) { - array = LLVMBuildLoad2(builder, deref_type, array, "strg.deref.indirect-load"); - } - *storage_target = LLVMBuildGEP2(builder, deref_type, array, &index, 1, "strg.deref"); break; @@ -210,6 +216,8 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit, Parameter parameter = g_array_index(param_list, Parameter, i); if (is_parameter_out(¶meter)) { reference = TRUE; + } else if (parameter.impl.declaration.type->kind == TypeKindReference) { + reference = TRUE; } LLVMValueRef llvm_arg = NULL; diff --git a/src/llvm/parser.c b/src/llvm/parser.c index 9f07ae8..201f28b 100644 --- a/src/llvm/parser.c +++ b/src/llvm/parser.c @@ -259,9 +259,13 @@ BackendError parse_module(const Module* module, const TargetConfig* config) { if (config->mode == Application) { TargetLinkConfig* link_config = lld_create_link_config(&target, config, module); - lld_link_target(link_config); + if (link_config != NULL) { + lld_link_target(link_config); - lld_delete_link_config(link_config); + lld_delete_link_config(link_config); + } else { + err = new_backend_impl_error(Implementation, NULL, "libclang error"); + } } } From 88e1f061d8c4a32de65a6e6e40400ca708d62820 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 12 Jul 2024 17:54:38 +0200 Subject: [PATCH 02/25] added: parameter access validation --- src/llvm/llvm-ir/expr.c | 55 ++++++++++++++++- src/llvm/llvm-ir/func.c | 7 +-- src/llvm/llvm-ir/func.h | 2 + src/llvm/llvm-ir/stmt.c | 4 ++ src/set/set.c | 129 ++++++++++++++++++++++++++-------------- src/set/types.h | 4 ++ 6 files changed, 149 insertions(+), 52 deletions(-) diff --git a/src/llvm/llvm-ir/expr.c b/src/llvm/llvm-ir/expr.c index 254a969..5ff4e9c 100644 --- a/src/llvm/llvm-ir/expr.c +++ b/src/llvm/llvm-ir/expr.c @@ -387,6 +387,49 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc return SUCCESS; } +BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, + LLVMBuilderRef builder, Parameter *parameter, + LLVMBool reference, + LLVMValueRef *llvm_result) { + + LLVMValueRef llvm_variable = NULL; + if (g_hash_table_contains(scope->func_scope->params, parameter->name)) { + llvm_variable = g_hash_table_lookup(scope->func_scope->params, parameter->name); + } + + Type* type; + + ParameterDeclaration decl; + + if (parameter->kind == ParameterDeclarationKind) { + decl = parameter->impl.definiton.declaration; + } else { + decl = parameter->impl.declaration; + } + type = decl.type; + + if (llvm_variable == NULL) { + return new_backend_impl_error(Implementation, NULL, "Variable not found"); + } + + if (decl.qualifier == In) { + *llvm_result = llvm_variable; + } else { + // no referencing, load value + LLVMTypeRef llvm_type; + + get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type); + + if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) { + *llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, ""); + } else { + *llvm_result = llvm_variable; + } + } + + return SUCCESS; +} + BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMBuilderRef builder, AddressOf* addressOf, LLVMValueRef *llvm_result) { @@ -405,7 +448,12 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, LLVMValueRef *llvm_result) { BackendError err; - LLVMValueRef llvm_pointer = get_variable(scope, dereference->variable->impl.variable->name); + LLVMValueRef llvm_pointer = NULL; + err = impl_expr(unit, scope, builder, dereference->variable, TRUE, &llvm_pointer); + if (err.kind != Success) { + return err; + } + LLVMTypeRef llvm_deref_type = NULL; err = get_type_impl(unit, scope->func_scope->global_scope, dereference->variable->result->impl.reference, &llvm_deref_type); if (err.kind != Success) { @@ -454,6 +502,11 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, reference, llvm_result); break; + case ExpressionKindParameter: + err = impl_parameter_load(unit, scope, builder, expr->impl.parameter, + reference, + llvm_result); + break; case ExpressionKindAddressOf: err = impl_address_of(unit, scope, builder, &expr->impl.addressOf, llvm_result); diff --git a/src/llvm/llvm-ir/func.c b/src/llvm/llvm-ir/func.c index 473d6ad..63d9b39 100644 --- a/src/llvm/llvm-ir/func.c +++ b/src/llvm/llvm-ir/func.c @@ -26,7 +26,7 @@ void delete_local_scope(LLVMLocalScope* scope) { free(scope); } -static LLVMValueRef get_parameter(const LLVMFuncScope* scope, +LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name) { if (g_hash_table_contains(scope->params, name)) { return g_hash_table_lookup(scope->params, name); @@ -44,11 +44,6 @@ LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name) { return get_variable(scope->parent_scope, name); } - LLVMValueRef param = get_parameter(scope->func_scope, name); - if (param != NULL) { - return param; - } - LLVMValueRef global_var = get_global_variable(scope->func_scope->global_scope, (char*) name); return global_var; } diff --git a/src/llvm/llvm-ir/func.h b/src/llvm/llvm-ir/func.h index 5ab4621..349135a 100644 --- a/src/llvm/llvm-ir/func.h +++ b/src/llvm/llvm-ir/func.h @@ -28,6 +28,8 @@ void delete_local_scope(LLVMLocalScope*); LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name); +LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name); + LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name); BackendError impl_function_types(LLVMBackendCompileUnit* unit, diff --git a/src/llvm/llvm-ir/stmt.c b/src/llvm/llvm-ir/stmt.c index c3f8fa2..697c4b8 100644 --- a/src/llvm/llvm-ir/stmt.c +++ b/src/llvm/llvm-ir/stmt.c @@ -27,6 +27,10 @@ BackendError impl_storage_expr( *storage_target = get_variable(scope, expr->impl.variable->name); break; + case StorageExprKindParameter: + *storage_target = + get_parameter(scope->func_scope, expr->impl.parameter->name); + break; case StorageExprKindDereference: LLVMValueRef index = NULL; diff --git a/src/set/set.c b/src/set/set.c index 1ad9652..67b6b9e 100644 --- a/src/set/set.c +++ b/src/set/set.c @@ -541,6 +541,18 @@ char* type_to_string(Type* type) { return string; } +int getParameter(const char *name, Parameter **parameter) { + // loop through all variable scope and find a variable + if (functionParameter != NULL) { + if (g_hash_table_contains(functionParameter, name)) { + *parameter = g_hash_table_lookup(functionParameter, name); + return SEMANTIC_OK; + } + } + + return SEMANTIC_ERROR; +} + int getVariableFromScope(const char *name, Variable **variable) { assert(name != NULL); assert(variable != NULL); @@ -548,13 +560,6 @@ int getVariableFromScope(const char *name, Variable **variable) { DEBUG("getting var from scope"); int found = 0; - // loop through all variable scope and find a variable - if (functionParameter != NULL) { - if (g_hash_table_contains(functionParameter, name)) { - *variable = g_hash_table_lookup(functionParameter, name); - found += 1; - } - } for (size_t i = 0; i < Scope->len; i++) { GHashTable *variable_table = g_array_index(Scope, GHashTable*, i); @@ -1435,6 +1440,14 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) { return SEMANTIC_OK; } +IO_Qualifier getParameterQualifier(Parameter* parameter) { + if (parameter->kind == ParameterDeclarationKind) { + return parameter->impl.declaration.qualifier; + } else { + return parameter->impl.definiton.declaration.qualifier; + } +} + Expression *createExpression(AST_NODE_PTR currentNode) { DEBUG("create Expression"); Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); @@ -1455,23 +1468,32 @@ Expression *createExpression(AST_NODE_PTR currentNode) { case AST_Ident: DEBUG("find var"); expression->kind = ExpressionKindVariable; - int status = getVariableFromScope(currentNode->value, &(expression->impl.variable)); + int status = getVariableFromScope(currentNode->value, &expression->impl.variable); if (status == SEMANTIC_ERROR) { - DEBUG("Identifier is not in current scope"); - print_diagnostic(¤tNode->location, Error, "Variable not found"); - return NULL; - } - switch (expression->impl.variable->kind) { - case VariableKindDeclaration: + expression->kind = ExpressionKindParameter; + status = getParameter(currentNode->value, &expression->impl.parameter); + if (status == SEMANTIC_ERROR) { + DEBUG("Identifier is not in current scope"); + print_diagnostic(¤tNode->location, Error, "Unknown identifier: `%s`", currentNode->value); + return NULL; + } + + if (getParameterQualifier(expression->impl.parameter) == Out) { + print_diagnostic(¤tNode->location, Error, "Parameter is write-only: `%s`", currentNode->value); + return NULL; + } + + if (expression->impl.parameter->kind == VariableKindDeclaration) { + expression->result = expression->impl.parameter->impl.declaration.type; + } else { + expression->result = expression->impl.parameter->impl.definiton.declaration.type; + } + } else { + if (expression->impl.variable->kind == VariableKindDeclaration) { expression->result = expression->impl.variable->impl.declaration.type; - DEBUG("%d", expression->impl.variable->impl.declaration.type->kind); - break; - case VariableKindDefinition: + } else { expression->result = expression->impl.variable->impl.definiton.declaration.type; - break; - default: - PANIC("current Variable should not be an BoxMember"); - break; + } } break; case AST_Add: @@ -1611,15 +1633,33 @@ Type* getVariableType(Variable* variable) { } } +Type* getParameterType(Parameter* parameter) { + if (parameter->kind == ParameterDeclarationKind) { + return parameter->impl.declaration.type; + } else { + return parameter->impl.definiton.declaration.type; + } +} + int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) { switch (node->kind) { case AST_Ident: expr->kind = StorageExprKindVariable; int status = getVariableFromScope(node->value, &expr->impl.variable); if (status == SEMANTIC_ERROR) { - return SEMANTIC_ERROR; + + expr->kind = StorageExprKindParameter; + status = getParameter(node->value, &expr->impl.parameter); + if (status == SEMANTIC_ERROR) { + print_diagnostic(&node->location, Error, "Unknown token: `%s`", node->value); + return SEMANTIC_ERROR; + } else { + expr->target_type = getParameterType(expr->impl.parameter); + } + + } else { + expr->target_type = getVariableType(expr->impl.variable); } - expr->target_type = getVariableType(expr->impl.variable); break; case AST_Dereference: expr->kind = StorageExprKindDereference; @@ -1656,11 +1696,19 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) { assign.nodePtr = currentNode; assign.destination = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr)); - int status = createStorageExpr(assign.destination, AST_get_node(currentNode, 0)); + AST_NODE_PTR strg_expr = AST_get_node(currentNode, 0); + int status = createStorageExpr(assign.destination, strg_expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } + if (strg_expr->kind == StorageExprKindParameter) { + if (getParameterQualifier(assign.destination->impl.parameter) == In) { + print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`", assign.destination->impl.parameter->name); + return SEMANTIC_ERROR; + } + } + assign.value = createExpression(AST_get_node(currentNode, 1)); if (assign.value == NULL) { return SEMANTIC_ERROR; @@ -1682,7 +1730,8 @@ int fillBlock(Block *block, AST_NODE_PTR currentNode) { g_array_append_val(Scope, lowerScope); for (size_t i = 0; i < currentNode->children->len; i++) { - int signal = createStatement(block, AST_get_node(currentNode, i)); + AST_NODE_PTR stmt_node = AST_get_node(currentNode, i); + int signal = createStatement(block, stmt_node); if (signal) { return SEMANTIC_ERROR; } @@ -2003,30 +2052,20 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) { if (set_get_type_impl(AST_get_node(paramdecl, 0), &(decl.type))) { return SEMANTIC_ERROR; } - Parameter param; - param.nodePtr = currentNode; - param.kind = ParameterDeclarationKind; - param.impl.declaration = decl; - param.name = AST_get_node(paramdecl, 1)->value; + Parameter* param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter)); + param->nodePtr = currentNode; + param->kind = ParameterDeclarationKind; + param->impl.declaration = decl; + param->name = AST_get_node(paramdecl, 1)->value; - DEBUG("param name: %s", param.name); - g_array_append_val(Paramlist, param); + DEBUG("param name: %s", param->name); + g_array_append_val(Paramlist, *param); - DEBUG("create var for param"); - - Variable *paramvar = mem_alloc(MemoryNamespaceSet, sizeof(Variable)); - paramvar->kind = VariableKindDeclaration; - paramvar->name = param.name; - paramvar->nodePtr = currentNode; - paramvar->impl.declaration.nodePtr = currentNode; - paramvar->impl.declaration.qualifier = Local; - paramvar->impl.declaration.type = param.impl.declaration.type; - - if (g_hash_table_contains(functionParameter, param.name)) { - print_diagnostic(¶m.nodePtr->location, Error, "Names of function parameters must be unique: %s", param.name); + if (g_hash_table_contains(functionParameter, param->name)) { + print_diagnostic(¶m->nodePtr->location, Error, "Names of function parameters must be unique: %s", param->name); return SEMANTIC_ERROR; } - g_hash_table_insert(functionParameter, (gpointer) param.name, paramvar); + g_hash_table_insert(functionParameter, (gpointer) param->name, param); DEBUG("created param successfully"); return SEMANTIC_OK; diff --git a/src/set/types.h b/src/set/types.h index 2eb6e44..b030a12 100644 --- a/src/set/types.h +++ b/src/set/types.h @@ -432,6 +432,7 @@ typedef enum ExpressionKind_t { ExpressionKindTransmute, ExpressionKindConstant, ExpressionKindVariable, + ExpressionKindParameter, ExpressionKindDereference, ExpressionKindAddressOf, } ExpressionKind; @@ -446,6 +447,7 @@ typedef struct Expression_t { Transmute transmute; TypeValue constant; Variable* variable; + Parameter* parameter; Dereference dereference; AddressOf addressOf; } impl; @@ -526,6 +528,7 @@ typedef struct Branch_t { typedef enum StorageExprKind_t { StorageExprKindVariable, + StorageExprKindParameter, StorageExprKindBoxAccess, StorageExprKindDereference, } StorageExprKind; @@ -535,6 +538,7 @@ typedef struct StorageExpr_t { Type* target_type; union StorageExprImpl { Variable* variable; + Parameter* parameter; BoxAccess boxAccess; StorageDereference dereference; } impl; From 0e03246fc3ef5bd237f1e277cf3f6e08e49c998b Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 12 Jul 2024 20:07:35 +0200 Subject: [PATCH 03/25] added: type check for assignment --- src/set/set.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/set/set.c b/src/set/set.c index 67b6b9e..4556c1b 100644 --- a/src/set/set.c +++ b/src/set/set.c @@ -1714,7 +1714,12 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) { return SEMANTIC_ERROR; } - // TODO: check assignment type compatability + if (!compareTypes(assign.destination->target_type, assign.value->result)) { + print_diagnostic(&assign.value->nodePtr->location, Error, "assignment requires `%s` but got `%s`", + type_to_string(assign.destination->target_type), + type_to_string(assign.value->result)); + return SEMANTIC_ERROR; + } ParentStatement->impl.assignment = assign; return SEMANTIC_OK; From 942c9484ace62e29f4c2145a2f70506dac1b6c57 Mon Sep 17 00:00:00 2001 From: servostar Date: Tue, 16 Jul 2024 19:44:57 +0200 Subject: [PATCH 04/25] fixed: parameter handling --- src/llvm/llvm-ir/expr.c | 2 +- src/llvm/llvm-ir/stmt.c | 47 ++++++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/llvm/llvm-ir/expr.c b/src/llvm/llvm-ir/expr.c index 5ff4e9c..d3a3c66 100644 --- a/src/llvm/llvm-ir/expr.c +++ b/src/llvm/llvm-ir/expr.c @@ -412,7 +412,7 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s return new_backend_impl_error(Implementation, NULL, "Variable not found"); } - if (decl.qualifier == In) { + if (decl.qualifier == In || reference) { *llvm_result = llvm_variable; } else { // no referencing, load value diff --git a/src/llvm/llvm-ir/stmt.c b/src/llvm/llvm-ir/stmt.c index 697c4b8..edd84a1 100644 --- a/src/llvm/llvm-ir/stmt.c +++ b/src/llvm/llvm-ir/stmt.c @@ -12,6 +12,27 @@ #include #include +BackendError impl_param_load( + LLVMBackendCompileUnit *unit, + LLVMBuilderRef builder, + LLVMLocalScope *scope, + const StorageExpr *expr, + LLVMValueRef* storage_target) { + BackendError err = SUCCESS; + + if (expr->impl.parameter->impl.declaration.qualifier == Out || expr->impl.parameter->impl.declaration.qualifier == InOut) { + LLVMTypeRef llvm_type = NULL; + err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.parameter->impl.declaration.type, &llvm_type); + if (err.kind != Success) { + return err; + } + + *storage_target = LLVMBuildLoad2(builder, llvm_type, *storage_target, "strg.param.out.load"); + } + + return err; +} + BackendError impl_storage_expr( LLVMBackendCompileUnit *unit, LLVMBuilderRef @@ -45,6 +66,13 @@ BackendError impl_storage_expr( return err; } + if (expr->impl.dereference.array->kind == StorageExprKindParameter) { + err = impl_param_load(unit, builder, scope, expr->impl.dereference.array, &array); + if (err.kind != Success) { + return err; + } + } + if (expr->impl.dereference.array->kind == StorageExprKindDereference) { LLVMTypeRef deref_type = NULL; err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type); @@ -216,21 +244,24 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit, param_list = call->function->impl.declaration.parameter; } - LLVMBool reference = FALSE; - Parameter parameter = g_array_index(param_list, Parameter, i); - if (is_parameter_out(¶meter)) { - reference = TRUE; - } else if (parameter.impl.declaration.type->kind == TypeKindReference) { - reference = TRUE; - } + Parameter param = g_array_index(param_list, Parameter, i); LLVMValueRef llvm_arg = NULL; - err = impl_expr(unit, scope, builder, arg, reference, &llvm_arg); + 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; } From d32b39e96095b33bfc892bf36251ac387e6ca8f9 Mon Sep 17 00:00:00 2001 From: servostar Date: Tue, 16 Jul 2024 21:25:59 +0200 Subject: [PATCH 05/25] fixed: assignment storing pointer instead of value --- src/llvm/llvm-ir/stmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm/llvm-ir/stmt.c b/src/llvm/llvm-ir/stmt.c index edd84a1..9f20c20 100644 --- a/src/llvm/llvm-ir/stmt.c +++ b/src/llvm/llvm-ir/stmt.c @@ -111,7 +111,7 @@ BackendError impl_assign_stmt( DEBUG("implementing assignment for variable: %p", assignment); LLVMValueRef llvm_value = NULL; - err = impl_expr(unit, scope, builder, assignment->value, TRUE, &llvm_value); + err = impl_expr(unit, scope, builder, assignment->value, false, &llvm_value); if (err.kind != Success) { return err; } From 0f237fd1cffad15effe5fb32cbd271358aa37b75 Mon Sep 17 00:00:00 2001 From: servostar Date: Wed, 17 Jul 2024 22:50:48 +0200 Subject: [PATCH 06/25] added: clang system call --- src/llvm/link/lld.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index 8c063d2..e804fbe 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -85,7 +85,34 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t return config; } +gboolean lld_generate_link_command(TargetLinkConfig* config, char** command) { + GString* commandString = g_string_new(""); + + g_string_append(commandString, "clang"); + + for (guint i = 0; i < config->object_file_names->len; i++) { + g_string_append(commandString, " "); + g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); + } + + *command = commandString->str; + + return true; +} + BackendError lld_link_target(TargetLinkConfig* config) { + + char* command = NULL; + lld_generate_link_command(config, &command); + + print_message(Info, "invoking binary driver with: %s", command); + + if (system(command)) { + print_message(Error, "failed generating binary..."); + } + + g_free(command); + return SUCCESS; } From 938a5c7fdfb67cde0a52cbb1b2fc05fdbad07448 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 18:27:34 +0200 Subject: [PATCH 07/25] added include rule to lexer and parser --- src/ast/ast.h | 1 + src/lex/lexer.l | 1 + src/yacc/parser.y | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/src/ast/ast.h b/src/ast/ast.h index 5c71d2c..a7be0be 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -79,6 +79,7 @@ enum AST_SyntaxElement_t { AST_AddressOf, AST_Dereference, AST_Reference, + AST_Include, AST_ELEMENT_COUNT }; diff --git a/src/lex/lexer.l b/src/lex/lexer.l index bfde8ff..e955b0e 100644 --- a/src/lex/lexer.l +++ b/src/lex/lexer.l @@ -81,6 +81,7 @@ "!" {DEBUG("\"%s\" tokenized with \'OpBitnot\'", yytext); return(OpBitnot);}; "^" {DEBUG("\"%s\" tokenized with \'OpBitxor\'", yytext); return(OpBitxor);}; "import" {DEBUG("\"%s\" tokenized with \'KeyImport\'", yytext); return(KeyImport);}; +"include" {DEBUG("\"%s\" tokenized with \'KeyInclude\'", yytext); return(KeyInclude);}; "silent" {DEBUG("\"%s\" tokenized with \'KeySilent\'", yytext); return(KeySilent);}; "box" {DEBUG("\"%s\" tokenized with \'KeyBox\'", yytext); return(KeyBox);}; "typeof" {DEBUG("\"%s\" tokenized with \'FunTypeof\'", yytext); return(FunTypeof);}; diff --git a/src/yacc/parser.y b/src/yacc/parser.y index 70f3069..29dd70c 100644 --- a/src/yacc/parser.y +++ b/src/yacc/parser.y @@ -53,6 +53,7 @@ %type opbool %type opbit %type moduleimport +%type moduleinclude %type programbody %type fundef %type fundecl @@ -109,6 +110,7 @@ %token OpBitnot %token OpBitxor %token KeyImport +%token KeyInclude %token KeySilent %token KeyBox %token FunTypeof @@ -142,6 +144,7 @@ program: program programbody {AST_push_node(root, $2); | programbody {AST_push_node(root, $1);}; programbody: moduleimport {$$ = $1;} + | moduleinclude {$$ = $1;} | fundef{$$ = $1;} | fundecl{$$ = $1;} | box{$$ = $1;} @@ -328,6 +331,9 @@ funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(new_loc(), AST_ moduleimport: KeyImport ValStr {$$ = AST_new_node(new_loc(), AST_Import, $2); DEBUG("Module-Import"); }; +moduleinclude: KeyInclude ValStr {$$ = AST_new_node(new_loc(), AST_Include, $2); + DEBUG("Module-Include"); }; + statementlist: statementlist statement {AST_push_node($1, $2); $$ = $1;} | statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL); From c4c422d89970b3eba86eb4672727eb91f7e2a4a4 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 19:55:17 +0200 Subject: [PATCH 08/25] added library binary resolving --- lib/CMakeLists.txt | 12 +++++++++--- lib/src/entry/entrypoint.c | 3 --- lib/src/io.gsc | 2 +- lib/src/mem.gsc | 2 +- lib/src/os.gsc | 2 +- lib/src/std.gsc | 6 +++--- src/ast/ast.c | 1 + src/cfg/opt.c | 30 ++++++++++++++++++++++++++++++ src/compiler.c | 6 +++++- src/llvm/link/lld.c | 12 ++++-------- src/set/set.c | 6 ++++++ src/set/types.h | 1 + 12 files changed, 62 insertions(+), 21 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 8be6998..097546c 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -16,10 +16,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/../bin/std") # add native module libraries file(GLOB_RECURSE STDLIB_IO_SOURCE_FILES src/io/*.c) -add_library(io ${STDLIB_IO_SOURCE_FILES}) +add_library(gscio ${STDLIB_IO_SOURCE_FILES}) file(GLOB_RECURSE STDLIB_MEM_SOURCE_FILES src/mem/*.c) -add_library(mem ${STDLIB_MEM_SOURCE_FILES}) +add_library(gscmem ${STDLIB_MEM_SOURCE_FILES}) file(GLOB_RECURSE STDLIB_OS_SOURCE_FILES src/os/*.c) -add_library(os ${STDLIB_OS_SOURCE_FILES}) +add_library(gscos ${STDLIB_OS_SOURCE_FILES}) + +# Complete standard library +add_library(gscstd + ${STDLIB_IO_SOURCE_FILES} + ${STDLIB_MEM_SOURCE_FILES} + ${STDLIB_OS_SOURCE_FILES}) diff --git a/lib/src/entry/entrypoint.c b/lib/src/entry/entrypoint.c index c41e482..75cf927 100644 --- a/lib/src/entry/entrypoint.c +++ b/lib/src/entry/entrypoint.c @@ -2,9 +2,6 @@ // Created by servostar on 6/10/24. // -extern void entry(void); - int main(int argc, char* argv[]) { - entry(); return 0; } diff --git a/lib/src/io.gsc b/lib/src/io.gsc index db8de9b..c729644 100644 --- a/lib/src/io.gsc +++ b/lib/src/io.gsc @@ -6,7 +6,7 @@ # | Generic Input/Output | # `----------------------------------------` -import "def.gsc" +include "def.gsc" # platform specific handle to an I/O device # can be a file, buffer, window or something else diff --git a/lib/src/mem.gsc b/lib/src/mem.gsc index 0307666..b9df686 100644 --- a/lib/src/mem.gsc +++ b/lib/src/mem.gsc @@ -6,7 +6,7 @@ # | Memory Management | # `----------------------------------------` -import "def.gsc" +include "def.gsc" # Allocate `len` bytes of heap memory # Returns a pointer to the memory as `ptr` diff --git a/lib/src/os.gsc b/lib/src/os.gsc index bfd6958..5f7a190 100644 --- a/lib/src/os.gsc +++ b/lib/src/os.gsc @@ -6,7 +6,7 @@ # | Operating System | # `----------------------------------------` -import "def.gsc" +include "def.gsc" # Return a hard coded C string identifying the underlying operating system # Will return one of the following: diff --git a/lib/src/std.gsc b/lib/src/std.gsc index cf690e3..36d6a75 100644 --- a/lib/src/std.gsc +++ b/lib/src/std.gsc @@ -7,10 +7,10 @@ # `----------------------------------------` # standard type definitions -import "def.gsc" +include "def.gsc" # I/O operations -import "io.gsc" +include "io.gsc" # memory management -import "mem.gsc" +include "mem.gsc" diff --git a/src/ast/ast.c b/src/ast/ast.c index 7da6bf5..9f00f56 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -101,6 +101,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node) { case AST_Ident: case AST_Macro: case AST_Import: + case AST_Include: case AST_Storage: case AST_Typekind: case AST_Sign: diff --git a/src/cfg/opt.c b/src/cfg/opt.c index 57ed113..22f0e98 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -212,6 +212,36 @@ TargetConfig* default_target_config_from_args() { char* default_import_path = mem_strdup(MemoryNamespaceOpt, "."); g_array_append_val(config->import_paths, default_import_path); + if (is_option_set("import-paths")) { + const Option* opt = get_option("import-paths"); + + if (opt->value != NULL) { + + const char* start = opt->value; + const char* end = NULL; + while((end = strchr(start, ',')) != NULL) { + + const int len = end - start; + char* import_path = malloc(len + 1); + memcpy(import_path, start, len); + import_path[len] = 0; + + g_array_append_val(config->import_paths, import_path); + + start = end; + } + + const int len = strlen(start); + if (len > 0) { + char* import_path = malloc(len + 1); + memcpy(import_path, start, len); + import_path[len] = 0; + + g_array_append_val(config->import_paths, import_path); + } + } + } + return config; } diff --git a/src/compiler.c b/src/compiler.c index 289daf7..7e85543 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -170,6 +170,10 @@ static void run_backend_codegen(const Module* module, const TargetConfig* target const char* get_absolute_import_path(const TargetConfig* config, const char* import_target_name) { INFO("resolving absolute path for import target: %s", import_target_name); + if (!g_str_has_suffix(import_target_name, ".gsc")) { + import_target_name = g_strjoin("", import_target_name, ".gsc", NULL); + } + for (guint i = 0; i < config->import_paths->len; i++) { const char* import_directory_path = g_array_index(config->import_paths, char*, i); @@ -204,7 +208,7 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f for (size_t i = 0; i < AST_get_child_count(root_module); i++) { AST_NODE_PTR child = AST_get_node(root_module, i); - if (child->kind == AST_Import) { + if (child->kind == AST_Import || child->kind == AST_Include) { const char* path = get_absolute_import_path(target, child->value); if (path == NULL) { diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index e1a2175..687dd3a 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -65,20 +65,16 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t g_array_append_val(config->object_file_names, target_object); INFO("resolved path of target object: %s", target_object); - // if it is an app, add entrypoint library - if (target_config->mode == Application) { - char* entrypoint = g_strdup("libentrypoint.a"); - g_array_append_val(module->imports, entrypoint); - } - // resolve absolute paths to dependent library object files DEBUG("resolving target dependencies..."); for (guint i = 0; i < module->imports->len; i++) { const char* dependency = g_array_index(module->imports, const char*, i); - const char* dependency_object = get_absolute_link_path(target_config, dependency); + const char* library = g_strjoin("", "libgsc", dependency, ".a", NULL); + + const char* dependency_object = get_absolute_link_path(target_config, library); if (dependency_object == NULL) { - ERROR("failed to resolve path to dependency object: %s", dependency); + ERROR("failed to resolve path to dependency object: %s", library); lld_delete_link_config(config); return NULL; } diff --git a/src/set/set.c b/src/set/set.c index 1ad9652..e10a4c2 100644 --- a/src/set/set.c +++ b/src/set/set.c @@ -2379,12 +2379,14 @@ Module *create_set(AST_NODE_PTR currentNode) { GHashTable *functions = g_hash_table_new(g_str_hash, g_str_equal); GHashTable *variables = g_hash_table_new(g_str_hash, g_str_equal); GArray *imports = g_array_new(FALSE, FALSE, sizeof(const char *)); + GArray *includes = g_array_new(FALSE, FALSE, sizeof(const char *)); rootModule->boxes = boxes; rootModule->types = types; rootModule->functions = functions; rootModule->variables = variables; rootModule->imports = imports; + rootModule->includes = includes; DEBUG("created Module struct"); @@ -2456,6 +2458,10 @@ Module *create_set(AST_NODE_PTR currentNode) { DEBUG("create Import"); g_array_append_val(imports, AST_get_node(currentNode, i)->value); break; + case AST_Include: + DEBUG("create Include"); + g_array_append_val(includes, AST_get_node(currentNode, i)->value); + break; default: INFO("Provided source file could not be parsed because of semantic error."); break; diff --git a/src/set/types.h b/src/set/types.h index 2eb6e44..98e9f97 100644 --- a/src/set/types.h +++ b/src/set/types.h @@ -580,6 +580,7 @@ typedef struct Module_t { GHashTable* variables; // to be resolved after the module has been parsed completely GArray* imports; + GArray* includes; } Module; From 056c62acadc6e0a9c0d0e5ff552594a301498ab8 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 21:59:29 +0200 Subject: [PATCH 09/25] added custom import and link paths to build.toml --- src/cfg/opt.c | 24 +++++++++++++++++++++++- src/llvm/link/lld.c | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/cfg/opt.c b/src/cfg/opt.c index 22f0e98..b29475d 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -103,7 +103,7 @@ TargetConfig* default_target_config() { config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin"); config->optimization_level = 1; config->root_module = NULL; - config->link_search_paths = g_array_new(FALSE, FALSE, sizeof(char*)); + config->link_search_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*)); config->lld_fatal_warnings = FALSE; config->gsc_fatal_warnings = FALSE; config->import_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*)); @@ -311,6 +311,21 @@ static void get_int(int* integer, const toml_table_t *table, const char* name) { } } +static void get_array(GArray* array, const toml_table_t *table, const char* name) { + const toml_array_t* toml_array = toml_array_in(table, name); + + if (toml_array) { + for (int i = 0; i < toml_array_nelem(toml_array); i++) { + toml_datum_t value = toml_string_at(toml_array, i); + + if (value.ok) { + char* copy = mem_strdup(MemoryNamespaceOpt, value.u.s); + g_array_append_val(array, copy); + } + } + } +} + static int parse_project_table(ProjectConfig *config, const toml_table_t *project_table) { DEBUG("parsing project table..."); @@ -387,6 +402,13 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_ if (err != PROJECT_OK) { return err; } + char* cwd = g_get_current_dir(); + + g_array_append_val(target_config->link_search_paths, cwd); + get_array(target_config->link_search_paths, target_table, "link-paths"); + + g_array_append_val(target_config->import_paths, cwd); + get_array(target_config->import_paths, target_table, "import-paths"); g_hash_table_insert(config->targets, target_config->name, target_config); diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index 801aa6a..0d3bf09 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -13,6 +13,8 @@ const char* get_absolute_link_path(const TargetConfig* config, const char* link_ for (guint i = 0; i < config->link_search_paths->len; i++) { const char* link_directory_path = g_array_index(config->link_search_paths, char*, i); + INFO("searching at: %s", link_directory_path); + char* path = g_build_filename(link_directory_path, link_target_name, NULL); char* cwd = g_get_current_dir(); char* canonical = g_canonicalize_filename(path, cwd); From fcf5e08ef0e9f6b0a250147ec490b25ddc126bb9 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 22:03:53 +0200 Subject: [PATCH 10/25] added output file option to clang --- src/llvm/link/lld.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index 0d3bf09..781944b 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -100,6 +100,9 @@ gboolean lld_generate_link_command(TargetLinkConfig* config, char** command) { g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); } + g_string_append(commandString, " -o "); + g_string_append(commandString, config->output_file); + *command = commandString->str; return true; From 11594bf44cad4acde3bf691026f347ef26ecc107 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 22:41:11 +0200 Subject: [PATCH 11/25] added binary driver clang --- src/cfg/opt.h | 1 + src/compiler.c | 3 +++ src/link/clang/driver.c | 42 ++++++++++++++++++++++++++++++++++++ src/link/clang/driver.h | 14 ++++++++++++ src/link/driver.h | 18 ++++++++++++++++ src/link/lib.c | 47 +++++++++++++++++++++++++++++++++++++++++ src/link/lib.h | 16 ++++++++++++++ src/llvm/link/lld.c | 31 ++++----------------------- 8 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 src/link/clang/driver.c create mode 100644 src/link/clang/driver.h create mode 100644 src/link/driver.h create mode 100644 src/link/lib.c create mode 100644 src/link/lib.h diff --git a/src/cfg/opt.h b/src/cfg/opt.h index 9b61def..e80f91f 100644 --- a/src/cfg/opt.h +++ b/src/cfg/opt.h @@ -24,6 +24,7 @@ typedef struct TargetLinkConfig_t { // colorize linker output bool colorize; char* output_file; + char* driver; } TargetLinkConfig; typedef enum TargetCompilationMode_t { diff --git a/src/compiler.c b/src/compiler.c index 7e85543..0ca4c9d 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -15,6 +15,7 @@ #include #include #include +#include #define GRAPHVIZ_FILE_EXTENSION "gv" @@ -355,6 +356,8 @@ static void build_project(ModuleFileStack *unit) { void run_compiler() { ModuleFileStack files = new_file_stack(); + link_init(); + if (is_option_set("build")) { build_project(&files); } else if (is_option_set("compile")) { diff --git a/src/link/clang/driver.c b/src/link/clang/driver.c new file mode 100644 index 0000000..6d4e0cf --- /dev/null +++ b/src/link/clang/driver.c @@ -0,0 +1,42 @@ +// +// Created by servostar on 18.07.24. +// + +#include +#include +#include + +bool clang_link(TargetLinkConfig* config) { + + GString* commandString = g_string_new(""); + + g_string_append(commandString, "clang"); + + for (guint i = 0; i < config->object_file_names->len; i++) { + g_string_append(commandString, " "); + g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); + } + + g_string_append(commandString, " -o "); + g_string_append(commandString, config->output_file); + + print_message(Info, "invoking binary link with: %s", commandString->str); + + if (system(commandString->str)) { + return false; + } + + g_string_free(commandString, true); + + return true; +} + +BinaryDriver* clang_get_driver() { + + BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof (BinaryDriver)); + + driver->name = "clang"; + driver->link_func = &clang_link; + + return driver; +} diff --git a/src/link/clang/driver.h b/src/link/clang/driver.h new file mode 100644 index 0000000..e8f15da --- /dev/null +++ b/src/link/clang/driver.h @@ -0,0 +1,14 @@ +// +// Created by servostar on 18.07.24. +// + +#ifndef GEMSTONE_CLANG_DRIVER_H +#define GEMSTONE_CLANG_DRIVER_H + +#include + +bool clang_link(TargetLinkConfig* config); + +BinaryDriver* clang_get_driver(); + +#endif // GEMSTONE_CLANG_DRIVER_H diff --git a/src/link/driver.h b/src/link/driver.h new file mode 100644 index 0000000..f797778 --- /dev/null +++ b/src/link/driver.h @@ -0,0 +1,18 @@ +// +// Created by servostar on 18.07.24. +// + +#ifndef GEMSTONE_DRIVER_H +#define GEMSTONE_DRIVER_H + +#include + +//! @brief Function a binary driver used to link files +typedef bool (*driver_link)(TargetLinkConfig*); + +typedef struct BinaryDriver_t { + const char* name; + driver_link link_func; +} BinaryDriver; + +#endif //GEMSTONE_DRIVER_H diff --git a/src/link/lib.c b/src/link/lib.c new file mode 100644 index 0000000..81ccdb8 --- /dev/null +++ b/src/link/lib.c @@ -0,0 +1,47 @@ +// +// Created by servostar on 18.07.24. +// + +#include +#include +#include +#include + +static driver_init AVAILABLE_DRIVER[] = { + clang_get_driver +}; + +static GHashTable* binary_driver = NULL; + +void link_init() { + INFO("initializing binary driver..."); + + if (binary_driver == NULL) { + binary_driver = mem_new_g_hash_table(MemoryNamespaceLld, g_str_hash, g_str_equal); + + for (unsigned long int i = 0; i < sizeof(AVAILABLE_DRIVER)/sizeof(driver_init); i++) { + BinaryDriver* driver = AVAILABLE_DRIVER[i](); + g_hash_table_insert(binary_driver, (gpointer) driver->name, driver); + INFO("initialized `%s` driver", driver->name); + } + } +} + +bool link_run(TargetLinkConfig* config) { + + if (g_hash_table_contains(binary_driver, config->driver)) { + print_message(Info, "Invoking binary driver: %s", config->driver); + + BinaryDriver* driver = g_hash_table_lookup(binary_driver, config->driver); + + if (!driver->link_func(config)) { + print_message(Error, "Driver %s failed", config->driver); + return false; + } + return true; + + } else { + print_message(Error, "Binary driver not available: `%s`", config->driver); + return false; + } +} diff --git a/src/link/lib.h b/src/link/lib.h new file mode 100644 index 0000000..44dcbde --- /dev/null +++ b/src/link/lib.h @@ -0,0 +1,16 @@ +// +// Created by servostar on 18.07.24. +// + +#ifndef GEMSTONE_LIB_H +#define GEMSTONE_LIB_H + +#include + +typedef BinaryDriver* (*driver_init)(); + +void link_init(); + +bool link_run(TargetLinkConfig*); + +#endif //GEMSTONE_LIB_H diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index 781944b..012c924 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -6,6 +6,7 @@ #include #include #include +#include const char* get_absolute_link_path(const TargetConfig* config, const char* link_target_name) { INFO("resolving absolute path for link target: %s", link_target_name); @@ -45,6 +46,7 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t config->fatal_warnings = target_config->lld_fatal_warnings; config->object_file_names = g_array_new(FALSE, FALSE, sizeof(char*)); config->colorize = stdout_supports_ansi_esc(); + config->driver = mem_strdup(MemoryNamespaceLld, "clang"); // append build object file char* basename = g_strjoin(".", target_config->name, "o", NULL); @@ -90,37 +92,12 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t return config; } -gboolean lld_generate_link_command(TargetLinkConfig* config, char** command) { - GString* commandString = g_string_new(""); - - g_string_append(commandString, "clang"); - - for (guint i = 0; i < config->object_file_names->len; i++) { - g_string_append(commandString, " "); - g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); - } - - g_string_append(commandString, " -o "); - g_string_append(commandString, config->output_file); - - *command = commandString->str; - - return true; -} - BackendError lld_link_target(TargetLinkConfig* config) { - char* command = NULL; - lld_generate_link_command(config, &command); - - print_message(Info, "invoking binary driver with: %s", command); - - if (system(command)) { - print_message(Error, "failed generating binary..."); + if (link_run(config)) { + return new_backend_impl_error(Implementation, NULL, "linking failed"); } - g_free(command); - return SUCCESS; } From 7cfbeb085dac3878c87c52afb2e67c40a4f465ac Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 22:50:37 +0200 Subject: [PATCH 12/25] added list-driver option --- src/cfg/opt.c | 1 + src/compiler.c | 2 -- src/link/lib.c | 21 +++++++++++++++++++++ src/link/lib.h | 2 ++ src/main.c | 8 ++++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/cfg/opt.c b/src/cfg/opt.c index b29475d..f5f47aa 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -268,6 +268,7 @@ void print_help(void) { " --debug print debug logs (if not disabled at compile time)", " --version print the version", " --list-targets print a list of all available targets supported", + " --list-driver print a list of all available binary driver", " --help print this help dialog", " --color-always always colorize output", " --print-gc-stats print statistics of the garbage collector" diff --git a/src/compiler.c b/src/compiler.c index 0ca4c9d..103f07d 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -356,8 +356,6 @@ static void build_project(ModuleFileStack *unit) { void run_compiler() { ModuleFileStack files = new_file_stack(); - link_init(); - if (is_option_set("build")) { build_project(&files); } else if (is_option_set("compile")) { diff --git a/src/link/lib.c b/src/link/lib.c index 81ccdb8..15cd7fa 100644 --- a/src/link/lib.c +++ b/src/link/lib.c @@ -21,9 +21,17 @@ void link_init() { for (unsigned long int i = 0; i < sizeof(AVAILABLE_DRIVER)/sizeof(driver_init); i++) { BinaryDriver* driver = AVAILABLE_DRIVER[i](); + + if (driver == NULL) { + ERROR("failed to init driver by index: %d", i); + continue; + } + g_hash_table_insert(binary_driver, (gpointer) driver->name, driver); INFO("initialized `%s` driver", driver->name); } + } else { + PANIC("binary driver already initialized"); } } @@ -45,3 +53,16 @@ bool link_run(TargetLinkConfig* config) { return false; } } + +void link_print_available_driver() { + printf("Available binary driver:\n"); + + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init(&iter, binary_driver); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + + printf(" - %s\n", (char*) key); + } +} diff --git a/src/link/lib.h b/src/link/lib.h index 44dcbde..cf592a1 100644 --- a/src/link/lib.h +++ b/src/link/lib.h @@ -13,4 +13,6 @@ void link_init(); bool link_run(TargetLinkConfig*); +void link_print_available_driver(); + #endif //GEMSTONE_LIB_H diff --git a/src/main.c b/src/main.c index 5b222a4..ea6aef9 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include #include #include +#include /** * @brief Log a debug message to inform about beginning exit procedures @@ -38,6 +39,8 @@ void setup(int argc, char *argv[]) { lex_init(); + link_init(); + DEBUG("finished starting up gemstone..."); } @@ -64,6 +67,11 @@ int main(int argc, char *argv[]) { exit(0); } + if (is_option_set("list-driver")) { + link_print_available_driver(); + exit(0); + } + run_compiler(); if (is_option_set("print-gc-stats")) { From 9786abc212002bbe81acfe542877541705db8607 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 23:00:38 +0200 Subject: [PATCH 13/25] added gcc driver --- src/link/gcc/driver.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/link/gcc/driver.h | 14 ++++++++++++++ src/link/lib.c | 6 +++++- src/link/lib.h | 2 +- 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/link/gcc/driver.c create mode 100644 src/link/gcc/driver.h diff --git a/src/link/gcc/driver.c b/src/link/gcc/driver.c new file mode 100644 index 0000000..854bf0c --- /dev/null +++ b/src/link/gcc/driver.c @@ -0,0 +1,42 @@ +// +// Created by servostar on 18.07.24. +// + +#include +#include +#include + +bool gcc_link(TargetLinkConfig* config) { + + GString* commandString = g_string_new(""); + + g_string_append(commandString, "gcc"); + + for (guint i = 0; i < config->object_file_names->len; i++) { + g_string_append(commandString, " "); + g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); + } + + g_string_append(commandString, " -o "); + g_string_append(commandString, config->output_file); + + print_message(Info, "invoking binary link with: %s", commandString->str); + + if (system(commandString->str)) { + return false; + } + + g_string_free(commandString, true); + + return true; +} + +BinaryDriver* gcc_get_driver() { + + BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof (BinaryDriver)); + + driver->name = "gcc"; + driver->link_func = &gcc_link; + + return driver; +} diff --git a/src/link/gcc/driver.h b/src/link/gcc/driver.h new file mode 100644 index 0000000..8227353 --- /dev/null +++ b/src/link/gcc/driver.h @@ -0,0 +1,14 @@ +// +// Created by servostar on 18.07.24. +// + +#ifndef GEMSTONE_GCC_DRIVER_H +#define GEMSTONE_GCC_DRIVER_H + +#include + +bool gcc_link(TargetLinkConfig* config); + +BinaryDriver* gcc_get_driver(); + +#endif // GEMSTONE_GCC_DRIVER_H diff --git a/src/link/lib.c b/src/link/lib.c index 15cd7fa..6e4aaf1 100644 --- a/src/link/lib.c +++ b/src/link/lib.c @@ -7,8 +7,12 @@ #include #include +#include +#include + static driver_init AVAILABLE_DRIVER[] = { - clang_get_driver + clang_get_driver, + gcc_get_driver }; static GHashTable* binary_driver = NULL; diff --git a/src/link/lib.h b/src/link/lib.h index cf592a1..74ac352 100644 --- a/src/link/lib.h +++ b/src/link/lib.h @@ -5,7 +5,7 @@ #ifndef GEMSTONE_LIB_H #define GEMSTONE_LIB_H -#include +#include typedef BinaryDriver* (*driver_init)(); From 09b3b8618035fdc6ffb2e11bfa0efd1fcce2cb48 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 23:05:41 +0200 Subject: [PATCH 14/25] added configuration options for driver --- src/cfg/opt.c | 12 ++++++++++++ src/cfg/opt.h | 2 ++ src/link/driver.h | 2 ++ src/llvm/link/lld.c | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/cfg/opt.c b/src/cfg/opt.c index f5f47aa..eb0ab8e 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -9,6 +9,7 @@ #include #include #include +#include static GHashTable* args = NULL; @@ -98,6 +99,7 @@ TargetConfig* default_target_config() { config->print_ast = false; config->print_asm = false; config->print_ir = false; + config->driver = DEFAULT_DRIVER; config->mode = Application; config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive"); config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin"); @@ -160,6 +162,14 @@ TargetConfig* default_target_config_from_args() { } } + if (is_option_set("driver")) { + const Option* opt = get_option("driver"); + + if (opt->value != NULL) { + config->driver = mem_strdup(MemoryNamespaceOpt, (char*) opt->value); + } + } + // TODO: free vvvvvvvvvvvvv char* cwd = g_get_current_dir(); g_array_append_val(config->link_search_paths, cwd); @@ -259,6 +269,7 @@ void print_help(void) { " --print-ir print resulting LLVM-IR to a file", " --mode=[app|lib] set the compilation mode to either application or library", " --output=name name of output files without extension", + " --driver set binary driver to use", " --link-paths=[paths,] set a list of directories to for libraries in", " --all-fatal-warnings treat all warnings as errors", " --lld-fatal-warnings treat linker warnings as errors", @@ -389,6 +400,7 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_ get_bool(&target_config->print_asm, target_table, "print_asm"); get_bool(&target_config->print_ir, target_table, "print_ir"); + get_str(&target_config->driver, target_table, "driver"); get_str(&target_config->root_module, target_table, "root"); get_str(&target_config->output_directory, target_table, "output"); get_str(&target_config->archive_directory, target_table, "archive"); diff --git a/src/cfg/opt.h b/src/cfg/opt.h index e80f91f..5699145 100644 --- a/src/cfg/opt.h +++ b/src/cfg/opt.h @@ -51,6 +51,8 @@ typedef struct TargetConfig_t { char* output_directory; // output directory for intermediate representations (LLVM-IR, Assembly, ...) char* archive_directory; + // binary driver for executable generation + char* driver; // mode of compilation TargetCompilationMode mode; // number between 1 and 3 diff --git a/src/link/driver.h b/src/link/driver.h index f797778..9eba996 100644 --- a/src/link/driver.h +++ b/src/link/driver.h @@ -7,6 +7,8 @@ #include +#define DEFAULT_DRIVER "clang" + //! @brief Function a binary driver used to link files typedef bool (*driver_link)(TargetLinkConfig*); diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index 012c924..5d596c2 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -46,7 +46,7 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t config->fatal_warnings = target_config->lld_fatal_warnings; config->object_file_names = g_array_new(FALSE, FALSE, sizeof(char*)); config->colorize = stdout_supports_ansi_esc(); - config->driver = mem_strdup(MemoryNamespaceLld, "clang"); + config->driver = target_config->driver; // append build object file char* basename = g_strjoin(".", target_config->name, "o", NULL); From b08b04ebf9bfb8dffd1a9954dbc9396198c77703 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 23:09:12 +0200 Subject: [PATCH 15/25] fixed no error on missing driver --- src/llvm/link/lld.c | 4 ++-- src/llvm/parser.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index 5d596c2..cb0fb2b 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -95,10 +95,10 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t BackendError lld_link_target(TargetLinkConfig* config) { if (link_run(config)) { - return new_backend_impl_error(Implementation, NULL, "linking failed"); + return SUCCESS; } - return SUCCESS; + return new_backend_impl_error(Implementation, NULL, "linking failed"); } void lld_delete_link_config(TargetLinkConfig* config) { diff --git a/src/llvm/parser.c b/src/llvm/parser.c index 201f28b..ac009f5 100644 --- a/src/llvm/parser.c +++ b/src/llvm/parser.c @@ -260,7 +260,7 @@ BackendError parse_module(const Module* module, const TargetConfig* config) { TargetLinkConfig* link_config = lld_create_link_config(&target, config, module); if (link_config != NULL) { - lld_link_target(link_config); + err = lld_link_target(link_config); lld_delete_link_config(link_config); } else { From 6596edf6f8acdff11c3e71f3a20b4fdf30ffcbda Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 23:12:39 +0200 Subject: [PATCH 16/25] fixed test ast_print_node --- tests/ast/test_ast.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ast/test_ast.py b/tests/ast/test_ast.py index d7f9665..b153c33 100644 --- a/tests/ast/test_ast.py +++ b/tests/ast/test_ast.py @@ -84,6 +84,7 @@ def run_check_print_node(): 53 address of 54 deref 55 ref +56 value """ == p.stdout From cedb12d7b6f3d2eb2d8501d9ba6ffbf4bf8ae098 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 23:12:47 +0200 Subject: [PATCH 17/25] fixed failing check --- src/set/set.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/set/set.c b/src/set/set.c index 6b27021..66f8f71 100644 --- a/src/set/set.c +++ b/src/set/set.c @@ -1483,7 +1483,7 @@ Expression *createExpression(AST_NODE_PTR currentNode) { return NULL; } - if (expression->impl.parameter->kind == VariableKindDeclaration) { + if (expression->impl.parameter->kind == ParameterDeclarationKind) { expression->result = expression->impl.parameter->impl.declaration.type; } else { expression->result = expression->impl.parameter->impl.definiton.declaration.type; @@ -1702,7 +1702,7 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) { return SEMANTIC_ERROR; } - if (strg_expr->kind == StorageExprKindParameter) { + if (strg_expr->kind == AST_Parameter) { if (getParameterQualifier(assign.destination->impl.parameter) == In) { print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`", assign.destination->impl.parameter->name); return SEMANTIC_ERROR; From 2a05b066157e09e2d67b30ab65c774a565a107c3 Mon Sep 17 00:00:00 2001 From: servostar Date: Thu, 18 Jul 2024 23:26:53 +0200 Subject: [PATCH 18/25] fixed segfault --- src/cfg/opt.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cfg/opt.c b/src/cfg/opt.c index eb0ab8e..5853082 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -69,7 +69,7 @@ GArray* get_non_options_after(const char* command) { return NULL; } - GArray* array = g_array_new(FALSE, FALSE, sizeof(const char*)); + GArray* array = mem_new_g_array(MemoryNamespaceOpt, sizeof(const char*)); GHashTableIter iter; gpointer key, value; @@ -83,7 +83,6 @@ GArray* get_non_options_after(const char* command) { } if (array->len == 0) { - g_array_free(array, FALSE); return NULL; } @@ -215,8 +214,6 @@ TargetConfig* default_target_config_from_args() { } config->root_module = mem_strdup(MemoryNamespaceOpt, ((char**) files->data) [0]); - - g_array_free(files, TRUE); } char* default_import_path = mem_strdup(MemoryNamespaceOpt, "."); @@ -354,7 +351,7 @@ static int parse_project_table(ProjectConfig *config, const toml_table_t *projec // author names toml_array_t *authors = toml_array_in(project_table, "authors"); if (authors) { - config->authors = g_array_new(FALSE, FALSE, sizeof(char *)); + config->authors = mem_new_g_array(MemoryNamespaceOpt, sizeof(char *)); for (int i = 0;; i++) { toml_datum_t author = toml_string_at(authors, i); @@ -437,7 +434,7 @@ static int parse_targets(ProjectConfig *config, const toml_table_t *root) { return PROJECT_SEMANTIC_ERR; } - config->targets = g_hash_table_new(g_str_hash, g_str_equal); + config->targets = mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal); for (int i = 0; i < MAX_TARGETS_PER_PROJECT; i++) { const char *key = toml_key_in(targets, i); @@ -502,7 +499,6 @@ void delete_target_config(TargetConfig* config) { for (guint i = 0; i < config->link_search_paths->len; i++) { free(g_array_index(config->link_search_paths, char*, i)); } - g_array_free(config->link_search_paths, TRUE); } mem_free(config); } @@ -512,7 +508,7 @@ void delete_project_config(ProjectConfig* config) { mem_free(config->name); } if (config->authors != NULL) { - g_array_free(config->authors, TRUE); + mem_free(config->authors); } if (config->desc != NULL) { mem_free(config->desc); From c0ed2f79b89314bc1744d1571b3cd12ae575ff93 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 19 Jul 2024 07:20:27 +0200 Subject: [PATCH 19/25] added architecture section to README --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index daaaf32..f6761a5 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,51 @@ Gemstone is a programming language compiler (short: GSC) written in C based on flex and GNU bison. It uses LLVM to produce optimized native binaries for many platforms and uses its own builtin build system for more complex project management. +## Architecture + +Gemstone is a LALR enabled non-reentrant compiler utilizing a linear flow of components. The compiler has multiple stages of operation, each representing a crucial step in compilation. + +```mermaid +--- +title: GSC Architecture Overview +--- +flowchart LR + lex["`**Lexical Analysis** + tokenization via flex`"] + bison["`**Syntax Analysis** + parsing via bison`"] + set["`**Semantic Analysis** + parse tree generation`"] + llvm["`**Codegen** + code generation via LLVM`"] + driver["`**Linking** + Linkage via Clang/GCC`"] + + start(("Start")) --> lex + + subgraph compile AST + lex --> bison + end + + subgraph Validation + bison --> import{"Import/Include?"} + import --> |yes| ast[[compile AST]] --> merge["Merge AST"] --> import + import --> |no| set + set --> llvm + end + + stop(("End")) + + subgraph Codegen + llvm --> lib{"Produce Library?"} + lib -->|no| driver --> executable(["Executable"]) + lib -->|yes| library(["Library"]) + end + + library --> stop + executable --> stop +``` + ## Dependencies (build) ### Windows 11 From 1d265cfc954eea55f0127804f970b4a8b4176a78 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 19 Jul 2024 21:28:38 +0200 Subject: [PATCH 20/25] added badges and descriptive header to README.md --- README.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f6761a5..fd72384 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,21 @@ -
- +
gemstone logo - +
+

+ Open source programming language compiler based on LLVM, GLib and GNU Bison/Flex +
+ capable of multi target cross compilation powered by simple build system. +

+
+ + + + +
-
-## Gemstone +## About Gemstone is a programming language compiler (short: GSC) written in C based on flex and GNU bison. It uses LLVM to produce optimized native binaries for many platforms and uses its own builtin build system for more complex project management. From 00866aa7f1a9f050d1f86db2b13ae56241729636 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 19 Jul 2024 21:29:47 +0200 Subject: [PATCH 21/25] changed alignment method to deprecated HTML --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd72384..96d9404 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -
+
gemstone logo

From 8d62ff9f94259b1877cd825335639fe7aefb6024 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 19 Jul 2024 21:59:59 +0200 Subject: [PATCH 22/25] added language badges --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 96d9404..ea6431b 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ +
+ + +

## About From 9bc0605cfab8c078abcc01797b88fa15159e8634 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 19 Jul 2024 22:07:35 +0200 Subject: [PATCH 23/25] changed ASCII diagram to mermaid chart --- README.md | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ea6431b..70d8240 100644 --- a/README.md +++ b/README.md @@ -136,33 +136,23 @@ For creating the build pipeline build the Dockerfile in the root folder of this Then the make targets are generated. Running `make release` will build gemstone from source in release mode. The generated binaries can be found either in `bin/release/gsc` or `bin/debug/gsc` depending on the chosen target. The following graph visualizes the build pipeline: -``` - SDK (environment) - │ - │ configure build environment - │ cmake, make, gcc, yacc, lex - │ - ▼ - Devkit (pipeline) - │ - │ create build pipeline - │ create make targets - ▼ - Pipeline - - -yacc (generate files) GCC (compile) Extra Source Files (src/*.c) -│ │ │ -├─ parser.tab.h ─────────────►│◄────────────────────┘ -│ │ -└─ parser.tab.c ─────────────►│ - │ -lex (generate file) │ -│ │ -└─ lexer.ll.c ──────────────►│ - │ - ▼ - gsc +```mermaid +flowchart LR + + subgraph Docker + alpine[Alpine Linux] --> sdk[SDK] --> dev[Devkit] + end + + subgraph Build + dev --> |generate parser| bison[Bison] + dev --> |generate lexer| flex[Flex] + bison --> cc[GCC/Clang/MSVC] + flex --> cc + cc --> debug + cc --> release + cc --> check + end + ``` ## Docker images From ee8809a3932caa435c7e809638154469886f01b6 Mon Sep 17 00:00:00 2001 From: servostar Date: Fri, 19 Jul 2024 22:22:35 +0200 Subject: [PATCH 24/25] fixed uninit err in backend --- src/llvm/llvm-ir/types.c | 2 +- tests/input_file/test.gem | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/llvm/llvm-ir/types.c b/src/llvm/llvm-ir/types.c index f699e97..c64ed6e 100644 --- a/src/llvm/llvm-ir/types.c +++ b/src/llvm/llvm-ir/types.c @@ -321,7 +321,7 @@ BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, gpointer key = NULL; gpointer val = NULL; - BackendError err; + BackendError err = SUCCESS; while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) { err = impl_type_define(unit, (Typedefine*) val, (const char*)key, scope); diff --git a/tests/input_file/test.gem b/tests/input_file/test.gem index 991288d..3479ad3 100644 --- a/tests/input_file/test.gem +++ b/tests/input_file/test.gem @@ -1,6 +1,4 @@ -import "std.io" - -fun main { - print("Hello, World!!!") -} \ No newline at end of file +fun main(out int: ret) { + ret = 56 as int +} From a57691cace54926c8533de26e3cac401eee03df0 Mon Sep 17 00:00:00 2001 From: servostar Date: Sun, 21 Jul 2024 01:36:44 +0200 Subject: [PATCH 25/25] added driver test fixed memory leaks added hello world test --- .env | 2 +- Dockerfile | 4 +- sdk/Dockerfile | 4 +- src/cfg/opt.c | 76 +++++++++------ src/cfg/opt.h | 2 + src/compiler.c | 25 +++-- src/io/files.c | 12 ++- src/llvm/backend.c | 7 +- src/llvm/link/lld.c | 26 +++-- src/llvm/llvm-ir/func.c | 4 +- src/llvm/parser.c | 9 +- src/main.c | 2 + src/mem/cache.h | 1 + src/set/set.c | 124 +++++++++++++----------- tests/CMakeLists.txt | 2 + tests/driver/CMakeLists.txt | 13 +++ tests/driver/clang/build.toml | 19 ++++ tests/driver/clang/main.gsc | 28 ++++++ tests/driver/clang/test_driver_clang.py | 29 ++++++ tests/driver/gcc/build.toml | 19 ++++ tests/driver/gcc/main.gsc | 28 ++++++ tests/driver/gcc/test_driver_gcc.py | 29 ++++++ tests/hello_world/CMakeLists.txt | 9 ++ tests/hello_world/build.toml | 19 ++++ tests/hello_world/main.gsc | 28 ++++++ tests/hello_world/test_hello_world.py | 29 ++++++ tests/input_file/CMakeLists.txt | 2 +- tests/input_file/{test.gem => test.gsc} | 0 28 files changed, 430 insertions(+), 122 deletions(-) create mode 100644 tests/driver/CMakeLists.txt create mode 100644 tests/driver/clang/build.toml create mode 100644 tests/driver/clang/main.gsc create mode 100644 tests/driver/clang/test_driver_clang.py create mode 100644 tests/driver/gcc/build.toml create mode 100644 tests/driver/gcc/main.gsc create mode 100644 tests/driver/gcc/test_driver_gcc.py create mode 100644 tests/hello_world/CMakeLists.txt create mode 100644 tests/hello_world/build.toml create mode 100644 tests/hello_world/main.gsc create mode 100644 tests/hello_world/test_hello_world.py rename tests/input_file/{test.gem => test.gsc} (100%) diff --git a/.env b/.env index 6eb74fb..b31e782 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -SDK=0.2.5-alpine-3.19.1 +SDK=0.2.6-alpine-3.19.1 diff --git a/Dockerfile b/Dockerfile index a68c334..6674f53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ -FROM servostar/gemstone:sdk-0.2.5-alpine-3.19.1 +FROM servostar/gemstone:sdk-0.2.6-alpine-3.19.1 LABEL authors="servostar" -LABEL version="0.2.5" +LABEL version="0.2.6" LABEL description="docker image for setting up the build pipeline on SDK" LABEL website="https://github.com/Servostar/gemstone" diff --git a/sdk/Dockerfile b/sdk/Dockerfile index 1cba1d3..5bfaf89 100644 --- a/sdk/Dockerfile +++ b/sdk/Dockerfile @@ -1,11 +1,11 @@ FROM alpine:3.19.1 LABEL authors="servostar" -LABEL version="0.2.5" +LABEL version="0.2.6" 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 glib glib-dev llvm17-libs llvm17-dev +RUN apk add build-base gcc clang make cmake bison flex git python3 graphviz glib glib-dev llvm17-libs llvm17-dev # create user for build RUN adduser --disabled-password lorang diff --git a/src/cfg/opt.c b/src/cfg/opt.c index 5853082..8a946b6 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -98,7 +98,7 @@ TargetConfig* default_target_config() { config->print_ast = false; config->print_asm = false; config->print_ir = false; - config->driver = DEFAULT_DRIVER; + config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER); config->mode = Application; config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive"); config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin"); @@ -169,9 +169,10 @@ TargetConfig* default_target_config_from_args() { } } - // TODO: free vvvvvvvvvvvvv char* cwd = g_get_current_dir(); - g_array_append_val(config->link_search_paths, cwd); + char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd); + g_array_append_val(config->link_search_paths, cached_cwd); + free(cwd); if (is_option_set("link-paths")) { const Option* opt = get_option("link-paths"); @@ -183,7 +184,7 @@ TargetConfig* default_target_config_from_args() { while((end = strchr(start, ',')) != NULL) { const int len = end - start; - char* link_path = malloc(len + 1); + char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1); memcpy(link_path, start, len); link_path[len] = 0; @@ -194,7 +195,7 @@ TargetConfig* default_target_config_from_args() { const int len = strlen(start); if (len > 0) { - char* link_path = malloc(len + 1); + char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1); memcpy(link_path, start, len); link_path[len] = 0; @@ -213,7 +214,7 @@ TargetConfig* default_target_config_from_args() { print_message(Warning, "Got more than one file to compile, using first, ignoring others."); } - config->root_module = mem_strdup(MemoryNamespaceOpt, ((char**) files->data) [0]); + config->root_module = mem_strdup(MemoryNamespaceOpt, g_array_index(files, char*, 0)); } char* default_import_path = mem_strdup(MemoryNamespaceOpt, "."); @@ -229,7 +230,7 @@ TargetConfig* default_target_config_from_args() { while((end = strchr(start, ',')) != NULL) { const int len = end - start; - char* import_path = malloc(len + 1); + char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1); memcpy(import_path, start, len); import_path[len] = 0; @@ -240,7 +241,7 @@ TargetConfig* default_target_config_from_args() { const int len = strlen(start); if (len > 0) { - char* import_path = malloc(len + 1); + char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1); memcpy(import_path, start, len); import_path[len] = 0; @@ -382,7 +383,7 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) { *mode = Library; return PROJECT_OK; } - printf("Invalid project configuration, mode is invalid: %s\n\n", name); + print_message(Error, "Invalid project configuration, mode is invalid: %s", name); return PROJECT_SEMANTIC_ERR; } @@ -413,11 +414,13 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_ return err; } char* cwd = g_get_current_dir(); + char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd); + free(cwd); - g_array_append_val(target_config->link_search_paths, cwd); + g_array_append_val(target_config->link_search_paths, cached_cwd); get_array(target_config->link_search_paths, target_table, "link-paths"); - g_array_append_val(target_config->import_paths, cwd); + g_array_append_val(target_config->import_paths, cached_cwd); get_array(target_config->import_paths, target_table, "import-paths"); g_hash_table_insert(config->targets, target_config->name, target_config); @@ -436,14 +439,14 @@ static int parse_targets(ProjectConfig *config, const toml_table_t *root) { config->targets = mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal); - for (int i = 0; i < MAX_TARGETS_PER_PROJECT; i++) { + for (int i = 0; i < toml_table_ntab(targets); i++) { const char *key = toml_key_in(targets, i); if (key == NULL) break; toml_table_t *target = toml_table_in(targets, key); - parse_target(config, target, key); + parse_target(config, target, mem_strdup(MemoryNamespaceOpt, (char*) key)); } return PROJECT_OK; @@ -455,8 +458,7 @@ int load_project_config(ProjectConfig *config) { FILE *config_file = fopen(PROJECT_CONFIG_FILE, "r"); if (config_file == NULL) { print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE, strerror(errno)); - INFO("project file not found"); - return PROJECT_TOML_ERR; + return PROJECT_SEMANTIC_ERR; } char err_buf[TOML_ERROR_MSG_BUF]; @@ -464,21 +466,24 @@ int load_project_config(ProjectConfig *config) { toml_table_t *conf = toml_parse_file(config_file, err_buf, sizeof(err_buf)); fclose(config_file); - if (conf == NULL) { + if (conf != NULL) { + int status = PROJECT_SEMANTIC_ERR; + toml_table_t *project = toml_table_in(conf, "project"); + + if (project != NULL) { + if (parse_project_table(config, project) == PROJECT_OK) { + status = parse_targets(config, conf); + } + } else { + print_message(Error, "Invalid project configuration: missing project table."); + } + + toml_free(conf); + return status; + } else { print_message(Error, "Invalid project configuration: %s", err_buf); - return PROJECT_SEMANTIC_ERR; } - toml_table_t *project = toml_table_in(conf, "project"); - if (project == NULL) { - print_message(Error, "Invalid project configuration: missing project table."); - } - - if (parse_project_table(config, project) == PROJECT_OK) { - return parse_targets(config, conf); - } - - toml_free(conf); return PROJECT_SEMANTIC_ERR; } @@ -497,7 +502,7 @@ void delete_target_config(TargetConfig* config) { } if (config->link_search_paths) { for (guint i = 0; i < config->link_search_paths->len; i++) { - free(g_array_index(config->link_search_paths, char*, i)); + mem_free(g_array_index(config->link_search_paths, char*, i)); } } mem_free(config); @@ -527,7 +532,7 @@ void delete_project_config(ProjectConfig* config) { delete_target_config(val); } - g_hash_table_destroy(config->targets); + mem_free(config->targets); } mem_free_from(MemoryNamespaceOpt, config); @@ -545,3 +550,16 @@ ProjectConfig* default_project_config() { return config; } + +static void* toml_cached_malloc(size_t bytes) { + return mem_alloc(MemoryNamespaceTOML, bytes); +} + +static void toml_cached_free(void* ptr) { + mem_free(ptr); +} + +void init_toml() { + INFO("setting up cached memory for TOML C99..."); + toml_set_memutil(toml_cached_malloc, toml_cached_free); +} diff --git a/src/cfg/opt.h b/src/cfg/opt.h index 5699145..06e6f1d 100644 --- a/src/cfg/opt.h +++ b/src/cfg/opt.h @@ -186,4 +186,6 @@ const Option* get_option(const char* option); [[nodiscard("must be freed")]] GArray* get_non_options_after(const char* command); +void init_toml(); + #endif //GEMSTONE_OPT_H diff --git a/src/compiler.c b/src/compiler.c index 103f07d..a515009 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -15,7 +15,6 @@ #include #include #include -#include #define GRAPHVIZ_FILE_EXTENSION "gv" @@ -166,13 +165,18 @@ static void run_backend_codegen(const Module* module, const TargetConfig* target print_message(Info, "Compilation finished successfully"); err = deinit_backend(); + if (err.kind != Success) { + ERROR("Unable to deinit backend: %s", err.impl.message); + } } const char* get_absolute_import_path(const TargetConfig* config, const char* import_target_name) { INFO("resolving absolute path for import target: %s", import_target_name); if (!g_str_has_suffix(import_target_name, ".gsc")) { - import_target_name = g_strjoin("", import_target_name, ".gsc", NULL); + char* full_filename = g_strjoin("", import_target_name, ".gsc", NULL); + import_target_name = mem_strdup(MemoryNamespaceLld, full_filename); + g_free(full_filename); } for (guint i = 0; i < config->import_paths->len; i++) { @@ -185,15 +189,16 @@ const char* get_absolute_import_path(const TargetConfig* config, const char* imp const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS); const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR); + char* cached_canonical = mem_strdup(MemoryNamespaceLld, canonical); + g_free(path); g_free(cwd); + g_free(canonical); if (exists && !is_dir) { - INFO("import target found at: %s", canonical); - return canonical; + INFO("import target found at: %s", cached_canonical); + return cached_canonical; } - - g_free(canonical); } // file not found @@ -233,7 +238,9 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f g_hash_table_insert(imports, (gpointer) path, NULL); gchar* directory = g_path_get_dirname(path); - g_array_append_val(target->import_paths, directory); + gchar* cached_directory = mem_strdup(MemoryNamespaceLld, directory); + g_free(directory); + g_array_append_val(target->import_paths, cached_directory); } } } else { @@ -323,7 +330,7 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co if (targets != NULL) { for (guint i = 0; i < targets->len; i++) { - const char *target_name = (((Option*) targets->data) + i)->string; + const char *target_name = g_array_index(targets, const char*, i); if (g_hash_table_contains(config->targets, target_name)) { build_target(unit, g_hash_table_lookup(config->targets, target_name)); @@ -332,7 +339,7 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co } } - g_array_free(targets, FALSE); + mem_free(targets); } else { print_message(Error, "No targets specified."); } diff --git a/src/io/files.c b/src/io/files.c index dc4d044..ddd018c 100644 --- a/src/io/files.c +++ b/src/io/files.c @@ -42,7 +42,7 @@ ModuleFile *push_file(ModuleFileStack *stack, const char *path) { // lazy init of heap stack if (stack->files == NULL) { - stack->files = g_array_new(FALSE, FALSE, sizeof(ModuleFile*)); + stack->files = mem_new_g_array(MemoryNamespaceStatic, sizeof(ModuleFile*)); } ModuleFile* new_file = mem_alloc(MemoryNamespaceStatic, sizeof(ModuleFile)); @@ -66,9 +66,10 @@ void delete_files(ModuleFileStack *stack) { fclose(file->handle); } + mem_free((void*) file); } - g_array_free(stack->files, TRUE); + mem_free(stack->files); DEBUG("deleted module file stack"); } @@ -330,8 +331,11 @@ const char *get_absolute_path(const char *path) { DEBUG("resolving absolute path of: %s", path); char* cwd = g_get_current_dir(); - char* canoical = g_canonicalize_filename(path, cwd); + char* canonical = g_canonicalize_filename(path, cwd); g_free(cwd); - return canoical; + char* cached_canonical = mem_strdup(MemoryNamespaceStatic, canonical); + g_free(canonical); + + return cached_canonical; } diff --git a/src/llvm/backend.c b/src/llvm/backend.c index 870987d..07f4954 100644 --- a/src/llvm/backend.c +++ b/src/llvm/backend.c @@ -7,6 +7,7 @@ #include #include #include +#include Target create_native_target() { DEBUG("creating native target..."); @@ -54,7 +55,11 @@ static char* create_target_output_name(const TargetConfig* config) { prefix = "lib"; } - return g_strjoin("", prefix, config->name, NULL); + char* name = g_strjoin("", prefix, config->name, NULL); + char* cached_name = mem_strdup(MemoryNamespaceLlvm, name); + g_free(name); + + return cached_name; } Target create_target_from_config(const TargetConfig* config) { diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c index cb0fb2b..79eec2a 100644 --- a/src/llvm/link/lld.c +++ b/src/llvm/link/lld.c @@ -19,19 +19,19 @@ const char* get_absolute_link_path(const TargetConfig* config, const char* link_ char* path = g_build_filename(link_directory_path, link_target_name, NULL); char* cwd = g_get_current_dir(); char* canonical = g_canonicalize_filename(path, cwd); + char* cached_canonical = mem_strdup(MemoryNamespaceLld, canonical); const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS); const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR); g_free(path); g_free(cwd); + g_free(canonical); if (exists && !is_dir) { - INFO("link target found at: %s", canonical); - return canonical; + INFO("link target found at: %s", cached_canonical); + return cached_canonical; } - - g_free(canonical); } // file not found @@ -44,26 +44,33 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t TargetLinkConfig* config = mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig)); config->fatal_warnings = target_config->lld_fatal_warnings; - config->object_file_names = g_array_new(FALSE, FALSE, sizeof(char*)); + config->object_file_names = mem_new_g_array(MemoryNamespaceLld, sizeof(char*)); config->colorize = stdout_supports_ansi_esc(); config->driver = target_config->driver; // append build object file char* basename = g_strjoin(".", target_config->name, "o", NULL); char* filename = g_build_filename(target_config->archive_directory, basename, NULL); + g_free(basename); const char* target_object = get_absolute_link_path(target_config, (const char*) filename); if (target_object == NULL) { ERROR("failed to resolve path to target object: %s", filename); + g_free(filename); lld_delete_link_config(config); + g_free(filename); return NULL; } + g_free(filename); { // output file after linking basename = g_strjoin(".", target_config->name, "out", NULL); filename = g_build_filename(target_config->output_directory, basename, NULL); - config->output_file = filename; + config->output_file = mem_strdup(MemoryNamespaceLld, filename); + + g_free(basename); + g_free(filename); } g_array_append_val(config->object_file_names, target_object); @@ -81,8 +88,10 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t ERROR("failed to resolve path to dependency object: %s", library); print_message(Warning, "failed to resolve path to dependency object: %s", dependency); lld_delete_link_config(config); lld_delete_link_config(config); + g_free((void*) library); return NULL; } + g_free((void*) library); g_array_append_val(config->object_file_names, dependency_object); INFO("resolved path of target object: %s", dependency_object); } @@ -102,9 +111,6 @@ BackendError lld_link_target(TargetLinkConfig* config) { } void lld_delete_link_config(TargetLinkConfig* config) { - for (guint i = 0; i < config->object_file_names->len; i++) { - free((void*) g_array_index(config->object_file_names, const char*, i)); - } - g_array_free(config->object_file_names, TRUE); + mem_free(config->object_file_names); mem_free(config); } diff --git a/src/llvm/llvm-ir/func.c b/src/llvm/llvm-ir/func.c index 63d9b39..032aa3b 100644 --- a/src/llvm/llvm-ir/func.c +++ b/src/llvm/llvm-ir/func.c @@ -103,7 +103,7 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit, DEBUG("implementing function declaration: %s()", func->name); BackendError err = SUCCESS; - GArray* llvm_params = g_array_new(FALSE, FALSE, sizeof(LLVMTypeRef)); + GArray* llvm_params = mem_new_g_array(MemoryNamespaceLlvm, sizeof(LLVMTypeRef)); GArray* func_params = NULL; if (func->kind == FunctionDeclarationKind) { @@ -135,8 +135,6 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit, g_hash_table_insert(scope->functions, (char*) func->name, llvm_fun_type); - g_array_free(llvm_params, FALSE); - return err; } diff --git a/src/llvm/parser.c b/src/llvm/parser.c index ac009f5..be7ae7c 100644 --- a/src/llvm/parser.c +++ b/src/llvm/parser.c @@ -90,10 +90,11 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit, ERROR("failed to emit code: %s", error); err = new_backend_impl_error(Implementation, NULL, "failed to emit code"); - LLVMDisposeMessage(error); + } else { print_message(Info, "Generated code was written to: %s", filename); } + LLVMDisposeMessage(error); g_free((void*) filename); g_free((void*) basename); @@ -124,9 +125,9 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target, ERROR("failed to create target machine: %s", error); err = new_backend_impl_error(Implementation, NULL, "unable to create target machine"); - LLVMDisposeMessage(error); return err; } + LLVMDisposeMessage(error); DEBUG("Creating target machine..."); LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine( @@ -147,6 +148,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target, err = emit_module_to_file(unit, target_machine, LLVMObjectFile, error, config); + LLVMDisposeTargetMachine(target_machine); + return err; } @@ -223,9 +226,9 @@ static BackendError build_module(LLVMBackendCompileUnit* unit, char* error = NULL; if (LLVMVerifyModule(unit->module, LLVMReturnStatusAction, &error)) { print_message(Error, "Unable to compile due to: %s", error); - LLVMDisposeMessage(error); err = new_backend_impl_error(Implementation, NULL, "LLVM backend verification error, see stdout"); } + LLVMDisposeMessage(error); return err; } diff --git a/src/main.c b/src/main.c index ea6aef9..0367f8b 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,8 @@ void setup(int argc, char *argv[]) { link_init(); + init_toml(); + DEBUG("finished starting up gemstone..."); } diff --git a/src/mem/cache.h b/src/mem/cache.h index 486e84c..cb47d06 100644 --- a/src/mem/cache.h +++ b/src/mem/cache.h @@ -15,6 +15,7 @@ typedef char* MemoryNamespaceName; #define MemoryNamespaceLex "Lexer" #define MemoryNamespaceLog "Logging" #define MemoryNamespaceOpt "Options" +#define MemoryNamespaceTOML "TOML" #define MemoryNamespaceSet "SET" #define MemoryNamespaceLlvm "LLVM" #define MemoryNamespaceLld "LLD" diff --git a/src/set/set.c b/src/set/set.c index 66f8f71..0d41b2e 100644 --- a/src/set/set.c +++ b/src/set/set.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -20,7 +19,7 @@ int createTypeCastFromExpression(Expression *expression, Type *resultType, Expre bool compareTypes(Type *leftType, Type *rightType); -char* type_to_string(Type* type); +char *type_to_string(Type *type); const Type ShortShortUnsingedIntType = { .kind = TypeKindComposite, @@ -335,8 +334,8 @@ int createRef(AST_NODE_PTR currentNode, Type **reftype) { assert(currentNode->children->len == 1); assert(AST_get_node(currentNode, 0)->kind == AST_Type); - Type *type = malloc(sizeof(Type)); - Type *referenceType = malloc(sizeof(Type)); + Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); + Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); referenceType->kind = TypeKindReference; referenceType->nodePtr = currentNode; @@ -459,8 +458,8 @@ int createDef(AST_NODE_PTR currentNode, GArray **variables) { } if (!compareTypes(def.declaration.type, name->result)) { - char* expected_type = type_to_string(def.declaration.type); - char* gotten_type = type_to_string(name->result); + char *expected_type = type_to_string(def.declaration.type); + char *gotten_type = type_to_string(name->result); print_diagnostic(&name->nodePtr->location, Warning, "expected `%s` got `%s`", expected_type, gotten_type); @@ -490,8 +489,8 @@ int createDef(AST_NODE_PTR currentNode, GArray **variables) { return status; } -char* type_to_string(Type* type) { - char* string = NULL; +char *type_to_string(Type *type) { + char *string = NULL; switch (type->kind) { case TypeKindPrimitive: @@ -510,27 +509,32 @@ char* type_to_string(Type* type) { if (type->impl.composite.scale < 1.0) { for (int i = 0; i < (int) (type->impl.composite.scale * 4); i++) { - char* concat = g_strconcat("half ", string, NULL); - string = concat; + char *concat = g_strconcat("half ", string, NULL); + string = mem_strdup(MemoryNamespaceSet, concat); + g_free(concat); } } else if (type->impl.composite.scale > 1.0) { for (int i = 0; i < (int) type->impl.composite.scale; i++) { - char* concat = g_strconcat("long ", string, NULL); - string = concat; + char *concat = g_strconcat("long ", string, NULL); + string = mem_strdup(MemoryNamespaceSet, concat); + g_free(concat); } } if (type->impl.composite.sign == Unsigned) { - char* concat = g_strconcat("unsigned ", string, NULL); - string = concat; + char *concat = g_strconcat("unsigned ", string, NULL); + string = mem_strdup(MemoryNamespaceSet, concat); + g_free(concat); } break; } case TypeKindReference: { - char* type_string = type_to_string(type->impl.reference); - char* concat = g_strconcat("ref ", type_string, NULL); - string = concat; + char *type_string = type_to_string(type->impl.reference); + char *concat = g_strconcat("ref ", type_string, NULL); + mem_free(type_string); + string = mem_strdup(MemoryNamespaceSet, concat); + g_free(concat); break; } case TypeKindBox: @@ -617,6 +621,7 @@ int fillTablesWithVars(GHashTable *variableTable, const GArray *variables) { } [[nodiscard("type must be freed")]] + TypeValue createTypeValue(AST_NODE_PTR currentNode) { DEBUG("create TypeValue"); TypeValue value; @@ -731,7 +736,7 @@ int createArithOperation(Expression *ParentExpression, AST_NODE_PTR currentNode, DEBUG("create arithmetic operation"); ParentExpression->impl.operation.kind = Arithmetic; ParentExpression->impl.operation.nodePtr = currentNode; - ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *)); + ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *)); assert(expectedChildCount == currentNode->children->len); @@ -809,7 +814,7 @@ int createRelationalOperation(Expression *ParentExpression, AST_NODE_PTR current // fill kind and Nodeptr ParentExpression->impl.operation.kind = Relational; ParentExpression->impl.operation.nodePtr = currentNode; - ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *)); + ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *)); // fill Operands for (size_t i = 0; i < currentNode->children->len; i++) { @@ -868,7 +873,7 @@ int createBoolOperation(Expression *ParentExpression, AST_NODE_PTR currentNode) // fill kind and Nodeptr ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.nodePtr = currentNode; - ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *)); + ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *)); // fill Operands for (size_t i = 0; i < currentNode->children->len; i++) { @@ -952,7 +957,7 @@ int createBoolNotOperation(Expression *ParentExpression, AST_NODE_PTR currentNod //fill kind and Nodeptr ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.nodePtr = currentNode; - ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *)); + ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *)); //fill Operand Expression *expression = createExpression(AST_get_node(currentNode, 0)); @@ -1020,7 +1025,7 @@ int createBitOperation(Expression *ParentExpression, AST_NODE_PTR currentNode) { // fill kind and Nodeptr ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.nodePtr = currentNode; - ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *)); + ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *)); // fill Operands for (size_t i = 0; i < currentNode->children->len; i++) { @@ -1157,7 +1162,7 @@ int createBitNotOperation(Expression *ParentExpression, AST_NODE_PTR currentNode //fill kind and Nodeptr ParentExpression->impl.operation.kind = Bitwise; ParentExpression->impl.operation.nodePtr = currentNode; - ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *)); + ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *)); //fill Operand Expression *expression = createExpression(AST_get_node(currentNode, 0)); @@ -1430,7 +1435,7 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) { return SEMANTIC_ERROR; } - Type *resultType = malloc(sizeof(Type)); + Type *resultType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); resultType->nodePtr = currentNode; resultType->kind = TypeKindReference; resultType->impl.reference = address_of.variable->result; @@ -1440,7 +1445,7 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) { return SEMANTIC_OK; } -IO_Qualifier getParameterQualifier(Parameter* parameter) { +IO_Qualifier getParameterQualifier(Parameter *parameter) { if (parameter->kind == ParameterDeclarationKind) { return parameter->impl.declaration.qualifier; } else { @@ -1479,7 +1484,8 @@ Expression *createExpression(AST_NODE_PTR currentNode) { } if (getParameterQualifier(expression->impl.parameter) == Out) { - print_diagnostic(¤tNode->location, Error, "Parameter is write-only: `%s`", currentNode->value); + print_diagnostic(¤tNode->location, Error, "Parameter is write-only: `%s`", + currentNode->value); return NULL; } @@ -1625,7 +1631,7 @@ bool compareTypes(Type *leftType, Type *rightType) { return FALSE; } -Type* getVariableType(Variable* variable) { +Type *getVariableType(Variable *variable) { if (variable->kind == VariableKindDeclaration) { return variable->impl.declaration.type; } else { @@ -1633,7 +1639,7 @@ Type* getVariableType(Variable* variable) { } } -Type* getParameterType(Parameter* parameter) { +Type *getParameterType(Parameter *parameter) { if (parameter->kind == ParameterDeclarationKind) { return parameter->impl.declaration.type; } else { @@ -1641,7 +1647,7 @@ Type* getParameterType(Parameter* parameter) { } } -int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) { +int createStorageExpr(StorageExpr *expr, AST_NODE_PTR node) { switch (node->kind) { case AST_Ident: expr->kind = StorageExprKindVariable; @@ -1669,7 +1675,7 @@ int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) { expr->impl.dereference.index = createExpression(index_node); expr->impl.dereference.array = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr)); - if (createStorageExpr(expr->impl.dereference.array, array_node) == SEMANTIC_ERROR){ + if (createStorageExpr(expr->impl.dereference.array, array_node) == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } @@ -1704,7 +1710,8 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) { if (strg_expr->kind == AST_Parameter) { if (getParameterQualifier(assign.destination->impl.parameter) == In) { - print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`", assign.destination->impl.parameter->name); + print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`", + assign.destination->impl.parameter->name); return SEMANTIC_ERROR; } } @@ -1730,8 +1737,8 @@ int createStatement(Block *block, AST_NODE_PTR currentNode); int fillBlock(Block *block, AST_NODE_PTR currentNode) { DEBUG("start filling Block"); block->nodePtr = currentNode; - block->statemnts = g_array_new(FALSE, FALSE, sizeof(Statement *)); - GHashTable *lowerScope = g_hash_table_new(g_str_hash, g_str_equal); + block->statemnts = mem_new_g_array(MemoryNamespaceSet, sizeof(Statement *)); + GHashTable *lowerScope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); g_array_append_val(Scope, lowerScope); for (size_t i = 0; i < currentNode->children->len; i++) { @@ -1742,7 +1749,7 @@ int fillBlock(Block *block, AST_NODE_PTR currentNode) { } } - g_hash_table_destroy(lowerScope); + mem_free(lowerScope); g_array_remove_index(Scope, Scope->len - 1); DEBUG("created Block successfully"); @@ -1921,7 +1928,7 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) { for (size_t i = 0; i < argsListNode->children->len; i++) { AST_NODE_PTR currentExprList = AST_get_node(argsListNode, i); - for (int j = ((int) currentExprList->children->len) -1; j >= 0; j--) { + for (int j = ((int) currentExprList->children->len) - 1; j >= 0; j--) { AST_NODE_PTR expr_node = AST_get_node(currentExprList, j); Expression *expr = createExpression(expr_node); if (expr == NULL) { @@ -1943,7 +1950,7 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) { switch (currentNode->kind) { case AST_Decl: { - GArray *variable = g_array_new(FALSE, FALSE, sizeof(Variable *)); + GArray *variable = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable *)); int status = createDecl(currentNode, &variable); if (status) { @@ -1962,7 +1969,7 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) { break; case AST_Def: { - GArray *variable = g_array_new(FALSE, FALSE, sizeof(Variable *)); + GArray *variable = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable *)); if (createDef(currentNode, &variable)) { return SEMANTIC_ERROR; @@ -2057,7 +2064,7 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) { if (set_get_type_impl(AST_get_node(paramdecl, 0), &(decl.type))) { return SEMANTIC_ERROR; } - Parameter* param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter)); + Parameter *param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter)); param->nodePtr = currentNode; param->kind = ParameterDeclarationKind; param->impl.declaration = decl; @@ -2067,7 +2074,8 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) { g_array_append_val(Paramlist, *param); if (g_hash_table_contains(functionParameter, param->name)) { - print_diagnostic(¶m->nodePtr->location, Error, "Names of function parameters must be unique: %s", param->name); + print_diagnostic(¶m->nodePtr->location, Error, "Names of function parameters must be unique: %s", + param->name); return SEMANTIC_ERROR; } g_hash_table_insert(functionParameter, (gpointer) param->name, param); @@ -2087,7 +2095,7 @@ int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) { fundef.nodePtr = currentNode; fundef.name = nameNode->value; fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); - fundef.parameter = g_array_new(FALSE, FALSE, sizeof(Parameter)); + fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); DEBUG("paramlistlist child count: %i", paramlistlist->children->len); for (size_t i = 0; i < paramlistlist->children->len; i++) { @@ -2150,7 +2158,8 @@ bool compareParameter(GArray *leftParameter, GArray *rightParameter) { int addFunction(const char *name, Function *function) { if (function->kind == FunctionDefinitionKind) { if (g_hash_table_contains(definedFunctions, name)) { - print_diagnostic(&function->nodePtr->location, Error, "Multiple definition of function: `%s`", function->name); + print_diagnostic(&function->nodePtr->location, Error, "Multiple definition of function: `%s`", + function->name); return SEMANTIC_ERROR; } g_hash_table_insert(declaredFunctions, (gpointer) name, function); @@ -2161,7 +2170,8 @@ int addFunction(const char *name, Function *function) { function->impl.declaration.parameter); // a function can have multiple declartations but all have to be identical if (result == FALSE) { - print_diagnostic(&function->nodePtr->location, Error, "Divergent declaration of function: `%s`", function->name); + print_diagnostic(&function->nodePtr->location, Error, "Divergent declaration of function: `%s`", + function->name); return SEMANTIC_ERROR; } } @@ -2219,7 +2229,7 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) { int createFunction(Function *function, AST_NODE_PTR currentNode) { assert(currentNode->kind == AST_Fun); - functionParameter = g_hash_table_new(g_str_hash, g_str_equal); + functionParameter = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); if (currentNode->children->len == 2) { int signal = createFunDecl(function, currentNode); @@ -2235,7 +2245,7 @@ int createFunction(Function *function, AST_NODE_PTR currentNode) { PANIC("function should have 2 or 3 children"); } - g_hash_table_destroy(functionParameter); + mem_free(functionParameter); functionParameter = NULL; int result = addFunction(function->name, function); @@ -2403,27 +2413,27 @@ int createTypeDef(GHashTable *types, AST_NODE_PTR currentNode) { Module *create_set(AST_NODE_PTR currentNode) { DEBUG("create root Module"); //create tables for types - declaredComposites = g_hash_table_new(g_str_hash, g_str_equal); - declaredBoxes = g_hash_table_new(g_str_hash, g_str_equal); - declaredFunctions = g_hash_table_new(g_str_hash, g_str_equal); - definedFunctions = g_hash_table_new(g_str_hash, g_str_equal); + declaredComposites = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + declaredBoxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + declaredFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + definedFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); //create scope - Scope = g_array_new(FALSE, FALSE, sizeof(GHashTable *)); + Scope = mem_new_g_array(MemoryNamespaceSet, sizeof(GHashTable *)); //building current scope for module - GHashTable *globalscope = g_hash_table_new(g_str_hash, g_str_equal); - globalscope = g_hash_table_new(g_str_hash, g_str_equal); + GHashTable *globalscope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + globalscope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); g_array_append_val(Scope, globalscope); Module *rootModule = mem_alloc(MemoryNamespaceSet, sizeof(Module)); - GHashTable *boxes = g_hash_table_new(g_str_hash, g_str_equal); - GHashTable *types = g_hash_table_new(g_str_hash, g_str_equal); - GHashTable *functions = g_hash_table_new(g_str_hash, g_str_equal); - GHashTable *variables = g_hash_table_new(g_str_hash, g_str_equal); - GArray *imports = g_array_new(FALSE, FALSE, sizeof(const char *)); - GArray *includes = g_array_new(FALSE, FALSE, sizeof(const char *)); + GHashTable *boxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + GHashTable *types = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + GHashTable *functions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + GHashTable *variables = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); + GArray *imports = mem_new_g_array(MemoryNamespaceSet, sizeof(const char *)); + GArray *includes = mem_new_g_array(MemoryNamespaceSet, sizeof(const char *)); rootModule->boxes = boxes; rootModule->types = types; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3ce0770..456af55 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,3 +13,5 @@ add_subdirectory(glib) add_subdirectory(llvm) add_subdirectory(project) add_subdirectory(cache) +add_subdirectory(hello_world) +add_subdirectory(driver) diff --git a/tests/driver/CMakeLists.txt b/tests/driver/CMakeLists.txt new file mode 100644 index 0000000..85fd68c --- /dev/null +++ b/tests/driver/CMakeLists.txt @@ -0,0 +1,13 @@ +include(CTest) + +# ------------------------------------------------------- # +# CTEST 1 +# test compilation and execution with GCC driver + +add_test(NAME driver_gcc + WORKING_DIRECTORY ${GEMSTONE_TEST_DIR}/driver/gcc + COMMAND python ${GEMSTONE_TEST_DIR}/driver/gcc/test_driver_gcc.py) + +add_test(NAME driver_clang + WORKING_DIRECTORY ${GEMSTONE_TEST_DIR}/driver/clang + COMMAND python ${GEMSTONE_TEST_DIR}/driver/clang/test_driver_clang.py) diff --git a/tests/driver/clang/build.toml b/tests/driver/clang/build.toml new file mode 100644 index 0000000..f200572 --- /dev/null +++ b/tests/driver/clang/build.toml @@ -0,0 +1,19 @@ +[project] +name = "driver compilation test" +version = "0.1.0" +description = "Print a string to stdout" +license = "GPL-2.0" +authors = [ "Sven Vogel " ] + +[target.release] +link-paths = [ "../../../bin/std" ] +import-paths = [ "../../../lib/src" ] +driver = "clang" +root = "main.gsc" +mode = "application" +output = "bin" +archive = "archive" +print_ast = false +print_asm = false +print_ir = false +opt = 3 diff --git a/tests/driver/clang/main.gsc b/tests/driver/clang/main.gsc new file mode 100644 index 0000000..70314a2 --- /dev/null +++ b/tests/driver/clang/main.gsc @@ -0,0 +1,28 @@ + +import "std" + +fun cstrlen(in cstr: str)(out u32: len) { + u32: idx = 0 as u32 + + while !(str[idx] == 0) { + idx = idx + 1 + } + + len = idx +} + +fun printcstr(in cstr: msg) { + u32: len = 0 + cstrlen(msg)(len) + + handle: stdout = 0 + getStdoutHandle()(stdout) + + u32: written = 0 + writeBytes(stdout, msg, len)(written) +} + +fun main() { + cstr: msg = "Hello, world!\n" + printcstr(msg) +} diff --git a/tests/driver/clang/test_driver_clang.py b/tests/driver/clang/test_driver_clang.py new file mode 100644 index 0000000..ae8f2b1 --- /dev/null +++ b/tests/driver/clang/test_driver_clang.py @@ -0,0 +1,29 @@ +import os.path +import subprocess +import logging +from logging import info + + +def check_clang(): + info("testing Clang driver...") + + logging.basicConfig(level=logging.INFO) + + p = subprocess.run(["../../../bin/check/gsc", "build", "release", "--verbose", "--driver=clang"], capture_output=True, text=True) + + print(p.stdout) + + assert p.returncode == 0 + + p = subprocess.run(["bin/release.out"], capture_output=True, text=True) + + print(p.stdout) + + assert "Hello, world!" in p.stdout + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + info("check if binary exists...") + assert os.path.exists("../../../bin/check/gsc") + + check_clang() diff --git a/tests/driver/gcc/build.toml b/tests/driver/gcc/build.toml new file mode 100644 index 0000000..85e76d9 --- /dev/null +++ b/tests/driver/gcc/build.toml @@ -0,0 +1,19 @@ +[project] +name = "driver compilation test" +version = "0.1.0" +description = "Print a string to stdout" +license = "GPL-2.0" +authors = [ "Sven Vogel " ] + +[target.release] +link-paths = [ "../../../bin/std" ] +import-paths = [ "../../../lib/src" ] +driver = "gcc" +root = "main.gsc" +mode = "application" +output = "bin" +archive = "archive" +print_ast = false +print_asm = false +print_ir = false +opt = 3 diff --git a/tests/driver/gcc/main.gsc b/tests/driver/gcc/main.gsc new file mode 100644 index 0000000..70314a2 --- /dev/null +++ b/tests/driver/gcc/main.gsc @@ -0,0 +1,28 @@ + +import "std" + +fun cstrlen(in cstr: str)(out u32: len) { + u32: idx = 0 as u32 + + while !(str[idx] == 0) { + idx = idx + 1 + } + + len = idx +} + +fun printcstr(in cstr: msg) { + u32: len = 0 + cstrlen(msg)(len) + + handle: stdout = 0 + getStdoutHandle()(stdout) + + u32: written = 0 + writeBytes(stdout, msg, len)(written) +} + +fun main() { + cstr: msg = "Hello, world!\n" + printcstr(msg) +} diff --git a/tests/driver/gcc/test_driver_gcc.py b/tests/driver/gcc/test_driver_gcc.py new file mode 100644 index 0000000..a081961 --- /dev/null +++ b/tests/driver/gcc/test_driver_gcc.py @@ -0,0 +1,29 @@ +import os.path +import subprocess +import logging +from logging import info + + +def check_gcc(): + info("testing GCC driver...") + + logging.basicConfig(level=logging.INFO) + + p = subprocess.run(["../../../bin/check/gsc", "build", "release", "--verbose", "--driver=gcc"], capture_output=True, text=True) + + print(p.stdout) + + assert p.returncode == 0 + + p = subprocess.run(["bin/release.out"], capture_output=True, text=True) + + print(p.stdout) + + assert "Hello, world!" in p.stdout + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + info("check if binary exists...") + assert os.path.exists("../../../bin/check/gsc") + + check_gcc() diff --git a/tests/hello_world/CMakeLists.txt b/tests/hello_world/CMakeLists.txt new file mode 100644 index 0000000..6ca46a7 --- /dev/null +++ b/tests/hello_world/CMakeLists.txt @@ -0,0 +1,9 @@ +include(CTest) + +# ------------------------------------------------------- # +# CTEST 1 +# test a simple project + +add_test(NAME hello_world + WORKING_DIRECTORY ${GEMSTONE_TEST_DIR}/hello_world + COMMAND python ${GEMSTONE_TEST_DIR}/hello_world/test_hello_world.py) diff --git a/tests/hello_world/build.toml b/tests/hello_world/build.toml new file mode 100644 index 0000000..71fbfd3 --- /dev/null +++ b/tests/hello_world/build.toml @@ -0,0 +1,19 @@ +[project] +name = "print C string test" +version = "0.1.0" +description = "Print a string to stdout" +license = "GPL-2.0" +authors = [ "Sven Vogel " ] + +[target.release] +link-paths = [ "../../bin/std" ] +import-paths = [ "../../lib/src" ] +driver = "gcc" +root = "main.gsc" +mode = "application" +output = "bin" +archive = "archive" +print_ast = false +print_asm = false +print_ir = false +opt = 3 diff --git a/tests/hello_world/main.gsc b/tests/hello_world/main.gsc new file mode 100644 index 0000000..70314a2 --- /dev/null +++ b/tests/hello_world/main.gsc @@ -0,0 +1,28 @@ + +import "std" + +fun cstrlen(in cstr: str)(out u32: len) { + u32: idx = 0 as u32 + + while !(str[idx] == 0) { + idx = idx + 1 + } + + len = idx +} + +fun printcstr(in cstr: msg) { + u32: len = 0 + cstrlen(msg)(len) + + handle: stdout = 0 + getStdoutHandle()(stdout) + + u32: written = 0 + writeBytes(stdout, msg, len)(written) +} + +fun main() { + cstr: msg = "Hello, world!\n" + printcstr(msg) +} diff --git a/tests/hello_world/test_hello_world.py b/tests/hello_world/test_hello_world.py new file mode 100644 index 0000000..a9f801d --- /dev/null +++ b/tests/hello_world/test_hello_world.py @@ -0,0 +1,29 @@ +import os.path +import subprocess +import logging +from logging import info + + +def check_build_and_run(): + info("testing compilation of hello world...") + + logging.basicConfig(level=logging.INFO) + + p = subprocess.run(["../../bin/check/gsc", "build", "release", "--verbose"], capture_output=True, text=True) + + print(p.stdout) + + assert p.returncode == 0 + + p = subprocess.run(["bin/release.out"], capture_output=True, text=True) + + print(p.stdout) + + assert "Hello, world!" in p.stdout + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + info("check if binary exists...") + assert os.path.exists("../../bin/check/gsc") + + check_build_and_run() diff --git a/tests/input_file/CMakeLists.txt b/tests/input_file/CMakeLists.txt index 263e769..23244fb 100644 --- a/tests/input_file/CMakeLists.txt +++ b/tests/input_file/CMakeLists.txt @@ -6,4 +6,4 @@ include(CTest) add_test(NAME input_file_check WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/check - COMMAND python ${GEMSTONE_TEST_DIR}/input_file/test_input_file.py ${GEMSTONE_TEST_DIR}/input_file/test.gem) + COMMAND python ${GEMSTONE_TEST_DIR}/input_file/test_input_file.py ${GEMSTONE_TEST_DIR}/input_file/test.gsc) diff --git a/tests/input_file/test.gem b/tests/input_file/test.gsc similarity index 100% rename from tests/input_file/test.gem rename to tests/input_file/test.gsc