MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1383 lines 52 kB view raw
1#include <stdlib.h> 2#include <stdio.h> 3#include <string.h> 4#include <inttypes.h> 5#include <time.h> 6#include <uthash.h> 7#include <utarray.h> 8 9#include "ant.h" 10#include "errors.h" 11#include "runtime.h" 12#include "internal.h" 13#include "descriptors.h" 14#include "silver/engine.h" 15 16#include "gc/modules.h" 17#include "modules/abort.h" 18#include "modules/events.h" 19#include "modules/symbol.h" 20 21typedef struct { 22 bool canceled; 23 bool stop_immediate; 24 bool stop_propagation; 25 bool dispatching; 26} event_data_t; 27 28static ant_value_t g_isTrusted_getter = 0; 29static ant_value_t g_eventemitter_ctor = 0; 30static ant_value_t g_eventemitter_proto = 0; 31static ant_value_t g_eventtarget_proto = 0; 32static ant_value_t g_event_proto = 0; 33static ant_value_t g_customevent_proto = 0; 34static ant_value_t g_errorevent_proto = 0; 35static ant_value_t g_promiserejectionevent_proto = 0; 36 37static event_data_t *get_event_data(ant_value_t obj) { 38 ant_value_t slot = js_get_slot(obj, SLOT_DATA); 39 if (vtype(slot) != T_NUM) return NULL; 40 return (event_data_t *)(uintptr_t)js_getnum(slot); 41} 42 43static double get_timestamp_ms(void) { 44 struct timespec ts; 45 clock_gettime(CLOCK_MONOTONIC, &ts); 46 return (double)ts.tv_sec * 1e3 + (double)ts.tv_nsec / 1e6; 47} 48 49typedef struct { 50 ant_value_t callback; 51 ant_value_t raw_callback; 52 ant_value_t signal; 53 bool once; 54 bool capture; 55} EventListenerEntry; 56 57static const UT_icd event_listener_icd = { 58 sizeof(EventListenerEntry), 59 NULL, NULL, NULL 60}; 61 62typedef struct { 63 unsigned char buf[48]; 64 unsigned char *ptr; 65 size_t len; 66} evt_key_t; 67 68typedef struct { 69 UT_array *listeners; 70 ant_value_t js_key; 71 unsigned char *hash_key; 72 size_t hash_key_len; 73 bool warned_max_listeners; 74 UT_hash_handle hh; 75} EventType; 76 77typedef struct emitter_reg { 78 EventType **events; 79 struct emitter_reg *next; 80} emitter_reg_t; 81 82static EventType *global_events = NULL; 83static emitter_reg_t *emitter_registry = NULL; 84 85static EventType *make_event_type(ant_value_t js_key, const evt_key_t *ek) { 86 EventType *evt = ant_calloc(sizeof(EventType) + ek->len); 87 if (!evt) return NULL; 88 evt->js_key = js_key; 89 evt->hash_key = (unsigned char *)(evt + 1); 90 evt->hash_key_len = ek->len; 91 memcpy(evt->hash_key, ek->ptr, ek->len); 92 utarray_new(evt->listeners, &event_listener_icd); 93 return evt; 94} 95 96static EventType *evt_find(EventType *table, const evt_key_t *ek) { 97 EventType *evt = NULL; 98 HASH_FIND(hh, table, ek->ptr, ek->len, evt); 99 return evt; 100} 101 102static EventType *evt_find_or_create(EventType **table, ant_value_t js_key, const evt_key_t *ek) { 103 EventType *evt = evt_find(*table, ek); 104 if (!evt) { 105 evt = make_event_type(js_key, ek); 106 if (!evt) return NULL; 107 HASH_ADD_KEYPTR(hh, *table, evt->hash_key, evt->hash_key_len, evt); 108 } 109 return evt; 110} 111 112static void evt_key_reset(evt_key_t *k) { 113 k->ptr = k->buf; 114 k->len = 0; 115} 116 117static void evt_key_free(evt_key_t *k) { 118 if (k->ptr != k->buf) free(k->ptr); 119 evt_key_reset(k); 120} 121 122static bool evt_key_init(ant_t *js, ant_value_t arg, evt_key_t *out) { 123 evt_key_reset(out); 124 uint8_t tag = (uint8_t)vtype(arg); 125 126 if (tag == T_STR) { 127 size_t slen = 0; 128 const char *s = js_getstr(js, arg, &slen); 129 out->len = 1 + slen; 130 131 if (out->len > sizeof(out->buf)) { 132 out->ptr = malloc(out->len); 133 if (!out->ptr) { evt_key_reset(out); return false; } 134 } 135 136 out->ptr[0] = tag; 137 if (slen) memcpy(out->ptr + 1, s, slen); 138 139 return true; 140 } 141 142 if (tag == T_SYMBOL) { 143 out->len = 1 + sizeof(ant_value_t); 144 out->ptr[0] = tag; 145 memcpy(out->ptr + 1, &arg, sizeof(ant_value_t)); 146 return true; 147 } 148 149 return false; 150} 151 152static EventType **get_or_create_emitter_events(ant_t *js, ant_value_t this_obj) { 153 ant_value_t slot = js_get_slot(this_obj, SLOT_DATA); 154 if (vtype(slot) == T_UNDEF) { 155 EventType **events = ant_calloc(sizeof(EventType *)); 156 if (!events) return NULL; 157 *events = NULL; 158 159 emitter_reg_t *reg = ant_calloc(sizeof(emitter_reg_t)); 160 if (!reg) { free(events); return NULL; } 161 reg->events = events; 162 reg->next = emitter_registry; 163 emitter_registry = reg; 164 165 js_set_slot(this_obj, SLOT_DATA, ANT_PTR(events)); 166 return events; 167 } 168 return (EventType **)(uintptr_t)js_getnum(slot); 169} 170 171static EventType *find_or_create_global_event_type(ant_t *js, ant_value_t js_key) { 172 evt_key_t ek; 173 if (!evt_key_init(js, js_key, &ek)) return NULL; 174 EventType *evt = evt_find_or_create(&global_events, js_key, &ek); 175 evt_key_free(&ek); 176 return evt; 177} 178 179static EventType *find_global_event_type(ant_t *js, ant_value_t js_key) { 180 evt_key_t ek; 181 if (!evt_key_init(js, js_key, &ek)) return NULL; 182 EventType *evt = evt_find(global_events, &ek); 183 evt_key_free(&ek); 184 return evt; 185} 186 187static EventType *find_or_create_emitter_event_type(ant_t *js, ant_value_t this_obj, ant_value_t js_key) { 188 EventType **events = get_or_create_emitter_events(js, this_obj); 189 if (!events) return NULL; 190 evt_key_t ek; 191 if (!evt_key_init(js, js_key, &ek)) return NULL; 192 EventType *evt = evt_find_or_create(events, js_key, &ek); 193 evt_key_free(&ek); 194 return evt; 195} 196 197static EventType *find_emitter_event_type(ant_t *js, ant_value_t this_obj, ant_value_t js_key) { 198 EventType **events = get_or_create_emitter_events(js, this_obj); 199 if (!events) return NULL; 200 evt_key_t ek; 201 if (!evt_key_init(js, js_key, &ek)) return NULL; 202 EventType *evt = evt_find(*events, &ek); 203 evt_key_free(&ek); 204 return evt; 205} 206 207static inline ant_value_t evt_key_from_arg(ant_value_t arg) { 208 uint8_t t = vtype(arg); 209 return (t == T_STR || t == T_SYMBOL) ? arg : 0; 210} 211 212static bool is_eventemitter_instance(ant_value_t target) { 213 return js_check_brand(target, BRAND_EVENTEMITTER); 214} 215 216static bool is_eventtarget_instance(ant_value_t target) { 217 return js_check_brand(target, BRAND_EVENTTARGET); 218} 219 220static int eventemitter_get_max_listeners_impl(ant_value_t target) { 221 ant_value_t slot = js_get_slot(target, SLOT_EVENT_MAX_LISTENERS); 222 if (vtype(slot) == T_NUM) { 223 int n = (int)js_getnum(slot); 224 return n >= 0 ? n : EVENTS_DEFAULT_MAX_LISTENERS; 225 } 226 return EVENTS_DEFAULT_MAX_LISTENERS; 227} 228 229static ant_value_t eventemitter_call_listener( 230 ant_t *js, 231 ant_value_t listener, 232 ant_value_t this_val, 233 ant_value_t *args, 234 int nargs 235) { 236 if (!is_callable(listener)) return js_mkundef(); 237 if (sv_check_c_stack_overflow(js)) 238 return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); 239 240 sv_call_plan_t plan; 241 ant_value_t err = sv_prepare_call( 242 js->vm, js, listener, this_val, args, nargs, 243 NULL, SV_CALL_MODE_NORMAL, &plan 244 ); 245 246 if (is_err(err)) return err; 247 return sv_execute_call_plan(js->vm, js, &plan, NULL); 248} 249 250static ant_value_t js_eventemitter_once_wrapper(ant_t *js, ant_value_t *args, int nargs) { 251 ant_value_t listener = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 252 if (!is_callable(listener)) return js_mkundef(); 253 return eventemitter_call_listener(js, listener, js->this_val, args, nargs); 254} 255 256static ant_value_t eventemitter_get_listeners_array(ant_t *js, ant_value_t target, ant_value_t key, bool raw) { 257 ant_value_t result = js_mkarr(js); 258 EventType *evt = NULL; 259 260 if (!is_object_type(target) || !key) return result; 261 evt = find_emitter_event_type(js, target, key); 262 if (!evt) return result; 263 264 for (unsigned int i = 0; i < utarray_len(evt->listeners); i++) { 265 EventListenerEntry *entry = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 266 if (!entry) continue; 267 js_arr_push(js, result, raw && entry->once && is_callable(entry->raw_callback) 268 ? entry->raw_callback 269 : entry->callback 270 ); 271 } 272 273 return result; 274} 275 276static void js_init_event_obj(ant_t *js, ant_value_t obj, ant_value_t type_val, bool bubbles, bool cancelable) { 277 js_set(js, obj, "type", type_val); 278 js_set(js, obj, "target", js_mknull()); 279 js_set(js, obj, "srcElement", js_mknull()); 280 js_set(js, obj, "currentTarget", js_mknull()); 281 js_set(js, obj, "eventPhase", js_mknum(0)); 282 js_set(js, obj, "bubbles", js_bool(bubbles)); 283 js_set(js, obj, "cancelable", js_bool(cancelable)); 284 js_set(js, obj, "defaultPrevented", js_false); 285 js_set(js, obj, "returnValue", js_true); 286 js_set(js, obj, "cancelBubble", js_false); 287 js_set(js, obj, "timeStamp", js_mknum(get_timestamp_ms())); 288 289 if (g_isTrusted_getter) 290 js_set_accessor_desc(js, obj, "isTrusted", 9, g_isTrusted_getter, js_mkundef(), 0); 291 292 event_data_t *data = ant_calloc(sizeof(event_data_t)); 293 if (data) js_set_slot(obj, SLOT_DATA, ANT_PTR(data)); 294} 295 296static ant_value_t js_event_ctor(ant_t *js, ant_value_t *args, int nargs) { 297 if (vtype(js->new_target) == T_UNDEF) 298 return js_mkerr_typed(js, JS_ERR_TYPE, "Event constructor requires 'new'"); 299 if (nargs < 1 || vtype(args[0]) == T_UNDEF) 300 return js_mkerr_typed(js, JS_ERR_TYPE, "Event constructor: type argument is required"); 301 302 ant_value_t type_val = args[0]; 303 if (vtype(type_val) != T_STR) { 304 type_val = js_tostring_val(js, type_val); 305 if (is_err(type_val)) return type_val; 306 } 307 308 bool bubbles = false, cancelable = false; 309 if (nargs >= 2 && vtype(args[1]) == T_OBJ) { 310 ant_value_t b = js_get(js, args[1], "bubbles"); 311 ant_value_t c = js_get(js, args[1], "cancelable"); 312 if (is_err(b)) return b; 313 if (is_err(c)) return c; 314 bubbles = js_truthy(js, b); 315 cancelable = js_truthy(js, c); 316 } 317 318 ant_value_t this_obj = js_mkobj(js); 319 ant_value_t proto = js_instance_proto_from_new_target(js, g_event_proto); 320 if (is_object_type(proto)) js_set_proto_init(this_obj, proto); 321 322 js_init_event_obj(js, this_obj, type_val, bubbles, cancelable); 323 return this_obj; 324} 325 326static ant_value_t js_event_get_isTrusted(ant_t *js, ant_value_t *args, int nargs) { 327 return js_false; 328} 329 330static ant_value_t js_eventemitter_ctor(ant_t *js, ant_value_t *args, int nargs) { 331 ant_value_t this_obj = js_getthis(js); 332 333 if (is_object_type(this_obj)) { 334 js_set_slot(this_obj, SLOT_BRAND, js_mknum(BRAND_EVENTEMITTER)); 335 return this_obj; 336 } 337 338 if (vtype(js->new_target) != T_UNDEF) { 339 ant_value_t obj = js_mkobj(js); 340 ant_value_t proto = js_instance_proto_from_new_target(js, g_eventemitter_proto); 341 if (is_object_type(proto)) js_set_proto_init(obj, proto); 342 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_EVENTEMITTER)); 343 return obj; 344 } 345 346 return js_mkerr_typed(js, JS_ERR_TYPE, "EventEmitter constructor requires an object receiver or 'new'"); 347} 348 349static ant_value_t js_event_preventDefault(ant_t *js, ant_value_t *args, int nargs) { 350 ant_value_t this_obj = js_getthis(js); 351 ant_value_t cancelable = js_get(js, this_obj, "cancelable"); 352 if (!js_truthy(js, cancelable)) return js_mkundef(); 353 event_data_t *data = get_event_data(this_obj); 354 if (data) data->canceled = true; 355 js_set(js, this_obj, "defaultPrevented", js_true); 356 js_set(js, this_obj, "returnValue", js_false); 357 return js_mkundef(); 358} 359 360static ant_value_t js_event_stopPropagation(ant_t *js, ant_value_t *args, int nargs) { 361 ant_value_t this_obj = js_getthis(js); 362 event_data_t *data = get_event_data(this_obj); 363 if (data) data->stop_propagation = true; 364 js_set(js, this_obj, "cancelBubble", js_true); 365 return js_mkundef(); 366} 367 368static ant_value_t js_event_stopImmediatePropagation(ant_t *js, ant_value_t *args, int nargs) { 369 ant_value_t this_obj = js_getthis(js); 370 event_data_t *data = get_event_data(this_obj); 371 if (data) { data->stop_immediate = true; data->stop_propagation = true; } 372 js_set(js, this_obj, "cancelBubble", js_true); 373 return js_mkundef(); 374} 375 376static ant_value_t js_event_composedPath(ant_t *js, ant_value_t *args, int nargs) { 377 ant_value_t this_obj = js_getthis(js); 378 event_data_t *data = get_event_data(this_obj); 379 ant_value_t result = js_mkarr(js); 380 if (data && data->dispatching) { 381 ant_value_t ct = js_get(js, this_obj, "currentTarget"); 382 if (is_object_type(ct)) js_arr_push(js, result, ct); 383 } 384 return result; 385} 386 387static ant_value_t js_event_initEvent(ant_t *js, ant_value_t *args, int nargs) { 388 ant_value_t this_obj = js_getthis(js); 389 if (nargs >= 1) { 390 ant_value_t type_val = vtype(args[0]) == T_STR ? args[0] : js_tostring_val(js, args[0]); 391 if (!is_err(type_val)) js_set(js, this_obj, "type", type_val); 392 } 393 if (nargs >= 2) js_set(js, this_obj, "bubbles", js_bool(js_truthy(js, args[1]))); 394 if (nargs >= 3) js_set(js, this_obj, "cancelable", js_bool(js_truthy(js, args[2]))); 395 js_set(js, this_obj, "defaultPrevented", js_false); 396 js_set(js, this_obj, "returnValue", js_true); 397 event_data_t *data = get_event_data(this_obj); 398 if (data) { data->canceled = false; data->stop_immediate = false; data->stop_propagation = false; } 399 return js_mkundef(); 400} 401 402static ant_value_t js_customevent_ctor(ant_t *js, ant_value_t *args, int nargs) { 403 if (vtype(js->new_target) == T_UNDEF) 404 return js_mkerr_typed(js, JS_ERR_TYPE, "CustomEvent constructor requires 'new'"); 405 if (nargs < 1 || vtype(args[0]) == T_UNDEF) 406 return js_mkerr_typed(js, JS_ERR_TYPE, "CustomEvent constructor: type argument is required"); 407 408 ant_value_t type_val = args[0]; 409 if (vtype(type_val) != T_STR) { 410 type_val = js_tostring_val(js, type_val); 411 if (is_err(type_val)) return type_val; 412 } 413 414 bool bubbles = false, cancelable = false; 415 ant_value_t detail = js_mknull(); 416 if (nargs >= 2 && vtype(args[1]) == T_OBJ) { 417 ant_value_t b = js_get(js, args[1], "bubbles"); 418 ant_value_t c = js_get(js, args[1], "cancelable"); 419 ant_value_t d = js_get(js, args[1], "detail"); 420 if (is_err(b)) return b; 421 if (is_err(c)) return c; 422 bubbles = js_truthy(js, b); 423 cancelable = js_truthy(js, c); 424 if (vtype(d) != T_UNDEF) detail = d; 425 } 426 427 ant_value_t this_obj = js_mkobj(js); 428 ant_value_t proto = js_instance_proto_from_new_target(js, g_customevent_proto); 429 if (is_object_type(proto)) js_set_proto_init(this_obj, proto); 430 431 js_init_event_obj(js, this_obj, type_val, bubbles, cancelable); 432 js_set(js, this_obj, "detail", detail); 433 return this_obj; 434} 435 436static ant_value_t js_errorevent_ctor(ant_t *js, ant_value_t *args, int nargs) { 437 if (vtype(js->new_target) == T_UNDEF) 438 return js_mkerr_typed(js, JS_ERR_TYPE, "ErrorEvent constructor requires 'new'"); 439 if (nargs < 1 || vtype(args[0]) == T_UNDEF) 440 return js_mkerr_typed(js, JS_ERR_TYPE, "ErrorEvent constructor: type argument is required"); 441 442 ant_value_t type_val = args[0]; 443 if (vtype(type_val) != T_STR) { 444 type_val = js_tostring_val(js, type_val); 445 if (is_err(type_val)) return type_val; 446 } 447 448 bool bubbles = false, cancelable = false; 449 ant_value_t message = js_mkstr(js, "", 0); 450 ant_value_t filename = js_mkstr(js, "", 0); 451 ant_value_t lineno = js_mknum(0); 452 ant_value_t colno = js_mknum(0); 453 ant_value_t error = js_mknull(); 454 455 if (nargs >= 2 && vtype(args[1]) == T_OBJ) { 456 ant_value_t b = js_get(js, args[1], "bubbles"); 457 ant_value_t c = js_get(js, args[1], "cancelable"); 458 ant_value_t m = js_get(js, args[1], "message"); 459 ant_value_t f = js_get(js, args[1], "filename"); 460 ant_value_t l = js_get(js, args[1], "lineno"); 461 ant_value_t co = js_get(js, args[1], "colno"); 462 ant_value_t e = js_get(js, args[1], "error"); 463 if (is_err(b)) return b; 464 if (is_err(c)) return c; 465 bubbles = js_truthy(js, b); 466 cancelable = js_truthy(js, c); 467 if (vtype(m) != T_UNDEF) { message = js_tostring_val(js, m); if (is_err(message)) return message; } 468 if (vtype(f) != T_UNDEF) { filename = js_tostring_val(js, f); if (is_err(filename)) return filename; } 469 if (vtype(l) != T_UNDEF) lineno = l; 470 if (vtype(co) != T_UNDEF) colno = co; 471 if (vtype(e) != T_UNDEF) error = e; 472 } 473 474 ant_value_t this_obj = js_mkobj(js); 475 ant_value_t proto = js_instance_proto_from_new_target(js, g_errorevent_proto); 476 if (is_object_type(proto)) js_set_proto_init(this_obj, proto); 477 478 js_init_event_obj(js, this_obj, type_val, bubbles, cancelable); 479 js_set(js, this_obj, "message", message); 480 js_set(js, this_obj, "filename", filename); 481 js_set(js, this_obj, "lineno", lineno); 482 js_set(js, this_obj, "colno", colno); 483 js_set(js, this_obj, "error", error); 484 return this_obj; 485} 486 487static ant_value_t js_promiserejectionevent_ctor(ant_t *js, ant_value_t *args, int nargs) { 488 if (vtype(js->new_target) == T_UNDEF) 489 return js_mkerr_typed(js, JS_ERR_TYPE, "PromiseRejectionEvent constructor requires 'new'"); 490 if (nargs < 1 || vtype(args[0]) == T_UNDEF) 491 return js_mkerr_typed(js, JS_ERR_TYPE, "PromiseRejectionEvent constructor: type argument is required"); 492 493 ant_value_t type_val = args[0]; 494 if (vtype(type_val) != T_STR) { 495 type_val = js_tostring_val(js, type_val); 496 if (is_err(type_val)) return type_val; 497 } 498 499 bool bubbles = false, cancelable = false; 500 ant_value_t promise = js_mkundef(); 501 ant_value_t reason = js_mkundef(); 502 503 if (nargs >= 2 && vtype(args[1]) == T_OBJ) { 504 ant_value_t b = js_get(js, args[1], "bubbles"); 505 ant_value_t c = js_get(js, args[1], "cancelable"); 506 ant_value_t p = js_get(js, args[1], "promise"); 507 ant_value_t r = js_get(js, args[1], "reason"); 508 if (is_err(b)) return b; 509 if (is_err(c)) return c; 510 bubbles = js_truthy(js, b); 511 cancelable = js_truthy(js, c); 512 if (vtype(p) != T_UNDEF) promise = p; 513 if (vtype(r) != T_UNDEF) reason = r; 514 } 515 516 ant_value_t this_obj = js_mkobj(js); 517 ant_value_t proto = js_instance_proto_from_new_target(js, g_promiserejectionevent_proto); 518 if (is_object_type(proto)) js_set_proto_init(this_obj, proto); 519 520 js_init_event_obj(js, this_obj, type_val, bubbles, cancelable); 521 js_set(js, this_obj, "promise", promise); 522 js_set(js, this_obj, "reason", reason); 523 return this_obj; 524} 525 526static ant_value_t js_eventtarget_ctor(ant_t *js, ant_value_t *args, int nargs) { 527 if (vtype(js->new_target) == T_UNDEF) 528 return js_mkerr_typed(js, JS_ERR_TYPE, "EventTarget constructor requires 'new'"); 529 530 ant_value_t this_obj = js_getthis(js); 531 if (is_object_type(this_obj)) js_set_slot(this_obj, SLOT_BRAND, js_mknum(BRAND_EVENTTARGET)); 532 return js_mkundef(); 533} 534 535static bool parse_addEventListener_options(ant_t *js, ant_value_t *args, int nargs, bool *once, bool *capture, ant_value_t *signal) { 536 *once = false; *capture = false; *signal = js_mkundef(); 537 if (nargs < 3) return true; 538 ant_value_t opts = args[2]; 539 if (vtype(opts) == T_BOOL) { 540 *capture = js_truthy(js, opts); 541 return true; 542 } 543 if (vtype(opts) != T_OBJ) return true; 544 545 ant_value_t sig = js_get(js, opts, "signal"); 546 if (vtype(sig) == T_NULL) return false; 547 if (vtype(sig) != T_UNDEF) { 548 if (!abort_signal_is_signal(sig)) return false; 549 *signal = sig; 550 } 551 552 ant_value_t o = js_get(js, opts, "once"); 553 ant_value_t ca = js_get(js, opts, "capture"); 554 if (vtype(o) != T_UNDEF) *once = js_truthy(js, o); 555 if (vtype(ca) != T_UNDEF) *capture = js_truthy(js, ca); 556 return true; 557} 558 559static ant_value_t add_listener_to(ant_t *js, ant_value_t *args, int nargs, EventType *evt) { 560 if (!evt) return js_mkerr(js, "failed to create event type"); 561 562 bool once, capture; 563 ant_value_t signal; 564 if (!parse_addEventListener_options(js, args, nargs, &once, &capture, &signal)) 565 return js_mkerr_typed(js, JS_ERR_TYPE, "Failed to execute 'addEventListener': signal is not an AbortSignal"); 566 567 if (vtype(signal) != T_UNDEF && abort_signal_is_aborted(signal)) return js_mkundef(); 568 569 ant_value_t cb = args[1]; 570 uint8_t cbt = vtype(cb); 571 if (cbt == T_NULL || cbt == T_UNDEF) return js_mkundef(); 572 if (cbt != T_FUNC && cbt != T_CFUNC) return js_mkundef(); 573 574 for (unsigned int i = 0; i < utarray_len(evt->listeners); i++) { 575 EventListenerEntry *e = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 576 if (e->callback == cb && e->capture == capture) return js_mkundef(); 577 } 578 579 EventListenerEntry entry = { cb, js_mkundef(), signal, once, capture }; 580 utarray_push_back(evt->listeners, &entry); 581 return js_mkundef(); 582} 583 584static ant_value_t remove_listener_from(ant_t *js, ant_value_t *args, int nargs, EventType *evt) { 585 if (!evt) return js_mkundef(); 586 587 bool capture = false; 588 if (nargs >= 3) { 589 ant_value_t opts = args[2]; 590 if (vtype(opts) == T_BOOL) capture = js_truthy(js, opts); 591 else if (vtype(opts) == T_OBJ) { 592 ant_value_t ca = js_get(js, opts, "capture"); 593 if (vtype(ca) != T_UNDEF) capture = js_truthy(js, ca); 594 }} 595 596 ant_value_t cb = (nargs >= 2) ? args[1] : js_mkundef(); 597 uint8_t cbt = vtype(cb); 598 if (cbt == T_NULL || cbt == T_UNDEF) return js_mkundef(); 599 600 for (unsigned int i = 0; i < utarray_len(evt->listeners); i++) { 601 EventListenerEntry *e = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 602 if (e->callback == cb && e->capture == capture) { 603 utarray_erase(evt->listeners, i, 1); 604 return js_mkundef(); 605 } 606 } 607 return js_mkundef(); 608} 609 610static ant_value_t dispatch_event_to(ant_t *js, ant_value_t event_obj, EventType *evt, ant_value_t target) { 611 if (!evt) return js_true; 612 613 event_data_t *data = get_event_data(event_obj); 614 if (data) { data->dispatching = true; data->stop_immediate = false; } 615 js_set(js, event_obj, "target", target); 616 js_set(js, event_obj, "currentTarget", target); 617 js_set(js, event_obj, "eventPhase", js_mknum(2)); 618 619 ant_value_t call_args[1] = { event_obj }; 620 unsigned int n = utarray_len(evt->listeners); 621 622 for (unsigned int i = 0; i < n;) { 623 EventListenerEntry *entry = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 624 625 if (vtype(entry->signal) != T_UNDEF && abort_signal_is_aborted(entry->signal)) { 626 utarray_erase(evt->listeners, i, 1); 627 n--; continue; 628 } 629 630 ant_value_t cb = entry->callback; 631 bool once = entry->once; 632 if (once) { utarray_erase(evt->listeners, i, 1); n--; } else i++; 633 634 uint8_t t = vtype(cb); 635 if (t != T_FUNC && t != T_CFUNC) continue; 636 637 eventemitter_call_listener(js, cb, js_mkundef(), call_args, 1); 638 if (data && data->stop_immediate) break; 639 } 640 641 if (data) data->dispatching = false; 642 js_set(js, event_obj, "currentTarget", js_mknull()); 643 js_set(js, event_obj, "eventPhase", js_mknum(0)); 644 645 bool canceled = data && data->canceled; 646 return js_bool(!canceled); 647} 648 649static ant_value_t js_add_event_listener_method(ant_t *js, ant_value_t *args, int nargs) { 650 if (nargs < 1) return js_mkundef(); 651 ant_value_t key = evt_key_from_arg(args[0]); 652 if (!key) return js_mkundef(); 653 return add_listener_to(js, args, nargs, 654 find_or_create_emitter_event_type(js, js_getthis(js), key)); 655} 656 657static ant_value_t js_add_event_listener(ant_t *js, ant_value_t *args, int nargs) { 658 if (nargs < 1) return js_mkundef(); 659 ant_value_t key = evt_key_from_arg(args[0]); 660 if (!key) return js_mkundef(); 661 return add_listener_to(js, args, nargs, find_or_create_global_event_type(js, key)); 662} 663 664static ant_value_t js_remove_event_listener_method(ant_t *js, ant_value_t *args, int nargs) { 665 if (nargs < 1) return js_mkundef(); 666 ant_value_t key = evt_key_from_arg(args[0]); 667 if (!key) return js_mkundef(); 668 return remove_listener_from(js, args, nargs, 669 find_emitter_event_type(js, js_getthis(js), key)); 670} 671 672static ant_value_t js_remove_event_listener(ant_t *js, ant_value_t *args, int nargs) { 673 if (nargs < 1) return js_mkundef(); 674 ant_value_t key = evt_key_from_arg(args[0]); 675 if (!key) return js_mkundef(); 676 return remove_listener_from(js, args, nargs, find_global_event_type(js, key)); 677} 678 679static ant_value_t js_dispatch_event_method(ant_t *js, ant_value_t *args, int nargs) { 680 if (nargs < 1 || !is_object_type(args[0])) return js_false; 681 ant_value_t this_obj = js_getthis(js); 682 ant_value_t key = js_get(js, args[0], "type"); 683 if (!evt_key_from_arg(key)) return js_false; 684 return dispatch_event_to(js, args[0], 685 find_emitter_event_type(js, this_obj, key), this_obj); 686} 687 688static ant_value_t js_dispatch_event(ant_t *js, ant_value_t *args, int nargs) { 689 if (nargs < 1 || !is_object_type(args[0])) return js_false; 690 ant_value_t key = js_get(js, args[0], "type"); 691 if (!evt_key_from_arg(key)) return js_false; 692 return dispatch_event_to(js, args[0], 693 find_global_event_type(js, key), js_glob(js)); 694} 695 696void js_dispatch_global_event(ant_t *js, ant_value_t event_obj) { 697 ant_value_t key = js_get(js, event_obj, "type"); 698 if (!evt_key_from_arg(key)) return; 699 EventType *evt = find_global_event_type(js, key); 700 if (!evt || utarray_len(evt->listeners) == 0) return; 701 dispatch_event_to(js, event_obj, evt, js_glob(js)); 702} 703 704static bool eventemitter_add_listener_impl( 705 ant_t *js, 706 ant_value_t target, ant_value_t key, 707 ant_value_t listener, bool once, bool prepend 708) { 709 EventType *evt = NULL; 710 EventListenerEntry entry = {0}; 711 uint8_t t = 0; 712 713 if (!is_object_type(target) || !key) return false; 714 t = vtype(listener); 715 if (t != T_FUNC && t != T_CFUNC) return false; 716 717 evt = find_or_create_emitter_event_type(js, target, key); 718 if (!evt) return false; 719 720 entry.callback = listener; 721 entry.raw_callback = js_mkundef(); 722 entry.signal = js_mkundef(); 723 entry.once = once; 724 entry.capture = false; 725 726 if (once) { 727 entry.raw_callback = js_heavy_mkfun(js, js_eventemitter_once_wrapper, listener); 728 if (is_callable(entry.raw_callback)) js_set(js, entry.raw_callback, "listener", listener); 729 } 730 731 if (!prepend || utarray_len(evt->listeners) == 0) utarray_push_back(evt->listeners, &entry); 732 else { 733 utarray_push_back(evt->listeners, &entry); 734 EventListenerEntry *items = (EventListenerEntry *)utarray_eltptr(evt->listeners, 0); 735 if (!items) return false; 736 memmove(items + 1, items, (utarray_len(evt->listeners) - 1u) * sizeof(*items)); 737 items[0] = entry; 738 } 739 740 int max_listeners = eventemitter_get_max_listeners_impl(target); 741 if ( 742 max_listeners > 0 && 743 !evt->warned_max_listeners && 744 (int)utarray_len(evt->listeners) > max_listeners 745 ) { 746 evt->warned_max_listeners = true; 747 if (vtype(key) == T_STR) { 748 fprintf( 749 stderr, 750 "Warning: Possible EventEmitter memory leak detected. " 751 "%u '%s' listeners added. Use emitter.setMaxListeners() to increase limit.\n", 752 (unsigned)utarray_len(evt->listeners), 753 js_str(js, key) 754 ); 755 } else { 756 fprintf( 757 stderr, 758 "Warning: Possible EventEmitter memory leak detected. " 759 "%u listeners added for a Symbol event. Use emitter.setMaxListeners() to increase limit.\n", 760 (unsigned)utarray_len(evt->listeners) 761 ); 762 } 763 } 764 765 return true; 766} 767 768static bool eventemitter_remove_listener_impl( 769 ant_t *js, 770 ant_value_t target, ant_value_t key, 771 ant_value_t listener 772) { 773 EventType *evt = NULL; 774 uint8_t t = 0; 775 776 if (!is_object_type(target) || !key) return false; 777 t = vtype(listener); 778 if (t != T_FUNC && t != T_CFUNC) return false; 779 780 evt = find_emitter_event_type(js, target, key); 781 if (!evt) return false; 782 783 for (unsigned int i = 0; i < utarray_len(evt->listeners); i++) { 784 EventListenerEntry *entry = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 785 if (entry->callback == listener || entry->raw_callback == listener) { 786 utarray_erase(evt->listeners, i, 1); 787 return true; 788 }} 789 790 return false; 791} 792 793static ant_offset_t eventemitter_listener_count_impl( 794 ant_t *js, 795 ant_value_t target, ant_value_t key 796) { 797 EventType *evt = NULL; 798 799 if (!is_object_type(target) || !key) return 0; 800 evt = find_emitter_event_type(js, target, key); 801 if (!evt) return 0; 802 803 return (ant_offset_t)utarray_len(evt->listeners); 804} 805 806static ant_value_t js_eventemitter_off(ant_t *js, ant_value_t *args, int nargs) { 807 if (nargs < 2) return js_mkerr(js, "off requires 2 arguments (event, listener)"); 808 ant_value_t key = evt_key_from_arg(args[0]); 809 810 if (!key) return js_mkerr(js, "event must be a string or Symbol"); 811 ant_value_t this_obj = js_getthis(js); 812 813 remove_listener_from( 814 js, args, nargs, 815 find_emitter_event_type(js, this_obj, key) 816 ); 817 818 return this_obj; 819} 820 821static bool eventemitter_emit_args_impl( 822 ant_t *js, 823 ant_value_t target, ant_value_t key, 824 ant_value_t *args, int nargs 825) { 826 EventType *evt = NULL; 827 828 if (!is_object_type(target) || !key) return false; 829 evt = find_emitter_event_type(js, target, key); 830 if (!evt || utarray_len(evt->listeners) == 0) return false; 831 832 for (unsigned int i = 0; i < utarray_len(evt->listeners);) { 833 EventListenerEntry *entry = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 834 ant_value_t cb = entry->callback; 835 bool once = entry->once; 836 837 if (once) utarray_erase(evt->listeners, i, 1); 838 else i++; 839 840 if (vtype(entry->signal) != T_UNDEF && abort_signal_is_aborted(entry->signal)) continue; 841 if (vtype(cb) != T_FUNC && vtype(cb) != T_CFUNC) continue; 842 843 ant_value_t result = eventemitter_call_listener(js, cb, target, args, nargs); 844 if (vtype(result) == T_ERR) { 845 if (vtype(key) == T_STR) fprintf(stderr, "Error in event listener for '%s': %s\n", js_str(js, key), js_str(js, result)); 846 else fprintf(stderr, "Error in event listener: %s\n", js_str(js, result)); 847 } 848 } 849 850 return true; 851} 852 853static ant_value_t js_eventemitter_emit(ant_t *js, ant_value_t *args, int nargs) { 854 if (nargs < 1) return js_mkerr(js, "emit requires at least 1 argument (event)"); 855 ant_value_t key = evt_key_from_arg(args[0]); 856 if (!key) return js_mkerr(js, "event must be a string or Symbol"); 857 858 return js_bool(eventemitter_emit_args_impl( 859 js, js_getthis(js), key, 860 nargs > 1 ? &args[1] : NULL, nargs - 1 861 )); 862} 863 864bool eventemitter_emit_args_val( 865 ant_t *js, 866 ant_value_t target, ant_value_t key, 867 ant_value_t *args, int nargs 868) { 869 return eventemitter_emit_args_impl(js, target, key, args, nargs); 870} 871 872bool eventemitter_emit_args( 873 ant_t *js, 874 ant_value_t target, const char *event_type, 875 ant_value_t *args, int nargs 876) { 877 return eventemitter_emit_args_val(js, target, js_mkstr(js, event_type, strlen(event_type)), args, nargs); 878} 879 880bool eventemitter_add_listener_val( 881 ant_t *js, 882 ant_value_t target, ant_value_t key, 883 ant_value_t listener, bool once 884) { 885 return eventemitter_add_listener_impl(js, target, key, listener, once, false); 886} 887 888bool eventemitter_add_listener( 889 ant_t *js, 890 ant_value_t target, const char *event_type, 891 ant_value_t listener, bool once 892) { 893 return eventemitter_add_listener_val(js, target, js_mkstr(js, event_type, strlen(event_type)), listener, once); 894} 895 896bool eventemitter_remove_listener_val( 897 ant_t *js, 898 ant_value_t target, ant_value_t key, 899 ant_value_t listener 900) { 901 return eventemitter_remove_listener_impl(js, target, key, listener); 902} 903 904bool eventemitter_remove_listener( 905 ant_t *js, 906 ant_value_t target, const char *event_type, 907 ant_value_t listener 908) { 909 return eventemitter_remove_listener_val(js, target, js_mkstr(js, event_type, strlen(event_type)), listener); 910} 911 912ant_offset_t eventemitter_listener_count_val( 913 ant_t *js, 914 ant_value_t target, ant_value_t key 915) { 916 return eventemitter_listener_count_impl(js, target, key); 917} 918 919ant_offset_t eventemitter_listener_count( 920 ant_t *js, 921 ant_value_t target, const char *event_type 922) { 923 return eventemitter_listener_count_val(js, target, js_mkstr(js, event_type, strlen(event_type))); 924} 925 926static ant_value_t js_eventemitter_add(ant_t *js, ant_value_t *args, int nargs, bool once, bool prepend) { 927 if (nargs < 2) return js_mkerr(js, "requires 2 arguments (event, listener)"); 928 ant_value_t key = evt_key_from_arg(args[0]); 929 930 if (!key) return js_mkerr(js, "event must be a string or Symbol"); 931 if (!eventemitter_add_listener_impl(js, js_getthis(js), key, args[1], once, prepend)) 932 return js_mkerr(js, "listener must be a function"); 933 934 return js_getthis(js); 935} 936 937static ant_value_t js_eventemitter_on(ant_t *js, ant_value_t *args, int nargs) { 938 return js_eventemitter_add(js, args, nargs, false, false); 939} 940 941static ant_value_t js_eventemitter_once(ant_t *js, ant_value_t *args, int nargs) { 942 return js_eventemitter_add(js, args, nargs, true, false); 943} 944 945static ant_value_t js_eventemitter_prepend_listener(ant_t *js, ant_value_t *args, int nargs) { 946 return js_eventemitter_add(js, args, nargs, false, true); 947} 948 949static ant_value_t js_eventemitter_prepend_once_listener(ant_t *js, ant_value_t *args, int nargs) { 950 return js_eventemitter_add(js, args, nargs, true, true); 951} 952 953static ant_value_t js_eventemitter_removeAllListeners(ant_t *js, ant_value_t *args, int nargs) { 954 ant_value_t this_obj = js_getthis(js); 955 EventType **events = NULL; 956 957 if (nargs < 1 || vtype(args[0]) == T_UNDEF) { 958 events = get_or_create_emitter_events(js, this_obj); 959 if (!events || !*events) return this_obj; 960 961 EventType *evt, *tmp; 962 HASH_ITER(hh, *events, evt, tmp) utarray_clear(evt->listeners); 963 return this_obj; 964 } 965 966 ant_value_t key = evt_key_from_arg(args[0]); 967 if (!key) return this_obj; 968 969 EventType *evt = find_emitter_event_type(js, this_obj, key); 970 if (evt) utarray_clear(evt->listeners); 971 972 return this_obj; 973} 974 975static ant_value_t js_eventemitter_listenerCount(ant_t *js, ant_value_t *args, int nargs) { 976 if (nargs < 1) return js_mknum(0); 977 ant_value_t key = evt_key_from_arg(args[0]); 978 979 if (!key) return js_mknum(0); 980 EventType *evt = find_emitter_event_type(js, js_getthis(js), key); 981 982 if (!evt) return js_mknum(0); 983 return js_mknum((double)utarray_len(evt->listeners)); 984} 985 986static ant_value_t js_eventemitter_setMaxListeners(ant_t *js, ant_value_t *args, int nargs) { 987 if (nargs < 1) return js_mkerr(js, "setMaxListeners requires 1 argument"); 988 if (vtype(args[0]) != T_NUM) return js_mkerr(js, "n must be a number"); 989 990 int n = (int)js_getnum(args[0]); 991 if (n < 0) return js_mkerr(js, "n must be non-negative"); 992 993 ant_value_t this_obj = js_getthis(js); 994 if (!is_object_type(this_obj)) return js_mkerr_typed(js, JS_ERR_TYPE, "setMaxListeners requires an object receiver"); 995 js_set_slot(this_obj, SLOT_EVENT_MAX_LISTENERS, js_mknum(n)); 996 return this_obj; 997} 998 999static ant_value_t js_eventemitter_getMaxListeners(ant_t *js, ant_value_t *args, int nargs) { 1000 ant_value_t this_obj = js_getthis(js); 1001 if (!is_object_type(this_obj)) return js_mknum(EVENTS_DEFAULT_MAX_LISTENERS); 1002 return js_mknum(eventemitter_get_max_listeners_impl(this_obj)); 1003} 1004 1005static ant_value_t js_eventemitter_rawListeners(ant_t *js, ant_value_t *args, int nargs) { 1006 if (nargs < 1) return js_mkarr(js); 1007 ant_value_t key = evt_key_from_arg(args[0]); 1008 if (!key) return js_mkarr(js); 1009 return eventemitter_get_listeners_array(js, js_getthis(js), key, true); 1010} 1011 1012static ant_value_t js_eventemitter_listeners(ant_t *js, ant_value_t *args, int nargs) { 1013 if (nargs < 1) return js_mkarr(js); 1014 ant_value_t key = evt_key_from_arg(args[0]); 1015 if (!key) return js_mkarr(js); 1016 return eventemitter_get_listeners_array(js, js_getthis(js), key, false); 1017} 1018 1019static ant_value_t js_eventemitter_eventNames(ant_t *js, ant_value_t *args, int nargs) { 1020 ant_value_t this_obj = js_getthis(js); 1021 ant_value_t result = js_mkarr(js); 1022 1023 EventType **events = get_or_create_emitter_events(js, this_obj); 1024 if (events && *events) { 1025 EventType *evt, *tmp; 1026 HASH_ITER(hh, *events, evt, tmp) if (utarray_len(evt->listeners) > 0) 1027 js_arr_push(js, result, evt->js_key); 1028 } 1029 1030 return result; 1031} 1032 1033static ant_value_t js_events_once_listener(ant_t *js, ant_value_t *args, int nargs) { 1034 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1035 if (!is_object_type(state)) return js_mkundef(); 1036 1037 ant_value_t promise = js_get_slot(state, SLOT_DATA); 1038 if (vtype(promise) != T_PROMISE) return js_mkundef(); 1039 1040 ant_value_t settled = js_get_slot(state, SLOT_SETTLED); 1041 if (vtype(settled) == T_BOOL && settled == js_true) return js_mkundef(); 1042 js_set_slot(state, SLOT_SETTLED, js_true); 1043 1044 ant_value_t signal = js_get(js, state, "signal"); 1045 ant_value_t abort_listener = js_get(js, state, "abortListener"); 1046 if (abort_signal_is_signal(signal) && is_callable(abort_listener)) 1047 abort_signal_remove_listener(js, signal, abort_listener); 1048 1049 ant_value_t values = js_mkarr(js); 1050 for (int i = 0; i < nargs; i++) js_arr_push(js, values, args[i]); 1051 js_resolve_promise(js, promise, values); 1052 1053 return js_mkundef(); 1054} 1055 1056static ant_value_t js_events_once_abort_listener(ant_t *js, ant_value_t *args, int nargs) { 1057 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1058 if (!is_object_type(state)) return js_mkundef(); 1059 1060 ant_value_t promise = js_get_slot(state, SLOT_DATA); 1061 if (vtype(promise) != T_PROMISE) return js_mkundef(); 1062 1063 ant_value_t settled = js_get_slot(state, SLOT_SETTLED); 1064 if (vtype(settled) == T_BOOL && settled == js_true) return js_mkundef(); 1065 js_set_slot(state, SLOT_SETTLED, js_true); 1066 1067 ant_value_t signal = js_get(js, state, "signal"); 1068 ant_value_t abort_listener = js_get(js, state, "abortListener"); 1069 if (abort_signal_is_signal(signal) && is_callable(abort_listener)) 1070 abort_signal_remove_listener(js, signal, abort_listener); 1071 1072 ant_value_t reason = abort_signal_get_reason(signal); 1073 if (vtype(reason) == T_UNDEF) reason = js_mkerr(js, "The operation was aborted"); 1074 js_reject_promise(js, promise, reason); 1075 1076 return js_mkundef(); 1077} 1078 1079static bool js_events_once_is_abort_key(ant_t *js, ant_value_t key) { 1080 size_t key_len = 0; 1081 const char *key_str = vtype(key) == T_STR ? js_getstr(js, key, &key_len) : NULL; 1082 return key_str && key_len == 5 && memcmp(key_str, "abort", 5) == 0; 1083} 1084 1085static void js_events_once_reject_aborted(ant_t *js, ant_value_t promise, ant_value_t signal) { 1086 ant_value_t reason = abort_signal_get_reason(signal); 1087 if (vtype(reason) == T_UNDEF) reason = js_mkerr(js, "The operation was aborted"); 1088 js_reject_promise(js, promise, reason); 1089} 1090 1091static ant_value_t js_events_once_attach( 1092 ant_t *js, 1093 ant_value_t promise, 1094 ant_value_t target, 1095 ant_value_t key, 1096 ant_value_t listener, 1097 ant_value_t signal 1098) { 1099 if (abort_signal_is_signal(target)) { 1100 if (!js_events_once_is_abort_key(js, key)) { 1101 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "AbortSignal only supports the abort event")); 1102 return promise; 1103 } 1104 abort_signal_add_listener(js, target, listener); 1105 return promise; 1106 } 1107 1108 if (is_eventemitter_instance(target)) { 1109 if (!eventemitter_add_listener_val(js, target, key, listener, true)) 1110 js_reject_promise(js, promise, js_mkerr(js, "listener must be a function")); 1111 return promise; 1112 } 1113 1114 if (is_eventtarget_instance(target)) { 1115 ant_value_t listener_options = js_mkobj(js); 1116 js_set(js, listener_options, "once", js_true); 1117 if (abort_signal_is_signal(signal)) js_set(js, listener_options, "signal", signal); 1118 1119 ant_value_t call_args[3] = { key, listener, listener_options }; 1120 ant_value_t result = add_listener_to(js, call_args, 3, find_or_create_emitter_event_type(js, target, key)); 1121 if (is_err(result)) js_reject_promise(js, promise, result); 1122 return promise; 1123 } 1124 1125 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "target is not an EventEmitter or EventTarget")); 1126 return promise; 1127} 1128 1129static ant_value_t js_events_once(ant_t *js, ant_value_t *args, int nargs) { 1130 if (nargs < 2 || !is_object_type(args[0])) 1131 return js_mkerr_typed(js, JS_ERR_TYPE, "events.once requires an emitter and event name"); 1132 1133 ant_value_t key = evt_key_from_arg(args[1]); 1134 if (!key) return js_mkerr_typed(js, JS_ERR_TYPE, "event must be a string or Symbol"); 1135 1136 ant_value_t promise = js_mkpromise(js); 1137 if (is_err(promise)) return promise; 1138 1139 ant_value_t state = js_mkobj(js); 1140 js_set_slot(state, SLOT_DATA, promise); 1141 js_set_slot(state, SLOT_SETTLED, js_false); 1142 1143 ant_value_t listener = js_heavy_mkfun(js, js_events_once_listener, state); 1144 ant_value_t target = args[0]; 1145 ant_value_t options = nargs >= 3 ? args[2] : js_mkundef(); 1146 ant_value_t signal = js_mkundef(); 1147 1148 if (is_object_type(options)) signal = js_get(js, options, "signal"); 1149 if (abort_signal_is_signal(signal)) { 1150 if (abort_signal_is_aborted(signal)) { 1151 js_events_once_reject_aborted(js, promise, signal); 1152 return promise; 1153 } 1154 ant_value_t abort_listener = js_heavy_mkfun(js, js_events_once_abort_listener, state); 1155 js_set(js, state, "signal", signal); 1156 js_set(js, state, "abortListener", abort_listener); 1157 abort_signal_add_listener(js, signal, abort_listener); 1158 } 1159 1160 return js_events_once_attach(js, promise, target, key, listener, signal); 1161} 1162 1163static ant_value_t js_events_disposable_dispose(ant_t *js, ant_value_t *args, int nargs) { 1164 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1165 if (!is_object_type(state)) return js_mkundef(); 1166 1167 ant_value_t disposed = js_get_slot(state, SLOT_SETTLED); 1168 if (vtype(disposed) == T_BOOL && disposed == js_true) return js_mkundef(); 1169 js_set_slot(state, SLOT_SETTLED, js_true); 1170 1171 ant_value_t signal = js_get(js, state, "signal"); 1172 ant_value_t listener = js_get(js, state, "listener"); 1173 if (abort_signal_is_signal(signal) && is_callable(listener)) 1174 abort_signal_remove_listener(js, signal, listener); 1175 1176 return js_mkundef(); 1177} 1178 1179static ant_value_t js_events_add_abort_listener(ant_t *js, ant_value_t *args, int nargs) { 1180 if (nargs < 2 || !abort_signal_is_signal(args[0]) || !is_callable(args[1])) 1181 return js_mkerr_typed(js, JS_ERR_TYPE, "events.addAbortListener requires an AbortSignal and listener"); 1182 1183 bool already_aborted = abort_signal_is_aborted(args[0]); 1184 if (already_aborted) { 1185 ant_value_t event = js_mkobj(js); 1186 js_set(js, event, "type", js_mkstr(js, "abort", 5)); 1187 eventemitter_call_listener(js, args[1], args[0], &event, 1); 1188 } else abort_signal_add_listener(js, args[0], args[1]); 1189 1190 ant_value_t state = js_mkobj(js); 1191 js_set_slot(state, SLOT_SETTLED, js_bool(already_aborted)); 1192 js_set(js, state, "signal", args[0]); 1193 js_set(js, state, "listener", args[1]); 1194 1195 ant_value_t disposable = js_mkobj(js); 1196 js_set(js, disposable, "dispose", js_heavy_mkfun(js, js_events_disposable_dispose, state)); 1197 1198 return disposable; 1199} 1200 1201static ant_value_t js_events_set_max_listeners(ant_t *js, ant_value_t *args, int nargs) { 1202 if (nargs < 1) return js_mkerr(js, "setMaxListeners requires at least 1 argument"); 1203 if (vtype(args[0]) != T_NUM) return js_mkerr(js, "n must be a number"); 1204 1205 int n = (int)js_getnum(args[0]); 1206 if (n < 0) return js_mkerr(js, "n must be non-negative"); 1207 1208 for (int i = 1; i < nargs; i++) { 1209 if (!is_object_type(args[i])) continue; 1210 js_set_slot(args[i], SLOT_EVENT_MAX_LISTENERS, js_mknum(n)); 1211 } 1212 1213 return js_mkundef(); 1214} 1215 1216static ant_value_t js_events_get_max_listeners(ant_t *js, ant_value_t *args, int nargs) { 1217 if (nargs < 1) return js_mknum(EVENTS_DEFAULT_MAX_LISTENERS); 1218 if (!is_object_type(args[0])) return js_mknum(EVENTS_DEFAULT_MAX_LISTENERS); 1219 return js_mknum(eventemitter_get_max_listeners_impl(args[0])); 1220} 1221 1222// TODO: fix stub 1223static ant_value_t js_events_on(ant_t *js, ant_value_t *args, int nargs) { 1224 return js_mkerr_typed(js, JS_ERR_TYPE, "events.on async iterator is not implemented"); 1225} 1226 1227ant_value_t events_library(ant_t *js) { 1228 ant_value_t lib = js_mkobj(js); 1229 1230 eventemitter_prototype(js); 1231 js_set_module_default(js, lib, g_eventemitter_ctor, "EventEmitter"); 1232 js_set(js, lib, "once", js_mkfun(js_events_once)); 1233 js_set(js, lib, "on", js_mkfun(js_events_on)); 1234 js_set(js, lib, "addAbortListener", js_mkfun(js_events_add_abort_listener)); 1235 js_set(js, lib, "setMaxListeners", js_mkfun(js_events_set_max_listeners)); 1236 js_set(js, lib, "getMaxListeners", js_mkfun(js_events_get_max_listeners)); 1237 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "events", 6)); 1238 1239 return lib; 1240} 1241 1242ant_value_t eventemitter_prototype(ant_t *js) { 1243 if (g_eventemitter_proto) return g_eventemitter_proto; 1244 1245 ant_value_t object_proto = js->sym.object_proto; 1246 ant_value_t function_proto = js_get_slot(js_glob(js), SLOT_FUNC_PROTO); 1247 if (vtype(function_proto) == T_UNDEF) function_proto = js_get_ctor_proto(js, "Function", 8); 1248 1249 ant_value_t eventemitter_ctor = js_mkobj(js); 1250 ant_value_t eventemitter_proto = js_mkobj(js); 1251 1252 if (is_object_type(object_proto)) js_set_proto_init(eventemitter_proto, object_proto); 1253 if (is_object_type(function_proto)) js_set_proto_init(eventemitter_ctor, function_proto); 1254 1255 js_set(js, eventemitter_proto, "on", js_mkfun(js_eventemitter_on)); 1256 js_set_exact(js, eventemitter_proto, "addListener", js_get(js, eventemitter_proto, "on")); 1257 js_set(js, eventemitter_proto, "once", js_mkfun(js_eventemitter_once)); 1258 js_set(js, eventemitter_proto, "prependListener", js_mkfun(js_eventemitter_prepend_listener)); 1259 js_set(js, eventemitter_proto, "prependOnceListener", js_mkfun(js_eventemitter_prepend_once_listener)); 1260 js_set(js, eventemitter_proto, "off", js_mkfun(js_eventemitter_off)); 1261 js_set_exact(js, eventemitter_proto, "removeListener", js_get(js, eventemitter_proto, "off")); 1262 js_set(js, eventemitter_proto, "emit", js_mkfun(js_eventemitter_emit)); 1263 js_set(js, eventemitter_proto, "removeAllListeners", js_mkfun(js_eventemitter_removeAllListeners)); 1264 js_set(js, eventemitter_proto, "listenerCount", js_mkfun(js_eventemitter_listenerCount)); 1265 js_set(js, eventemitter_proto, "setMaxListeners", js_mkfun(js_eventemitter_setMaxListeners)); 1266 js_set(js, eventemitter_proto, "getMaxListeners", js_mkfun(js_eventemitter_getMaxListeners)); 1267 js_set(js, eventemitter_proto, "listeners", js_mkfun(js_eventemitter_listeners)); 1268 js_set(js, eventemitter_proto, "rawListeners", js_mkfun(js_eventemitter_rawListeners)); 1269 js_set(js, eventemitter_proto, "eventNames", js_mkfun(js_eventemitter_eventNames)); 1270 js_set_sym(js, eventemitter_proto, get_toStringTag_sym(), js_mkstr(js, "EventEmitter", 12)); 1271 1272 js_set_slot(eventemitter_ctor, SLOT_CFUNC, js_mkfun(js_eventemitter_ctor)); 1273 js_mkprop_fast(js, eventemitter_ctor, "prototype", 9, eventemitter_proto); 1274 js_mkprop_fast(js, eventemitter_ctor, "name", 4, ANT_STRING("EventEmitter")); 1275 js_set_descriptor(js, eventemitter_ctor, "name", 4, 0); 1276 1277 g_eventemitter_proto = eventemitter_proto; 1278 g_eventemitter_ctor = js_obj_to_func(eventemitter_ctor); 1279 js_set(js, eventemitter_proto, "constructor", g_eventemitter_ctor); 1280 js_set_descriptor(js, eventemitter_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 1281 1282 return g_eventemitter_proto; 1283} 1284 1285void init_events_module(void) { 1286 ant_t *js = rt->js; 1287 ant_value_t global = js_glob(js); 1288 g_isTrusted_getter = js_mkfun(js_event_get_isTrusted); 1289 1290 g_event_proto = js_mkobj(js); 1291 js_set_sym(js, g_event_proto, get_toStringTag_sym(), js_mkstr(js, "Event", 5)); 1292 js_set(js, g_event_proto, "preventDefault", js_mkfun(js_event_preventDefault)); 1293 js_set(js, g_event_proto, "stopPropagation", js_mkfun(js_event_stopPropagation)); 1294 js_set(js, g_event_proto, "stopImmediatePropagation", js_mkfun(js_event_stopImmediatePropagation)); 1295 js_set(js, g_event_proto, "composedPath", js_mkfun(js_event_composedPath)); 1296 js_set(js, g_event_proto, "initEvent", js_mkfun(js_event_initEvent)); 1297 js_set(js, g_event_proto, "NONE", js_mknum(0)); 1298 js_set(js, g_event_proto, "CAPTURING_PHASE", js_mknum(1)); 1299 js_set(js, g_event_proto, "AT_TARGET", js_mknum(2)); 1300 js_set(js, g_event_proto, "BUBBLING_PHASE", js_mknum(3)); 1301 1302 ant_value_t event_fn = js_make_ctor(js, js_event_ctor, g_event_proto, "Event", 5); 1303 js_set(js, event_fn, "NONE", js_mknum(0)); 1304 js_set(js, event_fn, "CAPTURING_PHASE", js_mknum(1)); 1305 js_set(js, event_fn, "AT_TARGET", js_mknum(2)); 1306 js_set(js, event_fn, "BUBBLING_PHASE", js_mknum(3)); 1307 js_set(js, global, "Event", event_fn); 1308 1309 g_customevent_proto = js_mkobj(js); 1310 js_set_proto_init(g_customevent_proto, g_event_proto); 1311 js_set_sym(js, g_customevent_proto, get_toStringTag_sym(), js_mkstr(js, "CustomEvent", 11)); 1312 1313 ant_value_t customevent_fn = js_make_ctor(js, js_customevent_ctor, g_customevent_proto, "CustomEvent", 11); 1314 js_set(js, global, "CustomEvent", customevent_fn); 1315 1316 g_errorevent_proto = js_mkobj(js); 1317 js_set_proto_init(g_errorevent_proto, g_event_proto); 1318 js_set_sym(js, g_errorevent_proto, get_toStringTag_sym(), js_mkstr(js, "ErrorEvent", 10)); 1319 1320 ant_value_t errorevent_fn = js_make_ctor(js, js_errorevent_ctor, g_errorevent_proto, "ErrorEvent", 10); 1321 js_set(js, global, "ErrorEvent", errorevent_fn); 1322 1323 g_promiserejectionevent_proto = js_mkobj(js); 1324 js_set_proto_init(g_promiserejectionevent_proto, g_event_proto); 1325 js_set_sym(js, g_promiserejectionevent_proto, get_toStringTag_sym(), js_mkstr(js, "PromiseRejectionEvent", 21)); 1326 1327 ant_value_t pre_fn = js_make_ctor(js, js_promiserejectionevent_ctor, g_promiserejectionevent_proto, "PromiseRejectionEvent", 21); 1328 js_set(js, global, "PromiseRejectionEvent", pre_fn); 1329 1330 ant_value_t object_proto = js->sym.object_proto; 1331 ant_value_t function_proto = js_get_slot(global, SLOT_FUNC_PROTO); 1332 if (vtype(function_proto) == T_UNDEF) function_proto = js_get_ctor_proto(js, "Function", 8); 1333 1334 ant_value_t eventtarget_proto = js_mkobj(js); 1335 g_eventtarget_proto = eventtarget_proto; 1336 if (is_object_type(object_proto)) js_set_proto_init(eventtarget_proto, object_proto); 1337 js_set(js, eventtarget_proto, "addEventListener", js_mkfun(js_add_event_listener_method)); 1338 js_set(js, eventtarget_proto, "removeEventListener", js_mkfun(js_remove_event_listener_method)); 1339 js_set(js, eventtarget_proto, "dispatchEvent", js_mkfun(js_dispatch_event_method)); 1340 js_set_sym(js, eventtarget_proto, get_toStringTag_sym(), js_mkstr(js, "EventTarget", 11)); 1341 1342 ant_value_t eventtarget_ctor = js_mkobj(js); 1343 if (is_object_type(function_proto)) js_set_proto_init(eventtarget_ctor, function_proto); 1344 js_set_slot(eventtarget_ctor, SLOT_CFUNC, js_mkfun(js_eventtarget_ctor)); 1345 js_mkprop_fast(js, eventtarget_ctor, "prototype", 9, eventtarget_proto); 1346 js_mkprop_fast(js, eventtarget_ctor, "name", 4, ANT_STRING("EventTarget")); 1347 js_set_descriptor(js, eventtarget_ctor, "name", 4, 0); 1348 ant_value_t eventtarget_fn = js_obj_to_func(eventtarget_ctor); 1349 js_set(js, eventtarget_proto, "constructor", eventtarget_fn); 1350 js_set_descriptor(js, eventtarget_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 1351 1352 js_set(js, global, "addEventListener", js_mkfun(js_add_event_listener)); 1353 js_set(js, global, "removeEventListener", js_mkfun(js_remove_event_listener)); 1354 js_set(js, global, "dispatchEvent", js_mkfun(js_dispatch_event)); 1355 js_set(js, global, "EventTarget", eventtarget_fn); 1356} 1357 1358static void mark_event_type_listeners(ant_t *js, gc_mark_fn mark, EventType *events) { 1359 EventType *evt, *tmp; 1360 HASH_ITER(hh, events, evt, tmp) { 1361 if (vtype(evt->js_key) == T_STR) mark(js, evt->js_key); 1362 for (unsigned int i = 0; i < utarray_len(evt->listeners); i++) { 1363 EventListenerEntry *e = (EventListenerEntry *)utarray_eltptr(evt->listeners, i); 1364 mark(js, e->callback); 1365 if (vtype(e->raw_callback) != T_UNDEF) mark(js, e->raw_callback); 1366 if (vtype(e->signal) != T_UNDEF) mark(js, e->signal); 1367 } 1368}} 1369 1370void gc_mark_events(ant_t *js, gc_mark_fn mark) { 1371 mark_event_type_listeners(js, mark, global_events); 1372 for (emitter_reg_t *reg = emitter_registry; reg; reg = reg->next) { 1373 if (*reg->events) mark_event_type_listeners(js, mark, *reg->events); 1374 } 1375 if (g_isTrusted_getter) mark(js, g_isTrusted_getter); 1376 if (g_eventemitter_ctor) mark(js, g_eventemitter_ctor); 1377 if (g_eventemitter_proto) mark(js, g_eventemitter_proto); 1378 if (g_eventtarget_proto) mark(js, g_eventtarget_proto); 1379 if (g_event_proto) mark(js, g_event_proto); 1380 if (g_customevent_proto) mark(js, g_customevent_proto); 1381 if (g_errorevent_proto) mark(js, g_errorevent_proto); 1382 if (g_promiserejectionevent_proto) mark(js, g_promiserejectionevent_proto); 1383}