static duk_ret_t test_is_prototype_of(duk_context *ctx, void *udata) { (void) udata; prep(ctx); /* obj0.isPrototypeOf(dummy) -> false, traverses prototype chain of dummy */ duk_eval_string(ctx, "Object.prototype.isPrototypeOf"); duk_dup(ctx, 0); duk_push_object(ctx); duk_call_method(ctx, 1); printf("Object.prototype.isPrototypeOf result: %s\n", duk_safe_to_string(ctx, -1)); duk_pop(ctx); /* obj0.isPrototypeOf(obj1) -> true, traverses prototype chain of obj1 */ duk_eval_string(ctx, "Object.prototype.isPrototypeOf"); duk_dup(ctx, 0); duk_dup(ctx, 1); duk_call_method(ctx, 1); printf("Object.prototype.isPrototypeOf result: %s\n", duk_safe_to_string(ctx, -1)); duk_pop(ctx); /* dummy.isPrototypeOf(obj0) -> traverses prototype chain of obj0 and throws */ duk_eval_string(ctx, "Object.prototype.isPrototypeOf"); duk_push_object(ctx); duk_dup(ctx, 0); duk_call_method(ctx, 1); printf("Object.prototype.isPrototypeOf result: %s\n", duk_safe_to_string(ctx, -1)); duk_pop(ctx); return 0; }
// Given a module and js code, compile the code and execute as CJS module // return the result of the compiled code ran as a function. static duk_ret_t duv_mod_compile(duk_context *ctx) { // Check the args const duv_schema_entry schema[] = { { "code", dschema_is_data }, { NULL, NULL } }; dschema_check(ctx, schema); duk_to_string(ctx, 0); duk_push_this(ctx); duk_get_prop_string(ctx, -1, "id"); // Wrap the code duk_push_string(ctx, "function(){var module=this,exports=this.exports,require=this.require.bind(this);"); duk_dup(ctx, 0); duk_push_string(ctx, "}"); duk_concat(ctx, 3); duk_insert(ctx, -2); // Compile to a function duk_compile(ctx, DUK_COMPILE_FUNCTION); duk_push_this(ctx); duk_call_method(ctx, 0); return 1; }
static void duv_walk_cb(uv_handle_t *handle, duk_context *ctx) { duv_handle_t* data = handle->data; duk_dup(ctx, 0); duv_push_ref(ctx, data->context); duv_push_ref(ctx, data->ref); duk_call_method(ctx, 1); }
void test(duk_context *ctx) { int i, n; duk_push_c_function(ctx, func, 0); duk_push_undefined(ctx); duk_push_null(ctx); duk_push_true(ctx); duk_push_false(ctx); duk_push_number(ctx, 123.456); duk_push_string(ctx, "foo"); duk_push_object(ctx); duk_push_array(ctx); duk_push_fixed_buffer(ctx, 16); duk_push_pointer(ctx, (void *) 0xdeadbeef); n = duk_get_top(ctx); printf("top: %d\n", n); for (i = 1; i < n; i++) { duk_dup(ctx, 0); duk_dup(ctx, i); duk_call_method(ctx, 0); /* [ ... func this ] -> [ ret ] */ duk_pop(ctx); } }
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) { duk_idx_t nargs; /* Step 1 is not necessary because duk_call_method() will take * care of it. */ /* vararg function, thisArg needs special handling */ nargs = duk_get_top(ctx); /* = 1 + arg count */ if (nargs == 0) { duk_push_undefined(ctx); nargs++; } DUK_ASSERT(nargs >= 1); /* [ thisArg arg1 ... argN ] */ duk_push_this(ctx); /* 'func' in the algorithm */ duk_insert(ctx, 0); /* [ func thisArg arg1 ... argN ] */ DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld", (duk_tval *) duk_get_tval(ctx, 0), (duk_tval *) duk_get_tval(ctx, 1), (long) (nargs - 1), (long) duk_get_top(ctx))); duk_call_method(ctx, nargs - 1); return 1; }
static int sjs__compile_execute(duk_context *ctx) { const char *code; const char* filename; duk_size_t len; bool use_strict; int flags; /* [ ... use_strict code len filename ] */ use_strict = duk_require_boolean(ctx, -4); code = duk_require_pointer(ctx, -3); len = duk_require_uint(ctx, -2); filename = duk_require_string(ctx, -1); flags = 0; if (use_strict) { flags |= DUK_COMPILE_STRICT; } /* remove shebang if present */ if (strncmp(code, "#!", 2) == 0) { memcpy((void*) code, "//", 2); } duk_compile_lstring_filename(ctx, flags, code, len); /* [ ... use_strict code len function ] */ duk_push_global_object(ctx); /* 'this' binding */ duk_push_string(ctx, filename); duk_put_prop_string(ctx, -2, "__file__"); duk_call_method(ctx, 0); return 1; /* either the result or error are on the stack top */ }
int wrapped_compile_execute(duk_context *ctx) { int comp_flags; comp_flags = 0; duk_compile(ctx, comp_flags); #if 0 /* FIXME: something similar with public API */ if (interactive_mode) { duk_hcompiledfunction *f = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1); if (f && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) f)) { fprintf(stdout, "[bytecode length %d opcodes, registers %d, constants %d, inner functions %d]\n", (int) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(f), (int) f->nregs, (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(f), (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(f)); fflush(stdout); } else { fprintf(stdout, "[invalid compile result]\n"); fflush(stdout); } } #endif duk_push_global_object(ctx); /* 'this' binding */ duk_call_method(ctx, 0); if (interactive_mode) { /* * In interactive mode, write to stdout so output won't interleave as easily. * * NOTE: the ToString() coercion may fail in some cases; for instance, * if you evaluate: * * ( {valueOf: function() {return {}}, toString: function() {return {}}}); * * The error is: * * TypeError: failed to coerce with [[DefaultValue]] * duk_api.c:1420 * * These errors are caught and printed out as errors although * the errors are not generated by user code as such. Changing * duk_to_string() to duk_safe_to_string() would avoid these * errors. */ fprintf(stdout, "= %s\n", duk_to_string(ctx, -1)); fflush(stdout); } else { /* In non-interactive mode, success results are not written at all. * It is important that the result value is not string coerced, * as the string coercion may cause an error in some cases. */ } duk_pop(ctx); return 0; }
DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) { /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */ static const duk_uint16_t stridx_logfunc[6] = { DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO, DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL }; DUK_ASSERT_CTX_VALID(ctx); if (level < 0) { level = 0; } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) { level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1; } duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG); duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]); duk_dup(ctx, -2); /* [ ... Logger clog logfunc clog ] */ duk_push_vsprintf(ctx, fmt, ap); /* [ ... Logger clog logfunc clog(=this) msg ] */ duk_call_method(ctx, 1 /*nargs*/); /* [ ... Logger clog res ] */ duk_pop_3(ctx); }
void duk_eval_file(duk_context *ctx, const char *path) { duk_push_string_file_raw(ctx, path, 0); duk_push_string(ctx, path); duk_compile(ctx, DUK_COMPILE_EVAL); duk_push_global_object(ctx); /* 'this' binding */ duk_call_method(ctx, 0); }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) { (void) duk_push_this_coercible_to_object(ctx); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN); /* [ ... this func ] */ if (!duk_is_callable(ctx, -1)) { /* Fall back to the initial (original) Object.toString(). We don't * currently have pointers to the built-in functions, only the top * level global objects (like "Array") so this is now done in a bit * of a hacky manner. It would be cleaner to push the (original) * function and use duk_call_method(). */ /* XXX: 'this' will be ToObject() coerced twice, which is incorrect * but should have no visible side effects. */ DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString")); duk_set_top(ctx, 0); return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */ } /* [ ... this func ] */ duk_insert(ctx, -2); /* [ ... func this ] */ DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT", (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); duk_call_method(ctx, 0); return 1; }
static int wrapped_compile_execute(duk_context *ctx) { duk_compile (ctx, 0); duk_push_global_object (ctx); duk_call_method (ctx, 0); // return value is stored here duk_to_string(ctx, -1); duk_pop (ctx); return 0; }
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) { duk_idx_t len; duk_idx_t i; DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */ duk_push_this(ctx); if (!duk_is_callable(ctx, -1)) { DUK_DDD(DUK_DDDPRINT("func is not callable")); goto type_error; } duk_insert(ctx, 0); DUK_ASSERT_TOP(ctx, 3); DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT", (duk_tval *) duk_get_tval(ctx, 0), (duk_tval *) duk_get_tval(ctx, 1), (duk_tval *) duk_get_tval(ctx, 2))); /* [ func thisArg argArray ] */ if (duk_is_null_or_undefined(ctx, 2)) { DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args")); len = 0; } else if (!duk_is_object(ctx, 2)) { goto type_error; } else { DUK_DDD(DUK_DDDPRINT("argArray is an object")); /* XXX: make this an internal helper */ duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH); len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */ duk_pop(ctx); duk_require_stack(ctx, len); DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len)); for (i = 0; i < len; i++) { duk_get_prop_index(ctx, 2, i); } } duk_remove(ctx, 2); DUK_ASSERT_TOP(ctx, 2 + len); /* [ func thisArg arg1 ... argN ] */ DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld", (duk_tval *) duk_get_tval(ctx, 0), (duk_tval *) duk_get_tval(ctx, 1), (long) len)); duk_call_method(ctx, len); return 1; type_error: return DUK_RET_TYPE_ERROR; }
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) { DUK_ASSERT_TOP(thr, 0); (void) duk_push_this_coercible_to_object(thr); duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING); #if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */ duk_require_callable(thr, 1); #endif duk_dup_0(thr); /* -> [ O toString O ] */ duk_call_method(thr, 0); /* XXX: call method tail call? */ return 1; }
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) { DUK_ASSERT_TOP(ctx, 0); (void) duk_push_this_coercible_to_object(ctx); duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING); if (!duk_is_callable(ctx, 1)) { return DUK_RET_TYPE_ERROR; } duk_dup(ctx, 0); /* -> [ O toString O ] */ duk_call_method(ctx, 0); /* XXX: call method tailcall? */ return 1; }
static int NativeGetAllProps(duk_context* ctx) { if (!duk_is_string(ctx, 0)) { duk_error(ctx, DUK_ERR_TYPE_ERROR, "First argument must be the interface name"); } duk_push_c_lightfunc(ctx, AJS_MarshalMethodCall, 1, 0, 0); duk_push_this(ctx); MessageSetup(ctx, &AJ_PropertiesIface[0][1], "GetAll", NULL, AJ_MSG_METHOD_CALL); duk_dup(ctx, 0); duk_call_method(ctx, 1); return 1; }
static int wrapped_compile_execute(duk_context *ctx) { int comp_flags; /* XXX: Here it'd be nice to get some stats for the compilation result * when a suitable command line is given (e.g. code size, constant * count, function count. These are available internally but not through * the public API. */ comp_flags = 0; duk_compile(ctx, comp_flags); duk_push_global_object(ctx); /* 'this' binding */ duk_call_method(ctx, 0); if (interactive_mode) { /* * In interactive mode, write to stdout so output won't * interleave as easily. * * NOTE: the ToString() coercion may fail in some cases; * for instance, if you evaluate: * * ( {valueOf: function() {return {}}, * toString: function() {return {}}}); * * The error is: * * TypeError: failed to coerce with [[DefaultValue]] * duk_api.c:1420 * * These are handled now by the caller which also has stack * trace printing support. User code can print out errors * safely using duk_safe_to_string(). */ fprintf(stdout, "= %s\n", duk_to_string(ctx, -1)); fflush(stdout); } else { /* In non-interactive mode, success results are not written at all. * It is important that the result value is not string coerced, * as the string coercion may cause an error in some cases. */ } duk_pop(ctx); return 0; }
DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { /* * XXX: if duk_handle_call() took values through indices, this could be * made much more sensible. However, duk_handle_call() needs to fudge * the 'this' and 'func' values to handle bound function chains, which * is now done "in-place", so this is not a trivial change. */ DUK_ASSERT_CTX_VALID(ctx); obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */ duk__call_prop_prep_stack(ctx, obj_idx, nargs); duk_call_method(ctx, nargs); }
/* Default function to format objects. Tries to use toLogString() but falls * back to toString(). Any errors are propagated out without catching. */ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) { if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) { /* [ arg toLogString ] */ duk_dup(ctx, 0); duk_call_method(ctx, 0); /* [ arg result ] */ return 1; } /* [ arg undefined ] */ duk_pop(ctx); duk_to_string(ctx, 0); return 1; }
DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx, void *udata) { duk_idx_t obj_idx; duk_idx_t nargs; duk__pcall_prop_args *args; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(udata != NULL); args = (duk__pcall_prop_args *) udata; obj_idx = args->obj_idx; nargs = args->nargs; obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */ duk__call_prop_prep_stack(ctx, obj_idx, nargs); duk_call_method(ctx, nargs); return 1; }
static int sjs__compile_execute(duk_context *ctx) { const char *code; duk_size_t len; /* [ ... code len filename ] */ code = duk_require_pointer(ctx, -3); len = duk_require_uint(ctx, -2); duk_compile_lstring_filename(ctx, DUK_COMPILE_STRICT, code, len); /* [ ... code len function ] */ duk_push_global_object(ctx); /* 'this' binding */ duk_call_method(ctx, 0); return 1; /* either the result or error are on the stack top */ }
static int NativeGetProp(duk_context* ctx) { const char* prop; const char* iface; if (!duk_is_string(ctx, 0)) { duk_error(ctx, DUK_ERR_TYPE_ERROR, "Lone argument must be the property name"); } duk_push_c_lightfunc(ctx, AJS_MarshalMethodCall, 2, 0, 0); prop = duk_get_string(ctx, 0); duk_push_this(ctx); iface = FindInterfaceForMember(ctx, 0, &prop); MessageSetup(ctx, &AJ_PropertiesIface[0][1], "Get", NULL, AJ_MSG_METHOD_CALL); duk_push_string(ctx, iface); duk_push_string(ctx, prop); duk_call_method(ctx, 2); return 1; }
/* * Fulfill a libuv request. */ void mn_fulfill_req(duk_context *ctx, uv_req_t *req, int nargs) { mn_req_t *data = req->data; if (data->callback_ref) { mn_push_ref(ctx, data->callback_ref); if (nargs) { duk_insert(ctx, -1 - nargs); } mn_push_ref(ctx, data->context); if (nargs) { duk_insert(ctx, -1 - nargs); } duk_call_method(ctx, nargs); duk_pop(ctx); } else if (nargs) { duk_pop_n(ctx, nargs); } }
static duk_ret_t test_2(duk_context *ctx) { duk_set_top(ctx, 0); duk_push_c_function(ctx, my_adder, 3 /*nargs*/); duk_push_string(ctx, "my this binding"); duk_push_int(ctx, 10); duk_push_int(ctx, 11); duk_push_string(ctx, "foo"); /* causes error */ duk_push_int(ctx, 13); /* clipped */ duk_push_int(ctx, 14); /* clipped */ duk_call_method(ctx, 5); printf("result=%s\n", duk_to_string(ctx, -1)); duk_pop(ctx); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; }
/* Eval is just a wrapper now. */ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { duk_uint_t comp_flags; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); /* Note: strictness is *not* inherited from the current Duktape/C. * This would be confusing because the current strictness state * depends on whether we're running inside a Duktape/C activation * (= strict mode) or outside of any activation (= non-strict mode). * See tests/api/test-eval-strictness.c for more discussion. */ /* [ ... source? filename? ] (depends on flags) */ comp_flags = flags; comp_flags |= DUK_COMPILE_EVAL; rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */ /* [ ... closure/error ] */ if (rc != DUK_EXEC_SUCCESS) { rc = DUK_EXEC_ERROR; goto got_rc; } duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */ if (flags & DUK_COMPILE_SAFE) { rc = duk_pcall_method(ctx, 0); } else { duk_call_method(ctx, 0); rc = DUK_EXEC_SUCCESS; } /* [ ... result/error ] */ got_rc: if (flags & DUK_COMPILE_NORESULT) { duk_pop(ctx); } return rc; }
// Default Duktape.modLoad implementation // return Duktape.modCompile.call(module, loadFile(module.id)); // or load shared libraries using Duktape.loadlib. static duk_ret_t duv_mod_load(duk_context *ctx) { const char* id; const char* ext; const duv_schema_entry schema[] = { { NULL, NULL } }; dschema_check(ctx, schema); duk_get_global_string(ctx, "Duktape"); duk_push_this(ctx); duk_get_prop_string(ctx, -1, "id"); id = duk_get_string(ctx, -1); if (!id) { duk_error(ctx, DUK_ERR_ERROR, "Missing id in module"); return 0; } // calculate the extension to know which compiler to use. ext = id + strlen(id); while (ext > id && ext[0] != '/' && ext[0] != '.') { --ext; } if (strcmp(ext, ".js") != 0) { duk_pop(ctx); std::string s = std::string(id) + ".js"; duk_push_string(ctx, s.c_str()); } // Stack: [Duktape, this, id] duk_push_c_function(ctx, duv_loadfile, 1); // Stack: [Duktape, this, id, loadfile] duk_insert(ctx, -2); // Stack: [Duktape, this, loadfile, id] duk_call(ctx, 1); // Stack: [Duktape, this, data] duk_get_prop_string(ctx, -3, "modCompile"); // Stack: [Duktape, this, data, modCompile] duk_insert(ctx, -3); // Stack: [Duktape, modCompile, this, data] duk_call_method(ctx, 1); // Stack: [Duktape, exports] return 1; }
DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) { duk_idx_t obj_index; duk_idx_t nargs; /* Get the original arguments. Note that obj_index may be a relative * index so the stack must have the same top when we use it. */ DUK_ASSERT_CTX_VALID(ctx); obj_index = (duk_idx_t) duk_get_int(ctx, -2); nargs = (duk_idx_t) duk_get_int(ctx, -1); duk_pop_2(ctx); obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ duk__call_prop_prep_stack(ctx, obj_index, nargs); duk_call_method(ctx, nargs); return 1; }
void duv_emit(uv_handle_t* handle, const char* key, int nargs, int cleanup) { duk_context *ctx = handle->data; duv_push_handle(ctx, handle); // stack: args... this duk_get_prop_string(ctx, -1, key); // stack: args... this fn if (cleanup) duk_del_prop_string(ctx, -2, key); // stack: args... this fn if (!duk_is_function(ctx, -1)) { duk_pop_n(ctx, 2 + nargs); return; } duk_insert(ctx, -(nargs + 2)); // stack: fn args... this duk_insert(ctx, -(nargs + 1)); // stack: fn this args... duk_call_method(ctx, nargs); // stack: result duk_pop(ctx); }
static duk_ret_t js_Font_drawTextBox(duk_context* ctx) { int x = duk_require_int(ctx, 0); int y = duk_require_int(ctx, 1); int w = duk_require_int(ctx, 2); int h = duk_require_int(ctx, 3); int offset = duk_require_int(ctx, 4); const char* text = duk_to_string(ctx, 5); font_t* font; int line_height; const char* line_text; color_t mask; int num_lines; int i; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_get_prop_string(ctx, -1, "\xFF" "color_mask"); mask = duk_require_sphere_color(ctx, -1); duk_pop(ctx); duk_pop(ctx); if (!screen_is_skipframe(g_screen)) { duk_push_c_function(ctx, js_Font_wordWrapString, DUK_VARARGS); duk_push_this(ctx); duk_push_string(ctx, text); duk_push_int(ctx, w); duk_call_method(ctx, 2); duk_get_prop_string(ctx, -1, "length"); num_lines = duk_get_int(ctx, -1); duk_pop(ctx); line_height = get_font_line_height(font); for (i = 0; i < num_lines; ++i) { duk_get_prop_index(ctx, -1, i); line_text = duk_get_string(ctx, -1); duk_pop(ctx); draw_text(font, mask, x + offset, y, TEXT_ALIGN_LEFT, line_text); y += line_height; } duk_pop(ctx); } return 0; }
static duk_ret_t js_Font_getStringHeight(duk_context* ctx) { const char* text = duk_to_string(ctx, 0); int width = duk_require_int(ctx, 1); font_t* font; int num_lines; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_pop(ctx); duk_push_c_function(ctx, js_Font_wordWrapString, DUK_VARARGS); duk_push_this(ctx); duk_push_string(ctx, text); duk_push_int(ctx, width); duk_call_method(ctx, 2); duk_get_prop_string(ctx, -1, "length"); num_lines = duk_get_int(ctx, -1); duk_pop(ctx); duk_pop(ctx); duk_push_int(ctx, get_font_line_height(font) * num_lines); return 1; }
void mn_emit_event( duk_context *ctx, mn_handle_t *data, mn_cb_id_t type, int nargs ) { int fn_ref = data->callbacks[type]; if (fn_ref) { mn_push_ref(ctx, fn_ref); if (nargs) { duk_insert(ctx, -1 - nargs); } mn_push_ref(ctx, data->context); if (nargs) { duk_insert(ctx, -1 - nargs); } duk_call_method(ctx, nargs); duk_pop(ctx); } else if (nargs) { duk_pop_n(ctx, nargs); } }