mirror of
https://github.com/DoneJS-Runtime/quickjs-done-nextgen.git
synced 2025-01-09 17:43:15 +00:00
parent
0990875ae8
commit
ac958f1d2f
4 changed files with 137 additions and 10 deletions
|
@ -282,7 +282,8 @@ def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in pha
|
||||||
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
|
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
|
||||||
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
|
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
|
||||||
def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
|
def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
|
||||||
|
def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
|
||||||
|
def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
|
||||||
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
|
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
|
||||||
|
|
||||||
def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
|
def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
|
||||||
|
|
116
quickjs.c
116
quickjs.c
|
@ -20254,6 +20254,14 @@ static int new_label(JSParseState *s)
|
||||||
return new_label_fd(s->cur_func, -1);
|
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 */
|
/* return the label ID offset */
|
||||||
static int emit_label(JSParseState *s, int label)
|
static int emit_label(JSParseState *s, int label)
|
||||||
{
|
{
|
||||||
|
@ -23385,6 +23393,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
|
||||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
|
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
|
||||||
drop_count = 2;
|
drop_count = 2;
|
||||||
break;
|
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:
|
case OP_scope_get_private_field:
|
||||||
/* keep the object on the stack */
|
/* keep the object on the stack */
|
||||||
fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
|
fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
|
||||||
|
@ -23395,6 +23422,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;
|
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
|
||||||
drop_count = 2;
|
drop_count = 2;
|
||||||
break;
|
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:
|
case OP_scope_get_var:
|
||||||
{
|
{
|
||||||
JSAtom name;
|
JSAtom name;
|
||||||
|
@ -23653,8 +23699,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (optional_chaining_label >= 0)
|
if (optional_chaining_label >= 0) {
|
||||||
emit_label(s, optional_chaining_label);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23670,27 +23731,57 @@ static __exception int js_parse_delete(JSParseState *s)
|
||||||
return -1;
|
return -1;
|
||||||
switch(opcode = get_prev_opcode(fd)) {
|
switch(opcode = get_prev_opcode(fd)) {
|
||||||
case OP_get_field:
|
case OP_get_field:
|
||||||
|
case OP_get_field_opt_chain:
|
||||||
{
|
{
|
||||||
JSValue val;
|
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);
|
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
|
||||||
fd->byte_code.size = fd->last_opcode_pos;
|
fd->byte_code.size = fd->last_opcode_pos;
|
||||||
fd->last_opcode_pos = -1;
|
|
||||||
val = JS_AtomToValue(s->ctx, name);
|
val = JS_AtomToValue(s->ctx, name);
|
||||||
ret = emit_push_const(s, val, 1);
|
ret = emit_push_const(s, val, 1);
|
||||||
JS_FreeValue(s->ctx, val);
|
JS_FreeValue(s->ctx, val);
|
||||||
JS_FreeAtom(s->ctx, name);
|
JS_FreeAtom(s->ctx, name);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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:
|
case OP_get_array_el:
|
||||||
fd->byte_code.size = fd->last_opcode_pos;
|
fd->byte_code.size = fd->last_opcode_pos;
|
||||||
fd->last_opcode_pos = -1;
|
fd->last_opcode_pos = -1;
|
||||||
do_delete:
|
|
||||||
emit_op(s, OP_delete);
|
emit_op(s, OP_delete);
|
||||||
break;
|
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:
|
case OP_scope_get_var:
|
||||||
/* 'delete this': this is not a reference */
|
/* 'delete this': this is not a reference */
|
||||||
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
|
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
|
||||||
|
@ -30371,6 +30462,17 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
|
||||||
/* only used during parsing */
|
/* only used during parsing */
|
||||||
break;
|
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:
|
default:
|
||||||
no_change:
|
no_change:
|
||||||
dbuf_put(&bc_out, bc_buf + pos, len);
|
dbuf_put(&bc_out, bc_buf + pos, len);
|
||||||
|
|
|
@ -134,7 +134,5 @@ test262/test/language/expressions/generators/static-init-await-binding.js:16: Sy
|
||||||
test262/test/language/expressions/generators/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
|
test262/test/language/expressions/generators/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
|
||||||
test262/test/language/expressions/member-expression/computed-reference-null-or-undefined.js:28: Test262Error: Expected a TypeError but got a Test262Error
|
test262/test/language/expressions/member-expression/computed-reference-null-or-undefined.js:28: Test262Error: Expected a TypeError but got a Test262Error
|
||||||
test262/test/language/expressions/member-expression/computed-reference-null-or-undefined.js:28: strict mode: Test262Error: Expected a TypeError but got a Test262Error
|
test262/test/language/expressions/member-expression/computed-reference-null-or-undefined.js:28: strict mode: Test262Error: Expected a TypeError but got a Test262Error
|
||||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
|
|
||||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:16: strict mode: TypeError: cannot read property '_b' of undefined
|
|
||||||
test262/test/language/module-code/top-level-await/async-module-does-not-block-sibling-modules.js:13: SyntaxError: Could not find export 'check' in module 'test262/test/language/module-code/top-level-await/async-module-sync_FIXTURE.js'
|
test262/test/language/module-code/top-level-await/async-module-does-not-block-sibling-modules.js:13: SyntaxError: Could not find export 'check' in module 'test262/test/language/module-code/top-level-await/async-module-sync_FIXTURE.js'
|
||||||
test262/test/staging/top-level-await/tla-hang-entry.js:10: TypeError: $DONE() not called
|
test262/test/staging/top-level-await/tla-hang-entry.js:10: TypeError: $DONE() not called
|
||||||
|
|
|
@ -666,6 +666,31 @@ function test_syntax()
|
||||||
assert_throws(SyntaxError, "if \\u0123");
|
assert_throws(SyntaxError, "if \\u0123");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* optional chaining tests not present in test262 */
|
||||||
|
function test_optional_chaining()
|
||||||
|
{
|
||||||
|
var a, z;
|
||||||
|
z = null;
|
||||||
|
a = { b: { c: 2 } };
|
||||||
|
assert(delete z?.b.c, true);
|
||||||
|
assert(delete a?.b.c, true);
|
||||||
|
assert(JSON.stringify(a), '{"b":{}}', "optional chaining delete");
|
||||||
|
|
||||||
|
a = { b: { c: 2 } };
|
||||||
|
assert(delete z?.b["c"], true);
|
||||||
|
assert(delete a?.b["c"], true);
|
||||||
|
assert(JSON.stringify(a), '{"b":{}}');
|
||||||
|
|
||||||
|
a = {
|
||||||
|
b() { return this._b; },
|
||||||
|
_b: { c: 42 }
|
||||||
|
};
|
||||||
|
|
||||||
|
assert((a?.b)().c, 42);
|
||||||
|
|
||||||
|
assert((a?.["b"])().c, 42);
|
||||||
|
}
|
||||||
|
|
||||||
test_op1();
|
test_op1();
|
||||||
test_cvt();
|
test_cvt();
|
||||||
test_eq();
|
test_eq();
|
||||||
|
@ -688,3 +713,4 @@ test_function_expr_name();
|
||||||
test_reserved_names();
|
test_reserved_names();
|
||||||
test_number_literals();
|
test_number_literals();
|
||||||
test_syntax();
|
test_syntax();
|
||||||
|
test_optional_chaining();
|
||||||
|
|
Loading…
Reference in a new issue