rm for ... in

This commit is contained in:
2026-01-19 18:56:54 -06:00
parent 9b3891c126
commit ff18682485
17 changed files with 72 additions and 575 deletions

View File

@@ -441,11 +441,10 @@ function run_benchmarks(package_name, specific_bench) {
if (is_function(bench_mod)) {
benches.push({name: 'main', fn: bench_mod})
} else if (is_object(bench_mod)) {
for (var k in bench_mod) {
if (is_function(bench_mod[k])) {
arrfor(array(bench_mod), function(k) {
if (is_function(bench_mod[k]))
benches.push({name: k, fn: bench_mod[k]})
}
}
})
}
if (length(benches) > 0) {
@@ -474,7 +473,7 @@ function run_benchmarks(package_name, specific_bench) {
file_result.benchmarks.push(error_result)
pkg_result.total++
}
}
})
}
} catch (e) {
log.console(` Error loading ${f}: ${e}`)

View File

@@ -7,9 +7,9 @@ function fib(n) {
var now = time.number()
var arr = [1,2,3,4,5]
for (var i in arr) {
arrfor(arr, function(i) {
log.console(fib(28))
}
})
log.console(`elapsed: ${time.number()-now}`)

View File

@@ -84,7 +84,7 @@ function format_value(val) {
// Print configuration tree recursively
function print_config(obj, prefix = '') {
for (var key in obj) {
arrfor(array(obj), function(key) {
var val = obj[key]
var full_key = prefix ? prefix + '.' + key : key
@@ -92,7 +92,7 @@ function print_config(obj, prefix = '') {
print_config(val, full_key)
else
log.console(full_key + ' = ' + format_value(val))
}
})
}
// Main command handling

View File

@@ -94,12 +94,12 @@ function gather_graph(locator, visited) {
try {
var deps = pkg.dependencies(locator)
if (deps) {
for (var alias in deps) {
arrfor(array(deps), function(alias) {
var dep_locator = deps[alias]
add_node(dep_locator)
edges.push({ from: locator, to: dep_locator, alias: alias })
gather_graph(dep_locator, visited)
}
})
}
} catch (e) {
// Package might not have dependencies
@@ -193,7 +193,7 @@ if (format == 'tree') {
log.console("")
// Node definitions
for (var id in nodes) {
arrfor(array(nodes), function(id) {
var node = nodes[id]
var label = id
if (node.commit) label += "\\n@" + node.commit
@@ -204,7 +204,7 @@ if (format == 'tree') {
// Safe node ID for dot
var safe_id = replace(id, /[^a-zA-Z0-9]/g, '_')
log.console(' ' + safe_id + ' [' + attrs + '];')
}
})
log.console("")
@@ -224,9 +224,9 @@ if (format == 'tree') {
edges: []
}
for (var id in nodes) {
arrfor(array(nodes), function(id) {
output.nodes.push(nodes[id])
}
})
output.edges = edges

View File

@@ -119,10 +119,10 @@ function gather_packages(pkg_locator) {
var deps = pkg.dependencies(pkg_locator)
if (deps) {
for (var alias in deps) {
arrfor(array(deps), function(alias) {
var dep_locator = deps[alias]
gather_packages(dep_locator)
}
})
}
} catch (e) {
// Package might not have dependencies or cell.toml issue

View File

@@ -53,6 +53,8 @@ globalThis.ends_with = function(str, suffix) {
return search(str, suffix, -length(suffix)) != null
}
var js = use_embed('js')
var fd = use_embed('fd')
@@ -410,7 +412,9 @@ function handle_host(e) {
break
case "disconnect":
peer_queue.delete(e.peer)
for (var id in peers) if (peers[id] == e.peer) delete peers[id]
arrfor(array(peers), function(id) {
if (peers[id] == e.peer) delete peers[id]
})
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port)
break
case "receive":
@@ -425,11 +429,11 @@ function handle_host(e) {
obj[ACTORDATA].address = e.peer.address
obj[ACTORDATA].port = e.peer.port
}
for (var key in obj) {
arrfor(array(obj), function(key) {
if (object.has(obj, key)) {
populate_actor_addresses(obj[key])
}
}
})
}
if (data.data) populate_actor_addresses(data.data)
turn(data)

View File

@@ -1,4 +1,5 @@
var toml = use('toml')
var json = use('json')
var fd = use('fd')
var http = use('http')
@@ -7,6 +8,7 @@ var time = use('time')
var js = use('js')
var crypto = use('crypto')
var blob = use('blob')
var pkg_tools = use('package')
var os = use('os')
var link = use('link')
@@ -559,14 +561,14 @@ Shop.open_package_dylib = function(pkg) {
var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content)
if (cfg.dependencies) {
for (var alias in cfg.dependencies) {
arrfor(array(cfg.dependencies), function(alias) {
var dep_pkg = cfg.dependencies[alias]
try {
Shop.open_package_dylib(dep_pkg)
} catch (dep_e) {
// Dependency dylib load failed, continue with others
}
}
})
}
} catch (e) {
// Error reading toml, continue
@@ -1194,12 +1196,14 @@ Shop.module_reload = function(path, package) {
var old = use_cache[cache_key]
var newmod = get_module(path, package)
for (var i in newmod)
arrfor(array(newmod), function(i) {
old[i] = newmod[i]
})
for (var i in old)
arrfor(array(old), function(i) {
if (!(i in newmod))
old[i] = null
})
}
function get_package_scripts(package)

View File

@@ -35,10 +35,10 @@ var cmd = args[0]
if (cmd == 'list') {
var links = link.load()
var count = 0
for (var k in links) {
arrfor(array(links), function(k) {
log.console(k + " -> " + links[k])
count++
}
})
if (count == 0) log.console("No links.")
} else if (cmd == 'sync') {

35
link.cm
View File

@@ -120,12 +120,12 @@ Link.add = function(canonical, target, shop) {
var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content)
if (cfg.dependencies) {
for (var alias in cfg.dependencies) {
arrfor(array(cfg.dependencies), function(alias) {
var dep_locator = cfg.dependencies[alias]
// Skip local dependencies that don't exist
if (starts_with(dep_locator, '/') && !fd.is_dir(dep_locator)) {
log.console(" Skipping missing local dependency: " + dep_locator)
continue
return
}
// Install the dependency if not already in shop
try {
@@ -135,7 +135,7 @@ Link.add = function(canonical, target, shop) {
log.console(` Warning: Could not install dependency ${dep_locator}: ${e.message}`)
log.error(e)
}
}
})
}
} catch (e) {
log.console(` Warning: Could not read dependencies from ${toml_path}`)
@@ -166,12 +166,12 @@ Link.remove = function(canonical) {
Link.clear = function() {
// Remove all symlinks first
var links = Link.load()
for (var canonical in links) {
arrfor(array(links), function(canonical) {
var target_dir = get_package_abs_dir(canonical)
if (fd.is_link(target_dir)) {
fd.unlink(target_dir)
}
}
})
Link.save({})
log.console("Cleared all links")
@@ -216,18 +216,18 @@ Link.sync_all = function(shop) {
var count = 0
var errors = []
for (var canonical in links) {
arrfor(array(links), function(canonical) {
var target = links[canonical]
try {
// Validate target exists
var link_target = resolve_link_target(target)
if (!fd.is_dir(link_target)) {
errors.push(canonical + ': target ' + link_target + ' does not exist')
continue
return
}
if (!fd.is_file(link_target + '/cell.toml')) {
errors.push(canonical + ': target ' + link_target + ' is not a valid package')
continue
return
}
Link.sync_one(canonical, target, shop)
@@ -238,11 +238,11 @@ Link.sync_all = function(shop) {
var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content)
if (cfg.dependencies) {
for (var alias in cfg.dependencies) {
arrfor(array(cfg.dependencies), function(alias) {
var dep_locator = cfg.dependencies[alias]
// Skip local dependencies that don't exist
if (starts_with(dep_locator, '/') && !fd.is_dir(dep_locator)) {
continue
return
}
// Install the dependency if not already in shop
try {
@@ -251,7 +251,7 @@ Link.sync_all = function(shop) {
} catch (e) {
// Silently continue - dependency may already be installed
}
}
})
}
} catch (e) {
// Could not read dependencies - continue anyway
@@ -261,7 +261,7 @@ Link.sync_all = function(shop) {
} catch (e) {
errors.push(canonical + ': ' + e.message)
}
}
})
return { synced: count, errors: errors }
}
@@ -282,12 +282,11 @@ Link.get_target = function(canonical) {
// Returns null if no package links to this target
Link.get_origin = function(target) {
var links = Link.load()
for (var origin in links) {
if (links[origin] == target) {
return origin
}
}
return null
var found = null
arrfor(array(links), function(origin) {
if (links[origin] == target) found = origin
})
return found
}
return Link

View File

@@ -58,8 +58,7 @@ function print_deps(ctx, indent) {
return
}
var aliases = []
for (var k in deps) aliases.push(k)
var aliases = array(deps)
aliases = sort(aliases)
if (length(aliases) == 0) {

View File

@@ -1,5 +1,4 @@
var package = {}
var fd = use('fd')
var toml = use('toml')
var json = use('json')
@@ -76,11 +75,11 @@ package.find_alias = function(name, locator)
var config = package.load_config(name)
if (!config.dependencies) return null
for (var alias in config.dependencies)
if (config.dependencies[alias] == locator)
return alias
return null
var found = null
arrfor(array(config.dependencies), function(alias) {
if (config.dependencies[alias] == locator) found = alias
})
return found
}
package.alias_to_package = function(name, alias)
@@ -177,13 +176,13 @@ package.gather_dependencies = function(name)
var deps = package.dependencies(pkg_name)
if (!deps) return
for (var alias in deps) {
arrfor(array(deps), function(alias) {
var locator = deps[alias]
if (!all_deps[locator]) {
all_deps[locator] = true
gather_recursive(locator)
}
}
})
}
gather_recursive(name)
@@ -319,7 +318,7 @@ package.get_c_files = function(name, target, exclude_main) {
// Select appropriate file from each group
var result = []
for (var key in groups) {
arrfor(array(groups), function(key) {
var group = groups[key]
var selected = null
@@ -334,11 +333,11 @@ package.get_c_files = function(name, target, exclude_main) {
// Skip main.c if requested
if (exclude_main) {
var basename = fd.basename(selected)
if (basename == 'main.c' || starts_with(basename, 'main_')) continue
if (basename == 'main.c' || starts_with(basename, 'main_')) return
}
result.push(selected)
}
}
})
return result
}

View File

@@ -92,10 +92,10 @@ function gather_deps(locator, depth) {
try {
var deps = pkg.dependencies(locator)
if (deps) {
for (var alias in deps) {
arrfor(array(deps), function(alias) {
var dep_locator = deps[alias]
gather_deps(dep_locator, depth + 1)
}
})
}
} catch (e) {
// Package might not have dependencies
@@ -110,11 +110,7 @@ log.console("Target: " + target_triple)
log.console("")
// Sort by depth then alphabetically
var sorted = []
for (var locator in all_deps) {
sorted.push({ locator: locator, depth: all_deps[locator].depth })
}
var sorted = array(array(all_deps), function(locator) { return { locator: locator, depth: all_deps[locator].depth } })
sorted = sort(sorted, "locator")
sorted = sort(sorted, "depth")

View File

@@ -179,9 +179,6 @@ DEF( make_arg_ref, 7, 0, 2, atom_u16)
DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
DEF( make_var_ref, 5, 0, 2, atom)
DEF( for_in_start, 1, 1, 1, none)
DEF( for_in_next, 1, 1, 3, none)
/* arithmetic/logic operations */
DEF( neg, 1, 1, 1, none)
DEF( plus, 1, 1, 1, none)

View File

@@ -168,7 +168,6 @@ enum {
JS_CLASS_BYTECODE_FUNCTION, /* u.func */
JS_CLASS_BOUND_FUNCTION, /* u.bound_function */
JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */
JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */
JS_CLASS_REGEXP, /* u.regexp */
JS_CLASS_FINALIZATION_REGISTRY,
JS_CLASS_BLOB, /* u.opaque (blob *) */
@@ -682,15 +681,6 @@ typedef struct JSBoundFunction {
JSValue argv[0];
} JSBoundFunction;
typedef struct JSForInIterator {
JSValue obj;
uint32_t idx;
uint32_t atom_count;
uint8_t in_prototype_chain;
uint8_t is_array;
JSPropertyEnum *tab_atom; /* is_array = FALSE */
} JSForInIterator;
/* Used by js_object_keys and related functions */
typedef enum JSIteratorKindEnum {
JS_ITERATOR_KIND_KEY,
@@ -823,7 +813,6 @@ struct JSObject {
void *opaque;
struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
struct JSFunctionBytecode *function_bytecode;
JSVarRef **var_refs;
@@ -949,9 +938,6 @@ static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
#define HINT_STRING 0
@@ -1240,7 +1226,6 @@ static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
{ JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
{ JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
{ JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */
{ JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */
};
@@ -5316,30 +5301,6 @@ static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
JS_MarkValue(rt, bf->argv[i], mark_func);
}
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSForInIterator *it = p->u.for_in_iterator;
int i;
JS_FreeValueRT(rt, it->obj);
if (!it->is_array) {
for(i = 0; i < it->atom_count; i++) {
JS_FreeAtomRT(rt, it->tab_atom[i].atom);
}
js_free_rt(rt, it->tab_atom);
}
js_free_rt(rt, it);
}
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSForInIterator *it = p->u.for_in_iterator;
JS_MarkValue(rt, it->obj, mark_func);
}
static void free_object(JSRuntime *rt, JSObject *p)
{
int i;
@@ -5955,16 +5916,6 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
}
}
break;
case JS_CLASS_FOR_IN_ITERATOR: /* u.for_in_iterator */
{
JSForInIterator *it = p->u.for_in_iterator;
if (it) {
compute_value_size(it->obj, hp);
s->memory_used_count += 1;
s->memory_used_size += sizeof(*it);
}
}
break;
case JS_CLASS_REGEXP: /* u.regexp */
compute_jsstring_size(p->u.regexp.pattern, hp);
compute_jsstring_size(p->u.regexp.bytecode, hp);
@@ -11534,236 +11485,6 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *
return val;
}
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
{
JSObject *p, *p1;
JSPropertyEnum *tab_atom;
int i;
JSValue enum_obj;
JSForInIterator *it;
uint32_t tag, tab_atom_count;
tag = JS_VALUE_GET_TAG(obj);
if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL) {
obj = JS_ToObjectFree(ctx, obj);
}
it = js_malloc(ctx, sizeof(*it));
if (!it) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
if (JS_IsException(enum_obj)) {
js_free(ctx, it);
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
it->is_array = FALSE;
it->obj = obj;
it->idx = 0;
it->tab_atom = NULL;
it->atom_count = 0;
it->in_prototype_chain = FALSE;
p1 = JS_VALUE_GET_OBJ(enum_obj);
p1->u.for_in_iterator = it;
if (tag == JS_TAG_NULL)
return enum_obj;
p = JS_VALUE_GET_OBJ(obj);
if (p->fast_array) {
JSShape *sh;
JSShapeProperty *prs;
/* check that there are no enumerable normal fields */
sh = p->shape;
for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
if (prs->flags & JS_PROP_ENUMERABLE)
goto normal_case;
}
/* for fast arrays, we only store the number of elements */
it->is_array = TRUE;
it->atom_count = p->u.array.count;
} else {
normal_case:
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
JS_FreeValue(ctx, enum_obj);
return JS_EXCEPTION;
}
it->tab_atom = tab_atom;
it->atom_count = tab_atom_count;
}
return enum_obj;
}
/* obj -> enum_obj */
static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
{
sp[-1] = build_for_in_iterator(ctx, sp[-1]);
if (JS_IsException(sp[-1]))
return -1;
return 0;
}
/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */
static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
JSValueConst enum_obj)
{
JSObject *p;
JSForInIterator *it;
JSPropertyEnum *tab_atom;
uint32_t tab_atom_count, i;
JSValue obj1;
p = JS_VALUE_GET_OBJ(enum_obj);
it = p->u.for_in_iterator;
/* check if there are enumerable properties in the prototype chain (fast path) */
obj1 = JS_DupValue(ctx, it->obj);
for(;;) {
obj1 = JS_GetPrototypeFree(ctx, obj1);
if (JS_IsNull(obj1))
break;
if (JS_IsException(obj1))
goto fail;
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
JS_VALUE_GET_OBJ(obj1),
JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
JS_FreeValue(ctx, obj1);
goto fail;
}
JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
if (tab_atom_count != 0) {
JS_FreeValue(ctx, obj1);
goto slow_path;
}
/* must check for timeout to avoid infinite loop */
if (js_poll_interrupts(ctx)) {
JS_FreeValue(ctx, obj1);
goto fail;
}
}
JS_FreeValue(ctx, obj1);
return 1;
slow_path:
/* add the visited properties, even if they are not enumerable */
if (it->is_array) {
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
JS_VALUE_GET_OBJ(it->obj),
JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
goto fail;
}
it->is_array = FALSE;
it->tab_atom = tab_atom;
it->atom_count = tab_atom_count;
}
for(i = 0; i < it->atom_count; i++) {
if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)
goto fail;
}
return 0;
fail:
return -1;
}
/* enum_obj -> enum_obj value done */
static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
{
JSValueConst enum_obj;
JSObject *p;
JSAtom prop;
JSForInIterator *it;
JSPropertyEnum *tab_atom;
uint32_t tab_atom_count;
int ret;
enum_obj = sp[-1];
/* fail safe */
if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
goto done;
p = JS_VALUE_GET_OBJ(enum_obj);
if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
goto done;
it = p->u.for_in_iterator;
for(;;) {
if (it->idx >= it->atom_count) {
if (JS_IsNull(it->obj) || JS_IsNull(it->obj))
goto done; /* not an object */
/* no more property in the current object: look in the prototype */
if (!it->in_prototype_chain) {
ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);
if (ret < 0)
return -1;
if (ret)
goto done;
it->in_prototype_chain = TRUE;
}
it->obj = JS_GetPrototypeFree(ctx, it->obj);
if (JS_IsException(it->obj))
return -1;
if (JS_IsNull(it->obj))
goto done; /* no more prototype */
/* must check for timeout to avoid infinite loop */
if (js_poll_interrupts(ctx))
return -1;
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
JS_VALUE_GET_OBJ(it->obj),
JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
return -1;
}
JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count);
it->tab_atom = tab_atom;
it->atom_count = tab_atom_count;
it->idx = 0;
} else {
if (it->is_array) {
prop = __JS_AtomFromUInt32(it->idx);
it->idx++;
} else {
BOOL is_enumerable;
prop = it->tab_atom[it->idx].atom;
is_enumerable = it->tab_atom[it->idx].is_enumerable;
it->idx++;
if (it->in_prototype_chain) {
/* slow case: we are in the prototype chain */
ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);
if (ret < 0)
return ret;
if (ret)
continue; /* already visited */
/* add to the visited property list */
if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,
JS_PROP_ENUMERABLE) < 0)
return -1;
}
if (!is_enumerable)
continue;
}
/* check if the property was deleted */
ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);
if (ret < 0)
return ret;
if (ret)
break;
}
}
/* return the property */
sp[0] = JS_AtomToValue(ctx, prop);
sp[1] = JS_FALSE;
return 0;
done:
/* return the end */
sp[0] = JS_NULL;
sp[1] = JS_TRUE;
return 0;
}
static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
{
/* Try and handle fast arrays explicitly */
@@ -13820,17 +13541,6 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
CASE(OP_for_in_start):
sf->cur_pc = pc;
if (js_for_in_start(ctx, sp))
goto exception;
BREAK;
CASE(OP_for_in_next):
sf->cur_pc = pc;
if (js_for_in_next(ctx, sp))
goto exception;
sp += 2;
BREAK;
CASE(OP_nip_catch):
{
JSValue ret_val;
@@ -20293,172 +20003,10 @@ static int is_let(JSParseState *s, int decl_mask)
return res;
}
/* for-in loop parsing (for-of is not supported) */
/* for-in and for-of loops are not supported */
static __exception int js_parse_for_in_of(JSParseState *s, int label_name)
{
JSContext *ctx = s->ctx;
JSFunctionDef *fd = s->cur_func;
JSAtom var_name;
BOOL has_initializer, has_destructuring;
int tok, tok1, opcode, scope, block_scope_level;
int label_next, label_expr, label_cont, label_body, label_break;
int pos_next, pos_expr;
BlockEnv break_entry;
has_initializer = FALSE;
has_destructuring = FALSE;
block_scope_level = fd->scope_level;
label_cont = new_label(s);
label_body = new_label(s);
label_break = new_label(s);
label_next = new_label(s);
/* create scope for the lexical variables declared in the enumeration
expressions. XXX: Not completely correct because of weird capturing
semantics in `for (i of o) a.push(function(){return i})` */
push_scope(s);
/* local for_in scope starts here so individual elements
can be closed in statement. */
push_break_entry(s->cur_func, &break_entry,
label_name, label_break, label_cont, 1);
break_entry.scope_level = block_scope_level;
label_expr = emit_goto(s, OP_goto, -1);
pos_next = s->cur_func->byte_code.size;
emit_label(s, label_next);
tok = s->token.val;
if (tok == TOK_VAR || tok == TOK_DEF) {
if (next_token(s))
return -1;
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE, FALSE) < 0)
return -1;
has_destructuring = TRUE;
} else {
return js_parse_error(s, "variable name expected");
}
var_name = JS_ATOM_NULL;
} else {
var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
if (next_token(s)) {
JS_FreeAtom(s->ctx, var_name);
return -1;
}
if (js_define_var(s, var_name, tok)) {
JS_FreeAtom(s->ctx, var_name);
return -1;
}
emit_op(s, (tok == TOK_DEF || tok == TOK_VAR) ?
OP_scope_put_var_init : OP_scope_put_var);
emit_atom(s, var_name);
emit_u16(s, fd->scope_level);
}
} else {
int skip_bits;
if ((s->token.val == '[' || s->token.val == '{')
&& ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
return -1;
} else {
int lvalue_label;
if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
NULL, FALSE, TOK_FOR))
return -1;
put_lvalue(s, opcode, scope, var_name, lvalue_label,
PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
}
var_name = JS_ATOM_NULL;
}
emit_goto(s, OP_goto, label_body);
pos_expr = s->cur_func->byte_code.size;
emit_label(s, label_expr);
if (s->token.val == '=') {
/* XXX: potential scoping issue if inside `with` statement */
has_initializer = TRUE;
/* parse and evaluate initializer prior to evaluating the
object (only used with "for in" with a non lexical variable
in non strict mode */
if (next_token(s) || js_parse_assign_expr2(s, 0)) {
JS_FreeAtom(ctx, var_name);
return -1;
}
if (var_name != JS_ATOM_NULL) {
emit_op(s, OP_scope_put_var);
emit_atom(s, var_name);
emit_u16(s, fd->scope_level);
}
}
JS_FreeAtom(ctx, var_name);
if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
return js_parse_error(s, "'for of' loops are not supported");
} else if (s->token.val == TOK_IN) {
if (has_initializer &&
(tok != TOK_VAR || has_destructuring)) {
return js_parse_error(s, "a declaration in the head of a for-in loop can't have an initializer");
}
} else {
return js_parse_error(s, "expected 'in' in for control expression");
}
if (next_token(s))
return -1;
if (js_parse_expr(s))
return -1;
/* close the scope after having evaluated the expression so that
the TDZ values are in the closures */
close_scopes(s, s->cur_func->scope_level, block_scope_level);
emit_op(s, OP_for_in_start);
/* on stack: enum_obj */
emit_goto(s, OP_goto, label_cont);
if (js_parse_expect(s, ')'))
return -1;
if (OPTIMIZE) {
/* move the `next` code here */
DynBuf *bc = &s->cur_func->byte_code;
int chunk_size = pos_expr - pos_next;
int offset = bc->size - pos_next;
int i;
dbuf_realloc(bc, bc->size + chunk_size);
dbuf_put(bc, bc->buf + pos_next, chunk_size);
memset(bc->buf + pos_next, OP_nop, chunk_size);
/* `next` part ends with a goto */
s->cur_func->last_opcode_pos = bc->size - 5;
/* relocate labels */
for (i = label_cont; i < s->cur_func->label_count; i++) {
LabelSlot *ls = &s->cur_func->label_slots[i];
if (ls->pos >= pos_next && ls->pos < pos_expr)
ls->pos += offset;
}
}
emit_label(s, label_body);
if (js_parse_statement(s))
return -1;
close_scopes(s, s->cur_func->scope_level, block_scope_level);
emit_label(s, label_cont);
emit_op(s, OP_for_in_next);
/* on stack: enum_obj value bool */
emit_goto(s, OP_if_false, label_next);
/* drop the undefined value from for_in_next */
emit_op(s, OP_drop);
emit_label(s, label_break);
emit_op(s, OP_drop);
pop_break_entry(s->cur_func);
pop_scope(s);
return 0;
return js_parse_error(s, "'for in' and 'for of' loops are not supported");
}
static void set_eval_ret_undefined(JSParseState *s)

View File

@@ -289,11 +289,11 @@ function run_tests(package_name, specific_test) {
if (is_function(test_mod)) {
tests.push({name: 'main', fn: test_mod})
} else if (is_object(test_mod)) {
for (var k in test_mod) {
arrfor(array(test_mod), function(k) {
if (is_function(test_mod[k])) {
tests.push({name: k, fn: test_mod[k]})
}
}
})
}
if (length(tests) > 0) {

View File

@@ -781,24 +781,6 @@ return {
if (sum != 25) throw "for loop continue failed"
},
test_for_in_array: function() {
var arr = [10, 20, 30]
var sum = 0
for (var i in arr) {
sum = sum + arr[i]
}
if (sum != 60) throw "for in array failed"
},
test_for_in_object: function() {
var obj = {a: 1, b: 2, c: 3}
var sum = 0
for (var key in obj) {
sum = sum + obj[key]
}
if (sum != 6) throw "for in object failed"
},
test_nested_for_loops: function() {
var sum = 0
for (var i = 0; i < 3; i = i + 1) {
@@ -1658,18 +1640,6 @@ return {
if (o[k] != 200) throw "same object should be same key"
},
test_object_key_not_in_for_in: function() {
var k = {}
var o = {a: 1, b: 2}
o[k] = 999
var count = 0
for (var key in o) {
count = count + 1
if (key == k) throw "object key should not appear in for-in"
}
if (count != 2) throw "for-in should only see string keys"
},
test_object_key_computed_property: function() {
var k = {}
var o = {}
@@ -3462,24 +3432,6 @@ return {
if (data.users[1].name != "Bob") throw "mixed nested access failed"
},
test_empty_object_iteration: function() {
var obj = {}
var count = 0
for (var k in obj) {
count++
}
if (count != 0) throw "empty object iteration failed"
},
test_empty_array_iteration: function() {
var arr = []
var count = 0
for (var i in arr) {
count++
}
if (count != 0) throw "empty array iteration failed"
},
test_object_with_null_value: function() {
var obj = {a: null, b: 2}
if (obj.a != null) throw "object null value failed"

View File

@@ -166,26 +166,26 @@ function check_link_cycles() {
return null
}
for (var origin in links) {
arrfor(links, function(origin) {
var cycle_start = follow_chain(origin, {})
if (cycle_start) {
add_error("Link cycle detected starting from: " + origin)
}
}
})
}
// Check for dangling links
function check_dangling_links() {
var links = link.load()
for (var origin in links) {
arrfor(array(links), function(origin) {
var target = links[origin]
if (starts_with(target, '/')) {
if (!fd.is_dir(target)) {
add_error("Dangling link: " + origin + " -> " + target + " (target does not exist)")
}
}
}
})
}
// Gather packages to verify