From fd6b651af7d64cf9eff6daad03784d29073370f4 Mon Sep 17 00:00:00 2001 From: retoor Date: Tue, 29 Jul 2025 15:15:00 +0200 Subject: [PATCH] Crawler. --- string_backend.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 string_backend.c diff --git a/string_backend.c b/string_backend.c new file mode 100644 index 0000000..5beac33 --- /dev/null +++ b/string_backend.c @@ -0,0 +1,151 @@ +// string_backend.c +#include "wren.h" +#include +#include +#include + +// Helper to validate that the value in a slot is a string. +static bool validateString(WrenVM* vm, int slot, const char* name) { + if (wrenGetSlotType(vm, slot) == WREN_TYPE_STRING) return true; + wrenSetSlotString(vm, 0, "Argument must be a string."); + wrenAbortFiber(vm, 0); + return false; +} + +// Implements String.endsWith(_). +void stringEndsWith(WrenVM* vm) { + if (!validateString(vm, 1, "Suffix")) return; + + int stringLength, suffixLength; + const char* string = wrenGetSlotBytes(vm, 0, &stringLength); + const char* suffix = wrenGetSlotBytes(vm, 1, &suffixLength); + + if (suffixLength > stringLength) { + wrenSetSlotBool(vm, 0, false); + return; + } + + wrenSetSlotBool(vm, 0, memcmp(string + stringLength - suffixLength, suffix, suffixLength) == 0); +} + +// Implements String.startsWith(_). +void stringStartsWith(WrenVM* vm) { + if (!validateString(vm, 1, "Prefix")) return; + + int stringLength, prefixLength; + const char* string = wrenGetSlotBytes(vm, 0, &stringLength); + const char* prefix = wrenGetSlotBytes(vm, 1, &prefixLength); + + if (prefixLength > stringLength) { + wrenSetSlotBool(vm, 0, false); + return; + } + + wrenSetSlotBool(vm, 0, memcmp(string, prefix, prefixLength) == 0); +} + +// Implements String.replace(_, _). +void stringReplace(WrenVM* vm) { + if (!validateString(vm, 1, "From")) return; + if (!validateString(vm, 2, "To")) return; + + int haystackLen, fromLen, toLen; + const char* haystack = wrenGetSlotBytes(vm, 0, &haystackLen); + const char* from = wrenGetSlotBytes(vm, 1, &fromLen); + const char* to = wrenGetSlotBytes(vm, 2, &toLen); + + if (fromLen == 0) { + wrenSetSlotString(vm, 0, haystack); // Nothing to replace. + return; + } + + // Allocate a buffer for the result. This is a rough estimate. + // A more robust implementation would calculate the exact size or reallocate. + size_t resultCapacity = haystackLen * (toLen > fromLen ? toLen / fromLen + 1 : 1) + 1; + char* result = (char*)malloc(resultCapacity); + if (!result) { + // Handle allocation failure + wrenSetSlotString(vm, 0, "Memory allocation failed."); + wrenAbortFiber(vm, 0); + return; + } + + + char* dest = result; + const char* p = haystack; + const char* end = haystack + haystackLen; + + while (p < end) { + const char* found = strstr(p, from); + if (found) { + size_t len = found - p; + memcpy(dest, p, len); + dest += len; + memcpy(dest, to, toLen); + dest += toLen; + p = found + fromLen; + } else { + size_t len = end - p; + memcpy(dest, p, len); + dest += len; + p = end; + } + } + *dest = '\0'; + + wrenSetSlotString(vm, 0, result); + free(result); +} + +// Implements String.split(_). +void stringSplit(WrenVM* vm) { + if (!validateString(vm, 1, "Delimiter")) return; + + int haystackLen, delimLen; + const char* haystack = wrenGetSlotBytes(vm, 0, &haystackLen); + const char* delim = wrenGetSlotBytes(vm, 1, &delimLen); + + if (delimLen == 0) { + wrenSetSlotString(vm, 0, "Delimiter cannot be empty."); + wrenAbortFiber(vm, 0); + return; + } + + wrenSetSlotNewList(vm, 0); // Create the list to return. + + const char* p = haystack; + const char* end = haystack + haystackLen; + while (p < end) { + const char* found = strstr(p, delim); + if (found) { + wrenSetSlotBytes(vm, 1, p, found - p); + wrenInsertInList(vm, 0, -1, 1); + p = found + delimLen; + } else { + wrenSetSlotBytes(vm, 1, p, end - p); + wrenInsertInList(vm, 0, -1, 1); + p = end; + } + } + + // If the string ends with the delimiter, add an empty string. + if (haystackLen > 0 && (haystackLen >= delimLen) && + strcmp(haystack + haystackLen - delimLen, delim) == 0) { + wrenSetSlotBytes(vm, 1, "", 0); + wrenInsertInList(vm, 0, -1, 1); + } +} + +// Binds the foreign methods for the String class. +WrenForeignMethodFn bindStringForeignMethod(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature) { + if (strcmp(module, "main") != 0 && strcmp(module, "core") != 0) return NULL; + if (strcmp(className, "String") != 0 || isStatic) return NULL; + + if (strcmp(signature, "endsWith(_)") == 0) return stringEndsWith; + if (strcmp(signature, "startsWith(_)") == 0) return stringStartsWith; + if (strcmp(signature, "replace(_,_)") == 0) return stringReplace; + if (strcmp(signature, "split(_)") == 0) return stringSplit; + + return NULL; +} +