Skip to content

Commit e8aa66f

Browse files
committed
Destructuring in pattern matching
1 parent 8dbc648 commit e8aa66f

File tree

43 files changed

+4899
-723
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+4899
-723
lines changed

src/parser/expression.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,10 @@ pp.parseExprAtom = function (refShorthandDefaultPos) {
678678
return this.parseParenAndDistinguishExpression(null, null, canBeArrow);
679679

680680
case tt.bracketL:
681+
if (this.hasPlugin("lightscript") && this.state.inMatchCaseTest && !refShorthandDefaultPos) {
682+
// re-enter this fn, but with refShorthandDefaultPos and state tracking
683+
return this.parseMatchCaseTestPattern();
684+
}
681685
node = this.startNode();
682686
this.next();
683687
if (this.hasPlugin("lightscript") && this.match(tt._for)) {
@@ -688,6 +692,10 @@ pp.parseExprAtom = function (refShorthandDefaultPos) {
688692
return this.finishNode(node, "ArrayExpression");
689693

690694
case tt.braceL:
695+
if (this.hasPlugin("lightscript") && this.state.inMatchCaseTest && !refShorthandDefaultPos) {
696+
// re-enter this fn, but with refShorthandDefaultPos and state tracking
697+
return this.parseMatchCaseTestPattern();
698+
}
691699
return this.parseObj(false, refShorthandDefaultPos);
692700

693701
case tt._function:
@@ -1166,6 +1174,9 @@ pp.parsePropertyName = function (prop) {
11661174
// Initialize empty function node.
11671175

11681176
pp.initFunction = function (node, isAsync) {
1177+
if (this.hasPlugin("lightscript") && this.state.inMatchCaseTest) {
1178+
this.unexpected(node.start, "Cannot match on functions.");
1179+
}
11691180
node.id = null;
11701181
node.generator = false;
11711182
node.expression = false;

src/plugins/lightscript.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ pp.parseMatchStatement = function (node) {
559559
};
560560

561561
pp.parseMatch = function (node, isExpression) {
562+
if (this.state.inMatchCaseTest) this.unexpected();
562563
this.expect(tt._match);
563564
node.discriminant = this.parseParenExpression();
564565

@@ -594,8 +595,12 @@ pp.parseMatchCase = function (isExpression) {
594595

595596
node.test = this.parseMatchCaseTest();
596597

597-
if (this.eat(tt._with)) {
598-
node.binding = this.parseBindingAtom();
598+
if (this.isContextual("as")) {
599+
if (!this.state.allowMatchCaseTestPattern) {
600+
this.unexpected(null, "Cannot rename after destructuring.");
601+
}
602+
this.next();
603+
node.binding = this.parseIdentifier();
599604
}
600605

601606
if (isExpression) {
@@ -619,6 +624,7 @@ pp.parseMatchCase = function (isExpression) {
619624
pp.parseMatchCaseTest = function () {
620625
// can't be nested so no need to read/restore old value
621626
this.state.inMatchCaseTest = true;
627+
this.state.allowMatchCaseTestPattern = true;
622628

623629
this.expect(tt.bitwiseOR);
624630
if (this.isLineBreak()) this.unexpected(this.state.lastTokEnd, "Illegal newline.");
@@ -633,6 +639,7 @@ pp.parseMatchCaseTest = function () {
633639
}
634640

635641
this.state.inMatchCaseTest = false;
642+
this.state.allowMatchCaseTestPattern = false;
636643
return test;
637644
};
638645

@@ -649,8 +656,7 @@ pp.isSubscriptTokenForMatchCase = function (tokenType) {
649656
return (
650657
tokenType === tt.dot ||
651658
tokenType === tt.elvis ||
652-
tokenType === tt.tilde ||
653-
tokenType === tt.bracketL
659+
tokenType === tt.tilde
654660
);
655661
};
656662

@@ -672,6 +678,27 @@ pp.allowMatchCasePlaceholder = function () {
672678
return false;
673679
};
674680

681+
pp.parseMatchCaseTestPattern = function () {
682+
if (!this.state.allowMatchCaseTestPattern) {
683+
this.unexpected(null, "Only one pattern allowed per match case test.");
684+
}
685+
686+
const oldInMatchCaseTestPattern = this.state.inMatchCaseTestPattern;
687+
this.state.inMatchCaseTestPattern = true;
688+
689+
// re-enter parent function, allowing patterns.
690+
const refShorthandDefaultPos = { start: 0 };
691+
const node = this.parseExprAtom(refShorthandDefaultPos);
692+
693+
// once we have finished recursing through a pattern, disallow future patterns
694+
this.state.inMatchCaseTestPattern = oldInMatchCaseTestPattern;
695+
if (this.state.inMatchCaseTestPattern === false) {
696+
this.state.allowMatchCaseTestPattern = false;
697+
}
698+
699+
return node;
700+
};
701+
675702

676703
export default function (instance) {
677704

src/tokenizer/state.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export default class State {
4141
// for lightscript
4242
this.indentLevel = 0;
4343
this.inMatchCaseTest = false;
44+
this.inMatchCaseTestPattern = false;
45+
this.allowMatchCaseTestPattern = false;
4446

4547
this.type = tt.eof;
4648
this.value = null;
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
match x:
22
| a: 1
33
| b: b
4-
| c with c: c
5-
| d with { d }: d
6-
| e with { e = 1 }: e
7-
| f with [ f ]: f
8-
| g with [ g = 1 ]: g
4+
| c as c: c
5+
| as as as: as
6+
| ~isNumber() as n: n + 1

0 commit comments

Comments
 (0)