Skip to content

Commit

Permalink
Basic macro setup (#41)
Browse files Browse the repository at this point in the history
Introduces the first macro `@EnvironmentObservable` that removes code
that is repeatable, and similar to swift `@Observable`

```swift 
@EnvironmentObservable
final class Notes {
    @Persistent
    var name: String = ""
    
    var count: Int = 0
}
```


will expand to:
<img width="734" alt="Screenshot 2023-12-31 at 13 57 02"
src="https://github.com/MaximBazarov/Decide/assets/11208417/3f18a119-f2fb-44dd-afa9-2ba356771178">
  • Loading branch information
MaximBazarov authored Jan 5, 2024
1 parent ffc2901 commit f96cb9d
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 4 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/swift-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ jobs:
build:
runs-on: macos-13
steps:
- uses: swift-actions/setup-swift@v1
with:
swift-version: "5.9"
- name: Get swift version
run: swift --version
- uses: actions/checkout@v3
- name: Build
run: swift build -v
- name: Test
run: swift test
run: swift test
13 changes: 13 additions & 0 deletions Decide/Macros.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import DecideMacros

@attached(
member,
names: named(environment),
named(init(environment:))
)
@attached(memberAttribute)
@attached(extension, conformances: StateRoot)
public macro EnvironmentObservable() = #externalMacro(
module: "DecideMacros",
type: "StorageMacro"
)
12 changes: 12 additions & 0 deletions DecideMacros-Tests/Decide_Tests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import XCTest
import Decide

final class Decide_Tests: XCTestCase {
@EnvironmentObservable
final class Notes {
@Persistent
var name: String = ""

var count: Int = 0
}
}
12 changes: 12 additions & 0 deletions DecideMacros/Plugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#if canImport(SwiftCompilerPlugin)
import SwiftCompilerPlugin
import SwiftSyntaxMacros

@main
struct DecideCompilerPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
StorageMacro.self,
// AtomicPropertyMacro.self,
]
}
#endif
57 changes: 57 additions & 0 deletions DecideMacros/StorageMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import SwiftSyntax
import SwiftSyntaxMacros

public protocol ObservableState {
init()
}

public struct StorageMacro: MemberMacro, MemberAttributeMacro {
public static func expansion(
of node: SwiftSyntax.AttributeSyntax,
attachedTo declaration: some SwiftSyntax.DeclGroupSyntax,
providingAttributesFor member: some SwiftSyntax.DeclSyntaxProtocol,
in context: some SwiftSyntaxMacros.MacroExpansionContext
) throws -> [SwiftSyntax.AttributeSyntax] {
return [
AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: .identifier("ObservableValue")
)
)
]
}

// MARK: - MemberMacro
public static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
guard let _ = declaration.asProtocol(NamedDeclSyntax.self) else {
return []
}

let environment: DeclSyntax =
"""
public unowned let environment: Decide.SharedEnvironment
public init(environment: Decide.SharedEnvironment) {
self.environment = environment
}
"""

return [environment]
}
}


extension StorageMacro: ExtensionMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
[try ExtensionDeclSyntax("extension \(type): Decide.StateRoot {}")]
}
}
28 changes: 25 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.7
// swift-tools-version:5.9
//===----------------------------------------------------------------------===//
//
// This source file is part of the Decide package open source project
Expand All @@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//

import PackageDescription
import CompilerPluginSupport

let package = Package(
name: "Decide",
Expand All @@ -28,14 +29,25 @@ let package = Package(
.library(name: "DecideTesting", targets: ["DecideTesting"]),
],
dependencies: [
// Depend on the Swift 5.9 release of SwiftSyntax
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"),
],
targets: [
// - Decide -
.target(
name: "Decide",
dependencies: [],
dependencies: [
"DecideMacros"
],
path: "Decide"
),
.macro(
name: "DecideMacros",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
],
path: "DecideMacros"
),
.testTarget(
name: "Decide-Tests",
dependencies: [
Expand All @@ -50,5 +62,15 @@ let package = Package(
dependencies: ["Decide"],
path: "DecideTesting"
),
// Macros Tests
.testTarget(
name: "DecideMacros-Tests",
dependencies: [
"Decide",
"DecideMacros",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
],
path: "DecideMacros-Tests"
),
]
)

0 comments on commit f96cb9d

Please sign in to comment.