mirror of
https://github.com/bellard/quickjs.git
synced 2025-09-29 22:44:25 +03:00
optional chaining fixes (github issue #103)
This commit is contained in:
116
quickjs.c
116
quickjs.c
@@ -21530,6 +21530,14 @@ static int new_label(JSParseState *s)
|
||||
return new_label_fd(s->cur_func, -1);
|
||||
}
|
||||
|
||||
/* don't update the last opcode and don't emit line number info */
|
||||
static void emit_label_raw(JSParseState *s, int label)
|
||||
{
|
||||
emit_u8(s, OP_label);
|
||||
emit_u32(s, label);
|
||||
s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
|
||||
}
|
||||
|
||||
/* return the label ID offset */
|
||||
static int emit_label(JSParseState *s, int label)
|
||||
{
|
||||
@@ -24643,6 +24651,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
|
||||
drop_count = 2;
|
||||
break;
|
||||
case OP_get_field_opt_chain:
|
||||
{
|
||||
int opt_chain_label, next_label;
|
||||
opt_chain_label = get_u32(fd->byte_code.buf +
|
||||
fd->last_opcode_pos + 1 + 4 + 1);
|
||||
/* keep the object on the stack */
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
|
||||
fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
|
||||
next_label = emit_goto(s, OP_goto, -1);
|
||||
emit_label(s, opt_chain_label);
|
||||
/* need an additional undefined value for the
|
||||
case where the optional field does not
|
||||
exists */
|
||||
emit_op(s, OP_undefined);
|
||||
emit_label(s, next_label);
|
||||
drop_count = 2;
|
||||
opcode = OP_get_field;
|
||||
}
|
||||
break;
|
||||
case OP_scope_get_private_field:
|
||||
/* keep the object on the stack */
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
|
||||
@@ -24653,6 +24680,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
|
||||
drop_count = 2;
|
||||
break;
|
||||
case OP_get_array_el_opt_chain:
|
||||
{
|
||||
int opt_chain_label, next_label;
|
||||
opt_chain_label = get_u32(fd->byte_code.buf +
|
||||
fd->last_opcode_pos + 1 + 1);
|
||||
/* keep the object on the stack */
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
|
||||
fd->byte_code.size = fd->last_opcode_pos + 1;
|
||||
next_label = emit_goto(s, OP_goto, -1);
|
||||
emit_label(s, opt_chain_label);
|
||||
/* need an additional undefined value for the
|
||||
case where the optional field does not
|
||||
exists */
|
||||
emit_op(s, OP_undefined);
|
||||
emit_label(s, next_label);
|
||||
drop_count = 2;
|
||||
opcode = OP_get_array_el;
|
||||
}
|
||||
break;
|
||||
case OP_scope_get_var:
|
||||
{
|
||||
JSAtom name;
|
||||
@@ -24935,8 +24981,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optional_chaining_label >= 0)
|
||||
emit_label(s, optional_chaining_label);
|
||||
if (optional_chaining_label >= 0) {
|
||||
JSFunctionDef *fd = s->cur_func;
|
||||
int opcode;
|
||||
emit_label_raw(s, optional_chaining_label);
|
||||
/* modify the last opcode so that it is an indicator of an
|
||||
optional chain */
|
||||
opcode = get_prev_opcode(fd);
|
||||
if (opcode == OP_get_field || opcode == OP_get_array_el) {
|
||||
if (opcode == OP_get_field)
|
||||
opcode = OP_get_field_opt_chain;
|
||||
else
|
||||
opcode = OP_get_array_el_opt_chain;
|
||||
fd->byte_code.buf[fd->last_opcode_pos] = opcode;
|
||||
} else {
|
||||
fd->last_opcode_pos = -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24952,27 +25013,57 @@ static __exception int js_parse_delete(JSParseState *s)
|
||||
return -1;
|
||||
switch(opcode = get_prev_opcode(fd)) {
|
||||
case OP_get_field:
|
||||
case OP_get_field_opt_chain:
|
||||
{
|
||||
JSValue val;
|
||||
int ret;
|
||||
|
||||
int ret, opt_chain_label, next_label;
|
||||
if (opcode == OP_get_field_opt_chain) {
|
||||
opt_chain_label = get_u32(fd->byte_code.buf +
|
||||
fd->last_opcode_pos + 1 + 4 + 1);
|
||||
} else {
|
||||
opt_chain_label = -1;
|
||||
}
|
||||
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
|
||||
fd->byte_code.size = fd->last_opcode_pos;
|
||||
fd->last_opcode_pos = -1;
|
||||
val = JS_AtomToValue(s->ctx, name);
|
||||
ret = emit_push_const(s, val, 1);
|
||||
JS_FreeValue(s->ctx, val);
|
||||
JS_FreeAtom(s->ctx, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
emit_op(s, OP_delete);
|
||||
if (opt_chain_label >= 0) {
|
||||
next_label = emit_goto(s, OP_goto, -1);
|
||||
emit_label(s, opt_chain_label);
|
||||
/* if the optional chain is not taken, return 'true' */
|
||||
emit_op(s, OP_drop);
|
||||
emit_op(s, OP_push_true);
|
||||
emit_label(s, next_label);
|
||||
}
|
||||
fd->last_opcode_pos = -1;
|
||||
}
|
||||
goto do_delete;
|
||||
break;
|
||||
case OP_get_array_el:
|
||||
fd->byte_code.size = fd->last_opcode_pos;
|
||||
fd->last_opcode_pos = -1;
|
||||
do_delete:
|
||||
emit_op(s, OP_delete);
|
||||
break;
|
||||
case OP_get_array_el_opt_chain:
|
||||
{
|
||||
int opt_chain_label, next_label;
|
||||
opt_chain_label = get_u32(fd->byte_code.buf +
|
||||
fd->last_opcode_pos + 1 + 1);
|
||||
fd->byte_code.size = fd->last_opcode_pos;
|
||||
emit_op(s, OP_delete);
|
||||
next_label = emit_goto(s, OP_goto, -1);
|
||||
emit_label(s, opt_chain_label);
|
||||
/* if the optional chain is not taken, return 'true' */
|
||||
emit_op(s, OP_drop);
|
||||
emit_op(s, OP_push_true);
|
||||
emit_label(s, next_label);
|
||||
fd->last_opcode_pos = -1;
|
||||
}
|
||||
break;
|
||||
case OP_scope_get_var:
|
||||
/* 'delete this': this is not a reference */
|
||||
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
|
||||
@@ -31606,6 +31697,17 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
|
||||
case OP_set_class_name:
|
||||
/* only used during parsing */
|
||||
break;
|
||||
|
||||
case OP_get_field_opt_chain: /* equivalent to OP_get_field */
|
||||
{
|
||||
JSAtom name = get_u32(bc_buf + pos + 1);
|
||||
dbuf_putc(&bc_out, OP_get_field);
|
||||
dbuf_put_u32(&bc_out, name);
|
||||
}
|
||||
break;
|
||||
case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
|
||||
dbuf_putc(&bc_out, OP_get_array_el);
|
||||
break;
|
||||
|
||||
default:
|
||||
no_change:
|
||||
|
Reference in New Issue
Block a user