Skip to content

Commit 443e437

Browse files
committed
Fix parsing of variable names quoted with backticks, and allow variable attributes to be accessed by name
1 parent 9b2670c commit 443e437

File tree

9 files changed

+202
-170
lines changed

9 files changed

+202
-170
lines changed

Sources/MacroToolkit/Documentation.docc/Destructuring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ attribute lists, etc.). Lets use destructuring to parse an argument list.
4848
```swift
4949
// We're expecting exactly two arguments; a name and an age
5050
guard
51-
let (nameExpr, ageExpr) = attribute.arguments,
51+
let ((nil, nameExpr), (nil, ageExpr)) = destructure(attribute.arguments),
5252
let name = nameExpr.asStringLiteral?.value,
5353
let age = ageExpr.asIntegerLiteral?.value
5454
else {

Sources/MacroToolkit/Expr.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import SwiftSyntax
22

3+
// TODO: Create wrapper for tuple syntax
34
/// Wraps an expression syntax node.
45
public struct Expr {
56
/// The underlying syntax node.

Sources/MacroToolkit/Function.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public struct Function {
4545
case .attribute(let attributeSyntax):
4646
return .attribute(Attribute(attributeSyntax))
4747
case .ifConfigDecl(let ifConfigDeclSyntax):
48-
return .conditionalCompilationBlock(ConditionalCompilationBlock(ifConfigDeclSyntax))
48+
return .conditionalCompilationBlock(
49+
ConditionalCompilationBlock(ifConfigDeclSyntax))
4950
}
5051
}
5152
}

Sources/MacroToolkit/MacroAttribute.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@ public struct MacroAttribute {
2323
/// Gets the argument with the given label.
2424
public func argument(labeled label: String) -> Expr? {
2525
(_argumentListSyntax?.first { element in
26-
return element.label?.text == label
26+
element.label?.text == label
2727
}?.expression).map(Expr.init)
2828
}
2929

30-
// TODO: Include labels alongside each argument, and add way to conditionally get arguments without labels if no labels are present.
30+
// TODO: Add way to conditionally get arguments without labels if no labels are present.
3131
// This is required because most of the time when matching against the list of arguments, macro authors will want to ensure there
3232
// are no random extraenous labels.
3333
/// Gets the list of all of the attribute's arguments.
34-
public var arguments: [Expr] {
34+
public var arguments: [(label: String?, expr: Expr)] {
3535
guard let argumentList = _argumentListSyntax else {
3636
return []
3737
}
3838
return Array(argumentList).map { argument in
39-
Expr(argument.expression)
39+
(label: argument.label?.text, expr: Expr(argument.expression))
4040
}
4141
}
4242

Sources/MacroToolkit/Variable.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ public struct Variable {
4444
}
4545
}
4646

47+
/// Returns the attribute with the given name if the declaration has such an attribute.
48+
public func attribute(named name: String) -> Attribute? {
49+
for element in attributes {
50+
guard case let .attribute(attribute) = element else {
51+
continue
52+
}
53+
if attribute.name.name == name {
54+
return attribute
55+
}
56+
}
57+
return nil
58+
}
59+
4760
/// Determines whether the variable has the syntax of a stored property.
4861
///
4962
/// This syntactic check cannot account for semantic adjustments due to,

Sources/MacroToolkit/VariableBinding.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Foundation
12
import SwiftSyntax
23

34
/// A variable binding (e.g. the `a: Int = 3` part of `var a: Int = 3`)
@@ -36,7 +37,8 @@ public struct VariableBinding {
3637
///
3738
/// For example, the binding `(a, b) = (1, 2)` doesn't have an `identifier`.
3839
public var identifier: String? {
39-
_syntax.pattern.as(IdentifierPatternSyntax.self)?.identifier.text
40+
let identifier = _syntax.pattern.as(IdentifierPatternSyntax.self)?.identifier.text
41+
return identifier?.trimmingCharacters(in: CharacterSet(arrayLiteral: "`"))
4042
}
4143

4244
/// The type annotation supplied for the binding if any (e.g. the `Int` in `a: Int`).

Sources/MacroToolkitExamplePlugin/AddAsyncMacro.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ public struct AddAsyncMacro: PeerMacro {
7676
}
7777
"""
7878

79-
let continuationExpr = isResultReturn
80-
? "try await withCheckedThrowingContinuation { continuation in"
81-
: "await withCheckedContinuation { continuation in"
79+
let continuationExpr =
80+
isResultReturn
81+
? "try await withCheckedThrowingContinuation { continuation in"
82+
: "await withCheckedContinuation { continuation in"
8283

8384
let newBody: ExprSyntax =
8485
"""

Sources/MacroToolkitExamplePlugin/CustomCodableMacro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public struct CustomCodableMacro: MemberMacro {
1919
if let customKeyMacro = variable.attributes.first(called: "CodableKey") {
2020
guard
2121
let attribute = customKeyMacro.asMacroAttribute,
22-
let customKeyValue = destructureSingle(attribute.arguments)
22+
let customKeyValue = destructureSingle(attribute.arguments.map(\.expr))
2323
else {
2424
return nil
2525
}

0 commit comments

Comments
 (0)