Page MenuHomePhorge

symbol.c
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

symbol.c

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "ant.h"
#include "utf8.h"
#include "errors.h"
#include "runtime.h"
#include "internal.h"
#include "silver/engine.h"
#include "modules/symbol.h"
#include "descriptors.h"
#include "gc/roots.h"
#include "gc/modules.h"
#define DECL_SYM(name, _desc) static ant_value_t g_##name = {0};
WELLKNOWN_SYMBOLS(DECL_SYM)
#undef DECL_SYM
#define DEF_GET_SYM(name, _desc) ant_value_t get_##name##_sym(void) { return g_##name; }
WELLKNOWN_SYMBOLS(DEF_GET_SYM)
#undef DEF_GET_SYM
static ant_value_t builtin_Symbol(ant_t *js, ant_value_t *args, int nargs) {
if (vtype(js->new_target) != T_UNDEF)
return js_mkerr_typed(js, JS_ERR_TYPE, "Symbol is not a constructor");
const char *desc = NULL;
if (nargs > 0 && vtype(args[0]) == T_STR) {
desc = js_getstr(js, args[0], NULL);
}
return js_mksym(js, desc);
}
static ant_value_t builtin_Symbol_for(ant_t *js, ant_value_t *args, int nargs) {
if (nargs < 1 || vtype(args[0]) != T_STR) {
return js_mkerr(js, "Symbol.for requires a string argument");
}
char *key = js_getstr(js, args[0], NULL);
if (!key) return js_mkerr(js, "Invalid key");
return js_mksym_for(js, key);
}
static ant_value_t builtin_Symbol_keyFor(ant_t *js, ant_value_t *args, int nargs) {
if (nargs < 1 || vtype(args[0]) != T_SYMBOL) {
return js_mkundef();
}
const char *key = js_sym_key(args[0]);
if (!key) return js_mkundef();
return js_mkstr(js, key, strlen(key));
}
static ant_value_t builtin_Symbol_toString(ant_t *js, ant_value_t *args, int nargs) {
ant_value_t this_val = js_getthis(js);
if (vtype(this_val) != T_SYMBOL) {
return js_mkerr(js, "Symbol.prototype.toString requires a symbol");
}
return js_symbol_to_string(js, this_val);
}
static ant_value_t get_iterator_prototype(ant_t *js) {
if (vtype(js->sym.iterator_proto) == T_OBJ) return js->sym.iterator_proto;
js->sym.iterator_proto = js_mkobj(js);
js_set_proto_init(js->sym.iterator_proto, js->object);
js_set_sym(js, js->sym.iterator_proto, g_iterator, js_mkfun(sym_this_cb));
return js->sym.iterator_proto;
}
static ant_value_t arr_iter_next(ant_t *js, ant_value_t *args, int nargs) {
ant_value_t iter = js->this_val;
ant_value_t array = js_get_slot(iter, SLOT_DATA);
ant_value_t state_v = js_get_slot(iter, SLOT_ITER_STATE);
uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0;
uint32_t kind = ARR_ITER_KIND(state);
uint32_t idx = ARR_ITER_INDEX(state);
ant_value_t result = js_mkobj(js);
ant_offset_t len = js_arr_len(js, array);
if (idx >= (uint32_t)len) {
js_set(js, result, "done", js_true);
js_set(js, result, "value", js_mkundef());
return result;
}
ant_value_t value;
switch (kind) {
case ARR_ITER_KEYS:
value = js_mknum((double)idx);
break;
case ARR_ITER_ENTRIES: {
ant_value_t pair = js_mkarr(js);
js_arr_push(js, pair, js_mknum((double)idx));
js_arr_push(js, pair, js_arr_get(js, array, (ant_offset_t)idx));
value = pair;
break;
}
default:
value = js_arr_get(js, array, (ant_offset_t)idx);
break;
}
js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ARR_ITER_PACK(kind, idx + 1)));
js_set(js, result, "done", js_false);
js_set(js, result, "value", value);
return result;
}
static ant_value_t get_array_iterator_prototype(ant_t *js) {
if (vtype(js->sym.array_iterator_proto) == T_OBJ) return js->sym.array_iterator_proto;
ant_value_t iterator_proto = get_iterator_prototype(js);
js->sym.array_iterator_proto = js_mkobj(js);
js_set(js, js->sym.array_iterator_proto, "next", js_mkfun(arr_iter_next));
js_set_proto_init(js->sym.array_iterator_proto, iterator_proto);
return js->sym.array_iterator_proto;
}
ant_value_t make_array_iterator(ant_t *js, ant_value_t array, int kind) {
ant_value_t iter = js_mkobj(js);
js_set_slot_wb(js, iter, SLOT_DATA, array);
js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ARR_ITER_PACK(kind, 0)));
js_set_proto_init(iter, get_array_iterator_prototype(js));
return iter;
}
static ant_value_t str_iter_next(ant_t *js, ant_value_t *args, int nargs) {
ant_value_t iter = js->this_val;
ant_value_t str = js_get_slot(iter, SLOT_DATA);
ant_value_t idx_v = js_get_slot(iter, SLOT_ITER_STATE);
int idx = (vtype(idx_v) == T_NUM) ? (int)js_getnum(idx_v) : 0;
size_t slen;
char *s = js_getstr(js, str, &slen);
ant_value_t result = js_mkobj(js);
if (idx >= (int)slen) {
js_set(js, result, "done", js_true);
js_set(js, result, "value", js_mkundef());
return result;
}
unsigned char c = (unsigned char)s[idx];
int char_bytes = utf8_sequence_length(c);
if (char_bytes < 1) char_bytes = 1;
if (idx + char_bytes > (int)slen) char_bytes = (int)slen - idx;
js_set(js, result, "value", js_mkstr(js, s + idx, (ant_offset_t)char_bytes));
js_set(js, result, "done", js_false);
js_set_slot(iter, SLOT_ITER_STATE, js_mknum(idx + char_bytes));
return result;
}
static ant_value_t get_string_iterator_prototype(ant_t *js) {
if (vtype(js->sym.string_iterator_proto) == T_OBJ) return js->sym.string_iterator_proto;
ant_value_t iterator_proto = get_iterator_prototype(js);
js->sym.string_iterator_proto = js_mkobj(js);
js_set(js, js->sym.string_iterator_proto, "next", js_mkfun(str_iter_next));
js_set_proto_init(js->sym.string_iterator_proto, iterator_proto);
return js->sym.string_iterator_proto;
}
static ant_value_t string_iterator(ant_t *js, ant_value_t *args, int nargs) {
ant_value_t iter = js_mkobj(js);
js_set_slot_wb(js, iter, SLOT_DATA, js->this_val);
js_set_slot(iter, SLOT_ITER_STATE, js_mknum(0));
js_set_proto_init(iter, get_string_iterator_prototype(js));
return iter;
}
ant_value_t maybe_call_symbol_method(
ant_t *js, ant_value_t target,
ant_value_t sym,
ant_value_t this_arg, ant_value_t *args,
int nargs, bool *called
) {
*called = false;
if (vtype(sym) != T_SYMBOL || !is_object_type(target)) return js_mkundef();
ant_value_t method = js_get_sym(js, target, sym);
if (is_err(method)) return method;
uint8_t mt = vtype(method);
if (mt == T_UNDEF || mt == T_NULL) return js_mkundef();
if (mt != T_FUNC && mt != T_CFUNC) {
return js_mkerr_typed(js, JS_ERR_TYPE, "Symbol method is not callable");
}
*called = true;
return sv_vm_call(js->vm, js, method, this_arg, args, nargs, NULL, false);
}
void js_define_species_getter(ant_t *js, ant_value_t ctor) {
if (!is_object_type(ctor) || vtype(g_species) != T_SYMBOL) return;
ctor = js_as_obj(ctor);
js_set_sym_getter_desc(js, ctor, g_species, js_mkfun(sym_this_cb), JS_DESC_C);
}
void init_symbol_module(void) {
ant_t *js = rt->js;
js->sym.iterator_proto = js_mkundef();
js->sym.array_iterator_proto = js_mkundef();
js->sym.string_iterator_proto = js_mkundef();
gc_register_root(&js->sym.iterator_proto);
gc_register_root(&js->sym.array_iterator_proto);
gc_register_root(&js->sym.string_iterator_proto);
#define INIT_SYM(name, desc) g_##name = js_mksym_well_known(js, desc);
WELLKNOWN_SYMBOLS(INIT_SYM)
#undef INIT_SYM
ant_value_t symbol_proto = js_mkobj(js);
js_set(js, symbol_proto, "toString", js_mkfun(builtin_Symbol_toString));
ant_value_t symbol_ctor = js_mkobj(js);
js_set_slot(symbol_ctor, SLOT_CFUNC, js_mkfun(builtin_Symbol));
js_setprop(js, symbol_ctor, js_mkstr(js, "for", 3), js_mkfun(builtin_Symbol_for));
js_set(js, symbol_ctor, "keyFor", js_mkfun(builtin_Symbol_keyFor));
js_set(js, symbol_ctor, "prototype", symbol_proto);
#define SET_CTOR_SYM(name, _desc) js_set(js, symbol_ctor, #name, g_##name);
WELLKNOWN_SYMBOLS(SET_CTOR_SYM)
#undef SET_CTOR_SYM
ant_value_t func_symbol = js_obj_to_func(symbol_ctor);
js_set(js, js_glob(js), "Symbol", func_symbol);
// set internal types before ant module snapshot
ant_value_t array_ctor = js_get(js, js_glob(js), "Array");
ant_value_t array_proto = js_get(js, array_ctor, "prototype");
(void)get_array_iterator_prototype(js);
(void)get_string_iterator_prototype(js);
js_set_sym(js, rt->ant_obj, g_toStringTag, js_mkstr(js, "Ant", 3));
js_set_sym(js, array_proto, g_iterator, js_get(js, array_proto, "values"));
ant_value_t array_unscopables = js_mkobj(js);
js_set(js, array_unscopables, "find", js_true);
js_set(js, array_unscopables, "findIndex", js_true);
js_set(js, array_unscopables, "fill", js_true);
js_set(js, array_unscopables, "copyWithin", js_true);
js_set(js, array_unscopables, "entries", js_true);
js_set(js, array_unscopables, "keys", js_true);
js_set(js, array_unscopables, "values", js_true);
js_set(js, array_unscopables, "flat", js_true);
js_set(js, array_unscopables, "flatMap", js_true);
js_set_sym(js, array_proto, g_unscopables, array_unscopables);
ant_value_t string_ctor = js_get(js, js_glob(js), "String");
ant_value_t string_proto = js_get(js, string_ctor, "prototype");
js_set_sym(js, string_proto, g_iterator, js_mkfun(string_iterator));
ant_value_t promise_ctor = js_get(js, js_glob(js), "Promise");
ant_value_t promise_proto = js_get(js, promise_ctor, "prototype");
js_set_sym(js, promise_proto, g_toStringTag, js_mkstr(js, "Promise", 7));
js_define_species_getter(js, promise_ctor);
js_define_species_getter(js, array_ctor);
}
void gc_mark_symbols(ant_t *js, gc_mark_fn mark) {
mark(js, js->sym.iterator_proto);
mark(js, js->sym.array_iterator_proto);
mark(js, js->sym.string_iterator_proto);
#define GC_SYM(name, _desc) mark(js, g_##name);
WELLKNOWN_SYMBOLS(GC_SYM)
#undef GC_SYM
}

File Metadata

Mime Type
text/x-c
Expires
Sat, Aug 1, 2:09 PM (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
603517
Default Alt Text
symbol.c (9 KB)

Event Timeline