#include #include #include #include #include "utils.h" #include "string.h" #include "../utils/defs.h" #include "../utils/utf8.h" #include "../runtime/runtime.h" static int bin_ord(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { UNUSED(runtime); UNUSED(error); UNUSED(argc); ASSERT(argc == 1); uint32_t ret = 0; if(!Object_IsString(argv[0])) { Error_Report(error, 0, "Argument #%d is not a string", 1); return -1; } const char *string; size_t length; string = Object_GetString(argv[0], &length); ASSERT(string != NULL); if(length == 0) { Error_Report(error, 0, "Argument #%d is an empty string", 1); return -1; } int k = utf8_sequence_to_utf32_codepoint(string, length, &ret); UNUSED(k); ASSERT(k >= 0); Object *temp = Object_FromInt(ret, Runtime_GetHeap(runtime), error); if(temp == NULL) return -1; rets[0] = temp; return 1; } static int bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { UNUSED(argc); ASSERT(argc == 1); if(!Object_IsInt(argv[0])) { Error_Report(error, 0, "Argument #%d is not an integer", 1); return -1; } char buff[32]; int value = Object_GetInt(argv[0]); int k = utf8_sequence_from_utf32_codepoint(buff,sizeof(buff),value); if(k<0) { Error_Report(error, 0, "Argument #%d is not valid utf-32", 1); return -1; } Object *temp = Object_FromString(buff,k,Runtime_GetHeap(runtime),error); if(temp == NULL) return -1; rets[0] = temp; return 1; } static int bin_cat(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { unsigned int total_count = 0; for(unsigned int i = 0; i < argc; i += 1) { if(!Object_IsString(argv[i])) { Error_Report(error, 0, "Argument #%d is not a string", i+1); return -1; } size_t length; Object_GetString(argv[i], &length); total_count += length; // The Object_Count of a string doesn't match the // byte count, but the second argument of Object_GetString // does. } char starting[128]; char *buffer = starting; if(total_count > sizeof(starting)-1) { buffer = malloc(total_count+1); if(buffer == NULL) { Error_Report(error, 1, "No memory"); return -1; } } for(unsigned int i = 0, written = 0; i < argc; i += 1) { size_t length; const char *s = Object_GetString(argv[i], &length); memcpy(buffer + written, s, length); written += length; } buffer[total_count] = '\0'; Object *result = Object_FromString(buffer, total_count, Runtime_GetHeap(runtime), error); if(starting != buffer) free(buffer); if(result == NULL) return -1; rets[0] = result; return 1; } static int bin_slice(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { // 0: string // 1: start offset or none // 2: end offset or none ParsedArgument pargs[3]; if (!parseArgs(error, argv, argc, pargs, "s?i?i")) return -1; const char *srcstr = pargs[0].as_string.data; size_t srclen = pargs[0].as_string.size; size_t offset; size_t length; if (pargs[1].defined) { int64_t n = pargs[1].as_int; if (n < 0) { Error_Report(error, 0, "starting offset of string slice must be non-negative"); return -1; } offset = (size_t) n; } else offset = 0; if (pargs[2].defined) { int64_t n = pargs[2].as_int; if (n < 0) { Error_Report(error, 0, "length of string slice must be non-negative"); return -1; } length = (size_t) n; } else length = srclen - offset; if (offset > srclen) { Error_Report(error, 0, "string slice offset is out of bounds"); return -1; } if (offset + length > srclen) { Error_Report(error, 0, "string slice length is out of bounds"); return -1; } Heap *heap = Runtime_GetHeap(runtime); Object *slice = Object_FromString(srcstr + offset, length, heap, error); if (slice == NULL) return -1; rets[0] = slice; return 1; } static int bin_trim(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { // 0: string ParsedArgument pargs[1]; if (!parseArgs(error, argv, argc, pargs, "s")) return -1; const char *srcstr = pargs[0].as_string.data; size_t srclen = pargs[0].as_string.size; size_t offset = 0; size_t length = srclen; while (offset < srclen && srcstr[offset] == ' ') offset++; Heap *heap = Runtime_GetHeap(runtime); Object *result; if (offset == srclen) // The string only contained whitespace. // Return an empty string. result = Object_FromString("", 0, heap, error); else { // NOTE: The string doesn't contain only // whitespace, so the length can't // go under 1. while (srcstr[offset + length - 1] == ' ') length--; result = Object_FromString(srcstr + offset, length, heap, error); } if (result == NULL) return -1; rets[0] = result; return 1; } static int bin_toInt(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { // 0: string ParsedArgument pargs[1]; if (!parseArgs(error, argv, argc, pargs, "s")) return -1; const char *srcstr = pargs[0].as_string.data; size_t srclen = pargs[0].as_string.size; if (srclen == 0 || !isdigit(srcstr[0])) return returnValues2(error, runtime, rets, "ns", "String doesn't contain an integer"); int64_t result = 0; size_t i = 0; do { int digit = srcstr[i] - '0'; if (result > (INT64_MAX - digit) / 10) return returnValues2(error, runtime, rets, "ns", "An overflow occurred"); result = result * 10 + digit; i++; } while (i < srclen && isdigit(srcstr[i])); if (i < srclen) // Found something other than a digit after the // sequence of digits, therefore the string can't // be considered an integer. return returnValues2(error, runtime, rets, "ns", "String doesn't contain an integer"); return returnValues2(error, runtime, rets, "i", result); } StaticMapSlot bins_string[] = { { "ord", SM_FUNCT, .as_funct = bin_ord, .argc = 1 }, { "chr", SM_FUNCT, .as_funct = bin_chr, .argc = 1 }, { "cat", SM_FUNCT, .as_funct = bin_cat, .argc = -1 }, { "trim", SM_FUNCT, .as_funct = bin_trim, .argc = 1 }, { "slice", SM_FUNCT, .as_funct = bin_slice, .argc = 3 }, { "toInt", SM_FUNCT, .as_funct = bin_toInt, .argc = 1 }, };