Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pattern matching #251

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions experimental/pattern-matching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# [Pattern Matching](proposal-pattern-matching)

See also [AST examples](ast-examples) for this proposal.

## MatchExpression

```js
interface MatchExpression <: Expression {
type: "MatchExpression";
discriminant: Expression;
id: Pattern | null;
clauses: [ MatchClause ]
}
```

## MatchClause

```js
interface MatchClause <: Node {
type: "MatchClause";
test: MatchPattern | null;
guard: Expression | null;
id: Pattern | null;
consequent: BlockStatement
}
```

If `test` is `null`, `id` must be `null`.

## MatchPattern
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a mention here as to why we don’t just use Pattern? (You mentioned in the PR itself but seems important to include here as well.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, addressed in d67b89a.


```js
interface MatchPattern <: Node {}
```

While a Match Pattern shares similar structures with a Pattern, it is different from a Pattern:

- Literals or negative numbers are match patterns, but they are not patterns
- Any expression can be converted to an expression match pattern
- Multiple match patterns can be joined with `and`, `or` and `with` operators, but patterns can not
- Unlike array and object patterns, assignment patterns have no corresponding syntax in match patterns

## ArrayMatchPattern

```js
interface ArrayMatchPattern <: MatchPattern {
type: "ArrayMatchPattern";
elements: [ MatchPattern ];
}
```

## ObjectMatchPattern

```js
interface AssignmentMatchProperty <: Property {
type: "Property"; // inherited
value: MatchPattern;
kind: "init";
method: false;
}

interface ObjectMatchPattern <: MatchPattern {
type: "ObjectMatchPattern";
properties: [ AssignmentMatchProperty ];
JLHwung marked this conversation as resolved.
Show resolved Hide resolved
}
```

## RestMatchElement
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ArrayMatchPattern, ObjectMatchPattern and RestMatchElement are essentially ArrayPattern, ObjectPattern and RestElement with Pattern replaced by MatchPattern.


```js
interface RestMatchElement <: MatchPattern {
type: "RestMatchElement";
argument: MatchPattern;
}
```

## BinaryMatchPattern

```js
interface BinaryMatchPattern <: MatchPattern {
type: "BinaryMatchPattern";
operator: "and" | "or" | "with";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The champions have not decided the combinator token of "and" and "or": tc39/proposal-pattern-matching#179. We could change to & and | here if they go with these sigils.

left: MatchPattern;
right: MatchPattern;
}
```

## AsMatchPattern

```js
interface AsMatchPattern <: MatchPattern {
type: "AsMatchPattern";
test: MatchPattern;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AsMatchPattern is separated from BinaryMatchPattern because the right (renamed as id) accepts a Pattern, not MatchPattern.

id: Pattern;
}
```

## ExpressionMatchPattern

```js
interface ExpressionMatchPattern <: MatchPattern {
type: "ExpressionMatchPattern";
expression: Expression;
}
```

## NullMatchPattern

```js
interface NullMatchPattern <: MatchPattern {
type: "NullMatchPattern";
}
```

# Literal

```js
extend interface Literal <: Expression, MatchPattern {}
```

# Identifier

```js
extend interface Identifier <: Expression, Pattern, MatchPattern {}
```

### UnaryExpression

```js
extend interface UnaryExpression <: Expression, MatchPattern {}
```

If a UnaryExpression is a MatchPattern, its `operator` must be `"-"`, its `prefix` must be `true`, and its `argument` must be either a Literal with numeric value, or an identifier named `"Infinity"`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a pattern, this also allows undefined (even if the identifier resolves to something that's not the undefined value), but also, all number and bigint literals (with +, -, or no sign at all), null, booleans, etc.

Also, template literals haven't been thought out here - i filed tc39/proposal-pattern-matching#205 to track

Copy link
Contributor Author

@JLHwung JLHwung Jun 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, undefined is covered in the Identifier case

extend interface Identifier <: Expression, Pattern, MatchPattern {}

The UnaryExpression case is addressed to things like -0, -1, -1n and -Infinity, since they are an UnaryExpression from the AST perspective.

The template literals in ESTree has a specific type TemplateLiteral, in this PR the TemplateLiteral is not mentioned so it is not a MatchPattern. But yeah it is a good question whether it should be allowed. I will update this PR if necessary.


[proposal-pattern-matching]: https://tc39.es/proposal-pattern-matching/
[ast-examples]: https://gist.github.com/JLHwung/d2b64364dc63757282cef182367b4e84