mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibJS: Allow division after IdentifierNames in optional chain
The following syntax is valid: ```js e?.example / 1.2 ``` Previously, the `/` would be treated as a unterminated regex literal, because it was calling the regular `consume` instead of `consume_and_allow_division`. This is what is done when parsing IdentifierNames in parse_secondary_expression when a period is encountered. Allows us to parse clients-main-[hash].js on https://ubereats.com/
This commit is contained in:
parent
1bdc41faa1
commit
bd4c29322c
Notes:
github-actions[bot]
2024-11-11 19:20:18 +00:00
Author: https://github.com/Lubrsi Commit: https://github.com/LadybirdBrowser/ladybird/commit/bd4c29322c9 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2286
2 changed files with 17 additions and 2 deletions
|
@ -3561,7 +3561,7 @@ NonnullRefPtr<OptionalChain const> Parser::parse_optional_chain(NonnullRefPtr<Ex
|
||||||
default:
|
default:
|
||||||
if (match_identifier_name()) {
|
if (match_identifier_name()) {
|
||||||
auto start = position();
|
auto start = position();
|
||||||
auto identifier = consume();
|
auto identifier = consume_and_allow_division();
|
||||||
chain.append(OptionalChain::MemberReference {
|
chain.append(OptionalChain::MemberReference {
|
||||||
create_ast_node<Identifier>({ m_source_code, start, position() }, identifier.DeprecatedFlyString_value()),
|
create_ast_node<Identifier>({ m_source_code, start, position() }, identifier.DeprecatedFlyString_value()),
|
||||||
OptionalChain::Mode::Optional,
|
OptionalChain::Mode::Optional,
|
||||||
|
@ -3587,7 +3587,7 @@ NonnullRefPtr<OptionalChain const> Parser::parse_optional_chain(NonnullRefPtr<Ex
|
||||||
});
|
});
|
||||||
} else if (match_identifier_name()) {
|
} else if (match_identifier_name()) {
|
||||||
auto start = position();
|
auto start = position();
|
||||||
auto identifier = consume();
|
auto identifier = consume_and_allow_division();
|
||||||
chain.append(OptionalChain::MemberReference {
|
chain.append(OptionalChain::MemberReference {
|
||||||
create_ast_node<Identifier>({ m_source_code, start, position() }, identifier.DeprecatedFlyString_value()),
|
create_ast_node<Identifier>({ m_source_code, start, position() }, identifier.DeprecatedFlyString_value()),
|
||||||
OptionalChain::Mode::NotOptional,
|
OptionalChain::Mode::NotOptional,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
test("slash token resolution in lexer", () => {
|
test("slash token resolution in lexer", () => {
|
||||||
expect(`{ blah.blah; }\n/foo/`).toEval();
|
expect(`{ blah.blah; }\n/foo/`).toEval();
|
||||||
|
expect(`{ blah?.blah.blah; }\n/foo/`).toEval();
|
||||||
expect("``/foo/").not.toEval();
|
expect("``/foo/").not.toEval();
|
||||||
expect("1/foo/").not.toEval();
|
expect("1/foo/").not.toEval();
|
||||||
expect("1/foo").toEval();
|
expect("1/foo").toEval();
|
||||||
|
@ -16,24 +17,34 @@ test("slash token resolution in lexer", () => {
|
||||||
expect("+a++ / 1").toEval();
|
expect("+a++ / 1").toEval();
|
||||||
expect("+a-- / 1").toEval();
|
expect("+a-- / 1").toEval();
|
||||||
expect("a.in / b").toEval();
|
expect("a.in / b").toEval();
|
||||||
|
expect("a?.in.in / b").toEval();
|
||||||
expect("a.instanceof / b").toEval();
|
expect("a.instanceof / b").toEval();
|
||||||
|
expect("a?.instanceof.instanceof / b").toEval();
|
||||||
expect("class A { #name; d = a.#name / b; }").toEval();
|
expect("class A { #name; d = a.#name / b; }").toEval();
|
||||||
|
expect("class A { #name; d = a?.#name / b; }").toEval();
|
||||||
|
|
||||||
expect("async / b").toEval();
|
expect("async / b").toEval();
|
||||||
expect("a.delete / b").toEval();
|
expect("a.delete / b").toEval();
|
||||||
|
expect("a?.delete.delete / b").toEval();
|
||||||
expect("delete / b/").toEval();
|
expect("delete / b/").toEval();
|
||||||
expect("a.in / b").toEval();
|
expect("a.in / b").toEval();
|
||||||
|
expect("a?.in.in / b").toEval();
|
||||||
expect("for (a in / b/) {}").toEval();
|
expect("for (a in / b/) {}").toEval();
|
||||||
expect("a.instanceof / b").toEval();
|
expect("a.instanceof / b").toEval();
|
||||||
|
expect("a?.instanceof.instanceof / b").toEval();
|
||||||
expect("a instanceof / b/").toEval();
|
expect("a instanceof / b/").toEval();
|
||||||
|
expect("a?.instanceof instanceof / b/").toEval();
|
||||||
expect("new / b/").toEval();
|
expect("new / b/").toEval();
|
||||||
expect("null / b").toEval();
|
expect("null / b").toEval();
|
||||||
expect("for (a of / b/) {}").toEval();
|
expect("for (a of / b/) {}").toEval();
|
||||||
expect("a.return / b").toEval();
|
expect("a.return / b").toEval();
|
||||||
|
expect("a?.return.return / b").toEval();
|
||||||
expect("function foo() { return / b/ }").toEval();
|
expect("function foo() { return / b/ }").toEval();
|
||||||
expect("throw / b/").toEval();
|
expect("throw / b/").toEval();
|
||||||
expect("a.typeof / b").toEval();
|
expect("a.typeof / b").toEval();
|
||||||
|
expect("a?.typeof.typeof / b").toEval();
|
||||||
expect("a.void / b").toEval();
|
expect("a.void / b").toEval();
|
||||||
|
expect("a?.void.void / b").toEval();
|
||||||
expect("void / b/").toEval();
|
expect("void / b/").toEval();
|
||||||
|
|
||||||
expect("await / b").toEval();
|
expect("await / b").toEval();
|
||||||
|
@ -49,4 +60,8 @@ test("slash token resolution in lexer", () => {
|
||||||
expect("this / 1").toEval();
|
expect("this / 1").toEval();
|
||||||
expect("this / 1 /").not.toEval();
|
expect("this / 1 /").not.toEval();
|
||||||
expect("this / 1 / 1").toEval();
|
expect("this / 1 / 1").toEval();
|
||||||
|
|
||||||
|
expect("this?.a / 1").toEval();
|
||||||
|
expect("this?.a / 1 /").not.toEval();
|
||||||
|
expect("this?.a / 1 / 1").toEval();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue