Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4398655
iteration.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
iteration.h
View Options
#ifndef SV_ITERATION_H
#define SV_ITERATION_H
#include
"ant.h"
#include
"async.h"
#include
"utf8.h"
#include
"property.h"
#include
"silver/engine.h"
#include
"modules/symbol.h"
#include
"modules/collections.h"
#define SV_ITER_GENERIC 0
#define SV_ITER_ARRAY 1
#define SV_ITER_MAP 2
#define SV_ITER_SET 3
#define SV_ITER_STRING 4
static
inline
ant_value_t
sv_op_for_in
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
ant_value_t
obj
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
keys
=
js_for_in_keys
(
js
,
obj
);
if
(
is_err
(
keys
))
return
keys
;
vm
->
stack
[
vm
->
sp
++
]
=
keys
;
return
tov
(
0
);
}
static
inline
bool
sv_is_map_iter
(
ant_t
*
js
,
ant_value_t
obj
,
map_iterator_state_t
**
out_state
,
iter_type_t
*
out_type
)
{
if
(
vtype
(
obj
)
!=
T_OBJ
)
return
false
;
if
(
!
g_map_iter_proto
||
js_get_proto
(
js
,
obj
)
!=
g_map_iter_proto
)
return
false
;
ant_value_t
state_val
=
js_get_slot
(
obj
,
SLOT_ITER_STATE
);
if
(
vtype
(
state_val
)
==
T_UNDEF
)
return
false
;
map_iterator_state_t
*
st
=
(
map_iterator_state_t
*
)(
uintptr_t
)
js_getnum
(
state_val
);
if
(
!
st
)
return
false
;
*
out_state
=
st
;
*
out_type
=
st
->
type
;
return
true
;
}
static
inline
bool
sv_is_set_iter
(
ant_t
*
js
,
ant_value_t
obj
,
set_iterator_state_t
**
out_state
,
iter_type_t
*
out_type
)
{
if
(
vtype
(
obj
)
!=
T_OBJ
)
return
false
;
if
(
!
g_set_iter_proto
||
js_get_proto
(
js
,
obj
)
!=
g_set_iter_proto
)
return
false
;
ant_value_t
state_val
=
js_get_slot
(
obj
,
SLOT_ITER_STATE
);
if
(
vtype
(
state_val
)
==
T_UNDEF
)
return
false
;
set_iterator_state_t
*
st
=
(
set_iterator_state_t
*
)(
uintptr_t
)
js_getnum
(
state_val
);
if
(
!
st
)
return
false
;
*
out_state
=
st
;
*
out_type
=
st
->
type
;
return
true
;
}
static
inline
ant_value_t
sv_op_for_of
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
ant_value_t
iterable
=
vm
->
stack
[
--
vm
->
sp
];
if
(
vtype
(
iterable
)
==
T_ARR
)
{
vm
->
stack
[
vm
->
sp
++
]
=
iterable
;
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
0
);
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
SV_ITER_ARRAY
);
return
tov
(
0
);
}
if
(
vtype
(
iterable
)
==
T_STR
)
{
if
(
str_is_heap_rope
(
iterable
)
||
str_is_heap_builder
(
iterable
))
{
iterable
=
str_materialize
(
js
,
iterable
);
if
(
is_err
(
iterable
))
return
iterable
;
}
vm
->
stack
[
vm
->
sp
++
]
=
iterable
;
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
0
);
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
SV_ITER_STRING
);
return
tov
(
0
);
}
ant_value_t
iter_fn
=
js_get_sym
(
js
,
iterable
,
get_iterator_sym
());
if
(
!
is_callable
(
iter_fn
))
return
js_mkerr
(
js
,
"not iterable"
);
ant_value_t
iterator
=
sv_vm_call
(
vm
,
js
,
iter_fn
,
iterable
,
NULL
,
0
,
NULL
,
false
);
if
(
is_err
(
iterator
))
return
iterator
;
map_iterator_state_t
*
map_st
;
iter_type_t
map_type
;
if
(
sv_is_map_iter
(
js
,
iterator
,
&
map_st
,
&
map_type
))
{
vm
->
stack
[
vm
->
sp
++
]
=
ANT_PTR
(
map_st
);
vm
->
stack
[
vm
->
sp
++
]
=
tov
((
double
)
map_type
);
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
SV_ITER_MAP
);
return
tov
(
0
);
}
set_iterator_state_t
*
set_st
;
iter_type_t
set_type
;
if
(
sv_is_set_iter
(
js
,
iterator
,
&
set_st
,
&
set_type
))
{
vm
->
stack
[
vm
->
sp
++
]
=
ANT_PTR
(
set_st
);
vm
->
stack
[
vm
->
sp
++
]
=
tov
((
double
)
set_type
);
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
SV_ITER_SET
);
return
tov
(
0
);
}
ant_value_t
next_method
=
js_getprop_fallback
(
js
,
iterator
,
"next"
);
vm
->
stack
[
vm
->
sp
++
]
=
iterator
;
vm
->
stack
[
vm
->
sp
++
]
=
next_method
;
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
SV_ITER_GENERIC
);
return
tov
(
0
);
}
static
inline
ant_value_t
sv_op_for_await_of
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
ant_value_t
iterable
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
iter_fn
=
js_get_sym
(
js
,
iterable
,
get_asyncIterator_sym
());
if
(
!
is_callable
(
iter_fn
))
{
iter_fn
=
js_get_sym
(
js
,
iterable
,
get_iterator_sym
());
if
(
!
is_callable
(
iter_fn
))
return
js_mkerr
(
js
,
"not iterable"
);
}
ant_value_t
iterator
=
sv_vm_call
(
vm
,
js
,
iter_fn
,
iterable
,
NULL
,
0
,
NULL
,
false
);
if
(
is_err
(
iterator
))
return
iterator
;
ant_value_t
next_method
=
js_getprop_fallback
(
js
,
iterator
,
"next"
);
vm
->
stack
[
vm
->
sp
++
]
=
iterator
;
vm
->
stack
[
vm
->
sp
++
]
=
next_method
;
vm
->
stack
[
vm
->
sp
++
]
=
tov
(
SV_ITER_GENERIC
);
return
tov
(
0
);
}
static
inline
ant_value_t
sv_iter_result_get_named
(
ant_t
*
js
,
ant_value_t
result
,
const
char
*
interned
,
const
char
*
key
,
ant_offset_t
key_len
)
{
ant_object_t
*
ptr
=
is_object_type
(
result
)
?
js_obj_ptr
(
js_as_obj
(
result
))
:
NULL
;
ant_value_t
out
=
js_mkundef
();
bool
should_fallback
=
false
;
if
(
interned
&&
sv_try_get_shape_data_prop
(
js
,
ptr
,
interned
,
&
out
,
&
should_fallback
))
return
out
;
return
sv_getprop_fallback_len
(
js
,
result
,
key
,
key_len
);
}
static
inline
void
sv_iter_result_unpack
(
ant_t
*
js
,
ant_value_t
result
,
ant_value_t
*
out_done
,
ant_value_t
*
out_value
)
{
*
out_done
=
sv_iter_result_get_named
(
js
,
result
,
js
->
intern
.
done
,
"done"
,
4
);
*
out_value
=
sv_iter_result_get_named
(
js
,
result
,
js
->
intern
.
value
,
"value"
,
5
);
}
static
inline
ant_value_t
sv_iter_advance
(
sv_vm_t
*
vm
,
ant_t
*
js
,
int
hint
,
ant_value_t
*
out_value
,
bool
*
out_done
)
{
int
tag
=
hint
?
hint
:
(
int
)
js_getnum
(
vm
->
stack
[
vm
->
sp
-
1
]);
switch
(
tag
)
{
case
SV_ITER_ARRAY
:
{
ant_value_t
arr
=
vm
->
stack
[
vm
->
sp
-
3
];
int
idx
=
(
int
)
js_getnum
(
vm
->
stack
[
vm
->
sp
-
2
]);
ant_offset_t
len
=
js_arr_len
(
js
,
arr
);
if
(
idx
>=
(
int
)
len
)
{
*
out_value
=
js_mkundef
();
*
out_done
=
true
;
}
else
{
*
out_value
=
js_arr_get
(
js
,
arr
,
(
ant_offset_t
)
idx
);
*
out_done
=
false
;
vm
->
stack
[
vm
->
sp
-
2
]
=
tov
(
idx
+
1
);
}
return
tov
(
0
);
}
case
SV_ITER_MAP
:
{
map_iterator_state_t
*
st
=
(
map_iterator_state_t
*
)(
uintptr_t
)
js_getnum
(
vm
->
stack
[
vm
->
sp
-
3
]);
if
(
!
st
->
current
)
{
*
out_value
=
js_mkundef
();
*
out_done
=
true
;
}
else
{
map_entry_t
*
entry
=
st
->
current
;
ant_value_t
value
;
switch
(
st
->
type
)
{
case
ITER_TYPE_MAP_VALUES
:
value
=
entry
->
value
;
break
;
case
ITER_TYPE_MAP_KEYS
:
value
=
entry
->
key_val
;
break
;
case
ITER_TYPE_MAP_ENTRIES
:
{
ant_value_t
pair
=
js_mkarr
(
js
);
js_arr_push
(
js
,
pair
,
entry
->
key_val
);
js_arr_push
(
js
,
pair
,
entry
->
value
);
value
=
pair
;
break
;
}
default
:
value
=
js_mkundef
();
}
st
->
current
=
entry
->
hh
.
next
;
*
out_value
=
value
;
*
out_done
=
false
;
}
return
tov
(
0
);
}
case
SV_ITER_SET
:
{
set_iterator_state_t
*
st
=
(
set_iterator_state_t
*
)(
uintptr_t
)
js_getnum
(
vm
->
stack
[
vm
->
sp
-
3
]);
if
(
!
st
->
current
)
{
*
out_value
=
js_mkundef
();
*
out_done
=
true
;
}
else
{
set_entry_t
*
entry
=
st
->
current
;
ant_value_t
value
;
if
(
st
->
type
==
ITER_TYPE_SET_ENTRIES
)
{
ant_value_t
pair
=
js_mkarr
(
js
);
js_arr_push
(
js
,
pair
,
entry
->
value
);
js_arr_push
(
js
,
pair
,
entry
->
value
);
value
=
pair
;
}
else
{
value
=
entry
->
value
;
}
st
->
current
=
entry
->
hh
.
next
;
*
out_value
=
value
;
*
out_done
=
false
;
}
return
tov
(
0
);
}
case
SV_ITER_STRING
:
{
ant_value_t
str
=
vm
->
stack
[
vm
->
sp
-
3
];
int
idx
=
(
int
)
js_getnum
(
vm
->
stack
[
vm
->
sp
-
2
]);
ant_offset_t
slen
=
str_len_fast
(
js
,
str
);
if
(
idx
>=
(
int
)
slen
)
{
*
out_value
=
js_mkundef
();
*
out_done
=
true
;
}
else
{
ant_offset_t
off
=
vstr
(
js
,
str
,
NULL
);
utf8proc_int32_t
cp
;
ant_offset_t
cb_len
=
(
ant_offset_t
)
utf8_next
(
(
const
utf8proc_uint8_t
*
)(
uintptr_t
)(
off
+
idx
),
(
utf8proc_ssize_t
)(
slen
-
idx
),
&
cp
);
*
out_value
=
js_mkstr
(
js
,
(
const
void
*
)(
uintptr_t
)(
off
+
idx
),
cb_len
);
*
out_done
=
false
;
vm
->
stack
[
vm
->
sp
-
2
]
=
tov
(
idx
+
(
int
)
cb_len
);
}
return
tov
(
0
);
}
default
:
{
ant_value_t
next_method
=
vm
->
stack
[
vm
->
sp
-
2
];
ant_value_t
iterator
=
vm
->
stack
[
vm
->
sp
-
3
];
if
(
!
is_callable
(
next_method
))
return
js_mkerr
(
js
,
"iterator.next is not a function"
);
ant_value_t
result
=
sv_vm_call
(
vm
,
js
,
next_method
,
iterator
,
NULL
,
0
,
NULL
,
false
);
if
(
is_err
(
result
))
return
result
;
if
(
!
is_object_type
(
result
))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Iterator result is not an object"
);
ant_value_t
done
=
js_mkundef
();
sv_iter_result_unpack
(
js
,
result
,
&
done
,
out_value
);
if
(
is_err
(
done
))
return
done
;
if
(
is_err
(
*
out_value
))
return
*
out_value
;
*
out_done
=
js_truthy
(
js
,
done
);
return
tov
(
0
);
}}
}
static
inline
ant_value_t
sv_op_iter_next
(
sv_vm_t
*
vm
,
ant_t
*
js
,
uint8_t
*
ip
)
{
int
hint
=
(
int
)
sv_get_u8
(
ip
+
1
);
ant_value_t
value
;
bool
done
=
false
;
ant_value_t
status
=
sv_iter_advance
(
vm
,
js
,
hint
,
&
value
,
&
done
);
if
(
is_err
(
status
))
return
status
;
vm
->
stack
[
vm
->
sp
++
]
=
value
;
vm
->
stack
[
vm
->
sp
++
]
=
done
?
js_true
:
js_false
;
return
tov
(
0
);
}
static
inline
void
sv_op_iter_get_value
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
ant_value_t
obj
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
done
=
js_mkundef
();
ant_value_t
value
=
js_mkundef
();
sv_iter_result_unpack
(
js
,
obj
,
&
done
,
&
value
);
vm
->
stack
[
vm
->
sp
++
]
=
value
;
vm
->
stack
[
vm
->
sp
++
]
=
mkval
(
T_BOOL
,
js_truthy
(
js
,
done
));
}
static
inline
void
sv_op_iter_close
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
int
tag
=
(
int
)
js_getnum
(
vm
->
stack
[
vm
->
sp
-
1
]);
if
(
tag
==
SV_ITER_GENERIC
)
{
ant_value_t
iterator
=
vm
->
stack
[
vm
->
sp
-
3
];
ant_value_t
return_fn
=
js_getprop_fallback
(
js
,
iterator
,
"return"
);
if
(
is_callable
(
return_fn
))
sv_vm_call
(
vm
,
js
,
return_fn
,
iterator
,
NULL
,
0
,
NULL
,
false
);
}
vm
->
sp
-=
3
;
}
static
inline
ant_value_t
sv_op_destructure_init
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
return
sv_op_for_of
(
vm
,
js
);
}
static
inline
void
sv_op_destructure_close
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
sv_op_iter_close
(
vm
,
js
);
}
static
inline
ant_value_t
sv_op_destructure_next
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
ant_value_t
value
;
bool
done
=
false
;
ant_value_t
status
=
sv_iter_advance
(
vm
,
js
,
0
,
&
value
,
&
done
);
if
(
is_err
(
status
))
return
status
;
vm
->
stack
[
vm
->
sp
++
]
=
done
?
js_mkundef
()
:
value
;
return
tov
(
0
);
}
static
inline
ant_value_t
sv_op_destructure_rest
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
ant_value_t
rest
=
js_mkarr
(
js
);
for
(;;)
{
ant_value_t
value
;
bool
done
=
false
;
ant_value_t
status
=
sv_iter_advance
(
vm
,
js
,
0
,
&
value
,
&
done
);
if
(
is_err
(
status
))
return
status
;
if
(
done
)
break
;
js_arr_push
(
js
,
rest
,
value
);
}
vm
->
stack
[
vm
->
sp
++
]
=
rest
;
return
tov
(
0
);
}
static
inline
ant_value_t
sv_op_iter_call
(
sv_vm_t
*
vm
,
ant_t
*
js
,
uint8_t
*
ip
)
{
ant_value_t
method
=
vm
->
stack
[
vm
->
sp
-
1
];
ant_value_t
iterator
=
vm
->
stack
[
vm
->
sp
-
4
];
if
(
!
is_callable
(
method
))
return
js_mkerr
(
js
,
"iterator method is not callable"
);
ant_value_t
result
=
sv_vm_call
(
vm
,
js
,
method
,
iterator
,
NULL
,
0
,
NULL
,
false
);
if
(
is_err
(
result
))
return
result
;
vm
->
stack
[
vm
->
sp
++
]
=
result
;
return
tov
(
0
);
}
static
inline
sv_await_result_t
sv_op_await_iter_next
(
sv_vm_t
*
vm
,
ant_t
*
js
)
{
sv_await_result_t
out
=
{
.
state
=
SV_AWAIT_READY
,
.
value
=
js_mkundef
(),
.
handoff
=
false
,
};
ant_value_t
next_method
=
vm
->
stack
[
vm
->
sp
-
2
];
ant_value_t
iterator
=
vm
->
stack
[
vm
->
sp
-
3
];
if
(
!
is_callable
(
next_method
))
return
(
sv_await_result_t
){
.
state
=
SV_AWAIT_ERROR
,
.
value
=
js_mkerr
(
js
,
"iterator.next is not a function"
),
.
handoff
=
false
};
ant_value_t
result
=
sv_vm_call
(
vm
,
js
,
next_method
,
iterator
,
NULL
,
0
,
NULL
,
false
);
if
(
is_err
(
result
))
return
(
sv_await_result_t
){
.
state
=
SV_AWAIT_ERROR
,
.
value
=
result
,
.
handoff
=
false
};
if
(
vtype
(
result
)
==
T_PROMISE
)
{
vm
->
suspended_entry_fp
=
vm
->
fp
;
vm
->
suspended_saved_fp
=
vm
->
fp
-
1
;
sv_await_result_t
awaited
=
sv_await_value
(
vm
,
js
,
result
);
if
(
awaited
.
state
!=
SV_AWAIT_SUSPENDED
||
awaited
.
handoff
)
{
vm
->
suspended_entry_fp
=
-1
;
vm
->
suspended_saved_fp
=
-1
;
}
if
(
awaited
.
state
!=
SV_AWAIT_READY
)
return
awaited
;
result
=
awaited
.
value
;
}
ant_value_t
done
=
js_mkundef
();
ant_value_t
value
=
js_mkundef
();
sv_iter_result_unpack
(
js
,
result
,
&
done
,
&
value
);
if
(
is_err
(
done
))
return
(
sv_await_result_t
){
.
state
=
SV_AWAIT_ERROR
,
.
value
=
done
,
.
handoff
=
false
};
if
(
is_err
(
value
))
return
(
sv_await_result_t
){
.
state
=
SV_AWAIT_ERROR
,
.
value
=
value
,
.
handoff
=
false
};
if
(
vtype
(
value
)
==
T_PROMISE
)
{
vm
->
suspended_entry_fp
=
vm
->
fp
;
vm
->
suspended_saved_fp
=
vm
->
fp
-
1
;
sv_await_result_t
awaited_val
=
sv_await_value
(
vm
,
js
,
value
);
if
(
awaited_val
.
state
!=
SV_AWAIT_SUSPENDED
||
awaited_val
.
handoff
)
{
vm
->
suspended_entry_fp
=
-1
;
vm
->
suspended_saved_fp
=
-1
;
}
if
(
awaited_val
.
state
!=
SV_AWAIT_READY
)
return
awaited_val
;
value
=
awaited_val
.
value
;
}
vm
->
stack
[
vm
->
sp
++
]
=
value
;
vm
->
stack
[
vm
->
sp
++
]
=
mkval
(
T_BOOL
,
js_truthy
(
js
,
done
));
return
out
;
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, May 1, 2:41 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
541422
Default Alt Text
iteration.h (12 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment