static void es_gumbo_find_by_tag_name_r(GumboNode *node, GumboTag tag, duk_context *ctx, int *idxp, es_gumbo_output_t *ego) { if(node->type != GUMBO_NODE_ELEMENT && node->type != GUMBO_NODE_TEMPLATE) return; const GumboElement *e = &node->v.element; if(e->tag == tag) { push_gumbo_node(ctx, node, ego); duk_put_prop_index(ctx, -2, (*idxp)++); } for(int i = 0; i < e->children.length; i++) es_gumbo_find_by_tag_name_r(e->children.data[i], tag, ctx, idxp, ego); }
AJ_Status AJS_RegisterIO(duk_context* ctx, duk_idx_t ioIdx) { duk_idx_t pinIdx; duk_idx_t i; uint16_t numPins = AJS_TargetIO_GetNumPins(); /* * Create base pin protoype */ pinIdx = duk_push_object(ctx); AJS_SetPropertyAccessors(ctx, pinIdx, "functions", NULL, NativeFunctionsGetter); AJS_SetPropertyAccessors(ctx, pinIdx, "info", NULL, NativeInfoGetter); /* * Create the pin objects */ duk_push_array(ctx); for (i = 0; i < numPins; ++i) { AJS_CreateObjectFromPrototype(ctx, pinIdx); duk_push_int(ctx, i); duk_put_prop_string(ctx, -2, "id"); duk_put_prop_index(ctx, -2, i); } duk_put_prop_string(ctx, ioIdx, "pin"); duk_pop(ctx); /* * Register the native functions */ AJS_PutFunctionList(ctx, ioIdx, io_native_functions, TRUE); /* * GPIO attribute constants */ duk_put_number_list(ctx, ioIdx, io_constants); /* * A hidden property for keeping track of triggers */ duk_push_string(ctx, AJS_HIDDEN_PROP("trigs")); duk_push_array(ctx); duk_def_prop(ctx, ioIdx, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); /* * Compact the IO object and set it on the global object */ duk_compact(ctx, ioIdx); duk_dup(ctx, ioIdx); duk_put_global_string(ctx, AJS_IOObjectName); return AJ_OK; }
static duk_ret_t test_putprop_shorthand_a(duk_context *ctx) { duk_eval_string(ctx, "({ foo: 123 })"); duk_push_uint(ctx, 123); duk_put_prop_string(ctx, -2, "bar" "\x00" "quux"); duk_push_uint(ctx, 234); duk_put_prop_index(ctx, -2, 2001); duk_push_uint(ctx, 345); duk_put_prop_lstring(ctx, -2, "nul" "\x00" "keyx", 7); duk_json_encode(ctx, -1); printf("%s\n", duk_to_string(ctx, -1)); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; }
static int ModelImporter_GetAnimations(duk_context* ctx) { duk_push_this(ctx); ModelImporter* importer = js_to_class_instance<ModelImporter>(ctx, -1, 0); PODVector<Animation*> animations; importer->GetAnimations(animations); duk_push_array(ctx); for(unsigned i = 0; i < animations.Size(); i++) { js_push_class_object_instance(ctx, animations[i], 0); duk_put_prop_index(ctx, -2, i); } return 1; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) { /* Note: 'this' is not necessarily an Array object. The push() * algorithm is supposed to work for other kinds of objects too, * so the algorithm has e.g. an explicit update for the 'length' * property which is normally "magical" in arrays. */ duk_uint32_t len; duk_idx_t i, n; n = duk_get_top(ctx); len = duk__push_this_obj_len_u32(ctx); /* [ arg1 ... argN obj length ] */ /* Technically Array.prototype.push() can create an Array with length * longer than 2^32-1, i.e. outside the 32-bit range. The final length * is *not* wrapped to 32 bits in the specification. * * This implementation tracks length with a uint32 because it's much * more practical. * * See: test-bi-array-push-maxlen.js. */ if (len + (duk_uint32_t) n < len) { DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw")); return DUK_RET_RANGE_ERROR; } for (i = 0; i < n; i++) { duk_dup(ctx, i); duk_put_prop_index(ctx, -3, len + i); } len += n; duk_push_u32(ctx, len); duk_dup_top(ctx); duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH); /* [ arg1 ... argN obj length new_length ] */ return 1; }
/* * Structs and arrays have the same representation in JavaScript. Ideally an AllJoyn struct would be * represented as a JavaScript object but struct elements are not named in the wire protocol so * there is no way to map them into object properties. */ static AJ_Status PushContainerArg(duk_context* ctx, uint8_t typeId, AJ_Message* msg) { AJ_Arg arg; AJ_Status status = AJ_UnmarshalContainer(msg, &arg, typeId); if (status == AJ_OK) { int elem = 0; int arrayIndex = duk_push_array(ctx); while (status == AJ_OK) { status = PushArg(ctx, msg); if (status == AJ_OK) { duk_put_prop_index(ctx, arrayIndex, elem++); } } if (status == AJ_ERR_NO_MORE) { status = AJ_OK; } AJ_UnmarshalCloseContainer(msg, &arg); } return status; }
static gboolean gum_append_match (GumAddress address, gsize size, GumDukCore * core) { GumDukScope scope = GUM_DUK_SCOPE_INIT (core); duk_context * ctx = scope.ctx; duk_push_object (ctx); _gum_duk_push_uint64 (ctx, address, core); duk_put_prop_string (ctx, -2, "address"); duk_push_uint (ctx, size); duk_put_prop_string (ctx, -2, "size"); duk_put_prop_index (ctx, -2, (duk_uarridx_t) duk_get_length (ctx, -2)); return TRUE; }
void js_execute() { if(ctx) { /*duk_push_global_object(ctx); duk_push_c_function(ctx, duk_com_printf, 1); duk_put_prop_string(ctx, -2, "Com_Printf"); duk_pop(ctx); */ duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "consolecommand"); int argc = Cmd_Argc()-1; int arr_idx = duk_push_array(ctx); for(int i = 0; i < argc; i++) { duk_push_string(ctx, Cmd_Argv(i)); duk_put_prop_index(ctx, arr_idx, i); } duk_call(ctx, 1); duk_pop(ctx); } }
duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) { duk_hobject *e; duk_uint_fast32_t i; duk_uint_fast32_t idx; DUK_ASSERT(ctx != NULL); DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL); /* Create a temporary enumerator to get the (non-duplicated) key list; * the enumerator state is initialized without being needed, but that * has little impact. */ duk_hobject_enumerator_create(ctx, enum_flags); duk_push_array(ctx); /* [enum_target enum res] */ e = duk_require_hobject(ctx, -2); DUK_ASSERT(e != NULL); idx = 0; for (i = DUK__ENUM_START_INDEX; i < (duk_uint_fast32_t) e->e_next; i++) { duk_hstring *k; k = DUK_HOBJECT_E_GET_KEY(e, i); DUK_ASSERT(k); /* enumerator must have no keys deleted */ /* [enum_target enum res] */ duk_push_hstring(ctx, k); duk_put_prop_index(ctx, -2, idx); idx++; } /* [enum_target enum res] */ duk_remove(ctx, -2); /* [enum_target res] */ return 1; /* return 1 to allow callers to tail call */ }
static int NativeIoUart(duk_context* ctx) { AJ_Status status; uint8_t tx, rx; uint32_t baud; void* uartCtx = NULL; int32_t rxTrigId; int idx; tx = GetPinId(ctx, 0, AJS_IO_FUNCTION_UART_TX); rx = GetPinId(ctx, 1, AJS_IO_FUNCTION_UART_RX); baud = duk_require_int(ctx, 2); duk_pop(ctx); status = AJS_TargetIO_UartOpen(tx, rx, baud, &uartCtx, &rxTrigId); if (status != AJ_OK) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "Failed to open UART device\n"); } idx = NewIOObject(ctx, uartCtx, AJS_IO_FUNCTION_UART, NativeUartFinalizer); duk_push_c_lightfunc(ctx, NativeUartSetTrigger, 2, 0, 0); duk_put_prop_string(ctx, idx, "setTrigger"); duk_push_c_lightfunc(ctx, NativeUartClearTrigger, 1, 0, 0); duk_put_prop_string(ctx, idx, "clearTrigger"); duk_push_c_lightfunc(ctx, NativeUartRead, 2, 0, 0); duk_put_prop_string(ctx, idx, "read"); duk_push_c_lightfunc(ctx, NativeUartWrite, 1, 0, 0); duk_put_prop_string(ctx, idx, "write"); /* * Add the uart I/O object to the triggers array. */ duk_get_global_string(ctx, AJS_IOObjectName); duk_get_prop_string(ctx, -1, AJS_HIDDEN_PROP("trigs")); duk_dup(ctx, idx); duk_put_prop_index(ctx, -2, rxTrigId); duk_pop_2(ctx); return 1; }
static int SetTriggerCallback(duk_context* ctx, int pinFunc, int debounce) { AJ_Status status; int32_t trigId; AJS_IO_PinTriggerCondition condition = (AJS_IO_PinTriggerCondition)duk_require_int(ctx, 0); if (condition == AJS_IO_PIN_TRIGGER_DISABLE) { /* * For backwards compatibility */ return ClearTriggerCallback(ctx, pinFunc, condition); } if (!duk_is_function(ctx, 1)) { duk_error(ctx, DUK_ERR_TYPE_ERROR, "Trigger function required"); } /* * Enable the trigger */ status = AJS_TargetIO_PinEnableTrigger(PinCtxPtr(ctx), pinFunc, condition, &trigId, debounce); if (status != AJ_OK) { duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "Error %s", AJ_StatusText(status)); } duk_get_global_string(ctx, AJS_IOObjectName); duk_get_prop_string(ctx, -1, AJS_HIDDEN_PROP("trigs")); /* * Set the callback function on the pin object */ duk_push_this(ctx); duk_dup(ctx, 1); duk_put_prop_string(ctx, -2, "trigger"); /* * Add the pin object to the triggers array. */ duk_put_prop_index(ctx, -2, trigId); duk_pop_2(ctx); /* * Leave pin object on the stack */ return 1; }
static int es_gumbo_node_attributes(duk_context *ctx) { es_gumbo_node_t *egn = es_get_native_obj(ctx, 0, &es_native_gumbo_node); const GumboNode *node = egn->node; duk_push_array(ctx); if(node->type == GUMBO_NODE_ELEMENT || node->type == GUMBO_NODE_TEMPLATE) { const GumboElement *e = &node->v.element; for(int i = 0; i < e->attributes.length; i++) { GumboAttribute *attrib = e->attributes.data[i]; duk_push_object(ctx); duk_push_string(ctx, attrib->name); duk_put_prop_string(ctx, -2, "name"); duk_push_string(ctx, attrib->value); duk_put_prop_string(ctx, -2, "value"); duk_put_prop_index(ctx, -2, i); } } return 1; }
DUK_EXTERNAL void sjs_vm_setup_args(sjs_vm_t* vm, int argc, char* argv[]) { assert(vm); duk_context* ctx = vm->ctx; duk_get_global_string(ctx, "system"); /* system.argv */ { duk_push_array(ctx); /* -> [ ... system array ] */ for (int i = 0; i < argc; i++) { duk_push_string(ctx, argv[i]); duk_put_prop_index(ctx, -2, i); } duk_put_prop_string(ctx, -2, "argv"); /* -> [ ... system ] */ } duk_pop(ctx); }
int duk_bi_array_prototype_shift(duk_context *ctx) { unsigned int len; unsigned int i; len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); /* FIXME: Throw */ return 0; } duk_get_prop_index(ctx, 0, 0); /* stack[0] = object (this) * stack[1] = ToUint32(length) * stack[2] = elem at index 0 (retval) */ for (i = 1; i < len; i++) { DUK_ASSERT_TOP(ctx, 3); if (duk_get_prop_index(ctx, 0, i)) { /* fromPresent = true */ duk_put_prop_index(ctx, 0, i - 1); /* FIXME: Throw */ } else { /* fromPresent = false */ duk_del_prop_index(ctx, 0, i - 1); duk_pop(ctx); } } duk_del_prop_index(ctx, 0, len - 1); /* FIXME: Throw */ duk_push_number(ctx, (double) (len - 1)); /* FIXME: push uint */ duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); DUK_ASSERT_TOP(ctx, 3); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) { duk_uint32_t len; duk_uint32_t i; len = duk__push_this_obj_len_u32(ctx); if (len == 0) { duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); return 0; } duk_get_prop_index(ctx, 0, 0); /* stack[0] = object (this) * stack[1] = ToUint32(length) * stack[2] = elem at index 0 (retval) */ for (i = 1; i < len; i++) { DUK_ASSERT_TOP(ctx, 3); if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) { /* fromPresent = true */ duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1)); } else { /* fromPresent = false */ duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1)); duk_pop(ctx); } } duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1)); duk_push_u32(ctx, (duk_uint32_t) (len - 1)); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH); DUK_ASSERT_TOP(ctx, 3); return 1; }
void GCObjectPool::EnsureObjectList() { Isolate *isolate = Isolate::GetCurrent(); duk_context *ctx = isolate->GetDukContext(); // 每个 global 对象对应一个 stash 对象 duk_push_global_stash(ctx); duk_get_prop_string(ctx, -1, "__object_list"); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); // Create a new array with one `0` at index `0`. duk_push_array(ctx); duk_push_int(ctx, 0); duk_put_prop_index(ctx, -2, 0); duk_dup_top(ctx); // Store it as "name_" in the heap stash duk_put_prop_string(ctx, -3, "__object_list"); } duk_pop_2(ctx); }
GlobalStash::GlobalStash(const char *name) : name_(name) { Isolate *isolate = Isolate::GetCurrent(); duk_context *ctx = isolate->GetDukContext(); // 每个 global 对象对应一个 stash 对象 duk_push_global_stash(ctx); duk_get_prop_string(ctx, -1, name_); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); // Create a new array with one `0` at index `0`. duk_push_array(ctx); duk_push_int(ctx, 0); duk_put_prop_index(ctx, -2, 0); // Store it as "name_" in the heap stash duk_put_prop_string(ctx, -2, name_); } else { duk_pop(ctx); } duk_pop(ctx); }
static int Light_GetShadowCascade(duk_context* ctx) { duk_push_this(ctx); Light* light = js_to_class_instance<Light>(ctx, -1, 0); const CascadeParameters& parms = light->GetShadowCascade(); duk_push_array(ctx); duk_push_number(ctx, parms.splits_[0]); duk_put_prop_index(ctx, -2, 0); duk_push_number(ctx, parms.splits_[1]); duk_put_prop_index(ctx, -2, 1); duk_push_number(ctx, parms.splits_[2]); duk_put_prop_index(ctx, -2, 2); duk_push_number(ctx, parms.splits_[3]); duk_put_prop_index(ctx, -2, 3); duk_push_number(ctx, parms.fadeStart_); duk_put_prop_index(ctx, -2, 4); duk_push_number(ctx, parms.biasAutoAdjust_); duk_put_prop_index(ctx, -2, 5); return 1; }
void OnSignal(Entity * param0, Entity * param1, const float3 & param2, const float3 & param3, float param4, float param5) { duk_context* ctx = ctx_; duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_OnSignal"); duk_remove(ctx, -2); duk_push_number(ctx, (size_t)key_); duk_push_array(ctx); PushWeakObject(ctx, param0); duk_put_prop_index(ctx, -2, 0); PushWeakObject(ctx, param1); duk_put_prop_index(ctx, -2, 1); PushValueObjectCopy<float3>(ctx, param2, float3_ID, float3_Finalizer); duk_put_prop_index(ctx, -2, 2); PushValueObjectCopy<float3>(ctx, param3, float3_ID, float3_Finalizer); duk_put_prop_index(ctx, -2, 3); duk_push_number(ctx, param4); duk_put_prop_index(ctx, -2, 4); duk_push_number(ctx, param5); duk_put_prop_index(ctx, -2, 5); bool success = duk_pcall(ctx, 2) == 0; if (!success) LogError("[JavaScript] OnSignal: " + GetErrorString(ctx)); duk_pop(ctx); }
static void sjs__setup_system_module(sjs_vm_t* vm) { duk_context* ctx = vm->ctx; /* create system module */ duk_push_object(ctx); duk_put_global_string(ctx, "system"); duk_get_global_string(ctx, "system"); /* -> [ ... system ] */ /* system.versions */ { char duktape_version[16]; duk_push_object(ctx); /* -> [ ... system obj ] */ snprintf(duktape_version, sizeof(duktape_version), "v%ld.%ld.%ld", DUK_VERSION / 10000, DUK_VERSION % 10000 / 100, DUK_VERSION % 100); duk_push_string(ctx, duktape_version); duk_put_prop_string(ctx, -2, "duktape"); duk_push_lstring(ctx, DUK_GIT_COMMIT, 7); duk_put_prop_string(ctx, -2, "duktapeCommit"); duk_push_string(ctx, sjs_version()); duk_put_prop_string(ctx, -2, "sjs"); /* -> [ ... system obj ] */ duk_put_prop_string(ctx, -2, "versions"); /* -> [ ... system ] */ } /* system.env */ { duk_push_object(ctx); /* -> [ ... system obj ] */ for (int i = 0; environ[i]; i++) { const char* e = environ[i]; const char* ptr = strrchr(e, '='); const char* key; const char* value; if (!ptr) { continue; } key = e; value = ptr + 1; duk_push_lstring(ctx, key, (duk_size_t)(ptr - key)); duk_push_string(ctx, value); duk_put_prop(ctx, -3); } /* -> [ ... system obj ] */ duk_put_prop_string(ctx, -2, "env"); /* -> [ ... system ] */ } /* system.path */ { int i = 0; duk_push_array(ctx); /* -> [ ... system array ] */ /* path specified by env variable */ { char* sjs_path = getenv("SJS_PATH"); if (sjs_path) { char* token; char* saveptr; token = strtok_r(sjs_path, ":", &saveptr); for (;;) { if (!token) { break; } duk_push_string(ctx, token); duk_put_prop_index(ctx, -2, i); i++; token = strtok_r(NULL, ":", &saveptr); } } } /* default search paths */ { for (int j = 0; default_search_paths[j]; j++) { duk_push_string(ctx, default_search_paths[j]); duk_put_prop_index(ctx, -2, i); i++; } } duk_put_prop_string(ctx, -2, "path"); /* -> [ ... system ] */ } /* system.arch */ { duk_push_string(ctx, DUK_USE_ARCH_STRING); duk_put_prop_string(ctx, -2, "arch"); } /* system.platform */ { duk_push_string(ctx, DUK_USE_OS_STRING); duk_put_prop_string(ctx, -2, "platform"); } /* system.executable */ { char buf[8192] = {0}; sjs__executable(buf, sizeof(buf)); duk_push_string(ctx, buf); duk_put_prop_string(ctx, -2, "executable"); } /* system.exit(x) */ { duk_push_c_function(ctx, sjs__exit, 1 /* nargs */); duk_put_prop_string(ctx, -2, "exit"); } duk_pop(ctx); }
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_bool_t global; duk_int_t prev_last_index; duk_int_t this_index; duk_int_t arr_idx; DUK_ASSERT_TOP(ctx, 1); (void) duk_push_this_coercible_to_string(ctx); duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/); global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL); DUK_ASSERT_TOP(ctx, 2); /* stack[0] = regexp * stack[1] = string */ if (!global) { duk_regexp_match(thr); /* -> [ res_obj ] */ return 1; /* return 'res_obj' */ } /* Global case is more complex. */ /* [ regexp string ] */ duk_push_int(ctx, 0); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); duk_push_array(ctx); /* [ regexp string res_arr ] */ prev_last_index = 0; arr_idx = 0; for (;;) { DUK_ASSERT_TOP(ctx, 3); duk_dup(ctx, 0); duk_dup(ctx, 1); duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */ if (!duk_is_object(ctx, -1)) { duk_pop(ctx); break; } duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); DUK_ASSERT(duk_is_number(ctx, -1)); this_index = duk_get_int(ctx, -1); duk_pop(ctx); if (this_index == prev_last_index) { this_index++; duk_push_int(ctx, this_index); duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX); } prev_last_index = this_index; duk_get_prop_index(ctx, -1, 0); /* match string */ duk_put_prop_index(ctx, 2, arr_idx); arr_idx++; duk_pop(ctx); /* res_obj */ } if (arr_idx == 0) { duk_push_null(ctx); } return 1; /* return 'res_arr' or 'null' */ }
/* Raw helper to extract internal information / statistics about a value. * The return values are version specific and must not expose anything * that would lead to security issues (e.g. exposing compiled function * 'data' buffer might be an issue). Currently only counts and sizes and * such are given so there should not be a security impact. */ duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) { duk_tval *tv; duk_heaphdr *h; duk_int_t i, n; tv = duk_get_tval(ctx, 0); DUK_ASSERT(tv != NULL); /* because arg count is 1 */ duk_push_array(ctx); /* -> [ val arr ] */ /* type tag (public) */ duk_push_int(ctx, duk_get_type(ctx, 0)); /* address */ if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { h = DUK_TVAL_GET_HEAPHDR(tv); duk_push_pointer(ctx, (void *) h); } else { goto done; } DUK_ASSERT(h != NULL); /* refcount */ #ifdef DUK_USE_REFERENCE_COUNTING duk_push_int(ctx, DUK_HEAPHDR_GET_REFCOUNT(h)); #else duk_push_undefined(ctx); #endif /* heaphdr size and additional allocation size, followed by * type specific stuff (with varying value count) */ switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { case DUK_HTYPE_STRING: { duk_hstring *h_str = (duk_hstring *) h; duk_push_int(ctx, (int) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1)); break; } case DUK_HTYPE_OBJECT: { duk_hobject *h_obj = (duk_hobject *) h; duk_int_t hdr_size; if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) { hdr_size = (duk_int_t) sizeof(duk_hcompiledfunction); } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) { hdr_size = (duk_int_t) sizeof(duk_hnativefunction); } else if (DUK_HOBJECT_IS_THREAD(h_obj)) { hdr_size = (duk_int_t) sizeof(duk_hthread); } else { hdr_size = (duk_int_t) sizeof(duk_hobject); } duk_push_int(ctx, (int) hdr_size); duk_push_int(ctx, (int) DUK_HOBJECT_E_ALLOC_SIZE(h_obj)); duk_push_int(ctx, (int) h_obj->e_size); duk_push_int(ctx, (int) h_obj->e_used); duk_push_int(ctx, (int) h_obj->a_size); duk_push_int(ctx, (int) h_obj->h_size); if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) { duk_hbuffer *h_data = ((duk_hcompiledfunction *) h_obj)->data; if (h_data) { duk_push_int(ctx, DUK_HBUFFER_GET_SIZE(h_data)); } else { duk_push_int(ctx, 0); } } break; } case DUK_HTYPE_BUFFER: { duk_hbuffer *h_buf = (duk_hbuffer *) h; if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) { /* XXX: when usable_size == 0, dynamic buf ptr may now be NULL, in which case * the second allocation does not exist. */ duk_hbuffer_dynamic *h_dyn = (duk_hbuffer_dynamic *) h; duk_push_int(ctx, (int) (sizeof(duk_hbuffer_dynamic))); duk_push_int(ctx, (int) (DUK_HBUFFER_DYNAMIC_GET_ALLOC_SIZE(h_dyn))); } else { duk_push_int(ctx, (int) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1)); } break; } } done: /* set values into ret array */ /* FIXME: primitive to make array from valstack slice */ n = duk_get_top(ctx); for (i = 2; i < n; i++) { duk_dup(ctx, i); duk_put_prop_index(ctx, 1, i - 2); } duk_dup(ctx, 1); return 1; }
//duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); duk_bool_t aperl_duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { duk_bool_t ret = duk_put_prop_index(ctx, obj_index, arr_index); return ret; }
/* FIXME: the implementation now assumes "chained" bound functions, * whereas "collapsed" bound functions (where there is ever only * one bound function which directly points to a non-bound, final * function) would require a "collapsing" implementation which * merges argument lists etc here. */ int duk_bi_function_prototype_bind(duk_context *ctx) { duk_hobject *h_target; int nargs; int i; /* FIXME: stack checks */ /* vararg function, careful arg handling (e.g. thisArg may not be present) */ nargs = duk_get_top(ctx); /* = 1 + arg count */ if (nargs == 0) { duk_push_undefined(ctx); nargs++; } DUK_ASSERT(nargs >= 1); duk_push_this(ctx); if (!duk_is_callable(ctx, -1)) { DUK_DDD(DUK_DDDPRINT("func is not callable")); goto type_error; } /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */ DUK_ASSERT_TOP(ctx, nargs + 1); /* create bound function object */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_BOUND | DUK_HOBJECT_FLAG_CONSTRUCTABLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), DUK_BIDX_FUNCTION_PROTOTYPE); /* FIXME: check hobject flags (e.g. strict) */ /* [ thisArg arg1 ... argN func boundFunc ] */ duk_dup(ctx, -2); /* func */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); duk_dup(ctx, 0); /* thisArg */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); duk_push_array(ctx); /* [ thisArg arg1 ... argN func boundFunc argArray ] */ for (i = 0; i < nargs - 1; i++) { duk_dup(ctx, 1 + i); duk_put_prop_index(ctx, -2, i); } duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE); /* [ thisArg arg1 ... argN func boundFunc ] */ /* bound function 'length' property is interesting */ h_target = duk_get_hobject(ctx, -2); DUK_ASSERT(h_target != NULL); if (DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) { int tmp; duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH); tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */ duk_pop(ctx); duk_push_int(ctx, (tmp < 0 ? 0 : tmp)); } else { duk_push_int(ctx, 0); } duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */ /* caller and arguments must use the same thrower, [[ThrowTypeError]] */ duk_def_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE); duk_def_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE); /* these non-standard properties are copied for convenience */ /* FIXME: 'copy properties' API call? */ duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC); duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", duk_get_tval(ctx, -1))); return 1; type_error: return DUK_RET_TYPE_ERROR; }
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; }
/* XXX: the implementation now assumes "chained" bound functions, * whereas "collapsed" bound functions (where there is ever only * one bound function which directly points to a non-bound, final * function) would require a "collapsing" implementation which * merges argument lists etc here. */ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) { duk_hobject *h_bound; duk_hobject *h_target; duk_idx_t nargs; duk_idx_t i; /* vararg function, careful arg handling (e.g. thisArg may not be present) */ nargs = duk_get_top(ctx); /* = 1 + arg count */ if (nargs == 0) { duk_push_undefined(ctx); nargs++; } DUK_ASSERT(nargs >= 1); duk_push_this(ctx); if (!duk_is_callable(ctx, -1)) { DUK_DDD(DUK_DDDPRINT("func is not callable")); goto type_error; } /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */ DUK_ASSERT_TOP(ctx, nargs + 1); /* create bound function object */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_FLAG_BOUND | DUK_HOBJECT_FLAG_CONSTRUCTABLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION), DUK_BIDX_FUNCTION_PROTOTYPE); h_bound = duk_get_hobject(ctx, -1); DUK_ASSERT(h_bound != NULL); /* [ thisArg arg1 ... argN func boundFunc ] */ duk_dup(ctx, -2); /* func */ duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); duk_dup(ctx, 0); /* thisArg */ duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); duk_push_array(ctx); /* [ thisArg arg1 ... argN func boundFunc argArray ] */ for (i = 0; i < nargs - 1; i++) { duk_dup(ctx, 1 + i); duk_put_prop_index(ctx, -2, i); } duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE); /* [ thisArg arg1 ... argN func boundFunc ] */ /* bound function 'length' property is interesting */ h_target = duk_get_hobject(ctx, -2); if (h_target == NULL || /* lightfunc */ DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) { /* For lightfuncs, simply read the virtual property. */ duk_int_t tmp; duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH); tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */ duk_pop(ctx); duk_push_int(ctx, (tmp < 0 ? 0 : tmp)); } else { duk_push_int(ctx, 0); } duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */ /* caller and arguments must use the same thrower, [[ThrowTypeError]] */ duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE); duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE); /* these non-standard properties are copied for convenience */ /* XXX: 'copy properties' API call? */ duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC); duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); /* The 'strict' flag is copied to get the special [[Get]] of E5.1 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound * function. Not sure if this is correct, because the specification * is a bit ambiguous on this point but it would make sense. */ if (h_target == NULL) { /* Lightfuncs are always strict. */ DUK_HOBJECT_SET_STRICT(h_bound); } else if (DUK_HOBJECT_HAS_STRICT(h_target)) { DUK_HOBJECT_SET_STRICT(h_bound); } DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1))); return 1; type_error: return DUK_RET_TYPE_ERROR; }
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; }
static int Octree_Raycast(duk_context* ctx) { bool single = duk_get_current_magic(ctx) == DUK_MAGIC_RAYCAST_SINGLE; duk_idx_t nargs = duk_get_top(ctx); // require at least the ray if (nargs < 1) { duk_push_undefined(ctx); return 1; } Ray ray; if (!duk_get_ray(ctx, 0, ray)) { duk_push_undefined(ctx); return 1; } RayQueryLevel level = RAY_TRIANGLE; if (nargs > 1) { unsigned _level = (unsigned) duk_to_number(ctx, 1); if (_level > (unsigned) RAY_TRIANGLE_UV) { duk_push_undefined(ctx); return 1; } level = (RayQueryLevel) _level; } float maxDistance = M_INFINITY; if (nargs > 2) { maxDistance = (float) duk_to_number(ctx, 2); } unsigned char drawableFlags = DRAWABLE_ANY; if (nargs > 3) { drawableFlags = (unsigned char) duk_to_number(ctx, 3); } unsigned viewMask = DEFAULT_VIEWMASK; if (nargs > 4) { viewMask = (unsigned) duk_to_number(ctx, 4); } duk_push_this(ctx); Octree* octree = js_to_class_instance<Octree>(ctx, -1, 0); PODVector<RayQueryResult> result; RayOctreeQuery query(result, ray, level, maxDistance, drawableFlags, viewMask); single ? octree->RaycastSingle(query) : octree->Raycast(query); // handle case of nothing hit if (!result.Size()) { if (single) duk_push_null(ctx); else duk_push_array(ctx); return 1; } else { if (single) { duk_push_rayqueryresult(ctx, result[0]); } else { duk_push_array(ctx); for (unsigned i = 0; i < result.Size(); i++) { duk_push_rayqueryresult(ctx, result[i]); duk_put_prop_index(ctx, -2, i); } } } return 1; }
static duk_ret_t test_basic(duk_context *ctx) { duk_idx_t i, n; void *ptr; void *p1, *p2, *p3; duk_int_t ret; duk_push_undefined(ctx); duk_push_null(ctx); duk_push_boolean(ctx, 1); duk_push_number(ctx, 123.0); duk_push_string(ctx, "test string"); duk_eval_string(ctx, "({ foo: 'bar' })"); duk_eval_string(ctx, "Duktape.dec('hex', 'deadbeef');"); /* buffer */ /* Print pointer NULL/non-NULL */ n = duk_get_top(ctx); for (i = 0; i < n + 1; i++) { /* Note: access i == n on purpose (invalid index) */ ptr = duk_get_heapptr(ctx, i); printf("top: %ld\n", (long) duk_get_top(ctx)); printf("idx %ld: type %ld, duk_get_heapptr() -> %s\n", (long) i, (long) duk_get_type(ctx, i), (ptr ? "non-NULL" : "NULL")); duk_push_uint(ctx, (duk_uint_t) i); ret = duk_safe_call(ctx, raw_require_heapptr, 1 /*nargs*/, 1 /*nrets*/); if (ret == DUK_EXEC_SUCCESS) { ; } else { printf("idx %ld: type %ld, duk_require_heapptr() -> %s\n", (long) i, (long) duk_get_type(ctx, i), duk_safe_to_string(ctx, -1)); } duk_pop(ctx); } /* Write the values to the global stash to simulate whatever * reachability mechanisms user code uses. */ n = duk_get_top(ctx); duk_push_global_stash(ctx); for (i = 0; i < n; i++) { duk_dup(ctx, i); duk_put_prop_index(ctx, -2, (duk_uarridx_t) i); } /* Get borrowed references */ p1 = duk_get_heapptr(ctx, 4); p2 = duk_get_heapptr(ctx, 5); p3 = duk_get_heapptr(ctx, 6); /* Erase value stack, simulating user code moving on and relying on * stashed values keeping the target values reachable. Force a GC * for good measure. */ duk_set_top(ctx, 0); duk_gc(ctx, 0); /* Push the values back one by one and test that they're intact. */ duk_eval_string(ctx, "(function (v) { print(Duktape.enc('jx', v)); })"); duk_dup_top(ctx); duk_push_heapptr(ctx, p1); duk_call(ctx, 1); duk_pop(ctx); duk_dup_top(ctx); duk_push_heapptr(ctx, p2); duk_call(ctx, 1); duk_pop(ctx); duk_dup_top(ctx); duk_push_heapptr(ctx, p3); duk_call(ctx, 1); duk_pop(ctx); duk_dup_top(ctx); duk_push_heapptr(ctx, NULL); duk_call(ctx, 1); duk_pop(ctx); duk_pop(ctx); /* Done. */ printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; }
/* 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); }