152 lines
4.7 KiB
C
Raw Normal View History

2025-07-29 15:15:00 +02:00
// string_backend.c
#include "wren.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// 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;
}