diff --git a/source/quickjs.c b/source/quickjs.c index 7662fa9f..aea4f5f0 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -9514,38 +9514,11 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val)); break; case JS_TAG_OBJECT: - val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER); - if (JS_IsException(val)) - return JS_EXCEPTION; - goto redo; + JS_FreeValue(ctx, val); + return JS_ThrowTypeError(ctx, "cannot convert object to number"); case JS_TAG_STRING: case JS_TAG_STRING_ROPE: - { - const char *str; - const char *p; - size_t len; - - str = JS_ToCStringLen(ctx, &len, val); - JS_FreeValue(ctx, val); - if (!str) - return JS_EXCEPTION; - p = str; - p += skip_spaces(p); - if ((p - str) == len) { - ret = JS_NewInt32(ctx, 0); - } else { - int flags = ATOD_ACCEPT_BIN_OCT; - ret = js_atof(ctx, p, &p, 0, flags); - if (!JS_IsException(ret)) { - p += skip_spaces(p); - if ((p - str) != len) { - JS_FreeValue(ctx, ret); - ret = JS_NAN; - } - } - } - JS_FreeCString(ctx, str); - } + ret = JS_NewInt32(ctx,0); break; case JS_TAG_SYMBOL: JS_FreeValue(ctx, val); @@ -10045,16 +10018,7 @@ static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToP case JS_TAG_EXCEPTION: return JS_EXCEPTION; case JS_TAG_OBJECT: - { - JSValue val1, ret; - val1 = JS_ToPrimitive(ctx, val, HINT_STRING); - if (JS_IsException(val1)) - return val1; - ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey); - JS_FreeValue(ctx, val1); - return ret; - } - break; + return JS_AtomToString(ctx, JS_ATOM_true); case JS_TAG_FUNCTION_BYTECODE: return js_new_string8(ctx, "[function bytecode]"); case JS_TAG_SYMBOL: @@ -14510,47 +14474,57 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, break; } BREAK; +CASE(OP_template_concat): + { + int n, i; + JSValue out; + StringBuffer b_s, *b = &b_s; - CASE(OP_template_concat): - { - int n, i; - JSValue out; - StringBuffer b_s, *b = &b_s; + n = get_u16(pc); + pc += 2; - n = get_u16(pc); - pc += 2; + if (n <= 0) { + *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string); + BREAK; + } - if (n <= 0) { - *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string); - BREAK; - } + if (string_buffer_init(ctx, b, 64)) + goto exception; - if (string_buffer_init(ctx, b, 64)) - goto exception; + for (i = 0; i < n; i++) { + JSValue v = sp[i - n]; + JSValue s = js_cell_text(ctx, JS_NULL, 1, &v); + if (JS_IsException(s)) { + string_buffer_free(b); + for (int j = 0; j < n; j++) + JS_FreeValue(ctx, sp[j - n]); + sp -= n; + goto exception; + } + if (string_buffer_concat_value_free(b, s)) { + string_buffer_free(b); + for (int j = 0; j < n; j++) + JS_FreeValue(ctx, sp[j - n]); + sp -= n; + goto exception; + } + } - for (i = 0; i < n; i++) { - JSValue v = sp[i - n]; - JSValue s = js_cell_text(ctx, JS_NULL, 1, &v); - if (JS_IsException(s)) { - string_buffer_free(b); - goto exception; - } - if (string_buffer_concat_value_free(b, s)) { - string_buffer_free(b); - goto exception; - } - } + out = string_buffer_end(b); + if (JS_IsException(out)) { + for (int j = 0; j < n; j++) + JS_FreeValue(ctx, sp[j - n]); + sp -= n; + goto exception; + } - out = string_buffer_end(b); - if (JS_IsException(out)) - goto exception; + for (i = 0; i < n; i++) + JS_FreeValue(ctx, sp[i - n]); + sp -= n; + *sp++ = out; + } + BREAK; - for (i = 0; i < n; i++) - JS_FreeValue(ctx, sp[i - n]); - sp -= n; - *sp++ = out; - } - BREAK; CASE(OP_nop): BREAK; @@ -30985,47 +30959,58 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, if (argc < 1) return JS_NULL; - JSValue arg = argv[0]; + JSValueConst arg = argv[0]; int tag = JS_VALUE_GET_TAG(arg); - /* Handle string */ + /* Handle string / rope */ if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_ROPE) { - if (argc == 1) - return JS_DupValue(ctx, arg); + JSValue str = JS_ToString(ctx, arg); /* owned + flattens rope */ + if (JS_IsException(str)) + return JS_EXCEPTION; - JSString *p = JS_VALUE_GET_STRING(arg); + if (argc == 1) + return str; + + JSString *p = JS_VALUE_GET_STRING(str); int len = p->len; - /* text(string, from) - substring from index to end */ - /* text(string, from, to) - substring */ - if (argc >= 2 && (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT || - JS_VALUE_GET_TAG(argv[1]) == JS_TAG_FLOAT64)) { - int from; - if (JS_ToInt32(ctx, &from, argv[1])) - return JS_NULL; + if (argc >= 2) { + int tag1 = JS_VALUE_GET_TAG(argv[1]); + if (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64) { + int from, to; - /* Adjust negative index */ - if (from < 0) from += len; - if (from < 0) from = 0; - if (from > len) from = len; + if (JS_ToInt32(ctx, &from, argv[1])) { + JS_FreeValue(ctx, str); + return JS_EXCEPTION; + } - int to = len; /* Default: to end of string */ - if (argc >= 3) { - if (JS_ToInt32(ctx, &to, argv[2])) + if (from < 0) from += len; + if (from < 0) from = 0; + if (from > len) from = len; + + to = len; + if (argc >= 3) { + if (JS_ToInt32(ctx, &to, argv[2])) { + JS_FreeValue(ctx, str); + return JS_EXCEPTION; + } + if (to < 0) to += len; + if (to < 0) to = 0; + if (to > len) to = len; + } + + if (from > to) { + JS_FreeValue(ctx, str); return JS_NULL; + } - /* Adjust negative index */ - if (to < 0) to += len; - if (to < 0) to = 0; - if (to > len) to = len; + JSValue sub = js_sub_string(ctx, p, from, to); + JS_FreeValue(ctx, str); + return sub; } - - if (from > to) - return JS_NULL; - - return js_sub_string(ctx, p, from, to); } - return JS_DupValue(ctx, arg); + + return str; } /* Handle blob - convert to text representation */ @@ -31037,17 +31022,16 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, char format = '\0'; if (argc > 1) { const char *fmt = JS_ToCString(ctx, argv[1]); - if (fmt) { - format = fmt[0]; - JS_FreeCString(ctx, fmt); - } + if (!fmt) + return JS_EXCEPTION; + format = fmt[0]; + JS_FreeCString(ctx, fmt); } size_t byte_len = (bd->length + 7) / 8; const uint8_t *data = bd->data; if (format == 'h') { - /* Hexadecimal encoding */ static const char hex[] = "0123456789abcdef"; char *result = js_malloc(ctx, byte_len * 2 + 1); if (!result) return JS_EXCEPTION; @@ -31060,65 +31044,61 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, js_free(ctx, result); return ret; } else if (format == 'b') { - /* Binary encoding */ char *result = js_malloc(ctx, bd->length + 1); if (!result) return JS_EXCEPTION; - for (size_t i = 0; i < bd->length; i++) { + for (size_t i = 0; i < (size_t)bd->length; i++) { size_t byte_idx = i / 8; size_t bit_idx = i % 8; - result[i] = (data[byte_idx] & (1 << bit_idx)) ? '1' : '0'; + result[i] = (data[byte_idx] & (1u << bit_idx)) ? '1' : '0'; } result[bd->length] = '\0'; JSValue ret = JS_NewString(ctx, result); js_free(ctx, result); return ret; } else if (format == 'o') { - /* Octal encoding - 3 bits at a time */ - size_t octal_len = (bd->length + 2) / 3; + size_t octal_len = ((size_t)bd->length + 2) / 3; char *result = js_malloc(ctx, octal_len + 1); if (!result) return JS_EXCEPTION; for (size_t i = 0; i < octal_len; i++) { int val = 0; for (int j = 0; j < 3; j++) { - size_t bit_pos = i * 3 + j; - if (bit_pos < bd->length) { + size_t bit_pos = i * 3 + (size_t)j; + if (bit_pos < (size_t)bd->length) { size_t byte_idx = bit_pos / 8; size_t bit_idx = bit_pos % 8; - if (data[byte_idx] & (1 << bit_idx)) + if (data[byte_idx] & (1u << bit_idx)) val |= (1 << j); } } - result[i] = '0' + val; + result[i] = (char)('0' + val); } result[octal_len] = '\0'; JSValue ret = JS_NewString(ctx, result); js_free(ctx, result); return ret; } else if (format == 't') { - /* Base32 encoding (RFC 4648) */ static const char b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - size_t b32_len = (bd->length + 4) / 5; + size_t b32_len = ((size_t)bd->length + 4) / 5; char *result = js_malloc(ctx, b32_len + 1); if (!result) return JS_EXCEPTION; for (size_t i = 0; i < b32_len; i++) { int val = 0; for (int j = 0; j < 5; j++) { - size_t bit_pos = i * 5 + j; - if (bit_pos < bd->length) { + size_t bit_pos = i * 5 + (size_t)j; + if (bit_pos < (size_t)bd->length) { size_t byte_idx = bit_pos / 8; size_t bit_idx = bit_pos % 8; - if (data[byte_idx] & (1 << bit_idx)) + if (data[byte_idx] & (1u << bit_idx)) val |= (1 << j); } } - result[i] = b32[val]; + result[i] = b32[val & 31]; } result[b32_len] = '\0'; JSValue ret = JS_NewString(ctx, result); js_free(ctx, result); return ret; } else { - /* Default: UTF-8 (treat bytes as UTF-8 text) */ if (bd->length % 8 != 0) return JS_ThrowTypeError(ctx, "text: blob not byte-aligned for UTF-8"); return JS_NewStringLen(ctx, (const char *)data, byte_len); @@ -31132,13 +31112,12 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; if (argc > 1) { - /* Check for radix (number) or format (string) */ - if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT) { + int tag1 = JS_VALUE_GET_TAG(argv[1]); + if (tag1 == JS_TAG_INT) { int radix = JS_VALUE_GET_INT(argv[1]); return js_cell_number_to_radix_string(ctx, num, radix); } - if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_STRING || - JS_VALUE_GET_TAG(argv[1]) == JS_TAG_STRING_ROPE) { + if (tag1 == JS_TAG_STRING || tag1 == JS_TAG_STRING_ROPE) { const char *format = JS_ToCString(ctx, argv[1]); if (!format) return JS_EXCEPTION; JSValue result = js_cell_format_number(ctx, num, format); @@ -31157,10 +31136,12 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; const char *separator = ""; - if (argc > 1 && (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_STRING || - JS_VALUE_GET_TAG(argv[1]) == JS_TAG_STRING_ROPE)) { + BOOL sep_alloc = FALSE; + + if (argc > 1 && JS_VALUE_IS_TEXT(argv[1])) { separator = JS_ToCString(ctx, argv[1]); if (!separator) return JS_EXCEPTION; + sep_alloc = TRUE; } StringBuffer b_s, *b = &b_s; @@ -31168,30 +31149,36 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, for (int64_t i = 0; i < len; i++) { if (i > 0 && separator[0]) { - if (string_buffer_puts8(b, separator)) { - string_buffer_free(b); - if (argc > 1) JS_FreeCString(ctx, separator); - return JS_EXCEPTION; - } + if (string_buffer_puts8(b, separator)) + goto array_fail; } - JSValue item = JS_GetPropertyInt64(ctx, arg, i); - if (JS_IsException(item)) { - string_buffer_free(b); - if (argc > 1) JS_FreeCString(ctx, separator); - return JS_EXCEPTION; - } - if (!JS_VALUE_IS_TEXT(item)) - return JS_ThrowInternalError(ctx, "Array must be made of strings."); - if (string_buffer_concat_value_free(b, item)) { - string_buffer_free(b); - if (argc > 1) JS_FreeCString(ctx, separator); - return JS_EXCEPTION; + JSValue item = JS_GetPropertyInt64(ctx, arg, i); + if (JS_IsException(item)) + goto array_fail; + + if (!JS_VALUE_IS_TEXT(item)) { + JS_FreeValue(ctx, item); + JS_ThrowInternalError(ctx, "Array must be made of strings."); + goto array_fail; } + + JSValue item_str = JS_ToString(ctx, item); /* owned + flattens */ + JS_FreeValue(ctx, item); + if (JS_IsException(item_str)) + goto array_fail; + + if (string_buffer_concat_value_free(b, item_str)) + goto array_fail; } - if (argc > 1) JS_FreeCString(ctx, separator); + if (sep_alloc) JS_FreeCString(ctx, separator); return string_buffer_end(b); + +array_fail: + string_buffer_free(b); + if (sep_alloc) JS_FreeCString(ctx, separator); + return JS_EXCEPTION; } /* Handle function - return source or native stub */ @@ -31199,45 +31186,45 @@ static JSValue js_cell_text(JSContext *ctx, JSValueConst this_val, JSObject *p = JS_VALUE_GET_OBJ(arg); if (js_class_has_bytecode(p->class_id)) { JSFunctionBytecode *b = p->u.func.function_bytecode; - if (b->has_debug && b->debug.source) { + if (b->has_debug && b->debug.source) return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len); - } } - /* Native function - generate stub */ + const char *pref = "function "; const char *suff = "() {\n [native code]\n}"; - const char *name = NULL; + const char *name = ""; + const char *name_cstr = NULL; + JSObject *fp = JS_VALUE_GET_OBJ(arg); if (js_class_has_bytecode(fp->class_id)) { JSFunctionBytecode *fb = fp->u.func.function_bytecode; - name = JS_AtomToCString(ctx, fb->func_name); + name_cstr = JS_AtomToCString(ctx, fb->func_name); + if (name_cstr) + name = name_cstr; } - if (!name) name = ""; + size_t plen = strlen(pref); size_t nlen = strlen(name); size_t slen = strlen(suff); + char *result = js_malloc(ctx, plen + nlen + slen + 1); if (!result) { - if (name[0]) JS_FreeCString(ctx, name); + if (name_cstr) JS_FreeCString(ctx, name_cstr); return JS_EXCEPTION; } + memcpy(result, pref, plen); memcpy(result + plen, name, nlen); memcpy(result + plen + nlen, suff, slen + 1); + JSValue ret = JS_NewString(ctx, result); js_free(ctx, result); - if (name[0]) JS_FreeCString(ctx, name); + if (name_cstr) JS_FreeCString(ctx, name_cstr); return ret; } - /* Handle null */ -// if (JS_IsNull(arg)) -// return JS_NULL; - - if (JS_IsObject(arg)) - return JS_NewString(ctx, "[object]"); - - return JS_ThrowInternalError(ctx, "Could not convert to text. Tag is %d", JS_VALUE_GET_TAG(arg)); + return JS_ToString(ctx, arg); + return JS_ThrowInternalError(ctx, "Could not convert to text. Tag is %d", tag); } /* text.lower(str) - convert to lowercase */ diff --git a/test.ce b/test.ce index 7da7b400..ace122a1 100644 --- a/test.ce +++ b/test.ce @@ -324,7 +324,7 @@ function run_tests(package_name, specific_test) { } catch (e) { test_entry.status = "failed" test_entry.error = { - message: e.toString(), + message: e, stack: e.stack || "" } if (e.name) test_entry.error.name = e.name diff --git a/tests/suite.cm b/tests/suite.cm index c4f0e65a..715ea4ee 100644 --- a/tests/suite.cm +++ b/tests/suite.cm @@ -145,7 +145,7 @@ return { if (!caught) throw "string + boolean should throw" }, -/* test_null_plus_string_throws: function() { + test_null_plus_string_throws: function() { var caught = false try { var x = null + "hello" @@ -164,7 +164,7 @@ return { } if (!caught) throw "string + null should throw" }, -*/ + // ============================================================================ // COMPARISON OPERATORS // ============================================================================ @@ -1076,14 +1076,14 @@ return { if (parent.x != 10) throw "meme should not mutate parent" }, -/* test_meme_multiple_mixins: function() { + test_meme_multiple_mixins: function() { var parent = {a: 1} var mixin1 = {b: 2} var mixin2 = {c: 3} var child = meme(parent, mixin1, mixin2) if (child.a != 1 || child.b != 2 || child.c != 3) throw "meme multiple mixins failed" }, -*/ + // ============================================================================ // GLOBAL FUNCTIONS - PROTO // ============================================================================ @@ -1551,12 +1551,12 @@ return { if (search(str, "world") != 6) throw "string search failed" if (search(str, "xyz") != null) throw "string search not found failed" }, -/* + test_string_lastIndexOf: function() { var str = "hello hello" if (search(str, "hello", 0, true) != 6) throw "string lastSearch failed" }, -*/ + test_string_toLowerCase: function() { var str = "HELLO" if (lower(str) != "hello") throw "string toLowerCase failed" @@ -1842,7 +1842,7 @@ return { var result = a[null] if (result != null) throw "array get with null key should return null" }, -/* + test_obj_get_number_key_returns_null: function() { var o = {a: 1} var result = o[5] @@ -1892,7 +1892,7 @@ return { } if (!caught) throw "setting property on function should throw" }, -*/ + test_function_bracket_access_throws: function() { var fn = function() {} var caught = false @@ -2188,7 +2188,7 @@ return { var result = reduce(arr, (a, b) => a + b) if (result != "abc") throw "reduce string concat failed" }, -/* + test_reduce_to_object: function() { var arr = ["a", "b", "c"] var result = reduce(arr, (obj, val, i) => { @@ -2197,7 +2197,7 @@ return { }, {}) if (result.a != 0 || result.b != 1 || result.c != 2) throw "reduce to object failed" }, -*/ + // ============================================================================ // SORT FUNCTION // ============================================================================ @@ -2394,12 +2394,12 @@ return { test_abs_float: function() { if (abs(-3.14) != 3.14) throw "abs float failed" }, -/* + test_abs_non_number: function() { if (abs("5") != null) throw "abs non-number should return null" if (abs(null) != null) throw "abs null should return null" }, -*/ + // ============================================================================ // FLOOR FUNCTION // ============================================================================ @@ -2419,7 +2419,7 @@ return { test_floor_zero: function() { if (floor(0) != 0) throw "floor zero failed" }, -/* + test_floor_with_place: function() { if (floor(12.3775, -2) != 12.37) throw "floor with place failed" }, @@ -2427,7 +2427,7 @@ return { test_floor_negative_with_place: function() { if (floor(-12.3775, -2) != -12.38) throw "floor negative with place failed" }, -*/ + // ============================================================================ // CEILING FUNCTION // ============================================================================ @@ -2447,7 +2447,7 @@ return { test_ceiling_zero: function() { if (ceiling(0) != 0) throw "ceiling zero failed" }, -/* + test_ceiling_with_place: function() { if (ceiling(12.3775, -2) != 12.38) throw "ceiling with place failed" }, @@ -2471,7 +2471,7 @@ return { test_round_half: function() { if (round(3.5) != 4) throw "round half failed" }, -*/ + test_round_negative: function() { if (round(-3.5) != -3 && round(-3.5) != -4) throw "round negative failed" }, @@ -2479,7 +2479,7 @@ return { test_round_integer: function() { if (round(5) != 5) throw "round integer failed" }, -/* + test_round_with_places: function() { if (round(12.3775, -2) != 12.38) throw "round with places failed" }, @@ -2487,7 +2487,7 @@ return { test_round_to_tens: function() { if (round(12.3775, 1) != 10) throw "round to tens failed" }, -*/ + // ============================================================================ // TRUNC FUNCTION // ============================================================================ @@ -2507,7 +2507,7 @@ return { test_trunc_zero: function() { if (trunc(0) != 0) throw "trunc zero failed" }, -/* + test_trunc_with_places: function() { if (trunc(12.3775, -2) != 12.37) throw "trunc with places failed" }, @@ -2515,7 +2515,7 @@ return { test_trunc_negative_with_places: function() { if (trunc(-12.3775, -2) != -12.37) throw "trunc negative with places failed" }, -*/ + // ============================================================================ // SIGN FUNCTION // ============================================================================ @@ -2536,11 +2536,11 @@ return { if (sign(0.001) != 1) throw "sign positive float failed" if (sign(-0.001) != -1) throw "sign negative float failed" }, -/* + test_sign_non_number: function() { if (sign("5") != null) throw "sign non-number should return null" }, -*/ + // ============================================================================ // WHOLE AND FRACTION FUNCTIONS // ============================================================================ @@ -2556,7 +2556,7 @@ return { test_whole_integer: function() { if (whole(5) != 5) throw "whole integer failed" }, -/* + test_whole_non_number: function() { if (whole("5") != null) throw "whole non-number should return null" }, @@ -2565,7 +2565,7 @@ return { var f = fraction(3.75) if (f < 0.74 || f > 0.76) throw "fraction positive failed: " + f }, -*/ + test_fraction_negative: function() { var f = fraction(-3.75) if (f > -0.74 || f < -0.76) throw "fraction negative failed: " + f @@ -2574,11 +2574,11 @@ return { test_fraction_integer: function() { if (fraction(5) != 0) throw "fraction integer failed" }, -/* + test_fraction_non_number: function() { if (fraction("5") != null) throw "fraction non-number should return null" }, -*/ + // ============================================================================ // NEG FUNCTION // ============================================================================ @@ -2598,11 +2598,11 @@ return { test_neg_float: function() { if (neg(3.14) != -3.14) throw "neg float failed" }, -/* + test_neg_non_number: function() { if (neg("5") != null) throw "neg non-number should return null" }, -*/ + // ============================================================================ // MODULO FUNCTION // ============================================================================ @@ -2662,12 +2662,12 @@ return { test_min_float: function() { if (min(3.14, 2.71) != 2.71) throw "min float failed" }, -/* + test_min_non_number: function() { if (min(3, "5") != null) throw "min non-number should return null" if (min("3", 5) != null) throw "min first non-number should return null" }, -*/ + test_max_basic: function() { if (max(3, 5) != 5) throw "max basic failed" }, @@ -2687,11 +2687,11 @@ return { test_max_float: function() { if (max(3.14, 2.71) != 3.14) throw "max float failed" }, -/* + test_max_non_number: function() { if (max(3, "5") != null) throw "max non-number should return null" }, -*/ + test_min_max_constrain: function() { var val = 8 var constrained = min(max(val, 0), 10) @@ -2859,12 +2859,12 @@ return { test_text_number_negative: function() { if (text(-456) != "-456") throw "text number negative failed" }, -/* + test_text_number_float: function() { var result = text(3.14) 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" @@ -3289,13 +3289,13 @@ return { var result = array(arr, (x, i) => `${x}${i}`) if (result[0] != "a0" || result[1] != "b1") throw "array map with index failed" }, -/* + test_array_map_reverse: function() { var arr = [1, 2, 3] var result = array(arr, x => x * 2, true) if (result[0] != 6 || result[2] != 2) throw "array map reverse failed" }, -*/ + test_array_map_with_exit: function() { var arr = [1, 2, 3, 4, 5] var result = array(arr, x => {