diff options
author | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2025-05-23 23:58:30 +0330 |
---|---|---|
committer | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2025-05-23 23:58:30 +0330 |
commit | 3c9aea642e3b2f4083705f1cd42fa911d35ee696 (patch) | |
tree | d990b2ffdb63161a9aef7cce20e5714461f86085 | |
parent | 093c3bece426686b175db9ddaecd6abc8908fd87 (diff) |
add way to call C functions
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | code/main.felan | 74 | ||||
-rw-r--r-- | src/compiler/ast-tree.c | 605 | ||||
-rw-r--r-- | src/compiler/ast-tree.h | 23 | ||||
-rw-r--r-- | src/compiler/lexer.c | 20 | ||||
-rw-r--r-- | src/compiler/lexer.h | 2 | ||||
-rw-r--r-- | src/compiler/parser.c | 21 | ||||
-rw-r--r-- | src/compiler/parser.h | 2 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/runner/runner.c | 229 | ||||
-rw-r--r-- | src/runner/runner.h | 8 | ||||
-rw-r--r-- | src/utils/dl.c | 66 | ||||
-rw-r--r-- | src/utils/dl.h | 8 |
13 files changed, 937 insertions, 130 deletions
@@ -20,12 +20,12 @@ INC_DIRS := $(SRC_DIR) INC_FLAGS := $(addprefix -I,$(INC_DIRS)) # OP_FLAG := -Ofast -OP_FLAG := -O3 +# OP_FLAG := -O3 # OP_FLAG := -Oz -# OP_FLAG := -g +OP_FLAG := -g # CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 -DPRINT_STATISTICS -DPRINT_COMPILE_TREE $(OP_FLAG) -CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 -DPRINT_STATISTICS $(OP_FLAG) +CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 -lffi -DPRINT_STATISTICS $(OP_FLAG) # CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 $(OP_FLAG) EXEC_FILE := $(BUILD_DIR)/$(PROJECT_NAME) diff --git a/code/main.felan b/code/main.felan index c2e573c..dffcf15 100644 --- a/code/main.felan +++ b/code/main.felan @@ -1,69 +1,11 @@ -@import("basic.felan"); - -print :: (comptime t:type,v:t)->void{ - if @type_of(v) == u8 - @putc(v); - else - @putc('n'); -}; - -fun0 :: () -> void { - i := 0; - while true { - i += 1; - if i == 7 - return; - else if i % 2 == 0 - continue; - else if i == 8 - break; - print(u8,@cast(i,u8)+'0'); - print(u16,@cast(@cast(i,u8) + '0',u16)); - } -}; - -fun1 :: ()->void{ - a :[20]u8 = undefined; - a[0] = '2'; - b := a; - @putc(a[0]); - @putc(b[0]); -}; - -fun2 :: ()->void{ - b := '2'; - c := &b; - d := &c; - d.*.* = '6'; - @putc(b); - @putc(c.*); - @putc(d.*.*); -}; - -fun3 :: ()->void{ - st :: struct{ - a : i64; - }; - a : st = undefined; - a.a = 2; - @putc(@cast(a.a,u8)+'0'); -}; - -fun4 :: ()->void{ - p := @size_of(123); - @putc(@cast(p,u8)+'0'); -}; - -/* -libc :: @c_library("/lib/libc.so"); - -putchar : (i8)->void : @c_function(libc,"putchar"); -*/ +libc :: @c_library("/lib/libc.so.6"); +putchar :: @c_function(libc,"putchar",(i32)->i32); +puts :: @c_function(libc,"puts",(*u8)->i32); main :: ()->void{ - // fun0(); - // fun1(); - // fun2(); - // fun3(); - fun4(); + a :i32= 97; + a = putchar(a); + putchar(a); + b := "hello\0"; + puts(&(b[0])); }; diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c index 23d047f..628784a 100644 --- a/src/compiler/ast-tree.c +++ b/src/compiler/ast-tree.c @@ -157,6 +157,14 @@ AstTree AST_TREE_SHAPE_SHIFTER_TYPE = { .str_end = NULL, }; +AstTree AST_TREE_C_LIBRARY_TYPE = { + .token = AST_TREE_TOKEN_TYPE_C_LIBRARY, + .metadata = NULL, + .type = &AST_TREE_TYPE_TYPE, + .str_begin = NULL, + .str_end = NULL, +}; + AstTree AST_TREE_VOID_VALUE = { .token = AST_TREE_TOKEN_VALUE_VOID, .metadata = NULL, @@ -220,6 +228,8 @@ const char *AST_TREE_TOKEN_STRINGS[] = { "AST_TREE_TOKEN_TYPE_CODE", "AST_TREE_TOKEN_TYPE_NAMESPACE", "AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER", + "AST_TREE_TOKEN_TYPE_C_LIBRARY", + "AST_TREE_TOKEN_TYPE_C_FUNCTION", "AST_TREE_TOKEN_TYPE_BOOL", "AST_TREE_TOKEN_VALUE_VOID", @@ -230,6 +240,8 @@ const char *AST_TREE_TOKEN_STRINGS[] = { "AST_TREE_TOKEN_VALUE_UNDEFINED", "AST_TREE_TOKEN_VALUE_NAMESPACE", "AST_TREE_TOKEN_VALUE_SHAPE_SHIFTER", + "AST_TREE_TOKEN_VALUE_C_LIBRARY", + "AST_TREE_TOKEN_VALUE_C_FUNCTION", "AST_TREE_TOKEN_VALUE_INT", "AST_TREE_TOKEN_VALUE_FLOAT", "AST_TREE_TOKEN_VALUE_BOOL", @@ -356,6 +368,7 @@ void astTreePrint(const AstTree *tree, int indent) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_VOID: case AST_TREE_TOKEN_VALUE_NULL: @@ -363,6 +376,8 @@ void astTreePrint(const AstTree *tree, int indent) { case AST_TREE_TOKEN_VARIABLE_DEFINE: case AST_TREE_TOKEN_RAW_VALUE_NOT_OWNED: goto RETURN_SUCCESS; + case AST_TREE_TOKEN_TYPE_C_FUNCTION: + NOT_IMPLEMENTED; case AST_TREE_TOKEN_KEYWORD_BREAK: case AST_TREE_TOKEN_KEYWORD_CONTINUE: { AstTreeLoopControl *meatadata = tree->metadata; @@ -791,6 +806,7 @@ void astTreeDestroy(AstTree tree) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_NULL: case AST_TREE_TOKEN_VALUE_UNDEFINED: @@ -983,6 +999,25 @@ void astTreeDestroy(AstTree tree) { free(metadata); } return; + case AST_TREE_TOKEN_TYPE_C_FUNCTION: { + AstTreeCFunctionType *metadata = tree.metadata; + astTreeDelete(metadata->funcType); + free(metadata); + } + return; + case AST_TREE_TOKEN_VALUE_C_LIBRARY: { + AstTreeCLibrary *metadata = tree.metadata; + free(metadata); + } + return; + case AST_TREE_TOKEN_VALUE_C_FUNCTION: { + AstTreeCFunction *metadata = tree.metadata; + astTreeDelete(metadata->library); + astTreeDelete(metadata->name); + astTreeDelete(metadata->funcType); + free(metadata); + } + return; case AST_TREE_TOKEN_NONE: } printLog("token = %d", tree.token); @@ -1026,7 +1061,8 @@ bool astTreeShouldDelete(AstTree *tree) { tree != &AST_TREE_F32_TYPE && tree != &AST_TREE_F64_TYPE && tree != &AST_TREE_F128_TYPE && tree != &AST_TREE_CODE_TYPE && tree != &AST_TREE_NAMESPACE_TYPE && - tree != &AST_TREE_SHAPE_SHIFTER_TYPE && tree != &AST_TREE_VOID_VALUE; + tree != &AST_TREE_SHAPE_SHIFTER_TYPE && + tree != &AST_TREE_C_LIBRARY_TYPE && tree != &AST_TREE_VOID_VALUE; } void astTreeRootDelete(AstTreeRoot *root) { @@ -1098,6 +1134,7 @@ AstTree *copyAstTreeBack(AstTree *tree, AstTreeVariables oldVariables[], case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: return tree; case AST_TREE_TOKEN_VALUE_VOID: if (tree == &AST_TREE_VOID_VALUE) { @@ -1554,6 +1591,49 @@ AstTree *copyAstTreeBack(AstTree *tree, AstTreeVariables oldVariables[], variables_size, safetyCheck), tree->str_begin, tree->str_end); } + case AST_TREE_TOKEN_TYPE_C_FUNCTION: { + AstTreeCFunctionType *metadata = tree->metadata; + AstTreeCFunctionType *new_metadata = a404m_malloc(sizeof(*new_metadata)); + + new_metadata->funcType = + copyAstTreeBack(metadata->funcType, oldVariables, newVariables, + variables_size, safetyCheck); + + return newAstTree(tree->token, new_metadata, + copyAstTreeBack(tree->type, oldVariables, newVariables, + variables_size, safetyCheck), + tree->str_begin, tree->str_end); + } + case AST_TREE_TOKEN_VALUE_C_LIBRARY: { + AstTreeCLibrary *metadata = tree->metadata; + AstTreeCLibrary *new_metadata = a404m_malloc(sizeof(*new_metadata)); + + new_metadata->dl = metadata->dl; + + return newAstTree(tree->token, new_metadata, + copyAstTreeBack(tree->type, oldVariables, newVariables, + variables_size, safetyCheck), + tree->str_begin, tree->str_end); + } + case AST_TREE_TOKEN_VALUE_C_FUNCTION: { + AstTreeCFunction *metadata = tree->metadata; + AstTreeCFunction *new_metadata = a404m_malloc(sizeof(*new_metadata)); + + new_metadata->library = + copyAstTreeBack(metadata->library, oldVariables, newVariables, + variables_size, safetyCheck); + new_metadata->name = + copyAstTreeBack(metadata->name, oldVariables, newVariables, + variables_size, safetyCheck); + new_metadata->funcType = + copyAstTreeBack(metadata->funcType, oldVariables, newVariables, + variables_size, safetyCheck); + + return newAstTree(tree->token, new_metadata, + copyAstTreeBack(tree->type, oldVariables, newVariables, + variables_size, safetyCheck), + tree->str_begin, tree->str_end); + } case AST_TREE_TOKEN_NONE: } printLog("Bad token %d", tree->token); @@ -2074,6 +2154,8 @@ AstTreeRoot *makeAstRoot(const ParserNode *parsedRoot, char *filePath) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_TYPE_BOOL: case PARSER_TOKEN_OPERATOR_POINTER: case PARSER_TOKEN_OPERATOR_ADDRESS: @@ -2268,6 +2350,10 @@ AstTree *astTreeParse(const ParserNode *parserNode) { return &AST_TREE_NAMESPACE_TYPE; case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: return &AST_TREE_SHAPE_SHIFTER_TYPE; + case PARSER_TOKEN_TYPE_C_LIBRARY: + return &AST_TREE_C_LIBRARY_TYPE; + case PARSER_TOKEN_TYPE_C_FUNCTION: + NOT_IMPLEMENTED; case PARSER_TOKEN_TYPE_BOOL: return &AST_TREE_BOOL_TYPE; case PARSER_TOKEN_FUNCTION_CALL: @@ -2364,8 +2450,8 @@ AstTree *astTreeParse(const ParserNode *parserNode) { case PARSER_TOKEN_OPERATOR_MINUS: return astTreeParseUnaryOperator(parserNode, AST_TREE_TOKEN_OPERATOR_MINUS); case PARSER_TOKEN_OPERATOR_POINTER: - return astTreeParseUnaryOperator(parserNode, - AST_TREE_TOKEN_OPERATOR_POINTER); + return astTreeParseUnaryOperatorSingleChild( + parserNode, AST_TREE_TOKEN_OPERATOR_POINTER); case PARSER_TOKEN_OPERATOR_ADDRESS: return astTreeParseUnaryOperatorSingleChild( parserNode, AST_TREE_TOKEN_OPERATOR_ADDRESS); @@ -2495,6 +2581,8 @@ AstTree *astTreeParseFunction(const ParserNode *parserNode) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_TYPE_BOOL: case PARSER_TOKEN_KEYWORD_RETURN: case PARSER_TOKEN_KEYWORD_BREAK: @@ -2662,10 +2750,12 @@ AstTree *astTreeParseTypeFunction(const ParserNode *parserNode) { argument.isComptime = false; } - if (!typeIsEqual(argument.type->type, &AST_TREE_TYPE_TYPE)) { - printError(argument.str_begin, argument.str_end, "Type is incorrenct"); - return NULL; - } + /* +if (!typeIsEqual(argument.type->type, &AST_TREE_TYPE_TYPE)) { + printError(argument.str_begin, argument.str_end, "Type is incorrenct"); + return NULL; +} + */ if (typeFunction->arguments_size == arguments_size) { arguments_size += arguments_size / 2 + 1; @@ -2745,43 +2835,25 @@ AstTree *astTreeParseValue(const ParserNode *parserNode, AstTreeToken token, AstTree *astTreeParseString(const ParserNode *parserNode) { ParserNodeStringMetadata *node_metadata = parserNode->metadata; - AstTreeObject *metadata = a404m_malloc(sizeof(*metadata)); - - metadata->variables.size = node_metadata->end - node_metadata->begin; - metadata->variables.data = a404m_malloc(metadata->variables.size * - sizeof(*metadata->variables.data)); - - for (size_t i = 0; i < metadata->variables.size; ++i) { - AstTreeInt *cellMetadata = a404m_malloc(sizeof(*cellMetadata)); - *cellMetadata = node_metadata->begin[i]; - - metadata->variables.data[i] = - a404m_malloc(sizeof(*metadata->variables.data[i])); - metadata->variables.data[i]->isConst = true; - metadata->variables.data[i]->isLazy = false; - metadata->variables.data[i]->name_begin = NULL; - metadata->variables.data[i]->name_end = NULL; - metadata->variables.data[i]->type = copyAstTree(&AST_TREE_U8_TYPE); - metadata->variables.data[i]->value = - newAstTree(AST_TREE_TOKEN_VALUE_INT, cellMetadata, - copyAstTree(&AST_TREE_U8_TYPE), NULL, NULL); - metadata->variables.data[i]->initValue = NULL; - } + const size_t size = node_metadata->end - node_metadata->begin; + AstTreeRawValue *metadata = a404m_malloc(size * sizeof(u8)); + memcpy(metadata, node_metadata->begin, size); AstTreeBracket *type_metadata = a404m_malloc(sizeof(*type_metadata)); type_metadata->operand = &AST_TREE_U8_TYPE; - AstTreeInt *parameter_metadata = a404m_malloc(sizeof(*parameter_metadata)); - *parameter_metadata = metadata->variables.size; - AstTree *parameter = newAstTree(AST_TREE_TOKEN_VALUE_INT, parameter_metadata, - &AST_TREE_I64_TYPE, NULL, NULL); + AstTreeRawValue *parameter_metadata = + a404m_malloc(getSizeOfType(&AST_TREE_U64_TYPE)); + *(u64 *)parameter_metadata = size; + AstTree *parameter = newAstTree(AST_TREE_TOKEN_RAW_VALUE, parameter_metadata, + &AST_TREE_U64_TYPE, NULL, NULL); type_metadata->parameters.size = 1; type_metadata->parameters.data = a404m_malloc( type_metadata->parameters.size * sizeof(*type_metadata->parameters.data)); type_metadata->parameters.data[0] = parameter; - return newAstTree(AST_TREE_TOKEN_VALUE_OBJECT, metadata, + return newAstTree(AST_TREE_TOKEN_RAW_VALUE, metadata, newAstTree(AST_TREE_TOKEN_TYPE_ARRAY, type_metadata, &AST_TREE_TYPE_TYPE, NULL, NULL), parserNode->str_begin, parserNode->str_end); @@ -3111,6 +3183,8 @@ AstTree *astTreeParseCurlyBracket(const ParserNode *parserNode) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_TYPE_BOOL: case PARSER_TOKEN_KEYWORD_RETURN: case PARSER_TOKEN_KEYWORD_BREAK: @@ -3359,7 +3433,8 @@ AstTree *astTreeParseBracket(const ParserNode *parserNode, AstTreeToken token) { bool isFunction(AstTree *value) { return value->type->token == AST_TREE_TOKEN_TYPE_FUNCTION || - value->type->token == AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER; + value->type->token == AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER || + value->type->token == AST_TREE_TOKEN_TYPE_C_FUNCTION; } bool isShapeShifter(AstTreeFunction *function) { @@ -3418,6 +3493,8 @@ bool isConst(AstTree *tree) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_NULL: case AST_TREE_TOKEN_VALUE_UNDEFINED: @@ -3550,6 +3627,8 @@ AstTree *makeTypeOf(AstTree *value) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_OPERATOR_POINTER: case AST_TREE_TOKEN_KEYWORD_STRUCT: @@ -3852,7 +3931,17 @@ bool typeIsEqualBack(const AstTree *type0, const AstTree *type1) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: return type1->token == type0->token; + case AST_TREE_TOKEN_TYPE_C_FUNCTION: { + if (type1->token != type0->token) { + return false; + } + AstTreeCFunctionType *type0_metadata = type0->metadata; + AstTreeCFunctionType *type1_metadata = type1->metadata; + + return typeIsEqualBack(type0_metadata->funcType, type1_metadata->funcType); + } case AST_TREE_TOKEN_OPERATOR_POINTER: { if (type1->token != type0->token) { return false; @@ -3980,6 +4069,8 @@ AstTree *getValue(AstTree *tree, bool copy) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_NULL: case AST_TREE_TOKEN_VALUE_UNDEFINED: @@ -4124,6 +4215,8 @@ bool isIntType(AstTree *type) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_VOID: case AST_TREE_TOKEN_VALUE_NAMESPACE: @@ -4223,6 +4316,8 @@ bool isFloatType(AstTree *type) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_VOID: case AST_TREE_TOKEN_VALUE_NAMESPACE: @@ -4292,11 +4387,15 @@ bool isEqual(AstTree *left, AstTree *right) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_VOID: case AST_TREE_TOKEN_VALUE_NULL: case AST_TREE_TOKEN_VALUE_UNDEFINED: return true; + case AST_TREE_TOKEN_TYPE_C_FUNCTION: { + NOT_IMPLEMENTED; + } case AST_TREE_TOKEN_VALUE_NAMESPACE: { AstTreeNamespace *left_metadata = left->metadata; AstTreeNamespace *right_metadata = right->metadata; @@ -4568,8 +4667,11 @@ bool setAllTypes(AstTree *tree, AstTreeSetTypesHelper helper, case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: case AST_TREE_TOKEN_VALUE_VOID: return true; + case AST_TREE_TOKEN_TYPE_C_FUNCTION: + NOT_IMPLEMENTED; case AST_TREE_TOKEN_VALUE_NAMESPACE: NOT_IMPLEMENTED; case AST_TREE_TOKEN_VALUE_BOOL: @@ -4691,9 +4793,9 @@ bool setAllTypes(AstTree *tree, AstTreeSetTypesHelper helper, case AST_TREE_TOKEN_BUILTIN_PUTC: return setTypesBuiltinPutc(tree, helper, functionCall); case AST_TREE_TOKEN_BUILTIN_C_LIBRARY: - NOT_IMPLEMENTED; + return setTypesBuiltinCLibrary(tree, helper, functionCall); case AST_TREE_TOKEN_BUILTIN_C_FUNCTION: - NOT_IMPLEMENTED; + return setTypesBuiltinCFunction(tree, helper, functionCall); case AST_TREE_TOKEN_TYPE_ARRAY: return setTypesTypeArray(tree, helper); case AST_TREE_TOKEN_OPERATOR_ARRAY_ACCESS: @@ -5355,6 +5457,77 @@ bool setTypesFunctionCall(AstTree *tree, AstTreeSetTypesHelper _helper) { AstTreeTypeFunction *function = metadata->function->type->metadata; tree->type = copyAstTree(function->returnType); + } else if (metadata->function->type->token == + AST_TREE_TOKEN_TYPE_C_FUNCTION) { + AstTreeCFunctionType *cFunction = metadata->function->type->metadata; + AstTreeTypeFunction *function = cFunction->funcType->metadata; + if (function == NULL) { + printError(tree->str_begin, tree->str_end, "Bad function"); + return NULL; + } else if (function->arguments_size != metadata->parameters_size) { + printError(tree->str_begin, tree->str_end, + "Arguments doesn't match %ld != %ld", function->arguments_size, + metadata->parameters_size); + return NULL; + } + + AstTreeFunctionCallParam initedArguments[function->arguments_size]; + size_t initedArguments_size = function->arguments_size; + + for (size_t i = 0; i < initedArguments_size; ++i) { + initedArguments[i].value = NULL; + } + + for (size_t i = 0; i < metadata->parameters_size; ++i) { + AstTreeFunctionCallParam param = metadata->parameters[i]; + if (param.nameBegin != param.nameEnd) { + const size_t param_name_size = param.nameEnd - param.nameBegin; + for (size_t j = 0; j < function->arguments_size; ++j) { + AstTreeTypeFunctionArgument arg = function->arguments[j]; + if ((size_t)(arg.name_end - arg.name_begin) == param_name_size && + strnEquals(arg.name_begin, param.nameBegin, param_name_size)) { + initedArguments[j] = param; + goto END_OF_NAMED_FOR2; + } + } + printError(param.value->str_begin, param.value->str_end, + "Argument not found"); + return false; + } + END_OF_NAMED_FOR2: + } + + for (size_t i = 0; i < metadata->parameters_size; ++i) { + AstTreeFunctionCallParam param = metadata->parameters[i]; + if (param.nameBegin == param.nameEnd) { + for (size_t j = 0; j < function->arguments_size; ++j) { + // AstTreeTypeFunctionArgument arg = function->arguments[j]; + if (initedArguments[j].value == NULL) { + initedArguments[j] = param; + goto END_OF_UNNAMED_FOR2; + } + } + printError(param.value->str_begin, param.value->str_end, + "Too many arguments"); + return false; + } + END_OF_UNNAMED_FOR2: + } + + for (size_t i = 0; i < function->arguments_size; ++i) { + AstTreeTypeFunctionArgument arg = function->arguments[i]; + if (initedArguments[i].value == NULL) { + printError(arg.str_begin, arg.str_end, "Argument is not initialized"); + return false; + } + } + + for (size_t i = 0; i < initedArguments_size; ++i) { + metadata->parameters[i] = initedArguments[i]; + } + tree->type = copyAstTree(function->returnType); + } else { + UNREACHABLE; } return true; @@ -5530,12 +5703,6 @@ bool setTypesOperatorAddress(AstTree *tree, AstTreeSetTypesHelper helper) { return false; } - if (metadata->token != AST_TREE_TOKEN_VARIABLE) { - printError(tree->str_begin, tree->str_end, - "Can only get address of a variable (for now)"); - return false; - } - tree->type = newAstTree(AST_TREE_TOKEN_OPERATOR_POINTER, copyAstTree(metadata->type), &AST_TREE_TYPE_TYPE, tree->str_begin, tree->str_end); @@ -6102,7 +6269,7 @@ bool setTypesBuiltinSizeOf(AstTree *tree, AstTreeSetTypesHelper helper, if (type == NULL) { return false; - } else if (!typeIsEqual(type, &AST_TREE_TYPE_TYPE)) { + } else if (!typeIsEqual(type->type, &AST_TREE_TYPE_TYPE)) { printError(type->str_begin, type->str_end, "Type missmatch, the argument should be `type`"); return false; @@ -6204,10 +6371,70 @@ bool setTypesBuiltinIsComptime(AstTree *tree, AstTreeSetTypesHelper helper) { bool setTypesBuiltinStackAlloc(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunctionCall *functionCall) { - (void)tree; (void)helper; - (void)functionCall; - NOT_IMPLEMENTED; + if (functionCall->parameters_size == 1) { + AstTree *size = NULL; + + static const char SIZE_STR[] = "size"; + static const size_t SIZE_STR_SIZE = + sizeof(SIZE_STR) / sizeof(*SIZE_STR) - sizeof(*SIZE_STR); + + for (size_t i = 0; i < functionCall->parameters_size; ++i) { + AstTreeFunctionCallParam param = functionCall->parameters[i]; + const size_t param_name_size = param.nameEnd - param.nameBegin; + + if (param_name_size == 0) { + if (size == NULL) { + size = param.value; + } else { + printError(param.value->str_begin, param.value->str_end, + "Bad paramter"); + return false; + } + } else if (param_name_size == SIZE_STR_SIZE && + strnEquals(param.nameBegin, SIZE_STR, SIZE_STR_SIZE) && + size == NULL) { + size = param.value; + } else { + printError(param.value->str_begin, param.value->str_end, + "Bad paramter"); + return false; + } + } + + if (size == NULL) { + return false; + } else if (!typeIsEqual(size->type, &AST_TREE_U64_TYPE)) { + printError(size->str_begin, size->str_end, + "Type missmatch, the argument should be `u64`"); + return false; + } + + AstTreeTypeFunction *type_metadata = a404m_malloc(sizeof(*type_metadata)); + type_metadata->arguments_size = 1; + type_metadata->arguments = a404m_malloc(type_metadata->arguments_size * + sizeof(*type_metadata->arguments)); + + type_metadata->returnType = + newAstTree(AST_TREE_TOKEN_OPERATOR_POINTER, &AST_TREE_VOID_TYPE, + &AST_TREE_TYPE_TYPE, NULL, NULL); + + type_metadata->arguments[0] = (AstTreeTypeFunctionArgument){ + .type = copyAstTree(&AST_TREE_TYPE_TYPE), + .name_begin = SIZE_STR, + .name_end = SIZE_STR + SIZE_STR_SIZE, + .str_begin = NULL, + .str_end = NULL, + .isComptime = false, + }; + + tree->type = newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, type_metadata, + &AST_TREE_TYPE_TYPE, NULL, NULL); + return true; + } else { + printError(tree->str_begin, tree->str_end, "Too many or too few arguments"); + return false; + } } bool setTypesBuiltinHeapAlloc(AstTree *tree, AstTreeSetTypesHelper helper, @@ -6294,6 +6521,8 @@ bool setTypesBuiltinUnary(AstTree *tree, AstTreeSetTypesHelper helper, case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_VALUE_VOID: case AST_TREE_TOKEN_VALUE_NAMESPACE: @@ -6571,6 +6800,194 @@ bool setTypesBuiltinPutc(AstTree *tree, AstTreeSetTypesHelper helper, return true; } +bool setTypesBuiltinCLibrary(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunctionCall *functionCall) { + (void)helper; + if (functionCall->parameters_size == 1) { + AstTree *path = NULL; + + static const char PATH_STR[] = "path"; + static const size_t PATH_STR_SIZE = + sizeof(PATH_STR) / sizeof(*PATH_STR) - sizeof(*PATH_STR); + + for (size_t i = 0; i < functionCall->parameters_size; ++i) { + AstTreeFunctionCallParam param = functionCall->parameters[i]; + const size_t param_name_size = param.nameEnd - param.nameBegin; + + if (param_name_size == 0) { + if (path == NULL) { + path = param.value; + } else { + printError(param.value->str_begin, param.value->str_end, + "Bad paramter"); + return false; + } + } else if (param_name_size == PATH_STR_SIZE && + strnEquals(param.nameBegin, PATH_STR, PATH_STR_SIZE) && + path == NULL) { + path = param.value; + } else { + printError(param.value->str_begin, param.value->str_end, + "Bad paramter"); + return false; + } + } + + AstTree *path_type = makeStringType(); + + if (path == NULL) { + return false; + } else if (!typeIsEqual(path->type, path_type)) { + astTreeDelete(path_type); + printError(path->str_begin, path->str_end, + "Type missmatch, the argument should be `type`"); + return false; + } + + AstTreeTypeFunction *type_metadata = a404m_malloc(sizeof(*type_metadata)); + type_metadata->arguments_size = 1; + type_metadata->arguments = a404m_malloc(type_metadata->arguments_size * + sizeof(*type_metadata->arguments)); + + type_metadata->returnType = copyAstTree(&AST_TREE_C_LIBRARY_TYPE); + + type_metadata->arguments[0] = (AstTreeTypeFunctionArgument){ + .type = path_type, + .name_begin = PATH_STR, + .name_end = PATH_STR + PATH_STR_SIZE, + .str_begin = NULL, + .str_end = NULL, + .isComptime = false, + }; + + tree->type = newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, type_metadata, + &AST_TREE_TYPE_TYPE, NULL, NULL); + return true; + } else { + printError(tree->str_begin, tree->str_end, "Too many or too few arguments"); + return false; + } +} + +bool setTypesBuiltinCFunction(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunctionCall *functionCall) { + (void)helper; + if (functionCall->parameters_size != 3) { + printError(tree->str_begin, tree->str_end, "Too many or too few arguments"); + return false; + } + AstTree *library = NULL; + AstTree *name = NULL; + AstTree *funcType = NULL; + + static char LIBRARY_STR[] = "library"; + static const size_t LIBRARY_STR_SIZE = + sizeof(LIBRARY_STR) / sizeof(*LIBRARY_STR) - sizeof(*LIBRARY_STR); + static char NAME_STR[] = "name"; + static const size_t NAME_STR_SIZE = + sizeof(NAME_STR) / sizeof(*NAME_STR) - sizeof(*NAME_STR); + static char FUNC_TYPE_STR[] = "func_type"; + static const size_t FUNC_TYPE_STR_SIZE = + sizeof(FUNC_TYPE_STR) / sizeof(*FUNC_TYPE_STR) - sizeof(*FUNC_TYPE_STR); + + for (size_t i = 0; i < functionCall->parameters_size; ++i) { + AstTreeFunctionCallParam param = functionCall->parameters[i]; + const size_t param_name_size = param.nameEnd - param.nameBegin; + + if (param_name_size == 0) { + if (library == NULL) { + library = param.value; + } else if (name == NULL) { + name = param.value; + } else if (funcType == NULL) { + funcType = param.value; + } else { + printError(param.value->str_begin, param.value->str_end, + "Bad paramter"); + return false; + } + } else if (param_name_size == LIBRARY_STR_SIZE && + strnEquals(param.nameBegin, LIBRARY_STR, LIBRARY_STR_SIZE) && + library == NULL) { + library = param.value; + } else if (param_name_size == NAME_STR_SIZE && + strnEquals(param.nameBegin, NAME_STR, NAME_STR_SIZE) && + name == NULL) { + name = param.value; + } else if (param_name_size == FUNC_TYPE_STR_SIZE && + strnEquals(param.nameBegin, FUNC_TYPE_STR, FUNC_TYPE_STR_SIZE) && + library == NULL) { + funcType = param.value; + } else { + printError(param.value->str_begin, param.value->str_end, "Bad paramter"); + return false; + } + } + + AstTree *str_type = makeStringType(); + + if (library == NULL || name == NULL || funcType == NULL) { + return false; + } else if (!typeIsEqual(library->type, &AST_TREE_C_LIBRARY_TYPE)) { + printError(library->str_begin, library->str_end, + "library must have a type of `c_library`"); + return false; + } else if (!typeIsEqual(name->type, str_type)) { + astTreeDelete(str_type); + printError(name->str_begin, name->str_end, + "name must have a type of `[]u8`"); + return false; + } else if (funcType->token != AST_TREE_TOKEN_TYPE_FUNCTION) { + astTreeDelete(str_type); + printError(funcType->str_begin, funcType->str_end, + "func_type must have a type of `function type`"); + return false; + } + astTreeDelete(str_type); + + AstTreeTypeFunction *type_metadata = a404m_malloc(sizeof(*type_metadata)); + type_metadata->arguments_size = 3; + type_metadata->arguments = a404m_malloc(type_metadata->arguments_size * + sizeof(*type_metadata->arguments)); + + AstTreeCFunctionType *retType = a404m_malloc(sizeof(*retType)); + retType->funcType = copyAstTree(funcType); + + type_metadata->returnType = newAstTree( + AST_TREE_TOKEN_TYPE_C_FUNCTION, retType, &AST_TREE_TYPE_TYPE, NULL, NULL); + + type_metadata->arguments[0] = (AstTreeTypeFunctionArgument){ + .type = copyAstTree(library->type), + .name_begin = LIBRARY_STR, + .name_end = LIBRARY_STR + LIBRARY_STR_SIZE, + .str_begin = NULL, + .str_end = NULL, + .isComptime = false, + }; + + type_metadata->arguments[1] = (AstTreeTypeFunctionArgument){ + .type = copyAstTree(name->type), + .name_begin = NAME_STR, + .name_end = NAME_STR + NAME_STR_SIZE, + .str_begin = NULL, + .str_end = NULL, + .isComptime = false, + }; + + type_metadata->arguments[2] = (AstTreeTypeFunctionArgument){ + .type = copyAstTree(funcType->type), + .name_begin = FUNC_TYPE_STR, + .name_end = FUNC_TYPE_STR + FUNC_TYPE_STR_SIZE, + .str_begin = NULL, + .str_end = NULL, + .isComptime = false, + }; + + tree->type = newAstTree(AST_TREE_TOKEN_TYPE_FUNCTION, type_metadata, + &AST_TREE_TYPE_TYPE, NULL, NULL); + return true; +} + bool setTypesTypeArray(AstTree *tree, AstTreeSetTypesHelper helper) { AstTreeBracket *metadata = tree->metadata; @@ -6972,6 +7389,73 @@ AstTreeVariable *setTypesFindVariable(const char *name_begin, astTreeVariableDelete(arguments.data[i]); } free(arguments.data); + } else if (var->type->token == AST_TREE_TOKEN_TYPE_C_FUNCTION) { + AstTreeCFunctionType *cFunction = var->type->metadata; + AstTreeTypeFunction *function = cFunction->funcType->metadata; + + if (function->arguments_size != functionCall->parameters_size) { + continue; + } + + AstTreeFunctionCallParam initedArguments[function->arguments_size]; + size_t initedArguments_size = function->arguments_size; + + for (size_t i = 0; i < initedArguments_size; ++i) { + initedArguments[i].value = NULL; + } + + for (size_t i = 0; i < functionCall->parameters_size; ++i) { + AstTreeFunctionCallParam param = functionCall->parameters[i]; + if (param.nameBegin != param.nameEnd) { + const size_t param_name_size = param.nameEnd - param.nameBegin; + for (size_t j = 0; j < function->arguments_size; ++j) { + AstTreeTypeFunctionArgument arg = function->arguments[j]; + if ((size_t)(arg.name_end - arg.name_begin) == param_name_size && + strnEquals(arg.name_begin, param.nameBegin, + param_name_size)) { + if (!typeIsEqual(arg.type, param.value->type) || + (arg.isComptime && !isConst(param.value))) { + goto CONTINUE_OUTER; + } + initedArguments[j] = param; + goto END_OF_NAMED_FOR2; + } + } + goto CONTINUE_OUTER; + } + END_OF_NAMED_FOR2: + } + + for (size_t i = 0; i < functionCall->parameters_size; ++i) { + AstTreeFunctionCallParam param = functionCall->parameters[i]; + if (param.nameBegin == param.nameEnd) { + for (size_t j = 0; j < function->arguments_size; ++j) { + AstTreeTypeFunctionArgument arg = function->arguments[j]; + if (initedArguments[j].value == NULL) { + if (!typeIsEqual(arg.type, param.value->type) || + (arg.isComptime && !isConst(param.value))) { + goto CONTINUE_OUTER; + } + initedArguments[j] = param; + goto END_OF_UNNAMED_FOR2; + } + } + goto CONTINUE_OUTER; + } + END_OF_UNNAMED_FOR2: + } + + for (size_t i = 0; i < function->arguments_size; ++i) { + if (initedArguments[i].value == NULL) { + goto CONTINUE_OUTER; + } + } + if (variable != NULL) { + printError(name_begin, name_end, "Multiple candidates found for %.*s", + (int)(name_end - name_begin), name_begin); + return NULL; + } + variable = var; } CONTINUE_OUTER: } @@ -6986,13 +7470,26 @@ AstTreeVariable *setTypesFindVariable(const char *name_begin, } char *u8ArrayToCString(AstTree *tree) { - AstTreeObject *object = tree->metadata; - char *str = a404m_malloc((object->variables.size + 1) * sizeof(*str)); - for (size_t i = 0; i < object->variables.size; ++i) { - str[i] = *(AstTreeInt *)object->variables.data[i]->value->metadata; + if (tree->token == AST_TREE_TOKEN_RAW_VALUE || + tree->token == AST_TREE_TOKEN_RAW_VALUE_NOT_OWNED) { + AstTreeRawValue *value = tree->metadata; + const size_t size = getSizeOfType(tree->type); + + char *newValue = a404m_malloc((size + 1) * sizeof(*newValue)); + memcpy(newValue, value, size); + newValue[size] = '\0'; + + return newValue; + } else if (tree->token == AST_TREE_TOKEN_VALUE_OBJECT) { + AstTreeObject *object = tree->metadata; + char *str = a404m_malloc((object->variables.size + 1) * sizeof(*str)); + for (size_t i = 0; i < object->variables.size; ++i) { + str[i] = *(AstTreeInt *)object->variables.data[i]->value->metadata; + } + str[object->variables.size] = '\0'; + return str; } - str[object->variables.size] = '\0'; - return str; + UNREACHABLE; } AstTree *makeStringType() { @@ -7055,6 +7552,8 @@ size_t getSizeOfType(AstTree *type) { case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_FUNCTION: case AST_TREE_TOKEN_BUILTIN_CAST: case AST_TREE_TOKEN_BUILTIN_TYPE_OF: diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h index d05db7b..ff8529e 100644 --- a/src/compiler/ast-tree.h +++ b/src/compiler/ast-tree.h @@ -61,6 +61,8 @@ typedef enum AstTreeToken { AST_TREE_TOKEN_TYPE_CODE, AST_TREE_TOKEN_TYPE_NAMESPACE, AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER, + AST_TREE_TOKEN_TYPE_C_LIBRARY, + AST_TREE_TOKEN_TYPE_C_FUNCTION, AST_TREE_TOKEN_TYPE_BOOL, AST_TREE_TOKEN_VALUE_VOID, AST_TREE_TOKEN_STATIC_VARS_END = AST_TREE_TOKEN_VALUE_VOID, @@ -72,6 +74,8 @@ typedef enum AstTreeToken { AST_TREE_TOKEN_VALUE_UNDEFINED, AST_TREE_TOKEN_VALUE_NAMESPACE, AST_TREE_TOKEN_VALUE_SHAPE_SHIFTER, + AST_TREE_TOKEN_VALUE_C_LIBRARY, + AST_TREE_TOKEN_VALUE_C_FUNCTION, AST_TREE_TOKEN_VALUE_INT, AST_TREE_TOKEN_VALUE_FLOAT, AST_TREE_TOKEN_VALUE_BOOL, @@ -139,6 +143,7 @@ extern AstTree AST_TREE_F128_TYPE; extern AstTree AST_TREE_CODE_TYPE; extern AstTree AST_TREE_NAMESPACE_TYPE; extern AstTree AST_TREE_SHAPE_SHIFTER_TYPE; +extern AstTree AST_TREE_C_LIBRARY_TYPE; extern AstTree AST_TREE_VOID_VALUE; typedef struct AstTreeVariable { @@ -313,6 +318,20 @@ typedef struct AstTreeLoopControl { typedef struct AstTreeRawValue { } AstTreeRawValue; +typedef struct AstTreeCFunctionType { + AstTree *funcType; +} AstTreeCFunctionType; + +typedef struct AstTreeCLibrary { + void *dl; +} AstTreeCLibrary; + +typedef struct AstTreeCFunction { + AstTree *library; + AstTree *name; + AstTree *funcType; +} AstTreeCFunction; + #ifdef PRINT_COMPILE_TREE void astTreePrint(const AstTree *tree, int indent); void astTreeVariablePrint(const AstTreeVariable *variable, int indent); @@ -477,6 +496,10 @@ bool setTypesBuiltinBinaryWithRet(AstTree *tree, AstTreeSetTypesHelper helper, AstTree *retType); bool setTypesBuiltinPutc(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunctionCall *functionCall); +bool setTypesBuiltinCLibrary(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunctionCall *functionCall); +bool setTypesBuiltinCFunction(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunctionCall *functionCall); bool setTypesTypeArray(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesArrayAccess(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesAstFunction(AstTreeFunction *function, diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 577b009..1fbba2f 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -56,6 +56,8 @@ const char *LEXER_TOKEN_STRINGS[] = { "LEXER_TOKEN_KEYWORD_CODE", "LEXER_TOKEN_KEYWORD_NAMESPACE", "LEXER_TOKEN_KEYWORD_SHAPE_SHIFTER", + "LEXER_TOKEN_KEYWORD_C_LIBRARY", + "LEXER_TOKEN_KEYWORD_C_FUNCTION", "LEXER_TOKEN_NUMBER", "LEXER_TOKEN_CHAR", "LEXER_TOKEN_STRING", @@ -167,15 +169,18 @@ static const size_t LEXER_SYMBOL_SIZE = sizeof(LEXER_SYMBOL_TOKENS) / sizeof(*LEXER_SYMBOL_TOKENS); static const char *LEXER_KEYWORD_STRINGS[] = { - "type", "void", "i8", "u8", "i16", "u16", - "i32", "u32", "i64", "u64", + "type", "void", "i8", "u8", + "i16", "u16", "i32", "u32", + "i64", "u64", #ifdef FLOAT_16_SUPPORT "f16", #endif - "f32", "f64", "f128", "bool", "return", "true", - "false", "if", "else", "while", "comptime", "null", - "struct", "undefined", "code", "lazy", "namespace", "shape_shifter", - "break", "continue", + "f32", "f64", "f128", "bool", + "return", "true", "false", "if", + "else", "while", "comptime", "null", + "struct", "undefined", "code", "lazy", + "namespace", "shape_shifter", "break", "continue", + "c_library", "c_function", }; static const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_TYPE, LEXER_TOKEN_KEYWORD_VOID, @@ -196,6 +201,7 @@ static const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_CODE, LEXER_TOKEN_KEYWORD_LAZY, LEXER_TOKEN_KEYWORD_NAMESPACE, LEXER_TOKEN_KEYWORD_SHAPE_SHIFTER, LEXER_TOKEN_KEYWORD_BREAK, LEXER_TOKEN_KEYWORD_CONTINUE, + LEXER_TOKEN_KEYWORD_C_LIBRARY, LEXER_TOKEN_KEYWORD_C_FUNCTION, }; static const size_t LEXER_KEYWORD_SIZE = sizeof(LEXER_KEYWORD_TOKENS) / sizeof(*LEXER_KEYWORD_TOKENS); @@ -522,6 +528,8 @@ lexerPushClear(LexerNodeArray *array, size_t *array_size, char const *iter, case LEXER_TOKEN_KEYWORD_SHAPE_SHIFTER: case LEXER_TOKEN_KEYWORD_BREAK: case LEXER_TOKEN_KEYWORD_CONTINUE: + case LEXER_TOKEN_KEYWORD_C_LIBRARY: + case LEXER_TOKEN_KEYWORD_C_FUNCTION: if (*array_size == array->size) { *array_size += 1 + *array_size / 2; array->data = diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h index 3523a5f..e56617f 100644 --- a/src/compiler/lexer.h +++ b/src/compiler/lexer.h @@ -58,6 +58,8 @@ typedef enum LexerToken { LEXER_TOKEN_KEYWORD_CODE, LEXER_TOKEN_KEYWORD_NAMESPACE, LEXER_TOKEN_KEYWORD_SHAPE_SHIFTER, + LEXER_TOKEN_KEYWORD_C_LIBRARY, + LEXER_TOKEN_KEYWORD_C_FUNCTION, LEXER_TOKEN_NUMBER, LEXER_TOKEN_CHAR, LEXER_TOKEN_STRING, diff --git a/src/compiler/parser.c b/src/compiler/parser.c index ba7a4a0..f85c412 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -62,6 +62,8 @@ const char *PARSER_TOKEN_STRINGS[] = { "PARSER_TOKEN_TYPE_CODE", "PARSER_TOKEN_TYPE_NAMESPACE", "PARSER_TOKEN_TYPE_SHAPE_SHIFTER", + "PARSER_TOKEN_TYPE_C_LIBRARY", + "PARSER_TOKEN_TYPE_C_FUNCTION", "PARSER_TOKEN_KEYWORD_BREAK", "PARSER_TOKEN_KEYWORD_CONTINUE", @@ -287,6 +289,8 @@ void parserNodePrint(const ParserNode *node, int indent) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_KEYWORD_NULL: case PARSER_TOKEN_KEYWORD_UNDEFINED: case PARSER_TOKEN_KEYWORD_BREAK: @@ -595,6 +599,8 @@ void parserNodeDelete(ParserNode *node) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_KEYWORD_NULL: case PARSER_TOKEN_KEYWORD_UNDEFINED: case PARSER_TOKEN_KEYWORD_BREAK: @@ -943,6 +949,10 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end, return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_NAMESPACE); case LEXER_TOKEN_KEYWORD_SHAPE_SHIFTER: return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_SHAPE_SHIFTER); + case LEXER_TOKEN_KEYWORD_C_LIBRARY: + return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_C_LIBRARY); + case LEXER_TOKEN_KEYWORD_C_FUNCTION: + return parserNoMetadata(node, parent, PARSER_TOKEN_TYPE_C_FUNCTION); case LEXER_TOKEN_KEYWORD_NULL: return parserNoMetadata(node, parent, PARSER_TOKEN_KEYWORD_NULL); case LEXER_TOKEN_KEYWORD_UNDEFINED: @@ -1720,6 +1730,8 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end, case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_KEYWORD_NULL: case PARSER_TOKEN_KEYWORD_UNDEFINED: case PARSER_TOKEN_KEYWORD_BREAK: @@ -2261,6 +2273,8 @@ bool isExpression(ParserNode *node) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_KEYWORD_NULL: case PARSER_TOKEN_KEYWORD_UNDEFINED: case PARSER_TOKEN_KEYWORD_BREAK: @@ -2299,6 +2313,8 @@ bool isType(ParserNode *node) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_TYPE_BOOL: case PARSER_TOKEN_IDENTIFIER: case PARSER_TOKEN_SYMBOL_PARENTHESIS: @@ -2460,6 +2476,8 @@ bool isValue(ParserNode *node) { case PARSER_TOKEN_TYPE_CODE: case PARSER_TOKEN_TYPE_NAMESPACE: case PARSER_TOKEN_TYPE_SHAPE_SHIFTER: + case PARSER_TOKEN_TYPE_C_LIBRARY: + case PARSER_TOKEN_TYPE_C_FUNCTION: case PARSER_TOKEN_KEYWORD_NULL: case PARSER_TOKEN_KEYWORD_UNDEFINED: case PARSER_TOKEN_KEYWORD_IF: @@ -2521,6 +2539,9 @@ char escapeChar(char const *begin, char const *end, bool *success) { case '"': *success = true; return '\"'; + case '0': + *success = true; + return '\0'; default: *success = false; return 0; diff --git a/src/compiler/parser.h b/src/compiler/parser.h index 1967dd6..6ef1427 100644 --- a/src/compiler/parser.h +++ b/src/compiler/parser.h @@ -59,6 +59,8 @@ typedef enum ParserToken { PARSER_TOKEN_TYPE_CODE, PARSER_TOKEN_TYPE_NAMESPACE, PARSER_TOKEN_TYPE_SHAPE_SHIFTER, + PARSER_TOKEN_TYPE_C_LIBRARY, + PARSER_TOKEN_TYPE_C_FUNCTION, PARSER_TOKEN_KEYWORD_BREAK, PARSER_TOKEN_KEYWORD_CONTINUE, @@ -1,5 +1,6 @@ #include "compiler/ast-tree.h" #include "runner/runner.h" +#include "utils/dl.h" #include "utils/file.h" #include "utils/log.h" #include <stdio.h> @@ -70,6 +71,7 @@ static int run(const char *filePath) { int main(int argc, char *argv[]) { fileInit(); + dynamicLibraryInit(); if (argc < 2) { // compileRun("test/main.felan", "build/out", false); @@ -79,6 +81,7 @@ int main(int argc, char *argv[]) { } const int ret = run(argv[1]); + dynamicLibraryDestroy(); fileDelete(); return ret; } diff --git a/src/runner/runner.c b/src/runner/runner.c index faeb956..c5355cc 100644 --- a/src/runner/runner.c +++ b/src/runner/runner.c @@ -1,9 +1,13 @@ #include "runner.h" #include "compiler/ast-tree.h" +#include "utils/dl.h" #include "utils/log.h" #include "utils/memory.h" #include "utils/string.h" #include "utils/type.h" +#include <dlfcn.h> +#include <ffi.h> +#include <iso646.h> #include <stdatomic.h> #include <stdio.h> #include <stdlib.h> @@ -932,12 +936,103 @@ AstTree *runAstTreeBuiltin(AstTree *tree, AstTreeScope *scope, putchar(*(u8 *)arguments[0]->metadata); return copyAstTree(&AST_TREE_VOID_VALUE); } + case AST_TREE_TOKEN_BUILTIN_C_LIBRARY: { + AstTree *path = arguments[0]; + char *str = u8ArrayToCString(path); + void *dl = dynamicLibraryOpen(str); + + if (dl == NULL) { + printLog("Can't open dl %s", str); + UNREACHABLE; + } + free(str); + + AstTreeCLibrary *metadata = a404m_malloc(sizeof(*metadata)); + metadata->dl = dl; + + return newAstTree(AST_TREE_TOKEN_VALUE_C_LIBRARY, metadata, + &AST_TREE_C_LIBRARY_TYPE, NULL, NULL); + } + case AST_TREE_TOKEN_BUILTIN_C_FUNCTION: { + AstTree *library = arguments[0]; + AstTree *name = arguments[1]; + AstTree *funcType = arguments[2]; + + AstTreeCFunction *metadata = a404m_malloc(sizeof(*metadata)); + metadata->library = copyAstTree(library); + metadata->name = copyAstTree(name); + metadata->funcType = copyAstTree(funcType); + + if (tree->type->token != AST_TREE_TOKEN_TYPE_FUNCTION) { + UNREACHABLE; + } + + AstTreeTypeFunction *function = tree->type->metadata; + + return newAstTree(AST_TREE_TOKEN_VALUE_C_FUNCTION, metadata, + copyAstTree(function->returnType), NULL, NULL); + } case AST_TREE_TOKEN_BUILTIN_IMPORT: default: } UNREACHABLE; } +AstTree *runAstTreeCFunction(AstTree *tree, AstTree **arguments, + size_t arguments_size) { + AstTreeCFunction *metadata = tree->metadata; + AstTreeCLibrary *lib = metadata->library->metadata; + char *name = u8ArrayToCString(metadata->name); + AstTreeTypeFunction *funcType = metadata->funcType->metadata; + + void (*fun)() = dlsym(lib->dl, name); + free(name); + if (dlerror() != NULL) { + UNREACHABLE; + } + + ffi_cif cif; + ffi_type *args[arguments_size]; + void *values[arguments_size]; + ffi_arg rc; + + if (funcType->arguments_size != arguments_size) { + UNREACHABLE; + } + + for (size_t i = 0; i < arguments_size; ++i) { + AstTreeTypeFunctionArgument arg = funcType->arguments[i]; + args[i] = toFFIType(arg.type); + if (!typeIsEqual(arg.type, arguments[i]->type)) { + printLog("%s %s", AST_TREE_TOKEN_STRINGS[arg.type->token], + AST_TREE_TOKEN_STRINGS[arguments[i]->type->token]); + UNREACHABLE; + } else if (arguments[i]->token != AST_TREE_TOKEN_RAW_VALUE && + arguments[i]->token != AST_TREE_TOKEN_RAW_VALUE_NOT_OWNED) { + UNREACHABLE; + } + values[i] = arguments[i]->metadata; + } + + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, arguments_size, + toFFIType(funcType->returnType), args) == FFI_OK) { + ffi_call(&cif, fun, &rc, values); + if (typeIsEqual(funcType->returnType, &AST_TREE_VOID_TYPE)) { + return &AST_TREE_VOID_TYPE; + } else { + size_t size = getSizeOfType(funcType->returnType); + AstTreeRawValue *value = a404m_malloc(size); + memcpy(value, &rc, size); + return newAstTree(AST_TREE_TOKEN_RAW_VALUE, value, + copyAstTree(funcType->returnType), NULL, NULL); + } + } else { + UNREACHABLE; + } + + return &AST_TREE_VOID_VALUE; +} + AstTree *runExpression(AstTree *expr, AstTreeScope *scope, bool *shouldRet, bool isLeft, bool isComptime, u32 *breakCount, bool *shouldContinue) { @@ -998,6 +1093,23 @@ AstTree *runExpression(AstTree *expr, AstTreeScope *scope, bool *shouldRet, astTreeDelete(args[i]); } } + } else if (function->token == AST_TREE_TOKEN_VALUE_C_FUNCTION) { + for (size_t i = 0; i < args_size; ++i) { + AstTreeFunctionCallParam param = metadata->parameters[i]; + args[i] = getForVariable(param.value, scope, shouldRet, false, + isComptime, breakCount, shouldContinue, false); + if (discontinue(*shouldRet, *breakCount)) { + astTreeDelete(function); + for (size_t j = 0; j < i; ++j) { + astTreeDelete(args[i]); + } + return args[i]; + } + } + result = runAstTreeCFunction(function, args, args_size); + for (size_t i = 0; i < args_size; ++i) { + astTreeDelete(args[i]); + } } else { UNREACHABLE; } @@ -1243,6 +1355,8 @@ AstTree *runExpression(AstTree *expr, AstTreeScope *scope, bool *shouldRet, case AST_TREE_TOKEN_TYPE_CODE: case AST_TREE_TOKEN_TYPE_NAMESPACE: case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: case AST_TREE_TOKEN_VALUE_NULL: case AST_TREE_TOKEN_VALUE_UNDEFINED: case AST_TREE_TOKEN_VALUE_VOID: @@ -1298,7 +1412,7 @@ AstTree *runExpression(AstTree *expr, AstTreeScope *scope, bool *shouldRet, AstTreeRawValue *address = a404m_malloc(sizeof(void *)); *(void **)address = operand->metadata; - AstTree *type = copyAstTree(operand->type); + AstTree *type = copyAstTree(expr->type); astTreeDelete(operand); return newAstTree(AST_TREE_TOKEN_RAW_VALUE, address, type, NULL, NULL); @@ -1967,3 +2081,116 @@ AstTree *castTo(AstTree *tree, AstTree *to) { UNREACHABLE; } } + +ffi_type *toFFIType(AstTree *type) { + switch (type->token) { + case AST_TREE_TOKEN_TYPE_VOID: + return &ffi_type_void; + case AST_TREE_TOKEN_TYPE_BOOL: + case AST_TREE_TOKEN_TYPE_U8: + return &ffi_type_uint8; + case AST_TREE_TOKEN_TYPE_I8: + return &ffi_type_sint8; + case AST_TREE_TOKEN_TYPE_I16: + return &ffi_type_sint16; + case AST_TREE_TOKEN_TYPE_U16: + return &ffi_type_uint16; + case AST_TREE_TOKEN_TYPE_I32: + return &ffi_type_sint32; + case AST_TREE_TOKEN_TYPE_U32: + return &ffi_type_uint32; + case AST_TREE_TOKEN_TYPE_I64: + return &ffi_type_sint64; + case AST_TREE_TOKEN_TYPE_U64: + return &ffi_type_uint64; + case AST_TREE_TOKEN_TYPE_F16: + NOT_IMPLEMENTED; + case AST_TREE_TOKEN_TYPE_F32: + return &ffi_type_float; + case AST_TREE_TOKEN_TYPE_F64: + return &ffi_type_double; + case AST_TREE_TOKEN_TYPE_F128: + return &ffi_type_longdouble; + case AST_TREE_TOKEN_OPERATOR_POINTER: + return &ffi_type_pointer; + case AST_TREE_TOKEN_TYPE_ARRAY: + case AST_TREE_TOKEN_TYPE_CODE: + case AST_TREE_TOKEN_TYPE_TYPE: + case AST_TREE_TOKEN_TYPE_FUNCTION: + case AST_TREE_TOKEN_TYPE_NAMESPACE: + case AST_TREE_TOKEN_TYPE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_TYPE_C_LIBRARY: + case AST_TREE_TOKEN_TYPE_C_FUNCTION: + case AST_TREE_TOKEN_FUNCTION: + case AST_TREE_TOKEN_BUILTIN_CAST: + case AST_TREE_TOKEN_BUILTIN_TYPE_OF: + case AST_TREE_TOKEN_BUILTIN_SIZE_OF: + case AST_TREE_TOKEN_BUILTIN_IMPORT: + case AST_TREE_TOKEN_BUILTIN_IS_COMPTIME: + case AST_TREE_TOKEN_BUILTIN_STACK_ALLOC: + case AST_TREE_TOKEN_BUILTIN_HEAP_ALLOC: + case AST_TREE_TOKEN_BUILTIN_NEG: + case AST_TREE_TOKEN_BUILTIN_ADD: + case AST_TREE_TOKEN_BUILTIN_SUB: + case AST_TREE_TOKEN_BUILTIN_MUL: + case AST_TREE_TOKEN_BUILTIN_DIV: + case AST_TREE_TOKEN_BUILTIN_MOD: + case AST_TREE_TOKEN_BUILTIN_EQUAL: + case AST_TREE_TOKEN_BUILTIN_NOT_EQUAL: + case AST_TREE_TOKEN_BUILTIN_GREATER: + case AST_TREE_TOKEN_BUILTIN_SMALLER: + case AST_TREE_TOKEN_BUILTIN_GREATER_OR_EQUAL: + case AST_TREE_TOKEN_BUILTIN_SMALLER_OR_EQUAL: + case AST_TREE_TOKEN_BUILTIN_PUTC: + case AST_TREE_TOKEN_BUILTIN_C_LIBRARY: + case AST_TREE_TOKEN_BUILTIN_C_FUNCTION: + case AST_TREE_TOKEN_KEYWORD_RETURN: + case AST_TREE_TOKEN_KEYWORD_BREAK: + case AST_TREE_TOKEN_KEYWORD_CONTINUE: + case AST_TREE_TOKEN_KEYWORD_IF: + case AST_TREE_TOKEN_KEYWORD_WHILE: + case AST_TREE_TOKEN_KEYWORD_COMPTIME: + case AST_TREE_TOKEN_KEYWORD_STRUCT: + case AST_TREE_TOKEN_VALUE_VOID: + case AST_TREE_TOKEN_FUNCTION_CALL: + case AST_TREE_TOKEN_VARIABLE: + case AST_TREE_TOKEN_VARIABLE_DEFINE: + case AST_TREE_TOKEN_VALUE_NULL: + case AST_TREE_TOKEN_VALUE_UNDEFINED: + case AST_TREE_TOKEN_VALUE_NAMESPACE: + case AST_TREE_TOKEN_VALUE_SHAPE_SHIFTER: + case AST_TREE_TOKEN_VALUE_C_LIBRARY: + case AST_TREE_TOKEN_VALUE_C_FUNCTION: + case AST_TREE_TOKEN_VALUE_INT: + case AST_TREE_TOKEN_VALUE_FLOAT: + case AST_TREE_TOKEN_VALUE_BOOL: + case AST_TREE_TOKEN_VALUE_OBJECT: + case AST_TREE_TOKEN_RAW_VALUE: + case AST_TREE_TOKEN_RAW_VALUE_NOT_OWNED: + case AST_TREE_TOKEN_SHAPE_SHIFTER_ELEMENT: + case AST_TREE_TOKEN_OPERATOR_ASSIGN: + case AST_TREE_TOKEN_OPERATOR_PLUS: + case AST_TREE_TOKEN_OPERATOR_MINUS: + case AST_TREE_TOKEN_OPERATOR_SUM: + case AST_TREE_TOKEN_OPERATOR_SUB: + case AST_TREE_TOKEN_OPERATOR_MULTIPLY: + case AST_TREE_TOKEN_OPERATOR_DIVIDE: + case AST_TREE_TOKEN_OPERATOR_MODULO: + case AST_TREE_TOKEN_OPERATOR_EQUAL: + case AST_TREE_TOKEN_OPERATOR_NOT_EQUAL: + case AST_TREE_TOKEN_OPERATOR_GREATER: + case AST_TREE_TOKEN_OPERATOR_SMALLER: + case AST_TREE_TOKEN_OPERATOR_GREATER_OR_EQUAL: + case AST_TREE_TOKEN_OPERATOR_SMALLER_OR_EQUAL: + case AST_TREE_TOKEN_OPERATOR_ADDRESS: + case AST_TREE_TOKEN_OPERATOR_DEREFERENCE: + case AST_TREE_TOKEN_OPERATOR_ACCESS: + case AST_TREE_TOKEN_OPERATOR_LOGICAL_NOT: + case AST_TREE_TOKEN_OPERATOR_LOGICAL_AND: + case AST_TREE_TOKEN_OPERATOR_LOGICAL_OR: + case AST_TREE_TOKEN_OPERATOR_ARRAY_ACCESS: + case AST_TREE_TOKEN_SCOPE: + case AST_TREE_TOKEN_NONE: + } + UNREACHABLE; +} diff --git a/src/runner/runner.h b/src/runner/runner.h index 789f0a9..00322c6 100644 --- a/src/runner/runner.h +++ b/src/runner/runner.h @@ -1,6 +1,7 @@ #pragma once #include "compiler/ast-tree.h" +#include <ffi.h> void runnerVariableSetValue(AstTreeVariable *variable, AstTree *value); void runnerVariableSetValueWihtoutConstCheck(AstTreeVariable *variable, @@ -15,6 +16,9 @@ AstTree *runAstTreeFunction(AstTree *tree, AstTree **arguments, AstTree *runAstTreeBuiltin(AstTree *tree, AstTreeScope *scope, AstTree **arguments); +AstTree *runAstTreeCFunction(AstTree *tree, AstTree **arguments, + size_t arguments_size); + AstTree *runExpression(AstTree *expr, AstTreeScope *scope, bool *shouldRet, bool isLeft, bool isComptime, u32 *breakCount, bool *shouldContinue); @@ -27,4 +31,6 @@ bool discontinue(bool shouldRet, u32 breakCount); AstTree *toRawValue(AstTree *value); -AstTree *castTo(AstTree *value,AstTree *to); +AstTree *castTo(AstTree *value, AstTree *to); + +ffi_type *toFFIType(AstTree *type); diff --git a/src/utils/dl.c b/src/utils/dl.c new file mode 100644 index 0000000..1a1c430 --- /dev/null +++ b/src/utils/dl.c @@ -0,0 +1,66 @@ +#include "dl.h" +#include "utils/memory.h" +#include "utils/string.h" +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +void **dynamicLibraries; +char **dynamicLibraries_str; +size_t dynamicLibraries_length; +size_t dynamicLibraries_capacity; + +void dynamicLibraryInit() { + dynamicLibraries = a404m_malloc(0); + dynamicLibraries_str = a404m_malloc(0); + dynamicLibraries_length = 0; + dynamicLibraries_capacity = 0; +} + +void dynamicLibraryDestroy() { + for (size_t i = 0; i < dynamicLibraries_length; ++i) { + dlclose(dynamicLibraries[i]); + free(dynamicLibraries_str[i]); + } + free(dynamicLibraries); + free(dynamicLibraries_str); +} + +void *dynamicLibraryOpen(char *file) { + for (size_t i = 0; i < dynamicLibraries_length; ++i) { + if (strEquals(file, dynamicLibraries_str[i])) { + return dynamicLibraries[i]; + } + } + + void *dl = dlopen(file, RTLD_LAZY); + if (dl == NULL) { + fputs(dlerror(), stderr); + return NULL; + } + + if (dynamicLibraries_capacity == dynamicLibraries_length) { + dynamicLibraries_capacity += dynamicLibraries_capacity / 2 + 1; + dynamicLibraries_str = + a404m_realloc(dynamicLibraries_str, sizeof(*dynamicLibraries_str) * + dynamicLibraries_capacity); + dynamicLibraries = + a404m_realloc(dynamicLibraries, + sizeof(*dynamicLibraries) * dynamicLibraries_capacity); + } + dynamicLibraries[dynamicLibraries_length] = dl; + + const size_t file_length = strLength(file); + dynamicLibraries_str[dynamicLibraries_length] = + a404m_malloc(sizeof(**dynamicLibraries) * (file_length + 1)); + + for (size_t i = 0; i < file_length; ++i) { + dynamicLibraries_str[dynamicLibraries_length][i] = file[i]; + } + dynamicLibraries_str[dynamicLibraries_length][file_length] = '\0'; + + dynamicLibraries_length += 1; + + return dl; +} diff --git a/src/utils/dl.h b/src/utils/dl.h new file mode 100644 index 0000000..74cb865 --- /dev/null +++ b/src/utils/dl.h @@ -0,0 +1,8 @@ +#pragma once + +#include <stddef.h> + +void dynamicLibraryInit(); +void dynamicLibraryDestroy(); + +void* dynamicLibraryOpen(char *file); |