Skip to content

Making a Code Review #73

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 5 commits into from
Jun 19, 2025
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
6 changes: 3 additions & 3 deletions Sources/SyntaxKit/Attribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import SwiftSyntax

/// Internal representation of a Swift attribute with its arguments.
internal struct AttributeInfo {
let name: String
let arguments: [String]
internal let name: String
internal let arguments: [String]

init(name: String, arguments: [String] = []) {
internal init(name: String, arguments: [String] = []) {
self.name = name
self.arguments = arguments
}
Expand Down
15 changes: 15 additions & 0 deletions Sources/SyntaxKit/CodeBlock+Generate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ extension CodeBlock {
item = .stmt(stmt)
} else if let expr = self.syntax.as(ExprSyntax.self) {
item = .expr(expr)
} else if let token = self.syntax.as(TokenSyntax.self) {
// Wrap TokenSyntax in DeclReferenceExprSyntax and then in ExprSyntax
let expr = ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier(token.text)))
item = .expr(expr)
} else if let switchCase = self.syntax.as(SwitchCaseSyntax.self) {
// Wrap SwitchCaseSyntax in a SwitchExprSyntax and treat it as an expression
// This is a fallback for when SwitchCase is used standalone
let switchExpr = SwitchExprSyntax(
switchKeyword: .keyword(.switch, trailingTrivia: .space),
subject: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("_"))),
leftBrace: .leftBraceToken(leadingTrivia: .space, trailingTrivia: .newline),
cases: SwitchCaseListSyntax([SwitchCaseListSyntax.Element(switchCase)]),
rightBrace: .rightBraceToken(leadingTrivia: .newline)
)
item = .expr(ExprSyntax(switchExpr))
} else {
fatalError(
"Unsupported syntax type at top level: \(type(of: self.syntax)) generating from \(self)")
Expand Down
6 changes: 3 additions & 3 deletions Sources/SyntaxKit/CommentedCodeBlock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import SwiftSyntax
// MARK: - Wrapper `CodeBlock` that injects leading trivia

internal struct CommentedCodeBlock: CodeBlock {
let base: CodeBlock
let lines: [Line]
internal let base: CodeBlock
internal let lines: [Line]

var syntax: SyntaxProtocol {
internal var syntax: SyntaxProtocol {
// Shortcut if there are no comment lines
guard !lines.isEmpty else { return base.syntax }

Expand Down
82 changes: 55 additions & 27 deletions Sources/SyntaxKit/Enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,56 +145,84 @@
/// A Swift `case` declaration inside an `enum`.
public struct EnumCase: CodeBlock {
private let name: String
private var value: String?
private var intValue: Int?
private var literalValue: Literal?

/// Creates a `case` declaration.
/// - Parameter name: The name of the case.
public init(_ name: String) {
self.name = name
self.literalValue = nil
}

/// Sets the raw value of the case to a string.
/// - Parameter value: The string value.
/// Sets the raw value of the case to a Literal.
/// - Parameter value: The literal value.
/// - Returns: A copy of the case with the raw value set.
public func equals(_ value: String) -> Self {
public func equals(_ value: Literal) -> Self {
var copy = self
copy.value = value
copy.intValue = nil
copy.literalValue = value
return copy
}

/// Sets the raw value of the case to an integer.
/// Sets the raw value of the case to a string (for backward compatibility).
/// - Parameter value: The string value.
/// - Returns: A copy of the case with the raw value set.
public func equals(_ value: String) -> Self {
self.equals(.string(value))
}

/// Sets the raw value of the case to an integer (for backward compatibility).
/// - Parameter value: The integer value.
/// - Returns: A copy of the case with the raw value set.
public func equals(_ value: Int) -> Self {
var copy = self
copy.value = nil
copy.intValue = value
return copy
self.equals(.integer(value))
}

/// Sets the raw value of the case to a float (for backward compatibility).
/// - Parameter value: The float value.
/// - Returns: A copy of the case with the raw value set.
public func equals(_ value: Double) -> Self {
self.equals(.float(value))

Check warning on line 184 in Sources/SyntaxKit/Enum.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SyntaxKit/Enum.swift#L183-L184

Added lines #L183 - L184 were not covered by tests
}

public var syntax: SyntaxProtocol {
let caseKeyword = TokenSyntax.keyword(.case, trailingTrivia: .space)
let identifier = TokenSyntax.identifier(name, trailingTrivia: .space)

var initializer: InitializerClauseSyntax?
if let value = value {
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: StringLiteralExprSyntax(
openingQuote: .stringQuoteToken(),
segments: StringLiteralSegmentListSyntax([
.stringSegment(StringSegmentSyntax(content: .stringSegment(value)))
]),
closingQuote: .stringQuoteToken()
if let literal = literalValue {
switch literal {
case .string(let value):
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: StringLiteralExprSyntax(
openingQuote: .stringQuoteToken(),
segments: StringLiteralSegmentListSyntax([
.stringSegment(StringSegmentSyntax(content: .stringSegment(value)))
]),
closingQuote: .stringQuoteToken()
)
)
)
} else if let intValue = intValue {
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: IntegerLiteralExprSyntax(digits: .integerLiteral(String(intValue)))
)
case .float(let value):
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: FloatLiteralExprSyntax(literal: .floatLiteral(String(value)))
)
case .integer(let value):
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: IntegerLiteralExprSyntax(digits: .integerLiteral(String(value)))
)
case .nil:
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: NilLiteralExprSyntax(nilKeyword: .keyword(.nil))
)

Check warning on line 219 in Sources/SyntaxKit/Enum.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SyntaxKit/Enum.swift#L216-L219

Added lines #L216 - L219 were not covered by tests
case .boolean(let value):
initializer = InitializerClauseSyntax(
equal: .equalToken(leadingTrivia: .space, trailingTrivia: .space),
value: BooleanLiteralExprSyntax(literal: value ? .keyword(.true) : .keyword(.false))
)

Check warning on line 224 in Sources/SyntaxKit/Enum.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SyntaxKit/Enum.swift#L221-L224

Added lines #L221 - L224 were not covered by tests
}
}

return EnumCaseDeclSyntax(
Expand Down
2 changes: 1 addition & 1 deletion Sources/SyntaxKit/Group.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import SwiftSyntax

/// A group of code blocks.
public struct Group: CodeBlock {
let members: [CodeBlock]
internal let members: [CodeBlock]

/// Creates a group of code blocks.
/// - Parameter content: A ``CodeBlockBuilder`` that provides the members of the group.
Expand Down
4 changes: 2 additions & 2 deletions Sources/SyntaxKit/Let.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import SwiftSyntax

/// A Swift `let` declaration for use in an `if` statement.
public struct Let: CodeBlock {
let name: String
let value: String
internal let name: String
internal let value: String

/// Creates a `let` declaration for an `if` statement.
/// - Parameters:
Expand Down
8 changes: 4 additions & 4 deletions Sources/SyntaxKit/Parameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import SwiftSyntax

/// A parameter for a function or initializer.
public struct Parameter: CodeBlock {
let name: String
let type: String
let defaultValue: String?
let isUnnamed: Bool
internal let name: String
internal let type: String
internal let defaultValue: String?
internal let isUnnamed: Bool
internal var attributes: [AttributeInfo] = []

/// Creates a parameter for a function or initializer.
Expand Down
4 changes: 2 additions & 2 deletions Sources/SyntaxKit/ParameterExp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import SwiftSyntax

/// A parameter for a function call.
public struct ParameterExp: CodeBlock {
let name: String
let value: String
internal let name: String
internal let value: String

/// Creates a parameter for a function call.
/// - Parameters:
Expand Down
55 changes: 55 additions & 0 deletions Sources/SyntaxKit/Parenthesized.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// Parenthesized.swift
// SyntaxKit
//
// Created by Leo Dion.
// Copyright © 2025 BrightDigit.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//

import SwiftSyntax

/// A code block that wraps its content in parentheses.
public struct Parenthesized: CodeBlock {
private let content: CodeBlock

/// Creates a parenthesized code block.
/// - Parameter content: The code block to wrap in parentheses.
public init(@CodeBlockBuilderResult _ content: () -> [CodeBlock]) {
let blocks = content()
precondition(blocks.count == 1, "Parenthesized expects exactly one code block.")
self.content = blocks[0]
}

public var syntax: SyntaxProtocol {
ExprSyntax(
TupleExprSyntax(
leftParen: .leftParenToken(),
elements: LabeledExprListSyntax([
LabeledExprSyntax(expression: content.expr)
]),
rightParen: .rightParenToken()
)
)
}
}
12 changes: 6 additions & 6 deletions Sources/SyntaxKit/VariableExp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import SwiftSyntax

/// An expression that refers to a variable.
public struct VariableExp: CodeBlock {
let name: String
internal let name: String

/// Creates a variable expression.
/// - Parameter name: The name of the variable.
Expand Down Expand Up @@ -71,8 +71,8 @@ public struct VariableExp: CodeBlock {

/// An expression that accesses a property on a base expression.
public struct PropertyAccessExp: CodeBlock {
let baseName: String
let propertyName: String
internal let baseName: String
internal let propertyName: String

/// Creates a property access expression.
/// - Parameters:
Expand All @@ -97,9 +97,9 @@ public struct PropertyAccessExp: CodeBlock {

/// An expression that calls a function.
public struct FunctionCallExp: CodeBlock {
let baseName: String
let methodName: String
let parameters: [ParameterExp]
internal let baseName: String
internal let methodName: String
internal let parameters: [ParameterExp]

/// Creates a function call expression.
/// - Parameters:
Expand Down
12 changes: 6 additions & 6 deletions Sources/SyntaxKit/parser/TokenVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,24 @@
import Foundation
@_spi(RawSyntax) import SwiftSyntax

final class TokenVisitor: SyntaxRewriter {
internal final class TokenVisitor: SyntaxRewriter {
// var list = [String]()
var tree = [TreeNode]()
internal var tree = [TreeNode]()

private var current: TreeNode!
private var index = 0

private let locationConverter: SourceLocationConverter
private let showMissingTokens: Bool

init(locationConverter: SourceLocationConverter, showMissingTokens: Bool) {
internal init(locationConverter: SourceLocationConverter, showMissingTokens: Bool) {
self.locationConverter = locationConverter
self.showMissingTokens = showMissingTokens
super.init(viewMode: showMissingTokens ? .all : .sourceAccurate)
}

// swiftlint:disable:next cyclomatic_complexity function_body_length
override func visitPre(_ node: Syntax) {
override internal func visitPre(_ node: Syntax) {
let syntaxNodeType = node.syntaxNodeType

let className: String
Expand Down Expand Up @@ -177,7 +177,7 @@ final class TokenVisitor: SyntaxRewriter {
current = treeNode
}

override func visit(_ token: TokenSyntax) -> TokenSyntax {
override internal func visit(_ token: TokenSyntax) -> TokenSyntax {
current.text = token
.text
.escapeHTML()
Expand All @@ -199,7 +199,7 @@ final class TokenVisitor: SyntaxRewriter {
return token
}

override func visitPost(_ node: Syntax) {
override internal func visitPost(_ node: Syntax) {
if let parent = current.parent {
current = tree[parent]
} else {
Expand Down
Loading
Loading