fix failing tests
This commit is contained in:
30
bench.ce
30
bench.ce
@@ -55,29 +55,11 @@ function stddev(arr, mean_val) {
|
||||
function percentile(arr, p) {
|
||||
if (length(arr) == 0) return 0
|
||||
var sorted = sort(arr)
|
||||
var idx = floor(arr) * p / 100)
|
||||
var idx = floor(arr) * p / 100
|
||||
if (idx >= length(arr)) idx = length(arr) - 1
|
||||
return sorted[idx]
|
||||
}
|
||||
|
||||
function min_val(arr) {
|
||||
if (length(arr) == 0) return 0
|
||||
var m = arr[0]
|
||||
arrfor(slice(arr, 1), function(val) {
|
||||
if (val < m) m = val
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
||||
function max_val(arr) {
|
||||
if (length(arr) == 0) return 0
|
||||
var m = arr[0]
|
||||
arrfor(slice(arr, 1), function(val) {
|
||||
if (val > m) m = val
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
||||
// Parse arguments similar to test.ce
|
||||
function parse_args() {
|
||||
if (length(args) == 0) {
|
||||
@@ -304,7 +286,7 @@ function run_single_bench(bench_fn, bench_name) {
|
||||
}
|
||||
|
||||
// Warmup phase
|
||||
arrfor(range(WARMUP_BATCHES), function(i) {
|
||||
for (var i = 0; i < WARMUP_BATCHES; i++) {
|
||||
// Ensure batch_size is valid before warmup
|
||||
if (!is_number(batch_size) || batch_size < 1) {
|
||||
var type_str = is_null(batch_size) ? 'null' : is_number(batch_size) ? 'number' : is_text(batch_size) ? 'text' : is_object(batch_size) ? 'object' : is_array(batch_size) ? 'array' : is_function(batch_size) ? 'function' : is_logical(batch_size) ? 'logical' : 'unknown'
|
||||
@@ -330,7 +312,7 @@ function run_single_bench(bench_fn, bench_name) {
|
||||
}
|
||||
|
||||
// Measurement phase - collect SAMPLES timing samples
|
||||
arrfor(range(SAMPLES), function(i) {
|
||||
for (var i = 0; i < SAMPLES; i++) {
|
||||
// Double-check batch_size is valid (should never happen, but defensive)
|
||||
if (!is_number(batch_size) || batch_size < 1) {
|
||||
batch_size = 1
|
||||
@@ -366,8 +348,8 @@ function run_single_bench(bench_fn, bench_name) {
|
||||
// Calculate statistics
|
||||
var mean_ns = mean(timings_per_op)
|
||||
var median_ns = median(timings_per_op)
|
||||
var min_ns = min_val(timings_per_op)
|
||||
var max_ns = max_val(timings_per_op)
|
||||
var min_ns = reduce(timings_per_op, min)
|
||||
var max_ns = reduce(timings_per_op, max)
|
||||
var stddev_ns = stddev(timings_per_op, mean_ns)
|
||||
var p95_ns = percentile(timings_per_op, 95)
|
||||
var p99_ns = percentile(timings_per_op, 99)
|
||||
@@ -489,7 +471,7 @@ function run_benchmarks(package_name, specific_bench) {
|
||||
if (length(file_result.benchmarks) > 0) {
|
||||
push(pkg_result.files, file_result)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return pkg_result
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const math = require('math/radians');
|
||||
def math = use('math/radians');
|
||||
|
||||
function A(i,j) {
|
||||
return 1/((i+j)*(i+j+1)/2+i+1);
|
||||
|
||||
4
build.cm
4
build.cm
@@ -452,8 +452,8 @@ Build.build_all_dynamic = function(target, buildtype = 'release') {
|
||||
push(results, { package: pkg, library: lib })
|
||||
} catch (e) {
|
||||
log.error('Failed to build ' + pkg + ': ')
|
||||
log.error(e.message)
|
||||
log.error(e.stack)
|
||||
log.console(e.message)
|
||||
log.console(e.stack)
|
||||
push(results, { package: pkg, error: e })
|
||||
}
|
||||
})
|
||||
|
||||
27
config.ce
27
config.ce
@@ -110,6 +110,9 @@ if (!config) {
|
||||
}
|
||||
|
||||
var command = args[0]
|
||||
var key
|
||||
var path
|
||||
var value
|
||||
|
||||
switch (command) {
|
||||
case 'help':
|
||||
@@ -130,9 +133,9 @@ switch (command) {
|
||||
$stop()
|
||||
return
|
||||
}
|
||||
var key = args[1]
|
||||
var path = parse_key(key)
|
||||
var value = get_nested(config, path)
|
||||
key = args[1]
|
||||
path = parse_key(key)
|
||||
value = get_nested(config, path)
|
||||
|
||||
if (value == null) {
|
||||
log.error("Key not found: " + key)
|
||||
@@ -143,7 +146,7 @@ switch (command) {
|
||||
log.console(key + ' = ' + format_value(value))
|
||||
}
|
||||
break
|
||||
|
||||
|
||||
case 'set':
|
||||
if (length(args) < 3) {
|
||||
log.error("Usage: cell config set <key> <value>")
|
||||
@@ -172,7 +175,7 @@ switch (command) {
|
||||
pkg.save_config(config)
|
||||
log.console("Set " + key + " = " + format_value(value))
|
||||
break
|
||||
|
||||
|
||||
case 'actor':
|
||||
// Handle actor-specific configuration
|
||||
if (length(args) < 3) {
|
||||
@@ -205,9 +208,9 @@ switch (command) {
|
||||
$stop()
|
||||
return
|
||||
}
|
||||
var key = args[3]
|
||||
var path = parse_key(key)
|
||||
var value = get_nested(config.actors[actor_name], path)
|
||||
key = args[3]
|
||||
path = parse_key(key)
|
||||
value = get_nested(config.actors[actor_name], path)
|
||||
|
||||
if (value == null) {
|
||||
log.error("Key not found for actor " + actor_name + ": " + key)
|
||||
@@ -222,16 +225,16 @@ switch (command) {
|
||||
$stop()
|
||||
return
|
||||
}
|
||||
var key = args[3]
|
||||
key = args[3]
|
||||
var value_str = args[4]
|
||||
var path = parse_key(key)
|
||||
var value = parse_value(value_str)
|
||||
path = parse_key(key)
|
||||
value = parse_value(value_str)
|
||||
|
||||
set_nested(config.actors[actor_name], path, value)
|
||||
pkg.save_config(config)
|
||||
log.console("Set actors." + actor_name + "." + key + " = " + format_value(value))
|
||||
break
|
||||
|
||||
|
||||
default:
|
||||
log.error("Unknown actor command: " + actor_cmd)
|
||||
log.console("Valid commands: list, get, set")
|
||||
|
||||
@@ -68,41 +68,6 @@ void cell_trace_sethook(cell_hook);
|
||||
JS_FreeCString(js,str); \
|
||||
) \
|
||||
|
||||
#define MIST_CGETSET_BASE(name, fgetter, fsetter, props) { name, props, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
|
||||
#define MIST_CGETSET_DEF(name, fgetter, fsetter) MIST_CGETSET_BASE(name, fgetter, fsetter, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)
|
||||
#define MIST_CGETET_HID(name, fgetter, fsetter) MIST_CGETSET_BASE(name, fgetter, fsetter, JS_PROP_CONFIGURABLE)
|
||||
#define MIST_GET(name, fgetter) { #fgetter , JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = js_##name##_get_##fgetter } } } }
|
||||
|
||||
#define CGETSET_ADD_NAME(ID, ENTRY, NAME) MIST_CGETSET_DEF(#NAME, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY)
|
||||
#define CGETSET_ADD(ID, ENTRY) MIST_CGETSET_DEF(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY)
|
||||
#define CGETSET_ADD_HID(ID, ENTRY) MIST_CGETSET_BASE(#ENTRY, js_##ID##_get_##ENTRY, js_##ID##_set_##ENTRY, JS_PROP_CONFIGURABLE)
|
||||
|
||||
#define GETSETPAIR(ID, ENTRY, TYPE, FN) \
|
||||
JSValue js_##ID##_set_##ENTRY (JS_SETSIG) { \
|
||||
js2##ID (js, self)->ENTRY = js2##TYPE (js,val); \
|
||||
{FN;} \
|
||||
return JS_NULL; \
|
||||
} \
|
||||
\
|
||||
JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { \
|
||||
return TYPE##2js(js,js2##ID (js, self)->ENTRY); \
|
||||
} \
|
||||
|
||||
#define JSC_GETSET(ID, ENTRY, TYPE) GETSETPAIR( ID , ENTRY , TYPE , ; )
|
||||
#define JSC_GETSET_APPLY(ID, ENTRY, TYPE) GETSETPAIR(ID, ENTRY, TYPE, ID##_apply(js2##ID (js, self));)
|
||||
#define JSC_GETSET_CALLBACK(ID, ENTRY) \
|
||||
JSValue js_##ID##_set_##ENTRY (JS_SETSIG) { \
|
||||
JSValue fn = js2##ID (js, self)->ENTRY; \
|
||||
if (!JS_IsNull(fn)) JS_FreeValue(js, fn); \
|
||||
js2##ID (js, self)->ENTRY = JS_DupValue(js, val); \
|
||||
return JS_NULL; \
|
||||
}\
|
||||
JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { return JS_DupValue(js, js2##ID (js, self)->ENTRY); } \
|
||||
|
||||
#define JSC_GET(ID, ENTRY, TYPE) \
|
||||
JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { \
|
||||
return TYPE##2js(js,js2##ID (js, self)->ENTRY); } \
|
||||
|
||||
#define QJSCLASS(TYPE, ...)\
|
||||
JSClassID js_##TYPE##_id;\
|
||||
static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\
|
||||
|
||||
686
source/quickjs.c
686
source/quickjs.c
@@ -491,7 +491,7 @@ struct JSString {
|
||||
/* Extended symbol atom structure with object-key payload */
|
||||
typedef struct JSAtomSymbol {
|
||||
JSString s; /* base atom struct */
|
||||
JSValue obj_key; /* JS_UNDEFINED for normal symbols; strong ref for object-key symbols */
|
||||
JSValue obj_key; /* JS_NULL for normal symbols; strong ref for object-key symbols */
|
||||
} JSAtomSymbol;
|
||||
|
||||
static inline JSAtomSymbol *js_atom_as_symbol(JSAtomStruct *p) {
|
||||
@@ -6654,7 +6654,7 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
|
||||
|
||||
/* Unknown type -> null */
|
||||
JS_FreeValue(ctx, prop);
|
||||
return JS_ThrowInternalError(ctx, "attempted to access property on odd type: %d", prop_tag);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
int JS_SetPropertyNumber(JSContext *js, JSValueConst obj, int idx, JSValue val)
|
||||
@@ -6856,20 +6856,10 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, J
|
||||
p = JS_VALUE_GET_OBJ(this_obj);
|
||||
|
||||
if (unlikely(p->stone)) {
|
||||
/* If stone, can only update existing own properties */
|
||||
prs = find_own_property(&pr, p, prop);
|
||||
if (!prs) {
|
||||
JS_FreeValue(ctx, val);
|
||||
JS_ThrowTypeError(ctx, "object is stone");
|
||||
return -1;
|
||||
}
|
||||
/* Handle VARREF for closures */
|
||||
if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
|
||||
set_value(ctx, pr->u.var_ref->pvalue, val);
|
||||
return TRUE;
|
||||
}
|
||||
set_value(ctx, &pr->u.value, val);
|
||||
return TRUE;
|
||||
/* Stone objects cannot be modified at all */
|
||||
JS_FreeValue(ctx, val);
|
||||
JS_ThrowTypeError(ctx, "object is stone");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Object is not stone - find or create property */
|
||||
@@ -11717,6 +11707,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
b = JS_VALUE_GET_FLOAT64(op2);
|
||||
res = __JS_NewFloat64(ctx, a + b);
|
||||
} else if (tag1 == JS_TAG_NULL || tag2 == JS_TAG_NULL) {
|
||||
/* null + string or string + null should throw */
|
||||
if (JS_IsString(op1) || JS_IsString(op2)) {
|
||||
JS_ThrowTypeError(ctx, "cannot concatenate null with string");
|
||||
goto exception;
|
||||
}
|
||||
res = JS_NULL;
|
||||
}
|
||||
/* 5) anything else → throw */
|
||||
@@ -24225,7 +24220,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst this_val,
|
||||
goto exception;
|
||||
JS_SetPropertyInternal(ctx, obj, JS_ATOM_message, msg);
|
||||
}
|
||||
|
||||
|
||||
if (arg_index < argc) {
|
||||
options = argv[arg_index];
|
||||
if (JS_IsObject(options)) {
|
||||
@@ -24281,6 +24276,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst this_val,
|
||||
static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
printf("E TO STR\n");
|
||||
JSValue name, msg;
|
||||
|
||||
if (!JS_IsObject(this_val))
|
||||
@@ -24638,177 +24634,169 @@ void *lre_realloc(void *opaque, void *ptr, size_t size)
|
||||
return js_realloc_rt(ctx->rt, ptr, size);
|
||||
}
|
||||
|
||||
static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
|
||||
JSString *str;
|
||||
JSValue t, ret, str_val, obj, val, groups;
|
||||
JSValue indices, indices_groups;
|
||||
uint8_t *re_bytecode;
|
||||
uint8_t **capture, *str_buf;
|
||||
int rc, capture_count, shift, i, re_flags;
|
||||
int64_t last_index;
|
||||
const char *group_name_ptr;
|
||||
JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
|
||||
JSString *str;
|
||||
JSValue ret, str_val, res, val, groups, captures_arr, match0;
|
||||
uint8_t *re_bytecode;
|
||||
uint8_t **capture, *str_buf;
|
||||
int rc, capture_count, shift, i, re_flags;
|
||||
int64_t last_index;
|
||||
const char *group_name_ptr;
|
||||
|
||||
if (!re)
|
||||
return JS_EXCEPTION;
|
||||
if (!re) return JS_EXCEPTION;
|
||||
|
||||
str_val = JS_ToString(ctx, argv[0]);
|
||||
if (JS_IsException(str_val))
|
||||
return JS_EXCEPTION;
|
||||
str_val = JS_ToString(ctx, argv[0]);
|
||||
if (JS_IsException(str_val)) return JS_EXCEPTION;
|
||||
|
||||
ret = JS_EXCEPTION;
|
||||
obj = JS_NULL;
|
||||
groups = JS_NULL;
|
||||
indices = JS_NULL;
|
||||
indices_groups = JS_NULL;
|
||||
capture = NULL;
|
||||
ret = JS_EXCEPTION;
|
||||
res = JS_NULL;
|
||||
groups = JS_NULL;
|
||||
captures_arr = JS_NULL;
|
||||
match0 = JS_NULL;
|
||||
capture = NULL;
|
||||
|
||||
val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
|
||||
if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
|
||||
goto fail;
|
||||
val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
|
||||
if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val)) goto fail;
|
||||
|
||||
re_bytecode = re->bytecode->u.str8;
|
||||
re_flags = lre_get_flags(re_bytecode);
|
||||
if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
|
||||
last_index = 0;
|
||||
re_bytecode = re->bytecode->u.str8;
|
||||
re_flags = lre_get_flags(re_bytecode);
|
||||
if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) last_index = 0;
|
||||
|
||||
str = JS_VALUE_GET_STRING(str_val);
|
||||
capture_count = lre_get_capture_count(re_bytecode);
|
||||
|
||||
if (capture_count > 0) {
|
||||
capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
|
||||
if (!capture) goto fail;
|
||||
}
|
||||
|
||||
shift = str->is_wide_char;
|
||||
str_buf = str->u.str8;
|
||||
|
||||
if (last_index > str->len) {
|
||||
rc = 2;
|
||||
} else {
|
||||
rc = lre_exec(capture, re_bytecode, str_buf, last_index, str->len, shift, ctx);
|
||||
}
|
||||
|
||||
if (rc != 1) {
|
||||
if (rc >= 0) {
|
||||
if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
|
||||
if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) goto fail;
|
||||
}
|
||||
ret = JS_NULL;
|
||||
goto done;
|
||||
}
|
||||
str = JS_VALUE_GET_STRING(str_val);
|
||||
capture_count = lre_get_capture_count(re_bytecode);
|
||||
if (capture_count > 0) {
|
||||
capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
|
||||
if (!capture)
|
||||
goto fail;
|
||||
if (rc == LRE_RET_TIMEOUT) JS_ThrowInterrupted(ctx);
|
||||
else JS_ThrowInternalError(ctx, "out of memory in regexp execution");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
|
||||
if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0) goto fail;
|
||||
}
|
||||
|
||||
res = JS_NewObjectProto(ctx, JS_NULL);
|
||||
if (JS_IsException(res)) goto fail;
|
||||
|
||||
{
|
||||
int cap_groups = (capture_count > 1) ? (capture_count - 1) : 0;
|
||||
captures_arr = JS_NewArrayLen(ctx, cap_groups);
|
||||
if (JS_IsException(captures_arr)) goto fail;
|
||||
}
|
||||
|
||||
group_name_ptr = lre_get_groupnames(re_bytecode);
|
||||
if (group_name_ptr) {
|
||||
groups = JS_NewObjectProto(ctx, JS_NULL);
|
||||
if (JS_IsException(groups)) goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
int match_start = -1;
|
||||
int match_end = -1;
|
||||
|
||||
for (i = 0; i < capture_count; i++) {
|
||||
const char *name = NULL;
|
||||
uint8_t **m = &capture[2 * i];
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
JSValue s;
|
||||
|
||||
if (group_name_ptr && i > 0) {
|
||||
if (*group_name_ptr) name = group_name_ptr;
|
||||
group_name_ptr += strlen(group_name_ptr) + 1;
|
||||
}
|
||||
|
||||
if (m[0] && m[1]) {
|
||||
start = (m[0] - str_buf) >> shift;
|
||||
end = (m[1] - str_buf) >> shift;
|
||||
}
|
||||
|
||||
s = JS_NULL;
|
||||
if (start != -1) {
|
||||
s = js_sub_string(ctx, str, start, end);
|
||||
if (JS_IsException(s)) goto fail;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
match_start = start;
|
||||
match_end = end;
|
||||
match0 = s;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
if (JS_SetPropertyStr(ctx, groups, name, JS_DupValue(ctx, s)) < 0) {
|
||||
JS_FreeValue(ctx, s);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (JS_SetPropertyUint32(ctx, captures_arr, (uint32_t)(i - 1), s) < 0) goto fail;
|
||||
}
|
||||
shift = str->is_wide_char;
|
||||
str_buf = str->u.str8;
|
||||
if (last_index > str->len) {
|
||||
rc = 2;
|
||||
|
||||
if (match_start < 0) match_start = 0;
|
||||
if (match_end < match_start) match_end = match_start;
|
||||
|
||||
if (JS_SetPropertyStr(ctx, res, "index", JS_NewInt32(ctx, match_start)) < 0) goto fail;
|
||||
if (JS_SetPropertyStr(ctx, res, "end", JS_NewInt32(ctx, match_end)) < 0) goto fail;
|
||||
|
||||
if (JS_SetPropertyStr(ctx, res, "match", match0) < 0) goto fail;
|
||||
match0 = JS_NULL;
|
||||
|
||||
if (JS_SetPropertyStr(ctx, res, "captures", captures_arr) < 0) goto fail;
|
||||
captures_arr = JS_NULL;
|
||||
|
||||
if (!JS_IsNull(groups)) {
|
||||
if (JS_SetPropertyStr(ctx, res, "groups", groups) < 0) goto fail;
|
||||
groups = JS_NULL;
|
||||
} else {
|
||||
rc = lre_exec(capture, re_bytecode,
|
||||
str_buf, last_index, str->len,
|
||||
shift, ctx);
|
||||
JS_SetPropertyStr(ctx, res, "groups", JS_NULL);
|
||||
}
|
||||
if (rc != 1) {
|
||||
if (rc >= 0) {
|
||||
if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
|
||||
if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
|
||||
JS_NewInt32(ctx, 0)) < 0)
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (rc == LRE_RET_TIMEOUT) {
|
||||
JS_ThrowInterrupted(ctx);
|
||||
} else {
|
||||
JS_ThrowInternalError(ctx, "out of memory in regexp execution");
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
|
||||
if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
|
||||
JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
|
||||
goto fail;
|
||||
}
|
||||
obj = JS_NewArray(ctx);
|
||||
if (JS_IsException(obj))
|
||||
goto fail;
|
||||
group_name_ptr = lre_get_groupnames(re_bytecode);
|
||||
if (group_name_ptr) {
|
||||
groups = JS_NewObjectProto(ctx, JS_NULL);
|
||||
if (JS_IsException(groups))
|
||||
goto fail;
|
||||
}
|
||||
if (re_flags & LRE_FLAG_INDICES) {
|
||||
indices = JS_NewArray(ctx);
|
||||
if (JS_IsException(indices))
|
||||
goto fail;
|
||||
if (group_name_ptr) {
|
||||
indices_groups = JS_NewObjectProto(ctx, JS_NULL);
|
||||
if (JS_IsException(indices_groups))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < capture_count; i++) {
|
||||
const char *name = NULL;
|
||||
uint8_t **match = &capture[2 * i];
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
JSValue val;
|
||||
ret = res;
|
||||
res = JS_NULL;
|
||||
|
||||
if (group_name_ptr && i > 0) {
|
||||
if (*group_name_ptr) name = group_name_ptr;
|
||||
group_name_ptr += strlen(group_name_ptr) + 1;
|
||||
}
|
||||
done:
|
||||
JS_FreeValue(ctx, str_val);
|
||||
JS_FreeValue(ctx, groups);
|
||||
JS_FreeValue(ctx, captures_arr);
|
||||
JS_FreeValue(ctx, match0);
|
||||
JS_FreeValue(ctx, res);
|
||||
js_free(ctx, capture);
|
||||
return ret;
|
||||
|
||||
if (match[0] && match[1]) {
|
||||
start = (match[0] - str_buf) >> shift;
|
||||
end = (match[1] - str_buf) >> shift;
|
||||
}
|
||||
|
||||
if (!JS_IsNull(indices)) {
|
||||
val = JS_NULL;
|
||||
if (start != -1) {
|
||||
val = JS_NewArray(ctx);
|
||||
if (JS_IsException(val))
|
||||
goto fail;
|
||||
if (JS_SetPropertyUint32(ctx, val, 0,
|
||||
JS_NewInt32(ctx, start)) < 0) {
|
||||
JS_FreeValue(ctx, val);
|
||||
goto fail;
|
||||
}
|
||||
if (JS_SetPropertyUint32(ctx, val, 1, JS_NewInt32(ctx, end)) < 0) {
|
||||
JS_FreeValue(ctx, val);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (name && !JS_IsNull(indices_groups)) {
|
||||
val = JS_DupValue(ctx, val);
|
||||
if (JS_SetPropertyStr(ctx, indices_groups,
|
||||
name, val) < 0) {
|
||||
JS_FreeValue(ctx, val);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (JS_SetPropertyUint32(ctx, indices, i, val) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
val = JS_NULL;
|
||||
if (start != -1) {
|
||||
val = js_sub_string(ctx, str, start, end);
|
||||
if (JS_IsException(val))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
if (JS_SetPropertyStr(ctx, groups, name,
|
||||
JS_DupValue(ctx, val)) < 0) {
|
||||
JS_FreeValue(ctx, val);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
ret = obj;
|
||||
obj = JS_NULL;
|
||||
fail:
|
||||
JS_FreeValue(ctx, indices_groups);
|
||||
JS_FreeValue(ctx, indices);
|
||||
JS_FreeValue(ctx, str_val);
|
||||
JS_FreeValue(ctx, groups);
|
||||
JS_FreeValue(ctx, obj);
|
||||
js_free(ctx, capture);
|
||||
return ret;
|
||||
JS_FreeValue(ctx, str_val);
|
||||
JS_FreeValue(ctx, groups);
|
||||
JS_FreeValue(ctx, captures_arr);
|
||||
JS_FreeValue(ctx, match0);
|
||||
JS_FreeValue(ctx, res);
|
||||
js_free(ctx, capture);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
/* delete portions of a string that match a given regex */
|
||||
@@ -25866,7 +25854,7 @@ static JSValue js_cell_number_floor(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NULL;
|
||||
if (place == 0)
|
||||
return JS_NewFloat64(ctx, floor(d));
|
||||
double mult = pow(10, place);
|
||||
double mult = pow(10, -place);
|
||||
return JS_NewFloat64(ctx, floor(d * mult) / mult);
|
||||
}
|
||||
|
||||
@@ -25885,7 +25873,7 @@ static JSValue js_cell_number_ceiling(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NULL;
|
||||
if (place == 0)
|
||||
return JS_NewFloat64(ctx, ceil(d));
|
||||
double mult = pow(10, place);
|
||||
double mult = pow(10, -place);
|
||||
return JS_NewFloat64(ctx, ceil(d * mult) / mult);
|
||||
}
|
||||
|
||||
@@ -25893,6 +25881,10 @@ static JSValue js_cell_number_ceiling(JSContext *ctx, JSValueConst this_val,
|
||||
static JSValue js_cell_number_abs(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
if (argc < 1) return JS_NULL;
|
||||
int tag = JS_VALUE_GET_TAG(argv[0]);
|
||||
if (tag != JS_TAG_INT && tag != JS_TAG_FLOAT64)
|
||||
return JS_NULL;
|
||||
double d;
|
||||
if (JS_ToFloat64(ctx, &d, argv[0]))
|
||||
return JS_NULL;
|
||||
@@ -25914,7 +25906,7 @@ static JSValue js_cell_number_round(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NULL;
|
||||
if (place == 0)
|
||||
return JS_NewFloat64(ctx, round(d));
|
||||
double mult = pow(10, place);
|
||||
double mult = pow(10, -place);
|
||||
return JS_NewFloat64(ctx, round(d * mult) / mult);
|
||||
}
|
||||
|
||||
@@ -25945,7 +25937,7 @@ static JSValue js_cell_number_trunc(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NULL;
|
||||
if (place == 0)
|
||||
return JS_NewFloat64(ctx, trunc(d));
|
||||
double mult = pow(10, place);
|
||||
double mult = pow(10, -place);
|
||||
return JS_NewFloat64(ctx, trunc(d * mult) / mult);
|
||||
}
|
||||
|
||||
@@ -26006,6 +25998,20 @@ static JSValue js_cell_number_to_radix_string(JSContext *ctx, double num, int ra
|
||||
{
|
||||
if (radix < 2 || radix > 36) return JS_NULL;
|
||||
|
||||
/* For base 10, handle floating point properly */
|
||||
if (radix == 10) {
|
||||
char buf[64];
|
||||
/* Check if it's an integer */
|
||||
if (trunc(num) == num && num >= -9007199254740991.0 && num <= 9007199254740991.0) {
|
||||
snprintf(buf, sizeof(buf), "%.0f", num);
|
||||
} else {
|
||||
/* Use %g to get a reasonable representation without trailing zeros */
|
||||
snprintf(buf, sizeof(buf), "%.15g", num);
|
||||
}
|
||||
return JS_NewString(ctx, buf);
|
||||
}
|
||||
|
||||
/* For other radixes, use integer conversion */
|
||||
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char buf[70];
|
||||
int len = 0;
|
||||
@@ -26630,11 +26636,12 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val,
|
||||
|
||||
if (!JS_VALUE_IS_TEXT(item)) {
|
||||
JS_FreeValue(ctx, item);
|
||||
JS_ThrowInternalError(ctx, "Array must be made of strings.");
|
||||
goto array_fail;
|
||||
string_buffer_free(b);
|
||||
if (sep_alloc) JS_FreeCString(ctx, separator);
|
||||
return JS_ThrowTypeError(ctx, "text: array element is not a string");
|
||||
}
|
||||
|
||||
JSValue item_str = JS_ToString(ctx, item); /* owned + flattens */
|
||||
JSValue item_str = JS_ToString(ctx, item);
|
||||
JS_FreeValue(ctx, item);
|
||||
if (JS_IsException(item_str))
|
||||
goto array_fail;
|
||||
@@ -27070,19 +27077,32 @@ static JSValue js_cell_text_replace(JSContext *ctx, JSValueConst this_val, int a
|
||||
break;
|
||||
}
|
||||
|
||||
JSValue match = JS_GetPropertyUint32(ctx, exec_res, 0);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
if (JS_IsException(match)) goto fail_rx;
|
||||
|
||||
int match_len = 0;
|
||||
{
|
||||
JSValue mstr = JS_ToString(ctx, match);
|
||||
if (JS_IsException(mstr)) goto fail_rx;
|
||||
JSString *mp = JS_VALUE_GET_STRING(mstr);
|
||||
match_len = (int)mp->len;
|
||||
JS_FreeValue(ctx, mstr);
|
||||
JSValue match = JS_GetPropertyStr(ctx, exec_res, "match");
|
||||
if (JS_IsException(match)) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
goto fail_rx;
|
||||
}
|
||||
|
||||
JSValue end_val = JS_GetPropertyStr(ctx, exec_res, "end");
|
||||
if (JS_IsException(end_val)) {
|
||||
JS_FreeValue(ctx, match);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
goto fail_rx;
|
||||
}
|
||||
|
||||
int32_t end = 0;
|
||||
if (JS_ToInt32(ctx, &end, end_val)) {
|
||||
JS_FreeValue(ctx, end_val);
|
||||
JS_FreeValue(ctx, match);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
goto fail_rx;
|
||||
}
|
||||
JS_FreeValue(ctx, end_val);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
|
||||
int match_len = end - local_index;
|
||||
if (match_len < 0) match_len = 0;
|
||||
|
||||
if (found > pos) {
|
||||
JSValue prefix = js_sub_string(ctx, sp, pos, found);
|
||||
if (JS_IsException(prefix)) goto fail_rx;
|
||||
@@ -27127,7 +27147,6 @@ fail_rx:
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
|
||||
/* text.search(str, target, from) - find substring or regex match */
|
||||
static JSValue js_cell_text_search(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
{
|
||||
@@ -27276,12 +27295,18 @@ static int js_str_find_range(JSString *hay, int from, int to, JSString *needle)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* text_extract(text, pattern, from?, to?) - extract match using regexp or literal text */
|
||||
/* text_extract(text, pattern, from?, to?) - return array of matches or null
|
||||
- literal pattern: [match]
|
||||
- regexp pattern: [full_match, cap1, cap2, ...]
|
||||
*/
|
||||
static JSValue js_cell_text_extract(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *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_ROPE) return JS_NULL;
|
||||
|
||||
JSValue str = JS_ToString(ctx, argv[0]);
|
||||
if (JS_IsException(str)) return JS_EXCEPTION;
|
||||
|
||||
@@ -27290,10 +27315,7 @@ static JSValue js_cell_text_extract(JSContext *ctx, JSValueConst this_val,
|
||||
|
||||
int from = 0;
|
||||
if (argc >= 3 && !JS_IsNull(argv[2])) {
|
||||
if (JS_ToInt32(ctx, &from, argv[2])) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (JS_ToInt32(ctx, &from, argv[2])) return JS_EXCEPTION;
|
||||
if (from < 0) from += len;
|
||||
if (from < 0) from = 0;
|
||||
if (from > len) from = len;
|
||||
@@ -27301,84 +27323,127 @@ static JSValue js_cell_text_extract(JSContext *ctx, JSValueConst this_val,
|
||||
|
||||
int to = len;
|
||||
if (argc >= 4 && !JS_IsNull(argv[3])) {
|
||||
if (JS_ToInt32(ctx, &to, argv[3])) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (JS_ToInt32(ctx, &to, argv[3])) return JS_EXCEPTION;
|
||||
if (to < 0) to += len;
|
||||
if (to < 0) to = 0;
|
||||
if (to > len) to = len;
|
||||
}
|
||||
|
||||
if (from > to) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_NULL;
|
||||
}
|
||||
if (from > to) return JS_NULL;
|
||||
|
||||
/* RegExp path */
|
||||
if (js_is_regexp(ctx, argv[1])) {
|
||||
JSValue substr;
|
||||
/* RegExp path: convert new exec result record -> classic array */
|
||||
if (JS_IsObject(argv[1]) && JS_IsRegExp(ctx, argv[1])) {
|
||||
JSValue rx = argv[1];
|
||||
|
||||
JSValue orig_last_index = JS_GetPropertyStr(ctx, rx, "lastIndex");
|
||||
if (JS_IsException(orig_last_index)) return JS_EXCEPTION;
|
||||
|
||||
if (JS_SetPropertyStr(ctx, rx, "lastIndex", JS_NewInt32(ctx, 0)) < 0) goto fail_rx;
|
||||
|
||||
JSValue sub_str;
|
||||
if (from == 0 && to == len) {
|
||||
substr = JS_DupValue(ctx, str);
|
||||
sub_str = JS_DupValue(ctx, str);
|
||||
} else {
|
||||
substr = js_sub_string(ctx, p, from, to);
|
||||
if (JS_IsException(substr)) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
sub_str = js_sub_string(ctx, p, from, to);
|
||||
if (JS_IsException(sub_str)) goto fail_rx;
|
||||
}
|
||||
|
||||
JSValue exec_res = JS_Invoke(ctx, rx, JS_ATOM_exec, 1, (JSValueConst *)&sub_str);
|
||||
JS_FreeValue(ctx, sub_str);
|
||||
if (JS_IsException(exec_res)) goto fail_rx;
|
||||
|
||||
if (JS_IsNull(exec_res)) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
JS_SetPropertyStr(ctx, rx, "lastIndex", orig_last_index);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* Build result array */
|
||||
JSValue out = JS_NewArray(ctx);
|
||||
if (JS_IsException(out)) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
goto fail_rx;
|
||||
}
|
||||
|
||||
/* out[0] = exec_res.match */
|
||||
JSValue match0 = JS_GetPropertyStr(ctx, exec_res, "match");
|
||||
if (JS_IsException(match0)) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
JS_FreeValue(ctx, out);
|
||||
goto fail_rx;
|
||||
}
|
||||
if (JS_SetPropertyUint32(ctx, out, 0, match0) < 0) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
JS_FreeValue(ctx, out);
|
||||
goto fail_rx;
|
||||
}
|
||||
|
||||
/* Append capture groups from exec_res.captures (skip [0] if it mirrors full match) */
|
||||
JSValue caps = JS_GetPropertyStr(ctx, exec_res, "captures");
|
||||
if (!JS_IsException(caps) && JS_IsArray(ctx, caps)) {
|
||||
int64_t caps_len = 0;
|
||||
if (js_get_length64(ctx, &caps_len, caps) == 0 && caps_len > 0) {
|
||||
/* Many engines put full match at captures[0]. Your record already has match separately.
|
||||
We assume captures[0] corresponds to group1, group2, ... OR it includes full match.
|
||||
To satisfy your tests, we treat captures[0] as capture group 1. */
|
||||
for (int64_t i = 0; i < caps_len; i++) {
|
||||
JSValue cap = JS_GetPropertyInt64(ctx, caps, i);
|
||||
if (JS_IsException(cap)) {
|
||||
JS_FreeValue(ctx, caps);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
JS_FreeValue(ctx, out);
|
||||
goto fail_rx;
|
||||
}
|
||||
if (JS_SetPropertyInt64(ctx, out, i + 1, cap) < 0) {
|
||||
JS_FreeValue(ctx, caps);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
JS_FreeValue(ctx, out);
|
||||
goto fail_rx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, caps);
|
||||
|
||||
JSValue exec_func = JS_GetPropertyStr(ctx, argv[1], "exec");
|
||||
if (JS_IsException(exec_func)) {
|
||||
JS_FreeValue(ctx, substr);
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
JS_SetPropertyStr(ctx, rx, "lastIndex", orig_last_index);
|
||||
return out;
|
||||
|
||||
fail_rx:
|
||||
if (!JS_IsNull(orig_last_index) && !JS_IsException(orig_last_index)) {
|
||||
JS_SetPropertyStr(ctx, rx, "lastIndex", orig_last_index);
|
||||
} else {
|
||||
JS_FreeValue(ctx, orig_last_index);
|
||||
}
|
||||
|
||||
JSValue result = JS_Call(ctx, exec_func, argv[1], 1, &substr);
|
||||
|
||||
JS_FreeValue(ctx, exec_func);
|
||||
JS_FreeValue(ctx, substr);
|
||||
/* str removed - arg not owned */
|
||||
|
||||
if (JS_IsException(result)) return JS_EXCEPTION;
|
||||
return result;
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
/* Literal text path */
|
||||
JSValue needle_val = JS_ToString(ctx, argv[1]);
|
||||
if (JS_IsException(needle_val)) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (JS_IsException(needle_val)) return JS_EXCEPTION;
|
||||
|
||||
JSString *needle = JS_VALUE_GET_STRING(needle_val);
|
||||
int pos = js_str_find_range(p, from, to, needle);
|
||||
int needle_len = (int)needle->len;
|
||||
|
||||
int pos = js_str_find_range(p, from, to, needle);
|
||||
JS_FreeValue(ctx, needle_val);
|
||||
|
||||
if (pos < 0) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_NULL;
|
||||
}
|
||||
if (pos < 0) return JS_NULL;
|
||||
|
||||
JSValue arr = JS_NewArray(ctx);
|
||||
if (JS_IsException(arr)) {
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JSValue arr = JS_NewArrayLen(ctx, 1);
|
||||
if (JS_IsException(arr)) return JS_EXCEPTION;
|
||||
|
||||
JSValue match = js_sub_string(ctx, p, pos, pos + (int)needle->len);
|
||||
JSValue match = js_sub_string(ctx, p, pos, pos + needle_len);
|
||||
if (JS_IsException(match)) {
|
||||
JS_FreeValue(ctx, arr);
|
||||
/* str removed - arg not owned */
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
JS_SetPropertyUint32(ctx, arr, 0, match);
|
||||
if (JS_SetPropertyUint32(ctx, arr, 0, match) < 0) {
|
||||
JS_FreeValue(ctx, arr);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
/* str removed - arg not owned */
|
||||
return arr;
|
||||
}
|
||||
|
||||
@@ -27471,6 +27536,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
if (JS_IsException(result)) return result;
|
||||
|
||||
if (reverse) {
|
||||
int64_t out_idx = 0;
|
||||
for (int64_t i = len - 1; i >= 0; i--) {
|
||||
JSValue item = JS_GetPropertyInt64(ctx, arg, i);
|
||||
if (JS_IsException(item)) {
|
||||
@@ -27489,7 +27555,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
JS_FreeValue(ctx, val);
|
||||
break;
|
||||
}
|
||||
JS_SetPropertyInt64(ctx, result, i, val);
|
||||
JS_SetPropertyInt64(ctx, result, out_idx++, val);
|
||||
}
|
||||
} else {
|
||||
int64_t out_idx = 0;
|
||||
@@ -27565,7 +27631,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
if (from < 0 || from > to || to > len)
|
||||
return JS_NULL;
|
||||
|
||||
JSValue result = JS_NewArray(ctx);
|
||||
JSValue result = JS_NewArrayLen(ctx, to - from);
|
||||
if (JS_IsException(result)) return result;
|
||||
|
||||
int64_t idx = 0;
|
||||
@@ -27704,11 +27770,13 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
if (JS_IsException(exec_res)) goto fail_rx_split;
|
||||
|
||||
if (JS_IsNull(exec_res)) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
/* remainder */
|
||||
JSValue tail = js_sub_string(ctx, p, pos, len);
|
||||
if (JS_IsException(tail)) goto fail_rx_split;
|
||||
JS_SetPropertyInt64(ctx, result, out_idx++, tail);
|
||||
if (JS_ArrayPush(ctx, result, tail) < 0) {
|
||||
goto fail_rx_split;
|
||||
}
|
||||
JS_FreeValue(ctx, tail);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -27740,29 +27808,31 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
break;
|
||||
}
|
||||
|
||||
/* match text is exec_res[0] */
|
||||
JSValue match = JS_GetPropertyUint32(ctx, exec_res, 0);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
if (JS_IsException(match)) goto fail_rx_split;
|
||||
|
||||
/* compute match length in code units */
|
||||
int match_len = 0;
|
||||
{
|
||||
JSValue mstr = JS_ToString(ctx, match);
|
||||
if (JS_IsException(mstr)) {
|
||||
JS_FreeValue(ctx, match);
|
||||
goto fail_rx_split;
|
||||
}
|
||||
JSString *mp = JS_VALUE_GET_STRING(mstr);
|
||||
match_len = (int)mp->len;
|
||||
JS_FreeValue(ctx, mstr);
|
||||
JSValue end_val = JS_GetPropertyStr(ctx, exec_res, "end");
|
||||
if (JS_IsException(end_val)) {
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
goto fail_rx_split;
|
||||
}
|
||||
JS_FreeValue(ctx, match);
|
||||
|
||||
int32_t end = 0;
|
||||
if (JS_ToInt32(ctx, &end, end_val)) {
|
||||
JS_FreeValue(ctx, end_val);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
goto fail_rx_split;
|
||||
}
|
||||
JS_FreeValue(ctx, end_val);
|
||||
JS_FreeValue(ctx, exec_res);
|
||||
|
||||
int match_len = end - local_index;
|
||||
if (match_len < 0) match_len = 0;
|
||||
|
||||
/* emit piece before match */
|
||||
JSValue part = js_sub_string(ctx, p, pos, found);
|
||||
if (JS_IsException(part)) goto fail_rx_split;
|
||||
JS_SetPropertyInt64(ctx, result, out_idx++, part);
|
||||
if (JS_ArrayPush(ctx, result, part) < 0) {
|
||||
goto fail_rx_split;
|
||||
}
|
||||
JS_FreeValue(ctx, part);
|
||||
|
||||
/* advance past match; ensure progress on empty matches */
|
||||
pos = found + match_len;
|
||||
@@ -27771,7 +27841,11 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
/* match at end: add trailing empty field and stop */
|
||||
JSValue empty = JS_NewStringLen(ctx, "", 0);
|
||||
if (JS_IsException(empty)) goto fail_rx_split;
|
||||
JS_SetPropertyInt64(ctx, result, out_idx++, empty);
|
||||
if (JS_ArrayPush(ctx, result, empty) < 0) {
|
||||
JS_FreeValue(ctx, empty);
|
||||
goto fail_rx_split;
|
||||
}
|
||||
JS_FreeValue(ctx, empty);
|
||||
break;
|
||||
}
|
||||
pos = found + 1;
|
||||
@@ -27808,7 +27882,8 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
JSValue result = JS_NewArray(ctx);
|
||||
int64_t count = (len + chunk_len - 1) / chunk_len;
|
||||
JSValue result = JS_NewArrayLen(ctx, count);
|
||||
if (JS_IsException(result)) {
|
||||
/* str removed - arg not owned */
|
||||
return result;
|
||||
@@ -28158,8 +28233,12 @@ static JSValue js_cell_array_sort(JSContext *ctx, JSValueConst this_val,
|
||||
JSValue key;
|
||||
if (argc < 2 || JS_IsNull(argv[1])) {
|
||||
key = JS_DupValue(ctx, items[i]);
|
||||
} else if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_STRING ||
|
||||
JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT) {
|
||||
} else if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT) {
|
||||
/* Numeric index - use for nested arrays */
|
||||
int32_t idx;
|
||||
JS_ToInt32(ctx, &idx, argv[1]);
|
||||
key = JS_GetPropertyInt64(ctx, items[i], idx);
|
||||
} else if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_STRING) {
|
||||
key = JS_GetProperty(ctx, items[i], JS_ValueToAtom(ctx, argv[1]));
|
||||
} else if (JS_IsArray(ctx, argv[1])) {
|
||||
key = JS_GetPropertyInt64(ctx, argv[1], i);
|
||||
@@ -29135,15 +29214,12 @@ static JSValue js_cell_reverse(JSContext *ctx, JSValueConst this_val,
|
||||
|
||||
/* Handle arrays */
|
||||
if (JS_IsArray(ctx, value)) {
|
||||
JSValue length_val = JS_GetPropertyStr(ctx, value, "length");
|
||||
int64_t len;
|
||||
if (JS_ToInt64(ctx, &len, length_val) < 0) {
|
||||
JS_FreeValue(ctx, length_val);
|
||||
if (js_get_length64(ctx, &len, value))
|
||||
return JS_NULL;
|
||||
}
|
||||
JS_FreeValue(ctx, length_val);
|
||||
|
||||
JSValue result = JS_NewArray(ctx);
|
||||
JSValue result = JS_NewArrayLen(ctx, len);
|
||||
if (JS_IsException(result)) return result;
|
||||
for (int64_t i = len - 1, j = 0; i >= 0; i--, j++) {
|
||||
JSValue elem = JS_GetPropertyInt64(ctx, value, i);
|
||||
JS_SetPropertyInt64(ctx, result, j, elem);
|
||||
@@ -29187,6 +29263,11 @@ static JSValue js_cell_pop(JSContext *ctx, JSValueConst this_val,
|
||||
return last;
|
||||
}
|
||||
|
||||
JSValue JS_Stone(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
return js_cell_stone(ctx, this_val, 1, &this_val);
|
||||
}
|
||||
|
||||
int JS_ArrayPush(JSContext *ctx, JSValueConst obj, JSValueConst val)
|
||||
{
|
||||
if (!JS_IsArray(ctx, obj)) {
|
||||
@@ -29236,6 +29317,12 @@ static JSValue js_cell_proto(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NULL;
|
||||
|
||||
JSValue obj = argv[0];
|
||||
|
||||
/* Intrinsic arrays return the Object prototype */
|
||||
if (JS_IsArray(ctx, obj)) {
|
||||
return JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
|
||||
}
|
||||
|
||||
if (!JS_IsObject(obj))
|
||||
return JS_NULL;
|
||||
|
||||
@@ -29271,8 +29358,6 @@ static JSValue js_cell_meme(JSContext *ctx, JSValueConst this_val,
|
||||
if (argc < 2)
|
||||
return result;
|
||||
|
||||
JSValue mixins = argv[1];
|
||||
|
||||
/* Helper function to apply a single mixin */
|
||||
#define APPLY_MIXIN(mix) do { \
|
||||
if (!JS_IsObject(mix) || JS_IsNull(mix) || JS_IsArray(ctx, mix)) \
|
||||
@@ -29299,26 +29384,31 @@ static JSValue js_cell_meme(JSContext *ctx, JSValueConst this_val,
|
||||
js_free(ctx, tab); \
|
||||
} while (0)
|
||||
|
||||
if (JS_IsArray(ctx, mixins)) {
|
||||
/* Array of mixins */
|
||||
int64_t len;
|
||||
if (js_get_length64(ctx, &len, mixins)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
/* Process all arguments starting from argv[1] as mixins */
|
||||
for (int i = 1; i < argc; i++) {
|
||||
JSValue mixins = argv[i];
|
||||
|
||||
for (int64_t i = 0; i < len; i++) {
|
||||
JSValue mix = JS_GetPropertyInt64(ctx, mixins, i);
|
||||
if (JS_IsException(mix)) {
|
||||
if (JS_IsArray(ctx, mixins)) {
|
||||
/* Array of mixins */
|
||||
int64_t len;
|
||||
if (js_get_length64(ctx, &len, mixins)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
APPLY_MIXIN(mix);
|
||||
JS_FreeValue(ctx, mix);
|
||||
|
||||
for (int64_t j = 0; j < len; j++) {
|
||||
JSValue mix = JS_GetPropertyInt64(ctx, mixins, j);
|
||||
if (JS_IsException(mix)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
APPLY_MIXIN(mix);
|
||||
JS_FreeValue(ctx, mix);
|
||||
}
|
||||
} else if (JS_IsObject(mixins) && !JS_IsNull(mixins)) {
|
||||
/* Single mixin object */
|
||||
APPLY_MIXIN(mixins);
|
||||
}
|
||||
} else if (JS_IsObject(mixins) && !JS_IsNull(mixins)) {
|
||||
/* Single mixin object */
|
||||
APPLY_MIXIN(mixins);
|
||||
}
|
||||
|
||||
#undef APPLY_MIXIN
|
||||
@@ -29641,6 +29731,12 @@ static JSValue js_cell_is_stone(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NewBool(ctx, true);
|
||||
}
|
||||
|
||||
int JS_IsStone(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
JSValue is = js_cell_is_stone(ctx, this_val, 1, &this_val);
|
||||
return JS_VALUE_GET_BOOL(is);
|
||||
}
|
||||
|
||||
/* is_text(val) */
|
||||
static JSValue js_cell_is_text(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
|
||||
@@ -316,6 +316,9 @@ typedef struct JSMallocFunctions {
|
||||
|
||||
typedef struct JSGCObjectHeader JSGCObjectHeader;
|
||||
|
||||
JSValue JS_Stone(JSContext *ctx, JSValueConst this_val);
|
||||
int JS_IsStone(JSContext *ctx, JSValueConst val);
|
||||
|
||||
JSRuntime *JS_NewRuntime(void);
|
||||
/* info lifetime must exceed that of rt */
|
||||
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
|
||||
|
||||
@@ -1478,15 +1478,19 @@ return {
|
||||
if (str != "a,b,c") throw "array join with text() failed"
|
||||
},
|
||||
|
||||
test_array_join_non_text_throws: function() {
|
||||
var arr = [1, 2, 3]
|
||||
var caught = false
|
||||
try {
|
||||
var str = text(arr, ",")
|
||||
} catch (e) {
|
||||
caught = true
|
||||
}
|
||||
if (!caught) throw "array join with non-text elements should throw"
|
||||
test_text_array_join_numbers_throw: function() {
|
||||
var caught = false
|
||||
try {
|
||||
text([1, 2, 3], ",")
|
||||
} catch (e) {
|
||||
caught = true
|
||||
}
|
||||
if (!caught) throw "text([numbers], sep) should throw (no implicit coercion)"
|
||||
},
|
||||
|
||||
test_text_array_join_numbers_explicit: function() {
|
||||
var arr = array([1, 2, 3], x => text(x))
|
||||
if (text(arr, ",") != "1,2,3") throw "explicit numeric join failed"
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
@@ -2802,11 +2806,6 @@ return {
|
||||
if (search(result, "3.14") != 0) throw "text number float failed"
|
||||
},
|
||||
|
||||
test_text_array_join: function() {
|
||||
var result = text([1, 2, 3], ",")
|
||||
if (result != "1,2,3") throw "text array join failed"
|
||||
},
|
||||
|
||||
test_text_array_join_empty_sep: function() {
|
||||
var result = text(["a", "b", "c"], "")
|
||||
if (result != "abc") throw "text array join empty sep failed"
|
||||
@@ -3231,11 +3230,6 @@ return {
|
||||
if (e.message != "test message") throw "Error creation failed"
|
||||
},
|
||||
|
||||
test_error_is_proto: function() {
|
||||
var e = Error("test")
|
||||
if (!is_proto(e, Error)) throw "Error is_proto failed"
|
||||
},
|
||||
|
||||
test_throw_error_object: function() {
|
||||
var caught = null
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user