Skip to content

[WIP] support shadowing #1

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
41 changes: 41 additions & 0 deletions Sources/FunctionalViewComponent/FunctionalViewComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,45 @@
@attached(body)
public macro ViewComponent() = #externalMacro(module: "FunctionalViewComponentMacros", type: "ViewComponentMacro")

#if DEBUG
import SwiftUI
@ViewComponent
@MainActor
func basic(
arg1: Int,
arg2: String,
arg3: @escaping () -> Void
) -> some View {

@State var count: Int = 0

VStack {
Text("\(count), \(arg1), \(arg2)")
Button("Click me") {
count += 1
}
}

}

@ViewComponent
@MainActor
func objcct(
obj: AnyObject
) -> some View {

// unowned let obj = obj

@State var count: Int = 0

VStack {
}

}

#Preview {
basic(arg1: 1, arg2: "hoge", arg3: {
print("hit")
})
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import SwiftSyntaxMacros

extension FunctionDeclSyntax {
struct BodyComponents {
let stateDeclarations: [String]
let bindingDeclarations: [String]
let temporaryDeclarations: [String]
let stateDeclarations: [VariableDeclSyntax]
let bindingDeclarations: [VariableDeclSyntax]
let temporaryDeclarations: [VariableDeclSyntax]
let viewBody: [String]
}

Expand All @@ -22,24 +22,27 @@ extension FunctionDeclSyntax {
fatalError("Function body is required")
}

var stateDeclarations: [String] = []
var bindingDeclarations: [String] = []
var temporaryDeclarations: [String] = []
var stateDeclarations: [VariableDeclSyntax] = []
var bindingDeclarations: [VariableDeclSyntax] = []
var temporaryDeclarations: [VariableDeclSyntax] = []
var viewBody: [String] = []

for statement in body.statements {
let statementText = statement.trimmed.description

if statementText.contains("@State") {
stateDeclarations.append(statementText)
} else if statementText.contains("@Binding") {
bindingDeclarations.append(statementText)
} else if statementText.contains("var ") || statementText.contains("let ")
|| statementText.contains("unowned let") || statementText.contains("weak var")
{
temporaryDeclarations.append(statementText)

if let variableDecl = statement.item.as(VariableDeclSyntax.self) {

for attribute in variableDecl.attributes {
if attribute.as(AttributeSyntax.self)?.kind == AttributeSyntax.init(stringLiteral: "@State").kind {
stateDeclarations.append(variableDecl)
} else if attribute.as(AttributeSyntax.self)?.attributeName.description == "Binding" {
bindingDeclarations.append(variableDecl)
} else {
temporaryDeclarations.append(variableDecl)
}
}

} else {
viewBody.append(statementText)
viewBody.append(statement.trimmed.description)
}
}

Expand All @@ -51,7 +54,7 @@ extension FunctionDeclSyntax {
)
}

var initializerComponents: [InitializerComponent] {
func initializerComponents() -> [InitializerComponent] {
let parameters = self.signature.parameterClause.parameters
return parameters.map { param in
let name = param.secondName?.text ?? param.firstName.text
Expand Down Expand Up @@ -81,11 +84,9 @@ public struct ViewComponentMacro: BodyMacro {
fatalError("ViewComponentMacro can only be applied to function declarations.")
}

// イニシャライザのコンポーネントを取得
let initComponents = functionDecl.initializerComponents
let initComponents = functionDecl.initializerComponents()

// ボディのコンポーネントを取得
let components = functionDecl.extractBodyComponents()
let bodyComponents = functionDecl.extractBodyComponents()

let initBlock = """
init(\(initComponents.map { "\($0.name): \($0.type)" }.joined(separator: ", "))) {
Expand All @@ -95,22 +96,23 @@ public struct ViewComponentMacro: BodyMacro {

let bodyBlock = """
var body: some View {
\(components.viewBody.joined(separator: "\n").indented(1))
\(bodyComponents.viewBody.joined(separator: "\n").indented(1))
}
"""

let component = """
struct Component: View {

\(initComponents.map { "let \($0.name): \($0.type.replacingOccurrences(of: "@escaping", with: "").trimmingCharacters(in: .whitespaces))" }.joined(separator: "\n").indented(1))
\(bodyComponents.temporaryDeclarations.map { $0.trimmed.description }.joined(separator: "\n"))

\(components.stateDeclarations.joined(separator: "\n").indented(1))
\(initComponents.filter { c in bodyComponents.temporaryDeclarations.contains { $0.bindings.contains { $0.pattern == c.name } } }.map { "let \($0.name): \($0.type.replacingOccurrences(of: "@escaping", with: "").trimmingCharacters(in: .whitespaces))" }.joined(separator: "\n").indented(1))

\(components.bindingDeclarations.joined(separator: "\n").indented(1))
\(bodyComponents.stateDeclarations.map { $0.trimmed.description }.joined(separator: "\n").indented(1))

\(bodyComponents.bindingDeclarations.map { $0.trimmed.description }.joined(separator: "\n").indented(1))

\(initBlock.indented(1))

\(components.temporaryDeclarations.joined(separator: "\n"))

\(bodyBlock.indented(1))

Expand Down Expand Up @@ -152,3 +154,7 @@ struct FunctionalViewComponentPlugin: CompilerPlugin {
ViewComponentMacro.self
]
}

extension VariableDeclSyntax {

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,59 @@ final class TrackingMacroTests: XCTestCase {
}
"""#
} expansion: {
"""
"""
#"""
@MainActor
func hoge(arg1: Int, arg2: String, arg3: @escaping () -> Void) -> some View {

struct Component: View {



let arg1: Int

let arg2: String

let arg3: () -> Void

@State var count: Int = 0



init(arg1: Int, arg2: String, arg3: @escaping () -> Void) {

self.arg1 = arg1

self.arg2 = arg2

self.arg3 = arg3

}



var body: some View {

VStack {

Text("\(count), \(arg1), \(arg2)")

Button("Click me") {

count += 1

}

}

}



}

return Component(arg1: arg1, arg2: arg2, arg3: arg3)
}
"""#
}

}
Expand Down