Skip to content

Adding switch statement support #53

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

Merged
merged 2 commits into from
Sep 27, 2024
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
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public final class DeclarationCollection {
/// The collected internal(set) public variable declarations.
public internal(set) var variables: [Variable] = []

/// The collected switch expression declarations.
public internal(set) var switches: [SwitchExpression] = []

func reset() {
actors = []
classes = []
Expand All @@ -73,6 +76,7 @@ public final class DeclarationCollection {
subscripts = []
typealiases = []
variables = []
switches = []
}

func collect(from collection: DeclarationCollection) {
Expand All @@ -92,5 +96,6 @@ public final class DeclarationCollection {
subscripts = collection.subscripts
typealiases = collection.typealiases
variables = collection.variables
switches = collection.switches
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@ class RootDeclarationCollector: SyntaxVisitor {
if let entryNode = entryNode, node.id == entryNode.id { return .visitChildren }
let declaration = Variable(node: node)
declarationCollection.variables.append(declaration)
return .visitChildren
return .skipChildren
}

override func visit(_ node: SwitchExprSyntax) -> SyntaxVisitorContinueKind {
if let entryNode = entryNode, node.id == entryNode.id { return .visitChildren }
let declaration = SwitchExpression(node: node)
declarationCollection.switches.append(declaration)
return .skipChildren
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// SwitchExpressionInnerBindingMemberCollector.swift
//
//
// Copyright (c) CheekyGhost Labs 2024. All Rights Reserved.
//

import Foundation
import SwiftSyntax

class SwitchExpressionInnerBindingMemberCollector: SkipByDefaultVisitor {

struct Binding {
var keyword: String = ""
var value: String = ""
}

// MARK: - Properties

private(set) var memberName: String?

private(set) var bindings: [Binding] = []

private(set) var focusedFunctionNode: FunctionCallExprSyntax?

private(set) var focusedElementListNode: LabeledExprListSyntax?

// MARK: - Helpers

func collect(_ node: SwitchCaseItemSyntax) -> SwitchExpression.SwitchCase.Item? {
walk(node)
guard let memberName else { return nil }
var bindingMap: [String: String] = [:]
bindings.forEach { bindingMap[$0.keyword] = $0.value }
return .innerValueBindingMember(name: memberName, elements: bindingMap)
}

// MARK: - Overrides

override func visit(_ node: SwitchCaseItemSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: ExpressionPatternSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind {
guard focusedFunctionNode == nil else { return .skipChildren }
focusedFunctionNode = node
return .visitChildren
}

override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind {
guard let focusedNode = focusedFunctionNode, node.parent?.id == focusedNode.id else { return .skipChildren }
memberName = node.declName.baseName.text.trimmed
return .skipChildren
}

override func visit(_ node: LabeledExprListSyntax) -> SyntaxVisitorContinueKind {
guard node.parent?.id == focusedFunctionNode?.id else { return .skipChildren }
guard focusedElementListNode == nil else { return .skipChildren }
focusedElementListNode = node
return .visitChildren
}

override func visit(_ node: LabeledExprSyntax) -> SyntaxVisitorContinueKind {
guard let focusedElements = focusedElementListNode, node.parent?.id == focusedElements.id else { return .skipChildren }
return .visitChildren
}

override func visit(_ node: PatternExprSyntax) -> SyntaxVisitorContinueKind {
guard let focusedElements = focusedElementListNode, node.parent?.parent?.id == focusedElements.id else { return .skipChildren }
return .visitChildren
}

override func visit(_ node: ValueBindingPatternSyntax) -> SyntaxVisitorContinueKind {
let binding = Binding(
keyword: node.bindingSpecifier.text.trimmed,
value: node.pattern.trimmedDescription
)
bindings.append(binding)
return .skipChildren
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// SwitchExpressionValueBindingCollector.swift
//
//
// Copyright (c) CheekyGhost Labs 2024. All Rights Reserved.
//

import Foundation
import SwiftSyntax

class SwitchExpressionIsTypeCollector: SkipByDefaultVisitor {

// MARK: - Properties

private(set) var type: String?

// MARK: - Helpers

func collect(_ node: SwitchCaseItemSyntax) -> SwitchExpression.SwitchCase.Item? {
walk(node)
guard let type else { return nil }
return .isTypePattern(type: type)
}

// MARK: - Overrides

override func visit(_ node: SwitchCaseItemSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: IsTypePatternSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: IdentifierTypeSyntax) -> SyntaxVisitorContinueKind {
type = node.description
return .skipChildren
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// SwitchExpressionMemberCollector.swift
//
//
// Copyright (c) CheekyGhost Labs 2024. All Rights Reserved.
//

import Foundation
import SwiftSyntax

class SwitchExpressionMemberCollector: SkipByDefaultVisitor {

// MARK: - Properties

private(set) var memberName: String?

private(set) var focusedExpressionNode: ExpressionPatternSyntax?

// MARK: - Helpers

func collect(_ node: SwitchCaseItemSyntax) -> SwitchExpression.SwitchCase.Item? {
walk(node)
guard let memberName else { return nil }
return .member(name: memberName)
}

// MARK: - Overrides

override func visit(_ node: SwitchCaseItemSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: ExpressionPatternSyntax) -> SyntaxVisitorContinueKind {
guard focusedExpressionNode == nil else { return .skipChildren }
focusedExpressionNode = node
return .visitChildren
}

override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind {
guard let focusedNode = focusedExpressionNode, node.parent?.id == focusedNode.id else { return .skipChildren }
memberName = node.declName.baseName.text.trimmed
return .skipChildren
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// SwitchExpressionTupleCollector.swift
//
//
// Copyright (c) CheekyGhost Labs 2024. All Rights Reserved.
//

import Foundation
import SwiftSyntax

class SwitchExpressionTupleCollector: SkipByDefaultVisitor {

// MARK: - Properties

private(set) var memberName: String?

private(set) var elements: [String]?

private(set) var focusedExpressionNode: ExpressionPatternSyntax?

// MARK: - Helpers

func collect(_ node: SwitchCaseItemSyntax) -> SwitchExpression.SwitchCase.Item? {
walk(node)
guard let elements, memberName == nil else { return nil }
return .tuple(elements: elements)
}

// MARK: - Overrides

override func visit(_ node: SwitchCaseItemSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: ExpressionPatternSyntax) -> SyntaxVisitorContinueKind {
guard focusedExpressionNode == nil else { return .skipChildren }
focusedExpressionNode = node
return .visitChildren
}

override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind {
// This is a fallback as there should be no member syntax. If there is the result will return nil.
memberName = node.declName.baseName.text.trimmed
return .skipChildren
}

override func visit(_ node: TupleExprSyntax) -> SyntaxVisitorContinueKind {
guard let focusedExpressionNode, node.parent?.id == focusedExpressionNode.id, elements == nil else { return .skipChildren }
elements = node.elements.trimmedDescription.components(separatedBy: ",").map(\.trimmed)
return .skipChildren
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//
// SwitchExpressionValueBindingCollector.swift
//
//
// Copyright (c) CheekyGhost Labs 2024. All Rights Reserved.
//

import Foundation
import SwiftSyntax

class SwitchExpressionValueBindingCollector: SkipByDefaultVisitor {

// MARK: - Properties

private(set) var memberName: String?

private(set) var keyword: String?

private(set) var sequenceElements: [String] = []

private(set) var focusedBindingNode: ValueBindingPatternSyntax?

private(set) var focusedFunctionNode: FunctionCallExprSyntax?

// MARK: - Helpers

func collect(_ node: SwitchCaseItemSyntax) -> SwitchExpression.SwitchCase.Item? {
walk(node)
guard let keyword, memberName == nil else { return nil }
return .valueBinding(keyWord: keyword, elements: sequenceElements)
}

// MARK: - Overrides

override func visit(_ node: SwitchCaseItemSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: ValueBindingPatternSyntax) -> SyntaxVisitorContinueKind {
guard focusedBindingNode == nil else { return .skipChildren }
focusedBindingNode = node
keyword = node.bindingSpecifier.trimmedDescription
return .visitChildren
}

override func visit(_ node: ExpressionPatternSyntax) -> SyntaxVisitorContinueKind {
guard let focusedNode = focusedBindingNode, node.parent?.id == focusedNode.id else { return .skipChildren }
return .visitChildren
}

override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind {
// This is a fallback as there should be no member syntax. If there is the result will return nil.
memberName = node.declName.baseName.text.trimmed
return .skipChildren
}

override func visit(_ node: SequenceExprSyntax) -> SyntaxVisitorContinueKind {
return .visitChildren
}

override func visit(_ node: ExprListSyntax) -> SyntaxVisitorContinueKind {
sequenceElements = node.map(\.trimmedDescription)
return .skipChildren
}

/*
Initially listened for the variants I could derive from token exploration. However, as it always
ends up adding the `node.trimmedDescription`, and there is always an `ExprListSyntax` element that
contains them, the `ExprListSyntax` visitor override will just map the trimmed description value
into the sequence. Leaving these in as reference for future refactor/clean-up.
*/

// override func visit(_ node: UnresolvedPatternExprSyntax) -> SyntaxVisitorContinueKind {
// return .visitChildren
// }
//
// override func visit(_ node: TypeExprSyntax) -> SyntaxVisitorContinueKind {
// sequenceElements.append(node.trimmedDescription)
// return .skipChildren
// }
//
// override func visit(_ node: UnresolvedAsExprSyntax) -> SyntaxVisitorContinueKind {
// sequenceElements.append(node.trimmedDescription)
// return .skipChildren
// }
//
// override func visit(_ node: UnresolvedIsExprSyntax) -> SyntaxVisitorContinueKind {
// sequenceElements.append(node.trimmedDescription)
// return .skipChildren
// }
//
// override func visit(_ node: IdentifierPatternSyntax) -> SyntaxVisitorContinueKind {
// sequenceElements.append(node.identifier.trimmedDescription)
// return .skipChildren
// }
}
Loading
Loading