Skip to content

Commit 37cc439

Browse files
authored
Merge pull request #22237 from asgerf/unified/local-scoping-followups
Unified: Local scoping followups
2 parents e9322f4 + 6e0d62c commit 37cc439

10 files changed

Lines changed: 538 additions & 49 deletions

File tree

unified/extractor/ast_types.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ supertypes:
4949
- tuple_pattern
5050
- constructor_pattern
5151
- or_pattern
52+
- conditional_pattern
5253
- ignore_pattern
5354
- expr_equality_pattern
5455
- bulk_importing_pattern
@@ -369,7 +370,6 @@ named:
369370
catch_clause:
370371
modifier*: modifier
371372
pattern?: pattern
372-
guard?: expr
373373
body: block
374374

375375
# `switch value { case pattern: body case ...: default: body }`
@@ -381,11 +381,9 @@ named:
381381
# A single `case ...:` (or `default:`) entry in a switch.
382382
# An entry with multiple `case p1, p2:` patterns uses an `or_pattern`.
383383
# A `default:` entry has no pattern.
384-
# An optional `guard` corresponds to a `where`-clause on the case.
385384
switch_case:
386385
modifier*: modifier
387386
pattern?: pattern
388-
guard?: expr
389387
body: block
390388

391389
# Evaluate 'expr' and match its result against 'pattern', and return true if it matches.
@@ -446,6 +444,14 @@ named:
446444
modifier*: modifier
447445
pattern*: pattern
448446

447+
# A pattern that matches against a nested pattern, and subsequently checks a condition.
448+
# The match is rejected if the condition does not hold.
449+
# Variables bound in the nested pattern are in scope within the condition.
450+
conditional_pattern:
451+
modifier*: modifier
452+
condition: expr
453+
pattern: pattern
454+
449455
# A pattern with an optional associated name.
450456
pattern_element:
451457
modifier*: modifier

unified/extractor/src/languages/swift/swift.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ fn and_chain(
9494
.expect("control-flow statement must have at least one condition")
9595
}
9696

97+
/// Return the only pattern unchanged when there is exactly one, otherwise
98+
/// wrap the list in an `or_pattern`.
99+
fn make_or_pattern(
100+
ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>,
101+
items: Vec<yeast::Id>,
102+
) -> yeast::Id {
103+
if items.len() == 1 {
104+
items[0]
105+
} else {
106+
tree!((or_pattern pattern: {items}))
107+
}
108+
}
109+
97110
/// Translate a multi-part identifier (for example `Foo.Bar.Baz`) into a
98111
/// `member_access_expr` chain rooted at a `name_expr` over the first
99112
/// part. Panics on an empty input because the grammar's `_+` quantifier
@@ -746,22 +759,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
746759
rule!(
747760
(switchCase label: (switchCaseLabel caseItems: _* @items) statements: _* @body)
748761
=>
749-
switch_case {
750-
let pattern = if items.len() == 1 {
751-
items[0]
752-
} else {
753-
tree!((or_pattern pattern: {items}))
754-
};
755-
tree!((switch_case pattern: {pattern} body: (block stmt: {body})))
756-
}
762+
(switch_case
763+
pattern: {make_or_pattern(&mut ctx, items)}
764+
body: (block stmt: {body}))
757765
),
758766
rule!(
759767
(switchCase label: (switchDefaultLabel) statements: _* @body)
760768
=>
761769
(switch_case body: (block stmt: {body}))
762770
),
763-
// A single case item unwraps to its pattern (used as an `or_pattern`
764-
// element).
771+
// A single case item unwraps to its pattern, possibly boxed in conditional_pattern
772+
rule!((switchCaseItem pattern: @p whereClause: (whereClause condition: @cond)) => (conditional_pattern pattern: { p } condition: {cond})),
765773
rule!((switchCaseItem pattern: @p) => pattern { p }),
766774
// A pattern-matching condition (`if case let x = e`, `if case .foo(let x)
767775
// = e`) becomes a `pattern_guard_expr`: the matched pattern and the
@@ -877,17 +885,24 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
877885
body: {body}
878886
catch_clause: {catches})
879887
),
880-
// Catch block with bound identifier; optional where-clause guard.
888+
rule!(
889+
(catchItem pattern: @pattern whereClause: (whereClause condition: @guard))
890+
=>
891+
(conditional_pattern pattern: {pattern} condition: {guard})
892+
),
893+
rule!(
894+
(catchItem pattern: @pattern)
895+
=>
896+
pattern {pattern}
897+
),
898+
// Catch block with one or more patterns (which have been translated by the catchItem rules)
881899
rule!(
882900
(catchClause
883-
catchItems: (catchItem
884-
pattern: @pattern
885-
whereClause: (whereClause condition: @guard)?)
901+
catchItems: _+ @patterns
886902
body: @body)
887903
=>
888904
(catch_clause
889-
pattern: {pattern}
890-
guard: {guard}
905+
pattern: {make_or_pattern(&mut ctx, patterns)}
891906
body: {body})
892907
),
893908
// Catch block without error binding
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
switch n {
2+
case let x where x > 0:
3+
print("positive")
4+
case let y where y < 0, 0:
5+
print("non-positive")
6+
default:
7+
print("other")
8+
}
9+
10+
---
11+
12+
sourceFile
13+
endOfFileToken: endOfFile
14+
statements:
15+
codeBlockItem
16+
item:
17+
expressionStmt
18+
expression:
19+
switchExpr
20+
leftBrace: {
21+
rightBrace: }
22+
cases:
23+
switchCase
24+
label:
25+
switchCaseLabel
26+
colon: :
27+
caseKeyword: case
28+
caseItems:
29+
switchCaseItem
30+
pattern:
31+
valueBindingPattern
32+
pattern:
33+
identifierPattern
34+
identifier: identifier "x"
35+
bindingSpecifier: let
36+
whereClause:
37+
whereClause
38+
condition:
39+
infixOperatorExpr
40+
operator:
41+
binaryOperatorExpr
42+
operator: binaryOperator ">"
43+
leftOperand:
44+
declReferenceExpr
45+
baseName: identifier "x"
46+
rightOperand:
47+
integerLiteralExpr
48+
literal: integerLiteral "0"
49+
whereKeyword: where
50+
statements:
51+
codeBlockItem
52+
item:
53+
functionCallExpr
54+
leftParen: (
55+
rightParen: )
56+
arguments:
57+
labeledExpr
58+
expression:
59+
stringLiteralExpr
60+
closingQuote: "
61+
openingQuote: "
62+
segments:
63+
stringSegment
64+
content: stringSegment "positive"
65+
additionalTrailingClosures:
66+
calledExpression:
67+
declReferenceExpr
68+
baseName: identifier "print"
69+
switchCase
70+
label:
71+
switchCaseLabel
72+
colon: :
73+
caseKeyword: case
74+
caseItems:
75+
switchCaseItem
76+
trailingComma: ,
77+
pattern:
78+
valueBindingPattern
79+
pattern:
80+
identifierPattern
81+
identifier: identifier "y"
82+
bindingSpecifier: let
83+
whereClause:
84+
whereClause
85+
condition:
86+
infixOperatorExpr
87+
operator:
88+
binaryOperatorExpr
89+
operator: binaryOperator "<"
90+
leftOperand:
91+
declReferenceExpr
92+
baseName: identifier "y"
93+
rightOperand:
94+
integerLiteralExpr
95+
literal: integerLiteral "0"
96+
whereKeyword: where
97+
switchCaseItem
98+
pattern:
99+
expressionPattern
100+
expression:
101+
integerLiteralExpr
102+
literal: integerLiteral "0"
103+
statements:
104+
codeBlockItem
105+
item:
106+
functionCallExpr
107+
leftParen: (
108+
rightParen: )
109+
arguments:
110+
labeledExpr
111+
expression:
112+
stringLiteralExpr
113+
closingQuote: "
114+
openingQuote: "
115+
segments:
116+
stringSegment
117+
content: stringSegment "non-positive"
118+
additionalTrailingClosures:
119+
calledExpression:
120+
declReferenceExpr
121+
baseName: identifier "print"
122+
switchCase
123+
label:
124+
switchDefaultLabel
125+
colon: :
126+
defaultKeyword: default
127+
statements:
128+
codeBlockItem
129+
item:
130+
functionCallExpr
131+
leftParen: (
132+
rightParen: )
133+
arguments:
134+
labeledExpr
135+
expression:
136+
stringLiteralExpr
137+
closingQuote: "
138+
openingQuote: "
139+
segments:
140+
stringSegment
141+
content: stringSegment "other"
142+
additionalTrailingClosures:
143+
calledExpression:
144+
declReferenceExpr
145+
baseName: identifier "print"
146+
subject:
147+
declReferenceExpr
148+
baseName: identifier "n"
149+
switchKeyword: switch
150+
151+
---
152+
153+
top_level
154+
body:
155+
block
156+
stmt:
157+
switch_expr
158+
value:
159+
name_expr
160+
identifier: identifier "n"
161+
case:
162+
switch_case
163+
pattern:
164+
conditional_pattern
165+
condition:
166+
binary_expr
167+
left:
168+
name_expr
169+
identifier: identifier "x"
170+
operator: infix_operator ">"
171+
right: int_literal "0"
172+
pattern:
173+
name_pattern
174+
identifier: identifier "x"
175+
body:
176+
block
177+
stmt:
178+
call_expr
179+
callee:
180+
name_expr
181+
identifier: identifier "print"
182+
argument:
183+
argument
184+
value: string_literal "\"positive\""
185+
switch_case
186+
pattern:
187+
or_pattern
188+
pattern:
189+
conditional_pattern
190+
condition:
191+
binary_expr
192+
left:
193+
name_expr
194+
identifier: identifier "y"
195+
operator: infix_operator "<"
196+
right: int_literal "0"
197+
pattern:
198+
name_pattern
199+
identifier: identifier "y"
200+
expr_equality_pattern
201+
expr: int_literal "0"
202+
body:
203+
block
204+
stmt:
205+
call_expr
206+
callee:
207+
name_expr
208+
identifier: identifier "print"
209+
argument:
210+
argument
211+
value: string_literal "\"non-positive\""
212+
switch_case
213+
body:
214+
block
215+
stmt:
216+
call_expr
217+
callee:
218+
name_expr
219+
identifier: identifier "print"
220+
argument:
221+
argument
222+
value: string_literal "\"other\""
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
switch n {
2+
case let x where x > 0:
3+
print("positive")
4+
case let y where y < 0, 0:
5+
print("non-positive")
6+
default:
7+
print("other")
8+
}

0 commit comments

Comments
 (0)