Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399#ifndef SV_OBJECTS_H#define SV_OBJECTS_H
#include "utf8.h"#include "property.h"#include "descriptors.h"#include "gc/roots.h"
#include "silver/call.h"
static inline void sv_define_method( ant_t *js, sv_func_t *func, uint8_t *ip, ant_value_t obj, ant_value_t fn) { uint32_t atom_idx = sv_get_u32(ip + 1); uint8_t flags = sv_get_u8(ip + 5); sv_atom_t *a = &func->atoms[atom_idx]; ant_value_t desc_obj = js_as_obj(obj); bool is_getter = (flags & SV_DEFINE_METHOD_GETTER) != 0; bool is_setter = (flags & SV_DEFINE_METHOD_SETTER) != 0; uint8_t data_attrs = (flags & SV_DEFINE_METHOD_NON_ENUM) ? (ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE) : ANT_PROP_ATTR_DEFAULT; uint8_t accessor_desc = (flags & SV_DEFINE_METHOD_NON_ENUM) ? JS_DESC_C : (JS_DESC_E | JS_DESC_C); if (flags & SV_DEFINE_METHOD_SET_NAME) { const char *prefix = is_getter ? "get " : is_setter ? "set " : ""; size_t prefix_len = is_getter || is_setter ? 4 : 0; ant_value_t key = js_mkstr(js, a->str, a->len); ant_value_t named = js_maybe_set_function_name_from_key(js, fn, key, prefix, prefix_len); if (is_err(named)) return; } if (is_getter) { js_set_getter_desc(js, desc_obj, a->str, a->len, fn, accessor_desc); return; } if (is_setter) { js_set_setter_desc(js, desc_obj, a->str, a->len, fn, accessor_desc); return; } ant_value_t key = js_mkstr(js, a->str, a->len); mkprop(js, obj, key, fn, data_attrs);}
static inline void sv_op_define_method( sv_vm_t *vm, ant_t *js, sv_func_t *func, uint8_t *ip) { sv_define_method(js, func, ip, vm->stack[vm->sp - 2], vm->stack[vm->sp - 1]); vm->sp--;}
static inline void sv_define_method_comp( ant_t *js, uint8_t flags, ant_value_t obj, ant_value_t *key_slot, ant_value_t fn) { ant_value_t key = *key_slot; ant_value_t desc_obj = js_as_obj(obj); bool is_getter = (flags & SV_DEFINE_METHOD_GETTER) != 0; bool is_setter = (flags & SV_DEFINE_METHOD_SETTER) != 0; uint8_t data_attrs = (flags & SV_DEFINE_METHOD_NON_ENUM) ? (ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE) : ANT_PROP_ATTR_DEFAULT; uint8_t accessor_desc = (flags & SV_DEFINE_METHOD_NON_ENUM) ? JS_DESC_C : (JS_DESC_E | JS_DESC_C); if (flags & SV_DEFINE_METHOD_SET_NAME) { const char *prefix = is_getter ? "get " : is_setter ? "set " : ""; size_t prefix_len = is_getter || is_setter ? 4 : 0; ant_value_t named = js_maybe_set_function_name_from_key(js, fn, key, prefix, prefix_len); if (is_err(named)) return; } if (vtype(key) == kTypeSymbol) { if (is_getter) { js_set_sym_getter_desc(js, desc_obj, key, fn, accessor_desc); return; } if (is_setter) { js_set_sym_setter_desc(js, desc_obj, key, fn, accessor_desc); return; } mkprop(js, obj, key, fn, data_attrs); return; } ant_value_t key_str = sv_key_to_propstr(js, key); if (!is_err(key_str)) *key_slot = key_str; if ((is_getter || is_setter) && vtype(key_str) == kTypeString) { ant_offset_t klen = 0; ant_offset_t koff = vstr(js, key_str, &klen); const char *kptr = (const char *)(uintptr_t)(koff); if (is_getter) js_set_getter_desc(js, desc_obj, kptr, klen, fn, accessor_desc); else js_set_setter_desc(js, desc_obj, kptr, klen, fn, accessor_desc); return; } if (vtype(key_str) == kTypeString) { ant_offset_t klen = 0; ant_offset_t koff = vstr(js, key_str, &klen); const char *kptr = (const char *)(uintptr_t)(koff); mkprop(js, obj, js_mkstr(js, kptr, (size_t)klen), fn, data_attrs); } else mkprop(js, obj, key_str, fn, data_attrs);}
static inline void sv_op_define_method_comp( sv_vm_t *vm, ant_t *js, uint8_t *ip) { sv_define_method_comp( js, sv_get_u8(ip + 1), vm->stack[vm->sp - 3], &vm->stack[vm->sp - 2], vm->stack[vm->sp - 1] ); vm->sp -= 2;}
static inline void sv_set_name( ant_t *js, ant_value_t fn, const char *str, uint32_t len) { if (vtype(fn) == kTypeFunction) { sv_closure_t *c = js_func_closure(fn); if (!c->func_obj) { c->u.pending.name = str; c->u.pending.len = len; return; } } js_set_function_name(js, fn, str, len);}
static inline void sv_op_set_name( sv_vm_t *vm, ant_t *js, sv_func_t *func, uint8_t *ip) { uint32_t atom_idx = sv_get_u32(ip + 1); sv_atom_t *a = &func->atoms[atom_idx]; sv_set_name(js, vm->stack[vm->sp - 1], a->str, a->len);}
static inline void sv_op_set_name_comp(sv_vm_t *vm, ant_t *js) { ant_value_t key = vm->stack[vm->sp - 1]; ant_value_t fn = vm->stack[vm->sp - 2]; js_set_function_name_from_key(js, fn, key, "", 0);}
static inline void sv_op_set_proto(sv_vm_t *vm, ant_t *js) { ant_value_t proto = vm->stack[--vm->sp]; ant_value_t obj = vm->stack[vm->sp - 1]; uint8_t pt = vtype(proto); if (pt == kTypeObject || pt == kTypeNull || pt == kTypeFunction || pt == kTypeArray) js_set_proto_wb(js, obj, proto);}
static inline void sv_op_set_home_obj(sv_vm_t *vm, ant_t *js) { ant_value_t home = vm->stack[vm->sp - 1]; ant_value_t fn = vm->stack[vm->sp - 2]; sv_closure_t *c = js_func_closure(fn); c->super_val = home; c->call_flags |= SV_CALL_HAS_SUPER;}
static inline void sv_op_append(sv_vm_t *vm, ant_t *js) { js_arr_push(js, vm->stack[vm->sp - 2], vm->stack[vm->sp - 1]); vm->sp--;}
static inline ant_value_t sv_op_copy_data_props(sv_vm_t *vm, ant_t *js, uint8_t *ip) { uint16_t excluded_count = sv_get_u16(ip + 1); ant_value_t *excluded = &vm->stack[vm->sp - excluded_count]; ant_value_t src = vm->stack[vm->sp - excluded_count - 1]; ant_value_t dst = vm->stack[vm->sp - excluded_count - 2]; ant_value_t result = js_copy_data_props(js, dst, src, excluded, excluded_count); vm->sp -= excluded_count; return result;}
static inline ant_value_t sv_spread_into(sv_vm_t *vm, ant_t *js, ant_value_t arr, ant_value_t iterable) { if (vtype(arr) != kTypeArray) return js_mkerr(js, "spread target is not an array");
if (vtype(iterable) == kTypeArray && js_array_iteration_default(js, iterable)) { ant_value_t spread = js_arr_spread_into(js, arr, iterable); return is_err(spread) ? spread : tov(0); }
GC_ROOT_SAVE(root_mark, js);
if (vtype(iterable) == kTypeString) { if (str_is_heap_rope(iterable) || str_is_heap_builder(iterable)) { iterable = str_materialize(js, iterable); if (is_err(iterable)) { GC_ROOT_RESTORE(js, root_mark); return iterable; } GC_ROOT_PIN(js, iterable); } ant_offset_t slen = str_len_fast(js, iterable); for (ant_offset_t i = 0; i < slen; ) { ant_offset_t off = vstr(js, iterable, NULL); utf8proc_int32_t cp; ant_offset_t cb_len = (ant_offset_t)utf8_next( (const utf8proc_uint8_t *)(uintptr_t)(off + i), (utf8proc_ssize_t)(slen - i), &cp ); js_arr_push(js, arr, js_mkstr(js, (const void *)(uintptr_t)(off + i), cb_len)); i += cb_len; } GC_ROOT_RESTORE(js, root_mark); return tov(0); }
ant_value_t iter_fn = js_get_sym(js, iterable, js->sym.iterator_sym); uint8_t ft = vtype(iter_fn); if (ft != kTypeFunction && ft != kTypeBuiltin) { GC_ROOT_RESTORE(js, root_mark); return js_mkerr(js, "not iterable"); }
ant_value_t iterator = sv_vm_call(vm, js, iter_fn, iterable, NULL, 0, NULL, js_mkundef()); if (is_err(iterator)) { GC_ROOT_RESTORE(js, root_mark); return iterator; } if (!is_object_type(iterator)) { GC_ROOT_RESTORE(js, root_mark); return js_mkerr(js, "not iterable"); }
ant_value_t status = tov(0); ant_value_t result = js_mkundef(); GC_ROOT_PIN(js, iterator); GC_ROOT_PIN(js, result);
for (;;) { ant_value_t next_method = js_getprop_fallback(js, iterator, "next"); ft = vtype(next_method); if (ft != kTypeFunction && ft != kTypeBuiltin) { status = js_mkerr(js, "iterator.next is not a function"); break; }
result = sv_vm_call(vm, js, next_method, iterator, NULL, 0, NULL, js_mkundef()); if (is_err(result)) { status = result; break; } if (!is_object_type(result)) { status = js_mkerr_typed(js, JS_ERR_TYPE, "Iterator result is not an object"); break; }
ant_value_t done = js_getprop_fallback(js, result, "done"); if (js_truthy(js, done)) break;
ant_value_t value = js_getprop_fallback(js, result, "value"); js_arr_push(js, arr, value); }
GC_ROOT_RESTORE(js, root_mark); return status;}
static inline ant_value_t sv_op_spread(sv_vm_t *vm, ant_t *js) { if (vm->sp < 2) return js_mkerr(js, "invalid spread state"); ant_value_t status = sv_spread_into(vm, js, vm->stack[vm->sp - 2], vm->stack[vm->sp - 1]); vm->sp--; return status;}
static inline ant_value_t sv_op_define_class( sv_vm_t *vm, ant_t *js, sv_func_t *func, uint8_t *ip) { uint32_t atom_idx = sv_get_u32(ip + 1); uint8_t cls_flags = sv_get_u8(ip + 5); uint32_t source_start = sv_get_u32(ip + 6); uint32_t source_end = sv_get_u32(ip + 10); bool has_name = (cls_flags & SV_CLASS_FLAG_HAS_NAME) && (int)atom_idx < func->atom_count; bool has_heritage = (cls_flags & SV_CLASS_FLAG_HAS_HERITAGE) != 0; sv_atom_t *a = has_name ? &func->atoms[atom_idx] : NULL; ant_value_t ctor = vm->stack[vm->sp - 1]; ant_value_t parent = vm->stack[vm->sp - 2]; ant_value_t proto = js_mkundef(); uint8_t pt = vtype(parent); bool parent_is_callable = false;
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, ctor); GC_ROOT_PIN(js, proto);
bool default_ctor = vtype(ctor) == kTypeUndefined; if (default_ctor) { ant_value_t ctor_obj = mkobj(js, 0); ctor = js_obj_to_func_ex(js, ctor_obj, SV_CALL_IS_DEFAULT_CTOR); ant_value_t func_proto = js_get_slot(js->global, SLOT_FUNC_PROTO); if (vtype(func_proto) == kTypeFunction) js_set_proto_init(ctor_obj, func_proto); mkprop_interned_exact(js, ctor_obj, js->intern.length, tov(0), ANT_PROP_ATTR_CONFIGURABLE); }
proto = mkobj(js, 0); if (!has_heritage) js_set_proto_init(proto, js->sym.object_proto); else if (pt == kTypeNull) { js_set_proto_init(proto, js_mknull()); ant_value_t func_proto = js_get_slot(js->global, SLOT_FUNC_PROTO); if (vtype(func_proto) == kTypeFunction) js_set_proto_wb(js, ctor, func_proto); } else { if (!js_is_constructor(parent)) { GC_ROOT_RESTORE(js, root_mark); return js_mkerr_typed(js, JS_ERR_TYPE, "Class extends value is not a constructor"); }
ant_value_t parent_proto = js_getprop_fallback(js, parent, "prototype"); if (is_err(parent_proto)) { GC_ROOT_RESTORE(js, root_mark); return parent_proto; } if (!is_object_type(parent_proto) && vtype(parent_proto) != kTypeNull) { GC_ROOT_RESTORE(js, root_mark); return js_mkerr_typed(js, JS_ERR_TYPE, "Class extends value does not have a valid prototype property"); } js_set_proto_init(proto, parent_proto); js_set_proto_wb(js, ctor, parent); parent_is_callable = true; } if (parent_is_callable) if (vtype(ctor) == kTypeFunction) { sv_closure_t *c = js_func_closure(ctor); c->super_val = parent; c->call_flags |= SV_CALL_HAS_SUPER; }
if (vtype(ctor) == kTypeFunction) js_mark_constructor(js_func_obj(ctor), true); if ( vtype(ctor) == kTypeFunction && func->debug->source && source_end > source_start && source_end <= (uint32_t)func->debug->source_len ) { size_t source_len = (size_t)(source_end - source_start); const char *source = func->debug->source + source_start; js_set_func_source( js, ctor, source, source_len, func->unit ? JS_FUNC_SOURCE_UNIT : JS_FUNC_SOURCE_PINNED ); } defhidden(js, proto, "constructor", 11, ctor); ant_value_t ctor_obj = (vtype(ctor) == kTypeFunction) ? js_func_obj(ctor) : ctor; if (has_name || default_ctor) js_set_function_name(js, ctor, a ? a->str : "", a ? a->len : 0); mkprop_exact_attrs(js, ctor_obj, ANT_STRING("prototype"), proto, 0);
vm->stack[vm->sp - 2] = ctor; vm->stack[vm->sp - 1] = proto; GC_ROOT_RESTORE(js, root_mark); return js_mkundef();}
static inline ant_value_t sv_op_define_class_comp( sv_vm_t *vm, ant_t *js, sv_func_t *func, uint8_t *ip) { ant_value_t name = vm->stack[vm->sp - 1]; vm->sp--; GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, name); ant_value_t result = sv_op_define_class(vm, js, func, ip); GC_ROOT_RESTORE(js, root_mark); if (is_err(result)) return result; vm->stack[vm->sp++] = name; return result;}
#endif