Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4407320
using.h
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
using.h
View Options
#ifndef SV_USING_H
#define SV_USING_H
#include
"silver/engine.h"
#include
"errors.h"
#include
"gc/roots.h"
#include
"modules/symbol.h"
typedef
enum
{
SV_DISPOSAL_RECORD_DEFER
=
0
,
SV_DISPOSAL_RECORD_ADOPT
=
1
,
SV_DISPOSAL_RECORD_USE
=
2
}
sv_disposal_record_kind_t
;
static
inline
void
sv_using_array_clear
(
ant_value_t
arr
)
{
ant_object_t
*
ptr
=
js_obj_ptr
(
js_as_obj
(
arr
));
if
(
ptr
&&
ptr
->
type_tag
==
T_ARR
)
ptr
->
u
.
array
.
len
=
0
;
}
static
inline
ant_value_t
sv_make_suppressed_error_value
(
ant_t
*
js
,
ant_value_t
error
,
ant_value_t
suppressed
)
{
GC_ROOT_SAVE
(
root_mark
,
js
);
GC_ROOT_PIN
(
js
,
error
);
GC_ROOT_PIN
(
js
,
suppressed
);
ant_value_t
obj
=
js_mkobj
(
js
);
GC_ROOT_PIN
(
js
,
obj
);
if
(
is_err
(
obj
))
{
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
obj
;
}
ant_value_t
proto
=
js_get_ctor_proto
(
js
,
"SuppressedError"
,
15
);
if
(
is_object_type
(
proto
))
js_set_proto_init
(
obj
,
proto
);
js_mkprop_fast
(
js
,
obj
,
"error"
,
5
,
error
);
js_mkprop_fast
(
js
,
obj
,
"suppressed"
,
10
,
suppressed
);
js_mkprop_fast
(
js
,
obj
,
"message"
,
7
,
ANT_STRING
(
"An error was suppressed during disposal."
));
js_mkprop_fast
(
js
,
obj
,
"name"
,
4
,
ANT_STRING
(
"SuppressedError"
));
js_set_slot
(
obj
,
SLOT_ERROR_BRAND
,
js_true
);
js_capture_stack
(
js
,
obj
);
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
obj
;
}
static
inline
ant_value_t
sv_disposal_error_value
(
ant_t
*
js
,
ant_value_t
result
)
{
if
(
js
->
thrown_exists
)
{
ant_value_t
thrown
=
js
->
thrown_value
;
js
->
thrown_value
=
js_mkundef
();
js
->
thrown_stack
=
js_mkundef
();
js
->
thrown_exists
=
false
;
return
thrown
;
}
if
(
is_err
(
result
))
{
if
(
vdata
(
result
)
!=
0
)
return
mkval
(
T_OBJ
,
vdata
(
result
));
return
js_make_error_silent
(
js
,
JS_ERR_INTERNAL
,
"unknown disposal error"
);
}
return
result
;
}
static
inline
ant_value_t
sv_suppress_disposal_error
(
ant_t
*
js
,
ant_value_t
error
,
ant_value_t
previous
)
{
if
(
vtype
(
previous
)
==
T_UNDEF
)
return
error
;
return
sv_make_suppressed_error_value
(
js
,
error
,
previous
);
}
static
inline
ant_value_t
sv_disposal_record_call
(
ant_t
*
js
,
ant_value_t
record
)
{
ant_value_t
kind_v
=
js_arr_get
(
js
,
record
,
0
);
ant_value_t
value
=
js_arr_get
(
js
,
record
,
1
);
ant_value_t
method
=
js_arr_get
(
js
,
record
,
2
);
int
kind
=
vtype
(
kind_v
)
==
T_NUM
?
(
int
)
js_getnum
(
kind_v
)
:
-1
;
ant_value_t
this_arg
=
kind
==
SV_DISPOSAL_RECORD_USE
?
value
:
js_mkundef
();
ant_value_t
arg
=
value
;
ant_value_t
*
args
=
kind
==
SV_DISPOSAL_RECORD_ADOPT
?
&
arg
:
NULL
;
int
nargs
=
kind
==
SV_DISPOSAL_RECORD_ADOPT
?
1
:
0
;
if
(
!
is_callable
(
method
))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"disposer is not callable"
);
if
(
vtype
(
method
)
==
T_CFUNC
)
{
ant_value_t
saved_this
=
js
->
this_val
;
js
->
this_val
=
this_arg
;
ant_value_t
result
=
js_as_cfunc
(
method
)(
js
,
args
,
nargs
);
js
->
this_val
=
saved_this
;
return
result
;
}
return
sv_vm_call
(
js
->
vm
,
js
,
method
,
this_arg
,
args
,
nargs
,
NULL
,
false
);
}
static
inline
ant_value_t
sv_dispose_resource
(
ant_t
*
js
,
ant_value_t
resource
,
bool
is_async
)
{
if
(
vtype
(
resource
)
==
T_NULL
||
vtype
(
resource
)
==
T_UNDEF
)
return
js_mkundef
();
ant_value_t
method
=
js_get_sym
(
js
,
resource
,
is_async
?
get_asyncDispose_sym
()
:
get_dispose_sym
());
if
(
is_async
&&
(
vtype
(
method
)
==
T_UNDEF
||
vtype
(
method
)
==
T_NULL
))
method
=
js_get_sym
(
js
,
resource
,
get_dispose_sym
());
if
(
!
is_callable
(
method
))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
is_async
?
"resource is not async disposable"
:
"resource is not disposable"
);
if
(
vtype
(
method
)
==
T_CFUNC
)
{
ant_value_t
saved_this
=
js
->
this_val
;
js
->
this_val
=
resource
;
ant_value_t
result
=
js_as_cfunc
(
method
)(
js
,
NULL
,
0
);
js
->
this_val
=
saved_this
;
return
result
;
}
return
sv_vm_call
(
js
->
vm
,
js
,
method
,
resource
,
NULL
,
0
,
NULL
,
false
);
}
static
inline
ant_value_t
sv_using_push
(
ant_t
*
js
,
ant_value_t
entries
,
ant_value_t
resource
,
bool
is_async
)
{
if
(
vtype
(
resource
)
==
T_NULL
||
vtype
(
resource
)
==
T_UNDEF
)
return
resource
;
if
(
vtype
(
entries
)
!=
T_ARR
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"invalid using disposal stack"
);
GC_ROOT_SAVE
(
root_mark
,
js
);
GC_ROOT_PIN
(
js
,
entries
);
GC_ROOT_PIN
(
js
,
resource
);
ant_value_t
method
=
js_get_sym
(
js
,
resource
,
is_async
?
get_asyncDispose_sym
()
:
get_dispose_sym
());
if
(
is_async
&&
(
vtype
(
method
)
==
T_UNDEF
||
vtype
(
method
)
==
T_NULL
))
method
=
js_get_sym
(
js
,
resource
,
get_dispose_sym
());
GC_ROOT_PIN
(
js
,
method
);
if
(
!
is_callable
(
method
))
{
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"resource is not disposable"
);
}
ant_value_t
record
=
js_mkarr
(
js
);
GC_ROOT_PIN
(
js
,
record
);
if
(
is_err
(
record
))
{
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
record
;
}
js_arr_push
(
js
,
record
,
js_mknum
((
double
)
SV_DISPOSAL_RECORD_USE
));
js_arr_push
(
js
,
record
,
resource
);
js_arr_push
(
js
,
record
,
method
);
js_arr_push
(
js
,
entries
,
record
);
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
resource
;
}
static
inline
ant_value_t
sv_dispose_records_sync
(
ant_t
*
js
,
ant_value_t
records
,
ant_offset_t
len
,
ant_value_t
*
completion
,
bool
throw_completion
)
{
for
(
ant_offset_t
i
=
len
;
i
>
0
;
i
--
)
{
GC_ROOT_SAVE
(
iter_mark
,
js
);
ant_value_t
record
=
js_arr_get
(
js
,
records
,
i
-
1
);
GC_ROOT_PIN
(
js
,
record
);
ant_value_t
result
=
sv_disposal_record_call
(
js
,
record
);
if
(
is_err
(
result
)
||
js
->
thrown_exists
)
{
ant_value_t
error
=
sv_disposal_error_value
(
js
,
result
);
GC_ROOT_PIN
(
js
,
error
);
*
completion
=
sv_suppress_disposal_error
(
js
,
error
,
*
completion
);
if
(
is_err
(
*
completion
))
{
GC_ROOT_RESTORE
(
js
,
iter_mark
);
return
*
completion
;
}}
GC_ROOT_RESTORE
(
js
,
iter_mark
);
}
if
(
throw_completion
&&
vtype
(
*
completion
)
!=
T_UNDEF
)
{
ant_value_t
thrown
=
js_throw
(
js
,
*
completion
);
return
thrown
;
}
return
*
completion
;
}
static
inline
ant_value_t
sv_using_dispose_sync
(
ant_t
*
js
,
ant_value_t
entries
,
ant_value_t
completion
,
bool
throw_completion
)
{
if
(
vtype
(
entries
)
!=
T_ARR
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"invalid using disposal stack"
);
GC_ROOT_SAVE
(
root_mark
,
js
);
GC_ROOT_PIN
(
js
,
entries
);
GC_ROOT_PIN
(
js
,
completion
);
ant_offset_t
len
=
js_arr_len
(
js
,
entries
);
ant_value_t
work
=
js_mkarr
(
js
);
GC_ROOT_PIN
(
js
,
work
);
if
(
is_err
(
work
))
{
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
work
;
}
for
(
ant_offset_t
i
=
0
;
i
<
len
;
i
++
)
{
GC_ROOT_SAVE
(
copy_mark
,
js
);
ant_value_t
record
=
js_arr_get
(
js
,
entries
,
i
);
GC_ROOT_PIN
(
js
,
record
);
js_arr_push
(
js
,
work
,
record
);
GC_ROOT_RESTORE
(
js
,
copy_mark
);
}
sv_using_array_clear
(
entries
);
ant_value_t
result
=
sv_dispose_records_sync
(
js
,
work
,
js_arr_len
(
js
,
work
),
&
completion
,
throw_completion
);
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
result
;
}
static
inline
ant_value_t
sv_async_dispose_continue
(
ant_t
*
js
,
ant_value_t
state
,
bool
rejected
,
ant_value_t
reason
);
static
inline
ant_value_t
sv_async_dispose_on_fulfilled
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
return
sv_async_dispose_continue
(
js
,
state
,
false
,
js_mkundef
());
}
static
inline
ant_value_t
sv_async_dispose_on_rejected
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
return
sv_async_dispose_continue
(
js
,
state
,
true
,
nargs
>
0
?
args
[
0
]
:
js_mkundef
());
}
static
inline
ant_value_t
sv_async_dispose_continue
(
ant_t
*
js
,
ant_value_t
state
,
bool
rejected
,
ant_value_t
reason
)
{
GC_ROOT_SAVE
(
root_mark
,
js
);
GC_ROOT_PIN
(
js
,
state
);
GC_ROOT_PIN
(
js
,
reason
);
ant_value_t
entries
=
js_get_slot
(
state
,
SLOT_ENTRIES
);
ant_value_t
result_promise
=
js_get_slot
(
state
,
SLOT_DATA
);
ant_value_t
completion
=
js_get_slot
(
state
,
SLOT_AUX
);
GC_ROOT_PIN
(
js
,
entries
);
GC_ROOT_PIN
(
js
,
result_promise
);
GC_ROOT_PIN
(
js
,
completion
);
if
(
rejected
)
{
completion
=
sv_suppress_disposal_error
(
js
,
reason
,
completion
);
GC_ROOT_PIN
(
js
,
completion
);
js_set_slot
(
state
,
SLOT_AUX
,
completion
);
}
ant_value_t
idx_v
=
js_get_slot
(
state
,
SLOT_ITER_STATE
);
ant_offset_t
idx
=
vtype
(
idx_v
)
==
T_NUM
?
(
ant_offset_t
)
js_getnum
(
idx_v
)
:
0
;
while
(
idx
>
0
)
{
GC_ROOT_SAVE
(
iter_mark
,
js
);
idx
--
;
js_set_slot
(
state
,
SLOT_ITER_STATE
,
js_mknum
((
double
)
idx
));
ant_value_t
record
=
js_arr_get
(
js
,
entries
,
idx
);
GC_ROOT_PIN
(
js
,
record
);
ant_value_t
result
=
sv_disposal_record_call
(
js
,
record
);
GC_ROOT_PIN
(
js
,
result
);
if
(
is_err
(
result
)
||
js
->
thrown_exists
)
{
ant_value_t
error
=
sv_disposal_error_value
(
js
,
result
);
GC_ROOT_PIN
(
js
,
error
);
completion
=
sv_suppress_disposal_error
(
js
,
error
,
completion
);
js_set_slot
(
state
,
SLOT_AUX
,
completion
);
GC_ROOT_RESTORE
(
js
,
iter_mark
);
continue
;
}
if
(
vtype
(
result
)
==
T_PROMISE
)
{
ant_value_t
on_fulfilled
=
js_heavy_mkfun
(
js
,
sv_async_dispose_on_fulfilled
,
state
);
GC_ROOT_PIN
(
js
,
on_fulfilled
);
ant_value_t
on_rejected
=
js_heavy_mkfun
(
js
,
sv_async_dispose_on_rejected
,
state
);
GC_ROOT_PIN
(
js
,
on_rejected
);
js_promise_then
(
js
,
result
,
on_fulfilled
,
on_rejected
);
GC_ROOT_RESTORE
(
js
,
iter_mark
);
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
result_promise
;
}
GC_ROOT_RESTORE
(
js
,
iter_mark
);
}
if
(
vtype
(
completion
)
!=
T_UNDEF
)
js_reject_promise
(
js
,
result_promise
,
completion
);
else
js_resolve_promise
(
js
,
result_promise
,
js_mkundef
());
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
result_promise
;
}
static
inline
ant_value_t
sv_using_dispose_async
(
ant_t
*
js
,
ant_value_t
entries
,
ant_value_t
completion
)
{
ant_value_t
result_promise
=
js_mkpromise
(
js
);
if
(
is_err
(
result_promise
))
return
result_promise
;
GC_ROOT_SAVE
(
root_mark
,
js
);
GC_ROOT_PIN
(
js
,
result_promise
);
GC_ROOT_PIN
(
js
,
completion
);
if
(
vtype
(
entries
)
!=
T_ARR
)
{
ant_value_t
error
=
js_make_error_silent
(
js
,
JS_ERR_TYPE
,
"invalid using disposal stack"
);
GC_ROOT_PIN
(
js
,
error
);
js_reject_promise
(
js
,
result_promise
,
error
);
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
result_promise
;
}
GC_ROOT_PIN
(
js
,
entries
);
ant_offset_t
len
=
js_arr_len
(
js
,
entries
);
ant_value_t
work
=
js_mkarr
(
js
);
GC_ROOT_PIN
(
js
,
work
);
if
(
is_err
(
work
))
{
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
work
;
}
for
(
ant_offset_t
i
=
0
;
i
<
len
;
i
++
)
{
GC_ROOT_SAVE
(
copy_mark
,
js
);
ant_value_t
record
=
js_arr_get
(
js
,
entries
,
i
);
GC_ROOT_PIN
(
js
,
record
);
js_arr_push
(
js
,
work
,
record
);
GC_ROOT_RESTORE
(
js
,
copy_mark
);
}
sv_using_array_clear
(
entries
);
ant_value_t
state
=
js_mkobj
(
js
);
GC_ROOT_PIN
(
js
,
state
);
if
(
is_err
(
state
))
{
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
state
;
}
js_set_slot
(
state
,
SLOT_ENTRIES
,
work
);
js_set_slot
(
state
,
SLOT_DATA
,
result_promise
);
js_set_slot
(
state
,
SLOT_AUX
,
completion
);
js_set_slot
(
state
,
SLOT_ITER_STATE
,
js_mknum
((
double
)
js_arr_len
(
js
,
work
)));
ant_value_t
result
=
sv_async_dispose_continue
(
js
,
state
,
false
,
js_mkundef
());
GC_ROOT_RESTORE
(
js
,
root_mark
);
return
result
;
}
static
inline
ant_value_t
sv_using_dispose
(
ant_t
*
js
,
ant_value_t
entries
,
ant_value_t
completion
,
bool
is_async
,
bool
suppressed
)
{
ant_value_t
actual_completion
=
suppressed
?
completion
:
js_mkundef
();
if
(
is_async
)
return
sv_using_dispose_async
(
js
,
entries
,
actual_completion
);
return
sv_using_dispose_sync
(
js
,
entries
,
actual_completion
,
!
suppressed
);
}
static
inline
ant_value_t
sv_op_using_push
(
sv_vm_t
*
vm
,
ant_t
*
js
,
bool
is_async
)
{
ant_value_t
resource
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
entries
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
result
=
sv_using_push
(
js
,
entries
,
resource
,
is_async
);
if
(
!
is_err
(
result
))
vm
->
stack
[
vm
->
sp
++
]
=
result
;
return
result
;
}
static
inline
ant_value_t
sv_op_dispose_resource
(
sv_vm_t
*
vm
,
ant_t
*
js
,
bool
is_async
)
{
ant_value_t
resource
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
result
=
sv_dispose_resource
(
js
,
resource
,
is_async
);
if
(
!
is_err
(
result
))
vm
->
stack
[
vm
->
sp
++
]
=
result
;
return
result
;
}
static
inline
ant_value_t
sv_op_using_dispose
(
sv_vm_t
*
vm
,
ant_t
*
js
,
bool
is_async
,
bool
suppressed
)
{
ant_value_t
completion
=
suppressed
?
vm
->
stack
[
--
vm
->
sp
]
:
js_mkundef
();
ant_value_t
entries
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
result
=
sv_using_dispose
(
js
,
entries
,
completion
,
is_async
,
suppressed
);
if
(
!
is_err
(
result
))
vm
->
stack
[
vm
->
sp
++
]
=
result
;
return
result
;
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, May 1, 6:23 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
542817
Default Alt Text
using.h (12 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment