rm for ... in
This commit is contained in:
9
bench.ce
9
bench.ce
@@ -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}`)
|
||||
|
||||
@@ -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}`)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
12
graph.ce
12
graph.ce
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
4
link.ce
4
link.ce
@@ -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
35
link.cm
@@ -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
|
||||
|
||||
3
list.ce
3
list.ce
@@ -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) {
|
||||
|
||||
21
package.cm
21
package.cm
@@ -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
|
||||
}
|
||||
|
||||
10
resolve.ce
10
resolve.ce
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
456
source/quickjs.c
456
source/quickjs.c
@@ -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)
|
||||
|
||||
4
test.ce
4
test.ce
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user