Page MenuHomePhorge

iteration.h
No OneTemporary

Size
12 KB
Referenced Files
None
Subscribers
None

iteration.h

#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

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)

Event Timeline