extensive C testing
This commit is contained in:
471
source/quickjs.c
471
source/quickjs.c
@@ -1709,6 +1709,39 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
static JSValue js_cell_push (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
static JSValue js_cell_push (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
static JSValue js_cell_pop (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
static JSValue js_cell_pop (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
static JSValue js_cell_array_find (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
static JSValue js_cell_array_find (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_stone (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_length (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_reverse (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_proto (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_splat (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_meme (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_call (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_modulo (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_neg (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_not (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_lower (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_upper (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_trim (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_codepoint (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_search (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_character (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_abs (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_sign (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_floor (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_ceiling (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_round (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_trunc (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_whole (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_fraction (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_min (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_max (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_number_remainder (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_object (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
|
static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||||
JSValue JS_ThrowOutOfMemory (JSContext *ctx);
|
JSValue JS_ThrowOutOfMemory (JSContext *ctx);
|
||||||
static JSVarRef *get_var_ref (JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg);
|
static JSVarRef *get_var_ref (JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg);
|
||||||
static JSValue JS_EvalInternal (JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int flags, int scope_idx);
|
static JSValue JS_EvalInternal (JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int flags, int scope_idx);
|
||||||
@@ -3255,7 +3288,7 @@ JSValue JS_NewObject (JSContext *ctx) {
|
|||||||
|
|
||||||
/* Helper to check if a value is a bytecode function */
|
/* Helper to check if a value is a bytecode function */
|
||||||
static BOOL js_is_bytecode_function (JSValue val) {
|
static BOOL js_is_bytecode_function (JSValue val) {
|
||||||
if (JS_VALUE_GET_TAG (val) != JS_TAG_FUNCTION) return FALSE;
|
if (!JS_IsFunction (val)) return FALSE;
|
||||||
JSFunction *f = JS_VALUE_GET_FUNCTION (val);
|
JSFunction *f = JS_VALUE_GET_FUNCTION (val);
|
||||||
return f->kind == JS_FUNC_KIND_BYTECODE;
|
return f->kind == JS_FUNC_KIND_BYTECODE;
|
||||||
}
|
}
|
||||||
@@ -3263,7 +3296,7 @@ static BOOL js_is_bytecode_function (JSValue val) {
|
|||||||
/* return NULL without exception if not a function or no bytecode */
|
/* return NULL without exception if not a function or no bytecode */
|
||||||
static JSFunctionBytecode *JS_GetFunctionBytecode (JSValue val) {
|
static JSFunctionBytecode *JS_GetFunctionBytecode (JSValue val) {
|
||||||
JSFunction *f;
|
JSFunction *f;
|
||||||
if (JS_VALUE_GET_TAG (val) != JS_TAG_FUNCTION) return NULL;
|
if (!JS_IsFunction (val)) return NULL;
|
||||||
f = JS_VALUE_GET_FUNCTION (val);
|
f = JS_VALUE_GET_FUNCTION (val);
|
||||||
if (f->kind != JS_FUNC_KIND_BYTECODE) return NULL;
|
if (f->kind != JS_FUNC_KIND_BYTECODE) return NULL;
|
||||||
return f->u.func.function_bytecode;
|
return f->u.func.function_bytecode;
|
||||||
@@ -3280,7 +3313,7 @@ static int js_method_set_properties (JSContext *ctx, JSValue func_obj, JSValue n
|
|||||||
(void)ctx;
|
(void)ctx;
|
||||||
(void)flags;
|
(void)flags;
|
||||||
(void)home_obj;
|
(void)home_obj;
|
||||||
if (JS_VALUE_GET_TAG (func_obj) != JS_TAG_FUNCTION) return -1;
|
if (!JS_IsFunction (func_obj)) return -1;
|
||||||
JSFunction *f = JS_VALUE_GET_FUNCTION (func_obj);
|
JSFunction *f = JS_VALUE_GET_FUNCTION (func_obj);
|
||||||
/* name is now JSValue text */
|
/* name is now JSValue text */
|
||||||
if (JS_IsText (name)) { f->name = name; }
|
if (JS_IsText (name)) { f->name = name; }
|
||||||
@@ -3735,7 +3768,7 @@ static void build_backtrace (JSContext *ctx, JSValue error_obj, const char *file
|
|||||||
dbuf_printf (&dbuf, " at %s", str1);
|
dbuf_printf (&dbuf, " at %s", str1);
|
||||||
JS_FreeCString (ctx, func_name_str);
|
JS_FreeCString (ctx, func_name_str);
|
||||||
|
|
||||||
if (JS_VALUE_GET_TAG (sf->cur_func) == JS_TAG_FUNCTION) {
|
if (JS_IsFunction (sf->cur_func)) {
|
||||||
JSFunction *fn = JS_VALUE_GET_FUNCTION (sf->cur_func);
|
JSFunction *fn = JS_VALUE_GET_FUNCTION (sf->cur_func);
|
||||||
if (fn->kind == JS_FUNC_KIND_BYTECODE) {
|
if (fn->kind == JS_FUNC_KIND_BYTECODE) {
|
||||||
JSFunctionBytecode *b;
|
JSFunctionBytecode *b;
|
||||||
@@ -4622,7 +4655,7 @@ int JS_DeleteProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
|||||||
|
|
||||||
BOOL JS_IsCFunction (JSValue val, JSCFunction *func, int magic) {
|
BOOL JS_IsCFunction (JSValue val, JSCFunction *func, int magic) {
|
||||||
JSFunction *f;
|
JSFunction *f;
|
||||||
if (JS_VALUE_GET_TAG (val) != JS_TAG_FUNCTION) return FALSE;
|
if (!JS_IsFunction (val)) return FALSE;
|
||||||
f = JS_VALUE_GET_FUNCTION (val);
|
f = JS_VALUE_GET_FUNCTION (val);
|
||||||
if (f->kind == JS_FUNC_KIND_C)
|
if (f->kind == JS_FUNC_KIND_C)
|
||||||
return (f->u.cfunc.c_function.generic == func
|
return (f->u.cfunc.c_function.generic == func
|
||||||
@@ -6396,7 +6429,7 @@ static JSValue JS_CallInternal (JSContext *caller_ctx, JSValue func_obj, JSValue
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (js_poll_interrupts (caller_ctx)) return JS_EXCEPTION;
|
if (js_poll_interrupts (caller_ctx)) return JS_EXCEPTION;
|
||||||
if (unlikely (JS_VALUE_GET_TAG (func_obj) != JS_TAG_FUNCTION)) {
|
if (unlikely (!JS_IsFunction (func_obj))) {
|
||||||
not_a_function:
|
not_a_function:
|
||||||
return JS_ThrowTypeError (caller_ctx, "not a function");
|
return JS_ThrowTypeError (caller_ctx, "not a function");
|
||||||
}
|
}
|
||||||
@@ -21722,6 +21755,178 @@ static JSValue js_cell_text_extract (JSContext *ctx, JSValue this_val, int argc,
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* format(text, collection, transformer) - string interpolation
|
||||||
|
* Finds {name} or {name:format} patterns and substitutes from collection.
|
||||||
|
* Collection can be array (index by number) or record (index by key).
|
||||||
|
* Transformer can be function(value, format) or record of functions.
|
||||||
|
*/
|
||||||
|
static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||||
|
if (argc < 2) return JS_NULL;
|
||||||
|
if (!JS_IsText (argv[0])) return JS_NULL;
|
||||||
|
|
||||||
|
JSValue text_val = argv[0];
|
||||||
|
JSValue collection = argv[1];
|
||||||
|
JSValue transformer = argc > 2 ? argv[2] : JS_NULL;
|
||||||
|
|
||||||
|
int is_array = JS_IsArray (collection);
|
||||||
|
int is_record = JS_IsRecord (collection);
|
||||||
|
if (!is_array && !is_record) return JS_NULL;
|
||||||
|
|
||||||
|
JSText *sp = JS_VALUE_GET_STRING (text_val);
|
||||||
|
int len = (int)JSText_len (sp);
|
||||||
|
|
||||||
|
JSText *result = pretext_init (ctx, len);
|
||||||
|
if (!result) return JS_EXCEPTION;
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < len) {
|
||||||
|
/* Find next '{' */
|
||||||
|
int brace_start = -1;
|
||||||
|
for (int i = pos; i < len; i++) {
|
||||||
|
if (string_get (sp, i) == '{') {
|
||||||
|
brace_start = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brace_start < 0) {
|
||||||
|
/* No more braces, copy rest of string */
|
||||||
|
JSValue tail = js_sub_string (ctx, sp, pos, len);
|
||||||
|
if (JS_IsException (tail)) return JS_EXCEPTION;
|
||||||
|
result = pretext_concat_value (ctx, result, tail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy text before brace */
|
||||||
|
if (brace_start > pos) {
|
||||||
|
JSValue prefix = js_sub_string (ctx, sp, pos, brace_start);
|
||||||
|
if (JS_IsException (prefix)) return JS_EXCEPTION;
|
||||||
|
result = pretext_concat_value (ctx, result, prefix);
|
||||||
|
if (!result) return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find closing '}' */
|
||||||
|
int brace_end = -1;
|
||||||
|
for (int i = brace_start + 1; i < len; i++) {
|
||||||
|
if (string_get (sp, i) == '}') {
|
||||||
|
brace_end = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brace_end < 0) {
|
||||||
|
/* No closing brace, copy '{' and continue */
|
||||||
|
JSValue ch = js_sub_string (ctx, sp, brace_start, brace_start + 1);
|
||||||
|
if (JS_IsException (ch)) return JS_EXCEPTION;
|
||||||
|
result = pretext_concat_value (ctx, result, ch);
|
||||||
|
if (!result) return JS_EXCEPTION;
|
||||||
|
pos = brace_start + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract content between braces */
|
||||||
|
JSValue middle = js_sub_string (ctx, sp, brace_start + 1, brace_end);
|
||||||
|
if (JS_IsException (middle)) return JS_EXCEPTION;
|
||||||
|
|
||||||
|
/* Split on ':' to get name and format_spec */
|
||||||
|
JSText *middle_str = JS_VALUE_GET_STRING (middle);
|
||||||
|
int middle_len = (int)JSText_len (middle_str);
|
||||||
|
|
||||||
|
int colon_pos = -1;
|
||||||
|
for (int i = 0; i < middle_len; i++) {
|
||||||
|
if (string_get (middle_str, i) == ':') {
|
||||||
|
colon_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue name_val, format_spec;
|
||||||
|
if (colon_pos >= 0) {
|
||||||
|
name_val = js_sub_string (ctx, middle_str, 0, colon_pos);
|
||||||
|
format_spec = js_sub_string (ctx, middle_str, colon_pos + 1, middle_len);
|
||||||
|
} else {
|
||||||
|
name_val = middle;
|
||||||
|
format_spec = JS_KEY_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get value from collection */
|
||||||
|
JSValue coll_value = JS_NULL;
|
||||||
|
if (is_array) {
|
||||||
|
/* Parse name as integer index */
|
||||||
|
int32_t idx = 0;
|
||||||
|
if (JS_ToInt32 (ctx, &idx, name_val) == 0 && idx >= 0) {
|
||||||
|
coll_value = JS_GetPropertyUint32 (ctx, collection, (uint32_t)idx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Use name as key */
|
||||||
|
coll_value = JS_GetProperty (ctx, collection, name_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to get substitution */
|
||||||
|
JSValue substitution = JS_NULL;
|
||||||
|
int made_substitution = 0;
|
||||||
|
|
||||||
|
/* Try transformer first */
|
||||||
|
if (!JS_IsNull (transformer)) {
|
||||||
|
if (JS_IsFunction (transformer)) {
|
||||||
|
/* transformer(value, format_spec) */
|
||||||
|
JSValue args[2] = { coll_value, format_spec };
|
||||||
|
JSValue result_val = JS_Call (ctx, transformer, JS_NULL, 2, args);
|
||||||
|
if (JS_IsText (result_val)) {
|
||||||
|
substitution = result_val;
|
||||||
|
made_substitution = 1;
|
||||||
|
}
|
||||||
|
} else if (JS_IsRecord (transformer)) {
|
||||||
|
/* transformer[format_spec](value) */
|
||||||
|
JSValue func = JS_GetProperty (ctx, transformer, format_spec);
|
||||||
|
if (JS_IsFunction (func)) {
|
||||||
|
JSValue result_val = JS_Call (ctx, func, JS_NULL, 1, &coll_value);
|
||||||
|
if (JS_IsText (result_val)) {
|
||||||
|
substitution = result_val;
|
||||||
|
made_substitution = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no transformer match and value is number, try number.text(format) */
|
||||||
|
if (!made_substitution && JS_IsNumber (coll_value) && !JS_IsNull (format_spec)) {
|
||||||
|
JSValue text_method = JS_GetPropertyStr (ctx, coll_value, "text");
|
||||||
|
if (JS_IsFunction (text_method)) {
|
||||||
|
JSValue result_val = JS_Call (ctx, text_method, coll_value, 1, &format_spec);
|
||||||
|
if (JS_IsText (result_val)) {
|
||||||
|
substitution = result_val;
|
||||||
|
made_substitution = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If still no substitution but we have a value, convert to text */
|
||||||
|
if (!made_substitution && !JS_IsNull (coll_value)) {
|
||||||
|
JSValue text_val = JS_ToString (ctx, coll_value);
|
||||||
|
if (JS_IsText (text_val)) {
|
||||||
|
substitution = text_val;
|
||||||
|
made_substitution = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (made_substitution) {
|
||||||
|
result = pretext_concat_value (ctx, result, substitution);
|
||||||
|
if (!result) return JS_EXCEPTION;
|
||||||
|
} else {
|
||||||
|
/* No substitution, keep original {name} or {name:format} */
|
||||||
|
JSValue orig = js_sub_string (ctx, sp, brace_start, brace_end + 1);
|
||||||
|
if (JS_IsException (orig)) return JS_EXCEPTION;
|
||||||
|
result = pretext_concat_value (ctx, result, orig);
|
||||||
|
if (!result) return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = brace_end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pretext_end (ctx, result);
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* array function and sub-functions
|
* array function and sub-functions
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
@@ -23542,6 +23747,258 @@ JSValue JS_ArrayReduce (JSContext *ctx, JSValue arr, JSValue fn, JSValue initial
|
|||||||
return js_cell_array_reduce (ctx, JS_NULL, argc, argv);
|
return js_cell_array_reduce (ctx, JS_NULL, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
C API Wrappers for Cell Intrinsic Functions
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
/* C API: stone(val) - make value immutable */
|
||||||
|
JSValue JS_CellStone (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_stone (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: length(val) - get length of array/text/blob */
|
||||||
|
JSValue JS_CellLength (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_length (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: reverse(val) - reverse array or text */
|
||||||
|
JSValue JS_CellReverse (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_reverse (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: proto(obj) - get prototype */
|
||||||
|
JSValue JS_CellProto (JSContext *ctx, JSValue obj) {
|
||||||
|
return js_cell_proto (ctx, JS_NULL, 1, &obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: splat(val) - convert to array */
|
||||||
|
JSValue JS_CellSplat (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_splat (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: meme(obj, deep) - clone object */
|
||||||
|
JSValue JS_CellMeme (JSContext *ctx, JSValue obj, JSValue deep) {
|
||||||
|
JSValue argv[2] = { obj, deep };
|
||||||
|
int argc = JS_IsNull (deep) ? 1 : 2;
|
||||||
|
return js_cell_meme (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: apply(fn, args) - apply function to array of args */
|
||||||
|
JSValue JS_CellApply (JSContext *ctx, JSValue fn, JSValue args) {
|
||||||
|
JSValue argv[2] = { fn, args };
|
||||||
|
return js_cell_fn_apply (ctx, JS_NULL, 2, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: call(fn, this, args...) - call function */
|
||||||
|
JSValue JS_CellCall (JSContext *ctx, JSValue fn, JSValue this_val, JSValue args) {
|
||||||
|
JSValue argv[3] = { fn, this_val, args };
|
||||||
|
int argc = JS_IsNull (args) ? 2 : 3;
|
||||||
|
return js_cell_call (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: modulo(a, b) - modulo operation */
|
||||||
|
JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b) {
|
||||||
|
JSValue argv[2] = { a, b };
|
||||||
|
return js_cell_modulo (ctx, JS_NULL, 2, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: neg(val) - negate number */
|
||||||
|
JSValue JS_CellNeg (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_neg (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: not(val) - logical not */
|
||||||
|
JSValue JS_CellNot (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_not (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text functions */
|
||||||
|
|
||||||
|
/* C API: text(val) - convert to text */
|
||||||
|
JSValue JS_CellText (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_text (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: lower(text) - convert to lowercase */
|
||||||
|
JSValue JS_CellLower (JSContext *ctx, JSValue text) {
|
||||||
|
return js_cell_text_lower (ctx, JS_NULL, 1, &text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: upper(text) - convert to uppercase */
|
||||||
|
JSValue JS_CellUpper (JSContext *ctx, JSValue text) {
|
||||||
|
return js_cell_text_upper (ctx, JS_NULL, 1, &text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: trim(text, chars) - trim whitespace or specified chars */
|
||||||
|
JSValue JS_CellTrim (JSContext *ctx, JSValue text, JSValue chars) {
|
||||||
|
JSValue argv[2] = { text, chars };
|
||||||
|
int argc = JS_IsNull (chars) ? 1 : 2;
|
||||||
|
return js_cell_text_trim (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: codepoint(text, idx) - get codepoint at index */
|
||||||
|
JSValue JS_CellCodepoint (JSContext *ctx, JSValue text, JSValue idx) {
|
||||||
|
JSValue argv[2] = { text, idx };
|
||||||
|
int argc = JS_IsNull (idx) ? 1 : 2;
|
||||||
|
return js_cell_text_codepoint (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: replace(text, pattern, replacement) - replace in text */
|
||||||
|
JSValue JS_CellReplace (JSContext *ctx, JSValue text, JSValue pattern, JSValue replacement) {
|
||||||
|
JSValue argv[3] = { text, pattern, replacement };
|
||||||
|
return js_cell_text_replace (ctx, JS_NULL, 3, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: search(text, pattern, from) - search in text */
|
||||||
|
JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue from) {
|
||||||
|
JSValue argv[3] = { text, pattern, from };
|
||||||
|
int argc = JS_IsNull (from) ? 2 : 3;
|
||||||
|
return js_cell_text_search (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: extract(text, from, to) - extract substring */
|
||||||
|
JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to) {
|
||||||
|
JSValue argv[3] = { text, from, to };
|
||||||
|
int argc = 3;
|
||||||
|
if (JS_IsNull (to)) argc = 2;
|
||||||
|
if (JS_IsNull (from)) argc = 1;
|
||||||
|
return js_cell_text_extract (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: character(codepoint) - create single character text */
|
||||||
|
JSValue JS_CellCharacter (JSContext *ctx, JSValue codepoint) {
|
||||||
|
return js_cell_character (ctx, JS_NULL, 1, &codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number functions */
|
||||||
|
|
||||||
|
/* C API: number(val) - convert to number */
|
||||||
|
JSValue JS_CellNumber (JSContext *ctx, JSValue val) {
|
||||||
|
return js_cell_number (ctx, JS_NULL, 1, &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: abs(num) - absolute value */
|
||||||
|
JSValue JS_CellAbs (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_abs (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: sign(num) - sign of number (-1, 0, 1) */
|
||||||
|
JSValue JS_CellSign (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_sign (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: floor(num) - floor */
|
||||||
|
JSValue JS_CellFloor (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_floor (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: ceiling(num) - ceiling */
|
||||||
|
JSValue JS_CellCeiling (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_ceiling (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: round(num) - round to nearest integer */
|
||||||
|
JSValue JS_CellRound (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_round (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: trunc(num) - truncate towards zero */
|
||||||
|
JSValue JS_CellTrunc (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_trunc (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: whole(num) - integer part */
|
||||||
|
JSValue JS_CellWhole (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_whole (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: fraction(num) - fractional part */
|
||||||
|
JSValue JS_CellFraction (JSContext *ctx, JSValue num) {
|
||||||
|
return js_cell_number_fraction (ctx, JS_NULL, 1, &num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: min(a, b) - minimum of two numbers */
|
||||||
|
JSValue JS_CellMin (JSContext *ctx, JSValue a, JSValue b) {
|
||||||
|
JSValue argv[2] = { a, b };
|
||||||
|
return js_cell_number_min (ctx, JS_NULL, 2, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: max(a, b) - maximum of two numbers */
|
||||||
|
JSValue JS_CellMax (JSContext *ctx, JSValue a, JSValue b) {
|
||||||
|
JSValue argv[2] = { a, b };
|
||||||
|
return js_cell_number_max (ctx, JS_NULL, 2, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: remainder(a, b) - remainder after division */
|
||||||
|
JSValue JS_CellRemainder (JSContext *ctx, JSValue a, JSValue b) {
|
||||||
|
JSValue argv[2] = { a, b };
|
||||||
|
return js_cell_number_remainder (ctx, JS_NULL, 2, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Object functions */
|
||||||
|
|
||||||
|
/* C API: object(proto, props) - create object */
|
||||||
|
JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props) {
|
||||||
|
JSValue argv[2] = { proto, props };
|
||||||
|
int argc = JS_IsNull (props) ? 1 : 2;
|
||||||
|
if (JS_IsNull (proto)) argc = 0;
|
||||||
|
return js_cell_object (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C API: format(text, collection, transformer) - string interpolation */
|
||||||
|
JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer) {
|
||||||
|
JSValue argv[3] = { text, collection, transformer };
|
||||||
|
int argc = JS_IsNull (transformer) ? 2 : 3;
|
||||||
|
return js_cell_text_format (ctx, JS_NULL, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
Helper Functions for C API
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
/* Create an array from a list of JSValues */
|
||||||
|
JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values) {
|
||||||
|
JSValue arr = JS_NewArray (ctx);
|
||||||
|
if (JS_IsException (arr)) return arr;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (JS_ArrayPush (ctx, &arr, values[i]) < 0) {
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print a JSValue text to stdout */
|
||||||
|
void JS_PrintText (JSContext *ctx, JSValue val) {
|
||||||
|
if (!JS_IsText (val)) {
|
||||||
|
/* Try to convert to string first */
|
||||||
|
val = JS_ToString (ctx, val);
|
||||||
|
if (JS_IsException (val) || !JS_IsText (val)) {
|
||||||
|
printf ("[non-text value]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char *str = JS_ToCString (ctx, val);
|
||||||
|
if (str) {
|
||||||
|
printf ("%s", str);
|
||||||
|
JS_FreeCString (ctx, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print a JSValue text to stdout with newline */
|
||||||
|
void JS_PrintTextLn (JSContext *ctx, JSValue val) {
|
||||||
|
JS_PrintText (ctx, val);
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format and print - convenience function */
|
||||||
|
void JS_PrintFormatted (JSContext *ctx, const char *fmt, int count, JSValue *values) {
|
||||||
|
JSValue fmt_str = JS_NewString (ctx, fmt);
|
||||||
|
JSValue arr = JS_NewArrayFrom (ctx, count, values);
|
||||||
|
JSValue result = JS_CellFormat (ctx, fmt_str, arr, JS_NULL);
|
||||||
|
JS_PrintText (ctx, result);
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue js_cell_push (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
static JSValue js_cell_push (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||||
if (argc < 1) return JS_NULL;
|
if (argc < 1) return JS_NULL;
|
||||||
|
|
||||||
@@ -24079,6 +24536,8 @@ void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
|
|||||||
ctx, ctx->global_obj, "search", JS_NewCFunction (ctx, js_cell_text_search, "search", 3));
|
ctx, ctx->global_obj, "search", JS_NewCFunction (ctx, js_cell_text_search, "search", 3));
|
||||||
JS_SetPropertyStr (
|
JS_SetPropertyStr (
|
||||||
ctx, ctx->global_obj, "extract", JS_NewCFunction (ctx, js_cell_text_extract, "extract", 4));
|
ctx, ctx->global_obj, "extract", JS_NewCFunction (ctx, js_cell_text_extract, "extract", 4));
|
||||||
|
JS_SetPropertyStr (
|
||||||
|
ctx, ctx->global_obj, "format", JS_NewCFunction (ctx, js_cell_text_format, "format", 3));
|
||||||
JS_SetPropertyStr (
|
JS_SetPropertyStr (
|
||||||
ctx, ctx->global_obj, "reduce", JS_NewCFunction (ctx, js_cell_array_reduce, "reduce", 4));
|
ctx, ctx->global_obj, "reduce", JS_NewCFunction (ctx, js_cell_array_reduce, "reduce", 4));
|
||||||
JS_SetPropertyStr (ctx, ctx->global_obj, "arrfor", JS_NewCFunction (ctx, js_cell_array_for, "for", 4));
|
JS_SetPropertyStr (ctx, ctx->global_obj, "arrfor", JS_NewCFunction (ctx, js_cell_array_for, "for", 4));
|
||||||
|
|||||||
@@ -653,6 +653,59 @@ JSValue JS_ArraySort (JSContext *ctx, JSValue arr, JSValue selector);
|
|||||||
JSValue JS_ArrayFind (JSContext *ctx, JSValue arr, JSValue target_or_fn, JSValue reverse, JSValue from);
|
JSValue JS_ArrayFind (JSContext *ctx, JSValue arr, JSValue target_or_fn, JSValue reverse, JSValue from);
|
||||||
JSValue JS_ArrFor (JSContext *ctx, JSValue arr, JSValue fn, JSValue reverse, JSValue exit_val);
|
JSValue JS_ArrFor (JSContext *ctx, JSValue arr, JSValue fn, JSValue reverse, JSValue exit_val);
|
||||||
JSValue JS_ArrayReduce (JSContext *ctx, JSValue arr, JSValue fn, JSValue initial, JSValue reverse);
|
JSValue JS_ArrayReduce (JSContext *ctx, JSValue arr, JSValue fn, JSValue initial, JSValue reverse);
|
||||||
|
|
||||||
|
/* Cell intrinsic functions - C API wrappers */
|
||||||
|
|
||||||
|
/* Core functions */
|
||||||
|
JSValue JS_CellStone (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellLength (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellReverse (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellProto (JSContext *ctx, JSValue obj);
|
||||||
|
JSValue JS_CellSplat (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellMeme (JSContext *ctx, JSValue obj, JSValue deep);
|
||||||
|
JSValue JS_CellApply (JSContext *ctx, JSValue fn, JSValue args);
|
||||||
|
JSValue JS_CellCall (JSContext *ctx, JSValue fn, JSValue this_val, JSValue args);
|
||||||
|
JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b);
|
||||||
|
JSValue JS_CellNeg (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellNot (JSContext *ctx, JSValue val);
|
||||||
|
|
||||||
|
/* Text functions */
|
||||||
|
JSValue JS_CellText (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellLower (JSContext *ctx, JSValue text);
|
||||||
|
JSValue JS_CellUpper (JSContext *ctx, JSValue text);
|
||||||
|
JSValue JS_CellTrim (JSContext *ctx, JSValue text, JSValue chars);
|
||||||
|
JSValue JS_CellCodepoint (JSContext *ctx, JSValue text, JSValue idx);
|
||||||
|
JSValue JS_CellReplace (JSContext *ctx, JSValue text, JSValue pattern, JSValue replacement);
|
||||||
|
JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue from);
|
||||||
|
JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to);
|
||||||
|
JSValue JS_CellCharacter (JSContext *ctx, JSValue codepoint);
|
||||||
|
|
||||||
|
/* Number functions */
|
||||||
|
JSValue JS_CellNumber (JSContext *ctx, JSValue val);
|
||||||
|
JSValue JS_CellAbs (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellSign (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellFloor (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellCeiling (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellRound (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellTrunc (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellWhole (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellFraction (JSContext *ctx, JSValue num);
|
||||||
|
JSValue JS_CellMin (JSContext *ctx, JSValue a, JSValue b);
|
||||||
|
JSValue JS_CellMax (JSContext *ctx, JSValue a, JSValue b);
|
||||||
|
JSValue JS_CellRemainder (JSContext *ctx, JSValue a, JSValue b);
|
||||||
|
|
||||||
|
/* Object functions */
|
||||||
|
JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props);
|
||||||
|
|
||||||
|
/* Format function */
|
||||||
|
JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer);
|
||||||
|
|
||||||
|
/* Helper functions */
|
||||||
|
JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values);
|
||||||
|
void JS_PrintText (JSContext *ctx, JSValue val);
|
||||||
|
void JS_PrintTextLn (JSContext *ctx, JSValue val);
|
||||||
|
void JS_PrintFormatted (JSContext *ctx, const char *fmt, int count, JSValue *values);
|
||||||
|
|
||||||
JSValue JS_GetProperty (JSContext *ctx, JSValue this_obj, JSValue prop);
|
JSValue JS_GetProperty (JSContext *ctx, JSValue this_obj, JSValue prop);
|
||||||
|
|
||||||
// For records
|
// For records
|
||||||
|
|||||||
1034
source/suite.c
1034
source/suite.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user