rm for ... in
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user