mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
Read ordinary objects' properties through accessors outside the object core
Runtime units outside the object core (scr_json.c, scr_js_object.c) read and adjusted SCR_DYN_OBJ entries in place: v.obj.len, v.obj.entries[i] and the 48-byte ScrDynEntry fields. The single object model's generic objects (stage S3) change that storage, so these units now go through own-property accessors in scr_dyn.h: - scr_dyn_obj_count, scr_dyn_obj_key_at, scr_dyn_obj_value_at and scr_dyn_obj_prop_at (a ScrDynProp view: key, value, getter, setter and attributes) walk the properties in creation order; - scr_dyn_obj_index_of finds one by key; - scr_dyn_obj_set_attrs_at restricts a member a builtin object just added; - scr_dyn_own_symbol_prop and scr_dyn_copy_prop_at wrap the symbol-entry and copy primitives. The accessors are inline over today's entries, so behavior is unchanged. 21 units move (inspect, assert, util compare, console, http, http2, fetch, tls, fs, os, lib, array, message, publish, region, symbol, worker events, handle properties, builtin values, declaration adoption). A package test keeps entry storage reads inside the core. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
641f779fa3
commit
7ac0542aa9
@@ -5982,8 +5982,8 @@ void scr_arr_copy_metadata(ScrArr *a, ScrDyn *target) {
|
||||
target->v.arr.properties->v.obj.class_name = cls->name;
|
||||
ScrDyn *fields = scr_arr_class_fields(a);
|
||||
if (fields) {
|
||||
for (size_t i = 0; i < fields->v.obj.len; i++)
|
||||
scr_dyn_copy_entry(target, fields, &fields->v.obj.entries[i]);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(fields); i++)
|
||||
scr_dyn_copy_prop_at(target, fields, i);
|
||||
scr_dyn_release(fields);
|
||||
}
|
||||
return;
|
||||
@@ -5994,7 +5994,7 @@ void scr_arr_copy_metadata(ScrArr *a, ScrDyn *target) {
|
||||
return;
|
||||
metadata = SCR_AX(a)->metadata;
|
||||
if (!metadata) return;
|
||||
for (size_t i = 0; i < metadata->v.obj.len; i++) scr_dyn_copy_entry(target, metadata, &metadata->v.obj.entries[i]);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(metadata); i++) scr_dyn_copy_prop_at(target, metadata, i);
|
||||
}
|
||||
|
||||
ScrArr *scr_arr_named_keys(ScrArr *a) {
|
||||
@@ -6008,9 +6008,9 @@ ScrArr *scr_arr_named_keys(ScrArr *a) {
|
||||
scr_arr_push_ref(keys, scr_str_new(x->props[i].key, x->props[i].key_len));
|
||||
ScrDyn *fields = scr_arr_class_fields(a);
|
||||
if (fields) {
|
||||
for (size_t i = 0; i < fields->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &fields->v.obj.entries[i];
|
||||
if (entry->enumerable) scr_arr_push_ref(keys, scr_str_new(entry->key, entry->key_len));
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(fields); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(fields, i);
|
||||
if (entry.enumerable) scr_arr_push_ref(keys, scr_str_new(entry.key, entry.key_len));
|
||||
}
|
||||
scr_dyn_release(fields);
|
||||
return keys;
|
||||
@@ -6022,10 +6022,10 @@ ScrArr *scr_arr_named_keys(ScrArr *a) {
|
||||
return keys;
|
||||
}
|
||||
if (!metadata || metadata->kind != SCR_DYN_OBJ) return keys;
|
||||
for (size_t i = 0; i < metadata->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &metadata->v.obj.entries[i];
|
||||
if (!entry->enumerable || scr_arr_prop_index(a, entry->key, entry->key_len) != SIZE_MAX) continue;
|
||||
scr_arr_push_ref(keys, scr_str_new(entry->key, entry->key_len));
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(metadata); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(metadata, i);
|
||||
if (!entry.enumerable || scr_arr_prop_index(a, entry.key, entry.key_len) != SIZE_MAX) continue;
|
||||
scr_arr_push_ref(keys, scr_str_new(entry.key, entry.key_len));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
@@ -6038,9 +6038,9 @@ bool scr_arr_has_named_key(ScrArr *a, ScrStr *key) {
|
||||
if (metadata && metadata->kind == SCR_DYN_HANDLE && metadata->v.handle.tag == SCR_DYNH_MATCH_SOURCE)
|
||||
return true; /* index, input and groups, the only keys a pending result lists */
|
||||
if (!metadata || metadata->kind != SCR_DYN_OBJ) return false;
|
||||
for (size_t i = 0; i < metadata->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &metadata->v.obj.entries[i];
|
||||
if (entry->key_len == key->len && memcmp(entry->key, key->data, key->len) == 0) return true;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(metadata); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(metadata, i);
|
||||
if (entry.key_len == key->len && memcmp(entry.key, key->data, key->len) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -6067,20 +6067,22 @@ void scr_arr_adopt_view_properties(ScrArr *a, ScrDyn *view, ScrArr *target) {
|
||||
from->prop_cap = cap;
|
||||
}
|
||||
ScrDyn *named = view && view->kind == SCR_DYN_ARR ? view->v.arr.properties : NULL;
|
||||
if (!named || named->v.obj.len == 0) return;
|
||||
if (!named || scr_dyn_obj_count(named) == 0) return;
|
||||
/* The view's numeric properties are copies of the native ones (every
|
||||
* write to them goes to the native array), so only the others move. */
|
||||
bool numeric = false;
|
||||
for (size_t i = 0; i < named->v.obj.len && !numeric; i++) {
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(named) && !numeric; i++) {
|
||||
double number;
|
||||
numeric = scr_arr_numeric_key(named->v.obj.entries[i].key, named->v.obj.entries[i].key_len, &number);
|
||||
size_t key_len;
|
||||
const char *key = scr_dyn_obj_key_at(named, i, &key_len);
|
||||
numeric = scr_arr_numeric_key(key, key_len, &number);
|
||||
}
|
||||
if (numeric) {
|
||||
ScrDyn *rest = scr_dyn_new_obj();
|
||||
for (size_t i = 0; i < named->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &named->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(named); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(named, i);
|
||||
double number;
|
||||
if (!scr_arr_numeric_key(entry->key, entry->key_len, &number)) scr_dyn_copy_entry(rest, named, entry);
|
||||
if (!scr_arr_numeric_key(entry.key, entry.key_len, &number)) scr_dyn_copy_prop_at(rest, named, i);
|
||||
}
|
||||
named = rest;
|
||||
} else {
|
||||
@@ -6088,7 +6090,7 @@ void scr_arr_adopt_view_properties(ScrArr *a, ScrDyn *view, ScrArr *target) {
|
||||
}
|
||||
ScrArrExt *x = scr_arr_ext(a);
|
||||
ScrDyn *old = x->metadata;
|
||||
x->metadata = named->v.obj.len ? named : NULL;
|
||||
x->metadata = scr_dyn_obj_count(named) ? named : NULL;
|
||||
if (!x->metadata) scr_dyn_release(named);
|
||||
scr_dyn_release(old);
|
||||
}
|
||||
|
||||
@@ -718,7 +718,7 @@ static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
|
||||
if (a->v.arr.properties || b->v.arr.properties) {
|
||||
if (!a->v.arr.properties || !b->v.arr.properties) {
|
||||
const ScrDyn *table = a->v.arr.properties ? a->v.arr.properties : b->v.arr.properties;
|
||||
if (table->v.obj.len != 0) return false;
|
||||
if (scr_dyn_obj_count(table) != 0) return false;
|
||||
} else if (!scr_assert_dyn_deep_eq(a->v.arr.properties, b->v.arr.properties)) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -738,11 +738,11 @@ static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
|
||||
} else if (a->null_proto != b->null_proto || a->prototype != b->prototype) {
|
||||
return false;
|
||||
}
|
||||
if (a->v.obj.len != b->v.obj.len) return false;
|
||||
for (size_t i = 0; i < a->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &a->v.obj.entries[i];
|
||||
ScrDyn *bv = scr_dyn_obj_get(b, ent->key, ent->key_len);
|
||||
if (!bv || !scr_assert_dyn_deep_eq(ent->value, bv)) return false;
|
||||
if (scr_dyn_obj_count(a) != scr_dyn_obj_count(b)) return false;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(a); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(a, i);
|
||||
ScrDyn *bv = scr_dyn_obj_get(b, ent.key, ent.key_len);
|
||||
if (!bv || !scr_assert_dyn_deep_eq(ent.value, bv)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -782,30 +782,29 @@ static bool scr_assert_loose_nan(const ScrDyn *d) {
|
||||
return d->kind == SCR_DYN_NUM && d->v.num != d->v.num;
|
||||
}
|
||||
|
||||
/* An enumerable own entry, or NULL. Borrowed. */
|
||||
static const ScrDynEntry *scr_assert_loose_entry(const ScrDyn *d, const char *key, size_t len) {
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
if (ent->key_len == len && memcmp(ent->key, key, len) == 0) return ent->enumerable ? ent : NULL;
|
||||
}
|
||||
return NULL;
|
||||
/* The value of an enumerable own property, or NULL. Borrowed. */
|
||||
static const ScrDyn *scr_assert_loose_entry(const ScrDyn *d, const char *key, size_t len) {
|
||||
size_t i = scr_dyn_obj_index_of(d, key, len);
|
||||
if (i == SIZE_MAX) return NULL;
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
return ent.enumerable ? ent.value : NULL;
|
||||
}
|
||||
|
||||
static bool scr_assert_loose_counted(const ScrDynEntry *ent) {
|
||||
return ent->enumerable && !(ent->key_len == 6 && memcmp(ent->key, "%error", 6) == 0);
|
||||
static bool scr_assert_loose_counted(ScrDynProp ent) {
|
||||
return ent.enumerable && !(ent.key_len == 6 && memcmp(ent.key, "%error", 6) == 0);
|
||||
}
|
||||
|
||||
/* keyCheck and objEquiv over two objects' enumerable own keys. */
|
||||
static bool scr_assert_loose_keys(const ScrDyn *a, const ScrDyn *b) {
|
||||
size_t na = 0, nb = 0;
|
||||
for (size_t i = 0; i < a->v.obj.len; i++) na += scr_assert_loose_counted(&a->v.obj.entries[i]);
|
||||
for (size_t i = 0; i < b->v.obj.len; i++) nb += scr_assert_loose_counted(&b->v.obj.entries[i]);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(a); i++) na += scr_assert_loose_counted(scr_dyn_obj_prop_at(a, i));
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(b); i++) nb += scr_assert_loose_counted(scr_dyn_obj_prop_at(b, i));
|
||||
if (na != nb) return false;
|
||||
for (size_t i = 0; i < b->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &b->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(b); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(b, i);
|
||||
if (!scr_assert_loose_counted(ent)) continue;
|
||||
const ScrDynEntry *other = scr_assert_loose_entry(a, ent->key, ent->key_len);
|
||||
if (!other || !scr_assert_loose_eq(other->value, ent->value)) return false;
|
||||
const ScrDyn *other = scr_assert_loose_entry(a, ent.key, ent.key_len);
|
||||
if (!other || !scr_assert_loose_eq(other, ent.value)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1180,8 +1179,8 @@ static bool scr_assert_loose_array(const ScrDyn *a, const ScrDyn *b) {
|
||||
if (pa || pb) {
|
||||
if (!pa || !pb) {
|
||||
const ScrDyn *table = pa ? pa : pb;
|
||||
for (size_t i = 0; i < table->v.obj.len; i++)
|
||||
if (scr_assert_loose_counted(&table->v.obj.entries[i])) return false;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(table); i++)
|
||||
if (scr_assert_loose_counted(scr_dyn_obj_prop_at(table, i))) return false;
|
||||
} else if (!scr_assert_loose_keys(pa, pb)) {
|
||||
return false;
|
||||
}
|
||||
@@ -1295,7 +1294,7 @@ static void scr_assert_cf_value(ScrAssertBuf *b, const ScrDyn *d, size_t indent,
|
||||
* or `{`, then its entries. */
|
||||
static void scr_assert_cf_object(ScrAssertBuf *b, const ScrDyn *d, size_t indent, size_t depth,
|
||||
const char *cls) {
|
||||
if (d->v.obj.len == 0) {
|
||||
if (scr_dyn_obj_count(d) == 0) {
|
||||
if (cls) {
|
||||
ab_cstr(b, cls);
|
||||
ab_cstr(b, " {}");
|
||||
@@ -1320,25 +1319,25 @@ static void scr_assert_cf_object(ScrAssertBuf *b, const ScrDyn *d, size_t indent
|
||||
} else if (d->null_proto) ab_cstr(b, "[Object: null prototype] ");
|
||||
/* Render every entry, then sort the RENDERED texts (Node's
|
||||
* sorted:true sorts formatted entries, quotes included). */
|
||||
ScrCfEntry *ents = malloc(d->v.obj.len * sizeof *ents);
|
||||
ScrCfEntry *ents = malloc(scr_dyn_obj_count(d) * sizeof *ents);
|
||||
if (!ents) scr_assert_oom();
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
ScrAssertBuf eb = {0};
|
||||
scr_assert_cf_key(&eb, ent->key, ent->key_len);
|
||||
scr_assert_cf_key(&eb, ent.key, ent.key_len);
|
||||
ab_cstr(&eb, ": ");
|
||||
scr_assert_cf_value(&eb, ent->value, indent + 2, depth - 1);
|
||||
scr_assert_cf_value(&eb, ent.value, indent + 2, depth - 1);
|
||||
ents[i].text = eb.data ? eb.data : malloc(1);
|
||||
if (!ents[i].text) scr_assert_oom();
|
||||
ents[i].len = eb.len;
|
||||
}
|
||||
qsort(ents, d->v.obj.len, sizeof *ents, scr_assert_cf_entry_cmp);
|
||||
qsort(ents, scr_dyn_obj_count(d), sizeof *ents, scr_assert_cf_entry_cmp);
|
||||
ab_char(b, '{');
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ab_char(b, '\n');
|
||||
scr_assert_cf_pad(b, indent + 2);
|
||||
ab_bytes(b, ents[i].text, ents[i].len);
|
||||
if (i + 1 < d->v.obj.len) ab_char(b, ',');
|
||||
if (i + 1 < scr_dyn_obj_count(d)) ab_char(b, ',');
|
||||
free(ents[i].text);
|
||||
}
|
||||
free(ents);
|
||||
@@ -1364,11 +1363,11 @@ static const char *scr_assert_cf_bytes_class(ScrBytesElem elem) {
|
||||
}
|
||||
|
||||
|
||||
static bool scr_assert_cf_error_extra(const ScrDynEntry *ent) {
|
||||
if (!ent->enumerable || (ent->key_len > 0 && ent->key[0] == '%')) return false;
|
||||
return !((ent->key_len == 4 && memcmp(ent->key, "name", 4) == 0) ||
|
||||
(ent->key_len == 7 && memcmp(ent->key, "message", 7) == 0) ||
|
||||
(ent->key_len == 5 && memcmp(ent->key, "stack", 5) == 0));
|
||||
static bool scr_assert_cf_error_extra(ScrDynProp ent) {
|
||||
if (!ent.enumerable || (ent.key_len > 0 && ent.key[0] == '%')) return false;
|
||||
return !((ent.key_len == 4 && memcmp(ent.key, "name", 4) == 0) ||
|
||||
(ent.key_len == 7 && memcmp(ent.key, "message", 7) == 0) ||
|
||||
(ent.key_len == 5 && memcmp(ent.key, "stack", 5) == 0));
|
||||
}
|
||||
|
||||
/* An encoded Error: Node's stackless `[Name: message]` (assertion_error.js
|
||||
@@ -1386,8 +1385,8 @@ static void scr_assert_cf_error(ScrAssertBuf *b, const ScrDyn *d, size_t indent,
|
||||
}
|
||||
ab_char(b, ']');
|
||||
size_t extra = 0;
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
if (scr_assert_cf_error_extra(ent)) extra++;
|
||||
}
|
||||
if (extra == 0) return;
|
||||
@@ -1395,13 +1394,13 @@ static void scr_assert_cf_error(ScrAssertBuf *b, const ScrDyn *d, size_t indent,
|
||||
ScrCfEntry *ents = malloc(extra * sizeof *ents);
|
||||
if (!ents) scr_assert_oom();
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
if (!scr_assert_cf_error_extra(ent)) continue;
|
||||
ScrAssertBuf eb = {0};
|
||||
scr_assert_cf_key(&eb, ent->key, ent->key_len);
|
||||
scr_assert_cf_key(&eb, ent.key, ent.key_len);
|
||||
ab_cstr(&eb, ": ");
|
||||
scr_assert_cf_value(&eb, ent->value, indent + 2, depth - 1);
|
||||
scr_assert_cf_value(&eb, ent.value, indent + 2, depth - 1);
|
||||
ents[n].text = eb.data ? eb.data : malloc(1);
|
||||
if (!ents[n].text) scr_assert_oom();
|
||||
ents[n++].len = eb.len;
|
||||
@@ -1989,11 +1988,11 @@ static bool scr_assert_partial_eq(const ScrDyn *a, const ScrDyn *b);
|
||||
|
||||
/* objEquiv over the expected side's enumerable own keys. */
|
||||
static bool scr_assert_partial_keys(const ScrDyn *a, const ScrDyn *b) {
|
||||
for (size_t i = 0; i < b->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &b->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(b); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(b, i);
|
||||
if (!scr_assert_loose_counted(ent)) continue;
|
||||
const ScrDynEntry *other = scr_assert_loose_entry(a, ent->key, ent->key_len);
|
||||
if (!other || !scr_assert_partial_eq(other->value, ent->value)) return false;
|
||||
const ScrDyn *other = scr_assert_loose_entry(a, ent.key, ent.key_len);
|
||||
if (!other || !scr_assert_partial_eq(other, ent.value)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2043,11 +2042,11 @@ static bool scr_assert_partial_array(const ScrDyn *a, const ScrDyn *b) {
|
||||
const ScrDyn *pb = b->v.arr.properties;
|
||||
if (pb) {
|
||||
const ScrDyn *pa = a->v.arr.properties;
|
||||
for (size_t i = 0; i < pb->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &pb->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(pb); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(pb, i);
|
||||
if (!scr_assert_loose_counted(ent)) continue;
|
||||
const ScrDynEntry *other = pa ? scr_assert_loose_entry(pa, ent->key, ent->key_len) : NULL;
|
||||
if (!other || !scr_assert_partial_eq(other->value, ent->value)) return false;
|
||||
const ScrDyn *other = pa ? scr_assert_loose_entry(pa, ent.key, ent.key_len) : NULL;
|
||||
if (!other || !scr_assert_partial_eq(other, ent.value)) return false;
|
||||
}
|
||||
}
|
||||
size_t pos = 0;
|
||||
@@ -2434,11 +2433,11 @@ void scr_assert_loose_deep_result(bool equal, bool negated, ScrStr *msg, bool ha
|
||||
void scr_assert_expects_err_dyn(ScrDyn *actual, ScrDyn *expected, ScrStr *msg, bool has_msg) {
|
||||
if (actual->kind == SCR_DYN_OBJ && expected->kind == SCR_DYN_OBJ) {
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < expected->v.obj.len && ok; i++) {
|
||||
const ScrDynEntry *e = &expected->v.obj.entries[i];
|
||||
if (e->key_len == 6 && memcmp(e->key, "%error", 6) == 0) continue;
|
||||
ScrDyn *av = scr_dyn_obj_get(actual, e->key, e->key_len);
|
||||
if (av == NULL || !scr_assert_dyn_deep_eq(av, e->value)) ok = false;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(expected) && ok; i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(expected, i);
|
||||
if (e.key_len == 6 && memcmp(e.key, "%error", 6) == 0) continue;
|
||||
ScrDyn *av = scr_dyn_obj_get(actual, e.key, e.key_len);
|
||||
if (av == NULL || !scr_assert_dyn_deep_eq(av, e.value)) ok = false;
|
||||
}
|
||||
if (ok) return;
|
||||
}
|
||||
|
||||
@@ -441,8 +441,7 @@ ScrDyn *scr_buffer_constructor_value(void) {
|
||||
ScrDyn *table = scr_dyn_function_properties(scr_bv_buffer);
|
||||
ScrDyn *getter = scr_dyn_new_func(scr_closure_new(NULL, 0), scr_bv_prototype, 0, "native:function", "get prototype");
|
||||
scr_dyn_obj_set_accessor(table, "prototype", 9, getter, NULL);
|
||||
ScrDynEntry *entry = &table->v.obj.entries[table->v.obj.len - 1];
|
||||
entry->enumerable = entry->configurable = false;
|
||||
scr_dyn_obj_set_attrs_at(table, scr_dyn_obj_count(table) - 1, false, false, false);
|
||||
scr_dyn_obj_set(table, "poolSize", 8, scr_dyn_new_num(pool_size));
|
||||
ScrDyn *is_encoding = NULL;
|
||||
for (size_t i = 0; i < sizeof statics / sizeof statics[0]; i++) {
|
||||
|
||||
@@ -1757,11 +1757,11 @@ ScrStr *scr_fs_mkdtemp_sync_chk(const ScrDyn *prefix, const ScrDyn *opts, const
|
||||
if (!scr_fs_encoding_chk(opts)) return NULL;
|
||||
bool utf8 = true;
|
||||
if (opts->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < opts->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &opts->v.obj.entries[i];
|
||||
if (scr_fs_dyn_absent(e->value)) continue;
|
||||
if (strcmp(e->key, "encoding") == 0) {
|
||||
if (!scr_fs_utf8_encoding(e->value)) utf8 = false;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(opts); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(opts, i);
|
||||
if (scr_fs_dyn_absent(e.value)) continue;
|
||||
if (strcmp(e.key, "encoding") == 0) {
|
||||
if (!scr_fs_utf8_encoding(e.value)) utf8 = false;
|
||||
continue;
|
||||
}
|
||||
utf8 = false; /* an unmodeled effectful option */
|
||||
|
||||
@@ -507,8 +507,8 @@ static bool scr_console_holds_buffer(const ScrDyn *d) {
|
||||
if (scr_console_holds_buffer(d->v.arr.items[i])) return true;
|
||||
return false;
|
||||
case SCR_DYN_OBJ:
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDyn *value = d->v.obj.entries[i].value;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
const ScrDyn *value = scr_dyn_obj_value_at(d, i);
|
||||
if (value && scr_console_holds_buffer(value)) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -626,7 +626,7 @@ static ScrStr **scr_table_own_keys(const ScrDyn *item, size_t *count) {
|
||||
return keys;
|
||||
}
|
||||
if (item->kind != SCR_DYN_OBJ) return NULL;
|
||||
size_t len = item->v.obj.len;
|
||||
size_t len = scr_dyn_obj_count(item);
|
||||
const char **names = calloc(len ? len : 1, sizeof *names);
|
||||
size_t *lens = calloc(len ? len : 1, sizeof *lens);
|
||||
size_t *order = calloc(len ? len : 1, sizeof *order);
|
||||
@@ -634,10 +634,10 @@ static ScrStr **scr_table_own_keys(const ScrDyn *item, size_t *count) {
|
||||
if (!names || !lens || !order || !keys) scr_trap("scriptc: out of memory\n");
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
const ScrDynEntry *ent = &item->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
names[n] = ent->key;
|
||||
lens[n] = ent->key_len;
|
||||
ScrDynProp prop = scr_dyn_obj_prop_at(item, i);
|
||||
if (!prop.enumerable) continue;
|
||||
names[n] = prop.key;
|
||||
lens[n] = prop.key_len;
|
||||
n++;
|
||||
}
|
||||
scr_table_key_order(names, lens, n, order);
|
||||
@@ -652,16 +652,14 @@ static ScrStr **scr_table_own_keys(const ScrDyn *item, size_t *count) {
|
||||
/* item[key] when it is an own property; NULL otherwise. +1. */
|
||||
static ScrDyn *scr_table_own_value(const ScrDyn *item, const ScrStr *key) {
|
||||
if (item->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < item->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &item->v.obj.entries[i];
|
||||
if (ent->key_len != key->len || memcmp(ent->key, key->data, key->len) != 0) continue;
|
||||
if (ent->accessor) {
|
||||
scr_table_fence("console.table rows with accessor properties have no lowering");
|
||||
return NULL;
|
||||
}
|
||||
return scr_dyn_retain(ent->value);
|
||||
size_t i = scr_dyn_obj_index_of(item, key->data, key->len);
|
||||
if (i == SIZE_MAX) return NULL;
|
||||
ScrDynProp prop = scr_dyn_obj_prop_at(item, i);
|
||||
if (prop.accessor) {
|
||||
scr_table_fence("console.table rows with accessor properties have no lowering");
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
return scr_dyn_retain(prop.value);
|
||||
}
|
||||
if (item->kind == SCR_DYN_ARR || item->kind == SCR_DYN_BYTES) {
|
||||
size_t len = item->kind == SCR_DYN_ARR ? item->v.arr.len : item->v.bytes->len;
|
||||
|
||||
@@ -63,10 +63,10 @@ static bool scr_decl_adopt_plain(const ScrDyn *n, const ScrDynPath *path, bool l
|
||||
else if (n->v.obj.source_access && !n->v.obj.source_identity)
|
||||
want = "a plain object";
|
||||
else {
|
||||
for (size_t i = 0; i < n->v.obj.len && !want; i++) {
|
||||
const ScrDynEntry *e = &n->v.obj.entries[i];
|
||||
if (e->accessor) want = "a plain object (this value has accessor properties)";
|
||||
else if (!e->writable || !e->enumerable || !e->configurable)
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(n) && !want; i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(n, i);
|
||||
if (e.accessor) want = "a plain object (this value has accessor properties)";
|
||||
else if (!e.writable || !e.enumerable || !e.configurable)
|
||||
want = "a plain object (this value has non-default property attributes)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,6 +584,67 @@ _Static_assert(sizeof(((ScrDyn *)0)->v.arr) <= sizeof(((ScrDyn *)0)->v.typed_ref
|
||||
_Static_assert(sizeof(void *) != 8 || offsetof(ScrDyn, v.obj.shape) == 80, "v.obj.shape offset");
|
||||
_Static_assert(sizeof(void *) != 8 || offsetof(ScrDyn, v.obj.region) == 72, "v.obj.region offset");
|
||||
|
||||
/* ── own properties of ordinary objects ──────────────────────────────
|
||||
* Code outside the object core (scr_json.c and scr_js_object.c) reads and
|
||||
* adjusts an SCR_DYN_OBJ's own string-keyed properties through these
|
||||
* accessors, never through v.obj.entries, so the object's storage can
|
||||
* change underneath (the single object model's generic objects). Index i
|
||||
* runs over the properties in creation order, 0 <= i < scr_dyn_obj_count.
|
||||
* Keys and values are borrowed: they stay valid until the object changes. */
|
||||
typedef struct {
|
||||
const char *key;
|
||||
size_t key_len;
|
||||
ScrDyn *value; /* data property; the undefined value for an accessor */
|
||||
ScrDyn *getter; /* accessor property; NULL when absent */
|
||||
ScrDyn *setter; /* accessor property; NULL when absent */
|
||||
bool accessor;
|
||||
bool writable;
|
||||
bool enumerable;
|
||||
bool configurable;
|
||||
} ScrDynProp;
|
||||
|
||||
static inline size_t scr_dyn_obj_count(const ScrDyn *o) {
|
||||
return o->v.obj.len;
|
||||
}
|
||||
|
||||
static inline const char *scr_dyn_obj_key_at(const ScrDyn *o, size_t i, size_t *key_len) {
|
||||
*key_len = o->v.obj.entries[i].key_len;
|
||||
return o->v.obj.entries[i].key;
|
||||
}
|
||||
|
||||
/* The value of data property i (borrowed); the undefined value for an
|
||||
* accessor property, whose functions scr_dyn_obj_prop_at answers. */
|
||||
static inline ScrDyn *scr_dyn_obj_value_at(const ScrDyn *o, size_t i) {
|
||||
return o->v.obj.entries[i].value;
|
||||
}
|
||||
|
||||
static inline ScrDynProp scr_dyn_obj_prop_at(const ScrDyn *o, size_t i) {
|
||||
const ScrDynEntry *e = &o->v.obj.entries[i];
|
||||
return (ScrDynProp){e->key, e->key_len, e->value, e->getter, e->setter,
|
||||
e->accessor, e->writable, e->enumerable, e->configurable};
|
||||
}
|
||||
|
||||
/* The index of own property `key`, or SIZE_MAX. A linear scan: for code
|
||||
* that looks up options and headers, not for hot property reads. */
|
||||
static inline size_t scr_dyn_obj_index_of(const ScrDyn *o, const char *key, size_t key_len) {
|
||||
for (size_t i = 0; i < o->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &o->v.obj.entries[i];
|
||||
if (e->key_len == key_len && memcmp(e->key, key, key_len) == 0) return i;
|
||||
}
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
/* Sets the attributes of property i (`writable` is ignored for an
|
||||
* accessor property): builtin objects the runtime builds restrict their
|
||||
* members this way right after adding them. */
|
||||
static inline void scr_dyn_obj_set_attrs_at(ScrDyn *o, size_t i, bool writable, bool enumerable,
|
||||
bool configurable) {
|
||||
ScrDynEntry *e = &o->v.obj.entries[i];
|
||||
if (!e->accessor) e->writable = writable;
|
||||
e->enumerable = enumerable;
|
||||
e->configurable = configurable;
|
||||
}
|
||||
|
||||
/* ── intact parse regions ─────────────────────────────────────────────
|
||||
* Every heap dyn node carries a cycle header, so an ordinary release that
|
||||
* leaves an array or object alive buffers it as a possible cycle root, and
|
||||
@@ -748,6 +809,20 @@ ScrDyn *scr_dyn_get_own_property_symbols(const ScrDyn *value);
|
||||
/* The own property stored under a symbol key on an object (borrowed), or
|
||||
* NULL when it has none. */
|
||||
ScrDynEntry *scr_dyn_own_symbol_entry(const ScrDyn *object, const ScrDyn *key);
|
||||
/* The own symbol-keyed property `key` of `object` as a property view
|
||||
* (scr_dyn_obj_prop_at; `key` and `key_len` name its private storage
|
||||
* key); false when there is none. */
|
||||
static inline bool scr_dyn_own_symbol_prop(const ScrDyn *object, const ScrDyn *key, ScrDynProp *out) {
|
||||
const ScrDynEntry *e = scr_dyn_own_symbol_entry(object, key);
|
||||
if (!e) return false;
|
||||
*out = (ScrDynProp){e->key, e->key_len, e->value, e->getter, e->setter,
|
||||
e->accessor, e->writable, e->enumerable, e->configurable};
|
||||
return true;
|
||||
}
|
||||
/* Copies own property i of `source` to `target` (scr_dyn_copy_entry). */
|
||||
static inline void scr_dyn_copy_prop_at(ScrDyn *target, const ScrDyn *source, size_t i) {
|
||||
scr_dyn_copy_entry(target, source, &source->v.obj.entries[i]);
|
||||
}
|
||||
/* The private storage name of a symbol key (+1). With it,
|
||||
* scr_dyn_symbol_init_own gives an object that has no symbol properties
|
||||
* yet its first one, a writable, enumerable, configurable data property
|
||||
|
||||
@@ -60,17 +60,17 @@ static ScrDyn *hp_props_of(void *child) {
|
||||
return props;
|
||||
}
|
||||
|
||||
static ScrDynEntry *hp_entry(const ScrDyn *props, const char *key, size_t key_len) {
|
||||
if (!props) return NULL;
|
||||
for (size_t i = 0; i < props->v.obj.len; i++) {
|
||||
ScrDynEntry *e = &props->v.obj.entries[i];
|
||||
if (e->key_len == key_len && !memcmp(e->key, key, key_len)) return e;
|
||||
}
|
||||
return NULL;
|
||||
/* Own property `key` of the table object, in *out; false when absent. */
|
||||
static bool hp_entry(const ScrDyn *props, const char *key, size_t key_len, ScrDynProp *out) {
|
||||
if (!props) return false;
|
||||
size_t i = scr_dyn_obj_index_of(props, key, key_len);
|
||||
if (i == SIZE_MAX) return false;
|
||||
*out = scr_dyn_obj_prop_at(props, i);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hp_has(const ScrDyn *props, const char *key, size_t key_len) {
|
||||
return hp_entry(props, key, key_len) != NULL;
|
||||
return props && scr_dyn_obj_index_of(props, key, key_len) != SIZE_MAX;
|
||||
}
|
||||
|
||||
/* A property the program added, read with the child as `this`: an
|
||||
@@ -78,10 +78,10 @@ static bool hp_has(const ScrDyn *props, const char *key, size_t key_len) {
|
||||
* it (`Object.defineProperty(child, "x", { get() { return this.pid; } })`).
|
||||
* +1, or NULL with the exception pending. */
|
||||
static ScrDyn *hp_read(ScrDyn *props, ScrDyn *self, const char *key, size_t key_len) {
|
||||
ScrDynEntry *e = hp_entry(props, key, key_len);
|
||||
if (!e || !e->accessor) return scr_dyn_obj_read(props, key, key_len);
|
||||
if (!e->getter) return scr_dyn_retain(scr_dyn_undefined());
|
||||
ScrDyn *getter = scr_dyn_retain(e->getter);
|
||||
ScrDynProp e;
|
||||
if (!hp_entry(props, key, key_len, &e) || !e.accessor) return scr_dyn_obj_read(props, key, key_len);
|
||||
if (!e.getter) return scr_dyn_retain(scr_dyn_undefined());
|
||||
ScrDyn *getter = scr_dyn_retain(e.getter);
|
||||
scr_dyn_this_push_dyn(self);
|
||||
ScrDyn *result = scr_dyn_call(getter, NULL, 0, "getter");
|
||||
scr_dyn_this_pop();
|
||||
@@ -132,7 +132,8 @@ static ScrDyn *hp_get(void *h, const char *key, size_t key_len) {
|
||||
|
||||
static bool hp_set(void *h, const char *key, size_t key_len, const ScrDyn *value) {
|
||||
ScrDyn *props = hp_find(h);
|
||||
ScrDynEntry *entry = hp_entry(props, key, key_len);
|
||||
ScrDynProp found;
|
||||
const ScrDynProp *entry = hp_entry(props, key, key_len, &found) ? &found : NULL;
|
||||
if (entry && entry->accessor) {
|
||||
/* An accessor's setter runs on the child. Without one the write throws
|
||||
* the strict-mode TypeError, as the other handle getters do. */
|
||||
|
||||
@@ -4821,14 +4821,14 @@ static ScrArr *sf_headers_convert_init(const ScrDyn *headers, bool *canonical_ou
|
||||
return converted;
|
||||
}
|
||||
if (headers->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < headers->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &headers->v.obj.entries[i];
|
||||
ScrStr *raw_name = scr_str_new(e->key, e->key_len);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(headers); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(headers, i);
|
||||
ScrStr *raw_name = scr_str_new(e.key, e.key_len);
|
||||
ScrStr *name_bytes = sf_header_value_bytestring(raw_name);
|
||||
ScrStr *name = name_bytes ? sf_latin1_to_utf8(name_bytes) : NULL;
|
||||
scr_str_release(name_bytes);
|
||||
scr_str_release(raw_name);
|
||||
ScrDyn *source = scr_dyn_retain(e->value);
|
||||
ScrDyn *source = scr_dyn_retain(e.value);
|
||||
ScrStr *raw_value = name ? scr_dyn_string_coerce_js(source) : NULL;
|
||||
scr_dyn_release(source);
|
||||
ScrStr *value_bytes = raw_value
|
||||
@@ -6088,11 +6088,11 @@ static int8_t sf_light_header_form(const ScrDyn *headers, bool json_body,
|
||||
}
|
||||
int8_t form = 0;
|
||||
if (headers->kind == SCR_DYN_OBJ) {
|
||||
ScrArr *out = scr_arr_new(SCR_ELEM_STR, 2 * headers->v.obj.len);
|
||||
ScrArr *out = scr_arr_new(SCR_ELEM_STR, 2 * scr_dyn_obj_count(headers));
|
||||
form = 3;
|
||||
for (size_t i = 0; i < headers->v.obj.len && form == 3; i++) {
|
||||
const ScrDynEntry *e = &headers->v.obj.entries[i];
|
||||
const ScrDyn *value = e->value;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(headers) && form == 3; i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(headers, i);
|
||||
const ScrDyn *value = e.value;
|
||||
size_t count = value->kind == SCR_DYN_ARR ? value->v.arr.len : 1;
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
const ScrDyn *item = value->kind == SCR_DYN_ARR ? value->v.arr.items[j] : value;
|
||||
@@ -6106,7 +6106,7 @@ static int8_t sf_light_header_form(const ScrDyn *headers, bool json_body,
|
||||
form = 0;
|
||||
break;
|
||||
}
|
||||
scr_arr_push_ref(out, scr_str_new(e->key, e->key_len));
|
||||
scr_arr_push_ref(out, scr_str_new(e.key, e.key_len));
|
||||
scr_arr_push_ref(out, text);
|
||||
}
|
||||
}
|
||||
@@ -6666,27 +6666,27 @@ ScrPromise *scr_fetch_static(ScrStr *url, ScrDyn *init) {
|
||||
return sf_reject_now(promise, "fetch failed");
|
||||
}
|
||||
if (init && init->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < init->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &init->v.obj.entries[i];
|
||||
bool supported = sf_name(entry->key, entry->key_len, "method") ||
|
||||
sf_name(entry->key, entry->key_len, "headers") ||
|
||||
sf_name(entry->key, entry->key_len, "body") ||
|
||||
sf_name(entry->key, entry->key_len, "duplex") ||
|
||||
sf_name(entry->key, entry->key_len, "redirect") ||
|
||||
sf_name(entry->key, entry->key_len, "signal");
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(init); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(init, i);
|
||||
bool supported = sf_name(entry.key, entry.key_len, "method") ||
|
||||
sf_name(entry.key, entry.key_len, "headers") ||
|
||||
sf_name(entry.key, entry.key_len, "body") ||
|
||||
sf_name(entry.key, entry.key_len, "duplex") ||
|
||||
sf_name(entry.key, entry.key_len, "redirect") ||
|
||||
sf_name(entry.key, entry.key_len, "signal");
|
||||
bool recognized_unsupported =
|
||||
sf_name(entry->key, entry->key_len, "cache") ||
|
||||
sf_name(entry->key, entry->key_len, "credentials") ||
|
||||
sf_name(entry->key, entry->key_len, "dispatcher") ||
|
||||
sf_name(entry->key, entry->key_len, "integrity") ||
|
||||
sf_name(entry->key, entry->key_len, "keepalive") ||
|
||||
sf_name(entry->key, entry->key_len, "mode") ||
|
||||
sf_name(entry->key, entry->key_len, "priority") ||
|
||||
sf_name(entry->key, entry->key_len, "referrer") ||
|
||||
sf_name(entry->key, entry->key_len, "referrerPolicy") ||
|
||||
sf_name(entry->key, entry->key_len, "window");
|
||||
if (!supported && recognized_unsupported && entry->value &&
|
||||
entry->value->kind != SCR_DYN_UNDEF) {
|
||||
sf_name(entry.key, entry.key_len, "cache") ||
|
||||
sf_name(entry.key, entry.key_len, "credentials") ||
|
||||
sf_name(entry.key, entry.key_len, "dispatcher") ||
|
||||
sf_name(entry.key, entry.key_len, "integrity") ||
|
||||
sf_name(entry.key, entry.key_len, "keepalive") ||
|
||||
sf_name(entry.key, entry.key_len, "mode") ||
|
||||
sf_name(entry.key, entry.key_len, "priority") ||
|
||||
sf_name(entry.key, entry.key_len, "referrer") ||
|
||||
sf_name(entry.key, entry.key_len, "referrerPolicy") ||
|
||||
sf_name(entry.key, entry.key_len, "window");
|
||||
if (!supported && recognized_unsupported && entry.value &&
|
||||
entry.value->kind != SCR_DYN_UNDEF) {
|
||||
return sf_reject_now(promise, "fetch failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2047,10 +2047,10 @@ void scr_http_res_write_head_dyn(ScrHttpRes *r, double status, const ScrDyn *hea
|
||||
scr_dyn_arg_type_fail("headers", "an instance of Object", headers);
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < headers->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &headers->v.obj.entries[i];
|
||||
const ScrDyn *v = e->value;
|
||||
ScrStr *name = scr_str_new(e->key, e->key_len);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(headers); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(headers, i);
|
||||
const ScrDyn *v = e.value;
|
||||
ScrStr *name = scr_str_new(e.key, e.key_len);
|
||||
if (v->kind == SCR_DYN_STR) {
|
||||
scr_http_res_set_header(r, name, v->v.str);
|
||||
} else if (v->kind == SCR_DYN_NUM) {
|
||||
@@ -6200,10 +6200,10 @@ static bool scr_http_dynh_req_set(void *h, const char *key, size_t key_len, cons
|
||||
* consecutive same-name pairs). Numbers format through String(n). NULL =
|
||||
* a value this surface cannot honestly carry (exception pending). */
|
||||
static ScrArr *scr_http_dynh_pairs(const ScrDyn *headers) {
|
||||
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, headers->v.obj.len * 2);
|
||||
for (size_t i = 0; i < headers->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &headers->v.obj.entries[i];
|
||||
const ScrDyn *v = e->value;
|
||||
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, scr_dyn_obj_count(headers) * 2);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(headers); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(headers, i);
|
||||
const ScrDyn *v = e.value;
|
||||
size_t reps = v->kind == SCR_DYN_ARR ? v->v.arr.len : 1;
|
||||
for (size_t k = 0; k < reps; k++) {
|
||||
const ScrDyn *one = v->kind == SCR_DYN_ARR ? v->v.arr.items[k] : v;
|
||||
@@ -6218,7 +6218,7 @@ static ScrArr *scr_http_dynh_pairs(const ScrDyn *headers) {
|
||||
scr_jb_puts(&b, "Invalid value \"");
|
||||
scr_jb_puts(&b, one->kind == SCR_DYN_UNDEF ? "undefined" : "object");
|
||||
scr_jb_puts(&b, "\" for header \"");
|
||||
for (size_t c = 0; c < e->key_len; c++) scr_jb_putc(&b, e->key[c]);
|
||||
for (size_t c = 0; c < e.key_len; c++) scr_jb_putc(&b, e.key[c]);
|
||||
scr_jb_putc(&b, '"');
|
||||
ScrStr *msg = scr_jb_finish(&b);
|
||||
scr_throw_error_msg_code(SCR_ERR_TYPE, msg->data, msg->len, "ERR_HTTP_INVALID_HEADER_VALUE");
|
||||
@@ -6226,7 +6226,7 @@ static ScrArr *scr_http_dynh_pairs(const ScrDyn *headers) {
|
||||
scr_arr_release(pairs);
|
||||
return NULL;
|
||||
}
|
||||
scr_arr_push_ref(pairs, scr_str_new(e->key, e->key_len));
|
||||
scr_arr_push_ref(pairs, scr_str_new(e.key, e.key_len));
|
||||
scr_arr_push_ref(pairs, vs);
|
||||
}
|
||||
}
|
||||
@@ -6945,8 +6945,8 @@ static ScrDyn *scr_http_dynh_agent_get(void *h, const char *key, size_t key_len)
|
||||
scr_dyn_arr_push(arr, item);
|
||||
}
|
||||
/* the list is most recent first: reverse each array into Node's order */
|
||||
for (size_t i = 0; i < obj->v.obj.len; i++) {
|
||||
ScrDyn *arr = obj->v.obj.entries[i].value;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(obj); i++) {
|
||||
ScrDyn *arr = scr_dyn_obj_value_at(obj, i);
|
||||
for (size_t l = 0, r = arr->v.arr.len ? arr->v.arr.len - 1 : 0; l < r; l++, r--) {
|
||||
ScrDyn *t = arr->v.arr.items[l];
|
||||
arr->v.arr.items[l] = arr->v.arr.items[r];
|
||||
@@ -7449,13 +7449,13 @@ bool scr_http_req_opts_read(const ScrDyn *opts, bool secure, const char *api, Sc
|
||||
headers = headers_view;
|
||||
}
|
||||
if (headers != NULL && headers->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < headers->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &headers->v.obj.entries[i];
|
||||
ScrStr *name = scr_str_new(e->key, e->key_len);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(headers); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(headers, i);
|
||||
ScrStr *name = scr_str_new(e.key, e.key_len);
|
||||
ScrStr *label = scr_str_new("", 0);
|
||||
scr_http_validate_header_name(name, label);
|
||||
scr_str_release(label);
|
||||
const ScrDyn *v = e->value;
|
||||
const ScrDyn *v = e.value;
|
||||
if (!scr_exc_pending()) {
|
||||
if (v->kind == SCR_DYN_ARR) {
|
||||
for (size_t k = 0; k < v->v.arr.len && !scr_exc_pending(); k++)
|
||||
|
||||
@@ -2559,9 +2559,9 @@ ScrNetServer *scr_http2_create_secure_server_dyn(const ScrDyn *opts /*borrowed*/
|
||||
ScrHttpReqFn fn) {
|
||||
bool allow_http1 = false;
|
||||
if (opts != NULL && opts->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < opts->v.obj.len; i++) {
|
||||
if (strcmp(opts->v.obj.entries[i].key, "allowHTTP1") == 0) {
|
||||
allow_http1 = scr_dyn_truthy(opts->v.obj.entries[i].value);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(opts); i++) {
|
||||
if (strcmp(scr_dyn_obj_prop_at(opts, i).key, "allowHTTP1") == 0) {
|
||||
allow_http1 = scr_dyn_truthy(scr_dyn_obj_value_at(opts, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3105,15 +3105,15 @@ static void scr_h2_dyn_fire_goaway(ScrClosure *cb, double code, double last) {
|
||||
/* Flatten a dyn headers object into the flat pairs array (numbers via
|
||||
* String(n); the :status/:method/... pseudo-headers pass through). */
|
||||
static ScrArr *scr_h2_dom_to_pairs(const ScrDyn *headers) {
|
||||
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, headers->v.obj.len * 2);
|
||||
for (size_t i = 0; i < headers->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &headers->v.obj.entries[i];
|
||||
const ScrDyn *v = e->value;
|
||||
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, scr_dyn_obj_count(headers) * 2);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(headers); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(headers, i);
|
||||
const ScrDyn *v = e.value;
|
||||
ScrStr *vs;
|
||||
if (v->kind == SCR_DYN_STR) vs = scr_str_retain(v->v.str);
|
||||
else if (v->kind == SCR_DYN_NUM) vs = scr_f64_to_scrstr(v->v.num);
|
||||
else continue; /* undefined/null header: dropped, Node's stance */
|
||||
scr_arr_push_ref(pairs, scr_str_new(e->key, e->key_len));
|
||||
scr_arr_push_ref(pairs, scr_str_new(e.key, e.key_len));
|
||||
scr_arr_push_ref(pairs, vs);
|
||||
}
|
||||
return pairs;
|
||||
|
||||
@@ -973,21 +973,23 @@ ScrStr *scr_insp_regex(ScrRegex *re) {
|
||||
* the k-th symbol key. */
|
||||
static size_t insp_view_property_slots(const ScrDyn *props) {
|
||||
if (!props) return 0;
|
||||
return props->v.obj.len + (props->symbol_keys ? props->symbol_keys->v.arr.len : 0);
|
||||
return scr_dyn_obj_count(props) + (props->symbol_keys ? props->symbol_keys->v.arr.len : 0);
|
||||
}
|
||||
|
||||
static ScrStr *insp_accessor_tag(const ScrDynEntry *ent);
|
||||
static ScrStr *insp_accessor_tag(const ScrDynProp *ent);
|
||||
static void insp_key_into(InspBuf *b, const char *key, size_t len);
|
||||
|
||||
/* Slot k's `key: value` entry when it is enumerable, else NULL. */
|
||||
static ScrStr *insp_view_property(ScrDyn *props, size_t k, double recurse, double depth) {
|
||||
const ScrDynEntry *ent;
|
||||
ScrDynProp found;
|
||||
const ScrDynProp *ent = NULL;
|
||||
ScrStr *key = NULL;
|
||||
if (k < props->v.obj.len) {
|
||||
ent = &props->v.obj.entries[k];
|
||||
if (k < scr_dyn_obj_count(props)) {
|
||||
found = scr_dyn_obj_prop_at(props, k);
|
||||
ent = &found;
|
||||
} else {
|
||||
ScrDyn *symbol = props->symbol_keys->v.arr.items[k - props->v.obj.len];
|
||||
ent = scr_dyn_own_symbol_entry(props, symbol);
|
||||
ScrDyn *symbol = props->symbol_keys->v.arr.items[k - scr_dyn_obj_count(props)];
|
||||
if (scr_dyn_own_symbol_prop(props, symbol, &found)) ent = &found;
|
||||
if (ent && ent->enumerable) key = scr_insp_dyn(symbol, recurse, depth);
|
||||
}
|
||||
if (!ent || !ent->enumerable) return NULL;
|
||||
@@ -1005,10 +1007,11 @@ static ScrStr *insp_view_property(ScrDyn *props, size_t k, double recurse, doubl
|
||||
static size_t insp_view_property_count(ScrDyn *props) {
|
||||
size_t count = 0;
|
||||
for (size_t k = 0; k < insp_view_property_slots(props); k++) {
|
||||
if (k < props->v.obj.len) count += props->v.obj.entries[k].enumerable;
|
||||
if (k < scr_dyn_obj_count(props)) count += scr_dyn_obj_prop_at(props, k).enumerable;
|
||||
else {
|
||||
const ScrDynEntry *ent = scr_dyn_own_symbol_entry(props, props->symbol_keys->v.arr.items[k - props->v.obj.len]);
|
||||
count += ent && ent->enumerable;
|
||||
ScrDynProp ent;
|
||||
count += scr_dyn_own_symbol_prop(props, props->symbol_keys->v.arr.items[k - scr_dyn_obj_count(props)], &ent) &&
|
||||
ent.enumerable;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
@@ -1157,11 +1160,11 @@ static ScrDyn *insp_error_cause(ScrError *e, bool *enumerable, ScrDyn **view) {
|
||||
ScrDyn *node = scr_errdyn_view_of(e);
|
||||
if (node != NULL && node->kind == SCR_DYN_TYPED_REF) node = *view = scr_dyn_typed_ref_materialize(node);
|
||||
if (node != NULL && node->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < node->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &node->v.obj.entries[i];
|
||||
if (ent->key_len == 5 && memcmp(ent->key, "cause", 5) == 0) {
|
||||
*enumerable = ent->enumerable;
|
||||
return ent->value;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(node); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(node, i);
|
||||
if (ent.key_len == 5 && memcmp(ent.key, "cause", 5) == 0) {
|
||||
*enumerable = ent.enumerable;
|
||||
return ent.value;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -1176,9 +1179,9 @@ static ScrDyn *insp_error_cause(ScrError *e, bool *enumerable, ScrDyn **view) {
|
||||
* other non-enumerable property of an error. */
|
||||
bool scr_insp_error_bag_has_properties(ScrDyn *bag) {
|
||||
if (bag == NULL || bag->kind != SCR_DYN_OBJ) return false;
|
||||
for (size_t i = 0; i < bag->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &bag->v.obj.entries[i];
|
||||
if (ent->enumerable && !(ent->key_len == 5 && memcmp(ent->key, "cause", 5) == 0)) return true;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(bag); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(bag, i);
|
||||
if (ent.enumerable && !(ent.key_len == 5 && memcmp(ent.key, "cause", 5) == 0)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1282,7 +1285,7 @@ ScrStr *scr_insp_error(ScrError *e, double recurse, double depth) {
|
||||
* (/^[a-zA-Z_][a-zA-Z_0-9]*$/, '__proto__' excepted), quoted otherwise. */
|
||||
/* util.inspect's text for an accessor property: [Getter], [Setter] or
|
||||
* [Getter/Setter], by which of the two are functions. +1. */
|
||||
static ScrStr *insp_accessor_tag(const ScrDynEntry *ent) {
|
||||
static ScrStr *insp_accessor_tag(const ScrDynProp *ent) {
|
||||
bool get = ent->getter && ent->getter->kind == SCR_DYN_FUNC;
|
||||
bool set = ent->setter && ent->setter->kind == SCR_DYN_FUNC;
|
||||
const char *text = get && set ? "[Getter/Setter]" : get ? "[Getter]" : set ? "[Setter]" : "undefined";
|
||||
@@ -1371,12 +1374,12 @@ static ScrDyn *insp_assertion_ellipsis(ScrDyn *value) {
|
||||
* Node's `{ ... }` tail. */
|
||||
/* An own non-enumerable entry of the error encoding, NULL when absent or
|
||||
* enumerable (an enumerable one prints with the other own keys). */
|
||||
static const ScrDynEntry *insp_error_hidden_entry(const ScrDyn *d, const char *key, size_t len) {
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
if (ent->key_len == len && memcmp(ent->key, key, len) == 0) return ent->enumerable ? NULL : ent;
|
||||
}
|
||||
return NULL;
|
||||
static const ScrDynProp *insp_error_hidden_entry(const ScrDyn *d, const char *key, size_t len,
|
||||
ScrDynProp *out) {
|
||||
size_t i = scr_dyn_obj_index_of(d, key, len);
|
||||
if (i == SIZE_MAX) return NULL;
|
||||
*out = scr_dyn_obj_prop_at(d, i);
|
||||
return out->enumerable ? NULL : out;
|
||||
}
|
||||
|
||||
static ScrStr *scr_insp_dyn_error(ScrDyn *d, double recurse, double depth) {
|
||||
@@ -1390,19 +1393,20 @@ static ScrStr *scr_insp_dyn_error(ScrDyn *d, double recurse, double depth) {
|
||||
memcmp(name->v.str->data, "AssertionError", 14) == 0;
|
||||
double value_depth = assertion ? recurse : depth;
|
||||
size_t extra = 0;
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
if ((ent->key_len == 4 && memcmp(ent->key, "name", 4) == 0) ||
|
||||
(ent->key_len == 7 && memcmp(ent->key, "message", 7) == 0) ||
|
||||
(ent->key_len == 5 && memcmp(ent->key, "stack", 5) == 0))
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
if (!ent.enumerable) continue;
|
||||
if ((ent.key_len == 4 && memcmp(ent.key, "name", 4) == 0) ||
|
||||
(ent.key_len == 7 && memcmp(ent.key, "message", 7) == 0) ||
|
||||
(ent.key_len == 5 && memcmp(ent.key, "stack", 5) == 0))
|
||||
continue;
|
||||
extra++;
|
||||
}
|
||||
/* formatError shows a non-enumerable `cause`, and an AggregateError's
|
||||
* `errors` array, after the enumerable keys: `[cause]`, `[errors]`. */
|
||||
const ScrDynEntry *cause = insp_error_hidden_entry(d, "cause", 5);
|
||||
const ScrDynEntry *errors = insp_error_hidden_entry(d, "errors", 6);
|
||||
ScrDynProp cause_prop, errors_prop;
|
||||
const ScrDynProp *cause = insp_error_hidden_entry(d, "cause", 5, &cause_prop);
|
||||
const ScrDynProp *errors = insp_error_hidden_entry(d, "errors", 6, &errors_prop);
|
||||
if (errors && errors->value->kind != SCR_DYN_ARR) errors = NULL;
|
||||
extra += (cause != NULL) + (errors != NULL);
|
||||
InspBuf base = {0};
|
||||
@@ -1426,20 +1430,20 @@ static ScrStr *scr_insp_dyn_error(ScrDyn *d, double recurse, double depth) {
|
||||
if (extra == 0) return base_str;
|
||||
scr_insp_begin(recurse + 1);
|
||||
scr_insp_seen_push(d);
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
if ((ent->key_len == 4 && memcmp(ent->key, "name", 4) == 0) ||
|
||||
(ent->key_len == 7 && memcmp(ent->key, "message", 7) == 0) ||
|
||||
(ent->key_len == 5 && memcmp(ent->key, "stack", 5) == 0))
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
if (!ent.enumerable) continue;
|
||||
if ((ent.key_len == 4 && memcmp(ent.key, "name", 4) == 0) ||
|
||||
(ent.key_len == 7 && memcmp(ent.key, "message", 7) == 0) ||
|
||||
(ent.key_len == 5 && memcmp(ent.key, "stack", 5) == 0))
|
||||
continue;
|
||||
bool shortened = assertion && ((ent->key_len == 6 && memcmp(ent->key, "actual", 6) == 0) ||
|
||||
(ent->key_len == 8 && memcmp(ent->key, "expected", 8) == 0));
|
||||
ScrDyn *shown = shortened ? insp_assertion_ellipsis(ent->value) : scr_dyn_retain(ent->value);
|
||||
bool shortened = assertion && ((ent.key_len == 6 && memcmp(ent.key, "actual", 6) == 0) ||
|
||||
(ent.key_len == 8 && memcmp(ent.key, "expected", 8) == 0));
|
||||
ScrDyn *shown = shortened ? insp_assertion_ellipsis(ent.value) : scr_dyn_retain(ent.value);
|
||||
ScrStr *val = scr_insp_dyn(shown, recurse + 1, value_depth);
|
||||
scr_dyn_release(shown);
|
||||
InspBuf eb = {0};
|
||||
insp_key_into(&eb, ent->key, ent->key_len);
|
||||
insp_key_into(&eb, ent.key, ent.key_len);
|
||||
ib_cstr(&eb, ": ");
|
||||
ib_bytes(&eb, val->data, val->len);
|
||||
scr_str_release(val);
|
||||
@@ -1447,7 +1451,7 @@ static ScrStr *scr_insp_dyn_error(ScrDyn *d, double recurse, double depth) {
|
||||
scr_insp_entry(entry, false);
|
||||
scr_str_release(entry);
|
||||
}
|
||||
const ScrDynEntry *hidden[] = {cause, errors};
|
||||
const ScrDynProp *hidden[] = {cause, errors};
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
if (!hidden[i]) continue;
|
||||
ScrStr *val = scr_insp_dyn(hidden[i]->value, recurse + 1, value_depth);
|
||||
@@ -1690,9 +1694,9 @@ static ScrStr *scr_insp_dyn_collection(ScrDyn *d, double recurse, double depth,
|
||||
|
||||
/* An own symbol-keyed property of `d` (borrowed) this render shows, or
|
||||
* NULL: enumerable ones, and under showHidden the non-enumerable ones too. */
|
||||
static ScrDynEntry *scr_insp_symbol_entry(ScrDyn *d, size_t i) {
|
||||
ScrDynEntry *ent = scr_dyn_own_symbol_entry(d, d->symbol_keys->v.arr.items[i]);
|
||||
return ent && (ent->enumerable || g_show_hidden) ? ent : NULL;
|
||||
static bool scr_insp_symbol_entry(ScrDyn *d, size_t i, ScrDynProp *out) {
|
||||
return scr_dyn_own_symbol_prop(d, d->symbol_keys->v.arr.items[i], out) &&
|
||||
(out->enumerable || g_show_hidden);
|
||||
}
|
||||
|
||||
/* An ordinary object: `Name { key: value }` with its constructor name
|
||||
@@ -1700,15 +1704,21 @@ static ScrDynEntry *scr_insp_symbol_entry(ScrDyn *d, size_t i) {
|
||||
* enumerable string keys, then the own enumerable symbol keys. */
|
||||
/* An own entry this render shows: enumerable ones, and under showHidden
|
||||
* the non-enumerable ones too (never the encoding's `%` markers). */
|
||||
static bool insp_obj_shows(const ScrDynEntry *ent) {
|
||||
static bool insp_obj_shows(const ScrDynProp *ent) {
|
||||
return ent->enumerable || (g_show_hidden && !(ent->key_len && ent->key[0] == '%'));
|
||||
}
|
||||
|
||||
static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char *cls) {
|
||||
size_t shown = 0;
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) shown += insp_obj_shows(&d->v.obj.entries[i]);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
shown += insp_obj_shows(&ent);
|
||||
}
|
||||
size_t nsymbols = d->symbol_keys ? d->symbol_keys->v.arr.len : 0;
|
||||
for (size_t i = 0; i < nsymbols; i++) shown += scr_insp_symbol_entry(d, i) != NULL;
|
||||
for (size_t i = 0; i < nsymbols; i++) {
|
||||
ScrDynProp ent;
|
||||
shown += scr_insp_symbol_entry(d, i, &ent);
|
||||
}
|
||||
if (shown == 0) {
|
||||
if (cls) return scr_insp_class_tag(cls, " {}");
|
||||
return d->null_proto ? scr_str_new("[Object: null prototype] {}", 27)
|
||||
@@ -1720,17 +1730,17 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char
|
||||
: insp_styled_lit("[Object]", 8, INSP_SPECIAL);
|
||||
}
|
||||
scr_insp_begin(recurse + 1);
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &d->v.obj.entries[i];
|
||||
if (!insp_obj_shows(ent)) continue;
|
||||
ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse + 1, depth);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(d, i);
|
||||
if (!insp_obj_shows(&ent)) continue;
|
||||
ScrStr *val = ent.accessor ? insp_accessor_tag(&ent) : scr_insp_dyn(ent.value, recurse + 1, depth);
|
||||
InspBuf eb = {0};
|
||||
if (ent->enumerable) {
|
||||
insp_key_into(&eb, ent->key, ent->key_len);
|
||||
if (ent.enumerable) {
|
||||
insp_key_into(&eb, ent.key, ent.key_len);
|
||||
} else {
|
||||
/* formatProperty's hidden key: the key's rendering in brackets. */
|
||||
ib_char(&eb, '[');
|
||||
insp_key_into(&eb, ent->key, ent->key_len);
|
||||
insp_key_into(&eb, ent.key, ent.key_len);
|
||||
ib_char(&eb, ']');
|
||||
}
|
||||
ib_cstr(&eb, ": ");
|
||||
@@ -1742,8 +1752,9 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char
|
||||
if (scr_exc_pending()) break;
|
||||
}
|
||||
for (size_t i = 0; i < nsymbols; i++) {
|
||||
ScrDynEntry *ent = scr_insp_symbol_entry(d, i);
|
||||
if (!ent) continue;
|
||||
ScrDynProp found;
|
||||
if (!scr_insp_symbol_entry(d, i, &found)) continue;
|
||||
const ScrDynProp *ent = &found;
|
||||
ScrStr *key = scr_insp_dyn(d->symbol_keys->v.arr.items[i], recurse + 1, depth);
|
||||
ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse + 1, depth);
|
||||
InspBuf eb = {0};
|
||||
@@ -2063,7 +2074,7 @@ static ScrDyn *insp_inspect_value(void) {
|
||||
ScrDyn *set = scr_dyn_new_func(scr_closure_new((void *)members[i], 0), insp_inspect_member_call, 1,
|
||||
"native:function", members[i]);
|
||||
scr_dyn_obj_set_accessor(table, members[i], strlen(members[i]), get, set);
|
||||
table->v.obj.entries[table->v.obj.len - 1].enumerable = false;
|
||||
scr_dyn_obj_set_attrs_at(table, scr_dyn_obj_count(table) - 1, true, false, true);
|
||||
}
|
||||
scr_dyn_release(table);
|
||||
}
|
||||
@@ -2100,15 +2111,15 @@ static ScrDyn *insp_user_options(double depth) {
|
||||
insp_opt_set(options, "getters", scr_dyn_new_bool(false));
|
||||
insp_opt_set(options, "numericSeparator", scr_dyn_new_bool(false));
|
||||
if (g_user_options && g_user_options->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < g_user_options->v.obj.len; i++) {
|
||||
const ScrDynEntry *ent = &g_user_options->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
ScrDyn *value = scr_dyn_obj_read((ScrDyn *)g_user_options, ent->key, ent->key_len);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(g_user_options); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(g_user_options, i);
|
||||
if (!ent.enumerable) continue;
|
||||
ScrDyn *value = scr_dyn_obj_read((ScrDyn *)g_user_options, ent.key, ent.key_len);
|
||||
if (!value) {
|
||||
scr_dyn_release(options);
|
||||
return NULL;
|
||||
}
|
||||
scr_dyn_obj_set(options, ent->key, ent->key_len, value);
|
||||
scr_dyn_obj_set(options, ent.key, ent.key_len, value);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
@@ -2343,9 +2354,12 @@ static ScrStr *scr_insp_dyn_func(ScrDyn *d, double recurse, double depth) {
|
||||
}
|
||||
size_t shown = 0;
|
||||
if (table && table->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < table->v.obj.len; i++) shown += table->v.obj.entries[i].enumerable;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(table); i++) shown += scr_dyn_obj_prop_at(table, i).enumerable;
|
||||
size_t nsymbols = table->symbol_keys ? table->symbol_keys->v.arr.len : 0;
|
||||
for (size_t i = 0; i < nsymbols; i++) shown += scr_insp_symbol_entry(table, i) != NULL;
|
||||
for (size_t i = 0; i < nsymbols; i++) {
|
||||
ScrDynProp ent;
|
||||
shown += scr_insp_symbol_entry(table, i, &ent);
|
||||
}
|
||||
}
|
||||
if (shown == 0) {
|
||||
scr_dyn_release(table);
|
||||
@@ -2498,7 +2512,10 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) {
|
||||
* own `length` comes first, and non-enumerable properties show too. */
|
||||
const ScrDyn *props = d->v.arr.properties;
|
||||
size_t nprops = 0;
|
||||
for (size_t i = 0; props && i < props->v.obj.len; i++) nprops += insp_obj_shows(&props->v.obj.entries[i]);
|
||||
for (size_t i = 0; props && i < scr_dyn_obj_count(props); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(props, i);
|
||||
nprops += insp_obj_shows(&ent);
|
||||
}
|
||||
/* An instance of a class that extends Array: Node's `Name(length) `
|
||||
* prefix (scr_arr_copy_metadata names the class). */
|
||||
const char *cls = props ? props->v.obj.class_name : NULL;
|
||||
@@ -2562,15 +2579,15 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) {
|
||||
scr_str_release(s);
|
||||
entries++;
|
||||
}
|
||||
for (size_t k = 0; props && k < props->v.obj.len; k++) {
|
||||
const ScrDynEntry *ent = &props->v.obj.entries[k];
|
||||
if (!insp_obj_shows(ent)) continue;
|
||||
ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse + 1, depth);
|
||||
for (size_t k = 0; props && k < scr_dyn_obj_count(props); k++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(props, k);
|
||||
if (!insp_obj_shows(&ent)) continue;
|
||||
ScrStr *val = ent.accessor ? insp_accessor_tag(&ent) : scr_insp_dyn(ent.value, recurse + 1, depth);
|
||||
InspBuf eb = {0};
|
||||
/* formatProperty's hidden key: the key's rendering in brackets. */
|
||||
if (!ent->enumerable) ib_char(&eb, '[');
|
||||
insp_key_into(&eb, ent->key, ent->key_len);
|
||||
if (!ent->enumerable) ib_char(&eb, ']');
|
||||
if (!ent.enumerable) ib_char(&eb, '[');
|
||||
insp_key_into(&eb, ent.key, ent.key_len);
|
||||
if (!ent.enumerable) ib_char(&eb, ']');
|
||||
ib_cstr(&eb, ": ");
|
||||
ib_bytes(&eb, val->data, val->len);
|
||||
scr_str_release(val);
|
||||
@@ -2753,8 +2770,8 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) {
|
||||
scr_str_release(iso);
|
||||
ScrStr *prefix = ib_take(&head);
|
||||
bool fields = false;
|
||||
for (size_t i = 0; i < materialized->v.obj.len && !fields; i++)
|
||||
fields = materialized->v.obj.entries[i].enumerable;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(materialized) && !fields; i++)
|
||||
fields = scr_dyn_obj_prop_at(materialized, i).enumerable;
|
||||
if (!fields || recurse > depth) {
|
||||
scr_dyn_release(materialized);
|
||||
return prefix;
|
||||
@@ -3323,12 +3340,12 @@ bool scr_insp_format_read_options(const ScrDyn *options, ScrInspFormatOptions *o
|
||||
"maxArrayLength", "maxStringLength", "breakLength", "compact", "sorted",
|
||||
"getters", "numericSeparator", "stylize",
|
||||
};
|
||||
for (size_t i = 0; i < options->v.obj.len && !o->user_options; i++) {
|
||||
const ScrDynEntry *ent = &options->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(options) && !o->user_options; i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(options, i);
|
||||
if (!ent.enumerable) continue;
|
||||
bool read = false;
|
||||
for (size_t k = 0; k < sizeof known / sizeof *known && !read; k++)
|
||||
read = ent->key_len == strlen(known[k]) && memcmp(ent->key, known[k], ent->key_len) == 0;
|
||||
read = ent.key_len == strlen(known[k]) && memcmp(ent.key, known[k], ent.key_len) == 0;
|
||||
if (!read) o->user_options = options;
|
||||
}
|
||||
}
|
||||
@@ -3436,10 +3453,10 @@ static ScrStr *insp_table_cell(ScrDyn *v) {
|
||||
}
|
||||
const char *base = v->null_proto ? "[Object: null prototype]" : "Object";
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < v->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &v->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
if (ent->accessor) {
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(v); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(v, i);
|
||||
if (!ent.enumerable) continue;
|
||||
if (ent.accessor) {
|
||||
static const char message[] = "console.table cells holding accessor properties have no lowering";
|
||||
scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020");
|
||||
return scr_str_new("", 0);
|
||||
@@ -3463,12 +3480,12 @@ static ScrStr *insp_table_cell(ScrDyn *v) {
|
||||
}
|
||||
ScrStr *items[2];
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < v->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &v->v.obj.entries[i];
|
||||
if (!ent->enumerable) continue;
|
||||
ScrStr *val = scr_insp_dyn(ent->value, 1, 0);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(v); i++) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(v, i);
|
||||
if (!ent.enumerable) continue;
|
||||
ScrStr *val = scr_insp_dyn(ent.value, 1, 0);
|
||||
InspBuf eb = {0};
|
||||
insp_key_into(&eb, ent->key, ent->key_len);
|
||||
insp_key_into(&eb, ent.key, ent.key_len);
|
||||
ib_cstr(&eb, ": ");
|
||||
ib_str(&eb, val);
|
||||
scr_str_release(val);
|
||||
|
||||
@@ -716,8 +716,9 @@ ScrDyn *scr_process_versions(void) {
|
||||
scr_dyn_obj_set(scr_versions_object, "openssl", 7, scr_dyn_new_str(openssl));
|
||||
scr_str_release(node);
|
||||
scr_str_release(openssl);
|
||||
for (size_t i = 0; i < scr_versions_object->v.obj.len; i++) {
|
||||
scr_versions_object->v.obj.entries[i].writable = false;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(scr_versions_object); i++) {
|
||||
ScrDynProp prop = scr_dyn_obj_prop_at(scr_versions_object, i);
|
||||
scr_dyn_obj_set_attrs_at(scr_versions_object, i, false, prop.enumerable, prop.configurable);
|
||||
}
|
||||
scr_atexit(&scr_versions_object_cleanup);
|
||||
}
|
||||
@@ -914,8 +915,8 @@ static void scr_env_store(ScrDyn *out, const char *text, size_t ks, size_t ke,
|
||||
}
|
||||
|
||||
static int scr_env_entry_order(const void *left, const void *right) {
|
||||
const ScrDynEntry *a = *(const ScrDynEntry *const *)left;
|
||||
const ScrDynEntry *b = *(const ScrDynEntry *const *)right;
|
||||
const ScrDynProp *a = left;
|
||||
const ScrDynProp *b = right;
|
||||
size_t n = a->key_len < b->key_len ? a->key_len : b->key_len;
|
||||
int cmp = memcmp(a->key, b->key, n);
|
||||
return cmp ? cmp : (a->key_len > b->key_len) - (a->key_len < b->key_len);
|
||||
@@ -991,14 +992,14 @@ static ScrDyn *scr_env_parse_content(const ScrStr *input, bool ordinary) {
|
||||
/* Node's std::map orders UTF-8 keys before installing object properties.
|
||||
* Ordinary objects ignore string-valued __proto__ assignments; loading
|
||||
* the native environment retains that name as an ordinary variable. */
|
||||
size_t count = entries->v.obj.len;
|
||||
const ScrDynEntry **sorted = count ? malloc(count * sizeof(*sorted)) : NULL;
|
||||
size_t count = scr_dyn_obj_count(entries);
|
||||
ScrDynProp *sorted = count ? malloc(count * sizeof(*sorted)) : NULL;
|
||||
if (count && !sorted) scr_trap("scriptc: out of memory\n");
|
||||
for (size_t i = 0; i < count; i++) sorted[i] = &entries->v.obj.entries[i];
|
||||
for (size_t i = 0; i < count; i++) sorted[i] = scr_dyn_obj_prop_at(entries, i);
|
||||
if (count > 1) qsort(sorted, count, sizeof(*sorted), scr_env_entry_order);
|
||||
ScrDyn *result = ordinary ? scr_dyn_new_obj() : scr_dyn_new_obj_null_proto();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const ScrDynEntry *entry = sorted[i];
|
||||
const ScrDynProp *entry = &sorted[i];
|
||||
if (ordinary && entry->key_len == 9 && memcmp(entry->key, "__proto__", 9) == 0) continue;
|
||||
if (!ordinary) {
|
||||
scr_dyn_obj_set(result, entry->key, entry->key_len, scr_dyn_retain(entry->value));
|
||||
@@ -1103,15 +1104,15 @@ void scr_process_load_env_file(const ScrDyn *value) {
|
||||
if (!content) return;
|
||||
ScrDyn *entries = scr_env_parse_content(content, false);
|
||||
scr_str_release(content);
|
||||
for (size_t i = 0; i < entries->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &entries->v.obj.entries[i];
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(entries); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(entries, i);
|
||||
/* Node normalizes each raw sorted entry immediately before checking
|
||||
* the environment. Distinct invalid byte keys can normalize alike;
|
||||
* the first absent name wins, rather than the last parsed entry. */
|
||||
ScrStr *key = scr_str_from_utf8_lossy((const uint8_t *)entry->key, entry->key_len);
|
||||
ScrStr *key = scr_str_from_utf8_lossy((const uint8_t *)entry.key, entry.key_len);
|
||||
ScrStr *existing = scr_env_get(key);
|
||||
if (!existing) {
|
||||
const ScrStr *raw = entry->value->v.str;
|
||||
const ScrStr *raw = entry.value->v.str;
|
||||
ScrStr *value = scr_str_from_utf8_lossy((const uint8_t *)raw->data, raw->len);
|
||||
scr_env_set(key, value);
|
||||
scr_str_release(value);
|
||||
@@ -2810,10 +2811,9 @@ ScrDyn *scr_process_release(void) {
|
||||
#endif
|
||||
#undef SCR_RELEASE_FILE
|
||||
#undef SCR_RELEASE_PREFIX
|
||||
for (size_t i = 0; i < scr_release_object->v.obj.len; i++) {
|
||||
scr_release_object->v.obj.entries[i].writable = false;
|
||||
scr_release_object->v.obj.entries[i].configurable = false;
|
||||
}
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(scr_release_object); i++)
|
||||
scr_dyn_obj_set_attrs_at(scr_release_object, i, false,
|
||||
scr_dyn_obj_prop_at(scr_release_object, i).enumerable, false);
|
||||
scr_atexit(&scr_release_object_cleanup);
|
||||
}
|
||||
return scr_dyn_retain(scr_release_object);
|
||||
|
||||
@@ -636,9 +636,9 @@ static bool scr_publish_container_ok(const ScrDyn *d) {
|
||||
if (!scr_dyn_is_frozen(d)) return false;
|
||||
if (d->kind == SCR_DYN_ARR) return d->v.arr.properties == NULL;
|
||||
if (d->null_proto || d->v.obj.source_identity || d->v.obj.source_access) return false;
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &d->v.obj.entries[i];
|
||||
if (e->accessor || !e->enumerable) return false;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(d, i);
|
||||
if (e.accessor || !e.enumerable) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -666,8 +666,8 @@ static bool scr_publish_collect(ScrPublish *p, ScrDyn *root) {
|
||||
break;
|
||||
case SCR_DYN_OBJ:
|
||||
if (!scr_publish_container_ok(d)) return false;
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
ScrDyn *child = d->v.obj.entries[i].value;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDyn *child = scr_dyn_obj_value_at(d, i);
|
||||
if (child && !scr_publish_seen(p, child)) scr_publish_push(p, child);
|
||||
}
|
||||
break;
|
||||
@@ -1033,14 +1033,15 @@ ScrDyn *scr_message_decode(const ScrMessage *message) {
|
||||
} else scr_dyn_obj_set(values[i], property->key, property->length, value);
|
||||
}
|
||||
if (node->kind == SCR_MESSAGE_ERROR) {
|
||||
for (size_t j = 0; j < values[i]->v.obj.len; j++) {
|
||||
ScrDynEntry *entry = &values[i]->v.obj.entries[j];
|
||||
entry->enumerable = false;
|
||||
for (size_t j = 0; j < scr_dyn_obj_count(values[i]); j++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(values[i], j);
|
||||
bool enumerable = false;
|
||||
for (size_t k = 0; k < node->count; k++) {
|
||||
const ScrMessageProperty *property = &node->properties[k];
|
||||
if (!property->hidden && property->length == entry->key_len && !memcmp(property->key, entry->key, entry->key_len))
|
||||
entry->enumerable = true;
|
||||
if (!property->hidden && property->length == entry.key_len && !memcmp(property->key, entry.key, entry.key_len))
|
||||
enumerable = true;
|
||||
}
|
||||
scr_dyn_obj_set_attrs_at(values[i], j, entry.writable, enumerable, entry.configurable);
|
||||
}
|
||||
ScrError *error = scr_errdyn_err_of(values[i]);
|
||||
scr_error_commit_dyn(error, values[i]);
|
||||
|
||||
@@ -745,9 +745,8 @@ double scr_os_cpus_field(double i, double field) {
|
||||
|
||||
static void scr_os_constant(ScrDyn *o, const char *name, double value) {
|
||||
scr_dyn_obj_set(o, name, strlen(name), scr_dyn_new_num(value));
|
||||
ScrDynEntry *entry = &o->v.obj.entries[o->v.obj.len - 1];
|
||||
entry->writable = false;
|
||||
entry->configurable = false;
|
||||
size_t last = scr_dyn_obj_count(o) - 1;
|
||||
scr_dyn_obj_set_attrs_at(o, last, false, scr_dyn_obj_prop_at(o, last).enumerable, false);
|
||||
}
|
||||
#define SCR_OS_CONSTANT(o, name) scr_os_constant((o), #name, (double)(name))
|
||||
|
||||
@@ -1514,10 +1513,10 @@ ScrDyn *scr_node_constants(const ScrDyn *crypto_table) {
|
||||
scr_os_signal_constants(o);
|
||||
scr_fs_constants(o);
|
||||
if (crypto && crypto->kind == SCR_DYN_OBJ) {
|
||||
for (size_t i = 0; i < crypto->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &crypto->v.obj.entries[i];
|
||||
if (entry->accessor || !entry->value) continue;
|
||||
scr_dyn_obj_set(o, entry->key, entry->key_len, scr_dyn_retain(entry->value));
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(crypto); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(crypto, i);
|
||||
if (entry.accessor || !entry.value) continue;
|
||||
scr_dyn_obj_set(o, entry.key, entry.key_len, scr_dyn_retain(entry.value));
|
||||
}
|
||||
}
|
||||
scr_dyn_release(crypto);
|
||||
@@ -1718,10 +1717,12 @@ double scr_util_signal_exit_code(const ScrDyn *code) {
|
||||
ScrJsonBuf reason;
|
||||
scr_jb_init(&reason);
|
||||
scr_jb_puts(&reason, "must be one of: ");
|
||||
for (size_t i = 0; i < signals->v.obj.len; i++) {
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(signals); i++) {
|
||||
if (i > 0) scr_jb_puts(&reason, ", ");
|
||||
scr_jb_putc(&reason, '\'');
|
||||
scr_jb_write(&reason, signals->v.obj.entries[i].key, signals->v.obj.entries[i].key_len);
|
||||
size_t key_len;
|
||||
const char *key = scr_dyn_obj_key_at(signals, i, &key_len);
|
||||
scr_jb_write(&reason, key, key_len);
|
||||
scr_jb_putc(&reason, '\'');
|
||||
}
|
||||
ScrStr *text = scr_jb_finish(&reason);
|
||||
|
||||
@@ -278,8 +278,8 @@ static bool scr_pub_dyn_ok(const ScrDyn *d, const char **why) {
|
||||
*why = "Cannot publish an Object object";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < d->v.obj.len; i++)
|
||||
if (d->v.obj.entries[i].accessor) {
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++)
|
||||
if (scr_dyn_obj_prop_at(d, i).accessor) {
|
||||
*why = "Cannot publish an accessor property";
|
||||
return false;
|
||||
}
|
||||
@@ -325,9 +325,9 @@ void scr_pub_dyn_fn(void *v, ScrPub *ctx) {
|
||||
case SCR_DYN_ARR:
|
||||
case SCR_DYN_OBJ: {
|
||||
if (!scr_pub_dyn_ok(d, &why)) break;
|
||||
size_t n = d->kind == SCR_DYN_ARR ? d->v.arr.len : d->v.obj.len;
|
||||
size_t n = d->kind == SCR_DYN_ARR ? d->v.arr.len : scr_dyn_obj_count(d);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
ScrDyn *child = d->kind == SCR_DYN_ARR ? d->v.arr.items[i] : d->v.obj.entries[i].value;
|
||||
ScrDyn *child = d->kind == SCR_DYN_ARR ? d->v.arr.items[i] : scr_dyn_obj_value_at(d, i);
|
||||
if (child && child->rc != SIZE_MAX) SCR_PUB_ADD((uintptr_t)child);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -858,12 +858,12 @@ static void scr_rgn_walk_dyn(ScrRgnWalk *w, ScrDyn *d) {
|
||||
break;
|
||||
case SCR_DYN_OBJ:
|
||||
/* source_identity is owned through its access callback: not walked. */
|
||||
for (size_t i = 0; i < d->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &d->v.obj.entries[i];
|
||||
if (e->accessor) {
|
||||
scr_rgn_enter(w, e->getter, SCR_RGN_W_DYN, NULL);
|
||||
scr_rgn_enter(w, e->setter, SCR_RGN_W_DYN, NULL);
|
||||
} else scr_rgn_enter(w, e->value, SCR_RGN_W_DYN, NULL);
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(d); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(d, i);
|
||||
if (e.accessor) {
|
||||
scr_rgn_enter(w, e.getter, SCR_RGN_W_DYN, NULL);
|
||||
scr_rgn_enter(w, e.setter, SCR_RGN_W_DYN, NULL);
|
||||
} else scr_rgn_enter(w, e.value, SCR_RGN_W_DYN, NULL);
|
||||
}
|
||||
break;
|
||||
case SCR_DYN_FUNC: scr_rgn_enter(w, d->v.fn.clo, SCR_RGN_W_CLOSURE, NULL); break;
|
||||
|
||||
@@ -333,7 +333,7 @@ static void scr_dirent_init(void) {
|
||||
scr_dyn_obj_set(proto, methods[i].name, strlen(methods[i].name),
|
||||
scr_dyn_new_func(scr_closure_new(NULL, 0), methods[i].thunk, 0, "native:fs.Dirent",
|
||||
methods[i].name));
|
||||
proto->v.obj.entries[proto->v.obj.len - 1].enumerable = false;
|
||||
scr_dyn_obj_set_attrs_at(proto, scr_dyn_obj_count(proto) - 1, true, false, true);
|
||||
}
|
||||
ScrStr *desc = scr_str_new("type", 4);
|
||||
ScrSym *sym = scr_sym_new(desc);
|
||||
@@ -350,15 +350,14 @@ void scr_dyn_dirent_finish(ScrDyn *obj) {
|
||||
scr_dyn_region_store(obj, NULL); /* a prototype store (ScrDynRegion) */
|
||||
scr_dyn_release(obj->prototype);
|
||||
obj->prototype = scr_dyn_retain(scr_dirent_prototype);
|
||||
for (size_t i = 0; i < obj->v.obj.len; i++) {
|
||||
ScrDynEntry *ent = &obj->v.obj.entries[i];
|
||||
if (ent->key_len != 6 || memcmp(ent->key, "%dtype", 6) != 0) continue;
|
||||
ent->enumerable = false;
|
||||
size_t i = scr_dyn_obj_index_of(obj, "%dtype", 6);
|
||||
if (i != SIZE_MAX) {
|
||||
ScrDynProp ent = scr_dyn_obj_prop_at(obj, i);
|
||||
scr_dyn_obj_set_attrs_at(obj, i, ent.writable, false, ent.configurable);
|
||||
if (!obj->symbol_properties && !obj->symbol_keys)
|
||||
scr_dyn_symbol_init_own(obj, scr_dirent_type_key, scr_dirent_type_storage, ent->value);
|
||||
scr_dyn_symbol_init_own(obj, scr_dirent_type_key, scr_dirent_type_storage, ent.value);
|
||||
else
|
||||
scr_dyn_symbol_key_set(obj, scr_dirent_type_key, ent->value);
|
||||
break;
|
||||
scr_dyn_symbol_key_set(obj, scr_dirent_type_key, ent.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2597,21 +2597,21 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt
|
||||
}
|
||||
if (!scr_tls_opts_validate(opts)) return false; /* Node's typed errors first */
|
||||
bool ok = true;
|
||||
for (size_t i = 0; ok && i < opts->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &opts->v.obj.entries[i];
|
||||
const ScrDyn *v = e->value;
|
||||
for (size_t i = 0; ok && i < scr_dyn_obj_count(opts); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(opts, i);
|
||||
const ScrDyn *v = e.value;
|
||||
if (v->kind == SCR_DYN_UNDEF) continue; /* an undefined member reads as absent, like Node */
|
||||
if (strcmp(e->key, "cert") == 0 || strcmp(e->key, "key") == 0) {
|
||||
if (strcmp(e.key, "cert") == 0 || strcmp(e.key, "key") == 0) {
|
||||
char what[96];
|
||||
snprintf(what, sizeof what, "a %s '%s' option", api, e->key);
|
||||
snprintf(what, sizeof what, "a %s '%s' option", api, e.key);
|
||||
ScrBytes *b = scr_tls_pem_dyn(v, what, false);
|
||||
if (b == NULL) { ok = false; break; }
|
||||
ScrBytes **slot = e->key[0] == 'c' ? cert_out : key_out;
|
||||
ScrBytes **slot = e.key[0] == 'c' ? cert_out : key_out;
|
||||
scr_bytes_release(*slot);
|
||||
*slot = b;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "ca") == 0) {
|
||||
if (strcmp(e.key, "ca") == 0) {
|
||||
/* the server's `ca` verifies client certificates and completes the
|
||||
* server's own chain (scr_tls_srv_client_auth); a walk without
|
||||
* client certificates drops it */
|
||||
@@ -2623,7 +2623,7 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "requestCert") == 0) {
|
||||
if (strcmp(e.key, "requestCert") == 0) {
|
||||
if (auth != NULL) {
|
||||
auth->request = scr_tls_dyn_truthy(v);
|
||||
continue;
|
||||
@@ -2635,22 +2635,22 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "rejectUnauthorized") == 0) {
|
||||
if (strcmp(e.key, "rejectUnauthorized") == 0) {
|
||||
if (auth != NULL) auth->reject = scr_tls_dyn_not_false(v);
|
||||
continue; /* without client certificates it has no effect */
|
||||
}
|
||||
if (server_ok && (strcmp(e->key, "ALPNProtocols") == 0 || strcmp(e->key, "minVersion") == 0 ||
|
||||
strcmp(e->key, "maxVersion") == 0))
|
||||
if (server_ok && (strcmp(e.key, "ALPNProtocols") == 0 || strcmp(e.key, "minVersion") == 0 ||
|
||||
strcmp(e.key, "maxVersion") == 0))
|
||||
continue;
|
||||
if (strcmp(e->key, "SNICallback") == 0) {
|
||||
if (strcmp(e.key, "SNICallback") == 0) {
|
||||
scr_tls_opt_fence(api, "SNICallback",
|
||||
"SNICallback lowers only on http2.createSecureServer({ allowHTTP1: true, ... }) with a literal options object");
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
for (size_t k = 0; SCR_TLS_SRV_FENCED_OPTIONS[k] != NULL; k++) {
|
||||
if (strcmp(e->key, SCR_TLS_SRV_FENCED_OPTIONS[k]) == 0) {
|
||||
scr_tls_opt_fence(api, e->key,
|
||||
if (strcmp(e.key, SCR_TLS_SRV_FENCED_OPTIONS[k]) == 0) {
|
||||
scr_tls_opt_fence(api, e.key,
|
||||
"cert and key (PEM strings or Buffers) are the honestly-implemented members of a runtime options record");
|
||||
ok = false;
|
||||
break;
|
||||
@@ -2957,17 +2957,17 @@ static const char *const SCR_TLS_WRAP_FENCED_OPTIONS[] = {
|
||||
* certificates are not modeled), SNICallback and ALPNCallback fence.
|
||||
* False with the exception pending. */
|
||||
static bool scr_tls_wrap_socket_opts_check(const ScrDyn *record, const char *api) {
|
||||
for (size_t i = 0; record != NULL && i < record->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &record->v.obj.entries[i];
|
||||
if (e->value->kind == SCR_DYN_UNDEF) continue;
|
||||
if (strcmp(e->key, "requestCert") == 0) {
|
||||
if (!scr_tls_dyn_truthy(e->value)) continue;
|
||||
for (size_t i = 0; record != NULL && i < scr_dyn_obj_count(record); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(record, i);
|
||||
if (e.value->kind == SCR_DYN_UNDEF) continue;
|
||||
if (strcmp(e.key, "requestCert") == 0) {
|
||||
if (!scr_tls_dyn_truthy(e.value)) continue;
|
||||
scr_tls_opt_fence(api, "requestCert",
|
||||
"requestCert lowers with cert and key options, not beside a secureContext");
|
||||
return false;
|
||||
}
|
||||
if (strcmp(e->key, "SNICallback") == 0 || strcmp(e->key, "ALPNCallback") == 0) {
|
||||
scr_tls_opt_fence(api, e->key,
|
||||
if (strcmp(e.key, "SNICallback") == 0 || strcmp(e.key, "ALPNCallback") == 0) {
|
||||
scr_tls_opt_fence(api, e.key,
|
||||
"isServer, cert, key, secureContext, ALPNProtocols, minVersion and maxVersion are the implemented members");
|
||||
return false;
|
||||
}
|
||||
@@ -2980,21 +2980,21 @@ ScrNetSocket *scr_tls_wrap_socket(ScrNetSocket *raw, const ScrDyn *opts /*borrow
|
||||
static const char api[] = "new tls.TLSSocket";
|
||||
bool is_server = false;
|
||||
const ScrDyn *record = opts != NULL && opts->kind == SCR_DYN_OBJ ? opts : NULL;
|
||||
for (size_t i = 0; record != NULL && i < record->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &record->v.obj.entries[i];
|
||||
if (e->value->kind == SCR_DYN_UNDEF) continue;
|
||||
if (strcmp(e->key, "isServer") == 0) {
|
||||
is_server = scr_tls_dyn_truthy(e->value);
|
||||
for (size_t i = 0; record != NULL && i < scr_dyn_obj_count(record); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(record, i);
|
||||
if (e.value->kind == SCR_DYN_UNDEF) continue;
|
||||
if (strcmp(e.key, "isServer") == 0) {
|
||||
is_server = scr_tls_dyn_truthy(e.value);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "secureContext") == 0) {
|
||||
if (strcmp(e.key, "secureContext") == 0) {
|
||||
scr_tls_opt_fence(api, "secureContext",
|
||||
"secureContext lowers as a member of an options object literal");
|
||||
return NULL;
|
||||
}
|
||||
for (size_t k = 0; SCR_TLS_WRAP_FENCED_OPTIONS[k] != NULL; k++) {
|
||||
if (strcmp(e->key, SCR_TLS_WRAP_FENCED_OPTIONS[k]) == 0) {
|
||||
scr_tls_opt_fence(api, e->key,
|
||||
if (strcmp(e.key, SCR_TLS_WRAP_FENCED_OPTIONS[k]) == 0) {
|
||||
scr_tls_opt_fence(api, e.key,
|
||||
"isServer, cert, key, secureContext, ALPNProtocols, minVersion and maxVersion are the implemented members");
|
||||
return NULL;
|
||||
}
|
||||
@@ -3267,10 +3267,10 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed,
|
||||
/* createSecureContext's version checks come before its other options
|
||||
* (Node's SecureContext constructor). */
|
||||
if (ok && !scr_tls_versions_dyn(opts, &min_version, &max_version)) ok = false;
|
||||
for (size_t i = 0; ok && i < opts->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &opts->v.obj.entries[i];
|
||||
const ScrDyn *v = e->value;
|
||||
if (strcmp(e->key, "checkServerIdentity") == 0) {
|
||||
for (size_t i = 0; ok && i < scr_dyn_obj_count(opts); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(opts, i);
|
||||
const ScrDyn *v = e.value;
|
||||
if (strcmp(e.key, "checkServerIdentity") == 0) {
|
||||
/* Node spreads user options over the defaults, so a PRESENT key
|
||||
* replaces the builtin verifier even when its value is undefined
|
||||
* — validateFunction then throws for anything non-callable. A
|
||||
@@ -3287,7 +3287,7 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed,
|
||||
continue;
|
||||
}
|
||||
if (v->kind == SCR_DYN_UNDEF) continue;
|
||||
if (strcmp(e->key, "port") == 0) {
|
||||
if (strcmp(e.key, "port") == 0) {
|
||||
if (port >= 0) continue; /* the argument form wins, like Node */
|
||||
if (v->kind == SCR_DYN_NUM) port = v->v.num;
|
||||
else if (v->kind == SCR_DYN_STR) port = strtod(v->v.str->data, NULL); /* Node coerces numeric strings */
|
||||
@@ -3297,7 +3297,7 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "host") == 0) {
|
||||
if (strcmp(e.key, "host") == 0) {
|
||||
if (v->kind == SCR_DYN_STR) opt_host = v->v.str;
|
||||
else {
|
||||
scr_dyn_arg_type_fail("options.host", "of type string", v);
|
||||
@@ -3305,34 +3305,34 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "rejectUnauthorized") == 0) {
|
||||
if (strcmp(e.key, "rejectUnauthorized") == 0) {
|
||||
reject = scr_tls_dyn_not_false(v);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "ca") == 0) {
|
||||
if (strcmp(e.key, "ca") == 0) {
|
||||
scr_bytes_release(ca);
|
||||
if (!scr_tls_ca_dyn(v, "a tls.connect 'ca' option", &ca)) ok = false;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "cert") == 0 || strcmp(e->key, "key") == 0) {
|
||||
ScrBytes **slot = e->key[0] == 'c' ? &own_cert : &own_key;
|
||||
if (strcmp(e.key, "cert") == 0 || strcmp(e.key, "key") == 0) {
|
||||
ScrBytes **slot = e.key[0] == 'c' ? &own_cert : &own_key;
|
||||
scr_bytes_release(*slot);
|
||||
*slot = scr_tls_pem_dyn(v, e->key[0] == 'c' ? "a tls.connect 'cert' option" : "a tls.connect 'key' option",
|
||||
*slot = scr_tls_pem_dyn(v, e.key[0] == 'c' ? "a tls.connect 'cert' option" : "a tls.connect 'key' option",
|
||||
false);
|
||||
if (*slot == NULL) ok = false;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "ALPNProtocols") == 0) {
|
||||
if (strcmp(e.key, "ALPNProtocols") == 0) {
|
||||
alpn_value = v; /* converted after the context options, as TLSSocket does */
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "minVersion") == 0 || strcmp(e->key, "maxVersion") == 0) continue;
|
||||
if (strcmp(e->key, "timeout") == 0) {
|
||||
if (strcmp(e.key, "minVersion") == 0 || strcmp(e.key, "maxVersion") == 0) continue;
|
||||
if (strcmp(e.key, "timeout") == 0) {
|
||||
/* `if (options.timeout) tlssock.setTimeout(options.timeout)` */
|
||||
timeout_value = scr_tls_dyn_truthy(v) ? v : NULL;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "socket") == 0) {
|
||||
if (strcmp(e.key, "socket") == 0) {
|
||||
if (v->kind == SCR_DYN_HANDLE && v->v.handle.tag == SCR_DYNH_NET_SOCKET) {
|
||||
wrap = (ScrNetSocket *)v->v.handle.ptr;
|
||||
} else {
|
||||
@@ -3341,7 +3341,7 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(e->key, "servername") == 0) {
|
||||
if (strcmp(e.key, "servername") == 0) {
|
||||
if (v->kind == SCR_DYN_STR) servername = v->v.str;
|
||||
else {
|
||||
scr_dyn_arg_type_fail("options.servername", "of type string", v);
|
||||
@@ -3350,8 +3350,8 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed,
|
||||
continue;
|
||||
}
|
||||
for (size_t k = 0; SCR_TLS_CONNECT_FENCED_OPTIONS[k] != NULL; k++) {
|
||||
if (strcmp(e->key, SCR_TLS_CONNECT_FENCED_OPTIONS[k]) == 0) {
|
||||
scr_tls_opt_fence("tls.connect", e->key,
|
||||
if (strcmp(e.key, SCR_TLS_CONNECT_FENCED_OPTIONS[k]) == 0) {
|
||||
scr_tls_opt_fence("tls.connect", e.key,
|
||||
"port/host/socket/rejectUnauthorized/ca/servername/ALPNProtocols/minVersion/maxVersion/timeout are the implemented members of a runtime options record");
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
@@ -26,15 +26,15 @@ static bool util_deep_equal(const ScrDyn *, const ScrDyn *, bool, const ScrDeepF
|
||||
|
||||
static size_t util_deep_key_count(const ScrDyn *table) {
|
||||
size_t count = 0;
|
||||
if (table) for (size_t i = 0; i < table->v.obj.len; i++) count += table->v.obj.entries[i].enumerable;
|
||||
if (table) for (size_t i = 0; i < scr_dyn_obj_count(table); i++) count += scr_dyn_obj_prop_at(table, i).enumerable;
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool util_deep_same_keys(const ScrDyn *a, const ScrDyn *b) {
|
||||
if (util_deep_key_count(a) != util_deep_key_count(b)) return false;
|
||||
if (a) for (size_t i = 0; i < a->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &a->v.obj.entries[i];
|
||||
if (e->enumerable && (!b || !scr_dyn_obj_enumerable(b, e->key, e->key_len))) return false;
|
||||
if (a) for (size_t i = 0; i < scr_dyn_obj_count(a); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(a, i);
|
||||
if (e.enumerable && (!b || !scr_dyn_obj_enumerable(b, e.key, e.key_len))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -42,14 +42,14 @@ static bool util_deep_same_keys(const ScrDyn *a, const ScrDyn *b) {
|
||||
static ScrDyn *util_deep_constructor(const ScrDyn *value) {
|
||||
for (const ScrDyn *p = value; p; p = p->prototype) {
|
||||
const ScrDyn *table = p->kind == SCR_DYN_OBJ ? p : p->kind == SCR_DYN_ARR ? p->v.arr.properties : NULL;
|
||||
if (table) for (size_t i = 0; i < table->v.obj.len; i++) {
|
||||
const ScrDynEntry *e = &table->v.obj.entries[i];
|
||||
if (e->key_len == 11 && !memcmp(e->key, "constructor", 11)) {
|
||||
if (e->accessor) { util_deep_refused("native accessor properties"); return NULL; }
|
||||
if (p == value && e->value->kind == SCR_DYN_FUNC) {
|
||||
if (table) for (size_t i = 0; i < scr_dyn_obj_count(table); i++) {
|
||||
ScrDynProp e = scr_dyn_obj_prop_at(table, i);
|
||||
if (e.key_len == 11 && !memcmp(e.key, "constructor", 11)) {
|
||||
if (e.accessor) { util_deep_refused("native accessor properties"); return NULL; }
|
||||
if (p == value && e.value->kind == SCR_DYN_FUNC) {
|
||||
util_deep_refused("native own constructor functions"); return NULL;
|
||||
}
|
||||
return scr_dyn_retain(e->value);
|
||||
return scr_dyn_retain(e.value);
|
||||
}
|
||||
}
|
||||
if (!p->prototype) {
|
||||
@@ -77,8 +77,8 @@ static ScrDyn *util_deep_tag(const ScrDyn *value) {
|
||||
if (!scr_dyn_same_value(keys->v.arr.items[i], key)) continue;
|
||||
// General native getters retain an explicit boundary, including
|
||||
// non-enumerable Symbol.toStringTag descriptors read by Node.
|
||||
for (size_t j = 0; j < p->symbol_properties->v.obj.len; j++) {
|
||||
if (p->symbol_properties->v.obj.entries[j].accessor) {
|
||||
for (size_t j = 0; j < scr_dyn_obj_count(p->symbol_properties); j++) {
|
||||
if (scr_dyn_obj_prop_at(p->symbol_properties, j).accessor) {
|
||||
scr_dyn_release(key); util_deep_refused("native accessor properties"); return NULL;
|
||||
}
|
||||
}
|
||||
@@ -95,20 +95,21 @@ static bool util_deep_properties(const ScrDyn *a, const ScrDyn *b, bool skip,
|
||||
const ScrDeepFrame *frame) {
|
||||
if (util_deep_key_count(a) != util_deep_key_count(b)) return false;
|
||||
if (!a) return true;
|
||||
for (size_t i = 0; i < a->v.obj.len; i++) {
|
||||
const ScrDynEntry *x = &a->v.obj.entries[i];
|
||||
if (!x->enumerable) continue;
|
||||
const ScrDynEntry *y = NULL;
|
||||
if (b) for (size_t j = 0; j < b->v.obj.len; j++) {
|
||||
const ScrDynEntry *candidate = &b->v.obj.entries[j];
|
||||
if (candidate->enumerable && candidate->key_len == x->key_len &&
|
||||
!memcmp(candidate->key, x->key, x->key_len)) { y = candidate; break; }
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(a); i++) {
|
||||
ScrDynProp x = scr_dyn_obj_prop_at(a, i);
|
||||
if (!x.enumerable) continue;
|
||||
ScrDynProp yp;
|
||||
const ScrDynProp *y = NULL;
|
||||
if (b) for (size_t j = 0; j < scr_dyn_obj_count(b); j++) {
|
||||
ScrDynProp candidate = scr_dyn_obj_prop_at(b, j);
|
||||
if (candidate.enumerable && candidate.key_len == x.key_len &&
|
||||
!memcmp(candidate.key, x.key, x.key_len)) { yp = candidate; y = &yp; break; }
|
||||
}
|
||||
if (!y) return false;
|
||||
if (x->accessor || y->accessor) return util_deep_refused("native accessor properties");
|
||||
if (x.accessor || y->accessor) return util_deep_refused("native accessor properties");
|
||||
// Materializing a cyclic typed child can refresh its ancestor table.
|
||||
// Retain the values before that refresh replaces descriptor storage.
|
||||
ScrDyn *xv = scr_dyn_retain(x->value), *yv = scr_dyn_retain(y->value);
|
||||
ScrDyn *xv = scr_dyn_retain(x.value), *yv = scr_dyn_retain(y->value);
|
||||
bool same = util_deep_equal(xv, yv, skip, frame);
|
||||
scr_dyn_release(xv); scr_dyn_release(yv);
|
||||
if (!same) return false;
|
||||
|
||||
@@ -1385,17 +1385,17 @@ static ScrDyn *scr_worker_new_options(double root, ScrStr *filename, ScrDyn *opt
|
||||
scr_dyn_arg_type_fail("options", "object", options);
|
||||
return NULL;
|
||||
}
|
||||
for (size_t i = 0; i < options->v.obj.len; i++) {
|
||||
const ScrDynEntry *entry = &options->v.obj.entries[i];
|
||||
if (entry->accessor) return scr_worker_refusal("Worker option accessors are not supported yet");
|
||||
if (entry->key_len == 10 && !memcmp(entry->key, "workerData", 10)) data = entry->value;
|
||||
else if (entry->key_len == 4 && !memcmp(entry->key, "argv", 4)) argv = entry->value;
|
||||
else if (entry->key_len == 12 && !memcmp(entry->key, "transferList", 12)) transfer_list = entry->value;
|
||||
else if (entry->key_len == 14 && !memcmp(entry->key, "resourceLimits", 14)) limits = entry->value;
|
||||
else if (entry->key_len == 4 && !memcmp(entry->key, "name", 4)) name = entry->value;
|
||||
else if (entry->key_len == 6 && !memcmp(entry->key, "stdout", 6)) capture |= scr_dyn_truthy(entry->value) ? 1 : 0;
|
||||
else if (entry->key_len == 6 && !memcmp(entry->key, "stderr", 6)) capture |= scr_dyn_truthy(entry->value) ? 2 : 0;
|
||||
else if (entry->key_len == 5 && !memcmp(entry->key, "stdin", 5)) capture |= scr_dyn_truthy(entry->value) ? 4 : 0;
|
||||
for (size_t i = 0; i < scr_dyn_obj_count(options); i++) {
|
||||
ScrDynProp entry = scr_dyn_obj_prop_at(options, i);
|
||||
if (entry.accessor) return scr_worker_refusal("Worker option accessors are not supported yet");
|
||||
if (entry.key_len == 10 && !memcmp(entry.key, "workerData", 10)) data = entry.value;
|
||||
else if (entry.key_len == 4 && !memcmp(entry.key, "argv", 4)) argv = entry.value;
|
||||
else if (entry.key_len == 12 && !memcmp(entry.key, "transferList", 12)) transfer_list = entry.value;
|
||||
else if (entry.key_len == 14 && !memcmp(entry.key, "resourceLimits", 14)) limits = entry.value;
|
||||
else if (entry.key_len == 4 && !memcmp(entry.key, "name", 4)) name = entry.value;
|
||||
else if (entry.key_len == 6 && !memcmp(entry.key, "stdout", 6)) capture |= scr_dyn_truthy(entry.value) ? 1 : 0;
|
||||
else if (entry.key_len == 6 && !memcmp(entry.key, "stderr", 6)) capture |= scr_dyn_truthy(entry.value) ? 2 : 0;
|
||||
else if (entry.key_len == 5 && !memcmp(entry.key, "stdin", 5)) capture |= scr_dyn_truthy(entry.value) ? 4 : 0;
|
||||
else return scr_worker_refusal("This Worker constructor option is not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const src = join(import.meta.dirname, "..", "src");
|
||||
|
||||
/* Ordinary objects keep their properties behind the object core: units
|
||||
* outside it read and adjust them through the scr_dyn.h own-property
|
||||
* accessors (scr_dyn_obj_count, scr_dyn_obj_prop_at, ...), so the core can
|
||||
* change how it stores them. */
|
||||
const CORE = new Set(["scr_json.c", "scr_js_object.c", "scr_dyn.h"]);
|
||||
|
||||
test("only the object core reads ordinary objects' entry storage", () => {
|
||||
const offenders: string[] = [];
|
||||
for (const name of readdirSync(src)) {
|
||||
if (!/\.(c|h)$/.test(name) || name.endsWith(".test.c") || CORE.has(name)) continue;
|
||||
const lines = readFileSync(join(src, name), "utf8").split("\n");
|
||||
lines.forEach((line, i) => {
|
||||
if (/\bv\.obj\.(entries|len)\b/.test(line)) offenders.push(`${name}:${i + 1}: ${line.trim()}`);
|
||||
});
|
||||
}
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
Reference in New Issue
Block a user