Skip to content

Commit be4c23c

Browse files
committed
Parse macro declarations
1 parent 05518d0 commit be4c23c

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ extension TokenConsumer {
102102
return false
103103
case .initKeyword:
104104
return allowInitDecl
105+
case .macroContextualKeyword:
106+
// macro Foo ...
107+
return subparser.peek().tokenKind == .identifier
105108
case .some(_):
106109
// All other decl start keywords unconditonally start a decl.
107110
return true
@@ -149,6 +152,7 @@ extension Parser {
149152
/// declaration → subscript-declaration
150153
/// declaration → operator-declaration
151154
/// declaration → precedence-group-declaration
155+
/// declaration → macro-declaration
152156
///
153157
/// declarations → declaration declarations?
154158
///
@@ -236,6 +240,8 @@ extension Parser {
236240
return RawDeclSyntax(self.parsePrecedenceGroupDeclaration(attrs, handle))
237241
case (.actorContextualKeyword, let handle)?:
238242
return RawDeclSyntax(self.parseNominalTypeDeclaration(for: RawActorDeclSyntax.self, attrs: attrs, introucerHandle: handle))
243+
case (.macroContextualKeyword, let handle)?:
244+
return RawDeclSyntax(self.parseMacroDeclaration(attrs: attrs, introducerHandle: handle))
239245
case nil:
240246
if inMemberDeclList {
241247
let isProbablyVarDecl = self.at(any: [.identifier, .wildcardKeyword]) && self.peek().tokenKind.is(any: [.colon, .equal, .comma])
@@ -2007,6 +2013,65 @@ extension Parser {
20072013
}
20082014
}
20092015

2016+
/// Parse a macro declaration.
2017+
mutating func parseMacroDeclaration(
2018+
attrs: DeclAttributes,
2019+
introducerHandle: RecoveryConsumptionHandle
2020+
) -> RawMacroDeclSyntax {
2021+
let (unexpectedBeforeIntroducerKeyword, introducerKeyword) = self.eat(introducerHandle)
2022+
let (unexpectedBeforeName, name) = self.expectIdentifier(keywordRecovery: true)
2023+
2024+
// Optional generic parameters.
2025+
let genericParams: RawGenericParameterClauseSyntax?
2026+
if self.currentToken.starts(with: "<") {
2027+
genericParams = self.parseGenericParameters()
2028+
} else {
2029+
genericParams = nil
2030+
}
2031+
2032+
// Macro signature, which is either value-like or function-like.
2033+
let signature: RawMacroDeclSyntax.Signature
2034+
if let colon = self.consume(if: .colon) {
2035+
let type = self.parseType()
2036+
signature = .valueLike(
2037+
RawTypeAnnotationSyntax(colon: colon, type: type, arena: self.arena))
2038+
} else {
2039+
signature = .functionLike(self.parseFunctionSignature())
2040+
}
2041+
2042+
// External macro name
2043+
let (unexpectedBeforeEqual, equal) = self.expect(.equal)
2044+
let (unexpectedBeforeModuleName, moduleName) = self.expectIdentifier()
2045+
let (unexpectedBeforePeriod, period) = self.expect(.period)
2046+
let (unexpectedBeforeMacroTypeName, macroTypeName) = self.expectIdentifier()
2047+
2048+
let externalMacroName = RawExternalMacroNameSyntax(
2049+
unexpectedBeforeModuleName, moduleName: moduleName,
2050+
unexpectedBeforePeriod, period: period,
2051+
unexpectedBeforeMacroTypeName, macroTypeName: macroTypeName,
2052+
arena: self.arena
2053+
)
2054+
2055+
// Parse a 'where' clause if present.
2056+
let whereClause: RawGenericWhereClauseSyntax?
2057+
if self.at(.whereKeyword) {
2058+
whereClause = self.parseGenericWhereClause()
2059+
} else {
2060+
whereClause = nil
2061+
}
2062+
2063+
return RawMacroDeclSyntax(
2064+
attributes: attrs.attributes, modifiers: attrs.modifiers,
2065+
unexpectedBeforeIntroducerKeyword, macroKeyword: introducerKeyword,
2066+
unexpectedBeforeName, identifier: name,
2067+
genericParameterClause: genericParams,
2068+
signature: signature, unexpectedBeforeEqual, equal: equal,
2069+
externalName: externalMacroName,
2070+
genericWhereClause: whereClause,
2071+
arena: self.arena
2072+
)
2073+
}
2074+
20102075
/// Parse a macro expansion as an declaration.
20112076
///
20122077
///

Sources/SwiftParser/RawTokenKindSubset.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ enum DeclarationStart: RawTokenKindSubset {
322322
case importKeyword
323323
case initKeyword
324324
case letKeyword
325+
case macroContextualKeyword
325326
case operatorKeyword
326327
case precedencegroupKeyword
327328
case protocolKeyword
@@ -333,6 +334,7 @@ enum DeclarationStart: RawTokenKindSubset {
333334
init?(lexeme: Lexer.Lexeme) {
334335
switch lexeme.tokenKind {
335336
case .identifier where lexeme.tokenText == "actor": self = .actorContextualKeyword
337+
case .identifier where lexeme.tokenText == "macro": self = .macroContextualKeyword
336338
case .associatedtypeKeyword: self = .associatedtypeKeyword
337339
case .caseKeyword: self = .caseKeyword
338340
case .classKeyword: self = .classKeyword
@@ -367,6 +369,7 @@ enum DeclarationStart: RawTokenKindSubset {
367369
case .importKeyword: return .importKeyword
368370
case .initKeyword: return .initKeyword
369371
case .letKeyword: return .letKeyword
372+
case .macroContextualKeyword: return .identifier
370373
case .operatorKeyword: return .operatorKeyword
371374
case .precedencegroupKeyword: return .precedencegroupKeyword
372375
case .protocolKeyword: return .protocolKeyword
@@ -380,6 +383,7 @@ enum DeclarationStart: RawTokenKindSubset {
380383
var contextualKeyword: SyntaxText? {
381384
switch self {
382385
case .actorContextualKeyword: return "actor"
386+
case .macroContextualKeyword: return "macro"
383387
default: return nil
384388
}
385389
}
@@ -388,6 +392,7 @@ enum DeclarationStart: RawTokenKindSubset {
388392
switch self {
389393
case .actorContextualKeyword: return .declKeyword
390394
case .caseKeyword: return .declKeyword
395+
case .macroContextualKeyword: return .declKeyword
391396
default: return nil
392397
}
393398
}

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,25 @@ final class DeclarationTests: XCTestCase {
13221322

13231323
AssertParse("func foo(body: (isolated String) -> Int) {}")
13241324
}
1325+
1326+
func testMacroDecl() {
1327+
AssertParse("""
1328+
macro m1: Int = A.M1
1329+
macro m2(_: Int) = A.M2
1330+
macro m3(a b: Int) -> Int = A.M3
1331+
macro m4<T>: T = A.M4 where T.Assoc: P
1332+
macro m4<T: P>(_: T) = A.M4
1333+
""")
1334+
1335+
AssertParse("""
1336+
macro m1 1️⃣= A2️⃣
1337+
""",
1338+
diagnostics: [
1339+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected parameter clause in function signature"),
1340+
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '.' and macro type name in external macro name"),
1341+
]
1342+
)
1343+
}
13251344
}
13261345

13271346
extension Parser.DeclAttributes {

0 commit comments

Comments
 (0)