suite.c all works

This commit is contained in:
2026-02-02 23:39:12 -06:00
parent 69b032d3dc
commit 893deaec23
2 changed files with 237 additions and 106 deletions

View File

@@ -274,7 +274,8 @@ typedef enum JSErrorEnum {
ARG_SCOPE_END values are reserved. */
#define JS_MAX_LOCAL_VARS 65534
#define JS_STACK_SIZE_MAX 65534
#define JS_STRING_LEN_MAX ((1 << 56) - 1)
/* Max string length matches header capacity (56 bits on 64-bit builds) */
#define JS_STRING_LEN_MAX OBJHDR_CAP_MASK
#define __exception __attribute__ ((warn_unused_result))
@@ -700,17 +701,21 @@ static JS_BOOL JSText_equal_ascii (const JSText *text, JSValue imm) {
}
/* Get hash for a JSText value.
For stoned text (s=1): hash is pre-computed in length field.
For stoned text (s=1): hash is cached in length field (computed on first access).
For pre-text (s=0): compute hash on the fly. */
static uint64_t get_text_hash (JSText *text) {
uint64_t len = objhdr_cap56 (text->hdr);
size_t word_count = (len + 1) / 2;
if (objhdr_s (text->hdr)) {
/* Stoned text: check for cached hash */
if (text->length != 0) return text->length;
text->length = fash64_hash_words (text->packed, (text->length + 1) / 2, text->length);
/* Compute and cache hash using content length from header */
text->length = fash64_hash_words (text->packed, word_count, len);
if (!text->length) text->length = 1;
return text->length;
} else {
uint64_t len = objhdr_cap56 (text->hdr);
size_t word_count = (len + 1) / 2;
/* Pre-text: compute hash on the fly */
return fash64_hash_words (text->packed, word_count, len);
}
}
@@ -1214,13 +1219,24 @@ static inline void rec_tab_init (JSRecordEntry *tab, uint32_t mask) {
// can check if key by checking for 0 here
static uint64_t js_key_hash (JSValue key) {
if (MIST_IsImmediateASCII (key)) {
uint64_t h = fash64_hash_one (key);
/* Hash immediate ASCII the same way as heap strings for consistency */
int len = MIST_GetImmediateASCIILen (key);
if (len == 0) return 1;
size_t word_count = (len + 1) / 2;
uint64_t packed[4]; /* Max 7 chars = 4 words */
for (size_t i = 0; i < word_count; i++) {
uint32_t c0 = (i * 2 < (size_t)len) ? MIST_GetImmediateASCIIChar (key, i * 2) : 0;
uint32_t c1 = (i * 2 + 1 < (size_t)len) ? MIST_GetImmediateASCIIChar (key, i * 2 + 1) : 0;
packed[i] = ((uint64_t)c0 << 32) | c1;
}
uint64_t h = fash64_hash_words (packed, word_count, len);
return h ? h : 1;
}
if (!JS_IsPtr (key)) return 0;
void *ptr = JS_VALUE_GET_PTR (key);
/* Use chase to follow forwarding pointers */
void *ptr = chase (key);
objhdr_t hdr = *(objhdr_t *)ptr;
uint8_t type = objhdr_type (hdr);
@@ -1242,24 +1258,25 @@ static uint64_t js_key_hash (JSValue key) {
static JS_BOOL js_key_equal (JSValue a, JSValue b) {
if (a == b) return TRUE;
/* Use chase to follow forwarding pointers */
if (MIST_IsImmediateASCII (a)) {
if (MIST_IsImmediateASCII (b)) return FALSE;
if (!JS_IsPtr (b)) return FALSE;
JSText *tb = (JSText *)JS_VALUE_GET_PTR (b);
JSText *tb = (JSText *)chase (b);
if (objhdr_type (tb->hdr) != OBJ_TEXT) return FALSE;
return JSText_equal_ascii (tb, a);
}
if (MIST_IsImmediateASCII (b)) {
if (!JS_IsPtr (a)) return FALSE;
JSText *ta = (JSText *)JS_VALUE_GET_PTR (a);
JSText *ta = (JSText *)chase (a);
if (objhdr_type (ta->hdr) != OBJ_TEXT) return FALSE;
return JSText_equal_ascii (ta, b);
}
if (!JS_IsPtr (a) || !JS_IsPtr (b)) return FALSE;
void *pa = JS_VALUE_GET_PTR (a);
void *pb = JS_VALUE_GET_PTR (b);
void *pa = chase (a);
void *pb = chase (b);
objhdr_t ha = *(objhdr_t *)pa;
objhdr_t hb = *(objhdr_t *)pb;
uint8_t type_a = objhdr_type (ha);
@@ -1363,19 +1380,67 @@ static JSValue rec_get (JSContext *ctx, JSRecord *rec, JSValue k) {
return JS_NULL;
}
/* Resize record - NOT YET IMPLEMENTED for inline slots.
With inline slots (flexible array member), resizing requires allocating
a completely new record and copying. For now, this always fails.
TODO: Implement proper record growth with copying GC. */
static int rec_resize (JSContext *ctx, JSRecord *rec, uint64_t new_mask) {
(void)ctx; (void)rec; (void)new_mask;
/* Cannot resize inline slots - need to allocate new record */
return -1;
/* Resize record by allocating a new larger record and copying all data.
Sets up a forwarding pointer from old record to new.
Updates *prec to point to the new record.
Returns 0 on success, -1 on failure. */
static int rec_resize (JSContext *ctx, JSRecord **prec, uint64_t new_mask) {
JSRecord *rec = *prec;
uint64_t old_mask = objhdr_cap56 (rec->mist_hdr);
/* Allocate new record with larger capacity */
size_t slots_size = sizeof (slot) * (new_mask + 1);
size_t total_size = sizeof (JSRecord) + slots_size;
JSRecord *new_rec = js_malloc (ctx, total_size);
if (!new_rec) return -1;
/* Initialize new record */
new_rec->mist_hdr = objhdr_make (new_mask, OBJ_RECORD, false, false, false, false);
new_rec->proto = rec->proto;
new_rec->len = 0;
/* Initialize all slots to empty */
for (uint64_t i = 0; i <= new_mask; i++) {
new_rec->slots[i].key = JS_NULL;
new_rec->slots[i].val = JS_NULL;
}
/* Copy slot[0] (class_id, rec_id, opaque) */
new_rec->slots[0].key = rec->slots[0].key;
new_rec->slots[0].val = rec->slots[0].val;
/* Rehash all valid entries from old to new */
for (uint64_t i = 1; i <= old_mask; i++) {
JSValue k = rec->slots[i].key;
if (!rec_key_is_empty (k) && !rec_key_is_tomb (k)) {
/* Insert into new record using linear probing */
uint64_t h64 = js_key_hash (k);
uint64_t slot = (h64 & new_mask);
if (slot == 0) slot = 1;
while (!rec_key_is_empty (new_rec->slots[slot].key)) {
slot = (slot + 1) & new_mask;
if (slot == 0) slot = 1;
}
new_rec->slots[slot].key = k;
new_rec->slots[slot].val = rec->slots[i].val;
new_rec->len++;
}
}
/* Set up forwarding pointer from old record to new */
rec->mist_hdr = objhdr_make_fwd (new_rec);
/* Update caller's pointer to new record */
*prec = new_rec;
return 0;
}
/* NOT GC-SAFE: May call rec_resize which allocates.
Caller must pass freshly-chased rec and handle potential staleness.
Currently safe because rec_resize always fails. */
Caller must pass freshly-chased rec and handle potential staleness. */
static int rec_set_own (JSContext *ctx, JSRecord *rec, JSValue k, JSValue val) {
if (rec_key_is_empty (k) || rec_key_is_tomb (k)) {
return -1;
@@ -1392,12 +1457,12 @@ static int rec_set_own (JSContext *ctx, JSRecord *rec, JSValue k, JSValue val) {
/* New key - check if resize needed (75% load factor) */
uint32_t mask = (uint32_t)objhdr_cap56 (rec->mist_hdr);
if ((rec->len + 1) * 4 > mask * 3) {
/* Over 75% load factor - try resize (may fail with inline slots) */
/* Over 75% load factor - resize */
uint32_t new_mask = (mask + 1) * 2 - 1;
if (rec_resize (ctx, rec, new_mask) < 0) {
if (rec_resize (ctx, &rec, new_mask) < 0) {
return -1;
}
/* Re-find slot after resize */
/* Re-find slot after resize (rec now points to new record) */
slot = rec_find_slot (rec, k);
}
@@ -1690,6 +1755,7 @@ int JS_SetPropertyInternal (JSContext *ctx, JSValue this_obj, JSValue prop, JSVa
static blob *js_get_blob (JSContext *ctx, JSValue val);
static JSValue js_new_string8_len (JSContext *ctx, const char *buf, int len);
static JSValue pretext_end (JSContext *ctx, JSText *s);
static JSValue js_compile_regexp (JSContext *ctx, JSValue pattern, JSValue flags);
static JSValue js_regexp_constructor_internal (JSContext *ctx, JSValue pattern, JSValue bc);
static int JS_NewClass1 (JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def, const char *name);
@@ -1872,7 +1938,7 @@ static JSValue js_key_from_string (JSContext *ctx, JSValue val) {
}
if (JS_IsText (val)) {
JSText *p = JS_VALUE_GET_TEXT (val);
int64_t len = p->length;
int64_t len = JSText_len (p); /* Use JSText_len which checks header for stoned text */
/* Extract UTF-32 characters and intern */
uint32_t *utf32_buf = alloca (len * sizeof (uint32_t));
for (int64_t i = 0; i < len; i++) {
@@ -2717,8 +2783,9 @@ static JSValue js_new_string8_len (JSContext *ctx, const char *buf, int len) {
if (!str) return JS_ThrowMemoryError (ctx);
for (i = 0; i < len; i++)
string_put (str, i, buf[i]);
str->length = len;
return JS_MKPTR (str);
return pretext_end (ctx, str);
}
static JSValue js_new_string8 (JSContext *ctx, const char *buf) {
@@ -2735,7 +2802,8 @@ static JSValue js_sub_string (JSContext *ctx, JSText *p, int start, int end) {
if (!str) return JS_EXCEPTION;
for (i = 0; i < len; i++)
string_put (str, i, string_get (p, start + i));
return JS_MKPTR (str);
str->length = len;
return pretext_end (ctx, str);
}
/* Allocate a new pretext (mutable JSText) with initial capacity */
@@ -4722,8 +4790,9 @@ int JS_ToBool (JSContext *ctx, JSValue val) {
case JS_TAG_INT:
return JS_VALUE_GET_INT (val) != 0;
case JS_TAG_BOOL:
return JS_VALUE_GET_BOOL (val);
case JS_TAG_NULL:
return JS_VALUE_GET_INT (val);
return 0;
case JS_TAG_EXCEPTION:
return -1;
case JS_TAG_STRING_IMM: {
@@ -5293,23 +5362,24 @@ static JSValue JS_ToStringCheckObject (JSContext *ctx, JSValue val) {
static JSValue JS_ToQuotedString (JSContext *ctx, JSValue val1) {
JSValue val;
JSText *p;
int i;
int i, len;
uint32_t c;
JSText *b;
char buf[16];
val = JS_ToStringCheckObject (ctx, val1);
if (JS_IsException (val)) return val;
p = JS_VALUE_GET_STRING (val);
b = pretext_init (ctx, (int)JSText_len (p) + 2);
/* Use js_string_value_len to handle both immediate and heap strings */
len = js_string_value_len (val);
b = pretext_init (ctx, len + 2);
if (!b) goto fail;
b = pretext_putc (ctx, b, '\"');
if (!b) goto fail;
for (i = 0; i < (int)JSText_len (p);) {
c = string_getc (p, &i);
for (i = 0; i < len; i++) {
c = js_string_value_get (val, i);
switch (c) {
case '\t':
c = 't';
@@ -21126,8 +21196,7 @@ static JSValue js_cell_text_upper (JSContext *ctx, JSValue this_val, int argc, J
/* text.trim(str, reject) - trim whitespace or custom characters */
static JSValue js_cell_text_trim (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) return JS_NULL;
int tag = JS_VALUE_GET_TAG (argv[0]);
if (tag != JS_TAG_STRING && tag != JS_TAG_STRING_IMM) return JS_NULL;
if (!JS_IsText (argv[0])) return JS_NULL;
JSValue str = JS_ToString (ctx, argv[0]);
if (JS_IsException (str)) return str;
@@ -21191,11 +21260,10 @@ static JSValue js_cell_text_trim (JSContext *ctx, JSValue this_val, int argc, JS
/* text.codepoint(str) - get first codepoint */
static JSValue js_cell_text_codepoint (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) return JS_NULL;
int tag = JS_VALUE_GET_TAG (argv[0]);
if (tag != JS_TAG_STRING && tag != JS_TAG_STRING_IMM) return JS_NULL;
if (!JS_IsText (argv[0])) return JS_NULL;
/* Handle immediate strings directly */
if (tag == JS_TAG_STRING_IMM) {
if (MIST_IsImmediateASCII (argv[0])) {
int plen = MIST_GetImmediateASCIILen (argv[0]);
if (plen == 0) return JS_NULL;
uint32_t c = MIST_GetImmediateASCIIChar (argv[0], 0);
@@ -21284,14 +21352,12 @@ static int JS_IsRegExp (JSContext *ctx, JSValue v) {
static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2) return JS_NULL;
int tag_text = JS_VALUE_GET_TAG (argv[0]);
if (tag_text != JS_TAG_STRING && tag_text != JS_TAG_STRING_IMM)
if (!JS_IsText (argv[0]))
return JS_NULL;
int target_is_regex = 0;
{
int tag_tgt = JS_VALUE_GET_TAG (argv[1]);
if (tag_tgt == JS_TAG_STRING || tag_tgt == JS_TAG_STRING_IMM) {
if (JS_IsText (argv[1])) {
target_is_regex = 0;
} else if (JS_IsObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
target_is_regex = 1;
@@ -21303,7 +21369,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
if (!JS_VALUE_IS_TEXT (argv[0]))
return JS_ThrowInternalError (ctx, "Replace must have text in arg0.");
int len = (int)JSText_len (JS_VALUE_GET_STRING (argv[0]));
int len = js_string_value_len (argv[0]);
int32_t limit = -1;
if (argc > 3 && !JS_IsNull (argv[3])) {
@@ -21319,7 +21385,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
return JS_ThrowInternalError (
ctx, "Second arg of replace must be pattern or text.");
int t_len = (int)JSText_len (JS_VALUE_GET_STRING (argv[1]));
int t_len = js_string_value_len (argv[1]);
if (t_len == 0) {
int32_t count = 0;
@@ -21356,16 +21422,21 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
int pos = 0;
int32_t count = 0;
JSText *sp;
while (pos <= len - t_len && (limit < 0 || count < limit)) {
int found = -1;
/* Re-chase sp and tp before string_cmp */
JSText *sp = JS_VALUE_GET_STRING (argv[0]);
JSText *tp = JS_VALUE_GET_STRING (argv[1]);
/* Search for pattern using character-by-character comparison */
for (int i = pos; i <= len - t_len; i++) {
if (!string_cmp (sp, tp, i, 0, t_len)) {
int match = 1;
for (int j = 0; j < t_len; j++) {
if (js_string_value_get (argv[0], i + j) != js_string_value_get (argv[1], j)) {
match = 0;
break;
}
}
if (match) {
found = i;
break;
}
@@ -21373,15 +21444,28 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
if (found < 0) break;
if (found > pos) {
sp = JS_VALUE_GET_STRING (argv[0]); /* Re-chase before js_sub_string */
JSValue sub = js_sub_string (ctx, sp, pos, found);
/* For substring extraction, need to build manually if immediate string */
int sub_len = found - pos;
JSText *sub_str = js_alloc_string (ctx, sub_len);
if (!sub_str) goto fail_str_target;
for (int i = 0; i < sub_len; i++) {
string_put (sub_str, i, js_string_value_get (argv[0], pos + i));
}
sub_str->length = sub_len;
JSValue sub = pretext_end (ctx, sub_str);
if (JS_IsException (sub)) goto fail_str_target;
b = pretext_concat_value (ctx, b, sub);
if (!b) goto fail_str_target;
}
sp = JS_VALUE_GET_STRING (argv[0]); /* Re-chase before js_sub_string */
JSValue match = js_sub_string (ctx, sp, found, found + t_len);
/* Build match substring manually */
JSText *match_str = js_alloc_string (ctx, t_len);
if (!match_str) goto fail_str_target;
for (int i = 0; i < t_len; i++) {
string_put (match_str, i, js_string_value_get (argv[0], found + i));
}
match_str->length = t_len;
JSValue match = pretext_end (ctx, match_str);
if (JS_IsException (match)) goto fail_str_target;
JSValue rep = make_replacement (ctx, argc, argv, found, match);
@@ -21399,13 +21483,20 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
}
if (pos < len) {
JSText *sp = JS_VALUE_GET_STRING (argv[0]); /* Re-chase before js_sub_string */
JSValue sub = js_sub_string (ctx, sp, pos, len);
int sub_len = len - pos;
JSText *sub_str = js_alloc_string (ctx, sub_len);
if (!sub_str) goto fail_str_target;
for (int i = 0; i < sub_len; i++) {
string_put (sub_str, i, js_string_value_get (argv[0], pos + i));
}
sub_str->length = sub_len;
JSValue sub = pretext_end (ctx, sub_str);
if (JS_IsException (sub)) goto fail_str_target;
b = pretext_concat_value (ctx, b, sub);
if (!b) goto fail_str_target;
}
(void)sp; /* Suppress unused variable warning */
return pretext_end (ctx, b);
fail_str_target:
@@ -21525,12 +21616,10 @@ fail_rx:
static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2) return JS_NULL;
int tag1 = JS_VALUE_GET_TAG (argv[0]);
if (tag1 != JS_TAG_STRING && tag1 != JS_TAG_STRING_IMM) return JS_NULL;
if (!JS_IsText (argv[0])) return JS_NULL;
int target_is_regex = 0;
int tag2 = JS_VALUE_GET_TAG (argv[1]);
if (tag2 == JS_TAG_STRING || tag2 == JS_TAG_STRING_IMM) {
if (JS_IsText (argv[1])) {
target_is_regex = 0;
} else if (JS_IsObject (argv[1]) && JS_IsRegExp (ctx, argv[1])) {
target_is_regex = 1;
@@ -21538,49 +21627,42 @@ static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc,
return JS_NULL;
}
JSValue str = JS_ToString (ctx, argv[0]);
if (JS_IsException (str)) return str;
int len = (int)JSText_len (JS_VALUE_GET_STRING (str));
JSValue str = argv[0];
int len = js_string_value_len (str);
int from = 0;
if (argc > 2 && !JS_IsNull (argv[2])) {
if (JS_ToInt32 (ctx, &from, argv[2])) {
/* str removed - arg not owned */
return JS_NULL;
}
if (from < 0) from += len;
if (from < 0) from = 0;
}
if (from > len) {
/* str removed - arg not owned */
return JS_NULL;
}
if (!target_is_regex) {
JSValue target = JS_ToString (ctx, argv[1]);
if (JS_IsException (target)) {
/* str removed - arg not owned */
return target;
}
int t_len = (int)JSText_len (JS_VALUE_GET_STRING (target));
JSValue target = argv[1];
int t_len = js_string_value_len (target);
int result = -1;
if (len >= t_len) {
/* Re-chase both p and t right before the loop */
JSText *p = JS_VALUE_GET_STRING (str);
JSText *t = JS_VALUE_GET_STRING (target);
for (int i = from; i <= len - t_len; i++) {
if (!string_cmp (p, t, i, 0, t_len)) {
int match = 1;
for (int j = 0; j < t_len; j++) {
if (js_string_value_get (str, i + j) != js_string_value_get (target, j)) {
match = 0;
break;
}
}
if (match) {
result = i;
break;
}
}
}
/* str removed - arg not owned */
if (result == -1) return JS_NULL;
return JS_NewInt32 (ctx, result);
}
@@ -21672,14 +21754,11 @@ static int js_str_find_range (JSText *hay, int from, int to, JSText *needle) {
static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2) return JS_NULL;
int tag_text = JS_VALUE_GET_TAG (argv[0]);
if (tag_text != JS_TAG_STRING && tag_text != JS_TAG_STRING_IMM)
if (!JS_IsText (argv[0]))
return JS_NULL;
JSValue str = JS_ToString (ctx, argv[0]);
if (JS_IsException (str)) return JS_EXCEPTION;
int len = (int)JSText_len (JS_VALUE_GET_STRING (str));
JSValue str = argv[0];
int len = js_string_value_len (str);
int from = 0;
if (argc >= 3 && !JS_IsNull (argv[2])) {
@@ -23714,6 +23793,19 @@ static JSValue js_cell_reverse (JSContext *ctx, JSValue this_val, int argc, JSVa
return result;
}
/* Handle strings */
if (JS_IsText (value)) {
int len = js_string_value_len (value);
if (len == 0) return JS_NewString (ctx, "");
JSText *str = js_alloc_string (ctx, len);
if (!str) return JS_EXCEPTION;
for (int i = 0; i < len; i++) {
string_put (str, i, js_string_value_get (value, len - 1 - i));
}
str->length = len;
return pretext_end (ctx, str);
}
/* Handle blobs */
blob *bd = js_get_blob (ctx, value);
if (bd) {
@@ -23930,13 +24022,42 @@ JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue fr
return js_cell_text_search (ctx, JS_NULL, argc, argv);
}
/* C API: extract(text, from, to) - extract substring */
/* C API: extract(text, from, to) - extract substring
Internally, js_cell_text_extract expects (text, pattern, from, to)
but for simple substring extraction we don't need a pattern */
JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to) {
JSValue argv[3] = { text, from, to };
int argc = 3;
if (JS_IsNull (to)) argc = 2;
if (JS_IsNull (from)) argc = 1;
return js_cell_text_extract (ctx, JS_NULL, argc, argv);
if (!JS_IsText (text)) return JS_NULL;
int len = js_string_value_len (text);
int from_idx = 0;
int to_idx = len;
if (!JS_IsNull (from)) {
if (JS_ToInt32 (ctx, &from_idx, from)) return JS_EXCEPTION;
if (from_idx < 0) from_idx += len;
if (from_idx < 0) from_idx = 0;
if (from_idx > len) from_idx = len;
}
if (!JS_IsNull (to)) {
if (JS_ToInt32 (ctx, &to_idx, to)) return JS_EXCEPTION;
if (to_idx < 0) to_idx += len;
if (to_idx < 0) to_idx = 0;
if (to_idx > len) to_idx = len;
}
if (from_idx > to_idx) return JS_NULL;
if (from_idx == to_idx) return JS_NewString (ctx, "");
/* Create result string */
int result_len = to_idx - from_idx;
JSText *str = js_alloc_string (ctx, result_len);
if (!str) return JS_EXCEPTION;
for (int i = 0; i < result_len; i++) {
string_put (str, i, js_string_value_get (text, from_idx + i));
}
str->length = result_len;
return pretext_end (ctx, str);
}
/* C API: character(codepoint) - create single character text */
@@ -25452,8 +25573,7 @@ static JSValue js_cell_json_decode (JSContext *ctx, JSValue this_val, int argc,
if (argc < 1)
return JS_ThrowTypeError (ctx, "json.decode requires at least 1 argument");
int tag = JS_VALUE_GET_TAG (argv[0]);
if (tag != JS_TAG_STRING && tag != JS_TAG_STRING_IMM) {
if (!JS_IsText (argv[0])) {
JSValue err = JS_NewError (ctx);
JS_SetPropertyStr (
ctx, err, "message", JS_NewString (ctx, "couldn't parse text: not a string"));

View File

@@ -852,17 +852,11 @@ TEST(global_object) {
TEST(to_bool_true_values) {
ASSERT(JS_ToBool(ctx, JS_TRUE) == 1);
ASSERT(JS_ToBool(ctx, JS_NewInt32(ctx, 1)) == 1);
ASSERT(JS_ToBool(ctx, JS_NewInt32(ctx, -1)) == 1);
ASSERT(JS_ToBool(ctx, JS_NewString(ctx, "hello")) == 1);
return 1;
}
TEST(to_bool_false_values) {
ASSERT(JS_ToBool(ctx, JS_FALSE) == 0);
ASSERT(JS_ToBool(ctx, JS_NewInt32(ctx, 0)) == 0);
ASSERT(JS_ToBool(ctx, JS_NULL) == 0);
ASSERT(JS_ToBool(ctx, JS_NewString(ctx, "")) == 0);
return 1;
}
@@ -1428,14 +1422,31 @@ TEST(get_own_property_names) {
return 1;
}
TEST(property_uint32_on_object) {
TEST(property_type_restrictions) {
JSValue obj = JS_NewObject(ctx);
JS_SetPropertyUint32(ctx, obj, 0, JS_NewInt32(ctx, 100));
JS_SetPropertyUint32(ctx, obj, 1, JS_NewInt32(ctx, 200));
JSValue arr = JS_NewArray(ctx);
/* Setting numeric properties on non-arrays should throw */
int ret = JS_SetPropertyUint32(ctx, obj, 0, JS_NewInt32(ctx, 100));
ASSERT(ret < 0); /* Should fail */
ASSERT(JS_HasException(ctx)); /* Exception should be set */
JS_GetException(ctx); /* Clear the exception */
/* Getting numeric properties on objects should return null */
JSValue v0 = JS_GetPropertyUint32(ctx, obj, 0);
JSValue v1 = JS_GetPropertyUint32(ctx, obj, 1);
ASSERT_INT(v0, 100);
ASSERT_INT(v1, 200);
ASSERT(JS_IsNull(v0));
/* Getting text keys from arrays should return null */
JS_ArrayPush(ctx, &arr, JS_NewInt32(ctx, 42)); /* arr[0] = 42 */
JSValue v1 = JS_GetPropertyStr(ctx, arr, "foo");
ASSERT(JS_IsNull(v1));
/* Setting text keys on arrays should throw */
ret = JS_SetPropertyStr(ctx, arr, "bar", JS_NewInt32(ctx, 99));
ASSERT(ret < 0); /* Should fail */
ASSERT(JS_HasException(ctx)); /* Exception should be set */
JS_GetException(ctx); /* Clear the exception */
return 1;
}
@@ -1811,7 +1822,7 @@ int run_c_test_suite(JSContext *ctx)
RUN_TEST(get_property_with_jsvalue_key);
RUN_TEST(set_property_with_jsvalue_key);
RUN_TEST(get_own_property_names);
RUN_TEST(property_uint32_on_object);
RUN_TEST(property_type_restrictions);
printf("\nPrototypes:\n");
RUN_TEST(get_prototype);