Skip to content

Commit dcc3894

Browse files
authored
Merge pull request #1007 from SimplyDanny/runnable-examples
Make examples runnable
2 parents 2016c7e + 957c777 commit dcc3894

File tree

7 files changed

+152
-66
lines changed

7 files changed

+152
-66
lines changed

Examples/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
/.build
Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
import SwiftSyntax
2-
import SwiftSyntaxParser
2+
import SwiftParser
33
import Foundation
44

55
/// AddOneToIntegerLiterals will visit each token in the Syntax tree, and
66
/// (if it is an integer literal token) add 1 to the integer and return the
77
/// new integer literal token.
88
///
9-
/// For example will it turn:
9+
/// For example, it will turn
1010
/// ```
1111
/// let x = 2
1212
/// let y = 3_000
1313
/// ```
14-
/// into:
14+
/// into
1515
/// ```
1616
/// let x = 3
1717
/// let y = 3001
1818
/// ```
19-
class AddOneToIntegerLiterals: SyntaxRewriter {
20-
override func visit(_ token: TokenSyntax) -> Syntax {
19+
///
20+
private class AddOneToIntegerLiterals: SyntaxRewriter {
21+
override func visit(_ token: TokenSyntax) -> TokenSyntax {
2122
// Only transform integer literals.
2223
guard case .integerLiteral(let text) = token.tokenKind else {
23-
return Syntax(token)
24+
return token
2425
}
2526

2627
// Remove underscores from the original text.
@@ -33,12 +34,18 @@ class AddOneToIntegerLiterals: SyntaxRewriter {
3334
let newIntegerLiteralToken = token.withKind(.integerLiteral("\(int + 1)"))
3435

3536
// Return the new integer literal.
36-
return Syntax(newIntegerLiteralToken)
37+
return newIntegerLiteralToken
3738
}
3839
}
3940

40-
let file = CommandLine.arguments[1]
41-
let url = URL(fileURLWithPath: file)
42-
let sourceFile = try SyntaxParser.parse(url)
43-
let incremented = AddOneToIntegerLiterals().visit(sourceFile)
44-
print(incremented)
41+
@main
42+
struct Main {
43+
static func main() throws {
44+
let file = CommandLine.arguments[1]
45+
let url = URL(fileURLWithPath: file)
46+
let source = try String(contentsOf: url, encoding: .utf8)
47+
let sourceFile = Parser.parse(source: source)
48+
let incremented = AddOneToIntegerLiterals().visit(sourceFile)
49+
print(incremented)
50+
}
51+
}
Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
11
import SwiftSyntaxBuilder
22

3-
/// This example will print the following example:
3+
/// This example will print the following code:
44
///
5-
///```
5+
/// ```
66
/// import Foundation
77
/// import UIKit
88
/// class SomeViewController{
99
/// let tableView: UITableView
1010
/// }
11-
///```
12-
13-
let source = SourceFile {
14-
ImportDecl(path: "Foundation")
15-
ImportDecl(path: "UIKit")
16-
ClassDecl(identifier: "SomeViewController") {
17-
VariableDecl(.let, name: "tableView", type: "UITableView")
18-
}
19-
}
11+
/// ```
12+
///
13+
@main
14+
struct Main {
15+
static func main() {
16+
let source = SourceFile {
17+
ImportDecl(path: "Foundation")
18+
ImportDecl(path: "UIKit")
19+
ClassDecl(identifier: "SomeViewController") {
20+
VariableDecl(.let, name: "tableView", type: "UITableView")
21+
}
22+
}
2023

21-
let syntax = source.buildSyntax(format: Format())
24+
let syntax = source.build()
2225

23-
var text = ""
24-
syntax.write(to: &text)
26+
var text = ""
27+
syntax.write(to: &text)
2528

26-
print(text)
29+
print(text)
30+
}
31+
}

Examples/MigrateToNewIfLetSyntax.swift

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class MigrateToNewIfLetSyntax: SyntaxRewriter {
2929
let initializer = binding.initializer,
3030
// ... and both sides of the assignment are the same identifiers.
3131
binding.pattern.withoutTrivia().description == initializer.value.withoutTrivia().description {
32-
// Remove the initializer ...
32+
// Remove the initializer ...
3333
binding.initializer = nil
3434
// ... and remove whitespace before the comma (in `if` statements with multiple conditions).
3535
if index != node.conditions.count - 1 {
@@ -41,19 +41,16 @@ class MigrateToNewIfLetSyntax: SyntaxRewriter {
4141
}
4242
return StmtSyntax(node.withConditions(ConditionElementListSyntax(newConditions)))
4343
}
44-
45-
/// Utility function to migrate all swift files in a folder and its subfolders
46-
static func migrate(folderPath: String) {
47-
for case let fileURL as String in FileManager.default.enumerator(atPath: folderPath)! {
48-
if fileURL.hasSuffix("swift") {
49-
print("Rewriting", fileURL)
50-
let fullPath = folderPath + "/" + fileURL
51-
let tree = try! Parser.parse(source: String(data: FileManager.default.contents(atPath: fullPath)!, encoding: .utf8 )!)
52-
let newTree = MigrateToNewIfLetSyntax().visit(tree)
53-
try! newTree.description.write(toFile: fullPath, atomically: true, encoding: .utf8)
54-
}
55-
}
56-
}
5744
}
5845

59-
MigrateToNewIfLetSyntax.migrate(folderPath: "/path/to/folder")
46+
@main
47+
struct Main {
48+
static func main() throws {
49+
let file = CommandLine.arguments[1]
50+
let url = URL(fileURLWithPath: file)
51+
let source = try String(contentsOf: url, encoding: .utf8)
52+
let sourceFile = Parser.parse(source: source)
53+
let rewritten = MigrateToNewIfLetSyntax().visit(sourceFile)
54+
print(rewritten)
55+
}
56+
}

Examples/Package.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// swift-tools-version: 5.7
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "Examples",
7+
platforms: [
8+
.macOS(.v10_15),
9+
],
10+
products: [
11+
.executable(name: "AddOneToIntegerLiterals", targets: ["AddOneToIntegerLiterals"]),
12+
.executable(name: "CodeGenerationUsingSwiftSyntaxBuilder", targets: ["CodeGenerationUsingSwiftSyntaxBuilder"]),
13+
.executable(name: "MigrateToNewIfLetSyntax", targets: ["MigrateToNewIfLetSyntax"]),
14+
],
15+
dependencies: [
16+
.package(path: "../"),
17+
],
18+
targets: [
19+
.executableTarget(
20+
name: "AddOneToIntegerLiterals",
21+
dependencies: [
22+
.product(name: "SwiftParser", package: "swift-syntax"),
23+
.product(name: "SwiftSyntax", package: "swift-syntax"),
24+
],
25+
path: ".",
26+
exclude: ["README.md", "CodeGenerationUsingSwiftSyntaxBuilder.swift", "MigrateToNewIfLetSyntax.swift"]
27+
),
28+
.executableTarget(
29+
name: "CodeGenerationUsingSwiftSyntaxBuilder",
30+
dependencies: [
31+
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
32+
],
33+
path: ".",
34+
exclude: ["README.md", "AddOneToIntegerLiterals.swift", "MigrateToNewIfLetSyntax.swift"]
35+
),
36+
.executableTarget(
37+
name: "MigrateToNewIfLetSyntax",
38+
dependencies: [
39+
.product(name: "SwiftParser", package: "swift-syntax"),
40+
.product(name: "SwiftSyntax", package: "swift-syntax"),
41+
],
42+
path: ".",
43+
exclude: ["README.md", "CodeGenerationUsingSwiftSyntaxBuilder.swift", "AddOneToIntegerLiterals.swift"]
44+
),
45+
]
46+
)

Examples/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
# Snippets (Examples)
1+
# Examples
22

3-
- Command line tool to add one to every integer literal in a source file [AddOneToIntegerLiterals.swift](AddOneToIntegerLiterals.swift).
4-
- Code-generate a simple source file using SwiftSyntaxBuilder [CodeGenerationUsingSwiftSyntaxBuilder.swift](CodeGenerationUsingSwiftSyntaxBuilder.swift)
3+
Each example can be executed by navigating into this folder and running `swift run <example> <arguments>`. There is the following set of examples available:
4+
5+
- [AddOneToIntegerLiterals](AddOneToIntegerLiterals.swift): Command line tool to add 1 to every integer literal in a source file
6+
- [CodeGenerationUsingSwiftSyntaxBuilder](CodeGenerationUsingSwiftSyntaxBuilder.swift): Code-generate a simple source file using SwiftSyntaxBuilder
7+
- [MigrateToNewIfLetSyntax](MigrateToNewIfLetSyntax.swift): Command line tool to transform optional bindings in `if` statements to the new shorthand syntax
58

69
## Some Example Usages
710

build-script.py

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
PACKAGE_DIR = os.path.dirname(os.path.realpath(__file__))
1717
WORKSPACE_DIR = os.path.dirname(PACKAGE_DIR)
18+
EXAMPLES_DIR = os.path.join(PACKAGE_DIR, "Examples")
1819
SOURCES_DIR = os.path.join(PACKAGE_DIR, "Sources")
1920
SWIFTSYNTAX_DIR = os.path.join(SOURCES_DIR, "SwiftSyntax")
2021
SWIFTSYNTAX_DOCUMENTATION_DIR = \
@@ -401,13 +402,13 @@ def clear_gyb_files_from_previous_run(
401402

402403

403404
def get_swiftpm_invocation(
404-
toolchain: str, action: str, build_dir: Optional[str],
405+
toolchain: str, action: str, package_dir: str, build_dir: Optional[str],
405406
multiroot_data_file: Optional[str], release: bool
406407
) -> List[str]:
407408
swift_exec = os.path.join(toolchain, "bin", "swift")
408409

409410
swiftpm_call = [swift_exec, action]
410-
swiftpm_call.extend(["--package-path", PACKAGE_DIR])
411+
swiftpm_call.extend(["--package-path", package_dir])
411412
if platform.system() != "Darwin":
412413
swiftpm_call.extend(["--enable-test-discovery"])
413414
if release:
@@ -421,9 +422,12 @@ def get_swiftpm_invocation(
421422

422423

423424
class Builder(object):
424-
swiftpm_call: List[str]
425425
verbose: bool
426426
toolchain: str
427+
build_dir: Optional[str]
428+
multiroot_data_file: Optional[str]
429+
release: bool
430+
disable_sandbox: bool
427431

428432
def __init__(
429433
self,
@@ -434,23 +438,38 @@ def __init__(
434438
verbose: bool,
435439
disable_sandbox: bool = False,
436440
) -> None:
437-
self.swiftpm_call = get_swiftpm_invocation(
438-
toolchain=toolchain,
439-
action="build",
440-
build_dir=build_dir,
441-
multiroot_data_file=multiroot_data_file,
442-
release=release,
443-
)
444-
if disable_sandbox:
445-
self.swiftpm_call.append("--disable-sandbox")
446-
if verbose:
447-
self.swiftpm_call.extend(["--verbose"])
441+
self.build_dir = build_dir
442+
self.multiroot_data_file = multiroot_data_file
443+
self.release = release
444+
self.disable_sandbox = disable_sandbox
448445
self.verbose = verbose
449446
self.toolchain = toolchain
450447

451-
def build(self, product_name: str) -> None:
452-
print("** Building " + product_name + " **")
453-
command = list(self.swiftpm_call)
448+
def __get_swiftpm_invocation(self, package_dir: str) -> List[str]:
449+
invocation = get_swiftpm_invocation(
450+
self.toolchain,
451+
"build",
452+
package_dir,
453+
self.build_dir,
454+
self.multiroot_data_file,
455+
self.release
456+
)
457+
if self.disable_sandbox:
458+
invocation.append("--disable-sandbox")
459+
if self.verbose:
460+
invocation.append("--verbose")
461+
return invocation
462+
463+
def buildProduct(self, product_name: str) -> None:
464+
print("** Building product " + product_name + " **")
465+
self.__build(PACKAGE_DIR, product_name)
466+
467+
def buildExample(self, example_name: str) -> None:
468+
print("** Building example " + example_name + " **")
469+
self.__build(EXAMPLES_DIR, example_name)
470+
471+
def __build(self, package_dir: str, product_name: str) -> None:
472+
command = list(self.__get_swiftpm_invocation(package_dir))
454473
command.extend(["--product", product_name])
455474

456475
env = dict(os.environ)
@@ -599,6 +618,7 @@ def find_lit_test_helper_exec(
599618
swiftpm_call = get_swiftpm_invocation(
600619
toolchain=toolchain,
601620
action="build",
621+
package_dir=PACKAGE_DIR,
602622
build_dir=build_dir,
603623
multiroot_data_file=None,
604624
release=release,
@@ -651,6 +671,7 @@ def run_xctests(toolchain: str, build_dir: Optional[str],
651671
swiftpm_call = get_swiftpm_invocation(
652672
toolchain=toolchain,
653673
action="test",
674+
package_dir=PACKAGE_DIR,
654675
build_dir=build_dir,
655676
multiroot_data_file=multiroot_data_file,
656677
release=release,
@@ -738,9 +759,14 @@ def build_command(args: argparse.Namespace) -> None:
738759
)
739760
# Until rdar://53881101 is implemented, we cannot request a build of multiple
740761
# targets simultaneously. For now, just build one product after the other.
741-
builder.build("SwiftSyntax")
742-
builder.build("SwiftSyntaxParser")
743-
builder.build("SwiftSyntaxBuilder")
762+
builder.buildProduct("SwiftSyntax")
763+
builder.buildProduct("SwiftSyntaxParser")
764+
builder.buildProduct("SwiftSyntaxBuilder")
765+
766+
# Build examples
767+
builder.buildExample("AddOneToIntegerLiterals")
768+
builder.buildExample("CodeGenerationUsingSwiftSyntaxBuilder")
769+
builder.buildExample("MigrateToNewIfLetSyntax")
744770
except subprocess.CalledProcessError as e:
745771
fail_for_called_process_error("Building SwiftSyntax failed", e)
746772

@@ -756,7 +782,7 @@ def test_command(args: argparse.Namespace) -> None:
756782
disable_sandbox=args.disable_sandbox,
757783
)
758784

759-
builder.build("lit-test-helper")
785+
builder.buildProduct("lit-test-helper")
760786

761787
run_tests(
762788
toolchain=args.toolchain,

0 commit comments

Comments
 (0)