static int Deserializer_Read(duk_context* ctx) { duk_int_t magic = duk_get_current_magic(ctx); duk_push_this(ctx); // safe cast based on type check above Deserializer* deserial = CastToDeserializer(ctx, duk_get_top_index(ctx)); duk_pop(ctx); if (!deserial) { duk_push_boolean(ctx, 0); return 1; } char* data; String str; size_t length; IO_MAGIC_TYPE v = (IO_MAGIC_TYPE) magic; bool success = false; switch(v) { case IO_MAGIC_INT: duk_push_number(ctx, (double) deserial->ReadInt()); return 1; case IO_MAGIC_STRING: length = deserial->GetSize() - deserial->GetPosition(); str.Resize(length + 1); deserial->Read(&str[0], length); str[length] = '\0'; duk_push_string(ctx, str.CString()); return 1; case IO_MAGIC_ZEROSTRING: success = duk_push_string(ctx, deserial->ReadString().CString()); return 1; case IO_MAGIC_BINARY: length = deserial->GetSize() - deserial->GetPosition(); duk_push_fixed_buffer(ctx, length); duk_push_buffer_object(ctx, -1, 0, length, DUK_BUFOBJ_UINT8ARRAY); duk_replace(ctx, -2); data = (char*) duk_require_buffer_data(ctx, 0, &length); success = deserial->Read(data, length); return 1; default: break; } duk_push_undefined(ctx); return 1; }
duk_ret_t dukky_html_menu_element___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_HTMLELEMENT"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "type"); duk_push_c_function(ctx, dukky_html_menu_element_type_getter, 0); duk_push_c_function(ctx, dukky_html_menu_element_type_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "label"); duk_push_c_function(ctx, dukky_html_menu_element_label_getter, 0); duk_push_c_function(ctx, dukky_html_menu_element_label_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "compact"); duk_push_c_function(ctx, dukky_html_menu_element_compact_getter, 0); duk_push_c_function(ctx, dukky_html_menu_element_compact_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_menu_element___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_menu_element___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
/* Constructor */ DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t nargs; /* Calling as a non-constructor is not meaningful. */ if (!duk_is_constructor_call(ctx)) { return DUK_RET_TYPE_ERROR; } nargs = duk_get_top(ctx); duk_set_top(ctx, 1); duk_push_this(ctx); /* [ name this ] */ if (nargs == 0) { /* Automatic defaulting of logger name from caller. This would * work poorly with tail calls, but constructor calls are currently * never tail calls, so tail calls are not an issue now. */ if (thr->callstack_top >= 2) { duk_activation *act_caller = thr->callstack + thr->callstack_top - 2; duk_hobject *func_caller; func_caller = DUK_ACT_GET_FUNC(act_caller); if (func_caller) { /* Stripping the filename might be a good idea * ("/foo/bar/quux.js" -> logger name "quux"), * but now used verbatim. */ duk_push_hobject(ctx, func_caller); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME); duk_replace(ctx, 0); } } } /* the stack is unbalanced here on purpose; we only rely on the * initial two values: [ name this ]. */ if (duk_is_string(ctx, 0)) { duk_dup(ctx, 0); duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N); } else { /* don't set 'n' at all, inherited value is used as name */ } duk_compact(ctx, 1); return 0; /* keep default instance */ }
static duk_ret_t test_1(duk_context *ctx) { duk_idx_t i, n; prep(ctx); duk_replace(ctx, -3); /* -> [ 123 "foo" 345 ] */ n = duk_get_top(ctx); for (i = 0; i < n; i++) { printf("%ld: %s\n", (long) i, duk_to_string(ctx, i)); } return 0; }
int duk_builtin_object_constructor_create(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_hobject *proto = NULL; duk_hobject *h; DUK_ASSERT_TOP(ctx, 2); tv = duk_get_tval(ctx, 0); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_NULL(tv)) { ; } else if (DUK_TVAL_IS_OBJECT(tv)) { proto = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(proto != NULL); } else { return DUK_RET_TYPE_ERROR; } /* FIXME: direct helper to create with specific prototype */ (void) duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), -1); h = duk_get_hobject(ctx, -1); DUK_ASSERT(h != NULL); DUK_ASSERT(h->prototype == NULL); DUK_HOBJECT_SET_PROTOTYPE(thr, h, proto); if (!duk_is_undefined(ctx, 1)) { /* [ O Properties obj ] */ /* Use original function. No need to get it explicitly, * just call the helper. */ duk_replace(ctx, 0); /* [ obj Properties ] */ return duk_hobject_object_define_properties(ctx); } /* [ O Properties obj ] */ return 1; }
int duk_builtin_date_constructor(duk_context *ctx) { int nargs = duk_get_top(ctx); int is_cons = duk_is_constructor_call(ctx); double dparts[NUM_PARTS]; double d; DUK_DDDPRINT("Date constructor, nargs=%d, is_cons=%d", nargs, is_cons); duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), DUK_BIDX_DATE_PROTOTYPE); /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date * is mutable. */ if (nargs == 0 || !is_cons) { d = timeclip(GET_NOW_TIMEVAL(ctx)); duk_push_number(ctx, d); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); if (!is_cons) { /* called as a normal function: return new Date().toString() */ duk_to_string(ctx, -1); } return 1; } else if (nargs == 1) { duk_to_primitive(ctx, 0, DUK_HINT_NONE); if (duk_is_string(ctx, 0)) { parse_string(ctx, duk_to_string(ctx, 0)); duk_replace(ctx, 0); /* may be NaN */ } d = timeclip(duk_to_number(ctx, 0)); duk_push_number(ctx, d); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); return 1; } set_parts_from_args(ctx, dparts, nargs); /* Parts are in local time, convert when setting. */ set_this_timeval_from_dparts(ctx, dparts, FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */ duk_pop(ctx); /* -> [ ... this ] */ return 1; }
/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add * 1900 and replace value at idx_val. */ static void twodigit_year_fixup(duk_context *ctx, int idx_val) { double d; /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */ duk_to_number(ctx, idx_val); if (duk_is_nan(ctx, idx_val)) { return; } duk_dup(ctx, idx_val); duk_to_int(ctx, -1); d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */ if (d >= 0.0 && d <= 99.0) { d += 1900.0; duk_push_number(ctx, d); duk_replace(ctx, idx_val); } duk_pop(ctx); }
int main(int argc, char *argv[]) { duk_context *ctx; int i; int exitcode = 0; ctx = duk_create_heap_default(); if (!ctx) { return 1; } duk_push_c_function(ctx, handle_print, 1); duk_put_global_string(ctx, "print"); duk_push_c_function(ctx, handle_assert, 2); duk_put_global_string(ctx, "assert"); duk_push_object(ctx); duk_push_c_function(ctx, cb_resolve_module, DUK_VARARGS); duk_put_prop_string(ctx, -2, "resolve"); duk_push_c_function(ctx, cb_load_module, DUK_VARARGS); duk_put_prop_string(ctx, -2, "load"); duk_module_node_init(ctx); printf("top after init: %ld\n", (long) duk_get_top(ctx)); for (i = 1; i < argc; i++) { printf("Evaling: %s\n", argv[i]); if (duk_peval_string(ctx, argv[i]) != 0) { if (duk_get_prop_string(ctx, -1, "stack")) { duk_replace(ctx, -2); } else { duk_pop(ctx); } exitcode = 1; } printf("--> %s\n", duk_safe_to_string(ctx, -1)); duk_pop(ctx); } printf("Done\n"); duk_destroy_heap(ctx); return exitcode; }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) { duk_tval *tv; duk_hobject *proto = NULL; DUK_ASSERT_TOP(ctx, 2); tv = duk_get_tval(ctx, 0); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_NULL(tv)) { ; } else if (DUK_TVAL_IS_OBJECT(tv)) { proto = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(proto != NULL); } else { return DUK_RET_TYPE_ERROR; } (void) duk_push_object_helper_proto(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), proto); if (!duk_is_undefined(ctx, 1)) { /* [ O Properties obj ] */ /* Use original function. No need to get it explicitly, * just call the helper. */ duk_replace(ctx, 0); /* [ obj Properties ] */ return duk_hobject_object_define_properties(ctx); } /* [ O Properties obj ] */ return 1; }
static duk_ret_t duk_java_property_set(duk_context *ctx) { const char* key = duk_to_string(ctx, 0); DEBUG_LOG("ScriptEngine", "duk_java_property_set key %s ", key); duk_push_this(ctx); if(duk_get_prop_string(ctx, -1, JAVA_OBJECT_MARK)){ jobject ref = duk_to_pointer(ctx, -1); JNIEnv* env = get_java_jni_env(); jstring fieldName = (*env)->NewStringUTF(env, key); jobject fieldValue = duk_to_java_object(ctx, env, 1); DEBUG_LOG("ScriptEngine", "duk_java_property_set call staticVoidMethod %s ", key); (*env)->CallStaticVoidMethod(env, java_api_class, java_field_set_method, ref, fieldName, fieldValue); DEBUG_LOG("ScriptEngine", "duk_java_property_set call staticVoidMethod Success"); jthrowable exp = ( *env)->ExceptionOccurred(env); if(exp != NULL){ (*env)->ExceptionClear(env); jstring exceptionMessage = (*env)->CallStaticObjectMethod(env, java_api_class, java_exception_get_stack_trace_method, exp); jboolean isCopy = JNI_FALSE; const char* cstrMessage = (*env)->GetStringUTFChars(env, exceptionMessage, &isCopy); duk_push_error_object(ctx, DUK_ERR_EVAL_ERROR, "get java property %s error \n %s", key, cstrMessage); (*env)->ReleaseStringUTFChars(env, exceptionMessage, cstrMessage); ( *env)->DeleteLocalRef(env , exceptionMessage); (*env)->DeleteLocalRef(env, fieldValue); (*env)->DeleteLocalRef(env, fieldName); duk_throw(ctx); return 0; } (*env)->DeleteLocalRef(env, fieldValue); (*env)->DeleteLocalRef(env, fieldName); return 0; }else{ DEBUG_LOG("ScriptEngine", "duk_java_property_set key %d ", duk_get_top(ctx)); duk_pop(ctx); DEBUG_LOG("ScriptEngine", "duk_java_property_set key %d ", duk_get_top(ctx)); duk_replace(ctx, 0); DEBUG_LOG("ScriptEngine", "duk_java_property_set key %d ", duk_get_top(ctx)); duk_put_prop_string(ctx, 0, key); DEBUG_LOG("ScriptEngine", "duk_java_property_set key %d ", duk_get_top(ctx)); return 0; } }
void duk_to_fixed_buffer(duk_context *ctx, duk_idx_t index) { duk_hbuffer_dynamic *h_src; duk_uint8_t *data; duk_size_t size; index = duk_require_normalize_index(ctx, index); h_src = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); DUK_ASSERT(h_src != NULL); if (!DUK_HBUFFER_HAS_DYNAMIC(h_src)) { return; } size = DUK_HBUFFER_GET_SIZE(h_src); data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, size); if (size > 0U) { DUK_ASSERT(data != NULL); DUK_MEMCPY(data, DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h_src), size); } duk_replace(ctx, index); }
static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) { duk_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx); FILE *output = (flags & DUK_CONSOLE_STDOUT_ONLY) ? stdout : stderr; duk_idx_t n = duk_get_top(ctx); duk_idx_t i; duk_get_global_string(ctx, "console"); duk_get_prop_string(ctx, -1, "format"); for (i = 0; i < n; i++) { if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) { /* Slow path formatting. */ duk_dup(ctx, -1); /* console.format */ duk_dup(ctx, i); duk_call(ctx, 1); duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */ } } duk_pop_2(ctx); duk_push_string(ctx, " "); duk_insert(ctx, 0); duk_join(ctx, n); if (error_name) { duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1)); duk_push_string(ctx, "name"); duk_push_string(ctx, error_name); duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */ duk_get_prop_string(ctx, -1, "stack"); } fprintf(output, "%s\n", duk_to_string(ctx, -1)); if (flags & DUK_CONSOLE_FLUSH) { fflush(output); } return 0; }
duk_ret_t dukky_html_head_element___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_HTMLELEMENT"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_head_element___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_head_element___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
duk_ret_t dukky_storage_event___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_EVENT"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "key"); duk_push_c_function(ctx, dukky_storage_event_key_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "oldValue"); duk_push_c_function(ctx, dukky_storage_event_oldValue_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "newValue"); duk_push_c_function(ctx, dukky_storage_event_newValue_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "url"); duk_push_c_function(ctx, dukky_storage_event_url_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "storageArea"); duk_push_c_function(ctx, dukky_storage_event_storageArea_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_storage_event___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_storage_event___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
duk_ret_t dukky_html_embed_element___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_HTMLELEMENT"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "getSVGDocument"); duk_push_c_function(ctx, dukky_html_embed_element_getSVGDocument, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "src"); duk_push_c_function(ctx, dukky_html_embed_element_src_getter, 0); duk_push_c_function(ctx, dukky_html_embed_element_src_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "type"); duk_push_c_function(ctx, dukky_html_embed_element_type_getter, 0); duk_push_c_function(ctx, dukky_html_embed_element_type_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "width"); duk_push_c_function(ctx, dukky_html_embed_element_width_getter, 0); duk_push_c_function(ctx, dukky_html_embed_element_width_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "height"); duk_push_c_function(ctx, dukky_html_embed_element_height_getter, 0); duk_push_c_function(ctx, dukky_html_embed_element_height_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "align"); duk_push_c_function(ctx, dukky_html_embed_element_align_getter, 0); duk_push_c_function(ctx, dukky_html_embed_element_align_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "name"); duk_push_c_function(ctx, dukky_html_embed_element_name_getter, 0); duk_push_c_function(ctx, dukky_html_embed_element_name_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_embed_element___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_embed_element___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) { duk_hobject *obj; #if defined(DUK_USE_ES6_PROXY) duk_hobject *h_proxy_target; duk_hobject *h_proxy_handler; duk_hobject *h_trap_result; #endif duk_small_uint_t enum_flags; duk_int_t magic; DUK_ASSERT_TOP(thr, 1); magic = duk_get_current_magic(thr); if (magic == 3) { /* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs * and plain buffers pretend to be objects, so accept those too. */ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); } else { /* ES2015: ToObject coerce. */ obj = duk_to_hobject(thr, 0); } DUK_ASSERT(obj != NULL); DUK_UNREF(obj); /* XXX: proxy chains */ #if defined(DUK_USE_ES6_PROXY) /* XXX: better sharing of code between proxy target call sites */ if (DUK_LIKELY(!duk_hobject_proxy_check(obj, &h_proxy_target, &h_proxy_handler))) { goto skip_proxy; } duk_push_hobject(thr, h_proxy_handler); if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) { /* Careful with reachability here: don't pop 'obj' before pushing * proxy target. */ DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead")); duk_pop_2(thr); duk_push_hobject(thr, h_proxy_target); duk_replace(thr, 0); DUK_ASSERT_TOP(thr, 1); goto skip_proxy; } /* [ obj handler trap ] */ duk_insert(thr, -2); duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */ duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */ h_trap_result = duk_require_hobject(thr, -1); DUK_UNREF(h_trap_result); magic = duk_get_current_magic(thr); DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t))); enum_flags = duk__object_keys_enum_flags[magic]; duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags); return 1; skip_proxy: #endif /* DUK_USE_ES6_PROXY */ DUK_ASSERT_TOP(thr, 1); magic = duk_get_current_magic(thr); DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t))); enum_flags = duk__object_keys_enum_flags[magic]; return duk_hobject_get_enumerated_keys(thr, enum_flags); }
static duk_ret_t test_func(duk_context *ctx, void *udata) { (void) udata; if (ctx) { printf("dummy - return here\n"); fflush(stdout); return 0; } /* Up-to-date for Duktape 1.3.0, alphabetical order: * $ cd website/api; ls *.yaml */ (void) duk_alloc_raw(ctx, 0); (void) duk_alloc(ctx, 0); (void) duk_base64_decode(ctx, 0); (void) duk_base64_encode(ctx, 0); (void) duk_buffer_to_string(ctx, 0); (void) duk_call_method(ctx, 0); (void) duk_call_prop(ctx, 0, 0); (void) duk_call(ctx, 0); (void) duk_char_code_at(ctx, 0, 0); (void) duk_check_stack_top(ctx, 0); (void) duk_check_stack(ctx, 0); (void) duk_check_type_mask(ctx, 0, 0); (void) duk_check_type(ctx, 0, 0); (void) duk_compact(ctx, 0); (void) duk_compile_lstring_filename(ctx, 0, "dummy", 0); (void) duk_compile_lstring(ctx, 0, "dummy", 0); (void) duk_compile_string_filename(ctx, 0, "dummy"); (void) duk_compile_string(ctx, 0, "dummy"); (void) duk_compile(ctx, 0); (void) duk_concat(ctx, 0); (void) duk_config_buffer(ctx, 0, NULL, 0); (void) duk_copy(ctx, 0, 0); (void) duk_create_heap_default(); (void) duk_create_heap(NULL, NULL, NULL, NULL, NULL); (void) duk_debugger_attach(ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); (void) duk_debugger_cooperate(ctx); (void) duk_debugger_detach(ctx); (void) duk_debugger_notify(ctx, 0); (void) duk_debugger_pause(ctx); (void) duk_decode_string(ctx, 0, NULL, NULL); (void) duk_def_prop(ctx, 0, 0); (void) duk_del_prop_index(ctx, 0, 0); (void) duk_del_prop_string(ctx, 0, "dummy"); (void) duk_del_prop(ctx, 0); (void) duk_destroy_heap(ctx); (void) duk_dump_function(ctx); (void) duk_dup_top(ctx); (void) duk_dup(ctx, 0); (void) duk_enum(ctx, 0, 0); (void) duk_equals(ctx, 0, 0); duk_error_va(ctx, 0, NULL, NULL); duk_error(ctx, 0, "dummy"); /* (void) cast won't work without variadic macros */ (void) duk_eval_lstring_noresult(ctx, "dummy", 0); (void) duk_eval_lstring(ctx, "dummy", 0); (void) duk_eval_noresult(ctx); (void) duk_eval_string_noresult(ctx, "dummy"); (void) duk_eval_string(ctx, "dummy"); (void) duk_eval(ctx); (void) duk_fatal(ctx, "dummy"); (void) duk_free_raw(ctx, NULL); (void) duk_free(ctx, NULL); (void) duk_gc(ctx, 0); (void) duk_get_boolean(ctx, 0); (void) duk_get_buffer_data(ctx, 0, NULL); (void) duk_get_buffer(ctx, 0, NULL); (void) duk_get_c_function(ctx, 0); (void) duk_get_context(ctx, 0); (void) duk_get_current_magic(ctx); (void) duk_get_error_code(ctx, 0); (void) duk_get_finalizer(ctx, 0); (void) duk_get_global_string(ctx, 0); (void) duk_get_heapptr(ctx, 0); (void) duk_get_int(ctx, 0); (void) duk_get_length(ctx, 0); (void) duk_get_lstring(ctx, 0, NULL); (void) duk_get_magic(ctx, 0); (void) duk_get_memory_functions(ctx, NULL); (void) duk_get_number(ctx, 0); (void) duk_get_pointer(ctx, 0); (void) duk_get_prop_index(ctx, 0, 0); (void) duk_get_prop_string(ctx, 0, "dummy"); (void) duk_get_prop(ctx, 0); (void) duk_get_prototype(ctx, 0); (void) duk_get_string(ctx, 0); (void) duk_get_top_index(ctx); (void) duk_get_top(ctx); (void) duk_get_type_mask(ctx, 0); (void) duk_get_type(ctx, 0); (void) duk_get_uint(ctx, 0); (void) duk_has_prop_index(ctx, 0, 0); (void) duk_has_prop_string(ctx, 0, "dummy"); (void) duk_has_prop(ctx, 0); (void) duk_hex_decode(ctx, 0); (void) duk_hex_encode(ctx, 0); (void) duk_insert(ctx, 0); (void) duk_instanceof(ctx, 0, 0); (void) duk_is_array(ctx, 0); (void) duk_is_boolean(ctx, 0); (void) duk_is_bound_function(ctx, 0); (void) duk_is_buffer(ctx, 0); (void) duk_is_callable(ctx, 0); (void) duk_is_c_function(ctx, 0); (void) duk_is_constructor_call(ctx); (void) duk_is_dynamic_buffer(ctx, 0); (void) duk_is_ecmascript_function(ctx, 0); (void) duk_is_error(ctx, 0); (void) duk_is_eval_error(ctx, 0); (void) duk_is_fixed_buffer(ctx, 0); (void) duk_is_function(ctx, 0); (void) duk_is_lightfunc(ctx, 0); (void) duk_is_nan(ctx, 0); (void) duk_is_null_or_undefined(ctx, 0); (void) duk_is_null(ctx, 0); (void) duk_is_number(ctx, 0); (void) duk_is_object_coercible(ctx, 0); (void) duk_is_object(ctx, 0); (void) duk_is_pointer(ctx, 0); (void) duk_is_primitive(ctx, 0); (void) duk_is_range_error(ctx, 0); (void) duk_is_reference_error(ctx, 0); (void) duk_is_strict_call(ctx); (void) duk_is_string(ctx, 0); (void) duk_is_syntax_error(ctx, 0); (void) duk_is_thread(ctx, 0); (void) duk_is_type_error(ctx, 0); (void) duk_is_undefined(ctx, 0); (void) duk_is_uri_error(ctx, 0); (void) duk_is_valid_index(ctx, 0); (void) duk_join(ctx, 0); (void) duk_json_decode(ctx, 0); (void) duk_json_encode(ctx, 0); (void) duk_load_function(ctx); (void) duk_map_string(ctx, 0, NULL, NULL); (void) duk_new(ctx, 0); (void) duk_next(ctx, 0, 0); (void) duk_normalize_index(ctx, 0); (void) duk_pcall_method(ctx, 0); (void) duk_pcall_prop(ctx, 0, 0); (void) duk_pcall(ctx, 0); (void) duk_pcompile_lstring_filename(ctx, 0, "dummy", 0); (void) duk_pcompile_lstring(ctx, 0, "dummy", 0); (void) duk_pcompile_string_filename(ctx, 0, "dummy"); (void) duk_pcompile_string(ctx, 0, "dummy"); (void) duk_pcompile(ctx, 0); (void) duk_peval_lstring_noresult(ctx, "dummy", 0); (void) duk_peval_lstring(ctx, "dummy", 0); (void) duk_peval_noresult(ctx); (void) duk_peval_string_noresult(ctx, "dummy"); (void) duk_peval_string(ctx, "dummy"); (void) duk_peval(ctx); (void) duk_pnew(ctx, 0); (void) duk_pop_2(ctx); (void) duk_pop_3(ctx); (void) duk_pop_n(ctx, 0); (void) duk_pop(ctx); (void) duk_push_array(ctx); (void) duk_push_boolean(ctx, 0); (void) duk_push_buffer_object(ctx, 0, 0, 0, 0); (void) duk_push_buffer(ctx, 0, 0); (void) duk_push_c_function(ctx, NULL, 0); (void) duk_push_c_lightfunc(ctx, NULL, 0, 0, 0); (void) duk_push_context_dump(ctx); (void) duk_push_current_function(ctx); (void) duk_push_current_thread(ctx); (void) duk_push_dynamic_buffer(ctx, 0); (void) duk_push_error_object_va(ctx, 0, NULL, NULL); (void) duk_push_error_object(ctx, 0, "dummy"); (void) duk_push_external_buffer(ctx); (void) duk_push_false(ctx); (void) duk_push_fixed_buffer(ctx, 0); (void) duk_push_global_object(ctx); (void) duk_push_global_stash(ctx); (void) duk_push_heap_stash(ctx); (void) duk_push_heapptr(ctx, NULL); (void) duk_push_int(ctx, 0); (void) duk_push_lstring(ctx, "dummy", 0); (void) duk_push_nan(ctx); (void) duk_push_null(ctx); (void) duk_push_number(ctx, 0.0); (void) duk_push_object(ctx); (void) duk_push_pointer(ctx, NULL); (void) duk_push_sprintf(ctx, "dummy"); (void) duk_push_string(ctx, "dummy"); (void) duk_push_this(ctx); (void) duk_push_thread_new_globalenv(ctx); (void) duk_push_thread_stash(ctx, NULL); (void) duk_push_thread(ctx); (void) duk_push_true(ctx); (void) duk_push_uint(ctx, 0); (void) duk_push_undefined(ctx); (void) duk_push_vsprintf(ctx, "dummy", NULL); (void) duk_put_function_list(ctx, 0, NULL); (void) duk_put_global_string(ctx, NULL); (void) duk_put_number_list(ctx, 0, NULL); (void) duk_put_prop_index(ctx, 0, 0); (void) duk_put_prop_string(ctx, 0, "dummy"); (void) duk_put_prop(ctx, 0); (void) duk_realloc_raw(ctx, NULL, 0); (void) duk_realloc(ctx, NULL, 0); (void) duk_remove(ctx, 0); (void) duk_replace(ctx, 0); (void) duk_require_boolean(ctx, 0); (void) duk_require_buffer_data(ctx, 0, NULL); (void) duk_require_buffer(ctx, 0, NULL); (void) duk_require_c_function(ctx, 0); (void) duk_require_callable(ctx, 0); (void) duk_require_context(ctx, 0); (void) duk_require_function(ctx, 0); (void) duk_require_heapptr(ctx, 0); (void) duk_require_int(ctx, 0); (void) duk_require_lstring(ctx, 0, NULL); (void) duk_require_normalize_index(ctx, 0); (void) duk_require_null(ctx, 0); (void) duk_require_number(ctx, 0); (void) duk_require_object_coercible(ctx, 0); (void) duk_require_pointer(ctx, 0); (void) duk_require_stack_top(ctx, 0); (void) duk_require_stack(ctx, 0); (void) duk_require_string(ctx, 0); (void) duk_require_top_index(ctx); (void) duk_require_type_mask(ctx, 0, 0); (void) duk_require_uint(ctx, 0); (void) duk_require_undefined(ctx, 0); (void) duk_require_valid_index(ctx, 0); (void) duk_resize_buffer(ctx, 0, 0); (void) duk_safe_call(ctx, NULL, NULL, 0, 0); (void) duk_safe_to_lstring(ctx, 0, NULL); (void) duk_safe_to_string(ctx, 0); (void) duk_set_finalizer(ctx, 0); (void) duk_set_global_object(ctx); (void) duk_set_magic(ctx, 0, 0); (void) duk_set_prototype(ctx, 0); (void) duk_set_top(ctx, 0); (void) duk_steal_buffer(ctx, 0, NULL); (void) duk_strict_equals(ctx, 0, 0); (void) duk_substring(ctx, 0, 0, 0); (void) duk_swap_top(ctx, 0); (void) duk_swap(ctx, 0, 0); (void) duk_throw(ctx); (void) duk_to_boolean(ctx, 0); (void) duk_to_buffer(ctx, 0, NULL); (void) duk_to_defaultvalue(ctx, 0, 0); (void) duk_to_dynamic_buffer(ctx, 0, NULL); (void) duk_to_fixed_buffer(ctx, 0, NULL); (void) duk_to_int32(ctx, 0); (void) duk_to_int(ctx, 0); (void) duk_to_lstring(ctx, 0, NULL); (void) duk_to_null(ctx, 0); (void) duk_to_number(ctx, 0); (void) duk_to_object(ctx, 0); (void) duk_to_pointer(ctx, 0); (void) duk_to_primitive(ctx, 0, 0); (void) duk_to_string(ctx, 0); (void) duk_to_uint16(ctx, 0); (void) duk_to_uint32(ctx, 0); (void) duk_to_uint(ctx, 0); (void) duk_to_undefined(ctx, 0); (void) duk_trim(ctx, 0); (void) duk_xcopy_top(ctx, NULL, 0); (void) duk_xmove_top(ctx, NULL, 0); printf("never here\n"); fflush(stdout); return 0; }
DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t idx_td; duk_small_int_t i; /* traceback depth fits into 16 bits */ duk_small_int_t t; /* stack type fits into 16 bits */ duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ const char *str_tailcall = " tailcall"; const char *str_strict = " strict"; const char *str_construct = " construct"; const char *str_prevyield = " preventsyield"; const char *str_directeval = " directeval"; const char *str_empty = ""; DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */ DUK_UNREF(thr); duk_push_this(ctx); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA); idx_td = duk_get_top_index(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE); duk_push_this(ctx); /* [ ... this tracedata sep this ] */ /* XXX: skip null filename? */ if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) { /* Current tracedata contains 2 entries per callstack entry. */ for (i = 0; ; i += 2) { duk_int_t pc; duk_int_t line; duk_int_t flags; duk_double_t d; const char *funcname; const char *filename; duk_hobject *h_func; duk_hstring *h_name; duk_require_stack(ctx, 5); duk_get_prop_index(ctx, idx_td, i); duk_get_prop_index(ctx, idx_td, i + 1); d = duk_to_number(ctx, -1); pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); t = (duk_small_int_t) duk_get_type(ctx, -2); if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { /* * Ecmascript/native function call or lightfunc call */ count_func++; /* [ ... v1(func) v2(pc+flags) ] */ h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */ duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME); #if defined(DUK_USE_PC2LINE) line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc); #else line = 0; #endif /* [ ... v1 v2 name filename ] */ /* When looking for .fileName/.lineNumber, blame first * function which has a .fileName. */ if (duk_is_string(ctx, -1)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, line); return 1; } } /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ h_name = duk_get_hstring(ctx, -2); /* may be NULL */ funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); filename = duk_get_string(ctx, -1); filename = filename ? filename : ""; DUK_ASSERT(funcname != NULL); DUK_ASSERT(filename != NULL); if (h_func == NULL) { duk_push_sprintf(ctx, "at %s light%s%s%s%s%s", (const char *) funcname, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) { duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s", (const char *) funcname, (const char *) filename, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } else { duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s", (const char *) funcname, (const char *) filename, (long) line, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ duk_pop_n(ctx, 3); /* -> [ ... str ] */ } else if (t == DUK_TYPE_STRING) { /* * __FILE__ / __LINE__ entry, here 'pc' is line number directly. * Sometimes __FILE__ / __LINE__ is reported as the source for * the error (fileName, lineNumber), sometimes not. */ /* [ ... v1(filename) v2(line+flags) ] */ /* When looking for .fileName/.lineNumber, blame compilation * or C call site unless flagged not to do so. */ if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { duk_pop(ctx); return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, pc); return 1; } } duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal", (const char *) duk_get_string(ctx, -2), (long) pc); duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ duk_pop(ctx); /* -> [ ... str ] */ } else { /* unknown, ignore */ duk_pop_2(ctx); break; } } if (count_func >= DUK_USE_TRACEBACK_DEPTH) { /* Possibly truncated; there is no explicit truncation * marker so this is the best we can do. */ duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS); } } /* [ ... this tracedata sep this str1 ... strN ] */ if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { return 0; } else { /* The 'this' after 'sep' will get ToString() coerced by * duk_join() automatically. We don't want to do that * coercion when providing .fileName or .lineNumber (GH-254). */ duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/); return 1; } }
/* Shared helper for Object.getOwnPropertyNames() and Object.keys(). * Magic: 0=getOwnPropertyNames, 1=Object.keys. */ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; #if defined(DUK_USE_ES6_PROXY) duk_hobject *h_proxy_target; duk_hobject *h_proxy_handler; duk_hobject *h_trap_result; duk_uarridx_t i, len, idx; #endif duk_small_uint_t enum_flags; DUK_ASSERT_TOP(ctx, 1); obj = duk_require_hobject_or_lfunc_coerce(ctx, 0); DUK_ASSERT(obj != NULL); DUK_UNREF(obj); #if defined(DUK_USE_ES6_PROXY) if (DUK_LIKELY(!duk_hobject_proxy_check(thr, obj, &h_proxy_target, &h_proxy_handler))) { goto skip_proxy; } duk_push_hobject(ctx, h_proxy_handler); if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) { /* Careful with reachability here: don't pop 'obj' before pushing * proxy target. */ DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead")); duk_pop_2(ctx); duk_push_hobject(ctx, h_proxy_target); duk_replace(ctx, 0); DUK_ASSERT_TOP(ctx, 1); goto skip_proxy; } /* [ obj handler trap ] */ duk_insert(ctx, -2); duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */ duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */ h_trap_result = duk_require_hobject(ctx, -1); DUK_UNREF(h_trap_result); len = (duk_uarridx_t) duk_get_length(ctx, -1); idx = 0; duk_push_array(ctx); for (i = 0; i < len; i++) { /* [ obj trap_result res_arr ] */ if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) { /* XXX: for Object.keys() we should check enumerability of key */ /* [ obj trap_result res_arr propname ] */ duk_put_prop_index(ctx, -2, idx); idx++; } else { duk_pop(ctx); } } /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result) * should be filtered so that only enumerable keys remain. Enumerability * should be checked with [[GetOwnProperty]] on the original object * (i.e., the proxy in this case). If the proxy has a getOwnPropertyDescriptor * trap, it should be triggered for every property. If the proxy doesn't have * the trap, enumerability should be checked against the target object instead. * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames() * return the same result now for proxy traps. We still do clean up the trap * result, so that Object.keys() and Object.getOwnPropertyNames() will return a * clean array of strings without gaps. */ return 1; skip_proxy: #endif /* DUK_USE_ES6_PROXY */ DUK_ASSERT_TOP(ctx, 1); if (duk_get_current_magic(ctx)) { /* Object.keys */ enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_NO_PROXY_BEHAVIOR; } else { /* Object.getOwnPropertyNames */ enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE | DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_NO_PROXY_BEHAVIOR; } return duk_hobject_get_enumerated_keys(ctx, enum_flags); }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) { duk_idx_t nargs; duk_bool_t have_acc; duk_uint32_t i, len; duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */ /* We're a varargs function because we need to detect whether * initialValue was given or not. */ nargs = duk_get_top(ctx); DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs)); duk_set_top(ctx, 2); len = duk__push_this_obj_len_u32(ctx); if (!duk_is_callable(ctx, 0)) { goto type_error; } /* stack[0] = callback fn * stack[1] = initialValue * stack[2] = object (coerced this) * stack[3] = length (not needed, but not popped above) * stack[4] = accumulator */ have_acc = 0; if (nargs >= 2) { duk_dup(ctx, 1); have_acc = 1; } DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T", (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3))); /* For len == 0, i is initialized to len - 1 which underflows. * The condition (i < len) will then exit the for-loop on the * first round which is correct. Similarly, loop termination * happens by i underflowing. */ for (i = (idx_step >= 0 ? 0 : len - 1); i < len; /* i >= 0 would always be true */ i += idx_step) { DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T", (long) i, (long) len, (long) have_acc, (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, 4))); DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) || (!have_acc && duk_get_top(ctx) == 4)); if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) { continue; } if (!have_acc) { DUK_ASSERT_TOP(ctx, 4); duk_get_prop_index(ctx, 2, (duk_uarridx_t) i); have_acc = 1; DUK_ASSERT_TOP(ctx, 5); } else { DUK_ASSERT_TOP(ctx, 5); duk_dup(ctx, 0); duk_dup(ctx, 4); duk_get_prop_index(ctx, 2, (duk_uarridx_t) i); duk_push_u32(ctx, i); duk_dup(ctx, 2); DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T", (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); duk_call(ctx, 4); DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1))); duk_replace(ctx, 4); DUK_ASSERT_TOP(ctx, 5); } } if (!have_acc) { goto type_error; } DUK_ASSERT_TOP(ctx, 5); return 1; type_error: return DUK_RET_TYPE_ERROR; }
duk_ret_t dukky_document_fragment___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_NODE"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "getElementById"); duk_push_c_function(ctx, dukky_document_fragment_getElementById, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "prepend"); duk_push_c_function(ctx, dukky_document_fragment_prepend, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "append"); duk_push_c_function(ctx, dukky_document_fragment_append, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "query"); duk_push_c_function(ctx, dukky_document_fragment_query, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "queryAll"); duk_push_c_function(ctx, dukky_document_fragment_queryAll, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "querySelector"); duk_push_c_function(ctx, dukky_document_fragment_querySelector, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add a method */ duk_dup(ctx, 0); duk_push_string(ctx, "querySelectorAll"); duk_push_c_function(ctx, dukky_document_fragment_querySelectorAll, DUK_VARARGS); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "children"); duk_push_c_function(ctx, dukky_document_fragment_children_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "firstElementChild"); duk_push_c_function(ctx, dukky_document_fragment_firstElementChild_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "lastElementChild"); duk_push_c_function(ctx, dukky_document_fragment_lastElementChild_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "childElementCount"); duk_push_c_function(ctx, dukky_document_fragment_childElementCount_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_document_fragment___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_document_fragment___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
duk_ret_t dukky_html_table_cell_element___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_HTMLELEMENT"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "colSpan"); duk_push_c_function(ctx, dukky_html_table_cell_element_colSpan_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_colSpan_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "rowSpan"); duk_push_c_function(ctx, dukky_html_table_cell_element_rowSpan_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_rowSpan_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "headers"); duk_push_c_function(ctx, dukky_html_table_cell_element_headers_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_headers_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "cellIndex"); duk_push_c_function(ctx, dukky_html_table_cell_element_cellIndex_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "align"); duk_push_c_function(ctx, dukky_html_table_cell_element_align_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_align_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "axis"); duk_push_c_function(ctx, dukky_html_table_cell_element_axis_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_axis_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "height"); duk_push_c_function(ctx, dukky_html_table_cell_element_height_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_height_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "width"); duk_push_c_function(ctx, dukky_html_table_cell_element_width_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_width_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "ch"); duk_push_c_function(ctx, dukky_html_table_cell_element_ch_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_ch_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "chOff"); duk_push_c_function(ctx, dukky_html_table_cell_element_chOff_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_chOff_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "noWrap"); duk_push_c_function(ctx, dukky_html_table_cell_element_noWrap_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_noWrap_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "vAlign"); duk_push_c_function(ctx, dukky_html_table_cell_element_vAlign_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_vAlign_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "bgColor"); duk_push_c_function(ctx, dukky_html_table_cell_element_bgColor_getter, 0); duk_push_c_function(ctx, dukky_html_table_cell_element_bgColor_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_table_cell_element___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_table_cell_element___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
//void duk_replace(duk_context *ctx, duk_idx_t to_index); void aperl_duk_replace(duk_context *ctx, duk_idx_t to_index) { duk_replace(ctx, to_index); }
static int duk__traceback_getter_helper(duk_context *ctx, int output_type) { duk_hthread *thr = (duk_hthread *) ctx; int idx_td; int i; const char *str_tailcalled = " tailcalled"; const char *str_strict = " strict"; const char *str_construct = " construct"; const char *str_prevyield = " preventsyield"; const char *str_directeval = " directeval"; const char *str_empty = ""; DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */ duk_push_this(ctx); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TRACEDATA); idx_td = duk_get_top_index(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_TAB); duk_push_this(ctx); duk_to_string(ctx, -1); /* [ ... this tracedata sep ToString(this) ] */ /* FIXME: skip null filename? */ if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) { int t; /* Current tracedata contains 2 entries per callstack entry. */ for (i = 0; ; i += 2) { int pc; int line; int flags; double d; const char *funcname; duk_hobject *h_func; duk_hstring *h_name; duk_hbuffer_fixed *pc2line; duk_require_stack(ctx, 5); duk_get_prop_index(ctx, idx_td, i); duk_get_prop_index(ctx, idx_td, i + 1); d = duk_to_number(ctx, -1); pc = (int) fmod(d, DUK_DOUBLE_2TO32); flags = (int) floor(d / DUK_DOUBLE_2TO32); t = duk_get_type(ctx, -2); if (t == DUK_TYPE_OBJECT) { /* * Ecmascript/native function call */ /* [ ... v1(func) v2(pc+flags) ] */ h_func = duk_get_hobject(ctx, -2); DUK_ASSERT(h_func != NULL); duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME); duk_get_prop_stridx(ctx, -4, DUK_STRIDX_INT_PC2LINE); if (duk_is_buffer(ctx, -1)) { pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1); DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line)); line = duk_hobject_pc2line_query(pc2line, (duk_uint_fast32_t) pc); } else { line = 0; } duk_pop(ctx); /* [ ... v1 v2 name filename ] */ if (output_type == DUK__OUTPUT_TYPE_FILENAME) { return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, line); return 1; } h_name = duk_get_hstring(ctx, -2); /* may be NULL */ funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? "anon" : (const char *) DUK_HSTRING_GET_DATA(h_name); if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) { duk_push_sprintf(ctx, "%s %s native%s%s%s%s%s", funcname, duk_get_string(ctx, -1), (flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty, (flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty, (flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty, (flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty, (flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty); } else { duk_push_sprintf(ctx, "%s %s:%d%s%s%s%s%s", funcname, duk_get_string(ctx, -1), line, (flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty, (flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty, (flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty, (flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty, (flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty); } duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ duk_pop_n(ctx, 3); /* -> [ ... str ] */ } else if (t == DUK_TYPE_STRING) { /* * __FILE__ / __LINE__ entry, here 'pc' is line number directly. * Sometimes __FILE__ / __LINE__ is reported as the source for * the error (fileName, lineNumber), sometimes not. */ /* [ ... v1(filename) v2(line+flags) ] */ if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { duk_pop(ctx); return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, pc); return 1; } } duk_push_sprintf(ctx, "%s:%d", duk_get_string(ctx, -2), pc); duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ duk_pop(ctx); /* -> [ ... str ] */ } else { /* unknown, ignore */ duk_pop_2(ctx); break; } } if (i >= DUK_USE_TRACEBACK_DEPTH * 2) { /* Possibly truncated; there is no explicit truncation * marker so this is the best we can do. */ duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS); } } /* [ ... this tracedata sep ToString(this) str1 ... strN ] */ if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { return 0; } else { duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/); return 1; } }
int duk_bi_array_prototype_reduce_shared(duk_context *ctx) { int nargs; int have_acc; int i, len; int idx_step = duk_get_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */ /* We're a varargs function because we need to detect whether * initialValue was given or not. */ nargs = duk_get_top(ctx); DUK_DDD(DUK_DDDPRINT("nargs=%d", nargs)); duk_set_top(ctx, 2); len = duk__push_this_obj_len_u32(ctx); if (!duk_is_callable(ctx, 0)) { goto type_error; } /* stack[0] = callback fn * stack[1] = initialValue * stack[2] = object (coerced this) * stack[3] = length (not needed, but not popped above) * stack[4] = accumulator */ have_acc = 0; if (nargs >= 2) { duk_dup(ctx, 1); have_acc = 1; } DUK_DDD(DUK_DDDPRINT("have_acc=%d, acc=%!T", have_acc, duk_get_tval(ctx, 3))); for (i = (idx_step >= 0 ? 0 : len - 1); i >= 0 && i < len; i += idx_step) { DUK_DDD(DUK_DDDPRINT("i=%d, len=%d, have_acc=%d, top=%d, acc=%!T", i, len, have_acc, duk_get_top(ctx), duk_get_tval(ctx, 4))); DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) || (!have_acc && duk_get_top(ctx) == 4)); if (!duk_has_prop_index(ctx, 2, i)) { continue; } if (!have_acc) { DUK_ASSERT_TOP(ctx, 4); duk_get_prop_index(ctx, 2, i); have_acc = 1; DUK_ASSERT_TOP(ctx, 5); } else { DUK_ASSERT_TOP(ctx, 5); duk_dup(ctx, 0); duk_dup(ctx, 4); duk_get_prop_index(ctx, 2, i); duk_push_int(ctx, i); /* FIXME: type */ duk_dup(ctx, 2); DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T", duk_get_tval(ctx, -5), duk_get_tval(ctx, -4), duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1))); duk_call(ctx, 4); DUK_DDD(DUK_DDDPRINT("-> result: %!T", duk_get_tval(ctx, -1))); duk_replace(ctx, 4); DUK_ASSERT_TOP(ctx, 5); } } if (!have_acc) { goto type_error; } DUK_ASSERT_TOP(ctx, 5); return 1; type_error: return DUK_RET_TYPE_ERROR; }
DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { duk_context *ctx = (duk_context *) thr; duk_hobject *func; duk_hobject *val; duk_hobject *proto; duk_uint_t sanity; /* * Get the values onto the stack first. It would be possible to cover * some normal cases without resorting to the value stack. * * The right hand side could be a light function (as they generally * behave like objects). Light functions never have a 'prototype' * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError. * Using duk_require_hobject() is thus correct (except for error msg). */ duk_push_tval(ctx, tv_x); duk_push_tval(ctx, tv_y); func = duk_require_hobject(ctx, -1); /* * For bound objects, [[HasInstance]] just calls the target function * [[HasInstance]]. If that is again a bound object, repeat until * we find a non-bound Function object. */ /* XXX: this bound function resolution also happens elsewhere, * move into a shared helper. */ sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY; do { /* check func supports [[HasInstance]] (this is checked for every function * in the bound chain, including the final one) */ if (!DUK_HOBJECT_IS_CALLABLE(func)) { /* * Note: of native Ecmascript objects, only Function instances * have a [[HasInstance]] internal property. Custom objects might * also have it, but not in current implementation. * * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF? */ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid instanceof rval"); } if (!DUK_HOBJECT_HAS_BOUND(func)) { break; } /* [ ... lval rval ] */ duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */ duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */ func = duk_require_hobject(ctx, -1); /* func support for [[HasInstance]] checked in the beginning of the loop */ } while (--sanity > 0); if (sanity == 0) { DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, DUK_STR_BOUND_CHAIN_LIMIT); } /* * 'func' is now a non-bound object which supports [[HasInstance]] * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on * to execute E5 Section 15.3.5.3. */ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func)); /* [ ... lval rval(func) ] */ /* Handle lightfuncs through object coercion for now. */ /* XXX: direct implementation */ val = duk_get_hobject_or_lfunc_coerce(ctx, -2); if (!val) { goto pop_and_false; } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */ proto = duk_require_hobject(ctx, -1); duk_pop(ctx); /* -> [ ... lval rval ] */ sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; do { /* * Note: prototype chain is followed BEFORE first comparison. This * means that the instanceof lval is never itself compared to the * rval.prototype property. This is apparently intentional, see E5 * Section 15.3.5.3, step 4.a. * * Also note: * * js> (function() {}) instanceof Function * true * js> Function instanceof Function * true * * For the latter, h_proto will be Function.prototype, which is the * built-in Function prototype. Because Function.[[Prototype]] is * also the built-in Function prototype, the result is true. */ val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); if (!val) { goto pop_and_false; } else if (val == proto) { goto pop_and_true; } /* follow prototype chain */ } while (--sanity > 0); if (sanity == 0) { DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, DUK_STR_PROTOTYPE_CHAIN_LIMIT); } DUK_UNREACHABLE(); pop_and_false: duk_pop_2(ctx); return 0; pop_and_true: duk_pop_2(ctx); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_input; duk_hstring *h_match; duk_hstring *h_search; duk_hobject *h_re; duk_bufwriter_ctx bw_alloc; duk_bufwriter_ctx *bw; #ifdef DUK_USE_REGEXP_SUPPORT duk_bool_t is_regexp; duk_bool_t is_global; #endif duk_bool_t is_repl_func; duk_uint32_t match_start_coff, match_start_boff; #ifdef DUK_USE_REGEXP_SUPPORT duk_int_t match_caps; #endif duk_uint32_t prev_match_end_boff; const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */ duk_size_t tmp_sz; DUK_ASSERT_TOP(ctx, 2); h_input = duk_push_this_coercible_to_string(ctx); DUK_ASSERT(h_input != NULL); bw = &bw_alloc; DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */ DUK_ASSERT_TOP(ctx, 4); /* stack[0] = search value * stack[1] = replace value * stack[2] = input string * stack[3] = result buffer */ h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP); if (h_re) { #ifdef DUK_USE_REGEXP_SUPPORT is_regexp = 1; is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL); if (is_global) { /* start match from beginning */ duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); } #else /* DUK_USE_REGEXP_SUPPORT */ return DUK_RET_UNSUPPORTED_ERROR; #endif /* DUK_USE_REGEXP_SUPPORT */ } else { duk_to_string(ctx, 0); #ifdef DUK_USE_REGEXP_SUPPORT is_regexp = 0; is_global = 0; #endif } if (duk_is_function(ctx, 1)) { is_repl_func = 1; r_start = NULL; r_end = NULL; } else { duk_hstring *h_repl; is_repl_func = 0; h_repl = duk_to_hstring(ctx, 1); DUK_ASSERT(h_repl != NULL); r_start = DUK_HSTRING_GET_DATA(h_repl); r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl); } prev_match_end_boff = 0; for (;;) { /* * If matching with a regexp: * - non-global RegExp: lastIndex not touched on a match, zeroed * on a non-match * - global RegExp: on match, lastIndex will be updated by regexp * executor to point to next char after the matching part (so that * characters in the matching part are not matched again) * * If matching with a string: * - always non-global match, find first occurrence * * We need: * - The character offset of start-of-match for the replacer function * - The byte offsets for start-of-match and end-of-match to implement * the replacement values $&, $`, and $', and to copy non-matching * input string portions (including header and trailer) verbatim. * * NOTE: the E5.1 specification is a bit vague how the RegExp should * behave in the replacement process; e.g. is matching done first for * all matches (in the global RegExp case) before any replacer calls * are made? See: test-bi-string-proto-replace.js for discussion. */ DUK_ASSERT_TOP(ctx, 4); #ifdef DUK_USE_REGEXP_SUPPORT if (is_regexp) { duk_dup(ctx, 0); duk_dup(ctx, 2); duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */ if (!duk_is_object(ctx, -1)) { duk_pop(ctx); break; } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX); DUK_ASSERT(duk_is_number(ctx, -1)); match_start_coff = duk_get_int(ctx, -1); duk_pop(ctx); duk_get_prop_index(ctx, -1, 0); DUK_ASSERT(duk_is_string(ctx, -1)); h_match = duk_get_hstring(ctx, -1); DUK_ASSERT(h_match != NULL); duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */ if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) { /* This should be equivalent to match() algorithm step 8.f.iii.2: * detect an empty match and allow it, but don't allow it twice. */ duk_uint32_t last_index; duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); last_index = (duk_uint32_t) duk_get_uint(ctx, -1); DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld", (long) last_index, (long) (last_index + 1))); duk_pop(ctx); duk_push_int(ctx, last_index + 1); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); } DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */ match_caps = (duk_int_t) duk_get_length(ctx, -1); } else { #else /* DUK_USE_REGEXP_SUPPORT */ { /* unconditionally */ #endif /* DUK_USE_REGEXP_SUPPORT */ const duk_uint8_t *p_start, *p_end, *p; /* input string scan */ const duk_uint8_t *q_start; /* match string */ duk_size_t q_blen; #ifdef DUK_USE_REGEXP_SUPPORT DUK_ASSERT(!is_global); /* single match always */ #endif p_start = DUK_HSTRING_GET_DATA(h_input); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); p = p_start; h_search = duk_get_hstring(ctx, 0); DUK_ASSERT(h_search != NULL); q_start = DUK_HSTRING_GET_DATA(h_search); q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search); p_end -= q_blen; /* ensure full memcmp() fits in while */ match_start_coff = 0; while (p <= p_end) { DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); if (DUK_MEMCMP((void *) p, (void *) q_start, (size_t) q_blen) == 0) { duk_dup(ctx, 0); h_match = duk_get_hstring(ctx, -1); DUK_ASSERT(h_match != NULL); #ifdef DUK_USE_REGEXP_SUPPORT match_caps = 0; #endif goto found; } /* track utf-8 non-continuation bytes */ if ((p[0] & 0xc0) != 0x80) { match_start_coff++; } p++; } /* not found */ break; } found: /* stack[0] = search value * stack[1] = replace value * stack[2] = input string * stack[3] = result buffer * stack[4] = regexp match OR match string */ match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff); tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz); prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match); if (is_repl_func) { duk_idx_t idx_args; duk_hstring *h_repl; /* regexp res_obj is at index 4 */ duk_dup(ctx, 1); idx_args = duk_get_top(ctx); #ifdef DUK_USE_REGEXP_SUPPORT if (is_regexp) { duk_int_t idx; duk_require_stack(ctx, match_caps + 2); for (idx = 0; idx < match_caps; idx++) { /* match followed by capture(s) */ duk_get_prop_index(ctx, 4, idx); } } else { #else /* DUK_USE_REGEXP_SUPPORT */ { /* unconditionally */ #endif /* DUK_USE_REGEXP_SUPPORT */ /* match == search string, by definition */ duk_dup(ctx, 0); } duk_push_int(ctx, match_start_coff); duk_dup(ctx, 2); /* [ ... replacer match [captures] match_char_offset input ] */ duk_call(ctx, duk_get_top(ctx) - idx_args); h_repl = duk_to_hstring(ctx, -1); /* -> [ ... repl_value ] */ DUK_ASSERT(h_repl != NULL); DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl); duk_pop(ctx); /* repl_value */ } else { r = r_start; while (r < r_end) { duk_int_t ch1; duk_int_t ch2; #ifdef DUK_USE_REGEXP_SUPPORT duk_int_t ch3; #endif duk_size_t left; ch1 = *r++; if (ch1 != DUK_ASC_DOLLAR) { goto repl_write; } left = r_end - r; if (left <= 0) { goto repl_write; } ch2 = r[0]; switch ((int) ch2) { case DUK_ASC_DOLLAR: { ch1 = (1 << 8) + DUK_ASC_DOLLAR; goto repl_write; } case DUK_ASC_AMP: { DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match); r++; continue; } case DUK_ASC_GRAVE: { tmp_sz = (duk_size_t) match_start_boff; DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz); r++; continue; } case DUK_ASC_SINGLEQUOTE: { duk_uint32_t match_end_boff; /* Use match charlen instead of bytelen, just in case the input and * match codepoint encodings would have different lengths. */ match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match)); tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); r++; continue; } default: { #ifdef DUK_USE_REGEXP_SUPPORT duk_int_t capnum, captmp, capadv; /* XXX: optional check, match_caps is zero if no regexp, * so dollar will be interpreted literally anyway. */ if (!is_regexp) { goto repl_write; } if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) { goto repl_write; } capnum = ch2 - DUK_ASC_0; capadv = 1; if (left >= 2) { ch3 = r[1]; if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) { captmp = capnum * 10 + (ch3 - DUK_ASC_0); if (captmp < match_caps) { capnum = captmp; capadv = 2; } } } if (capnum > 0 && capnum < match_caps) { DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */ /* regexp res_obj is at offset 4 */ duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum); if (duk_is_string(ctx, -1)) { duk_hstring *h_tmp_str; h_tmp_str = duk_get_hstring(ctx, -1); DUK_ASSERT(h_tmp_str != NULL); DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str); } else { /* undefined -> skip (replaced with empty) */ } duk_pop(ctx); r += capadv; continue; } else { goto repl_write; } #else /* DUK_USE_REGEXP_SUPPORT */ goto repl_write; /* unconditionally */ #endif /* DUK_USE_REGEXP_SUPPORT */ } /* default case */ } /* switch (ch2) */ repl_write: /* ch1 = (r_increment << 8) + byte */ DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff)); r += ch1 >> 8; } /* while repl */ } /* if (is_repl_func) */ duk_pop(ctx); /* pop regexp res_obj or match string */ #ifdef DUK_USE_REGEXP_SUPPORT if (!is_global) { #else { /* unconditionally; is_global==0 */ #endif break; } } /* trailer */ tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff); DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz); DUK_ASSERT_TOP(ctx, 4); DUK_BW_COMPACT(thr, bw); duk_to_string(ctx, -1); return 1; } /* * split() */ /* XXX: very messy now, but works; clean up, remove unused variables (nomimally * used so compiler doesn't complain). */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hstring *h_input; duk_hstring *h_sep; duk_uint32_t limit; duk_uint32_t arr_idx; #ifdef DUK_USE_REGEXP_SUPPORT duk_bool_t is_regexp; #endif duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */ duk_uint32_t prev_match_end_coff, prev_match_end_boff; duk_uint32_t match_start_boff, match_start_coff; duk_uint32_t match_end_boff, match_end_coff; DUK_UNREF(thr); h_input = duk_push_this_coercible_to_string(ctx); DUK_ASSERT(h_input != NULL); duk_push_array(ctx); if (duk_is_undefined(ctx, 1)) { limit = 0xffffffffUL; } else { limit = duk_to_uint32(ctx, 1); } if (limit == 0) { return 1; } /* If the separator is a RegExp, make a "clone" of it. The specification * algorithm calls [[Match]] directly for specific indices; we emulate this * by tweaking lastIndex and using a "force global" variant of duk_regexp_match() * which will use global-style matching even when the RegExp itself is non-global. */ if (duk_is_undefined(ctx, 0)) { /* The spec algorithm first does "R = ToString(separator)" before checking * whether separator is undefined. Since this is side effect free, we can * skip the ToString() here. */ duk_dup(ctx, 2); duk_put_prop_index(ctx, 3, 0); return 1; } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) { #ifdef DUK_USE_REGEXP_SUPPORT duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR); duk_dup(ctx, 0); duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */ duk_replace(ctx, 0); /* lastIndex is initialized to zero by new RegExp() */ is_regexp = 1; #else return DUK_RET_UNSUPPORTED_ERROR; #endif } else { duk_to_string(ctx, 0); #ifdef DUK_USE_REGEXP_SUPPORT is_regexp = 0; #endif } /* stack[0] = separator (string or regexp) * stack[1] = limit * stack[2] = input string * stack[3] = result array */ prev_match_end_boff = 0; prev_match_end_coff = 0; arr_idx = 0; matched = 0; for (;;) { /* * The specification uses RegExp [[Match]] to attempt match at specific * offsets. We don't have such a primitive, so we use an actual RegExp * and tweak lastIndex. Since the RegExp may be non-global, we use a * special variant which forces global-like behavior for matching. */ DUK_ASSERT_TOP(ctx, 4); #ifdef DUK_USE_REGEXP_SUPPORT if (is_regexp) { duk_dup(ctx, 0); duk_dup(ctx, 2); duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */ if (!duk_is_object(ctx, -1)) { duk_pop(ctx); break; } matched = 1; duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX); DUK_ASSERT(duk_is_number(ctx, -1)); match_start_coff = duk_get_int(ctx, -1); match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff); duk_pop(ctx); if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) { /* don't allow an empty match at the end of the string */ duk_pop(ctx); break; } duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); DUK_ASSERT(duk_is_number(ctx, -1)); match_end_coff = duk_get_int(ctx, -1); match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff); duk_pop(ctx); /* empty match -> bump and continue */ if (prev_match_end_boff == match_end_boff) { duk_push_int(ctx, match_end_coff + 1); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); duk_pop(ctx); continue; } } else { #else /* DUK_USE_REGEXP_SUPPORT */ { /* unconditionally */ #endif /* DUK_USE_REGEXP_SUPPORT */ const duk_uint8_t *p_start, *p_end, *p; /* input string scan */ const duk_uint8_t *q_start; /* match string */ duk_size_t q_blen, q_clen; p_start = DUK_HSTRING_GET_DATA(h_input); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); p = p_start + prev_match_end_boff; h_sep = duk_get_hstring(ctx, 0); DUK_ASSERT(h_sep != NULL); q_start = DUK_HSTRING_GET_DATA(h_sep); q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep); q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep); p_end -= q_blen; /* ensure full memcmp() fits in while */ match_start_coff = prev_match_end_coff; if (q_blen == 0) { /* Handle empty separator case: it will always match, and always * triggers the check in step 13.c.iii initially. Note that we * must skip to either end of string or start of first codepoint, * skipping over any continuation bytes! * * Don't allow an empty string to match at the end of the input. */ matched = 1; /* empty separator can always match */ match_start_coff++; p++; while (p < p_end) { if ((p[0] & 0xc0) != 0x80) { goto found; } p++; } goto not_found; } DUK_ASSERT(q_blen > 0 && q_clen > 0); while (p <= p_end) { DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */ if (DUK_MEMCMP((void *) p, (void *) q_start, (duk_size_t) q_blen) == 0) { /* never an empty match, so step 13.c.iii can't be triggered */ goto found; } /* track utf-8 non-continuation bytes */ if ((p[0] & 0xc0) != 0x80) { match_start_coff++; } p++; } not_found: /* not found */ break; found: matched = 1; match_start_boff = (duk_uint32_t) (p - p_start); match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */ match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */ /* empty match (may happen with empty separator) -> bump and continue */ if (prev_match_end_boff == match_end_boff) { prev_match_end_boff++; prev_match_end_coff++; continue; } } /* if (is_regexp) */ /* stack[0] = separator (string or regexp) * stack[1] = limit * stack[2] = input string * stack[3] = result array * stack[4] = regexp res_obj (if is_regexp) */ DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld", (long) match_start_boff, (long) match_start_coff, (long) match_end_boff, (long) match_end_coff, (long) prev_match_end_boff, (long) prev_match_end_coff)); duk_push_lstring(ctx, (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff), (duk_size_t) (match_start_boff - prev_match_end_boff)); duk_put_prop_index(ctx, 3, arr_idx); arr_idx++; if (arr_idx >= limit) { goto hit_limit; } #ifdef DUK_USE_REGEXP_SUPPORT if (is_regexp) { duk_size_t i, len; len = duk_get_length(ctx, 4); for (i = 1; i < len; i++) { DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */ duk_get_prop_index(ctx, 4, (duk_uarridx_t) i); duk_put_prop_index(ctx, 3, arr_idx); arr_idx++; if (arr_idx >= limit) { goto hit_limit; } } duk_pop(ctx); /* lastIndex already set up for next match */ } else { #else /* DUK_USE_REGEXP_SUPPORT */ { /* unconditionally */ #endif /* DUK_USE_REGEXP_SUPPORT */ /* no action */ } prev_match_end_boff = match_end_boff; prev_match_end_coff = match_end_coff; continue; } /* for */ /* Combined step 11 (empty string special case) and 14-15. */ DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld", (long) prev_match_end_boff, (long) prev_match_end_coff)); if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) { /* Add trailer if: * a) non-empty input * b) empty input and no (zero size) match found (step 11) */ duk_push_lstring(ctx, (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff)); duk_put_prop_index(ctx, 3, arr_idx); /* No arr_idx update or limit check */ } return 1; hit_limit: #ifdef DUK_USE_REGEXP_SUPPORT if (is_regexp) { duk_pop(ctx); } #endif return 1; } /* * Various */ #ifdef DUK_USE_REGEXP_SUPPORT DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, duk_bool_t force_new) { duk_hobject *h; /* Shared helper for match() steps 3-4, search() steps 3-4. */ DUK_ASSERT(index >= 0); if (force_new) { goto do_new; } h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP); if (!h) { goto do_new; } return; do_new: duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR); duk_dup(ctx, index); duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */ duk_replace(ctx, index); } #endif /* DUK_USE_REGEXP_SUPPORT */ #ifdef DUK_USE_REGEXP_SUPPORT DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; /* Easiest way to implement the search required by the specification * is to do a RegExp test() with lastIndex forced to zero. To avoid * side effects on the argument, "clone" the RegExp if a RegExp was * given as input. * * The global flag of the RegExp should be ignored; setting lastIndex * to zero (which happens when "cloning" the RegExp) should have an * equivalent effect. */ DUK_ASSERT_TOP(ctx, 1); (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */ duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/); /* stack[0] = regexp * stack[1] = string */ /* Avoid using RegExp.prototype methods, as they're writable and * configurable and may have been changed. */ duk_dup(ctx, 0); duk_dup(ctx, 1); /* [ ... re_obj input ] */ duk_regexp_match(thr); /* -> [ ... res_obj ] */ if (!duk_is_object(ctx, -1)) { duk_push_int(ctx, -1); return 1; } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX); DUK_ASSERT(duk_is_number(ctx, -1)); return 1; } #else /* DUK_USE_REGEXP_SUPPORT */ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) { DUK_UNREF(ctx); return DUK_RET_UNSUPPORTED_ERROR; }
duk_ret_t dukky_html_anchor_element___proto(duk_context *ctx) { /* Set this prototype's prototype (left-parent) */ /* get prototype */ duk_get_global_string(ctx, dukky_magic_string_prototypes); duk_get_prop_string(ctx, -1, "\xFF\xFFNETSURF_DUKTAPE_PROTOTYPE_HTMLELEMENT"); duk_replace(ctx, -2); duk_set_prototype(ctx, 0); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "target"); duk_push_c_function(ctx, dukky_html_anchor_element_target_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_target_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "download"); duk_push_c_function(ctx, dukky_html_anchor_element_download_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_download_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "ping"); duk_push_c_function(ctx, dukky_html_anchor_element_ping_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_ping_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "rel"); duk_push_c_function(ctx, dukky_html_anchor_element_rel_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_rel_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "relList"); duk_push_c_function(ctx, dukky_html_anchor_element_relList_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "hreflang"); duk_push_c_function(ctx, dukky_html_anchor_element_hreflang_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_hreflang_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "type"); duk_push_c_function(ctx, dukky_html_anchor_element_type_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_type_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "text"); duk_push_c_function(ctx, dukky_html_anchor_element_text_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_text_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "coords"); duk_push_c_function(ctx, dukky_html_anchor_element_coords_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_coords_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "charset"); duk_push_c_function(ctx, dukky_html_anchor_element_charset_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_charset_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "name"); duk_push_c_function(ctx, dukky_html_anchor_element_name_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_name_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "rev"); duk_push_c_function(ctx, dukky_html_anchor_element_rev_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_rev_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "shape"); duk_push_c_function(ctx, dukky_html_anchor_element_shape_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_shape_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "href"); duk_push_c_function(ctx, dukky_html_anchor_element_href_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_href_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add readonly property */ duk_dup(ctx, 0); duk_push_string(ctx, "origin"); duk_push_c_function(ctx, dukky_html_anchor_element_origin_getter, 0); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "protocol"); duk_push_c_function(ctx, dukky_html_anchor_element_protocol_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_protocol_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "username"); duk_push_c_function(ctx, dukky_html_anchor_element_username_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_username_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "password"); duk_push_c_function(ctx, dukky_html_anchor_element_password_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_password_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "host"); duk_push_c_function(ctx, dukky_html_anchor_element_host_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_host_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "hostname"); duk_push_c_function(ctx, dukky_html_anchor_element_hostname_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_hostname_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "port"); duk_push_c_function(ctx, dukky_html_anchor_element_port_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_port_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "pathname"); duk_push_c_function(ctx, dukky_html_anchor_element_pathname_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_pathname_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "search"); duk_push_c_function(ctx, dukky_html_anchor_element_search_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_search_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Add read/write property */ duk_dup(ctx, 0); duk_push_string(ctx, "hash"); duk_push_c_function(ctx, dukky_html_anchor_element_hash_getter, 0); duk_push_c_function(ctx, dukky_html_anchor_element_hash_setter, 1); duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE); duk_pop(ctx); /* Set the destructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_anchor_element___destructor, 1); duk_set_finalizer(ctx, -2); duk_pop(ctx); /* Set the constructor */ duk_dup(ctx, 0); duk_push_c_function(ctx, dukky_html_anchor_element___constructor, 2); duk_put_prop_string(ctx, -2, "\xFF\xFFNETSURF_DUKTAPE_INIT"); duk_pop(ctx); return 1; /* The prototype object */ }
DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) { duk_context *ctx; #if defined(DUK_USE_ASSERTIONS) duk_int_t entry_top; #endif ctx = (duk_context *) thr; #if defined(DUK_USE_ASSERTIONS) entry_top = duk_get_top(ctx); #endif /* * If tracebacks are disabled, 'fileName' and 'lineNumber' are added * as plain own properties. Since Error.prototype has accessors of * the same name, we need to define own properties directly (cannot * just use e.g. duk_put_prop_stridx). Existing properties are not * overwritten in case they already exist. */ if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { /* Compiler SyntaxError (or other error) gets the primary blame. * Currently no flag to prevent blaming. */ duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line); duk_push_hstring(ctx, thr->compile_ctx->h_filename); } else if (c_filename && !noblame_fileline) { /* C call site gets blamed next, unless flagged not to do so. * XXX: file/line is disabled in minimal builds, so disable this * too when appropriate. */ duk_push_int(ctx, c_line); duk_push_string(ctx, c_filename); } else { /* Finally, blame the innermost callstack entry which has a * .fileName property. */ duk_small_uint_t depth; duk_int_t i, i_min; duk_uint32_t ecma_line; depth = DUK_USE_TRACEBACK_DEPTH; i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0); DUK_ASSERT(i_min >= 0); DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) { duk_activation *act; duk_hobject *func; duk_uint32_t pc; act = thr_callstack->callstack + i; DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size); func = DUK_ACT_GET_FUNC(act); if (func == NULL) { /* Lightfunc, not blamed now. */ continue; } /* PC points to next instruction, find offending PC, * PC == 0 for native code. */ pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */ DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ act = NULL; /* invalidated by pushes, so get out of the way */ duk_push_hobject(ctx, func); /* [ ... error func ] */ duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME); if (!duk_is_string(ctx, -1)) { duk_pop_2(ctx); continue; } /* [ ... error func fileName ] */ ecma_line = 0; #if defined(DUK_USE_PC2LINE) if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) { ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc); } else { /* Native function, no relevant lineNumber. */ } #endif /* DUK_USE_PC2LINE */ duk_push_u32(ctx, ecma_line); /* [ ... error func fileName lineNumber ] */ duk_replace(ctx, -3); /* [ ... error lineNumber fileName ] */ goto define_props; } /* No activation matches, use undefined for both .fileName and * .lineNumber (matches what we do with a _Tracedata based * no-match lookup. */ duk_push_undefined(ctx); duk_push_undefined(ctx); } define_props: /* [ ... error lineNumber fileName ] */ #if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(duk_get_top(ctx) == entry_top + 2); #endif duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); }
/* Log frontend shared helper, magic value indicates log level. Provides * frontend functions: trace(), debug(), info(), warn(), error(), fatal(). * This needs to have small footprint, reasonable performance, minimal * memory churn, etc. */ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_double_t now; duk_small_int_t entry_lev = duk_get_current_magic(ctx); duk_small_int_t logger_lev; duk_int_t nargs; duk_int_t i; duk_size_t tot_len; const duk_uint8_t *arg_str; duk_size_t arg_len; duk_uint8_t *buf, *p; const duk_uint8_t *q; duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE]; duk_size_t date_len; duk_small_int_t rc; DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5); /* XXX: sanitize to printable (and maybe ASCII) */ /* XXX: better multiline */ /* * Logger arguments are: * * magic: log level (0-5) * this: logger * stack: plain log args * * We want to minimize memory churn so a two-pass approach * is used: first pass formats arguments and computes final * string length, second pass copies strings either into a * pre-allocated and reused buffer (short messages) or into a * newly allocated fixed buffer. If the backend function plays * nice, it won't coerce the buffer to a string (and thus * intern it). */ nargs = duk_get_top(ctx); /* [ arg1 ... argN this ] */ /* * Log level check */ duk_push_this(ctx); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L); logger_lev = (duk_small_int_t) duk_get_int(ctx, -1); if (entry_lev < logger_lev) { return 0; } /* log level could be popped but that's not necessary */ now = duk_bi_date_get_now(ctx); duk_bi_date_format_timeval(now, date_buf); date_len = DUK_STRLEN((const char *) date_buf); duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N); duk_to_string(ctx, -1); DUK_ASSERT(duk_is_string(ctx, -1)); /* [ arg1 ... argN this loggerLevel loggerName ] */ /* * Pass 1 */ /* Line format: <time> <entryLev> <loggerName>: <msg> */ tot_len = 0; tot_len += 3 + /* separators: space, space, colon */ 3 + /* level string */ date_len + /* time */ duk_get_length(ctx, -1); /* loggerName */ for (i = 0; i < nargs; i++) { /* When formatting an argument to a string, errors may happen from multiple * causes. In general we want to catch obvious errors like a toLogString() * throwing an error, but we don't currently try to catch every possible * error. In particular, internal errors (like out of memory or stack) are * not caught. Also, we expect Error toString() to not throw an error. */ if (duk_is_object(ctx, i)) { /* duk_pcall_prop() may itself throw an error, but we're content * in catching the obvious errors (like toLogString() throwing an * error). */ duk_push_hstring_stridx(ctx, DUK_STRIDX_FMT); duk_dup(ctx, i); /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */ /* call: this.fmt(arg) */ rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/); if (rc) { /* Keep the error as the result (coercing it might fail below, * but we don't catch that now). */ ; } duk_replace(ctx, i); } (void) duk_to_lstring(ctx, i, &arg_len); tot_len++; /* sep (even before first one) */ tot_len += arg_len; } /* * Pass 2 */ if (tot_len <= DUK_BI_LOGGER_SHORT_MSG_LIMIT) { duk_hbuffer_dynamic *h_buf; DUK_DDD(DUK_DDDPRINT("reuse existing small log message buffer, tot_len %ld", (long) tot_len)); /* We can assert for all buffer properties because user code * never has access to heap->log_buffer. */ DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); h_buf = thr->heap->log_buffer; DUK_ASSERT(h_buf != NULL); DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_buf)); DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_ALLOC_SIZE(h_buf) == DUK_BI_LOGGER_SHORT_MSG_LIMIT); /* Set buffer 'visible size' to actual message length and * push it to the stack. */ DUK_HBUFFER_SET_SIZE((duk_hbuffer *) h_buf, tot_len); duk_push_hbuffer(ctx, (duk_hbuffer *) h_buf); buf = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf); } else { DUK_DDD(DUK_DDDPRINT("use a one-off large log message buffer, tot_len %ld", (long) tot_len)); buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len); } DUK_ASSERT(buf != NULL); p = buf; DUK_MEMCPY((void *) p, (void *) date_buf, date_len); p += date_len; *p++ = (duk_uint8_t) DUK_ASC_SPACE; q = duk__log_level_strings + (entry_lev * 3); DUK_MEMCPY((void *) p, (void *) q, (duk_size_t) 3); p += 3; *p++ = (duk_uint8_t) DUK_ASC_SPACE; arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len); DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len); p += arg_len; *p++ = (duk_uint8_t) DUK_ASC_COLON; for (i = 0; i < nargs; i++) { *p++ = (duk_uint8_t) DUK_ASC_SPACE; arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len); DUK_ASSERT(arg_str != NULL); DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len); p += arg_len; } DUK_ASSERT(buf + tot_len == p); /* [ arg1 ... argN this loggerLevel loggerName buffer ] */ #if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_LOGGING) /* Do debugger forwarding before raw() because the raw() function * doesn't get the log level right now. */ if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { const char *log_buf; duk_size_t sz_buf; log_buf = (const char *) duk_get_buffer(ctx, -1, &sz_buf); DUK_ASSERT(log_buf != NULL); duk_debug_write_notify(thr, DUK_DBG_CMD_LOG); duk_debug_write_int(thr, (duk_int32_t) entry_lev); duk_debug_write_string(thr, (const char *) log_buf, sz_buf); duk_debug_write_eom(thr); } #endif /* Call this.raw(msg); look up through the instance allows user to override * the raw() function in the instance or in the prototype for maximum * flexibility. */ duk_push_hstring_stridx(ctx, DUK_STRIDX_RAW); duk_dup(ctx, -2); /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */ duk_call_prop(ctx, -6, 1); /* this.raw(buffer) */ return 0; }