Skip to content

Commit d7180b9

Browse files
authored
Merge pull request #1453 from hamishknight/outliner
2 parents 7e099ed + 56f6371 commit d7180b9

File tree

5 files changed

+97
-34
lines changed

5 files changed

+97
-34
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,20 +1768,14 @@ extension Parser {
17681768
)
17691769
}
17701770

1771-
var body = [RawCodeBlockItemSyntax]()
1772-
var codeBlockProgress = LoopProgressCondition()
1773-
while !self.at(.rightBrace),
1774-
let newItem = self.parseCodeBlockItem(),
1775-
codeBlockProgress.evaluate(currentToken)
1776-
{
1777-
body.append(newItem)
1778-
}
1771+
let body = parseCodeBlockItemList(until: { $0.at(.rightBrace) })
1772+
17791773
let (unexpectedBeforeRBrace, rbrace) = self.expect(.rightBrace)
17801774
return .getter(
17811775
RawCodeBlockSyntax(
17821776
unexpectedBeforeLBrace,
17831777
leftBrace: lbrace,
1784-
statements: RawCodeBlockItemListSyntax(elements: body, arena: self.arena),
1778+
statements: body,
17851779
unexpectedBeforeRBrace,
17861780
rightBrace: rbrace,
17871781
arena: self.arena

Sources/SwiftParser/Expressions.swift

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,21 +1710,15 @@ extension Parser {
17101710
let signature = self.parseClosureSignatureIfPresent()
17111711

17121712
// Parse the body.
1713-
var elements = [RawCodeBlockItemSyntax]()
1714-
do {
1715-
var loopProgress = LoopProgressCondition()
1716-
while !self.at(.rightBrace), let newItem = self.parseCodeBlockItem(), loopProgress.evaluate(currentToken) {
1717-
elements.append(newItem)
1718-
}
1719-
}
1713+
let elements = parseCodeBlockItemList(until: { $0.at(.rightBrace) })
17201714

17211715
// Parse the closing '}'.
17221716
let (unexpectedBeforeRBrace, rbrace) = self.expect(.rightBrace)
17231717
return RawClosureExprSyntax(
17241718
unexpectedBeforeLBrace,
17251719
leftBrace: lbrace,
17261720
signature: signature,
1727-
statements: RawCodeBlockItemListSyntax(elements: elements, arena: arena),
1721+
statements: elements,
17281722
unexpectedBeforeRBrace,
17291723
rightBrace: rbrace,
17301724
arena: self.arena
@@ -2350,16 +2344,9 @@ extension Parser {
23502344
}
23512345

23522346
mutating func parseSwitchCaseBody() -> RawCodeBlockItemListSyntax {
2353-
var items = [RawCodeBlockItemSyntax]()
2354-
var loopProgress = LoopProgressCondition()
2355-
while !self.at(.rightBrace) && !self.at(.poundEndifKeyword, .poundElseifKeyword, .poundElseKeyword)
2356-
&& !self.withLookahead({ $0.isStartOfConditionalSwitchCases() }),
2357-
let newItem = self.parseCodeBlockItem(),
2358-
loopProgress.evaluate(currentToken)
2359-
{
2360-
items.append(newItem)
2361-
}
2362-
return RawCodeBlockItemListSyntax(elements: items, arena: self.arena)
2347+
parseCodeBlockItemList(until: {
2348+
$0.at(.rightBrace) || $0.at(.poundEndifKeyword, .poundElseifKeyword, .poundElseKeyword) || $0.withLookahead({ $0.isStartOfConditionalSwitchCases() })
2349+
})
23632350
}
23642351

23652352
/// Parse a single switch case clause.

Sources/SwiftParser/TopLevel.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ extension Parser {
5959
}
6060

6161
extension Parser {
62-
mutating func parseCodeBlockItemList(isAtTopLevel: Bool, allowInitDecl: Bool = true, stopCondition: (inout Parser) -> Bool) -> RawCodeBlockItemListSyntax {
62+
mutating func parseCodeBlockItemList(isAtTopLevel: Bool = false, allowInitDecl: Bool = true, until stopCondition: (inout Parser) -> Bool) -> RawCodeBlockItemListSyntax {
6363
var elements = [RawCodeBlockItemSyntax]()
6464
var loopProgress = LoopProgressCondition()
6565
while !stopCondition(&self), loopProgress.evaluate(currentToken) {
@@ -89,7 +89,7 @@ extension Parser {
8989
///
9090
/// top-level-declaration → statements?
9191
mutating func parseTopLevelCodeBlockItems() -> RawCodeBlockItemListSyntax {
92-
return parseCodeBlockItemList(isAtTopLevel: true, stopCondition: { _ in false })
92+
return parseCodeBlockItemList(isAtTopLevel: true, until: { _ in false })
9393
}
9494

9595
/// The optional form of `parseCodeBlock` that checks to see if the parser has
@@ -116,7 +116,7 @@ extension Parser {
116116
/// indented to close this code block or a surrounding context. See `expectRightBrace`.
117117
mutating func parseCodeBlock(introducer: RawTokenSyntax? = nil, allowInitDecl: Bool = true) -> RawCodeBlockSyntax {
118118
let (unexpectedBeforeLBrace, lbrace) = self.expect(.leftBrace)
119-
let itemList = parseCodeBlockItemList(isAtTopLevel: false, allowInitDecl: allowInitDecl, stopCondition: { $0.at(.rightBrace) })
119+
let itemList = parseCodeBlockItemList(allowInitDecl: allowInitDecl, until: { $0.at(.rightBrace) })
120120
let (unexpectedBeforeRBrace, rbrace) = self.expectRightBrace(leftBrace: lbrace, introducer: introducer)
121121

122122
return .init(
@@ -148,7 +148,7 @@ extension Parser {
148148
/// statement → compiler-control-statement
149149
/// statements → statement statements?
150150
@_spi(RawSyntax)
151-
public mutating func parseCodeBlockItem(isAtTopLevel: Bool = false, allowInitDecl: Bool = true) -> RawCodeBlockItemSyntax? {
151+
public mutating func parseCodeBlockItem(isAtTopLevel: Bool, allowInitDecl: Bool) -> RawCodeBlockItemSyntax? {
152152
if let remainingTokens = remainingTokensIfMaximumNestingLevelReached() {
153153
return RawCodeBlockItemSyntax(
154154
remainingTokens,
@@ -229,7 +229,7 @@ extension Parser {
229229
// If config of attributes is parsed as part of declaration parsing as it
230230
// doesn't constitute its own code block item.
231231
let directive = self.parsePoundIfDirective { (parser, _) in
232-
parser.parseCodeBlockItem()
232+
parser.parseCodeBlockItem(isAtTopLevel: isAtTopLevel, allowInitDecl: allowInitDecl)
233233
} addSemicolonIfNeeded: { lastElement, newItemAtStartOfLine, parser in
234234
if lastElement.semicolon == nil && !newItemAtStartOfLine {
235235
return RawCodeBlockItemSyntax(

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,87 @@ final class StatementExpressionTests: XCTestCase {
18301830
)
18311831
}
18321832

1833+
func testConsecutiveStatements1() {
1834+
assertParse(
1835+
"{a1️⃣ b2️⃣ c}",
1836+
diagnostics: [
1837+
DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'"),
1838+
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'"),
1839+
]
1840+
)
1841+
}
1842+
1843+
func testConsecutiveStatements2() {
1844+
assertParse(
1845+
"switch x {case y: a1️⃣ b2️⃣ c}",
1846+
diagnostics: [
1847+
DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'"),
1848+
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'"),
1849+
]
1850+
)
1851+
}
1852+
1853+
func testConsecutiveStatements3() {
1854+
assertParse(
1855+
"""
1856+
var i: Int { a1️⃣ b2️⃣ c }
1857+
""",
1858+
diagnostics: [
1859+
DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'"),
1860+
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'"),
1861+
]
1862+
)
1863+
}
1864+
1865+
func testConsecutiveStatements4() {
1866+
assertParse(
1867+
"""
1868+
var i: Int { get {a1️⃣ b} set {c2️⃣ d} }
1869+
""",
1870+
diagnostics: [
1871+
DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'"),
1872+
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'"),
1873+
]
1874+
)
1875+
}
1876+
1877+
func testInitCallInPoundIf() {
1878+
// Make sure we parse 'init()' as an expr, not a decl.
1879+
assertParse(
1880+
"""
1881+
class C {
1882+
init() {
1883+
#if true
1884+
init()
1885+
#endif
1886+
}
1887+
}
1888+
""",
1889+
substructure: Syntax(
1890+
FunctionCallExprSyntax(
1891+
calledExpression: IdentifierExprSyntax(identifier: .keyword(.init("init")!)),
1892+
leftParen: .leftParenToken(),
1893+
argumentList: TupleExprElementListSyntax([]),
1894+
rightParen: .rightParenToken()
1895+
)
1896+
)
1897+
)
1898+
}
1899+
1900+
func testUnexpectedCloseBraceInPoundIf() {
1901+
assertParse(
1902+
"""
1903+
#if true
1904+
1️⃣}
1905+
class C {}
1906+
#endif
1907+
""",
1908+
diagnostics: [
1909+
DiagnosticSpec(message: "unexpected brace before class")
1910+
]
1911+
)
1912+
}
1913+
18331914
func testStringLiteralAfterKeyPath() {
18341915
assertParse(
18351916
#"""

Tests/SwiftParserTest/translated/InvalidTests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ final class InvalidTests: XCTestCase {
162162
1️⃣let y = "foo"
163163
switch y {
164164
case "bar":
165-
blah blah // ignored
165+
blah2️⃣ blah // ignored
166166
}
167167
case "baz":
168168
break
@@ -174,7 +174,8 @@ final class InvalidTests: XCTestCase {
174174
}
175175
"""#,
176176
diagnostics: [
177-
DiagnosticSpec(message: "all statements inside a switch must be covered by a 'case' or 'default' label")
177+
DiagnosticSpec(locationMarker: "1️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label"),
178+
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'"),
178179
]
179180
)
180181
}

0 commit comments

Comments
 (0)