fix failing tests

This commit is contained in:
2026-01-23 07:56:49 -06:00
parent 4cf0ce00de
commit e6838338fc
8 changed files with 431 additions and 388 deletions

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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 })
}
})

View File

@@ -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")

View File

@@ -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){\

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 {