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

[DNM] Support box-drawing-based blocks #2928

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
19 changes: 14 additions & 5 deletions CodeGeneration/Sources/SyntaxSupport/Child.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public enum ChildKind {
/// The child is a token that matches one of the given `choices`.
/// If `requiresLeadingSpace` or `requiresTrailingSpace` is not `nil`, it
/// overrides the default leading/trailing space behavior of the token.
case token(choices: [TokenChoice], requiresLeadingSpace: Bool? = nil, requiresTrailingSpace: Bool? = nil)
case token(choices: [TokenChoice], requiresLeadingSpace: Bool? = nil, requiresTrailingSpace: Bool? = nil, defaultAt: Int? = nil)

public var isNodeChoices: Bool {
if case .nodeChoices = self {
Expand Down Expand Up @@ -108,7 +108,7 @@ public class Child: NodeChoiceConvertible {
/// A docc comment describing the child, including the trivia provided when
/// initializing the ``Child``, and the list of possible token choices inferred automatically.
public var documentation: SwiftSyntax.Trivia {
if case .token(let choices, _, _) = kind {
if case .token(let choices, _, _, _) = kind {
let tokenChoicesTrivia = SwiftSyntax.Trivia.docCommentTrivia(
from: GrammarGenerator.childTokenChoices(for: choices)
)
Expand Down Expand Up @@ -230,9 +230,18 @@ public class Child: NodeChoiceConvertible {
/// Grab the existing reference to that token from the global list.
public var tokenKind: Token? {
switch kind {
case .token(let choices, _, _):
if choices.count == 1 {
switch choices.first! {
case .token(let choices, _, _, defaultAt: let defaultIndex):
let defaultToken: TokenChoice?
if let defaultIndex {
defaultToken = choices[defaultIndex]
} else if let onlyToken = choices.only {
defaultToken = onlyToken
} else {
defaultToken = nil
}

if let defaultToken {
switch defaultToken {
case .keyword: return .keyword
case .token(let token): return token
}
Expand Down
12 changes: 10 additions & 2 deletions CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ public let COMMON_NODES: [Node] = [
children: [
Child(
name: "leftBrace",
kind: .token(choices: [.token(.leftBrace)]),
kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0),
documentation: "The brace introducing the code block."
),
Child(
Expand All @@ -74,7 +78,11 @@ public let COMMON_NODES: [Node] = [
),
Child(
name: "rightBrace",
kind: .token(choices: [.token(.rightBrace)]),
kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0),
documentation: "The brace closing the code block."
),
]
Expand Down
36 changes: 30 additions & 6 deletions CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ public let DECL_NODES: [Node] = [
children: [
Child(
name: "leftBrace",
kind: .token(choices: [.token(.leftBrace)]),
kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0),
documentation: "The brace introducing the accessor block."
),
Child(
Expand All @@ -75,7 +79,11 @@ public let DECL_NODES: [Node] = [
),
Child(
name: "rightBrace",
kind: .token(choices: [.token(.rightBrace)]),
kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0),
documentation: "The brace closing the accessor block."
),
]
Expand Down Expand Up @@ -1579,15 +1587,23 @@ public let DECL_NODES: [Node] = [
children: [
Child(
name: "leftBrace",
kind: .token(choices: [.token(.leftBrace)])
kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0)
),
Child(
name: "members",
kind: .collection(kind: .memberBlockItemList, collectionElementName: "Member")
),
Child(
name: "rightBrace",
kind: .token(choices: [.token(.rightBrace)])
kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0)
),
]
),
Expand Down Expand Up @@ -1972,7 +1988,11 @@ public let DECL_NODES: [Node] = [
),
Child(
name: "leftBrace",
kind: .token(choices: [.token(.leftBrace)])
kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0)
),
Child(
name: "groupAttributes",
Expand All @@ -1981,7 +2001,11 @@ public let DECL_NODES: [Node] = [
),
Child(
name: "rightBrace",
kind: .token(choices: [.token(.rightBrace)])
kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0)
),
],
childHistory: [
Expand Down
24 changes: 20 additions & 4 deletions CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,11 @@ public let EXPR_NODES: [Node] = [
children: [
Child(
name: "leftBrace",
kind: .token(choices: [.token(.leftBrace)])
kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0)
),
Child(
name: "signature",
Expand All @@ -524,7 +528,11 @@ public let EXPR_NODES: [Node] = [
),
Child(
name: "rightBrace",
kind: .token(choices: [.token(.rightBrace)])
kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0)
),
]
),
Expand Down Expand Up @@ -1949,7 +1957,11 @@ public let EXPR_NODES: [Node] = [
),
Child(
name: "leftBrace",
kind: .token(choices: [.token(.leftBrace)]),
kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0),
documentation: "The brace introducing the switch body."
),
Child(
Expand All @@ -1959,7 +1971,11 @@ public let EXPR_NODES: [Node] = [
),
Child(
name: "rightBrace",
kind: .token(choices: [.token(.rightBrace)]),
kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0),
documentation: "The brace closing the switch body."
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct GrammarGenerator {
return "(\(choicesDescriptions.joined(separator: " | ")))\(optionality)"
case .collection(kind: let kind, _, _, _):
return "\(kind.doccLink)\(optionality)"
case .token(let choices, _, _):
case .token(let choices, _, _, _):
if choices.count == 1 {
return "\(grammar(for: choices.first!))\(optionality)"
} else {
Expand Down
12 changes: 12 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/TokenSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ public enum Token: CaseIterable {
case infixQuestionMark
case integerLiteral
case keyword
case leadingBoxCorner
case leadingBoxJunction
case leftAngle
case leftBrace
case leftParen
Expand Down Expand Up @@ -168,6 +170,8 @@ public enum Token: CaseIterable {
case singleQuote
case stringQuote
case stringSegment
case trailingBoxCorner
case trailingBoxJunction
case unknown
case wildcard

Expand Down Expand Up @@ -207,6 +211,10 @@ public enum Token: CaseIterable {
return .other(name: "integerLiteral", nameForDiagnostics: "integer literal")
case .keyword:
return TokenSpec(name: "keyword", nameForDiagnostics: "keyword", text: nil, kind: .keyword)
case .leadingBoxCorner:
return .punctuator(name: "leadingBoxCorner", text: "╗")
case .leadingBoxJunction:
return .punctuator(name: "leadingBoxJunction", text: "╣")
case .leftAngle:
return .punctuator(name: "leftAngle", text: "<")
case .leftBrace:
Expand Down Expand Up @@ -269,6 +277,10 @@ public enum Token: CaseIterable {
return .punctuator(name: "stringQuote", text: "\"")
case .stringSegment:
return .other(name: "stringSegment", nameForDiagnostics: "string segment")
case .trailingBoxCorner:
return .punctuator(name: "trailingBoxCorner", text: "╚")
case .trailingBoxJunction:
return .punctuator(name: "trailingBoxJunction", text: "╠")
case .unknown:
return .other(name: "unknown", nameForDiagnostics: "token")
case .wildcard:
Expand Down
12 changes: 10 additions & 2 deletions CodeGeneration/Sources/SyntaxSupport/Traits.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,16 @@ public let TRAITS: [Trait] = [
Trait(
traitName: "Braced",
children: [
Child(name: "leftBrace", kind: .token(choices: [.token(.leftBrace)])),
Child(name: "rightBrace", kind: .token(choices: [.token(.rightBrace)])),
Child(name: "leftBrace", kind: .token(choices: [
.token(.leftBrace),
.token(.leadingBoxCorner),
.token(.leadingBoxJunction),
], defaultAt: 0)),
Child(name: "rightBrace", kind: .token(choices: [
.token(.rightBrace),
.token(.trailingBoxCorner),
.token(.trailingBoxJunction),
], defaultAt: 0)),
]
),
Trait(
Expand Down
5 changes: 5 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/Trivia.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,9 @@ public let TRIVIAS: [Trivia] = [
Character("\u{2B7F}")
]
),

Trivia(
name: "BoxDrawing",
comment: #"Box-drawing characters which have no syntactic significance."#
),
]
4 changes: 2 additions & 2 deletions CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ extension Child {
if token.text != nil {
return ExprSyntax(".\(token.identifier)Token()")
}
if case .token(let choices, _, _) = kind,
if case .token(let choices, _, _, _) = kind,
case .keyword(let keyword) = choices.only
{
return ExprSyntax(".\(token.memberCallName)(.\(keyword.spec.memberCallName))")
Expand All @@ -100,7 +100,7 @@ extension Child {
/// `precondition` statement that verifies the variable with name var_name and of type
/// ``TokenSyntax`` contains one of the supported text options. Otherwise return `nil`.
public func generateAssertStmtTextChoices(varName: String) -> FunctionCallExprSyntax? {
guard case .token(choices: let choices, requiresLeadingSpace: _, requiresTrailingSpace: _) = kind else {
guard case .token(choices: let choices, requiresLeadingSpace: _, requiresTrailingSpace: _, defaultAt: _) = kind else {
return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ let parserTokenSpecSetFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {

for layoutNode in SYNTAX_NODES.compactMap(\.layoutNode) {
for child in layoutNode.children {
if case let .token(choices, _, _) = child.kind, choices.count > 1 {
if case let .token(choices, _, _, _) = child.kind, choices.count > 1 {
try! ExtensionDeclSyntax("extension \(layoutNode.kind.syntaxType)") {
try EnumDeclSyntax(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
}

ExprSyntax("assertAnyHasNoError(kind, \(raw: index), \(verifiedChoices))")
case .token(choices: let choices, requiresLeadingSpace: _, requiresTrailingSpace: _):
case .token(choices: let choices, requiresLeadingSpace: _, requiresTrailingSpace: _, defaultAt: _):
let choices = ArrayExprSyntax {
for choice in choices {
switch choice {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fileprivate extension ChildKind {
return choices.count == otherChoices.count && zip(choices, otherChoices).allSatisfy { $0.hasSameType(as: $1) }
case (.collection(kind: let kind, _, _, _), .collection(kind: let otherKind, _, _, _)):
return kind == otherKind
case (.token(let choices, _, _), .token(let otherChoices, _, _)):
case (.token(let choices, _, _, _), .token(let otherChoices, _, _, _)):
return choices == otherChoices
case (.node(let kind), .collection(kind: let otherKind, _, _, _)):
return kind == otherKind
Expand Down Expand Up @@ -92,7 +92,7 @@ fileprivate extension Child {
guard childIndex + 2 < node.children.count else {
return false
}
if case .token(choices: [.token(.colon)], _, _) = node.children[childIndex + 2].kind {
if case .token(choices: [.token(.colon)], _, _, _) = node.children[childIndex + 2].kind {
return true
} else {
return false
Expand Down Expand Up @@ -173,7 +173,7 @@ class ValidateSyntaxNodes: XCTestCase {
///
/// - Returns: A failure message if validation failed, otherwise `nil`
private func validateSingleTokenChoiceChild(child: Child, in node: LayoutNode) -> String? {
guard case .token(choices: let tokenChoices, _, _) = child.kind, let choice = tokenChoices.only else {
guard case .token(choices: let tokenChoices, _, _, _) = child.kind, let choice = tokenChoices.only else {
return nil
}
switch choice {
Expand Down Expand Up @@ -369,7 +369,7 @@ class ValidateSyntaxNodes: XCTestCase {
var failures: [ValidationFailure] = []
for node in SYNTAX_NODES.compactMap(\.layoutNode) {
for child in node.children {
guard case .token(choices: let tokenChoices, _, _) = child.kind,
guard case .token(choices: let tokenChoices, _, _, _) = child.kind,
tokenChoices.count > 1,
tokenChoices.allSatisfy({ $0.isKeyword })
else {
Expand Down
8 changes: 8 additions & 0 deletions Sources/SwiftIDEUtils/SyntaxClassification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ extension RawTokenKind {
return .integerLiteral
case .keyword:
return .keyword
case .leadingBoxCorner:
return .none
case .leadingBoxJunction:
return .none
case .leftAngle:
return .none
case .leftBrace:
Expand Down Expand Up @@ -198,6 +202,10 @@ extension RawTokenKind {
return .stringLiteral
case .stringSegment:
return .stringLiteral
case .trailingBoxCorner:
return .none
case .trailingBoxJunction:
return .none
case .unknown:
return .none
case .wildcard:
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftIfConfig/ActiveSyntaxRewriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ extension Trivia {
for piece in pieces {
switch piece {
case .backslashes, .carriageReturnLineFeeds, .carriageReturns, .formfeeds, .newlines, .pounds, .spaces, .tabs,
.unexpectedText, .verticalTabs:
.unexpectedText, .verticalTabs, .boxDrawing:
piece.write(to: &stream)

case .blockComment(let text), .docBlockComment(let text), .docLineComment(let text), .lineComment(let text):
Expand Down
Loading