diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0023a53
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.DS_Store
+/.build
+/Packages
+xcuserdata/
+DerivedData/
+.swiftpm/configuration/registries.json
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+.netrc
diff --git a/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..0c4aab6
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,52 @@
+// swift-tools-version: 5.9
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+import CompilerPluginSupport
+
+let package = Package(
+ name: "CopyableMacro",
+ 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: "CopyableMacro",
+ targets: ["CopyableMacro"]
+ ),
+ .executable(
+ name: "CopyableMacroClient",
+ targets: ["CopyableMacroClient"]
+ ),
+ ],
+ dependencies: [
+ // Depend on the Swift 5.9 release of SwiftSyntax
+ .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"),
+ ],
+ 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: "CopyableMacroMacros",
+ 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: "CopyableMacro", dependencies: ["CopyableMacroMacros"]),
+
+ // A client of the library, which is able to use the macro in its own code.
+ .executableTarget(name: "CopyableMacroClient", dependencies: ["CopyableMacro"]),
+
+ // A test target used to develop the macro implementation.
+ .testTarget(
+ name: "CopyableMacroTests",
+ dependencies: [
+ "CopyableMacroMacros",
+ .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
+ ]
+ ),
+ ]
+)
diff --git a/Sources/CopyableMacro/CopyableMacro.swift b/Sources/CopyableMacro/CopyableMacro.swift
new file mode 100644
index 0000000..a394735
--- /dev/null
+++ b/Sources/CopyableMacro/CopyableMacro.swift
@@ -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(_ value: T) -> (T, String) = #externalMacro(module: "CopyableMacroMacros", type: "StringifyMacro")
\ No newline at end of file
diff --git a/Sources/CopyableMacroClient/main.swift b/Sources/CopyableMacroClient/main.swift
new file mode 100644
index 0000000..6b0b2ba
--- /dev/null
+++ b/Sources/CopyableMacroClient/main.swift
@@ -0,0 +1,8 @@
+import CopyableMacro
+
+let a = 17
+let b = 25
+
+let (result, code) = #stringify(a + b)
+
+print("The value \(result) was produced by the code \"\(code)\"")
diff --git a/Sources/CopyableMacroMacros/CopyableMacroMacro.swift b/Sources/CopyableMacroMacros/CopyableMacroMacro.swift
new file mode 100644
index 0000000..4859e60
--- /dev/null
+++ b/Sources/CopyableMacroMacros/CopyableMacroMacro.swift
@@ -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.argumentList.first?.expression else {
+ fatalError("compiler bug: the macro does not have any arguments")
+ }
+
+ return "(\(argument), \(literal: argument.description))"
+ }
+}
+
+@main
+struct CopyableMacroPlugin: CompilerPlugin {
+ let providingMacros: [Macro.Type] = [
+ StringifyMacro.self,
+ ]
+}
diff --git a/Tests/CopyableMacroTests/CopyableMacroTests.swift b/Tests/CopyableMacroTests/CopyableMacroTests.swift
new file mode 100644
index 0000000..e98061b
--- /dev/null
+++ b/Tests/CopyableMacroTests/CopyableMacroTests.swift
@@ -0,0 +1,46 @@
+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(CopyableMacroMacros)
+import CopyableMacroMacros
+
+let testMacros: [String: Macro.Type] = [
+ "stringify": StringifyMacro.self,
+]
+#endif
+
+final class CopyableMacroTests: XCTestCase {
+ func testMacro() throws {
+ #if canImport(CopyableMacroMacros)
+ 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(CopyableMacroMacros)
+ 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
+ }
+}