intrinsic arrays

This commit is contained in:
2026-01-22 08:30:41 -06:00
parent addb38da65
commit 45d82438ca
5 changed files with 240 additions and 166 deletions

6
fd.c
View File

@@ -502,10 +502,9 @@ JSC_SCALL(fd_readdir,
ret = JS_ThrowInternalError(js, "FindFirstFile failed for %s", path);
} else {
ret = JS_NewArray(js);
int i = 0;
do {
if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) continue;
JS_SetPropertyUint32(js, ret, i++, JS_NewString(js, ffd.cFileName));
JS_ArrayPush(js, ret,JS_NewString(js, ffd.cFileName));
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
}
@@ -515,10 +514,9 @@ JSC_SCALL(fd_readdir,
d = opendir(str);
if (d) {
ret = JS_NewArray(js);
int i = 0;
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) continue;
JS_SetPropertyUint32(js, ret, i++, JS_NewString(js, dir->d_name));
JS_ArrayPush(js, ret, JS_NewString(js, dir->d_name));
}
closedir(d);
} else {

View File

@@ -304,31 +304,4 @@ int uncaught_exception(JSContext *js, JSValue v)
JS_FreeValue(js, exp);
JS_FreeValue(js, v);
return 0;
exp = JS_GetException(js);
if (JS_IsNull(rt->on_exception)) {
const char *str = JS_ToCString(js, exp);
if (str) {
printf("Uncaught exception: %s\n", str);
JS_FreeCString(js, str);
}
JSValue stack = JS_GetPropertyStr(js, exp, "stack");
if (!JS_IsNull(stack)) {
const char *stack_str = JS_ToCString(js, stack);
if (stack_str) {
printf("Stack trace:\n%s\n", stack_str);
JS_FreeCString(js, stack_str);
}
}
JS_FreeValue(js, stack);
} else {
JSValue ret = JS_Call(js, rt->on_exception, JS_NULL, 1, &exp);
JS_FreeValue(js, ret);
}
JS_FreeValue(js, exp);
JS_FreeValue(js, v);
return 0;
}

View File

@@ -275,8 +275,7 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val,
case WOTA_ARR: {
long long c;
data_ptr = wota_read_array(&c, data_ptr);
JSValue arr = JS_NewArray(ctx);
JS_SetLength(ctx, arr, c);
JSValue arr = JS_NewArrayLen(ctx, c);
for (long long i = 0; i < c; i++) {
JSValue elem_val = JS_NULL;
JSAtom idx_atom = JS_NewAtomUInt32(ctx, (uint32_t)i);

View File

@@ -876,8 +876,6 @@ static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
static void js_dump_value_write(void *opaque, const char *buf, size_t len);
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic);
static void js_array_finalizer(JSRuntime *rt, JSValue val);
static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void free_array(JSRuntime *rt, JSArray *arr);
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
@@ -920,6 +918,12 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
static JSValue js_cell_push(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
static JSValue js_cell_pop(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
static JSValue js_cell_array_find(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
static JSProperty *add_property(JSContext *ctx,
JSObject *p, JSAtom prop, int prop_flags);
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
@@ -4751,7 +4755,7 @@ JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
}
/* Create an intrinsic array with specified capacity */
static JSValue JS_NewArrayLen(JSContext *ctx, uint32_t len)
JSValue JS_NewArrayLen(JSContext *ctx, uint32_t len)
{
JSRuntime *rt = ctx->rt;
JSArray *arr;
@@ -5093,27 +5097,6 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
}
}
static void js_array_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
int i;
for(i = 0; i < p->u.array.count; i++) {
JS_FreeValueRT(rt, p->u.array.u.values[i]);
}
js_free_rt(rt, p->u.array.u.values);
}
static void js_array_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
int i;
for(i = 0; i < p->u.array.count; i++) {
JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
}
}
/* Free intrinsic array (JS_TAG_ARRAY) */
static void free_array(JSRuntime *rt, JSArray *arr)
@@ -6698,6 +6681,18 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
return JS_NULL;
case JS_TAG_EXCEPTION:
return JS_EXCEPTION;
case JS_TAG_ARRAY:
{
JSArray *arr = JS_VALUE_GET_ARRAY(obj);
/* Only integer indexed access is allowed on arrays */
if (__JS_AtomIsTaggedInt(prop)) {
uint32_t idx = __JS_AtomToUInt32(prop);
if (idx < arr->len) {
return JS_DupValue(ctx, arr->values[idx]);
}
}
}
return JS_NULL;
case JS_TAG_STRING:
{
JSString *p1 = JS_VALUE_GET_STRING(obj);
@@ -7129,6 +7124,19 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
return atom;
}
static uint32_t js_string_get_length(JSValueConst val)
{
if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
JSString *p = JS_VALUE_GET_STRING(val);
return p->len;
} else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
JSStringRope *r = JS_VALUE_GET_PTR(val);
return r->len;
} else {
return 0;
}
}
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JSValue prop)
{
@@ -7138,37 +7146,38 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
int this_tag = JS_VALUE_GET_TAG(this_obj);
if (this_tag == JS_TAG_NULL) {
JS_FreeValue(js, prop);
JS_FreeValue(ctx, prop);
return JS_NULL;
}
if (this_tag == JS_TAG_ARRAY) {
JSArray *arr = JS_VALUE_GET_ARRAY(this_obj);
if (prop_tag == JS_TAG_INT) {
int idx = JS_VALUE_GET_INT(prop);
if (idx < 0 || idx >= JS_VALUE_GET_ARRAY(this_obj)->len) {
if (idx < 0 || (uint32_t)idx >= arr->len) {
return JS_NULL;
}
return JS_DupValue(ctx, JS_VALUE_GET_ARRAY(this_obj)->values[idx]);
return JS_DupValue(ctx, arr->values[idx]);
}
if (prop_tag == JS_TAG_FLOAT64) {
double d = JS_VALUE_GET_FLOAT64(prop);
if (d < 0 || d >= JS_VALUE_GET_ARRAY(this_obj)->len) {
uint32_t idx = (uint32_t)d;
if (d < 0 || d != (double)idx || idx >= arr->len) {
return JS_NULL;
}
return JS_DupValue(ctx, JS_VALUE_GET_ARRAY(this_obj)->values[(int)d]);
return JS_DupValue(ctx, arr->values[idx]);
}
return JS_EXCEPTION;
}
if (this_tag == JS_TAG_OBJECT) {
JS_FreeValue(ctx, prop);
return JS_ThrowTypeError(ctx, "array index must be a number");
}
if (this_tag == JS_TAG_OBJECT) {
/* Records only accept string or object keys */
if (prop_tag == JS_TAG_INT || prop_tag == JS_TAG_FLOAT64) {
return JS_EXCEPTION;
JS_FreeValue(ctx, prop);
return JS_ThrowTypeError(ctx, "record index must be text or record");
}
if (prop_tag == JS_TAG_STRING || prop_tag == JS_TAG_STRING_ROPE) {
@@ -7178,7 +7187,48 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JS_FreeAtom(ctx, atom);
return ret;
}
if (prop_tag == JS_TAG_OBJECT) {
/* Object key - handled via symbol lookup */
atom = JS_ValueToAtom(ctx, prop);
JS_FreeValue(ctx, prop);
if (atom == JS_ATOM_NULL)
return JS_EXCEPTION;
ret = JS_GetProperty(ctx, this_obj, atom);
JS_FreeAtom(ctx, atom);
return ret;
}
JS_FreeValue(ctx, prop);
return JS_ThrowTypeError(ctx, "record index must be text or record");
}
if (this_tag == JS_TAG_STRING || this_tag == JS_TAG_STRING_ROPE) {
if (prop_tag == JS_TAG_INT) {
int idx = JS_VALUE_GET_INT(prop);
uint32_t len = js_string_get_length(this_obj);
if (idx < 0 || (uint32_t)idx >= len) {
return JS_NULL;
}
return js_sub_string(ctx, JS_VALUE_GET_STRING(this_obj), idx, idx + 1);
}
if (prop_tag == JS_TAG_FLOAT64) {
double d = JS_VALUE_GET_FLOAT64(prop);
uint32_t idx = (uint32_t)d;
uint32_t len = js_string_get_length(this_obj);
if (d < 0 || d != (double)idx || idx >= len) {
return JS_NULL;
}
return js_sub_string(ctx, JS_VALUE_GET_STRING(this_obj), idx, idx + 1);
}
JS_FreeValue(ctx, prop);
return JS_ThrowTypeError(ctx, "string index must be a number");
}
JS_FreeValue(ctx, prop);
return JS_ThrowTypeError(ctx, "cannot read property of this value: %d", this_tag);
}
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
@@ -7405,6 +7455,23 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
tag = JS_VALUE_GET_TAG(this_obj);
if (unlikely(tag != JS_TAG_OBJECT)) {
if (tag == JS_TAG_ARRAY) {
/* Arrays only accept integer index via JS_SetPropertyValue */
JS_FreeValue(ctx, val);
if (__JS_AtomIsTaggedInt(prop)) {
uint32_t idx = __JS_AtomToUInt32(prop);
JSArray *arr = JS_VALUE_GET_ARRAY(this_obj);
if (idx < arr->len) {
/* This path shouldn't be used for arrays - use JS_SetPropertyValue */
JS_ThrowTypeError(ctx, "use JS_SetPropertyValue for array element access");
} else {
JS_ThrowRangeError(ctx, "array index out of bounds");
}
} else {
JS_ThrowTypeError(ctx, "array index must be a number");
}
return -1;
}
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
p = NULL;
p1 = JS_VALUE_GET_OBJ(obj);
@@ -7545,6 +7612,8 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JSValue prop, JSValue val, int flags)
{
JSAtom atom;
int ret;
uint32_t prop_tag = JS_VALUE_GET_TAG(prop);
int this_tag = JS_VALUE_GET_TAG(this_obj);
@@ -7577,12 +7646,13 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
double d = JS_VALUE_GET_FLOAT64(prop);
JSArray *arr = JS_VALUE_GET_ARRAY(this_obj);
JS_FreeValue(ctx, prop);
if (d < 0 || d >= arr->len || d != (double)(uint32_t)d) {
uint32_t idx = (uint32_t)d;
if (d < 0 || d != (double)idx || idx >= arr->len) {
JS_FreeValue(ctx, val);
JS_ThrowRangeError(ctx, "array index out of bounds");
return -1;
}
set_value(ctx, &arr->values[(uint32_t)d], val);
set_value(ctx, &arr->values[idx], val);
return TRUE;
}
JS_FreeValue(ctx, prop);
@@ -7592,7 +7662,9 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
if (this_tag == JS_TAG_OBJECT) {
if (prop_tag != JS_TAG_STRING && prop_tag != JS_TAG_STRING_ROPE && prop_tag != JS_TAG_OBJECT) {
JS_ThrowTypeError(ctx, "record index must be a text or record");
JS_FreeValue(ctx, prop);
JS_FreeValue(ctx, val);
JS_ThrowTypeError(ctx, "record index must be text or record");
return -1;
}
@@ -7606,6 +7678,12 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JS_FreeAtom(ctx, atom);
return ret;
}
/* Not an array or object */
JS_FreeValue(ctx, prop);
JS_FreeValue(ctx, val);
JS_ThrowTypeError(ctx, "cannot set property on this value");
return -1;
}
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
@@ -7848,6 +7926,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
return -1;
}
JS_ThrowTypeError(ctx, "intrinsic arrays only support numeric indices");
assert(0);
return -1;
}
@@ -7983,26 +8062,9 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
}
} else if (prs->flags & JS_PROP_LENGTH) {
if (flags & JS_PROP_HAS_VALUE) {
/* Note: no JS code is executable because
'val' is guaranted to be a Uint32 */
res = set_array_length(ctx, p, JS_DupValue(ctx, val),
flags);
} else {
res = TRUE;
}
/* still need to reset the writable flag if
needed. The JS_PROP_LENGTH is kept because the
Uint32 test is still done if the length
property is read-only. */
if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
JS_PROP_HAS_WRITABLE) {
prs = get_shape_prop(p->shape);
if (js_update_property_flags(ctx, p, &prs,
prs->flags & ~JS_PROP_WRITABLE))
return -1;
}
return res;
/* Object-based arrays removed - length property not supported */
JS_ThrowTypeError(ctx, "cannot set length property");
return -1;
} else {
if (flags & JS_PROP_HAS_VALUE) {
JS_FreeValue(ctx, pr->u.value);
@@ -8438,6 +8500,15 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
JSObject *p;
int res;
/* Arrays do not support property deletion */
if (JS_VALUE_GET_TAG(obj) == JS_TAG_ARRAY) {
if (flags & (JS_PROP_THROW | JS_PROP_THROW_STRICT)) {
JS_ThrowTypeError(ctx, "cannot delete array element");
return -1;
}
return FALSE;
}
obj1 = JS_ToObject(ctx, obj);
if (JS_IsException(obj1))
return -1;
@@ -8446,7 +8517,7 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
JS_FreeValue(ctx, obj1);
if (res != FALSE)
return res;
if (flags & JS_PROP_THROW ||
if (flags & JS_PROP_THROW ||
flags & JS_PROP_THROW_STRICT) {
JS_ThrowTypeError(ctx, "could not delete property");
return -1;
@@ -9467,19 +9538,6 @@ static void js_print_float64(JSPrintValueState *s, double d)
s->write_func(s->write_opaque, buf, len);
}
static uint32_t js_string_get_length(JSValueConst val)
{
if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
JSString *p = JS_VALUE_GET_STRING(val);
return p->len;
} else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
JSStringRope *r = JS_VALUE_GET_PTR(val);
return r->len;
} else {
return 0;
}
}
static void js_dump_char(JSPrintValueState *s, int c, int sep)
{
if (c == sep || c == '\\') {
@@ -9867,6 +9925,29 @@ static void js_print_value(JSPrintValueState *s, JSValueConst val)
js_putc(s, ')');
}
break;
case JS_TAG_ARRAY:
{
JSArray *arr = JS_VALUE_GET_ARRAY(val);
uint32_t i, count;
js_putc(s, '[');
count = min_uint32(arr->len, s->options.max_item_count);
for (i = 0; i < count; i++) {
if (i > 0)
js_puts(s, ", ");
if (s->level < s->options.max_depth) {
s->level++;
js_print_value(s, arr->values[i]);
s->level--;
} else {
js_puts(s, "...");
}
}
if (arr->len > count) {
js_printf(s, ", ... %u more", arr->len - count);
}
js_putc(s, ']');
}
break;
default:
js_printf(s, "[unknown tag %d]", tag);
break;
@@ -24460,6 +24541,18 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
if (JS_WriteFunctionTag(s, obj))
goto fail;
break;
case JS_TAG_ARRAY:
{
JSArray *arr = JS_VALUE_GET_ARRAY(obj);
uint32_t i;
bc_put_u8(s, BC_TAG_ARRAY);
bc_put_leb128(s, arr->len);
for (i = 0; i < arr->len; i++) {
if (JS_WriteObjectRec(s, arr->values[i]))
goto fail;
}
}
break;
case JS_TAG_OBJECT:
{
JSObject *p = JS_VALUE_GET_OBJ(obj);
@@ -25158,38 +25251,39 @@ static JSValue JS_ReadArray(BCReaderState *s, int tag)
JSValue obj;
uint32_t len, i;
JSValue val;
int ret, prop_flags;
BOOL is_template;
obj = JS_NewArray(ctx);
if (BC_add_object_ref(s, obj))
goto fail;
is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
if (bc_get_leb128(s, &len))
goto fail;
for(i = 0; i < len; i++) {
return JS_EXCEPTION;
/* Create intrinsic array with preallocated capacity */
obj = JS_NewArrayLen(ctx, len);
if (JS_IsException(obj))
return JS_EXCEPTION;
/* Note: intrinsic arrays don't support object reference tracking
for circular references - they're simpler value containers */
/* Read and set each element directly */
JSArray *arr = JS_VALUE_GET_ARRAY(obj);
for (i = 0; i < len; i++) {
val = JS_ReadObjectRec(s);
if (JS_IsException(val))
goto fail;
if (is_template)
prop_flags = JS_PROP_ENUMERABLE;
else
prop_flags = JS_PROP_C_W_E;
ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
prop_flags);
if (ret < 0)
goto fail;
/* Replace the null placeholder with the read value */
JS_FreeValue(ctx, arr->values[i]);
arr->values[i] = val;
}
/* Template objects have additional 'raw' property - not supported for intrinsic arrays */
if (is_template) {
val = JS_ReadObjectRec(s);
if (JS_IsException(val))
goto fail;
if (!JS_IsNull(val)) {
ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
if (ret < 0)
goto fail;
}
JS_PreventExtensions(ctx, obj);
/* Skip the raw property for intrinsic arrays */
JS_FreeValue(ctx, val);
}
return obj;
fail:
@@ -26570,32 +26664,8 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
goto fail;
}
t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift);
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0)
goto fail;
t = str_val, str_val = JS_NULL;
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0)
goto fail;
t = groups, groups = JS_NULL;
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
t, prop_flags) < 0) {
goto fail;
}
if (!JS_IsNull(indices)) {
t = indices_groups, indices_groups = JS_NULL;
if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
t, prop_flags) < 0) {
goto fail;
}
t = indices, indices = JS_NULL;
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
t, prop_flags) < 0) {
goto fail;
}
}
}
ret = obj;
obj = JS_NULL;
@@ -29188,8 +29258,6 @@ static JSValue js_cell_text_extract(JSContext *ctx, JSValueConst this_val,
}
JS_DefinePropertyValueUint32(ctx, arr, 0, match, JS_PROP_C_W_E);
JS_DefinePropertyValueStr(ctx, arr, "index", JS_NewInt32(ctx, pos), JS_PROP_C_W_E);
JS_DefinePropertyValueStr(ctx, arr, "input", JS_DupValue(ctx, str), JS_PROP_C_W_E);
/* str removed - arg not owned */
return arr;
@@ -29218,13 +29286,10 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
if (d < 0) return JS_NULL;
int64_t len = (int64_t)floor(d);
JSValue result = JS_NewArray(ctx);
JSValue result = JS_NewArrayLen(ctx, len);
if (JS_IsException(result)) return result;
if (argc < 2 || JS_IsNull(argv[1])) {
/* Just set length */
JS_SetPropertyStr(ctx, result, "length", JS_NewInt64(ctx, len > 100 ? 100 : len));
} else if (JS_IsFunction(ctx, argv[1])) {
if (JS_IsFunction(ctx, argv[1])) {
/* Fill with function results */
JSValueConst func = argv[1];
int arity = 0;
@@ -29264,8 +29329,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
if (argc < 2 || JS_IsNull(argv[1])) {
/* Copy */
JSValue result = JS_NewArray(ctx);
JSValue result = JS_NewArrayLen(ctx, len);
if (JS_IsException(result)) return result;
for (int64_t i = 0; i < len; i++) {
JSValue val = JS_GetPropertyInt64(ctx, arg, i);
@@ -29284,7 +29348,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
int reverse = argc > 2 && JS_ToBool(ctx, argv[2]);
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
JSValue result = JS_NewArray(ctx);
JSValue result = JS_NewArrayLen(ctx, len);
if (JS_IsException(result)) return result;
if (reverse) {
@@ -29340,7 +29404,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
if (js_get_length64(ctx, &len2, argv[1]))
return JS_EXCEPTION;
JSValue result = JS_NewArray(ctx);
JSValue result = JS_NewArrayLen(ctx, len + len2);
if (JS_IsException(result)) return result;
int64_t idx = 0;
@@ -29417,7 +29481,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
if (argc < 2 || JS_IsNull(argv[1])) {
/* Split into characters */
JSValue result = JS_NewArray(ctx);
JSValue result = JS_NewArrayLen(ctx, len);
if (JS_IsException(result)) {
return result;
}
@@ -29444,7 +29508,23 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
JSValue result = JS_NewArray(ctx);
size_t sep_len = strlen(sep);
/* Count the number of parts first */
int64_t count = 0;
if (sep_len == 0) {
count = len;
} else {
const char *pos = cstr;
const char *found;
count = 1;
while ((found = strstr(pos, sep)) != NULL) {
count++;
pos = found + sep_len;
}
}
JSValue result = JS_NewArrayLen(ctx, count);
if (JS_IsException(result)) {
JS_FreeCString(ctx, cstr);
JS_FreeCString(ctx, sep);
@@ -29452,7 +29532,6 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
}
int64_t idx = 0;
size_t sep_len = strlen(sep);
const char *pos = cstr;
const char *found;
@@ -31035,7 +31114,7 @@ static JSValue js_cell_reverse(JSContext *ctx, JSValueConst this_val,
* proto() function - get prototype of an object
* ============================================================================ */
static JSValue js_cell_pop(JSContext *ctx, JSValueConst this_val,
static JSValue js_cell_pop(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (argc < 1)
@@ -31050,11 +31129,33 @@ static JSValue js_cell_reverse(JSContext *ctx, JSValueConst this_val,
if (arr->len == 0)
return JS_NULL;
JSValue last = JS_DupValue(ctx, arr->values[arr->len-1]);
/* Transfer ownership: take value without dup, clear slot, decrement len */
JSValue last = arr->values[arr->len - 1];
arr->values[arr->len - 1] = JS_NULL;
arr->len--;
return last;
}
JSValue JS_ArrayPush(JSContext *ctx, JSValueConst obj, JSValueConst val)
{
if (!JS_IsArray(ctx, obj))
return JS_ThrowTypeError(ctx, "not an array");
JSValue stack[2];
stack[0] = obj;
stack[1] = val;
return js_cell_push(ctx, JS_NULL, 2, stack);
}
JSValue JS_ArrayPop(JSContext *ctx, JSValueConst obj)
{
if (!JS_IsArray(ctx, obj))
return JS_ThrowTypeError(ctx, "not an array");
return js_cell_pop(ctx, JS_NULL, 1, &obj);
}
static JSValue js_cell_push(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{

View File

@@ -669,9 +669,12 @@ JSValue JS_NewObject(JSContext *ctx);
JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val);
JSValue JS_NewArray(JSContext *ctx);
JSValue JS_NewArrayLen(JSContext *ctx, uint32_t len);
int JS_IsArray(JSContext *ctx, JSValueConst val);
int JS_GetLength(JSContext *ctx, JSValueConst obj, int64_t *pres);
int JS_SetLength(JSContext *ctx, JSValueConst obj, int64_t len);
JSValue JS_ArrayPush(JSContext *ctx, JSValueConst obj, JSValueConst val);
JSValue JS_ArrayPop(JSContext *ctx, JSValueConst obj);
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
JSAtom prop, JSValueConst receiver,