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

macros #404

Merged
merged 7 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@
"version" : "1.0.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "67c5007099d9ffdd292f421f81f4efe5ee42963e",
"version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-07-10-a"
}
},
{
"identity" : "viewinspector",
"kind" : "remoteSourceControl",
Expand Down
24 changes: 22 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// swift-tools-version:5.6
// swift-tools-version:5.9
import PackageDescription
import CompilerPluginSupport

let package = Package(
name: "Verge",
Expand All @@ -15,6 +16,7 @@ let package = Package(
.library(name: "VergeORM", targets: ["VergeORM"]),
.library(name: "VergeRx", targets: ["VergeRx"]),
.library(name: "VergeClassic", targets: ["VergeClassic"]),
.library(name: "VergeMacros", targets: ["VergeMacros"]),
],
dependencies: [
.package(url: "https://github.com/ReactiveX/RxSwift.git", from: "6.0.0"),
Expand All @@ -25,12 +27,27 @@ let package = Package(

/// for testing
.package(url: "https://github.com/nalexn/ViewInspector.git", from: "0.9.3"),
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b")
],
targets: [

// compiler plugin
.macro(
name: "VergeMacrosPlugin",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]
),

// macro exports
.target(name: "VergeMacros", dependencies: ["VergeMacrosPlugin"]),

.target(name: "VergeTiny", dependencies: []),
.target(
name: "Verge",
dependencies: [
"VergeMacros",
.product(name: "Atomics", package: "swift-atomics"),
.product(name: "DequeModule", package: "swift-collections"),
.product(name: "ConcurrencyTaskManager", package: "swift-concurrency-task-manager"),
Expand All @@ -46,7 +63,6 @@ let package = Package(
name: "VergeORM",
dependencies: [
"Verge",
// .product(name: "HashTreeCollections", package: "swift-collections"),
.product(name: "HashTreeCollections", package: "swift-collections"),
]
),
Expand Down Expand Up @@ -78,6 +94,10 @@ let package = Package(
name: "VergeTinyTests",
dependencies: ["VergeTiny"]
),
.testTarget(name: "VergeMacrosTests", dependencies: [
"VergeMacrosPlugin",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
])
],
swiftLanguageVersions: [.v5]
)
29 changes: 29 additions & 0 deletions Sources/Verge/macros.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@freestanding(expression)
public macro ifChanged<State, U0>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, onChanged: (U0) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, onChanged: (U0, U1) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, onChanged: (U0, U1, U2) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, onChanged: (U0, U1, U2, U3) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3, U4>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, _ keyPath_4: KeyPath<State, U4>, onChanged: (U0, U1, U2, U3, U4) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3, U4, U5>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, _ keyPath_4: KeyPath<State, U4>, _ keyPath_5: KeyPath<State, U5>, onChanged: (U0, U1, U2, U3, U4, U5) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3, U4, U5, U6>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, _ keyPath_4: KeyPath<State, U4>, _ keyPath_5: KeyPath<State, U5>, _ keyPath_6: KeyPath<State, U6>, onChanged: (U0, U1, U2, U3, U4, U5, U6) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3, U4, U5, U6, U7>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, _ keyPath_4: KeyPath<State, U4>, _ keyPath_5: KeyPath<State, U5>, _ keyPath_6: KeyPath<State, U6>, _ keyPath_7: KeyPath<State, U7>, onChanged: (U0, U1, U2, U3, U4, U5, U6, U7) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3, U4, U5, U6, U7, U8>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, _ keyPath_4: KeyPath<State, U4>, _ keyPath_5: KeyPath<State, U5>, _ keyPath_6: KeyPath<State, U6>, _ keyPath_7: KeyPath<State, U7>, _ keyPath_8: KeyPath<State, U8>, onChanged: (U0, U1, U2, U3, U4, U5, U6, U7, U8) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")

@freestanding(expression)
public macro ifChanged<State, U0, U1, U2, U3, U4, U5, U6, U7, U8, U9>(_ state: Changes<State>, _ keyPath_0: KeyPath<State, U0>, _ keyPath_1: KeyPath<State, U1>, _ keyPath_2: KeyPath<State, U2>, _ keyPath_3: KeyPath<State, U3>, _ keyPath_4: KeyPath<State, U4>, _ keyPath_5: KeyPath<State, U5>, _ keyPath_6: KeyPath<State, U6>, _ keyPath_7: KeyPath<State, U7>, _ keyPath_8: KeyPath<State, U8>, _ keyPath_9: KeyPath<State, U9>, onChanged: (U0, U1, U2, U3, U4, U5, U6, U7, U8, U9) -> Void) -> Void = #externalMacro(module: "VergeMacrosPlugin", type: "IfChangedMacro")
1 change: 1 addition & 0 deletions Sources/VergeMacros/Source.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

48 changes: 48 additions & 0 deletions Sources/VergeMacrosPlugin/DatabaseStateMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct DatabaseStateMacro {

}

extension DatabaseStateMacro: ConformanceMacro {
public static func expansion<Declaration, Context>(
of node: SwiftSyntax.AttributeSyntax,
providingConformancesOf declaration: Declaration,
in context: Context
) throws -> [(SwiftSyntax.TypeSyntax, SwiftSyntax.GenericWhereClauseSyntax?)]
where Declaration: SwiftSyntax.DeclGroupSyntax, Context: SwiftSyntaxMacros.MacroExpansionContext {

// Decode the expansion arguments.
guard let structDecl = declaration.as(StructDeclSyntax.self) else {
// context.diagnose(OptionSetMacroDiagnostic.requiresStruct.diagnose(at: decl))
return []
}

// If there is an explicit conformance to OptionSet already, don't add one.
if let inheritedTypes = structDecl.inheritanceClause?.inheritedTypeCollection,
inheritedTypes.contains(where: { inherited in inherited.typeName.trimmedDescription == "DatabaseType" }) {
return []
}

return [("DatabaseType", nil)]
}

}

extension DatabaseStateMacro: MemberMacro {

public static func expansion<Declaration, Context>(
of node: SwiftSyntax.AttributeSyntax,
providingMembersOf declaration: Declaration,
in context: Context
) throws -> [SwiftSyntax.DeclSyntax]
where Declaration: SwiftSyntax.DeclGroupSyntax, Context: SwiftSyntaxMacros.MacroExpansionContext {

return [
"var _backingStorage: DatabaseStorage<Schema, Indexes> = .init()"
]

}
}
87 changes: 87 additions & 0 deletions Sources/VergeMacrosPlugin/IfChangedMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct IfChangedMacro: ExpressionMacro {

public enum Error: Swift.Error {
case foundNotKeyPathLiteral
case faildToExpand

}

public static func expansion(
of node: some SwiftSyntax.FreestandingMacroExpansionSyntax,
in context: some SwiftSyntaxMacros.MacroExpansionContext
) throws -> SwiftSyntax.ExprSyntax {

let onChangedClosure: ClosureExprSyntax

if let _onChangedClosure: ClosureExprSyntax = node.trailingClosure {
onChangedClosure = _onChangedClosure
} else {

let onChangedParameter = node.argumentList.last!
let _onChangedClosure = onChangedParameter.expression.cast(ClosureExprSyntax.self)

onChangedClosure = _onChangedClosure
}

let arguments = node.argumentList.filter { $0.label?.text != "onChanged" }

let stateExpr = arguments.map { $0 }[0].cast(TupleExprElementSyntax.self).expression.cast(
IdentifierExprSyntax.self
).identifier

let keyPahts = arguments.dropFirst()

let names: [(String, KeyPathComponentListSyntax)] = {
return keyPahts.map { keyPath in
let components = keyPath.cast(TupleExprElementSyntax.self).expression.cast(
KeyPathExprSyntax.self
).components

let name =
components
.map {
$0.cast(KeyPathComponentSyntax.self).component.cast(
KeyPathPropertyComponentSyntax.self
).identifier.description
}
.joined(separator: "_")

return (name, components)
}
}()

let conditions = names.map { arg in

return
(
condition: """
primitiveState\(arg.1) != previousState?\(arg.1)
""",
property: """
let \(arg.0) = primitiveState\(arg.1)
""",
accessor: "primitiveState\(arg.1)"
)
}

return """
{ () -> Void in

let primitiveState = \(stateExpr).primitive
let previousState = \(stateExpr).previous?.primitive

guard \(raw: conditions.map { $0.condition }.joined(separator: " || ")) else {
return
}

let _: Void = \(onChangedClosure)(\(raw: conditions.map { $0.accessor }.joined(separator: ",")))
}()
"""

}

}
12 changes: 12 additions & 0 deletions Sources/VergeMacrosPlugin/Plugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

@main
struct Plugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
DatabaseStateMacro.self,
IfChangedMacro.self,
]
}
20 changes: 20 additions & 0 deletions Sources/VergeMacrosPlugin/StateMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct StateMacro {

}
//
//extension StateMacro: MemberMacro {
//
// public static func expansion<Declaration, Context>(
// of node: SwiftSyntax.AttributeSyntax,
// providingMembersOf declaration: Declaration,
// in context: Context
// ) throws -> [SwiftSyntax.DeclSyntax]
// where Declaration: SwiftSyntax.DeclGroupSyntax, Context: SwiftSyntaxMacros.MacroExpansionContext {
//
// }
//
//}
Loading
Loading