Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4447024
events.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
50 KB
Referenced Files
None
Subscribers
None
events.c
View Options
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<inttypes.h>
#include
<time.h>
#include
<uthash.h>
#include
<utarray.h>
#include
"ant.h"
#include
"errors.h"
#include
"runtime.h"
#include
"internal.h"
#include
"descriptors.h"
#include
"silver/engine.h"
#include
"gc/modules.h"
#include
"modules/abort.h"
#include
"modules/events.h"
#include
"modules/symbol.h"
typedef
struct
{
bool
canceled
;
bool
stop_immediate
;
bool
stop_propagation
;
bool
dispatching
;
}
event_data_t
;
static
ant_value_t
g_isTrusted_getter
=
0
;
static
ant_value_t
g_eventemitter_ctor
=
0
;
static
ant_value_t
g_eventemitter_proto
=
0
;
static
ant_value_t
g_eventtarget_proto
=
0
;
static
ant_value_t
g_event_proto
=
0
;
static
ant_value_t
g_customevent_proto
=
0
;
static
ant_value_t
g_errorevent_proto
=
0
;
static
ant_value_t
g_promiserejectionevent_proto
=
0
;
static
event_data_t
*
get_event_data
(
ant_value_t
obj
)
{
ant_value_t
slot
=
js_get_slot
(
obj
,
SLOT_DATA
);
if
(
vtype
(
slot
)
!=
T_NUM
)
return
NULL
;
return
(
event_data_t
*
)(
uintptr_t
)
js_getnum
(
slot
);
}
static
double
get_timestamp_ms
(
void
)
{
struct
timespec
ts
;
clock_gettime
(
CLOCK_MONOTONIC
,
&
ts
);
return
(
double
)
ts
.
tv_sec
*
1e3
+
(
double
)
ts
.
tv_nsec
/
1e6
;
}
typedef
struct
{
ant_value_t
callback
;
ant_value_t
raw_callback
;
ant_value_t
signal
;
bool
once
;
bool
capture
;
}
EventListenerEntry
;
static
const
UT_icd
event_listener_icd
=
{
sizeof
(
EventListenerEntry
),
NULL
,
NULL
,
NULL
};
typedef
struct
{
unsigned
char
buf
[
48
];
unsigned
char
*
ptr
;
size_t
len
;
}
evt_key_t
;
typedef
struct
{
UT_array
*
listeners
;
ant_value_t
js_key
;
unsigned
char
*
hash_key
;
size_t
hash_key_len
;
bool
warned_max_listeners
;
UT_hash_handle
hh
;
}
EventType
;
typedef
struct
emitter_reg
{
EventType
**
events
;
struct
emitter_reg
*
next
;
}
emitter_reg_t
;
static
EventType
*
global_events
=
NULL
;
static
emitter_reg_t
*
emitter_registry
=
NULL
;
static
EventType
*
make_event_type
(
ant_value_t
js_key
,
const
evt_key_t
*
ek
)
{
EventType
*
evt
=
ant_calloc
(
sizeof
(
EventType
)
+
ek
->
len
);
if
(
!
evt
)
return
NULL
;
evt
->
js_key
=
js_key
;
evt
->
hash_key
=
(
unsigned
char
*
)(
evt
+
1
);
evt
->
hash_key_len
=
ek
->
len
;
memcpy
(
evt
->
hash_key
,
ek
->
ptr
,
ek
->
len
);
utarray_new
(
evt
->
listeners
,
&
event_listener_icd
);
return
evt
;
}
static
EventType
*
evt_find
(
EventType
*
table
,
const
evt_key_t
*
ek
)
{
EventType
*
evt
=
NULL
;
HASH_FIND
(
hh
,
table
,
ek
->
ptr
,
ek
->
len
,
evt
);
return
evt
;
}
static
EventType
*
evt_find_or_create
(
EventType
**
table
,
ant_value_t
js_key
,
const
evt_key_t
*
ek
)
{
EventType
*
evt
=
evt_find
(
*
table
,
ek
);
if
(
!
evt
)
{
evt
=
make_event_type
(
js_key
,
ek
);
if
(
!
evt
)
return
NULL
;
HASH_ADD_KEYPTR
(
hh
,
*
table
,
evt
->
hash_key
,
evt
->
hash_key_len
,
evt
);
}
return
evt
;
}
static
void
evt_key_reset
(
evt_key_t
*
k
)
{
k
->
ptr
=
k
->
buf
;
k
->
len
=
0
;
}
static
void
evt_key_free
(
evt_key_t
*
k
)
{
if
(
k
->
ptr
!=
k
->
buf
)
free
(
k
->
ptr
);
evt_key_reset
(
k
);
}
static
bool
evt_key_init
(
ant_t
*
js
,
ant_value_t
arg
,
evt_key_t
*
out
)
{
evt_key_reset
(
out
);
uint8_t
tag
=
(
uint8_t
)
vtype
(
arg
);
if
(
tag
==
T_STR
)
{
size_t
slen
=
0
;
const
char
*
s
=
js_getstr
(
js
,
arg
,
&
slen
);
out
->
len
=
1
+
slen
;
if
(
out
->
len
>
sizeof
(
out
->
buf
))
{
out
->
ptr
=
malloc
(
out
->
len
);
if
(
!
out
->
ptr
)
{
evt_key_reset
(
out
);
return
false
;
}
}
out
->
ptr
[
0
]
=
tag
;
if
(
slen
)
memcpy
(
out
->
ptr
+
1
,
s
,
slen
);
return
true
;
}
if
(
tag
==
T_SYMBOL
)
{
out
->
len
=
1
+
sizeof
(
ant_value_t
);
out
->
ptr
[
0
]
=
tag
;
memcpy
(
out
->
ptr
+
1
,
&
arg
,
sizeof
(
ant_value_t
));
return
true
;
}
return
false
;
}
static
EventType
**
get_or_create_emitter_events
(
ant_t
*
js
,
ant_value_t
this_obj
)
{
ant_value_t
slot
=
js_get_slot
(
this_obj
,
SLOT_DATA
);
if
(
vtype
(
slot
)
==
T_UNDEF
)
{
EventType
**
events
=
ant_calloc
(
sizeof
(
EventType
*
));
if
(
!
events
)
return
NULL
;
*
events
=
NULL
;
emitter_reg_t
*
reg
=
ant_calloc
(
sizeof
(
emitter_reg_t
));
if
(
!
reg
)
{
free
(
events
);
return
NULL
;
}
reg
->
events
=
events
;
reg
->
next
=
emitter_registry
;
emitter_registry
=
reg
;
js_set_slot
(
this_obj
,
SLOT_DATA
,
ANT_PTR
(
events
));
return
events
;
}
return
(
EventType
**
)(
uintptr_t
)
js_getnum
(
slot
);
}
static
EventType
*
find_or_create_global_event_type
(
ant_t
*
js
,
ant_value_t
js_key
)
{
evt_key_t
ek
;
if
(
!
evt_key_init
(
js
,
js_key
,
&
ek
))
return
NULL
;
EventType
*
evt
=
evt_find_or_create
(
&
global_events
,
js_key
,
&
ek
);
evt_key_free
(
&
ek
);
return
evt
;
}
static
EventType
*
find_global_event_type
(
ant_t
*
js
,
ant_value_t
js_key
)
{
evt_key_t
ek
;
if
(
!
evt_key_init
(
js
,
js_key
,
&
ek
))
return
NULL
;
EventType
*
evt
=
evt_find
(
global_events
,
&
ek
);
evt_key_free
(
&
ek
);
return
evt
;
}
static
EventType
*
find_or_create_emitter_event_type
(
ant_t
*
js
,
ant_value_t
this_obj
,
ant_value_t
js_key
)
{
EventType
**
events
=
get_or_create_emitter_events
(
js
,
this_obj
);
if
(
!
events
)
return
NULL
;
evt_key_t
ek
;
if
(
!
evt_key_init
(
js
,
js_key
,
&
ek
))
return
NULL
;
EventType
*
evt
=
evt_find_or_create
(
events
,
js_key
,
&
ek
);
evt_key_free
(
&
ek
);
return
evt
;
}
static
EventType
*
find_emitter_event_type
(
ant_t
*
js
,
ant_value_t
this_obj
,
ant_value_t
js_key
)
{
EventType
**
events
=
get_or_create_emitter_events
(
js
,
this_obj
);
if
(
!
events
)
return
NULL
;
evt_key_t
ek
;
if
(
!
evt_key_init
(
js
,
js_key
,
&
ek
))
return
NULL
;
EventType
*
evt
=
evt_find
(
*
events
,
&
ek
);
evt_key_free
(
&
ek
);
return
evt
;
}
static
inline
ant_value_t
evt_key_from_arg
(
ant_value_t
arg
)
{
uint8_t
t
=
vtype
(
arg
);
return
(
t
==
T_STR
||
t
==
T_SYMBOL
)
?
arg
:
0
;
}
static
bool
is_eventemitter_instance
(
ant_value_t
target
)
{
return
js_check_brand
(
target
,
BRAND_EVENTEMITTER
);
}
static
bool
is_eventtarget_instance
(
ant_value_t
target
)
{
return
js_check_brand
(
target
,
BRAND_EVENTTARGET
);
}
static
int
eventemitter_get_max_listeners_impl
(
ant_value_t
target
)
{
ant_value_t
slot
=
js_get_slot
(
target
,
SLOT_EVENT_MAX_LISTENERS
);
if
(
vtype
(
slot
)
==
T_NUM
)
{
int
n
=
(
int
)
js_getnum
(
slot
);
return
n
>=
0
?
n
:
EVENTS_DEFAULT_MAX_LISTENERS
;
}
return
EVENTS_DEFAULT_MAX_LISTENERS
;
}
static
ant_value_t
eventemitter_call_listener
(
ant_t
*
js
,
ant_value_t
listener
,
ant_value_t
this_val
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
!
is_callable
(
listener
))
return
js_mkundef
();
if
(
sv_check_c_stack_overflow
(
js
))
return
js_mkerr_typed
(
js
,
JS_ERR_RANGE
|
JS_ERR_NO_STACK
,
"Maximum call stack size exceeded"
);
sv_call_plan_t
plan
;
ant_value_t
err
=
sv_prepare_call
(
js
->
vm
,
js
,
listener
,
this_val
,
args
,
nargs
,
NULL
,
SV_CALL_MODE_NORMAL
,
&
plan
);
if
(
is_err
(
err
))
return
err
;
return
sv_execute_call_plan
(
js
->
vm
,
js
,
&
plan
,
NULL
);
}
static
ant_value_t
js_eventemitter_once_wrapper
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
listener
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
!
is_callable
(
listener
))
return
js_mkundef
();
return
eventemitter_call_listener
(
js
,
listener
,
js
->
this_val
,
args
,
nargs
);
}
static
ant_value_t
eventemitter_get_listeners_array
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
bool
raw
)
{
ant_value_t
result
=
js_mkarr
(
js
);
EventType
*
evt
=
NULL
;
if
(
!
is_object_type
(
target
)
||
!
key
)
return
result
;
evt
=
find_emitter_event_type
(
js
,
target
,
key
);
if
(
!
evt
)
return
result
;
for
(
unsigned
int
i
=
0
;
i
<
utarray_len
(
evt
->
listeners
);
i
++
)
{
EventListenerEntry
*
entry
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
if
(
!
entry
)
continue
;
js_arr_push
(
js
,
result
,
raw
&&
entry
->
once
&&
is_callable
(
entry
->
raw_callback
)
?
entry
->
raw_callback
:
entry
->
callback
);
}
return
result
;
}
static
void
js_init_event_obj
(
ant_t
*
js
,
ant_value_t
obj
,
ant_value_t
type_val
,
bool
bubbles
,
bool
cancelable
)
{
js_set
(
js
,
obj
,
"type"
,
type_val
);
js_set
(
js
,
obj
,
"target"
,
js_mknull
());
js_set
(
js
,
obj
,
"srcElement"
,
js_mknull
());
js_set
(
js
,
obj
,
"currentTarget"
,
js_mknull
());
js_set
(
js
,
obj
,
"eventPhase"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"bubbles"
,
js_bool
(
bubbles
));
js_set
(
js
,
obj
,
"cancelable"
,
js_bool
(
cancelable
));
js_set
(
js
,
obj
,
"defaultPrevented"
,
js_false
);
js_set
(
js
,
obj
,
"returnValue"
,
js_true
);
js_set
(
js
,
obj
,
"cancelBubble"
,
js_false
);
js_set
(
js
,
obj
,
"timeStamp"
,
js_mknum
(
get_timestamp_ms
()));
if
(
g_isTrusted_getter
)
js_set_accessor_desc
(
js
,
obj
,
"isTrusted"
,
9
,
g_isTrusted_getter
,
js_mkundef
(),
0
);
event_data_t
*
data
=
ant_calloc
(
sizeof
(
event_data_t
));
if
(
data
)
js_set_slot
(
obj
,
SLOT_DATA
,
ANT_PTR
(
data
));
}
static
ant_value_t
js_event_ctor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Event constructor requires 'new'"
);
if
(
nargs
<
1
||
vtype
(
args
[
0
])
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Event constructor: type argument is required"
);
ant_value_t
type_val
=
args
[
0
];
if
(
vtype
(
type_val
)
!=
T_STR
)
{
type_val
=
js_tostring_val
(
js
,
type_val
);
if
(
is_err
(
type_val
))
return
type_val
;
}
bool
bubbles
=
false
,
cancelable
=
false
;
if
(
nargs
>=
2
&&
vtype
(
args
[
1
])
==
T_OBJ
)
{
ant_value_t
b
=
js_get
(
js
,
args
[
1
],
"bubbles"
);
ant_value_t
c
=
js_get
(
js
,
args
[
1
],
"cancelable"
);
if
(
is_err
(
b
))
return
b
;
if
(
is_err
(
c
))
return
c
;
bubbles
=
js_truthy
(
js
,
b
);
cancelable
=
js_truthy
(
js
,
c
);
}
ant_value_t
this_obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_instance_proto_from_new_target
(
js
,
g_event_proto
);
if
(
is_object_type
(
proto
))
js_set_proto_init
(
this_obj
,
proto
);
js_init_event_obj
(
js
,
this_obj
,
type_val
,
bubbles
,
cancelable
);
return
this_obj
;
}
static
ant_value_t
js_event_get_isTrusted
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_false
;
}
static
ant_value_t
js_eventemitter_ctor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
is_object_type
(
this_obj
))
{
js_set_slot
(
this_obj
,
SLOT_BRAND
,
js_mknum
(
BRAND_EVENTEMITTER
));
return
this_obj
;
}
if
(
vtype
(
js
->
new_target
)
!=
T_UNDEF
)
{
ant_value_t
obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_instance_proto_from_new_target
(
js
,
g_eventemitter_proto
);
if
(
is_object_type
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_set_slot
(
obj
,
SLOT_BRAND
,
js_mknum
(
BRAND_EVENTEMITTER
));
return
obj
;
}
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"EventEmitter constructor requires an object receiver or 'new'"
);
}
static
ant_value_t
js_event_preventDefault
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
ant_value_t
cancelable
=
js_get
(
js
,
this_obj
,
"cancelable"
);
if
(
!
js_truthy
(
js
,
cancelable
))
return
js_mkundef
();
event_data_t
*
data
=
get_event_data
(
this_obj
);
if
(
data
)
data
->
canceled
=
true
;
js_set
(
js
,
this_obj
,
"defaultPrevented"
,
js_true
);
js_set
(
js
,
this_obj
,
"returnValue"
,
js_false
);
return
js_mkundef
();
}
static
ant_value_t
js_event_stopPropagation
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
event_data_t
*
data
=
get_event_data
(
this_obj
);
if
(
data
)
data
->
stop_propagation
=
true
;
js_set
(
js
,
this_obj
,
"cancelBubble"
,
js_true
);
return
js_mkundef
();
}
static
ant_value_t
js_event_stopImmediatePropagation
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
event_data_t
*
data
=
get_event_data
(
this_obj
);
if
(
data
)
{
data
->
stop_immediate
=
true
;
data
->
stop_propagation
=
true
;
}
js_set
(
js
,
this_obj
,
"cancelBubble"
,
js_true
);
return
js_mkundef
();
}
static
ant_value_t
js_event_composedPath
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
event_data_t
*
data
=
get_event_data
(
this_obj
);
ant_value_t
result
=
js_mkarr
(
js
);
if
(
data
&&
data
->
dispatching
)
{
ant_value_t
ct
=
js_get
(
js
,
this_obj
,
"currentTarget"
);
if
(
is_object_type
(
ct
))
js_arr_push
(
js
,
result
,
ct
);
}
return
result
;
}
static
ant_value_t
js_event_initEvent
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
>=
1
)
{
ant_value_t
type_val
=
vtype
(
args
[
0
])
==
T_STR
?
args
[
0
]
:
js_tostring_val
(
js
,
args
[
0
]);
if
(
!
is_err
(
type_val
))
js_set
(
js
,
this_obj
,
"type"
,
type_val
);
}
if
(
nargs
>=
2
)
js_set
(
js
,
this_obj
,
"bubbles"
,
js_bool
(
js_truthy
(
js
,
args
[
1
])));
if
(
nargs
>=
3
)
js_set
(
js
,
this_obj
,
"cancelable"
,
js_bool
(
js_truthy
(
js
,
args
[
2
])));
js_set
(
js
,
this_obj
,
"defaultPrevented"
,
js_false
);
js_set
(
js
,
this_obj
,
"returnValue"
,
js_true
);
event_data_t
*
data
=
get_event_data
(
this_obj
);
if
(
data
)
{
data
->
canceled
=
false
;
data
->
stop_immediate
=
false
;
data
->
stop_propagation
=
false
;
}
return
js_mkundef
();
}
static
ant_value_t
js_customevent_ctor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"CustomEvent constructor requires 'new'"
);
if
(
nargs
<
1
||
vtype
(
args
[
0
])
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"CustomEvent constructor: type argument is required"
);
ant_value_t
type_val
=
args
[
0
];
if
(
vtype
(
type_val
)
!=
T_STR
)
{
type_val
=
js_tostring_val
(
js
,
type_val
);
if
(
is_err
(
type_val
))
return
type_val
;
}
bool
bubbles
=
false
,
cancelable
=
false
;
ant_value_t
detail
=
js_mknull
();
if
(
nargs
>=
2
&&
vtype
(
args
[
1
])
==
T_OBJ
)
{
ant_value_t
b
=
js_get
(
js
,
args
[
1
],
"bubbles"
);
ant_value_t
c
=
js_get
(
js
,
args
[
1
],
"cancelable"
);
ant_value_t
d
=
js_get
(
js
,
args
[
1
],
"detail"
);
if
(
is_err
(
b
))
return
b
;
if
(
is_err
(
c
))
return
c
;
bubbles
=
js_truthy
(
js
,
b
);
cancelable
=
js_truthy
(
js
,
c
);
if
(
vtype
(
d
)
!=
T_UNDEF
)
detail
=
d
;
}
ant_value_t
this_obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_instance_proto_from_new_target
(
js
,
g_customevent_proto
);
if
(
is_object_type
(
proto
))
js_set_proto_init
(
this_obj
,
proto
);
js_init_event_obj
(
js
,
this_obj
,
type_val
,
bubbles
,
cancelable
);
js_set
(
js
,
this_obj
,
"detail"
,
detail
);
return
this_obj
;
}
static
ant_value_t
js_errorevent_ctor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"ErrorEvent constructor requires 'new'"
);
if
(
nargs
<
1
||
vtype
(
args
[
0
])
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"ErrorEvent constructor: type argument is required"
);
ant_value_t
type_val
=
args
[
0
];
if
(
vtype
(
type_val
)
!=
T_STR
)
{
type_val
=
js_tostring_val
(
js
,
type_val
);
if
(
is_err
(
type_val
))
return
type_val
;
}
bool
bubbles
=
false
,
cancelable
=
false
;
ant_value_t
message
=
js_mkstr
(
js
,
""
,
0
);
ant_value_t
filename
=
js_mkstr
(
js
,
""
,
0
);
ant_value_t
lineno
=
js_mknum
(
0
);
ant_value_t
colno
=
js_mknum
(
0
);
ant_value_t
error
=
js_mknull
();
if
(
nargs
>=
2
&&
vtype
(
args
[
1
])
==
T_OBJ
)
{
ant_value_t
b
=
js_get
(
js
,
args
[
1
],
"bubbles"
);
ant_value_t
c
=
js_get
(
js
,
args
[
1
],
"cancelable"
);
ant_value_t
m
=
js_get
(
js
,
args
[
1
],
"message"
);
ant_value_t
f
=
js_get
(
js
,
args
[
1
],
"filename"
);
ant_value_t
l
=
js_get
(
js
,
args
[
1
],
"lineno"
);
ant_value_t
co
=
js_get
(
js
,
args
[
1
],
"colno"
);
ant_value_t
e
=
js_get
(
js
,
args
[
1
],
"error"
);
if
(
is_err
(
b
))
return
b
;
if
(
is_err
(
c
))
return
c
;
bubbles
=
js_truthy
(
js
,
b
);
cancelable
=
js_truthy
(
js
,
c
);
if
(
vtype
(
m
)
!=
T_UNDEF
)
{
message
=
js_tostring_val
(
js
,
m
);
if
(
is_err
(
message
))
return
message
;
}
if
(
vtype
(
f
)
!=
T_UNDEF
)
{
filename
=
js_tostring_val
(
js
,
f
);
if
(
is_err
(
filename
))
return
filename
;
}
if
(
vtype
(
l
)
!=
T_UNDEF
)
lineno
=
l
;
if
(
vtype
(
co
)
!=
T_UNDEF
)
colno
=
co
;
if
(
vtype
(
e
)
!=
T_UNDEF
)
error
=
e
;
}
ant_value_t
this_obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_instance_proto_from_new_target
(
js
,
g_errorevent_proto
);
if
(
is_object_type
(
proto
))
js_set_proto_init
(
this_obj
,
proto
);
js_init_event_obj
(
js
,
this_obj
,
type_val
,
bubbles
,
cancelable
);
js_set
(
js
,
this_obj
,
"message"
,
message
);
js_set
(
js
,
this_obj
,
"filename"
,
filename
);
js_set
(
js
,
this_obj
,
"lineno"
,
lineno
);
js_set
(
js
,
this_obj
,
"colno"
,
colno
);
js_set
(
js
,
this_obj
,
"error"
,
error
);
return
this_obj
;
}
static
ant_value_t
js_promiserejectionevent_ctor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"PromiseRejectionEvent constructor requires 'new'"
);
if
(
nargs
<
1
||
vtype
(
args
[
0
])
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"PromiseRejectionEvent constructor: type argument is required"
);
ant_value_t
type_val
=
args
[
0
];
if
(
vtype
(
type_val
)
!=
T_STR
)
{
type_val
=
js_tostring_val
(
js
,
type_val
);
if
(
is_err
(
type_val
))
return
type_val
;
}
bool
bubbles
=
false
,
cancelable
=
false
;
ant_value_t
promise
=
js_mkundef
();
ant_value_t
reason
=
js_mkundef
();
if
(
nargs
>=
2
&&
vtype
(
args
[
1
])
==
T_OBJ
)
{
ant_value_t
b
=
js_get
(
js
,
args
[
1
],
"bubbles"
);
ant_value_t
c
=
js_get
(
js
,
args
[
1
],
"cancelable"
);
ant_value_t
p
=
js_get
(
js
,
args
[
1
],
"promise"
);
ant_value_t
r
=
js_get
(
js
,
args
[
1
],
"reason"
);
if
(
is_err
(
b
))
return
b
;
if
(
is_err
(
c
))
return
c
;
bubbles
=
js_truthy
(
js
,
b
);
cancelable
=
js_truthy
(
js
,
c
);
if
(
vtype
(
p
)
!=
T_UNDEF
)
promise
=
p
;
if
(
vtype
(
r
)
!=
T_UNDEF
)
reason
=
r
;
}
ant_value_t
this_obj
=
js_mkobj
(
js
);
ant_value_t
proto
=
js_instance_proto_from_new_target
(
js
,
g_promiserejectionevent_proto
);
if
(
is_object_type
(
proto
))
js_set_proto_init
(
this_obj
,
proto
);
js_init_event_obj
(
js
,
this_obj
,
type_val
,
bubbles
,
cancelable
);
js_set
(
js
,
this_obj
,
"promise"
,
promise
);
js_set
(
js
,
this_obj
,
"reason"
,
reason
);
return
this_obj
;
}
static
ant_value_t
js_eventtarget_ctor
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
vtype
(
js
->
new_target
)
==
T_UNDEF
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"EventTarget constructor requires 'new'"
);
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
is_object_type
(
this_obj
))
js_set_slot
(
this_obj
,
SLOT_BRAND
,
js_mknum
(
BRAND_EVENTTARGET
));
return
js_mkundef
();
}
static
bool
parse_addEventListener_options
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
bool
*
once
,
bool
*
capture
,
ant_value_t
*
signal
)
{
*
once
=
false
;
*
capture
=
false
;
*
signal
=
js_mkundef
();
if
(
nargs
<
3
)
return
true
;
ant_value_t
opts
=
args
[
2
];
if
(
vtype
(
opts
)
==
T_BOOL
)
{
*
capture
=
js_truthy
(
js
,
opts
);
return
true
;
}
if
(
vtype
(
opts
)
!=
T_OBJ
)
return
true
;
ant_value_t
sig
=
js_get
(
js
,
opts
,
"signal"
);
if
(
vtype
(
sig
)
==
T_NULL
)
return
false
;
if
(
vtype
(
sig
)
!=
T_UNDEF
)
{
if
(
!
abort_signal_is_signal
(
sig
))
return
false
;
*
signal
=
sig
;
}
ant_value_t
o
=
js_get
(
js
,
opts
,
"once"
);
ant_value_t
ca
=
js_get
(
js
,
opts
,
"capture"
);
if
(
vtype
(
o
)
!=
T_UNDEF
)
*
once
=
js_truthy
(
js
,
o
);
if
(
vtype
(
ca
)
!=
T_UNDEF
)
*
capture
=
js_truthy
(
js
,
ca
);
return
true
;
}
static
ant_value_t
add_listener_to
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
EventType
*
evt
)
{
if
(
!
evt
)
return
js_mkerr
(
js
,
"failed to create event type"
);
bool
once
,
capture
;
ant_value_t
signal
;
if
(
!
parse_addEventListener_options
(
js
,
args
,
nargs
,
&
once
,
&
capture
,
&
signal
))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Failed to execute 'addEventListener': signal is not an AbortSignal"
);
if
(
vtype
(
signal
)
!=
T_UNDEF
&&
abort_signal_is_aborted
(
signal
))
return
js_mkundef
();
ant_value_t
cb
=
args
[
1
];
uint8_t
cbt
=
vtype
(
cb
);
if
(
cbt
==
T_NULL
||
cbt
==
T_UNDEF
)
return
js_mkundef
();
if
(
cbt
!=
T_FUNC
&&
cbt
!=
T_CFUNC
)
return
js_mkundef
();
for
(
unsigned
int
i
=
0
;
i
<
utarray_len
(
evt
->
listeners
);
i
++
)
{
EventListenerEntry
*
e
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
if
(
e
->
callback
==
cb
&&
e
->
capture
==
capture
)
return
js_mkundef
();
}
EventListenerEntry
entry
=
{
cb
,
js_mkundef
(),
signal
,
once
,
capture
};
utarray_push_back
(
evt
->
listeners
,
&
entry
);
return
js_mkundef
();
}
static
ant_value_t
remove_listener_from
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
EventType
*
evt
)
{
if
(
!
evt
)
return
js_mkundef
();
bool
capture
=
false
;
if
(
nargs
>=
3
)
{
ant_value_t
opts
=
args
[
2
];
if
(
vtype
(
opts
)
==
T_BOOL
)
capture
=
js_truthy
(
js
,
opts
);
else
if
(
vtype
(
opts
)
==
T_OBJ
)
{
ant_value_t
ca
=
js_get
(
js
,
opts
,
"capture"
);
if
(
vtype
(
ca
)
!=
T_UNDEF
)
capture
=
js_truthy
(
js
,
ca
);
}}
ant_value_t
cb
=
(
nargs
>=
2
)
?
args
[
1
]
:
js_mkundef
();
uint8_t
cbt
=
vtype
(
cb
);
if
(
cbt
==
T_NULL
||
cbt
==
T_UNDEF
)
return
js_mkundef
();
for
(
unsigned
int
i
=
0
;
i
<
utarray_len
(
evt
->
listeners
);
i
++
)
{
EventListenerEntry
*
e
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
if
(
e
->
callback
==
cb
&&
e
->
capture
==
capture
)
{
utarray_erase
(
evt
->
listeners
,
i
,
1
);
return
js_mkundef
();
}
}
return
js_mkundef
();
}
static
ant_value_t
dispatch_event_to
(
ant_t
*
js
,
ant_value_t
event_obj
,
EventType
*
evt
,
ant_value_t
target
)
{
if
(
!
evt
)
return
js_true
;
event_data_t
*
data
=
get_event_data
(
event_obj
);
if
(
data
)
{
data
->
dispatching
=
true
;
data
->
stop_immediate
=
false
;
}
js_set
(
js
,
event_obj
,
"target"
,
target
);
js_set
(
js
,
event_obj
,
"currentTarget"
,
target
);
js_set
(
js
,
event_obj
,
"eventPhase"
,
js_mknum
(
2
));
ant_value_t
call_args
[
1
]
=
{
event_obj
};
unsigned
int
n
=
utarray_len
(
evt
->
listeners
);
for
(
unsigned
int
i
=
0
;
i
<
n
;)
{
EventListenerEntry
*
entry
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
if
(
vtype
(
entry
->
signal
)
!=
T_UNDEF
&&
abort_signal_is_aborted
(
entry
->
signal
))
{
utarray_erase
(
evt
->
listeners
,
i
,
1
);
n
--
;
continue
;
}
ant_value_t
cb
=
entry
->
callback
;
bool
once
=
entry
->
once
;
if
(
once
)
{
utarray_erase
(
evt
->
listeners
,
i
,
1
);
n
--
;
}
else
i
++
;
uint8_t
t
=
vtype
(
cb
);
if
(
t
!=
T_FUNC
&&
t
!=
T_CFUNC
)
continue
;
eventemitter_call_listener
(
js
,
cb
,
js_mkundef
(),
call_args
,
1
);
if
(
data
&&
data
->
stop_immediate
)
break
;
}
if
(
data
)
data
->
dispatching
=
false
;
js_set
(
js
,
event_obj
,
"currentTarget"
,
js_mknull
());
js_set
(
js
,
event_obj
,
"eventPhase"
,
js_mknum
(
0
));
bool
canceled
=
data
&&
data
->
canceled
;
return
js_bool
(
!
canceled
);
}
static
ant_value_t
js_add_event_listener_method
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkundef
();
return
add_listener_to
(
js
,
args
,
nargs
,
find_or_create_emitter_event_type
(
js
,
js_getthis
(
js
),
key
));
}
static
ant_value_t
js_add_event_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkundef
();
return
add_listener_to
(
js
,
args
,
nargs
,
find_or_create_global_event_type
(
js
,
key
));
}
static
ant_value_t
js_remove_event_listener_method
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkundef
();
return
remove_listener_from
(
js
,
args
,
nargs
,
find_emitter_event_type
(
js
,
js_getthis
(
js
),
key
));
}
static
ant_value_t
js_remove_event_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkundef
();
return
remove_listener_from
(
js
,
args
,
nargs
,
find_global_event_type
(
js
,
key
));
}
static
ant_value_t
js_dispatch_event_method
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
ant_value_t
this_obj
=
js_getthis
(
js
);
ant_value_t
key
=
js_get
(
js
,
args
[
0
],
"type"
);
if
(
!
evt_key_from_arg
(
key
))
return
js_false
;
return
dispatch_event_to
(
js
,
args
[
0
],
find_emitter_event_type
(
js
,
this_obj
,
key
),
this_obj
);
}
static
ant_value_t
js_dispatch_event
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
ant_value_t
key
=
js_get
(
js
,
args
[
0
],
"type"
);
if
(
!
evt_key_from_arg
(
key
))
return
js_false
;
return
dispatch_event_to
(
js
,
args
[
0
],
find_global_event_type
(
js
,
key
),
js_glob
(
js
));
}
void
js_dispatch_global_event
(
ant_t
*
js
,
ant_value_t
event_obj
)
{
ant_value_t
key
=
js_get
(
js
,
event_obj
,
"type"
);
if
(
!
evt_key_from_arg
(
key
))
return
;
EventType
*
evt
=
find_global_event_type
(
js
,
key
);
if
(
!
evt
||
utarray_len
(
evt
->
listeners
)
==
0
)
return
;
dispatch_event_to
(
js
,
event_obj
,
evt
,
js_glob
(
js
));
}
static
bool
eventemitter_add_listener_impl
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
listener
,
bool
once
,
bool
prepend
)
{
EventType
*
evt
=
NULL
;
EventListenerEntry
entry
=
{
0
};
uint8_t
t
=
0
;
if
(
!
is_object_type
(
target
)
||
!
key
)
return
false
;
t
=
vtype
(
listener
);
if
(
t
!=
T_FUNC
&&
t
!=
T_CFUNC
)
return
false
;
evt
=
find_or_create_emitter_event_type
(
js
,
target
,
key
);
if
(
!
evt
)
return
false
;
entry
.
callback
=
listener
;
entry
.
raw_callback
=
js_mkundef
();
entry
.
signal
=
js_mkundef
();
entry
.
once
=
once
;
entry
.
capture
=
false
;
if
(
once
)
{
entry
.
raw_callback
=
js_heavy_mkfun
(
js
,
js_eventemitter_once_wrapper
,
listener
);
if
(
is_callable
(
entry
.
raw_callback
))
js_set
(
js
,
entry
.
raw_callback
,
"listener"
,
listener
);
}
if
(
!
prepend
||
utarray_len
(
evt
->
listeners
)
==
0
)
utarray_push_back
(
evt
->
listeners
,
&
entry
);
else
{
utarray_push_back
(
evt
->
listeners
,
&
entry
);
EventListenerEntry
*
items
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
0
);
if
(
!
items
)
return
false
;
memmove
(
items
+
1
,
items
,
(
utarray_len
(
evt
->
listeners
)
-
1u
)
*
sizeof
(
*
items
));
items
[
0
]
=
entry
;
}
int
max_listeners
=
eventemitter_get_max_listeners_impl
(
target
);
if
(
max_listeners
>
0
&&
!
evt
->
warned_max_listeners
&&
(
int
)
utarray_len
(
evt
->
listeners
)
>
max_listeners
)
{
evt
->
warned_max_listeners
=
true
;
if
(
vtype
(
key
)
==
T_STR
)
{
fprintf
(
stderr
,
"Warning: Possible EventEmitter memory leak detected. "
"%u '%s' listeners added. Use emitter.setMaxListeners() to increase limit.
\n
"
,
(
unsigned
)
utarray_len
(
evt
->
listeners
),
js_str
(
js
,
key
)
);
}
else
{
fprintf
(
stderr
,
"Warning: Possible EventEmitter memory leak detected. "
"%u listeners added for a Symbol event. Use emitter.setMaxListeners() to increase limit.
\n
"
,
(
unsigned
)
utarray_len
(
evt
->
listeners
)
);
}
}
return
true
;
}
static
bool
eventemitter_remove_listener_impl
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
listener
)
{
EventType
*
evt
=
NULL
;
uint8_t
t
=
0
;
if
(
!
is_object_type
(
target
)
||
!
key
)
return
false
;
t
=
vtype
(
listener
);
if
(
t
!=
T_FUNC
&&
t
!=
T_CFUNC
)
return
false
;
evt
=
find_emitter_event_type
(
js
,
target
,
key
);
if
(
!
evt
)
return
false
;
for
(
unsigned
int
i
=
0
;
i
<
utarray_len
(
evt
->
listeners
);
i
++
)
{
EventListenerEntry
*
entry
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
if
(
entry
->
callback
==
listener
||
entry
->
raw_callback
==
listener
)
{
utarray_erase
(
evt
->
listeners
,
i
,
1
);
return
true
;
}}
return
false
;
}
static
ant_offset_t
eventemitter_listener_count_impl
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
)
{
EventType
*
evt
=
NULL
;
if
(
!
is_object_type
(
target
)
||
!
key
)
return
0
;
evt
=
find_emitter_event_type
(
js
,
target
,
key
);
if
(
!
evt
)
return
0
;
return
(
ant_offset_t
)
utarray_len
(
evt
->
listeners
);
}
static
ant_value_t
js_eventemitter_off
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"off requires 2 arguments (event, listener)"
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkerr
(
js
,
"event must be a string or Symbol"
);
ant_value_t
this_obj
=
js_getthis
(
js
);
remove_listener_from
(
js
,
args
,
nargs
,
find_emitter_event_type
(
js
,
this_obj
,
key
)
);
return
this_obj
;
}
static
bool
eventemitter_emit_args_impl
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
*
args
,
int
nargs
)
{
EventType
*
evt
=
NULL
;
if
(
!
is_object_type
(
target
)
||
!
key
)
return
false
;
evt
=
find_emitter_event_type
(
js
,
target
,
key
);
if
(
!
evt
||
utarray_len
(
evt
->
listeners
)
==
0
)
return
false
;
for
(
unsigned
int
i
=
0
;
i
<
utarray_len
(
evt
->
listeners
);)
{
EventListenerEntry
*
entry
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
ant_value_t
cb
=
entry
->
callback
;
bool
once
=
entry
->
once
;
if
(
once
)
utarray_erase
(
evt
->
listeners
,
i
,
1
);
else
i
++
;
if
(
vtype
(
entry
->
signal
)
!=
T_UNDEF
&&
abort_signal_is_aborted
(
entry
->
signal
))
continue
;
if
(
vtype
(
cb
)
!=
T_FUNC
&&
vtype
(
cb
)
!=
T_CFUNC
)
continue
;
ant_value_t
result
=
eventemitter_call_listener
(
js
,
cb
,
target
,
args
,
nargs
);
if
(
vtype
(
result
)
==
T_ERR
)
{
if
(
vtype
(
key
)
==
T_STR
)
fprintf
(
stderr
,
"Error in event listener for '%s': %s
\n
"
,
js_str
(
js
,
key
),
js_str
(
js
,
result
));
else
fprintf
(
stderr
,
"Error in event listener: %s
\n
"
,
js_str
(
js
,
result
));
}
}
return
true
;
}
static
ant_value_t
js_eventemitter_emit
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"emit requires at least 1 argument (event)"
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkerr
(
js
,
"event must be a string or Symbol"
);
return
js_bool
(
eventemitter_emit_args_impl
(
js
,
js_getthis
(
js
),
key
,
nargs
>
1
?
&
args
[
1
]
:
NULL
,
nargs
-
1
));
}
bool
eventemitter_emit_args_val
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
*
args
,
int
nargs
)
{
return
eventemitter_emit_args_impl
(
js
,
target
,
key
,
args
,
nargs
);
}
bool
eventemitter_emit_args
(
ant_t
*
js
,
ant_value_t
target
,
const
char
*
event_type
,
ant_value_t
*
args
,
int
nargs
)
{
return
eventemitter_emit_args_val
(
js
,
target
,
js_mkstr
(
js
,
event_type
,
strlen
(
event_type
)),
args
,
nargs
);
}
bool
eventemitter_add_listener_val
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
listener
,
bool
once
)
{
return
eventemitter_add_listener_impl
(
js
,
target
,
key
,
listener
,
once
,
false
);
}
bool
eventemitter_add_listener
(
ant_t
*
js
,
ant_value_t
target
,
const
char
*
event_type
,
ant_value_t
listener
,
bool
once
)
{
return
eventemitter_add_listener_val
(
js
,
target
,
js_mkstr
(
js
,
event_type
,
strlen
(
event_type
)),
listener
,
once
);
}
bool
eventemitter_remove_listener_val
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
listener
)
{
return
eventemitter_remove_listener_impl
(
js
,
target
,
key
,
listener
);
}
bool
eventemitter_remove_listener
(
ant_t
*
js
,
ant_value_t
target
,
const
char
*
event_type
,
ant_value_t
listener
)
{
return
eventemitter_remove_listener_val
(
js
,
target
,
js_mkstr
(
js
,
event_type
,
strlen
(
event_type
)),
listener
);
}
ant_offset_t
eventemitter_listener_count_val
(
ant_t
*
js
,
ant_value_t
target
,
ant_value_t
key
)
{
return
eventemitter_listener_count_impl
(
js
,
target
,
key
);
}
ant_offset_t
eventemitter_listener_count
(
ant_t
*
js
,
ant_value_t
target
,
const
char
*
event_type
)
{
return
eventemitter_listener_count_val
(
js
,
target
,
js_mkstr
(
js
,
event_type
,
strlen
(
event_type
)));
}
static
ant_value_t
js_eventemitter_add
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
bool
once
,
bool
prepend
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"requires 2 arguments (event, listener)"
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkerr
(
js
,
"event must be a string or Symbol"
);
if
(
!
eventemitter_add_listener_impl
(
js
,
js_getthis
(
js
),
key
,
args
[
1
],
once
,
prepend
))
return
js_mkerr
(
js
,
"listener must be a function"
);
return
js_getthis
(
js
);
}
static
ant_value_t
js_eventemitter_on
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_eventemitter_add
(
js
,
args
,
nargs
,
false
,
false
);
}
static
ant_value_t
js_eventemitter_once
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_eventemitter_add
(
js
,
args
,
nargs
,
true
,
false
);
}
static
ant_value_t
js_eventemitter_prepend_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_eventemitter_add
(
js
,
args
,
nargs
,
false
,
true
);
}
static
ant_value_t
js_eventemitter_prepend_once_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_eventemitter_add
(
js
,
args
,
nargs
,
true
,
true
);
}
static
ant_value_t
js_eventemitter_removeAllListeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
EventType
**
events
=
NULL
;
if
(
nargs
<
1
||
vtype
(
args
[
0
])
==
T_UNDEF
)
{
events
=
get_or_create_emitter_events
(
js
,
this_obj
);
if
(
!
events
||
!*
events
)
return
this_obj
;
EventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
*
events
,
evt
,
tmp
)
utarray_clear
(
evt
->
listeners
);
return
this_obj
;
}
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
this_obj
;
EventType
*
evt
=
find_emitter_event_type
(
js
,
this_obj
,
key
);
if
(
evt
)
utarray_clear
(
evt
->
listeners
);
return
this_obj
;
}
static
ant_value_t
js_eventemitter_listenerCount
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mknum
(
0
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mknum
(
0
);
EventType
*
evt
=
find_emitter_event_type
(
js
,
js_getthis
(
js
),
key
);
if
(
!
evt
)
return
js_mknum
(
0
);
return
js_mknum
((
double
)
utarray_len
(
evt
->
listeners
));
}
static
ant_value_t
js_eventemitter_setMaxListeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"setMaxListeners requires 1 argument"
);
if
(
vtype
(
args
[
0
])
!=
T_NUM
)
return
js_mkerr
(
js
,
"n must be a number"
);
int
n
=
(
int
)
js_getnum
(
args
[
0
]);
if
(
n
<
0
)
return
js_mkerr
(
js
,
"n must be non-negative"
);
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
!
is_object_type
(
this_obj
))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"setMaxListeners requires an object receiver"
);
js_set_slot
(
this_obj
,
SLOT_EVENT_MAX_LISTENERS
,
js_mknum
(
n
));
return
this_obj
;
}
static
ant_value_t
js_eventemitter_getMaxListeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
!
is_object_type
(
this_obj
))
return
js_mknum
(
EVENTS_DEFAULT_MAX_LISTENERS
);
return
js_mknum
(
eventemitter_get_max_listeners_impl
(
this_obj
));
}
static
ant_value_t
js_eventemitter_rawListeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkarr
(
js
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkarr
(
js
);
return
eventemitter_get_listeners_array
(
js
,
js_getthis
(
js
),
key
,
true
);
}
static
ant_value_t
js_eventemitter_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkarr
(
js
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
0
]);
if
(
!
key
)
return
js_mkarr
(
js
);
return
eventemitter_get_listeners_array
(
js
,
js_getthis
(
js
),
key
,
false
);
}
static
ant_value_t
js_eventemitter_eventNames
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
ant_value_t
result
=
js_mkarr
(
js
);
EventType
**
events
=
get_or_create_emitter_events
(
js
,
this_obj
);
if
(
events
&&
*
events
)
{
EventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
*
events
,
evt
,
tmp
)
if
(
utarray_len
(
evt
->
listeners
)
>
0
)
js_arr_push
(
js
,
result
,
evt
->
js_key
);
}
return
result
;
}
static
ant_value_t
js_events_once_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
!
is_object_type
(
state
))
return
js_mkundef
();
ant_value_t
promise
=
js_get_slot
(
state
,
SLOT_DATA
);
if
(
vtype
(
promise
)
!=
T_PROMISE
)
return
js_mkundef
();
ant_value_t
settled
=
js_get_slot
(
state
,
SLOT_SETTLED
);
if
(
vtype
(
settled
)
==
T_BOOL
&&
settled
==
js_true
)
return
js_mkundef
();
js_set_slot
(
state
,
SLOT_SETTLED
,
js_true
);
ant_value_t
signal
=
js_get
(
js
,
state
,
"signal"
);
ant_value_t
abort_listener
=
js_get
(
js
,
state
,
"abortListener"
);
if
(
abort_signal_is_signal
(
signal
)
&&
is_callable
(
abort_listener
))
abort_signal_remove_listener
(
js
,
signal
,
abort_listener
);
ant_value_t
values
=
js_mkarr
(
js
);
for
(
int
i
=
0
;
i
<
nargs
;
i
++
)
js_arr_push
(
js
,
values
,
args
[
i
]);
js_resolve_promise
(
js
,
promise
,
values
);
return
js_mkundef
();
}
static
ant_value_t
js_events_once_abort_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
!
is_object_type
(
state
))
return
js_mkundef
();
ant_value_t
promise
=
js_get_slot
(
state
,
SLOT_DATA
);
if
(
vtype
(
promise
)
!=
T_PROMISE
)
return
js_mkundef
();
ant_value_t
settled
=
js_get_slot
(
state
,
SLOT_SETTLED
);
if
(
vtype
(
settled
)
==
T_BOOL
&&
settled
==
js_true
)
return
js_mkundef
();
js_set_slot
(
state
,
SLOT_SETTLED
,
js_true
);
ant_value_t
signal
=
js_get
(
js
,
state
,
"signal"
);
ant_value_t
abort_listener
=
js_get
(
js
,
state
,
"abortListener"
);
if
(
abort_signal_is_signal
(
signal
)
&&
is_callable
(
abort_listener
))
abort_signal_remove_listener
(
js
,
signal
,
abort_listener
);
ant_value_t
reason
=
abort_signal_get_reason
(
signal
);
if
(
vtype
(
reason
)
==
T_UNDEF
)
reason
=
js_mkerr
(
js
,
"The operation was aborted"
);
js_reject_promise
(
js
,
promise
,
reason
);
return
js_mkundef
();
}
static
bool
js_events_once_is_abort_key
(
ant_t
*
js
,
ant_value_t
key
)
{
size_t
key_len
=
0
;
const
char
*
key_str
=
vtype
(
key
)
==
T_STR
?
js_getstr
(
js
,
key
,
&
key_len
)
:
NULL
;
return
key_str
&&
key_len
==
5
&&
memcmp
(
key_str
,
"abort"
,
5
)
==
0
;
}
static
void
js_events_once_reject_aborted
(
ant_t
*
js
,
ant_value_t
promise
,
ant_value_t
signal
)
{
ant_value_t
reason
=
abort_signal_get_reason
(
signal
);
if
(
vtype
(
reason
)
==
T_UNDEF
)
reason
=
js_mkerr
(
js
,
"The operation was aborted"
);
js_reject_promise
(
js
,
promise
,
reason
);
}
static
ant_value_t
js_events_once_attach
(
ant_t
*
js
,
ant_value_t
promise
,
ant_value_t
target
,
ant_value_t
key
,
ant_value_t
listener
,
ant_value_t
signal
)
{
if
(
abort_signal_is_signal
(
target
))
{
if
(
!
js_events_once_is_abort_key
(
js
,
key
))
{
js_reject_promise
(
js
,
promise
,
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"AbortSignal only supports the abort event"
));
return
promise
;
}
abort_signal_add_listener
(
js
,
target
,
listener
);
return
promise
;
}
if
(
is_eventemitter_instance
(
target
))
{
if
(
!
eventemitter_add_listener_val
(
js
,
target
,
key
,
listener
,
true
))
js_reject_promise
(
js
,
promise
,
js_mkerr
(
js
,
"listener must be a function"
));
return
promise
;
}
if
(
is_eventtarget_instance
(
target
))
{
ant_value_t
listener_options
=
js_mkobj
(
js
);
js_set
(
js
,
listener_options
,
"once"
,
js_true
);
if
(
abort_signal_is_signal
(
signal
))
js_set
(
js
,
listener_options
,
"signal"
,
signal
);
ant_value_t
call_args
[
3
]
=
{
key
,
listener
,
listener_options
};
ant_value_t
result
=
add_listener_to
(
js
,
call_args
,
3
,
find_or_create_emitter_event_type
(
js
,
target
,
key
));
if
(
is_err
(
result
))
js_reject_promise
(
js
,
promise
,
result
);
return
promise
;
}
js_reject_promise
(
js
,
promise
,
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"target is not an EventEmitter or EventTarget"
));
return
promise
;
}
static
ant_value_t
js_events_once
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
||
!
is_object_type
(
args
[
0
]))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"events.once requires an emitter and event name"
);
ant_value_t
key
=
evt_key_from_arg
(
args
[
1
]);
if
(
!
key
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"event must be a string or Symbol"
);
ant_value_t
promise
=
js_mkpromise
(
js
);
if
(
is_err
(
promise
))
return
promise
;
ant_value_t
state
=
js_mkobj
(
js
);
js_set_slot
(
state
,
SLOT_DATA
,
promise
);
js_set_slot
(
state
,
SLOT_SETTLED
,
js_false
);
ant_value_t
listener
=
js_heavy_mkfun
(
js
,
js_events_once_listener
,
state
);
ant_value_t
target
=
args
[
0
];
ant_value_t
options
=
nargs
>=
3
?
args
[
2
]
:
js_mkundef
();
ant_value_t
signal
=
js_mkundef
();
if
(
is_object_type
(
options
))
signal
=
js_get
(
js
,
options
,
"signal"
);
if
(
abort_signal_is_signal
(
signal
))
{
if
(
abort_signal_is_aborted
(
signal
))
{
js_events_once_reject_aborted
(
js
,
promise
,
signal
);
return
promise
;
}
ant_value_t
abort_listener
=
js_heavy_mkfun
(
js
,
js_events_once_abort_listener
,
state
);
js_set
(
js
,
state
,
"signal"
,
signal
);
js_set
(
js
,
state
,
"abortListener"
,
abort_listener
);
abort_signal_add_listener
(
js
,
signal
,
abort_listener
);
}
return
js_events_once_attach
(
js
,
promise
,
target
,
key
,
listener
,
signal
);
}
static
ant_value_t
js_events_disposable_dispose
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
!
is_object_type
(
state
))
return
js_mkundef
();
ant_value_t
disposed
=
js_get_slot
(
state
,
SLOT_SETTLED
);
if
(
vtype
(
disposed
)
==
T_BOOL
&&
disposed
==
js_true
)
return
js_mkundef
();
js_set_slot
(
state
,
SLOT_SETTLED
,
js_true
);
ant_value_t
signal
=
js_get
(
js
,
state
,
"signal"
);
ant_value_t
listener
=
js_get
(
js
,
state
,
"listener"
);
if
(
abort_signal_is_signal
(
signal
)
&&
is_callable
(
listener
))
abort_signal_remove_listener
(
js
,
signal
,
listener
);
return
js_mkundef
();
}
static
ant_value_t
js_events_add_abort_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
||
!
abort_signal_is_signal
(
args
[
0
])
||
!
is_callable
(
args
[
1
]))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"events.addAbortListener requires an AbortSignal and listener"
);
bool
already_aborted
=
abort_signal_is_aborted
(
args
[
0
]);
if
(
already_aborted
)
{
ant_value_t
event
=
js_mkobj
(
js
);
js_set
(
js
,
event
,
"type"
,
js_mkstr
(
js
,
"abort"
,
5
));
eventemitter_call_listener
(
js
,
args
[
1
],
args
[
0
],
&
event
,
1
);
}
else
abort_signal_add_listener
(
js
,
args
[
0
],
args
[
1
]);
ant_value_t
state
=
js_mkobj
(
js
);
js_set_slot
(
state
,
SLOT_SETTLED
,
js_bool
(
already_aborted
));
js_set
(
js
,
state
,
"signal"
,
args
[
0
]);
js_set
(
js
,
state
,
"listener"
,
args
[
1
]);
ant_value_t
disposable
=
js_mkobj
(
js
);
js_set
(
js
,
disposable
,
"dispose"
,
js_heavy_mkfun
(
js
,
js_events_disposable_dispose
,
state
));
return
disposable
;
}
static
ant_value_t
js_events_set_max_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"setMaxListeners requires at least 1 argument"
);
if
(
vtype
(
args
[
0
])
!=
T_NUM
)
return
js_mkerr
(
js
,
"n must be a number"
);
int
n
=
(
int
)
js_getnum
(
args
[
0
]);
if
(
n
<
0
)
return
js_mkerr
(
js
,
"n must be non-negative"
);
for
(
int
i
=
1
;
i
<
nargs
;
i
++
)
{
if
(
!
is_object_type
(
args
[
i
]))
continue
;
js_set_slot
(
args
[
i
],
SLOT_EVENT_MAX_LISTENERS
,
js_mknum
(
n
));
}
return
js_mkundef
();
}
static
ant_value_t
js_events_get_max_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mknum
(
EVENTS_DEFAULT_MAX_LISTENERS
);
if
(
!
is_object_type
(
args
[
0
]))
return
js_mknum
(
EVENTS_DEFAULT_MAX_LISTENERS
);
return
js_mknum
(
eventemitter_get_max_listeners_impl
(
args
[
0
]));
}
// TODO: fix stub
static
ant_value_t
js_events_on
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"events.on async iterator is not implemented"
);
}
ant_value_t
events_library
(
ant_t
*
js
)
{
ant_value_t
lib
=
js_mkobj
(
js
);
eventemitter_prototype
(
js
);
js_set_module_default
(
js
,
lib
,
g_eventemitter_ctor
,
"EventEmitter"
);
js_set
(
js
,
lib
,
"once"
,
js_mkfun
(
js_events_once
));
js_set
(
js
,
lib
,
"on"
,
js_mkfun
(
js_events_on
));
js_set
(
js
,
lib
,
"addAbortListener"
,
js_mkfun
(
js_events_add_abort_listener
));
js_set
(
js
,
lib
,
"setMaxListeners"
,
js_mkfun
(
js_events_set_max_listeners
));
js_set
(
js
,
lib
,
"getMaxListeners"
,
js_mkfun
(
js_events_get_max_listeners
));
js_set_sym
(
js
,
lib
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"events"
,
6
));
return
lib
;
}
ant_value_t
eventemitter_prototype
(
ant_t
*
js
)
{
if
(
g_eventemitter_proto
)
return
g_eventemitter_proto
;
ant_value_t
object_proto
=
js
->
sym
.
object_proto
;
ant_value_t
function_proto
=
js_get_slot
(
js_glob
(
js
),
SLOT_FUNC_PROTO
);
if
(
vtype
(
function_proto
)
==
T_UNDEF
)
function_proto
=
js_get_ctor_proto
(
js
,
"Function"
,
8
);
ant_value_t
eventemitter_ctor
=
js_mkobj
(
js
);
ant_value_t
eventemitter_proto
=
js_mkobj
(
js
);
if
(
is_object_type
(
object_proto
))
js_set_proto_init
(
eventemitter_proto
,
object_proto
);
if
(
is_object_type
(
function_proto
))
js_set_proto_init
(
eventemitter_ctor
,
function_proto
);
js_set
(
js
,
eventemitter_proto
,
"on"
,
js_mkfun
(
js_eventemitter_on
));
js_set_exact
(
js
,
eventemitter_proto
,
"addListener"
,
js_get
(
js
,
eventemitter_proto
,
"on"
));
js_set
(
js
,
eventemitter_proto
,
"once"
,
js_mkfun
(
js_eventemitter_once
));
js_set
(
js
,
eventemitter_proto
,
"prependListener"
,
js_mkfun
(
js_eventemitter_prepend_listener
));
js_set
(
js
,
eventemitter_proto
,
"prependOnceListener"
,
js_mkfun
(
js_eventemitter_prepend_once_listener
));
js_set
(
js
,
eventemitter_proto
,
"off"
,
js_mkfun
(
js_eventemitter_off
));
js_set_exact
(
js
,
eventemitter_proto
,
"removeListener"
,
js_get
(
js
,
eventemitter_proto
,
"off"
));
js_set
(
js
,
eventemitter_proto
,
"emit"
,
js_mkfun
(
js_eventemitter_emit
));
js_set
(
js
,
eventemitter_proto
,
"removeAllListeners"
,
js_mkfun
(
js_eventemitter_removeAllListeners
));
js_set
(
js
,
eventemitter_proto
,
"listenerCount"
,
js_mkfun
(
js_eventemitter_listenerCount
));
js_set
(
js
,
eventemitter_proto
,
"setMaxListeners"
,
js_mkfun
(
js_eventemitter_setMaxListeners
));
js_set
(
js
,
eventemitter_proto
,
"getMaxListeners"
,
js_mkfun
(
js_eventemitter_getMaxListeners
));
js_set
(
js
,
eventemitter_proto
,
"listeners"
,
js_mkfun
(
js_eventemitter_listeners
));
js_set
(
js
,
eventemitter_proto
,
"rawListeners"
,
js_mkfun
(
js_eventemitter_rawListeners
));
js_set
(
js
,
eventemitter_proto
,
"eventNames"
,
js_mkfun
(
js_eventemitter_eventNames
));
js_set_sym
(
js
,
eventemitter_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"EventEmitter"
,
12
));
js_set_slot
(
eventemitter_ctor
,
SLOT_CFUNC
,
js_mkfun
(
js_eventemitter_ctor
));
js_mkprop_fast
(
js
,
eventemitter_ctor
,
"prototype"
,
9
,
eventemitter_proto
);
js_mkprop_fast
(
js
,
eventemitter_ctor
,
"name"
,
4
,
ANT_STRING
(
"EventEmitter"
));
js_set_descriptor
(
js
,
eventemitter_ctor
,
"name"
,
4
,
0
);
g_eventemitter_proto
=
eventemitter_proto
;
g_eventemitter_ctor
=
js_obj_to_func
(
eventemitter_ctor
);
js_set
(
js
,
eventemitter_proto
,
"constructor"
,
g_eventemitter_ctor
);
js_set_descriptor
(
js
,
eventemitter_proto
,
"constructor"
,
11
,
JS_DESC_W
|
JS_DESC_C
);
return
g_eventemitter_proto
;
}
void
init_events_module
(
void
)
{
ant_t
*
js
=
rt
->
js
;
ant_value_t
global
=
js_glob
(
js
);
g_isTrusted_getter
=
js_mkfun
(
js_event_get_isTrusted
);
g_event_proto
=
js_mkobj
(
js
);
js_set_sym
(
js
,
g_event_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"Event"
,
5
));
js_set
(
js
,
g_event_proto
,
"preventDefault"
,
js_mkfun
(
js_event_preventDefault
));
js_set
(
js
,
g_event_proto
,
"stopPropagation"
,
js_mkfun
(
js_event_stopPropagation
));
js_set
(
js
,
g_event_proto
,
"stopImmediatePropagation"
,
js_mkfun
(
js_event_stopImmediatePropagation
));
js_set
(
js
,
g_event_proto
,
"composedPath"
,
js_mkfun
(
js_event_composedPath
));
js_set
(
js
,
g_event_proto
,
"initEvent"
,
js_mkfun
(
js_event_initEvent
));
js_set
(
js
,
g_event_proto
,
"NONE"
,
js_mknum
(
0
));
js_set
(
js
,
g_event_proto
,
"CAPTURING_PHASE"
,
js_mknum
(
1
));
js_set
(
js
,
g_event_proto
,
"AT_TARGET"
,
js_mknum
(
2
));
js_set
(
js
,
g_event_proto
,
"BUBBLING_PHASE"
,
js_mknum
(
3
));
ant_value_t
event_fn
=
js_make_ctor
(
js
,
js_event_ctor
,
g_event_proto
,
"Event"
,
5
);
js_set
(
js
,
event_fn
,
"NONE"
,
js_mknum
(
0
));
js_set
(
js
,
event_fn
,
"CAPTURING_PHASE"
,
js_mknum
(
1
));
js_set
(
js
,
event_fn
,
"AT_TARGET"
,
js_mknum
(
2
));
js_set
(
js
,
event_fn
,
"BUBBLING_PHASE"
,
js_mknum
(
3
));
js_set
(
js
,
global
,
"Event"
,
event_fn
);
g_customevent_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
g_customevent_proto
,
g_event_proto
);
js_set_sym
(
js
,
g_customevent_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"CustomEvent"
,
11
));
ant_value_t
customevent_fn
=
js_make_ctor
(
js
,
js_customevent_ctor
,
g_customevent_proto
,
"CustomEvent"
,
11
);
js_set
(
js
,
global
,
"CustomEvent"
,
customevent_fn
);
g_errorevent_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
g_errorevent_proto
,
g_event_proto
);
js_set_sym
(
js
,
g_errorevent_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"ErrorEvent"
,
10
));
ant_value_t
errorevent_fn
=
js_make_ctor
(
js
,
js_errorevent_ctor
,
g_errorevent_proto
,
"ErrorEvent"
,
10
);
js_set
(
js
,
global
,
"ErrorEvent"
,
errorevent_fn
);
g_promiserejectionevent_proto
=
js_mkobj
(
js
);
js_set_proto_init
(
g_promiserejectionevent_proto
,
g_event_proto
);
js_set_sym
(
js
,
g_promiserejectionevent_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"PromiseRejectionEvent"
,
21
));
ant_value_t
pre_fn
=
js_make_ctor
(
js
,
js_promiserejectionevent_ctor
,
g_promiserejectionevent_proto
,
"PromiseRejectionEvent"
,
21
);
js_set
(
js
,
global
,
"PromiseRejectionEvent"
,
pre_fn
);
ant_value_t
object_proto
=
js
->
sym
.
object_proto
;
ant_value_t
function_proto
=
js_get_slot
(
global
,
SLOT_FUNC_PROTO
);
if
(
vtype
(
function_proto
)
==
T_UNDEF
)
function_proto
=
js_get_ctor_proto
(
js
,
"Function"
,
8
);
ant_value_t
eventtarget_proto
=
js_mkobj
(
js
);
g_eventtarget_proto
=
eventtarget_proto
;
if
(
is_object_type
(
object_proto
))
js_set_proto_init
(
eventtarget_proto
,
object_proto
);
js_set
(
js
,
eventtarget_proto
,
"addEventListener"
,
js_mkfun
(
js_add_event_listener_method
));
js_set
(
js
,
eventtarget_proto
,
"removeEventListener"
,
js_mkfun
(
js_remove_event_listener_method
));
js_set
(
js
,
eventtarget_proto
,
"dispatchEvent"
,
js_mkfun
(
js_dispatch_event_method
));
js_set_sym
(
js
,
eventtarget_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"EventTarget"
,
11
));
ant_value_t
eventtarget_ctor
=
js_mkobj
(
js
);
if
(
is_object_type
(
function_proto
))
js_set_proto_init
(
eventtarget_ctor
,
function_proto
);
js_set_slot
(
eventtarget_ctor
,
SLOT_CFUNC
,
js_mkfun
(
js_eventtarget_ctor
));
js_mkprop_fast
(
js
,
eventtarget_ctor
,
"prototype"
,
9
,
eventtarget_proto
);
js_mkprop_fast
(
js
,
eventtarget_ctor
,
"name"
,
4
,
ANT_STRING
(
"EventTarget"
));
js_set_descriptor
(
js
,
eventtarget_ctor
,
"name"
,
4
,
0
);
ant_value_t
eventtarget_fn
=
js_obj_to_func
(
eventtarget_ctor
);
js_set
(
js
,
eventtarget_proto
,
"constructor"
,
eventtarget_fn
);
js_set_descriptor
(
js
,
eventtarget_proto
,
"constructor"
,
11
,
JS_DESC_W
|
JS_DESC_C
);
js_set
(
js
,
global
,
"addEventListener"
,
js_mkfun
(
js_add_event_listener
));
js_set
(
js
,
global
,
"removeEventListener"
,
js_mkfun
(
js_remove_event_listener
));
js_set
(
js
,
global
,
"dispatchEvent"
,
js_mkfun
(
js_dispatch_event
));
js_set
(
js
,
global
,
"EventTarget"
,
eventtarget_fn
);
}
static
void
mark_event_type_listeners
(
ant_t
*
js
,
gc_mark_fn
mark
,
EventType
*
events
)
{
EventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
events
,
evt
,
tmp
)
{
if
(
vtype
(
evt
->
js_key
)
==
T_STR
)
mark
(
js
,
evt
->
js_key
);
for
(
unsigned
int
i
=
0
;
i
<
utarray_len
(
evt
->
listeners
);
i
++
)
{
EventListenerEntry
*
e
=
(
EventListenerEntry
*
)
utarray_eltptr
(
evt
->
listeners
,
i
);
mark
(
js
,
e
->
callback
);
if
(
vtype
(
e
->
raw_callback
)
!=
T_UNDEF
)
mark
(
js
,
e
->
raw_callback
);
if
(
vtype
(
e
->
signal
)
!=
T_UNDEF
)
mark
(
js
,
e
->
signal
);
}
}}
void
gc_mark_events
(
ant_t
*
js
,
gc_mark_fn
mark
)
{
mark_event_type_listeners
(
js
,
mark
,
global_events
);
for
(
emitter_reg_t
*
reg
=
emitter_registry
;
reg
;
reg
=
reg
->
next
)
{
if
(
*
reg
->
events
)
mark_event_type_listeners
(
js
,
mark
,
*
reg
->
events
);
}
if
(
g_isTrusted_getter
)
mark
(
js
,
g_isTrusted_getter
);
if
(
g_eventemitter_ctor
)
mark
(
js
,
g_eventemitter_ctor
);
if
(
g_eventemitter_proto
)
mark
(
js
,
g_eventemitter_proto
);
if
(
g_eventtarget_proto
)
mark
(
js
,
g_eventtarget_proto
);
if
(
g_event_proto
)
mark
(
js
,
g_event_proto
);
if
(
g_customevent_proto
)
mark
(
js
,
g_customevent_proto
);
if
(
g_errorevent_proto
)
mark
(
js
,
g_errorevent_proto
);
if
(
g_promiserejectionevent_proto
)
mark
(
js
,
g_promiserejectionevent_proto
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 11:16 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
541771
Default Alt Text
events.c (50 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment