Skip to content

Commit 82cb9bc

Browse files
committed
Extend swift-parser-cli with option to apply a static build configuration
Introduce the option "--build-configuration" to this test program. The input is JSON for a static build configuration, and that configuration will be applied to the parse tree to remove all inactive #if regions before doing anything else with the parse command (printing diagnostics, printing the tree, etc.). Also add a "print" subcommand that prints back the tree after applying whatever transformations are described above. One can use this to implement a basic "preprocess" step that removes all inactive #if regions from the source code.
1 parent 2fd4ea7 commit 82cb9bc

File tree

6 files changed

+96
-18
lines changed

6 files changed

+96
-18
lines changed

SwiftParserCLI/Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ let package = Package(
2525
"InstructionCounter",
2626
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
2727
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
28+
.product(name: "SwiftIfConfig", package: "swift-syntax"),
2829
.product(name: "SwiftOperators", package: "swift-syntax"),
2930
.product(name: "SwiftParser", package: "swift-syntax"),
3031
.product(name: "SwiftParserDiagnostics", package: "swift-syntax"),
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ArgumentParser
14+
import SwiftParser
15+
import SwiftSyntax
16+
17+
struct Print: ParsableCommand, ParseCommand {
18+
static var configuration = CommandConfiguration(
19+
commandName: "print",
20+
abstract: "Print the parsed source file after applying any other arguments"
21+
)
22+
23+
@OptionGroup
24+
var arguments: ParseArguments
25+
26+
@Flag(name: .long, help: "Include trivia in the output")
27+
var includeTrivia: Bool = false
28+
29+
func run() throws {
30+
try withParsedSourceFile(wantDiagnostics: false) { (tree, _) in
31+
print(tree.description)
32+
}
33+
}
34+
}

SwiftParserCLI/Sources/swift-parser-cli/Commands/PrintDiags.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@ struct PrintDiags: ParsableCommand, ParseCommand {
2828
var colorize: Bool = false
2929

3030
func run() throws {
31-
try sourceFileContents.withUnsafeBufferPointer { sourceBuffer in
32-
let tree = Parser.parse(source: sourceBuffer)
33-
var diags = ParseDiagnosticsGenerator.diagnostics(for: tree)
34-
if foldSequences {
35-
diags += foldAllSequences(tree).1
36-
}
37-
31+
try withParsedSourceFile { (tree, diags) in
3832
var group = GroupedDiagnostics()
3933
group.addSourceFile(tree: tree, displayName: sourceFileName, diagnostics: diags)
4034
let annotatedSource = DiagnosticsFormatter.annotateSources(

SwiftParserCLI/Sources/swift-parser-cli/Commands/PrintTree.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,8 @@ struct PrintTree: ParsableCommand, ParseCommand {
2727
var includeTrivia: Bool = false
2828

2929
func run() throws {
30-
try sourceFileContents.withUnsafeBufferPointer { sourceBuffer in
31-
let tree = Parser.parse(source: sourceBuffer)
32-
33-
let resultTree: Syntax
34-
if foldSequences {
35-
resultTree = foldAllSequences(tree).0
36-
} else {
37-
resultTree = Syntax(tree)
38-
}
39-
40-
print(resultTree.debugDescription(includeTrivia: includeTrivia))
30+
try withParsedSourceFile(wantDiagnostics: false) { (tree, _) in
31+
print(tree.debugDescription(includeTrivia: includeTrivia))
4132
}
4233
}
4334
}

SwiftParserCLI/Sources/swift-parser-cli/ParseCommand.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import ArgumentParser
14+
import Foundation
15+
import SwiftDiagnostics
16+
import SwiftIfConfig
17+
import SwiftParser
18+
import SwiftParserDiagnostics
19+
import SwiftSyntax
1420

1521
struct ParseArguments: ParsableArguments {
1622
@Argument(help: "The source file that should be parsed; if omitted, use stdin")
@@ -21,6 +27,9 @@ struct ParseArguments: ParsableArguments {
2127

2228
@Flag(name: .long, help: "Perform sequence folding with the standard operators")
2329
var foldSequences: Bool = false
30+
31+
@Option(help: "Apply the given static build configuration to the source text before further processing")
32+
var buildConfiguration: String?
2433
}
2534

2635
/// A command that has arguments to parse source code
@@ -50,4 +59,52 @@ extension ParseCommand {
5059

5160
/// Whether sequence folding using standard operators should be performed
5261
var foldSequences: Bool { arguments.foldSequences }
62+
63+
/// Parse the source file, applying any additional configuration options
64+
/// such as sequence folding, and provide it to the given closure.
65+
func withParsedSourceFile<R>(
66+
wantDiagnostics: Bool = true,
67+
body: (SourceFileSyntax, [Diagnostic]) throws -> R
68+
) throws -> R {
69+
return try sourceFileContents.withUnsafeBufferPointer { sourceBuffer in
70+
// Parse the sources
71+
var tree = Parser.parse(source: sourceBuffer)
72+
73+
// If we want diagnostics, gather them from the parser.
74+
var diags: [Diagnostic] = []
75+
if wantDiagnostics {
76+
diags += ParseDiagnosticsGenerator.diagnostics(for: tree)
77+
}
78+
79+
// If we are supposed to fold sequences, do it now.
80+
if foldSequences {
81+
let (folded, foldDiags) = foldAllSequences(tree)
82+
83+
tree = folded.cast(SourceFileSyntax.self)
84+
if wantDiagnostics {
85+
diags += foldDiags
86+
}
87+
}
88+
89+
// If we are supposed to apply a build configuration, do it now.
90+
if let buildConfiguration = arguments.buildConfiguration {
91+
// Load the build configuration.
92+
let buildConfigurationText = try Data(contentsOf: URL(fileURLWithPath: buildConfiguration))
93+
let staticBuildConfiguration = try JSONDecoder().decode(
94+
StaticBuildConfiguration.self,
95+
from: buildConfigurationText
96+
)
97+
98+
// Apply the build configuration.
99+
let (configured, configuredDiags) = tree.removingInactive(in: staticBuildConfiguration)
100+
101+
tree = configured.cast(SourceFileSyntax.self)
102+
if wantDiagnostics {
103+
diags += configuredDiags
104+
}
105+
}
106+
107+
return try body(tree, diags)
108+
}
109+
}
53110
}

SwiftParserCLI/Sources/swift-parser-cli/swift-parser-cli.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class SwiftParserCli: ParsableCommand {
3232
subcommands: [
3333
BasicFormat.self,
3434
PerformanceTest.self,
35+
Print.self,
3536
PrintDiags.self,
3637
PrintTree.self,
3738
Reduce.self,

0 commit comments

Comments
 (0)