fix tests; add comprehensive tests for functions and fix bugs in the mach VM regarding them.

This commit is contained in:
2026-02-24 17:41:18 -06:00
parent c2f57d1dae
commit 33d9013409
6 changed files with 1009 additions and 14 deletions

View File

@@ -11503,15 +11503,20 @@ static JSValue js_cell_is_upper (JSContext *ctx, JSValue this_val, int argc, JSV
return JS_NewBool (ctx, c >= 'A' && c <= 'Z');
}
/* is_whitespace(val) - check if value is a single whitespace character */
/* is_whitespace(val) - check if all characters are whitespace (non-empty) */
static JSValue js_cell_is_whitespace (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) return JS_FALSE;
JSValue val = argv[0];
if (!JS_IsText (val)) return JS_FALSE;
if (js_string_value_len (val) != 1) return JS_FALSE;
uint32_t c = js_string_value_get (val, 0);
return JS_NewBool (ctx, c == ' ' || c == '\t' || c == '\n'
|| c == '\r' || c == '\f' || c == '\v');
int len = js_string_value_len (val);
if (len == 0) return JS_FALSE;
for (int i = 0; i < len; i++) {
uint32_t c = js_string_value_get (val, i);
if (!(c == ' ' || c == '\t' || c == '\n'
|| c == '\r' || c == '\f' || c == '\v'))
return JS_FALSE;
}
return JS_TRUE;
}
/* is_proto(val, master) - check if val has master in prototype chain */
@@ -11571,6 +11576,47 @@ static JSValue js_cell_logical(JSContext *ctx, JSValue this_val, int argc, JSVal
return JS_NULL;
}
/* realloc wrapper for unicode_normalize */
static void *normalize_realloc(void *opaque, void *ptr, size_t size) {
(void)opaque;
if (size == 0) {
pjs_free(ptr);
return NULL;
}
return pjs_realloc(ptr, size);
}
/* normalize(text) — NFC normalization */
static JSValue js_cell_normalize(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) return JS_NULL;
JSValue val = argv[0];
if (!JS_IsText(val)) return JS_NULL;
int len = js_string_value_len(val);
if (len == 0) return JS_NewString(ctx, "");
uint32_t *src = pjs_malloc(len * sizeof(uint32_t));
if (!src) return JS_EXCEPTION;
for (int i = 0; i < len; i++)
src[i] = js_string_value_get(val, i);
uint32_t *dst = NULL;
int dst_len = unicode_normalize(&dst, src, len, UNICODE_NFC, NULL,
normalize_realloc);
pjs_free(src);
if (dst_len < 0) {
pjs_free(dst);
return JS_NULL;
}
JSText *str = js_alloc_string(ctx, dst_len);
if (!str) {
pjs_free(dst);
return JS_EXCEPTION;
}
for (int i = 0; i < dst_len; i++)
string_put(str, i, dst[i]);
str->length = dst_len;
pjs_free(dst);
return pretext_end(ctx, str);
}
/* starts_with(str, prefix) — search(str, prefix) == 0 */
static JSValue js_cell_starts_with(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2) return JS_NULL;
@@ -11616,6 +11662,85 @@ static JSValue js_cell_some(JSContext *ctx, JSValue this_val, int argc, JSValue
return JS_FALSE;
}
/* C API: Type-check wrappers for sensory functions */
JS_BOOL JS_IsDigit (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_digit (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsLetter (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_letter (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsLower (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_lower (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsUpper (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_upper (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsWhitespace (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_whitespace (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsCharacter (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_character (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsFit (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_fit (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
JS_BOOL JS_IsData (JSValue val) {
return !JS_IsNull (val) && !JS_IsFunction (val);
}
JS_BOOL JS_IsActor (JSContext *ctx, JSValue val) {
JSValue r = js_cell_is_actor (ctx, JS_NULL, 1, &val);
return JS_VALUE_GET_BOOL (r);
}
/* C API: logical(val) */
JSValue JS_CellLogical (JSContext *ctx, JSValue val) {
return js_cell_logical (ctx, JS_NULL, 1, &val);
}
/* C API: every(arr, pred) */
JSValue JS_CellEvery (JSContext *ctx, JSValue arr, JSValue pred) {
JSValue argv[2] = { arr, pred };
return js_cell_every (ctx, JS_NULL, 2, argv);
}
/* C API: some(arr, pred) */
JSValue JS_CellSome (JSContext *ctx, JSValue arr, JSValue pred) {
JSValue argv[2] = { arr, pred };
return js_cell_some (ctx, JS_NULL, 2, argv);
}
/* C API: starts_with(text, prefix) */
JSValue JS_CellStartsWith (JSContext *ctx, JSValue text, JSValue prefix) {
JSValue argv[2] = { text, prefix };
return js_cell_starts_with (ctx, JS_NULL, 2, argv);
}
/* C API: ends_with(text, suffix) */
JSValue JS_CellEndsWith (JSContext *ctx, JSValue text, JSValue suffix) {
JSValue argv[2] = { text, suffix };
return js_cell_ends_with (ctx, JS_NULL, 2, argv);
}
/* C API: normalize(text) */
JSValue JS_CellNormalize (JSContext *ctx, JSValue text) {
return js_cell_normalize (ctx, JS_NULL, 1, &text);
}
static void js_set_global_cfunc(JSContext *ctx, const char *name, JSCFunction *func, int length) {
JSGCRef ref;
JS_PushGCRef(ctx, &ref);
@@ -11740,6 +11865,7 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
js_set_global_cfunc(ctx, "ends_with", js_cell_ends_with, 2);
js_set_global_cfunc(ctx, "every", js_cell_every, 2);
js_set_global_cfunc(ctx, "some", js_cell_some, 2);
js_set_global_cfunc(ctx, "normalize", js_cell_normalize, 1);
/* fn record with apply property */
{