forked from OSchip/llvm-project
168 lines
4.6 KiB
C++
168 lines
4.6 KiB
C++
//===---- 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 "clang/ASTMatchers/Dynamic/Parser.h"
|
|
#include "clang/Basic/CharInfo.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSwitch.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);
|
|
}
|
|
|
|
llvm_unreachable("Invalid query kind");
|
|
}
|
|
|
|
} // namespace query
|
|
} // namespace clang
|