summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-query/QueryParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-query/QueryParser.cpp')
-rw-r--r--clang-tools-extra/clang-query/QueryParser.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp
new file mode 100644
index 00000000000..1e4493e609e
--- /dev/null
+++ b/clang-tools-extra/clang-query/QueryParser.cpp
@@ -0,0 +1,165 @@
+//===---- QueryParser.cpp - clang-query command parser --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "QueryParser.h"
+#include "Query.h"
+#include "QuerySession.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/Basic/CharInfo.h"
+
+using namespace llvm;
+using namespace clang::ast_matchers::dynamic;
+
+namespace clang {
+namespace query {
+
+// Lex any amount of whitespace followed by a "word" (any sequence of
+// non-whitespace characters) from the start of region [Begin,End). If no word
+// is found before End, return StringRef(). Begin is adjusted to exclude the
+// lexed region.
+static StringRef LexWord(const char *&Begin, const char *End) {
+ while (true) {
+ if (Begin == End)
+ return StringRef();
+
+ if (!isWhitespace(*Begin))
+ break;
+
+ ++Begin;
+ }
+
+ const char *WordBegin = Begin;
+
+ while (true) {
+ ++Begin;
+
+ if (Begin == End || isWhitespace(*Begin))
+ return StringRef(WordBegin, Begin - WordBegin);
+ }
+}
+
+static QueryRef ParseSetBool(bool QuerySession::*Var, StringRef ValStr) {
+ unsigned Value = StringSwitch<unsigned>(ValStr)
+ .Case("false", 0)
+ .Case("true", 1)
+ .Default(~0u);
+ if (Value == ~0u) {
+ return new InvalidQuery("expected 'true' or 'false', got '" + ValStr + "'");
+ }
+ return new SetQuery<bool>(Var, Value);
+}
+
+static QueryRef ParseSetOutputKind(StringRef ValStr) {
+ unsigned OutKind = StringSwitch<unsigned>(ValStr)
+ .Case("diag", OK_Diag)
+ .Case("print", OK_Print)
+ .Case("dump", OK_Dump)
+ .Default(~0u);
+ if (OutKind == ~0u) {
+ return new InvalidQuery("expected 'diag', 'print' or 'dump', got '" +
+ ValStr + "'");
+ }
+ return new SetQuery<OutputKind>(&QuerySession::OutKind, OutputKind(OutKind));
+}
+
+static QueryRef EndQuery(const char *Begin, const char *End, QueryRef Q) {
+ const char *Extra = Begin;
+ if (!LexWord(Begin, End).empty())
+ return new InvalidQuery("unexpected extra input: '" +
+ StringRef(Extra, End - Extra) + "'");
+ return Q;
+}
+
+enum ParsedQueryKind {
+ PQK_Invalid,
+ PQK_NoOp,
+ PQK_Help,
+ PQK_Match,
+ PQK_Set
+};
+
+enum ParsedQueryVariable {
+ PQV_Invalid,
+ PQV_Output,
+ PQV_BindRoot
+};
+
+QueryRef ParseQuery(StringRef Line) {
+ const char *Begin = Line.data();
+ const char *End = Line.data() + Line.size();
+
+ StringRef CommandStr = LexWord(Begin, End);
+ ParsedQueryKind QKind = StringSwitch<ParsedQueryKind>(CommandStr)
+ .Case("", PQK_NoOp)
+ .Case("help", PQK_Help)
+ .Case("m", PQK_Match)
+ .Case("match", PQK_Match)
+ .Case("set", PQK_Set)
+ .Default(PQK_Invalid);
+
+ switch (QKind) {
+ case PQK_NoOp:
+ return new NoOpQuery;
+
+ case PQK_Help:
+ return EndQuery(Begin, End, new HelpQuery);
+
+ case PQK_Match: {
+ Diagnostics Diag;
+ Optional<DynTypedMatcher> Matcher =
+ Parser::parseMatcherExpression(StringRef(Begin, End - Begin), &Diag);
+ if (!Matcher) {
+ std::string ErrStr;
+ llvm::raw_string_ostream OS(ErrStr);
+ Diag.printToStreamFull(OS);
+ return new InvalidQuery(OS.str());
+ }
+ return new MatchQuery(*Matcher);
+ }
+
+ case PQK_Set: {
+ StringRef VarStr = LexWord(Begin, End);
+ if (VarStr.empty())
+ return new InvalidQuery("expected variable name");
+
+ ParsedQueryVariable Var = StringSwitch<ParsedQueryVariable>(VarStr)
+ .Case("output", PQV_Output)
+ .Case("bind-root", PQV_BindRoot)
+ .Default(PQV_Invalid);
+ if (Var == PQV_Invalid)
+ return new InvalidQuery("unknown variable: '" + VarStr + "'");
+
+ StringRef ValStr = LexWord(Begin, End);
+ if (ValStr.empty())
+ return new InvalidQuery("expected variable value");
+
+ QueryRef Q;
+ switch (Var) {
+ case PQV_Output:
+ Q = ParseSetOutputKind(ValStr);
+ break;
+ case PQV_BindRoot:
+ Q = ParseSetBool(&QuerySession::BindRoot, ValStr);
+ break;
+ case PQV_Invalid:
+ llvm_unreachable("Invalid query kind");
+ }
+
+ return EndQuery(Begin, End, Q);
+ }
+
+ case PQK_Invalid:
+ return new InvalidQuery("unknown command: " + CommandStr);
+ }
+}
+
+} // namespace query
+} // namespace clang
OpenPOWER on IntegriCloud