Implement optional chaining (#5164)
The work is based on PR #4843, only fixed some conflicts and cppcheck errors. Co-authored-by: Robert Fancsik robert.fancsik@h-lab.eu JerryScript-DCO-1.0-Signed-off-by: Gergo Csizi gergocs@inf.u-szeged.hu
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
function expectSyntaxError(str) {
|
||||
try {
|
||||
eval(str);
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert(e instanceof SyntaxError);
|
||||
}
|
||||
}
|
||||
|
||||
function expectTypeError(cb) {
|
||||
try {
|
||||
cb();
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
}
|
||||
|
||||
expectSyntaxError("this?.a``");
|
||||
expectSyntaxError("this?.['a']``");
|
||||
expectSyntaxError("this?.``");
|
||||
expectSyntaxError("this.a?.``");
|
||||
expectSyntaxError("this['a']?.``");
|
||||
expectSyntaxError("this?.a = 9");
|
||||
expectSyntaxError("this.a.a.a.a.a?.a = 9");
|
||||
expectSyntaxError("this?.a.a.a.a.a.a = 9");
|
||||
expectSyntaxError("this?.a++");
|
||||
expectSyntaxError("this?.a.a.a.a.a.a++");
|
||||
expectSyntaxError("this.a.a.a.a.?a.a++");
|
||||
expectSyntaxError("this?.a--");
|
||||
expectSyntaxError("this?.a.a.a.a.a.a--");
|
||||
expectSyntaxError("this.a.a.a.a.?a.a--");
|
||||
|
||||
var o = {
|
||||
a: 4.1,
|
||||
b() {
|
||||
return 4.2;
|
||||
},
|
||||
c: {
|
||||
a: 4.3,
|
||||
b() {
|
||||
return 4.4
|
||||
}
|
||||
},
|
||||
e(...args) {
|
||||
return args.reduce((p, c) => p + c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert(o?.a === 4.1);
|
||||
assert(o?.a2 === undefined);
|
||||
assert(this.o?.a === 4.1);
|
||||
assert(this.o?.a2 === undefined);
|
||||
assert(this.o?.['a'] === 4.1);
|
||||
assert(this.o?.['a2'] === undefined);
|
||||
assert(typeof o?.a === 'number');
|
||||
assert(typeof o?.a2 === 'undefined');
|
||||
|
||||
assert(o?.c?.a === 4.3);
|
||||
assert(o?.c?.a2 === undefined);
|
||||
assert(this.o?.c?.a === 4.3);
|
||||
assert(this.o?.c?.a2 === undefined);
|
||||
assert(this.o?.c?.['a'] === 4.3);
|
||||
assert(this.o?.c?.['a2'] === undefined);
|
||||
assert(typeof o?.c?.a === 'number');
|
||||
assert(typeof o?.c?.a2 === 'undefined');
|
||||
|
||||
assert(o?.d === undefined);
|
||||
assert(o?.d?.d === undefined);
|
||||
assert(o?.d?.d?.['d'] === undefined);
|
||||
|
||||
assert(o?.b?.() === 4.2);
|
||||
assert(o?.b2?.() === undefined);
|
||||
|
||||
assert(o?.c?.b?.() === 4.4);
|
||||
assert(o?.c?.b2?.() === undefined);
|
||||
|
||||
assert(o?.e(...[1.25, 2.25, 3.25]) === 6.75);
|
||||
assert(o?.e(...[1.25, 2.25, 3.25], ...[0.25]) === 7);
|
||||
assert(o?.['e'](...[1.25, 2.25, 3.25]) === 6.75);
|
||||
assert(o?.['e'](...[1.25, 2.25, 3.25], ...[0.25]) === 7);
|
||||
|
||||
assert(o?.e?.(...[1.25, 2.25, 3.25]) === 6.75);
|
||||
assert(o?.e?.(...[1.25, 2.25, 3.25], ...[0.25]) === 7);
|
||||
assert(o?.['e']?.(...[1.25, 2.25, 3.25]) === 6.75);
|
||||
assert(o?.['e']?.(...[1.25, 2.25, 3.25], ...[0.25]) === 7);
|
||||
|
||||
// Test short circuit
|
||||
let count = 0;
|
||||
assert(undefined?.[count++] === undefined);
|
||||
assert(undefined?.[count++]() === undefined);
|
||||
assert(undefined?.[count++]()() === undefined);
|
||||
assert(null?.[count++] === undefined);
|
||||
assert(null?.[count++]() === undefined);
|
||||
assert(null?.[count++]()() === undefined);
|
||||
assert(count === 0);
|
||||
|
||||
// Test optional call
|
||||
var g = undefined;
|
||||
|
||||
function f () {
|
||||
return 4.5;
|
||||
}
|
||||
|
||||
assert(g?.() === undefined);
|
||||
assert(this?.g?.() === undefined);
|
||||
assert(this.g?.() === undefined);
|
||||
|
||||
expectTypeError(_ => {
|
||||
this.g();
|
||||
});
|
||||
|
||||
assert(f?.() === 4.5);
|
||||
assert(this?.f?.() === 4.5);
|
||||
assert(this.f?.() === 4.5);
|
||||
assert(f() === 4.5);
|
||||
|
||||
// test direct eval
|
||||
var a = 5.1;
|
||||
eval('a = 5.2');
|
||||
assert(a === 5.2);
|
||||
eval?.('a = 5.3');
|
||||
assert(a === 5.3);
|
||||
eval?.(...['a = 5.4']);
|
||||
assert(a === 5.4);
|
||||
|
||||
const saved_eval = eval;
|
||||
eval = undefined;
|
||||
|
||||
eval?.('a = 5.5')
|
||||
assert(a === 5.4);
|
||||
eval?.(...['a = 5.5'])
|
||||
assert(a === 5.4);
|
||||
|
||||
eval = saved_eval;
|
||||
|
||||
// test optional private property access
|
||||
class A {
|
||||
#a = 5.1;
|
||||
|
||||
test(o) {
|
||||
return o?.#a;
|
||||
}
|
||||
}
|
||||
|
||||
let instance = new A;
|
||||
assert(instance.test(instance) === 5.1);
|
||||
assert(instance.test(undefined) === undefined);
|
||||
assert(instance.test(null) === undefined);
|
||||
expectTypeError(_ => {
|
||||
instance.test({});
|
||||
});
|
||||
@@ -2003,16 +2003,12 @@
|
||||
<test id="language/expressions/class/elements/async-gen-private-method/yield-promise-reject-next.js"><reason></reason></test>
|
||||
<test id="language/expressions/class/elements/class-name-static-initializer-anonymous.js"><reason></reason></test>
|
||||
<test id="language/expressions/class/elements/class-name-static-initializer-default-export.js"><reason></reason></test>
|
||||
<test id="language/expressions/class/elements/grammar-private-field-optional-chaining.js"><reason></reason></test>
|
||||
<test id="language/expressions/class/elements/private-field-after-optional-chain.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/async-gen-private-method-static/yield-promise-reject-next-catch.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/async-gen-private-method-static/yield-promise-reject-next-for-await-of-async-iterator.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/async-gen-private-method-static/yield-promise-reject-next.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/async-gen-private-method/yield-promise-reject-next-catch.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/async-gen-private-method/yield-promise-reject-next-for-await-of-async-iterator.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/async-gen-private-method/yield-promise-reject-next.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/grammar-private-field-optional-chaining.js"><reason></reason></test>
|
||||
<test id="language/statements/class/elements/private-field-after-optional-chain.js"><reason></reason></test>
|
||||
<!-- END - ESNext stage 3 proposals: class fields, private methods and static class features -->
|
||||
|
||||
<!-- ESNext stage 3 proposal: top level await
|
||||
@@ -2512,37 +2508,6 @@
|
||||
<test id="language/statements/while/tco-body.js"><reason></reason></test>
|
||||
<!-- END - ES2015: Proper Tail Call (PTC) Optimization -->
|
||||
|
||||
<!-- ES2020: Optional Chaining
|
||||
features: [optional-chaining]
|
||||
https://github.com/tc39/proposal-optional-chaining
|
||||
-->
|
||||
<test id="language/expressions/optional-chaining/call-expression.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/eval-optional-call.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/iteration-statement-do.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/iteration-statement-for-await-of.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/iteration-statement-for-in.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/iteration-statement-for-of-type-error.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/iteration-statement-for.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/iteration-statement-while.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/member-expression-async-identifier.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/member-expression-async-literal.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/member-expression-async-this.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/member-expression.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/new-target-optional-call.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-call-preserves-this.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain-async-optional-chain-square-brackets.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain-async-square-brackets.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain-expression-optional-expression.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain-prod-arguments.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain-prod-expression.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain-prod-identifiername.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-chain.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/optional-expression.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/runtime-semantics-evaluation.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/short-circuiting.js"><reason></reason></test>
|
||||
<test id="language/expressions/optional-chaining/super-property-optional-call.js"><reason></reason></test>
|
||||
<!-- END - ES2020: Optional Chaining -->
|
||||
|
||||
<!-- ES2017: Shared Memory and Atomics
|
||||
features: [Atomics]
|
||||
https://github.com/tc39/ecmascript_sharedmem
|
||||
|
||||
Reference in New Issue
Block a user