Skip to content

Commit f14a6e1

Browse files
committed
Parse unsafe expression
1 parent 070818d commit f14a6e1

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

Sources/SwiftOperators/OperatorTable+Folding.swift

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#if compiler(>=6)
14-
public import SwiftSyntax
14+
@_spi(ExperimentalLanguageFeatures) public import SwiftSyntax
1515
#else
16-
import SwiftSyntax
16+
@_spi(ExperimentalLanguageFeatures) import SwiftSyntax
1717
#endif
1818

1919
extension ExprSyntax {
@@ -104,8 +104,8 @@ extension OperatorTable {
104104
op: ExprSyntax,
105105
rhs: ExprSyntax
106106
) -> ExprSyntax {
107-
// If the left-hand side is a "try" or "await", hoist it up to encompass
108-
// the right-hand side as well.
107+
// If the left-hand side is a "try", "await", or "unsafe", hoist it up to
108+
// encompass the right-hand side as well.
109109
if let tryExpr = lhs.as(TryExprSyntax.self) {
110110
return ExprSyntax(
111111
TryExprSyntax(
@@ -138,6 +138,24 @@ extension OperatorTable {
138138
)
139139
}
140140

141+
if let unsafeExpr = lhs.as(UnsafeExprSyntax.self) {
142+
return ExprSyntax(
143+
UnsafeExprSyntax(
144+
leadingTrivia: unsafeExpr.leadingTrivia,
145+
unsafeExpr.unexpectedBeforeUnsafeKeyword,
146+
unsafeKeyword: unsafeExpr.unsafeKeyword,
147+
unsafeExpr.unexpectedBetweenUnsafeKeywordAndExpression,
148+
expression: makeBinaryOperationExpr(
149+
lhs: unsafeExpr.expression,
150+
op: op,
151+
rhs: rhs
152+
),
153+
unsafeExpr.unexpectedAfterExpression,
154+
trailingTrivia: unsafeExpr.trailingTrivia
155+
)
156+
)
157+
}
158+
141159
// The form of the binary operation depends on the operator itself,
142160
// which will be one of the unresolved infix operators.
143161

Sources/SwiftParser/Expressions.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,19 @@ extension Parser {
444444
arena: self.arena
445445
)
446446
)
447+
case (.unsafe, let handle)?:
448+
let unsafeTok = self.eat(handle)
449+
let sub = self.parseSequenceExpressionElement(
450+
flavor: flavor,
451+
pattern: pattern
452+
)
453+
return RawExprSyntax(
454+
RawUnsafeExprSyntax(
455+
unsafeKeyword: unsafeTok,
456+
expression: sub,
457+
arena: self.arena
458+
)
459+
)
447460
case (._move, let handle)?:
448461
let moveKeyword = self.eat(handle)
449462
let sub = self.parseSequenceExpressionElement(

Sources/SwiftParser/TokenSpecSet.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ enum ExpressionModifierKeyword: TokenSpecSet {
700700
case `repeat`
701701
case each
702702
case any
703+
case unsafe
703704

704705
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
705706
switch PrepareForKeywordMatch(lexeme) {
@@ -713,6 +714,7 @@ enum ExpressionModifierKeyword: TokenSpecSet {
713714
case TokenSpec(.repeat): self = .repeat
714715
case TokenSpec(.each): self = .each
715716
case TokenSpec(.any): self = .any
717+
case TokenSpec(.unsafe) where experimentalFeatures.contains(.unsafeExpression): self = .unsafe
716718
default: return nil
717719
}
718720
}
@@ -729,6 +731,7 @@ enum ExpressionModifierKeyword: TokenSpecSet {
729731
case .repeat: return .keyword(.repeat)
730732
case .each: return .keyword(.each)
731733
case .any: return .keyword(.any)
734+
case .unsafe: return .keyword(.unsafe)
732735
}
733736
}
734737
}

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,6 +2188,40 @@ final class StatementExpressionTests: ParserTestCase {
21882188
)
21892189
}
21902190

2191+
func testUnsafeExpr() {
2192+
assertParse(
2193+
"""
2194+
func f() {
2195+
let x = unsafe y
2196+
}
2197+
""",
2198+
experimentalFeatures: .unsafeExpression
2199+
)
2200+
2201+
assertParse(
2202+
"""
2203+
func f() {
2204+
let x = unsafe1️⃣ y
2205+
}
2206+
""",
2207+
diagnostics: [
2208+
DiagnosticSpec(
2209+
message: "consecutive statements on a line must be separated by newline or ';'",
2210+
fixIts: [
2211+
"insert newline",
2212+
"insert ';'",
2213+
]
2214+
)
2215+
],
2216+
fixedSource: """
2217+
func f() {
2218+
let x = unsafe
2219+
y
2220+
}
2221+
"""
2222+
)
2223+
}
2224+
21912225
func testUnterminatedInterpolationAtEndOfMultilineStringLiteral() {
21922226
assertParse(
21932227
#"""

0 commit comments

Comments
 (0)