Stub out a tool that runs a script over a Swift AST.

The tool is currently hard-coded to find functions in the SwiftUI library that take parameters of type `(...) -> T` where `T: View` but where the parameter isn't annotated with `@ViewBuilder`.  The long-term vision here, of course, is that this reads and interprets a script file, but that's quite a bit more work (especially to generate a million bindings to the AST).  In the meantime, I think having a functional harness that people familiar with the C++ API can easily hack on to make their own tools is still pretty useful.

The harness does try to open a script file and lex the first token of it, because that's exactly as far as I got before deciding to hard-code the query I wanted.  Since this input is otherwise ignored, you can just point the tool at any old `.swift` file (or just an empty file) and it'll be fine.
This commit is contained in:
John McCall
2019-07-25 01:13:42 -04:00
parent 48024ec734
commit d53a88d920
8 changed files with 538 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
//===--- ASTScriptConfiguration.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// Configuration parsing for an AST script.
///
//===----------------------------------------------------------------------===//
#include "ASTScriptConfiguration.h"
#include "swift/Basic/QuotedString.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
using namespace scripting;
std::unique_ptr<ASTScriptConfiguration>
ASTScriptConfiguration::parse(CompilerInstance &compiler,
ArrayRef<const char *> args) {
bool hadError = false;
std::unique_ptr<ASTScriptConfiguration> result(
new ASTScriptConfiguration(compiler));
#define emitError(WHAT) do { \
llvm::errs() << "error: " << WHAT << "\n"; \
hadError = true; \
} while (0)
auto popArg = [&](const char *what) -> StringRef {
// Gracefully handle the case of running out of arguments.
if (args.empty()) {
assert(what && "expected explanation here!");
emitError(what);
return "";
}
auto arg = args.front();
args = args.slice(1);
return arg;
};
auto setScriptFile = [&](StringRef filename) {
if (!result->ScriptFile.empty()) {
emitError("multiple script files ("
<< QuotedString(result->ScriptFile)
<< ", "
<< QuotedString(filename)
<< ")");
}
result->ScriptFile = filename;
};
// Parse the arguments.
while (!hadError && !args.empty()) {
StringRef arg = popArg(nullptr);
if (!arg.startswith("-")) {
setScriptFile(arg);
} else if (arg == "-f") {
StringRef filename = popArg("expected path after -f");
if (!hadError)
setScriptFile(filename);
} else if (arg == "-h" || arg == "--help") {
llvm::errs()
<< "usage: swift-ast-script <script-args> -- <compiler-args\n"
"accepted script arguments:\n"
" <filename>\n"
" -f <filename>\n"
" Specify the file to use as the script; required argument\n";
hadError = true;
} else {
emitError("unknown argument " << QuotedString(arg));
}
}
// Check well-formedness.
if (!hadError) {
if (result->ScriptFile.empty()) {
emitError("script file is required");
}
}
if (hadError)
result.reset();
return result;
}