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

[Gardening] Expand SwiftSyntax's Documentation #1168

Merged
merged 3 commits into from
Jan 4, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 9 additions & 6 deletions Sources/SwiftParser/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@
/// from a bad parse should be left `nonmutating` to indicate that they do not
/// consume tokens.
///
/// Token consumption is generally conditional via ``TokenConsumer/consume(if:)``
/// or unconditional via `consumeAnyToken()`. During parsing, it is
/// also useful to assert that the current token matches some expected structure
/// via ``TokenConsumer/eat(_:)``, which acts like ``TokenConsumer/consume(if:)``,
/// but asserts if the parsed token did not match the expected kind.
/// Token consumption is generally either unconditional via ``TokenConsumer/consumeAnyToken()``
CodaFi marked this conversation as resolved.
Show resolved Hide resolved
/// or conditional via a combination of ``TokenConsumer/at(_:where:)``
/// and `TokenConsumer.eat(_:)`. When parsing conditionally, `at` returns a
/// handle that is passed to `eat`. This ensures that any structure that is
/// checked for is actually parsed by the parser at that position. If the parser
/// detects any unexpected structure, an assertion is raised. To perform
/// conditional consumption and validation in one step, use `consume(if:)` for
/// one kind of token, or `consume(ifAny:)` to consume many kinds of tokens.
///
/// It can also be useful to expect the presence of certain structural elements.
/// For example, a function that parses the content of code items might expect
Expand All @@ -43,7 +46,7 @@
/// /* */
/// let rbrace = self.expect(.rightBrace)
///
/// Unlike ``TokenConsumer/eat(_:)``, `expect(_:)` returns
/// Unlike ``TokenConsumer/eat(_:)``, ``Parser/expect(_:remapping:)`` returns
/// a `missing` token of the given kind. This allows the tree to remain
/// well-formed even when the input text is not, all without affecting
/// source fidelity.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

@main struct ImportFormatter {
static func main() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import SwiftSyntax
import SwiftParser
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
let sourceFile = Parser.parse(source: file)
var items = classifyItems(in: sourceFile)
let pivotPoint = items.partition { item in
switch item {
case .import(_, _):
return false
case .other(_):
return true
}
}
items[..<pivotPoint]
.sort { lhs, rhs in
guard
case let .import(lhsImport, _) = lhs,
case let .import(rhsImport, _) = rhs
else {
fatalError("Partition must only contain import items!")
}
return lhsImport.path.description < rhsImport.path.description
}
let formattedStatements = items.map { item in
switch item {
case .import(_, let statement):
return statement
case .other(let statement):
return statement
}
}
return
sourceFile
.withStatements(CodeBlockItemListSyntax(formattedStatements))
}

enum Item {
case `import`(ImportDeclSyntax, CodeBlockItemSyntax)
case other(CodeBlockItemSyntax)
}

func classifyItems(in file: SourceFileSyntax) -> [Item] {
file
.statements
.map { statement in
if case .decl(let decl) = statement.item,
let `import` = decl.as(ImportDeclSyntax.self)
{
return .import(`import`, statement)
} else {
return .other(statement)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import SwiftSyntax
import SwiftParser
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
let sourceFile = Parser.parse(source: file)
var items = classifyItems(in: sourceFile)
let pivotPoint = items.partition { item in
switch item {
case .import(_, _):
return false
case .other(_):
return true
}
}
items[..<pivotPoint]
.sort { lhs, rhs in
guard
case let .import(lhsImport, _) = lhs,
case let .import(rhsImport, _) = rhs
else {
fatalError("Partition must only contain import items!")
}
return lhsImport.path.description < rhsImport.path.description
}
let formattedStatements = items.enumerated().map { (offset, item) in
switch item {
case .import(_, let statement):
return
statement
.withLeadingTrivia(offset == 0 ? [] : .newline)
.withTrailingTrivia([])
case .other(let statement):
return statement
}
}
return
sourceFile
.withStatements(CodeBlockItemListSyntax(formattedStatements))
}

enum Item {
case `import`(ImportDeclSyntax, CodeBlockItemSyntax)
case other(CodeBlockItemSyntax)
}

func classifyItems(in file: SourceFileSyntax) -> [Item] {
file
.statements
.map { statement in
if case .decl(let decl) = statement.item,
let `import` = decl.as(ImportDeclSyntax.self)
{
return .import(`import`, statement)
} else {
return .other(statement)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
/* Formatter here */
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import SwiftSyntax
import SwiftParser
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
/* Formatter here */
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import SwiftSyntax
import SwiftParser
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
let sourceFile = Parser.parse(source: file)
/* format source file */
return sourceFile
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import SwiftSyntax
import SwiftParser
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
let sourceFile = Parser.parse(source: file)
var items = classifyItems(in: sourceFile)
return sourceFile
}

enum Item {
case `import`(ImportDeclSyntax, CodeBlockItemSyntax)
case other(CodeBlockItemSyntax)
}

func classifyItems(in file: SourceFileSyntax) -> [Item] {
/* Classify items here */
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import SwiftSyntax
import SwiftParser
import Foundation

@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}

let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}

guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}

let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}

func formatImports(in file: String) -> SourceFileSyntax {
let sourceFile = Parser.parse(source: file)
var items = classifyItems(in: sourceFile)
return sourceFile
}

enum Item {
case `import`(ImportDeclSyntax, CodeBlockItemSyntax)
case other(CodeBlockItemSyntax)
}

func classifyItems(in file: SourceFileSyntax) -> [Item] {
file
.statements
.map { statement in
if case .decl(let decl) = statement.item,
let `import` = decl.as(ImportDeclSyntax.self)
{
return .import(`import`, statement)
} else {
return .other(statement)
}
}
}
}