Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syntactic macro system #969

Merged
merged 25 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b83ae36
Add nodes to describe general macro expansions
DougGregor Sep 15, 2022
300b844
Regenerate syntax nodes
DougGregor Oct 15, 2022
f00847d
Parse macro expansion expressions
DougGregor Sep 15, 2022
97adb1e
Parse a macro expansion as a declaration
DougGregor Oct 15, 2022
df54256
Add the basic shell of a SwiftSyntaxMacros package.
rxwei Oct 13, 2022
d581342
Introduce a macro system with syntactic rewriting capabilities
DougGregor Oct 15, 2022
e98bd51
Refactor macro expansion logic to make it easier to extend
DougGregor Oct 16, 2022
f1db1b9
Factor out some macro definitions into an example system we can use
DougGregor Oct 16, 2022
4482f08
Add a #colorLiteral-like macro
DougGregor Oct 16, 2022
23a28a6
[swift-parser-cli] Add an expand-macros subcommand to swift-parser-cli
DougGregor Oct 16, 2022
d7c3938
Document how to use and experiment with the SwiftSyntaxMacros module
DougGregor Oct 16, 2022
cb7b9f3
Have MacroApplication rely entirely on Syntax.evaluateMacro.
DougGregor Oct 17, 2022
3c9d14b
Update a few tests to match expected output
DougGregor Oct 18, 2022
5efd552
Rename "macro expansion" nodes to "pound literal"
DougGregor Oct 18, 2022
a868f1d
Regenerate for syntax node name change
DougGregor Oct 18, 2022
22b87b2
Update tests for macro expansion node name change
DougGregor Oct 18, 2022
20ff3b6
[Parser] Stop producing PoundLineExprSyntax nodes.
DougGregor Oct 18, 2022
f228056
Rename `#myLine` to `#line` now that it's just a normal macro
DougGregor Oct 18, 2022
0db788c
Stop parsing into PoundColumnExprSyntax, add a macro instead
DougGregor Oct 18, 2022
646870d
Stop parsing into PoundDsohandleExprSyntax.
DougGregor Oct 18, 2022
948fcd9
[Parser] Replace `#function` with a macro.
DougGregor Oct 18, 2022
85af5e9
[Parser] Stop parsing `#colorLiteral`, `#fileLiteral`, and `#imageLit…
DougGregor Oct 18, 2022
ba10173
[Parser] Stop creating `PoundFile(ID|Path|)Syntax` nodes.
DougGregor Oct 18, 2022
38d7dfc
Implement macros for #file/#fileID/#filePath
DougGregor Oct 18, 2022
5c02eb5
Underscore _SwiftSyntaxMacros because it is So Very Experimental
DougGregor Oct 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1500,4 +1500,43 @@ public let DECL_NODES: [Node] = [
])
]),

Node(name: "MacroExpansionDecl",
nameForDiagnostics: "pound literal declaration",
kind: "Decl",
children: [
Child(name: "PoundToken",
kind: "PoundToken",
description: "The `#` sign.",
tokenChoices: [
"Pound"
]),
Child(name: "Macro",
kind: "IdentifierToken",
tokenChoices: [
"Identifier"
]),
Child(name: "LeftParen",
kind: "LeftParenToken",
isOptional: true,
tokenChoices: [
"LeftParen"
]),
Child(name: "ArgumentList",
kind: "TupleExprElementList",
collectionElementName: "Argument"),
Child(name: "RightParen",
kind: "RightParenToken",
isOptional: true,
tokenChoices: [
"RightParen"
]),
Child(name: "TrailingClosure",
kind: "ClosureExpr",
isOptional: true),
Child(name: "AdditionalTrailingClosures",
kind: "MultipleTrailingClosureElementList",
isOptional: true,
collectionElementName: "AdditionalTrailingClosure")
]),

]
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,45 @@ public let EXPR_NODES: [Node] = [
])
]),

Node(name: "MacroExpansionExpr",
nameForDiagnostics: "pound literal expression",
kind: "Expr",
children: [
Child(name: "PoundToken",
kind: "PoundToken",
description: "The `#` sign.",
tokenChoices: [
"Pound"
]),
Child(name: "Macro",
kind: "IdentifierToken",
tokenChoices: [
"Identifier"
]),
Child(name: "LeftParen",
kind: "LeftParenToken",
isOptional: true,
tokenChoices: [
"LeftParen"
]),
Child(name: "ArgumentList",
kind: "TupleExprElementList",
collectionElementName: "Argument"),
Child(name: "RightParen",
kind: "RightParenToken",
isOptional: true,
tokenChoices: [
"RightParen"
]),
Child(name: "TrailingClosure",
kind: "ClosureExpr",
isOptional: true),
Child(name: "AdditionalTrailingClosures",
kind: "MultipleTrailingClosureElementList",
isOptional: true,
collectionElementName: "AdditionalTrailingClosure")
]),

Node(name: "PostfixIfConfigExpr",
nameForDiagnostics: nil,
kind: "Expr",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,6 @@ public let SYNTAX_NODE_SERIALIZATION_CODES: [String: Int] = [
"KeyPathComponentList": 285,
"KeyPathComponent": 286,
"OldKeyPathExpr": 287,
"MacroExpansionExpr": 288,
"MacroExpansionDecl": 289,
]
17 changes: 16 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ let package = Package(
.library(name: "SwiftSyntax", type: .static, targets: ["SwiftSyntax"]),
.library(name: "SwiftSyntaxParser", type: .static, targets: ["SwiftSyntaxParser"]),
.library(name: "SwiftSyntaxBuilder", type: .static, targets: ["SwiftSyntaxBuilder"]),
.library(name: "_SwiftSyntaxMacros", type: .static, targets: ["_SwiftSyntaxMacros"]),
],
targets: [
.target(
Expand Down Expand Up @@ -140,13 +141,21 @@ let package = Package(
"SwiftCompilerSupport.h"
]
),
.target(
name: "_SwiftSyntaxMacros",
dependencies: [
"SwiftSyntax", "SwiftSyntaxBuilder", "SwiftParser", "SwiftDiagnostics"
],
exclude: [
"CMakeLists.txt",
]),
.executableTarget(
name: "lit-test-helper",
dependencies: ["SwiftSyntax", "SwiftSyntaxParser"]
),
.executableTarget(
name: "swift-parser-cli",
dependencies: ["SwiftDiagnostics", "SwiftSyntax", "SwiftParser", "SwiftOperators",
dependencies: ["SwiftDiagnostics", "SwiftSyntax", "SwiftParser", "SwiftOperators", "_SwiftSyntaxMacros",
.product(name: "ArgumentParser", package: "swift-argument-parser")]
),
.testTarget(
Expand All @@ -166,6 +175,12 @@ let package = Package(
dependencies: ["SwiftSyntaxParser", "_SwiftSyntaxTestSupport"],
exclude: ["Inputs"]
),
.testTarget(
name: "SwiftSyntaxMacrosTest",
dependencies: ["SwiftDiagnostics", "SwiftOperators", "SwiftParser",
"_SwiftSyntaxTestSupport", "SwiftSyntaxBuilder",
"_SwiftSyntaxMacros"]
),
.testTarget(
name: "PerformanceTest",
dependencies: ["SwiftSyntax", "SwiftSyntaxParser", "SwiftParser"],
Expand Down
36 changes: 36 additions & 0 deletions Sources/SwiftBasicFormat/generated/BasicFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,24 @@ open class BasicFormat: SyntaxRewriter {
return ExprSyntax(ObjcSelectorExprSyntax(unexpectedBeforePoundSelector, poundSelector: poundSelector, unexpectedBetweenPoundSelectorAndLeftParen, leftParen: leftParen, unexpectedBetweenLeftParenAndKind, kind: kind, unexpectedBetweenKindAndColon, colon: colon, unexpectedBetweenColonAndName, name: name, unexpectedBetweenNameAndRightParen, rightParen: rightParen))
}

open override func visit(_ node: MacroExpansionExprSyntax) -> ExprSyntax {
let unexpectedBeforePoundToken = node.unexpectedBeforePoundToken.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let poundToken = self.visit(node.poundToken).cast(TokenSyntax.self)
let unexpectedBetweenPoundTokenAndMacro = node.unexpectedBetweenPoundTokenAndMacro.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let macro = self.visit(node.macro).cast(TokenSyntax.self)
let unexpectedBetweenMacroAndLeftParen = node.unexpectedBetweenMacroAndLeftParen.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let leftParen = node.leftParen.map(self.visit)?.cast(TokenSyntax.self)
let unexpectedBetweenLeftParenAndArgumentList = node.unexpectedBetweenLeftParenAndArgumentList.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let argumentList = self.visit(node.argumentList).cast(TupleExprElementListSyntax.self)
let unexpectedBetweenArgumentListAndRightParen = node.unexpectedBetweenArgumentListAndRightParen.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let rightParen = node.rightParen.map(self.visit)?.cast(TokenSyntax.self)
let unexpectedBetweenRightParenAndTrailingClosure = node.unexpectedBetweenRightParenAndTrailingClosure.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let trailingClosure = node.trailingClosure.map(self.visit)?.cast(ClosureExprSyntax.self)
let unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures = node.unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let additionalTrailingClosures = node.additionalTrailingClosures.map(self.visit)?.cast(MultipleTrailingClosureElementListSyntax.self)
return ExprSyntax(MacroExpansionExprSyntax(unexpectedBeforePoundToken, poundToken: poundToken, unexpectedBetweenPoundTokenAndMacro, macro: macro, unexpectedBetweenMacroAndLeftParen, leftParen: leftParen, unexpectedBetweenLeftParenAndArgumentList, argumentList: argumentList, unexpectedBetweenArgumentListAndRightParen, rightParen: rightParen, unexpectedBetweenRightParenAndTrailingClosure, trailingClosure: trailingClosure, unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures, additionalTrailingClosures: additionalTrailingClosures))
}

open override func visit(_ node: PostfixIfConfigExprSyntax) -> ExprSyntax {
let unexpectedBeforeBase = node.unexpectedBeforeBase.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let base = node.base.map(self.visit)?.cast(ExprSyntax.self)
Expand Down Expand Up @@ -1575,6 +1593,24 @@ open class BasicFormat: SyntaxRewriter {
return Syntax(PrecedenceGroupAssociativitySyntax(unexpectedBeforeAssociativityKeyword, associativityKeyword: associativityKeyword, unexpectedBetweenAssociativityKeywordAndColon, colon: colon, unexpectedBetweenColonAndValue, value: value))
}

open override func visit(_ node: MacroExpansionDeclSyntax) -> DeclSyntax {
let unexpectedBeforePoundToken = node.unexpectedBeforePoundToken.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let poundToken = self.visit(node.poundToken).cast(TokenSyntax.self)
let unexpectedBetweenPoundTokenAndMacro = node.unexpectedBetweenPoundTokenAndMacro.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let macro = self.visit(node.macro).cast(TokenSyntax.self)
let unexpectedBetweenMacroAndLeftParen = node.unexpectedBetweenMacroAndLeftParen.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let leftParen = node.leftParen.map(self.visit)?.cast(TokenSyntax.self)
let unexpectedBetweenLeftParenAndArgumentList = node.unexpectedBetweenLeftParenAndArgumentList.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let argumentList = self.visit(node.argumentList).cast(TupleExprElementListSyntax.self)
let unexpectedBetweenArgumentListAndRightParen = node.unexpectedBetweenArgumentListAndRightParen.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let rightParen = node.rightParen.map(self.visit)?.cast(TokenSyntax.self)
let unexpectedBetweenRightParenAndTrailingClosure = node.unexpectedBetweenRightParenAndTrailingClosure.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let trailingClosure = node.trailingClosure.map(self.visit)?.cast(ClosureExprSyntax.self)
let unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures = node.unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures.map(self.visit)?.cast(UnexpectedNodesSyntax.self)
let additionalTrailingClosures = node.additionalTrailingClosures.map(self.visit)?.cast(MultipleTrailingClosureElementListSyntax.self)
return DeclSyntax(MacroExpansionDeclSyntax(unexpectedBeforePoundToken, poundToken: poundToken, unexpectedBetweenPoundTokenAndMacro, macro: macro, unexpectedBetweenMacroAndLeftParen, leftParen: leftParen, unexpectedBetweenLeftParenAndArgumentList, argumentList: argumentList, unexpectedBetweenArgumentListAndRightParen, rightParen: rightParen, unexpectedBetweenRightParenAndTrailingClosure, trailingClosure: trailingClosure, unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures, additionalTrailingClosures: additionalTrailingClosures))
}

open override func visit(_ node: TokenListSyntax) -> Syntax {
let formattedChildren = node.children(viewMode: .all).map {
self.visit($0).cast(TokenSyntax.self)
Expand Down
55 changes: 55 additions & 0 deletions Sources/SwiftParser/Declarations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ extension Parser {
return RawDeclSyntax(directive)
case (.poundWarningKeyword, _)?, (.poundErrorKeyword, _)?:
return self.parsePoundDiagnosticDeclaration()
case (.pound, _)?:
return RawDeclSyntax(self.parseMacroExpansionDeclaration())
case nil:
break
}
Expand Down Expand Up @@ -2336,4 +2338,57 @@ extension Parser {
arena: self.arena))
}
}

/// Parse a macro expansion as an declaration.
///
///
/// Grammar
/// =======
///
/// macro-expansion-declaration → '#' identifier expr-call-suffix?
mutating func parseMacroExpansionDeclaration() -> RawMacroExpansionDeclSyntax {
let poundKeyword = self.consumeAnyToken()
let (unexpectedBeforeMacro, macro) = self.expectIdentifier()

// Parse the optional parenthesized argument list.
let leftParen = self.consume(if: .leftParen, where: { !$0.isAtStartOfLine })
let args: [RawTupleExprElementSyntax]
let unexpectedBeforeRightParen: RawUnexpectedNodesSyntax?
let rightParen: RawTokenSyntax?
if leftParen != nil {
args = parseArgumentListElements(pattern: .none)
(unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
} else {
args = []
unexpectedBeforeRightParen = nil
rightParen = nil
}

// Parse the optional trailing closures.
let trailingClosure: RawClosureExprSyntax?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would a macro expansion declaration with a trailing closure look like?

let additionalTrailingClosures: RawMultipleTrailingClosureElementListSyntax?
if self.at(.leftBrace),
self.lookahead().isValidTrailingClosure(.trailingClosure) {
(trailingClosure, additionalTrailingClosures) =
self.parseTrailingClosures(.trailingClosure)
} else {
trailingClosure = nil
additionalTrailingClosures = nil
}

return RawMacroExpansionDeclSyntax(
poundToken: poundKeyword,
unexpectedBeforeMacro,
macro: macro,
leftParen: leftParen,
argumentList: RawTupleExprElementListSyntax(
elements: args, arena: self.arena
),
unexpectedBeforeRightParen,
rightParen: rightParen,
trailingClosure: trailingClosure,
additionalTrailingClosures: additionalTrailingClosures,
arena: self.arena
)
}
}
16 changes: 0 additions & 16 deletions Sources/SwiftParser/Directives.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,6 @@ extension Parser {
}

extension Parser {
/// Parse a #line literal.
///
/// Grammar
/// =======
///
/// literal-expression → '#line'
@_spi(RawSyntax)
public mutating func parsePoundLineDirective() -> RawPoundLineExprSyntax {
let (unexpectedBeforeToken, token) = self.expect(.poundLineKeyword)
return RawPoundLineExprSyntax(
unexpectedBeforeToken,
poundLine: token,
arena: self.arena
)
}

/// Parse a line control directive.
///
/// Grammar
Expand Down