diff --git a/apps/script_console.cpp b/apps/script_console.cpp index 1f38c07..79e8699 100644 --- a/apps/script_console.cpp +++ b/apps/script_console.cpp @@ -476,6 +476,20 @@ EXTERNAL_STUB(ExternalSystemShellEnableLogging); EXTERNAL_STUB(ExternalSystemGetEnvironmentVariable); EXTERNAL_STUB(ExternalSystemSetEnvironmentVariable); +void *LibraryLoad(const char *cName) { + // TODO. + (void) cName; + AddLogOutput(scriptInstance, EsLiteral("(LibraryLoad has not been implemented yet)")); + return nullptr; +} + +void *LibraryGetAddress(void *library, const char *cName) { + // TODO. + (void) library; + (void) cName; + return nullptr; +} + // --------------------------------- User interface. #define COLOR_BACKGROUND (0xFFFDFDFD) diff --git a/util/script.c b/util/script.c index 1c48d77..25535eb 100644 --- a/util/script.c +++ b/util/script.c @@ -1,11 +1,10 @@ // TODO Basic missing features: // - Maps: T[int], T[str]. // - Control flow: break, continue. -// - Other operators: remainder, ternary. +// - Other operators: integer modulo. // - Named optional arguments with default values. -// - Accessing structs and functypes from imported modules. +// - Using declared types from imported modules. // - struct inheritance. -// - Allow implicit casts when passing functions parameters // TODO Larger missing features: // - Serialization. @@ -115,6 +114,7 @@ #define T_INTTYPE_CONSTANT (93) #define T_ANYTYPE_CAST (94) #define T_CAST_TYPE_WRAPPER (95) +#define T_ZERO (96) #define T_EXIT_SCOPE (100) #define T_END_FUNCTION (101) @@ -129,6 +129,7 @@ #define T_SWAP (110) #define T_INTERPOLATE_ILIST (111) #define T_ROT3 (112) +#define T_LIBCALL (113) #define T_FLOAT_ADD (120) #define T_FLOAT_MINUS (121) @@ -205,6 +206,7 @@ #define T_INTTYPE (198) #define T_HANDLETYPE (199) #define T_ANYTYPE (200) +#define T_LIBRARY (201) #define STACK_READ_STRING(textVariable, bytesVariable, stackIndex) \ if (context->c->stackPointer < stackIndex) return -1; \ @@ -271,7 +273,7 @@ typedef struct Node { struct Node *parent; // Set in ASTSetScopes. Scope *scope; // Set in ASTSetScopes. struct Node *expressionType; // Set in ASTSetTypes. - struct ImportData *importData; + struct ImportData *importData; // The module being imported by this node. } Node; typedef struct Value { @@ -385,6 +387,11 @@ typedef struct CoroutineState { uintptr_t variableBase; Value externalCoroutineData; void *externalCoroutineData2; + + // Data stored for library calls: + uintptr_t parameterCount; + Value returnValue; + int returnValueType; } CoroutineState; typedef struct ExecutionContext { @@ -422,6 +429,7 @@ typedef struct ImportData { struct ImportData *nextImport; struct ImportData *parentImport; Node *rootNode; + void *library; } ImportData; Node globalExpressionTypeVoid = { .type = T_VOID }; @@ -472,6 +480,8 @@ void PrintBackTrace(ExecutionContext *context, uint32_t instructionPointer, Coro void *FileLoad(const char *path, size_t *length); CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context); void ExternalPassREPLResult(ExecutionContext *context, Value value); +void *LibraryLoad(const char *name); +void *LibraryGetAddress(void *library, const char *name); // --------------------------------- Base module. @@ -977,6 +987,7 @@ Token TokenNext(Tokenizer *tokenizer) { else if KEYWORD("#extcall") token.type = T_EXTCALL; else if KEYWORD("#import") token.type = T_IMPORT; else if KEYWORD("#inline") token.type = T_INLINE; + else if KEYWORD("#library") token.type = T_LIBRARY; else if KEYWORD("#option") token.type = T_OPTION; else if KEYWORD("#persist") token.type = T_PERSIST; else if KEYWORD("#success") token.type = T_SUCCESS; @@ -1025,6 +1036,10 @@ Token TokenNext(Tokenizer *tokenizer) { if (tokenizer->position == tokenizer->inputBytes) break; c = tokenizer->input[tokenizer->position]; } + + if (token.textBytes == 1 && token.text[0] == '0') { + token.type = T_ZERO; + } } else if (c == '"') { // TODO Escape sequence to insert an arbitrary codepoint. @@ -1347,7 +1362,7 @@ Node *ParseExpression(Tokenizer *tokenizer, bool allowAssignment, uint8_t preced string->token.textBytes++; } } - } else if (node->token.type == T_NUMERIC_LITERAL || node->token.type == T_SUCCESS + } else if (node->token.type == T_NUMERIC_LITERAL || node->token.type == T_SUCCESS || node->token.type == T_ZERO || node->token.type == T_TRUE || node->token.type == T_FALSE || node->token.type == T_NULL) { node->type = node->token.type; } else if (node->token.type == T_LOGICAL_NOT || node->token.type == T_MINUS || node->token.type == T_BITWISE_NOT) { @@ -2306,7 +2321,40 @@ Node *ParseRoot(Tokenizer *tokenizer) { link = &node->sibling; if (TokenNext(tokenizer).type != T_SEMICOLON) { - PrintError2(tokenizer, node, "Expected a semicolon after the import statement.\n"); + PrintError2(tokenizer, node, "Expected a semicolon after the #import statement.\n"); + return NULL; + } + } else if (token.type == T_LIBRARY) { + if (tokenizer->module->library) { + PrintError(tokenizer, "The library has already been set for this module.\n"); + return NULL; + } else { + TokenNext(tokenizer); + Token token = TokenNext(tokenizer); + + if (token.type != T_STRING_LITERAL) { + if (token.type != T_ERROR) PrintError(tokenizer, "Expected a string literal for the library name.\n"); + return NULL; + } + + char name[256]; + + if (token.textBytes > sizeof(name) - 1) { + PrintError(tokenizer, "The library name is too long.\n"); + return NULL; + } + + MemoryCopy(name, token.text, token.textBytes); + name[token.textBytes] = 0; + tokenizer->module->library = LibraryLoad(name); + + if (!tokenizer->module->library) { + return NULL; + } + } + + if (TokenNext(tokenizer).type != T_SEMICOLON) { + PrintError(tokenizer, "Expected a semicolon after the #library statement.\n"); return NULL; } } else { @@ -2631,11 +2679,13 @@ bool ASTMatching(Node *left, Node *right) { return true; } else if (!left || !right) { return false; - } else if (left->type == T_NULL && (right->type == T_STRUCT || right->type == T_LIST || right->type == T_HANDLETYPE - || right->type == T_FUNCTYPE || right->type == T_INTTYPE)) { + } else if (left->type == T_NULL && (right->type == T_STRUCT || right->type == T_LIST || right->type == T_FUNCTYPE)) { return true; - } else if (right->type == T_NULL && (left->type == T_STRUCT || left->type == T_LIST || left->type == T_HANDLETYPE - || left->type == T_FUNCTYPE || left->type == T_INTTYPE)) { + } else if (right->type == T_NULL && (left->type == T_STRUCT || left->type == T_LIST || left->type == T_FUNCTYPE)) { + return true; + } else if (left->type == T_ZERO && (right->type == T_INT || right->type == T_INTTYPE || right->type == T_HANDLETYPE)) { + return true; + } else if (right->type == T_ZERO && (left->type == T_INT || left->type == T_INTTYPE || left->type == T_HANDLETYPE)) { return true; } else if (left->type != right->type) { return false; @@ -2852,6 +2902,8 @@ int64_t ASTEvaluateIntConstant(Tokenizer *tokenizer, Node *node, bool *error) { if (node->type == T_NUMERIC_LITERAL) { return ASTNumericLiteralToValue(node).i; + } else if (node->type == T_ZERO) { + return 0; } else if (node->type == T_ADD) { return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) + ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error); } else if (node->type == T_MINUS) { @@ -2902,6 +2954,7 @@ int64_t ASTEvaluateIntConstant(Tokenizer *tokenizer, Node *node, bool *error) { bool ASTIsIntegerConstant(Node *node) { if (node->type != T_NUMERIC_LITERAL + && node->type != T_ZERO && node->type != T_ADD && node->type != T_MINUS && node->type != T_ASTERISK @@ -2970,7 +3023,7 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) { node->expressionType = &globalExpressionTypeBool; } else if (node->type == T_SUCCESS) { node->expressionType = &globalExpressionTypeErrVoid; - } else if (node->type == T_NULL) { + } else if (node->type == T_NULL || node->type == T_ZERO) { node->expressionType = node; } else if (node->type == T_STRING_LITERAL) { node->expressionType = &globalExpressionTypeStr; @@ -3004,38 +3057,49 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) { || node->type == T_DOUBLE_EQUALS || node->type == T_NOT_EQUALS || node->type == T_LOGICAL_AND || node->type == T_LOGICAL_OR || node->type == T_BIT_SHIFT_LEFT || node->type == T_BIT_SHIFT_RIGHT || node->type == T_BITWISE_OR || node->type == T_BITWISE_AND || node->type == T_BITWISE_XOR) { - if (!ASTMatching(node->firstChild->expressionType, node->firstChild->sibling->expressionType)) { - PrintError2(tokenizer, node, "The expression on the left and right side of a binary operator must have the same type.\n"); - return false; + Node *leftType = node->firstChild->expressionType; + Node *rightType = node->firstChild->sibling->expressionType; + bool useRightType = false; + + if (!ASTMatching(leftType, rightType)) { + if (leftType && rightType && leftType->type == T_INTTYPE && rightType->type == T_INTTYPE + && (ASTImplicitCastIsPossible(leftType, rightType) || ASTImplicitCastIsPossible(rightType, leftType))) { + // If both expressions are inttypes with one inheriting from the other, allow an implicit cast. + // Nothing needs to be done to cast between inttypes. + useRightType = ASTImplicitCastIsPossible(rightType, leftType); + } else { + PrintError2(tokenizer, node, "The expression on the left and right side of a binary operator must have the same type.\n"); + return false; + } } if (node->type == T_ADD) { - if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeInt) - && !ASTIsIntType(node->firstChild->expressionType) - && !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeFloat) - && !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeStr)) { + if (!ASTMatching(leftType, &globalExpressionTypeInt) + && !ASTIsIntType(leftType) + && !ASTMatching(leftType, &globalExpressionTypeFloat) + && !ASTMatching(leftType, &globalExpressionTypeStr)) { PrintError2(tokenizer, node, "The add operator expects integers, floats or strings.\n"); return false; } } else if (node->type == T_LOGICAL_AND || node->type == T_LOGICAL_OR) { - if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeBool)) { + if (!ASTMatching(leftType, &globalExpressionTypeBool)) { PrintError2(tokenizer, node, "This operator expects boolean expressions.\n"); return false; } } else if (node->type == T_DOUBLE_EQUALS || node->type == T_NOT_EQUALS) { - if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeInt) - && !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeFloat) - && !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeStr) - && !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeBool) - && (!node->firstChild->expressionType || node->firstChild->expressionType->type != T_LIST) - && (!node->firstChild->expressionType || node->firstChild->expressionType->type != T_STRUCT)) { + if (!ASTMatching(leftType, &globalExpressionTypeInt) + && !ASTMatching(leftType, &globalExpressionTypeFloat) + && !ASTMatching(leftType, &globalExpressionTypeStr) + && !ASTMatching(leftType, &globalExpressionTypeBool) + && (!leftType || leftType->type != T_LIST) + && (!leftType || leftType->type != T_STRUCT)) { PrintError2(tokenizer, node, "These types cannot be compared.\n"); return false; } } else { - if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeInt) - && !ASTIsIntType(node->firstChild->expressionType) - && !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeFloat)) { + if (!ASTMatching(leftType, &globalExpressionTypeInt) + && !ASTIsIntType(leftType) + && !ASTMatching(leftType, &globalExpressionTypeFloat)) { PrintError2(tokenizer, node, "This operator expects either integers or floats.\n"); return false; } @@ -3045,7 +3109,7 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) { || node->type == T_DOUBLE_EQUALS || node->type == T_NOT_EQUALS) { node->expressionType = &globalExpressionTypeBool; } else { - node->expressionType = node->firstChild->expressionType; + node->expressionType = useRightType ? rightType : leftType; } } else if (node->type == T_DECLARE) { if (node->firstChild->sibling && ASTImplicitCastIsPossible(node->firstChild, node->firstChild->sibling->expressionType)) { @@ -3133,7 +3197,8 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) { node->expressionType = expressionType->firstChild->sibling; Node *match = expressionType->firstChild->firstChild; - Node *argument = node->firstChild->sibling->firstChild; + Node **argumentLink = &node->firstChild->sibling->firstChild; + Node *argument = *argumentLink; size_t index = 1; while (true) { @@ -3143,13 +3208,18 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) { PrintError2(tokenizer, node, "The function has a different number of arguments to this.\n"); return false; } else { - if (!ASTMatching(argument->expressionType, match->firstChild)) { + if (ASTImplicitCastIsPossible(match->firstChild, argument->expressionType)) { + Node *cast = ASTImplicitCastApply(tokenizer, node, match->firstChild, argument); + if (!cast) return false; + *argumentLink = cast; + } else if (!ASTMatching(argument->expressionType, match->firstChild)) { PrintError2(tokenizer, node, "The types for argument %d do not match.\n", index); return false; } match = match->sibling; - argument = argument->sibling; + argumentLink = &argument->sibling; + argument = *argumentLink; index++; } } @@ -3926,11 +3996,8 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b if (!FunctionBuilderRecurse(tokenizer, declare, builder, false)) return false; // Push the starting index of 0. - uint8_t b = T_NUMERIC_LITERAL; + uint8_t b = T_ZERO; FunctionBuilderAppend(builder, &b, sizeof(b)); - Value v; - v.i = 0; - FunctionBuilderAppend(builder, &v, sizeof(v)); // Push the list. if (!FunctionBuilderRecurse(tokenizer, list, builder, false)) return false; @@ -4010,6 +4077,7 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b // Stack: index, list, ... b = T_NUMERIC_LITERAL; FunctionBuilderAppend(builder, &b, sizeof(b)); + Value v; v.i = 1; FunctionBuilderAppend(builder, &v, sizeof(v)); // Stack: 1, index, list, ... @@ -4279,7 +4347,7 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b FunctionBuilderAppend(builder, &b, sizeof(b)); b = T_POP; FunctionBuilderAppend(builder, &b, sizeof(b)); - } else if (node->type == T_NULL || node->type == T_LOGICAL_NOT || node->type == T_AWAIT || node->type == T_ERR_CAST) { + } else if (node->type == T_NULL || node->type == T_LOGICAL_NOT || node->type == T_AWAIT || node->type == T_ERR_CAST || node->type == T_ZERO) { FunctionBuilderAddLineNumber(builder, node); FunctionBuilderAppend(builder, &node->type, sizeof(node->type)); } else if (node->type == T_ANYTYPE_CAST) { @@ -4375,14 +4443,28 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b } else { Node *importStatement = node->firstChild->expressionType->parent; Assert(importStatement->type == T_IMPORT); - uint32_t index = ScopeLookupIndex(node, importStatement->importData->rootNode->scope, false, false); - index += importStatement->importData->globalVariableOffset; + uint32_t realIndex = ScopeLookupIndex(node, importStatement->importData->rootNode->scope, false, true); + Node *declarationNode = importStatement->importData->rootNode->scope->entries[realIndex]; + FunctionBuilderAddLineNumber(builder, node); uint8_t b = T_POP; FunctionBuilderAppend(builder, &b, sizeof(b)); - b = T_VARIABLE; - FunctionBuilderAppend(builder, &b, sizeof(b)); - FunctionBuilderAppend(builder, &index, sizeof(index)); + + if (declarationNode->type == T_INTTYPE_CONSTANT) { + bool error = false; + Value intConstantValue; + intConstantValue.i = ASTEvaluateIntConstant(tokenizer, declarationNode->firstChild, &error); + if (error) return false; + uint8_t b = T_NUMERIC_LITERAL; + FunctionBuilderAppend(builder, &b, sizeof(b)); + FunctionBuilderAppend(builder, &intConstantValue, sizeof(intConstantValue)); + } else { + uint32_t index = ScopeLookupIndex(node, importStatement->importData->rootNode->scope, false, false); + index += importStatement->importData->globalVariableOffset; + b = T_VARIABLE; + FunctionBuilderAppend(builder, &b, sizeof(b)); + FunctionBuilderAppend(builder, &index, sizeof(index)); + } } } } else if (node->type == T_NUMERIC_LITERAL) { @@ -4452,7 +4534,23 @@ bool ASTGenerate(Tokenizer *tokenizer, Node *root, ExecutionContext *context) { context->heap[heapIndex].lambdaID = context->functionData->dataBytes; context->globalVariables[variableIndex].i = heapIndex; - if (child->isExternalCall) { + if (child->isExternalCall && child->token.module->library) { + char name[256]; + + if (child->token.textBytes > sizeof(name) - 1) { + PrintError2(tokenizer, child, "The function name is too long to be loaded from a library.\n"); + return NULL; + } + + MemoryCopy(name, child->token.text, child->token.textBytes); + name[child->token.textBytes] = 0; + + void *address = LibraryGetAddress(child->token.module->library, name); + if (!address) return false; + uint8_t b = T_LIBCALL; + FunctionBuilderAppend(context->functionData, &b, sizeof(b)); + FunctionBuilderAppend(context->functionData, &address, sizeof(address)); + } else if (child->isExternalCall) { uint8_t b = T_EXTCALL; uint16_t index = 0xFFFF; @@ -4793,13 +4891,13 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex context->c->stackIsManaged[context->c->stackPointer] = false; MemoryCopy(&context->c->stack[context->c->stackPointer++], &functionData[instructionPointer], sizeof(Value)); instructionPointer += sizeof(Value); - } else if (command == T_NULL) { + } else if (command == T_NULL || command == T_ZERO) { if (context->c->stackPointer == context->c->stackEntriesAllocated) { PrintError4(context, instructionPointer - 1, "Stack overflow.\n"); return 0; } - context->c->stackIsManaged[context->c->stackPointer] = true; + context->c->stackIsManaged[context->c->stackPointer] = command == T_NULL; context->c->stack[context->c->stackPointer++].i = 0; } else if (command == T_STRING_LITERAL) { if (context->c->stackPointer == context->c->stackEntriesAllocated) { @@ -6040,7 +6138,7 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex } else if (command == T_REPL_RESULT) { if (context->c->stackPointer < 1) return -1; ExternalPassREPLResult(context, context->c->stack[--context->c->stackPointer]); - } else if (command == T_END_FUNCTION || command == T_EXTCALL) { + } else if (command == T_END_FUNCTION || command == T_EXTCALL || command == T_LIBCALL) { if (command == T_EXTCALL) { uint16_t index = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8); instructionPointer += 2; @@ -6102,6 +6200,29 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex } else { return -1; } + } else if (command == T_LIBCALL) { + context->c->parameterCount = 0; + context->c->returnValueType = EXTCALL_NO_RETURN; + + void *address; + MemoryCopy(&address, &functionData[instructionPointer], sizeof(address)); + instructionPointer += sizeof(address); + + if (!((bool (*)(void *)) address)(context)) { + return 0; + } + + context->c->stackPointer -= context->c->parameterCount; + + if (context->c->returnValueType != EXTCALL_NO_RETURN) { + if (context->c->stackPointer == context->c->stackEntriesAllocated) { + PrintDebug("Evaluation stack overflow.\n"); + return -1; + } + + context->c->stackIsManaged[context->c->stackPointer] = context->c->returnValueType == EXTCALL_RETURN_MANAGED; + context->c->stack[context->c->stackPointer++] = context->c->returnValue; + } } context->c->localVariableCount = variableBase + 1; @@ -6109,7 +6230,7 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex if (context->c->backTracePointer) { BackTraceItem *item = &context->c->backTrace[context->c->backTracePointer - 1]; - if (command == T_EXTCALL) { + if (command == T_EXTCALL || command == T_LIBCALL) { context->c->backTracePointer--; instructionPointer = item->instructionPointer; variableBase = item->variableBase; @@ -6128,7 +6249,7 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex } } - if (command != T_EXTCALL) { + if (command != T_EXTCALL && command != T_LIBCALL) { context->c->backTracePointer--; instructionPointer = item->instructionPointer; variableBase = item->variableBase; @@ -6246,6 +6367,53 @@ bool ScriptParseOptions(ExecutionContext *context) { return true; } +bool ScriptParameterCString(void *engine, char **output) { + ExecutionContext *context = (ExecutionContext *) engine; + context->c->parameterCount++; + if (context->c->stackPointer < context->c->parameterCount) return false; + if (!context->c->stackIsManaged[context->c->stackPointer - context->c->parameterCount]) return false; + uint64_t index = context->c->stack[context->c->stackPointer - context->c->parameterCount].i; + if (context->heapEntriesAllocated <= index) return false; + const char *text; + size_t bytes; + HeapEntry *entry = &context->heap[index]; + ScriptHeapEntryToString(context, entry, &text, &bytes); + *output = (char *) AllocateResize(NULL, bytes + 1); + MemoryCopy(*output, text, bytes); + (*output)[bytes] = 0; + return true; +} + +bool ScriptParameterInt64(void *engine, int64_t *output) { + ExecutionContext *context = (ExecutionContext *) engine; + context->c->parameterCount++; + if (context->c->stackPointer < context->c->parameterCount) return false; + *output = context->c->stack[context->c->stackPointer - context->c->parameterCount].i; + return true; +} + +bool ScriptParameterUint32(void *engine, uint32_t *output) { int64_t i; if (!ScriptParameterInt64(engine, &i)) return false; *output = i; return true; } +bool ScriptParameterUint64(void *engine, uint64_t *output) { int64_t i; if (!ScriptParameterInt64(engine, &i)) return false; *output = i; return true; } +bool ScriptParameterInt32 (void *engine, int32_t *output) { int64_t i; if (!ScriptParameterInt64(engine, &i)) return false; *output = i; return true; } + +void ScriptReturnInt(void *engine, int64_t input) { + ExecutionContext *context = (ExecutionContext *) engine; + Assert(context->c->returnValueType == EXTCALL_NO_RETURN); + context->c->returnValueType = EXTCALL_RETURN_UNMANAGED; + context->c->returnValue.i = input; +} + +bool ScriptParameterPointer(void *engine, void **output) { + int64_t i; + if (!ScriptParameterInt64(engine, &i)) return false; + *output = (void *) (intptr_t) i; + return true; +} + +void ScriptReturnPointer(void *engine, void *input) { + ScriptReturnInt(engine, (int64_t) (intptr_t) input); +} + bool ScriptLoad(Tokenizer tokenizer, ExecutionContext *context, ImportData *importData, bool replMode) { Node *previousRootNode = context->rootNode; ImportData *previousImportData = context->functionData->importData; @@ -6537,6 +6705,7 @@ int ExternalCharacterToByte(ExecutionContext *context, Value *returnValue) { #define pclose _pclose #define setenv(x, y, z) !SetEnvironmentVariable(x, y) #else +#include #include #include #include @@ -7494,6 +7663,38 @@ void PrintError4(ExecutionContext *context, uint32_t instructionPointer, const c PrintBackTrace(context, instructionPointer, context->c, ""); } +void *LibraryLoad(const char *name) { + Assert(strlen(name) < 256); + char name2[256 + 20]; + strcpy(name2, "l"); + strcat(name2, name); + strcat(name2, ".so"); + + void *library = dlopen(name2, RTLD_NOW); + + if (!library) { + PrintError3("The library \"%s\" could not be found or loaded.\n", name2); + } + + return library; +} + +void *LibraryGetAddress(void *library, const char *name) { + Assert(strlen(name) < 256); + Assert(library); + char name2[256 + 20]; + strcpy(name2, "ScriptExt"); + strcat(name2, name); + + void *address = dlsym(library, name2); + + if (!address) { + PrintError3("The library symbol \"%s\" could not be found.\n", name2); + } + + return address; +} + void *FileLoad(const char *path, size_t *length) { FILE *file = fopen(path, "rb"); if (!file) return NULL;