8000 Merge pull request #1979 from StevenWong12/parse_hashbang_as_child_of… · swiftlang/swift-syntax@3eb344c · GitHub
[go: up one dir, main page]

Skip to content

Commit 3eb344c

Browse files
authored
Merge pull request #1979 from StevenWong12/parse_hashbang_as_child_of_sourfile
Parse hashbang as a child of `SourceFileSyntax`
2 parents f695301 + 605a5b8 commit 3eb344c

27 files changed

+166
-105
lines changed

CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,12 @@ public let DECL_NODES: [Node] = [
20052005
parserFunction: "parseSourceFile",
20062006
traits: ["WithStatements"],
20072007
children: [
2008+
Child(
2009+
name: "Shebang",
2010+
kind: .token(choices: [.token(.shebang)]),
2011+
documentation: "A shebang can specify the path of the compiler when using Swift source file as a script.",
2012+
isOptional: true
2013+
),
20082014
Child(
20092015
name: "Statements",
20102016
kind: .collection(kind: .codeBlockItemList, collectionElementName: "Statement")

CodeGeneration/Sources/SyntaxSupport/TokenSpec.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ public enum Token: CaseIterable {
127127
case rightParen
128128
case rightSquare
129129
case semicolon
130+
case shebang
130131
case singleQuote
131132
case stringQuote
132133
case stringSegment
@@ -223,6 +224,8 @@ public enum Token: CaseIterable {
223224
return .punctuator(name: "rightSquare", text: "]")
224225
case .semicolon:
225226
return .punctuator(name: "semicolon", text: ";")
227+
case .shebang:
228+
return .other(name: "shebang", nameForDiagnostics: "shebang")
226229
case .singleQuote:
227230
return .punctuator(name: "singleQuote", text: "\'")
228231
case .stringQuote:

CodeGeneration/Sources/SyntaxSupport/Trivia.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,6 @@ public let TRIVIAS: [Trivia] = [
159159
]
160160
),
161161

162-
Trivia(
163-
name: "Shebang",
164-
comment: #"A script command, starting with '#!'."#
165-
),
166-
167162
Trivia(
168163
name: "Space",
169164
comment: #"A space ' ' character."#,

Sources/SwiftIDEUtils/SyntaxClassification.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ extension RawTokenKind {
180180
return .none
181181
case .semicolon:
182182
return .none
183+
case .shebang:
184+
return .none
183185
case .singleQuote:
184186
return .stringLiteral
185187
case .stringQuote:

Sources/SwiftParser/Lexer/Cursor.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,11 @@ extension Lexer.Cursor {
905905
case UInt8(ascii: "\\"): _ = self.advance(); return Lexer.Result(.backslash)
906906

907907
case UInt8(ascii: "#"):
908+
// Try lex shebang.
909+
if self.isAtStartOfFile, self.peek(at: 1) == UInt8(ascii: "!") {
910+
self.advanceToEndOfLine()
911+
return Lexer.Result(.shebang)
912+
}
908913
// Try lex a raw string literal.
909914
if let delimiterLength = self.advanceIfOpeningRawStringDelimiter() {
910915
return Lexer.Result(.rawStringPoundDelimiter, stateTransition: .push(newState: .afterRawStringDelimiter(delimiterLength: delimiterLength)))
@@ -1171,12 +1176,6 @@ extension Lexer.Cursor {
11711176
default:
11721177
break
11731178
}
1174-
case UInt8(ascii: "#"):
1175-
guard start.isAtStartOfFile, self.advance(if: { $0 == "!" }) else {
1176-
break
1177-
}
1178-
self.advanceToEndOfLine()
1179-
continue
11801179
case UInt8(ascii: "<"), UInt8(ascii: ">"):
11811180
if self.tryLexConflictMarker(start: start) {
11821181
error = LexingDiagnostic(.sourceConflictMarker, position: start)
@@ -1189,6 +1188,7 @@ extension Lexer.Cursor {
11891188
UInt8(ascii: "}"), UInt8(ascii: "]"), UInt8(ascii: ")"),
11901189
UInt8(ascii: "@"), UInt8(ascii: ","), UInt8(ascii: ";"),
11911190
UInt8(ascii: ":"), UInt8(ascii: "\\"), UInt8(ascii: "$"),
1191+
UInt8(ascii: "#"),
11921192

11931193
// Start of integer/hex/float literals.
11941194
UInt8(ascii: "0"), UInt8(ascii: "1"), UInt8(ascii: "2"),

Sources/SwiftParser/Lexer/RegexLiteralLexer.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,10 @@ extension Lexer.Cursor {
625625
case .arrow, .ellipsis, .period, .atSign, .pound, .backtick, .backslash:
626626
return false
627627

628+
// Shebang does not sequence expressions.
629+
case .shebang:
630+
return false
631+
628632
case .keyword:
629633
// There are a handful of keywords that are expressions, handle them.
630634
// Otherwise, a regex literal can generally be parsed after a keyword.

Sources/SwiftParser/TokenPrecedence.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ enum TokenPrecedence: Comparable {
124124
.dollarIdentifier, .identifier,
125125
// '_' can occur in types to replace a type identifier
126126
.wildcard,
127-
// String segment, string interpolation anchor, pound, and regex pattern don't really fit anywhere else
128-
.pound, .stringSegment, .regexLiteralPattern:
127+
// String segment, string interpolation anchor, pound, shebang and regex pattern don't really fit anywhere else
128+
.pound, .stringSegment, .regexLiteralPattern, .shebang:
129129
self = .identifierLike
130130

131131
// MARK: Expr keyword

Sources/SwiftParser/TopLevel.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ extension Parser {
4040
/// ``Parser/parse(source:parseTransition:filenameForDiagnostics:languageVersion:enableBareSlashRegexLiteral:)-7tndx``
4141
/// API calls.
4242
mutating func parseSourceFile() -> RawSourceFileSyntax {
43+
let shebang = self.consume(if: .shebang)
4344
let items = self.parseTopLevelCodeBlockItems()
4445
let unexpectedBeforeEndOfFileToken = consumeRemainingTokens()
4546
let endOfFile = self.consume(if: .endOfFile)!
4647
return .init(
48+
shebang: shebang,
4749
statements: items,
4850
RawUnexpectedNodesSyntax(unexpectedBeforeEndOfFileToken, arena: self.arena),
4951
endOfFileToken: endOfFile,

Sources/SwiftParser/TriviaParser.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,6 @@ public struct TriviaParser {
8181
}
8282

8383
case UInt8(ascii: "#"):
84-
// "#!...": .shebang
85-
// NOTE: .shebang appears only if this trivia is at the start of the
86-
// file. We don't know if this trivia is at the start of the file, but
87-
// we believe that the lexer lexed it accordingly.
88-
if position == .leading && pieces.isEmpty && cursor.advance(if: { $0 == "!" }) {
89-
cursor.advanceToEndOfLine()
90-
pieces.append(.shebang(start.text(upTo: cursor)))
91-
continue
92-
}
9384
cursor.advance(while: { $0 == "#" })
9485
pieces.append(.pounds(start.distance(to: cursor)))
9586
continue

Sources/SwiftParser/generated/TokenSpecStaticMembers.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ extension TokenSpec {
187187
return TokenSpec(.semicolon)
188188
}
189189

190+
static var shebang: TokenSpec {
191+
return TokenSpec(.shebang)
192+
}
193+
190194
static var singleQuote: TokenSpec {
191195
return TokenSpec(.singleQuote)
192196
}

0 commit comments

Comments
 (0)
0