-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0c80ccc
Showing
6 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
xcuserdata/ | ||
DerivedData/ | ||
.swiftpm/configuration/registries.json | ||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata | ||
.netrc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// swift-tools-version: 6.0 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
import CompilerPluginSupport | ||
|
||
let package = Package( | ||
name: "Mocked", | ||
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6), .macCatalyst(.v13)], | ||
products: [ | ||
// Products define the executables and libraries a package produces, making them visible to other packages. | ||
.library( | ||
name: "Mocked", | ||
targets: ["Mocked"] | ||
), | ||
.executable( | ||
name: "MockedClient", | ||
targets: ["MockedClient"] | ||
), | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.0-latest"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package, defining a module or a test suite. | ||
// Targets can depend on other targets in this package and products from dependencies. | ||
// Macro implementation that performs the source transformation of a macro. | ||
.macro( | ||
name: "MockedMacros", | ||
dependencies: [ | ||
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"), | ||
.product(name: "SwiftCompilerPlugin", package: "swift-syntax") | ||
] | ||
), | ||
|
||
// Library that exposes a macro as part of its API, which is used in client programs. | ||
.target(name: "Mocked", dependencies: ["MockedMacros"]), | ||
|
||
// A client of the library, which is able to use the macro in its own code. | ||
.executableTarget(name: "MockedClient", dependencies: ["Mocked"]), | ||
|
||
// A test target used to develop the macro implementation. | ||
.testTarget( | ||
name: "MockedTests", | ||
dependencies: [ | ||
"MockedMacros", | ||
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), | ||
] | ||
), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// The Swift Programming Language | ||
// https://docs.swift.org/swift-book | ||
|
||
/// A macro that produces both a value and a string containing the | ||
/// source code that generated the value. For example, | ||
/// | ||
/// #stringify(x + y) | ||
/// | ||
/// produces a tuple `(x + y, "x + y")`. | ||
@freestanding(expression) | ||
public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MockedMacros", type: "StringifyMacro") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import Mocked | ||
|
||
let a = 17 | ||
let b = 25 | ||
|
||
let (result, code) = #stringify(a + b) | ||
|
||
print("The value \(result) was produced by the code \"\(code)\"") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import SwiftCompilerPlugin | ||
import SwiftSyntax | ||
import SwiftSyntaxBuilder | ||
import SwiftSyntaxMacros | ||
|
||
/// Implementation of the `stringify` macro, which takes an expression | ||
/// of any type and produces a tuple containing the value of that expression | ||
/// and the source code that produced the value. For example | ||
/// | ||
/// #stringify(x + y) | ||
/// | ||
/// will expand to | ||
/// | ||
/// (x + y, "x + y") | ||
public struct StringifyMacro: ExpressionMacro { | ||
public static func expansion( | ||
of node: some FreestandingMacroExpansionSyntax, | ||
in context: some MacroExpansionContext | ||
) -> ExprSyntax { | ||
guard let argument = node.arguments.first?.expression else { | ||
fatalError("compiler bug: the macro does not have any arguments") | ||
} | ||
|
||
return "(\(argument), \(literal: argument.description))" | ||
} | ||
} | ||
|
||
@main | ||
struct MockedPlugin: CompilerPlugin { | ||
let providingMacros: [Macro.Type] = [ | ||
StringifyMacro.self, | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import SwiftSyntax | ||
import SwiftSyntaxBuilder | ||
import SwiftSyntaxMacros | ||
import SwiftSyntaxMacrosTestSupport | ||
import XCTest | ||
|
||
// Macro implementations build for the host, so the corresponding module is not available when cross-compiling. Cross-compiled tests may still make use of the macro itself in end-to-end tests. | ||
#if canImport(MockedMacros) | ||
import MockedMacros | ||
|
||
let testMacros: [String: Macro.Type] = [ | ||
"stringify": StringifyMacro.self, | ||
] | ||
#endif | ||
|
||
final class MockedTests: XCTestCase { | ||
func testMacro() throws { | ||
#if canImport(MockedMacros) | ||
assertMacroExpansion( | ||
""" | ||
#stringify(a + b) | ||
""", | ||
expandedSource: """ | ||
(a + b, "a + b") | ||
""", | ||
macros: testMacros | ||
) | ||
#else | ||
throw XCTSkip("macros are only supported when running tests for the host platform") | ||
#endif | ||
} | ||
|
||
func testMacroWithStringLiteral() throws { | ||
#if canImport(MockedMacros) | ||
assertMacroExpansion( | ||
#""" | ||
#stringify("Hello, \(name)") | ||
"""#, | ||
expandedSource: #""" | ||
("Hello, \(name)", #""Hello, \(name)""#) | ||
"""#, | ||
macros: testMacros | ||
) | ||
#else | ||
throw XCTSkip("macros are only supported when running tests for the host platform") | ||
#endif | ||
} | ||
} |