18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Support/ManagedStatic.h"
25 namespace ast_matchers {
61 : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
62 CodeCompletionLocation(nullptr) {
63 NextToken = getNextToken();
67 unsigned CodeCompletionOffset)
68 : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
69 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
70 NextToken = getNextToken();
79 NextToken = getNextToken();
91 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
93 Result.
Text = StringRef(CodeCompletionLocation, 0);
94 CodeCompletionLocation =
nullptr;
107 Result.
Text = Code.substr(0, 1);
108 Code = Code.drop_front();
112 Result.
Text = Code.substr(0, 1);
113 Code = Code.drop_front();
117 Result.
Text = Code.substr(0, 1);
118 Code = Code.drop_front();
122 Result.
Text = Code.substr(0, 1);
123 Code = Code.drop_front();
129 consumeStringLiteral(&Result);
132 case '0':
case '1':
case '2':
case '3':
case '4':
133 case '5':
case '6':
case '7':
case '8':
case '9':
135 consumeUnsignedLiteral(&Result);
141 size_t TokenLength = 1;
146 if (CodeCompletionLocation == Code.data() + TokenLength) {
147 CodeCompletionLocation =
nullptr;
149 Result.
Text = Code.substr(0, TokenLength);
150 Code = Code.drop_front(TokenLength);
153 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
158 Result.
Text = Code.substr(0, TokenLength);
159 Code = Code.drop_front(TokenLength);
162 Result.
Text = Code.substr(0, 1);
163 Code = Code.drop_front(1);
168 Result.
Range.
End = currentLocation();
173 void consumeUnsignedLiteral(TokenInfo *Result) {
175 if (Code.size() > 1) {
178 case 'x':
case 'b': Length = 2;
181 while (Length < Code.size() &&
isHexDigit(Code[Length]))
184 Result->Text = Code.substr(0, Length);
185 Code = Code.drop_front(Length);
188 if (!Result->Text.getAsInteger(0, Value)) {
190 Result->Value =
Value;
193 Range.Start = Result->Range.Start;
194 Range.End = currentLocation();
204 void consumeStringLiteral(TokenInfo *Result) {
205 bool InEscape =
false;
206 const char Marker = Code[0];
207 for (
size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
212 if (Code[Length] ==
'\\') {
216 if (Code[Length] == Marker) {
218 Result->Text = Code.substr(0, Length + 1);
219 Result->Value = Code.substr(1, Length - 1);
220 Code = Code.drop_front(Length + 1);
225 StringRef ErrorText = Code;
226 Code = Code.drop_front(Code.size());
228 Range.Start = Result->Range.Start;
229 Range.End = currentLocation();
235 void consumeWhitespace() {
237 if (Code[0] ==
'\n') {
239 StartOfLine = Code.drop_front();
241 Code = Code.drop_front();
245 SourceLocation currentLocation() {
246 SourceLocation Location;
247 Location.Line = Line;
248 Location.Column = Code.data() - StartOfLine.data() + 1;
253 StringRef StartOfLine;
257 const char *CodeCompletionLocation;
264 return std::vector<ArgKind>();
267 std::vector<MatcherCompletion>
269 return std::vector<MatcherCompletion>();
276 P->ContextStack.push_back(std::make_pair(C, 0u));
280 P->ContextStack.pop_back();
284 ++
P->ContextStack.back().second;
293 bool Parser::parseIdentifierPrefixImpl(
VariantValue *Value) {
299 NamedValues ? NamedValues->lookup(NameToken.Text)
318 return parseMatcherExpressionImpl(NameToken, Value);
325 bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
326 VariantValue *Value) {
343 std::vector<ParserValue> Args;
347 ScopedContextEntry SCE(
this, Ctor ? *Ctor :
nullptr);
355 if (Args.size() > 0) {
366 NameToken.Text, NameToken.Range,
368 ParserValue ArgValue;
371 if (!parseExpressionImpl(&ArgValue.Value)) {
375 Args.push_back(ArgValue);
391 addCompletion(BindToken, MatcherCompletion(
"bind(\"",
"bind", 1));
418 BindID = IDToken.Value.getString();
426 NameToken.Text, NameToken.Range);
427 SourceRange MatcherRange = NameToken.Range;
428 MatcherRange.End = EndToken.Range.End;
430 *Ctor, MatcherRange, BindID, Args, Error);
431 if (Result.isNull())
return false;
439 void Parser::addCompletion(
const TokenInfo &CompToken,
440 const MatcherCompletion& Completion) {
441 if (StringRef(Completion.TypedText).startswith(CompToken.Text) &&
442 Completion.Specificity > 0) {
443 Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
444 Completion.MatcherDecl, Completion.Specificity);
448 std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
449 ArrayRef<ArgKind> AcceptedTypes) {
450 if (!NamedValues)
return std::vector<MatcherCompletion>();
451 std::vector<MatcherCompletion> Result;
452 for (
const auto &Entry : *NamedValues) {
453 unsigned Specificity;
454 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
456 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
457 Result.emplace_back(Entry.getKey(), Decl, Specificity);
463 void Parser::addExpressionCompletions() {
469 for (ContextStackTy::iterator I = ContextStack.begin(),
470 E = ContextStack.end();
478 addCompletion(CompToken, Completion);
481 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
482 addCompletion(CompToken, Completion);
487 bool Parser::parseExpressionImpl(VariantValue *Value) {
494 return parseIdentifierPrefixImpl(Value);
497 addExpressionCompletions();
519 llvm_unreachable(
"Unknown token kind.");
524 Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
527 NamedValues(NamedValues), Error(Error) {}
529 Parser::RegistrySema::~RegistrySema() {}
532 Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
533 return Registry::lookupMatcherCtor(MatcherName);
539 if (BindID.empty()) {
540 return Registry::constructMatcher(Ctor, NameRange, Args, Error);
542 return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
547 std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(
549 return Registry::getAcceptedCompletionTypes(
Context);
552 std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
554 return Registry::getMatcherCompletions(AcceptedTypes);
557 bool Parser::parseExpression(StringRef Code,
Sema *
S,
561 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
571 std::vector<MatcherCompletion>
572 Parser::completeExpression(StringRef Code,
unsigned CompletionOffset,
Sema *
S,
576 Parser P(&Tokenizer, S, NamedValues, &Error);
578 P.parseExpressionImpl(&Dummy);
581 std::sort(P.Completions.begin(), P.Completions.end(),
588 return P.Completions;
592 Parser::parseMatcherExpression(StringRef Code,
Sema *
S,
596 if (!parseExpression(Code, S, NamedValues, &Value, Error))
604 if (!Result.hasValue()) {
virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error)=0
Process a matcher expression.
Simple matcher expression parser.
bool isMatcher() const
Matcher value functions.
static LLVM_READONLY bool isWhitespace(unsigned char c)
std::string getTypeAsString() const
String representation of the type of the value.
Registry of all known matchers.
CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
CodeTokenizer(StringRef MatcherCode, Diagnostics *Error, unsigned CodeCompletionOffset)
ArgStream addError(const SourceRange &Range, ErrorType Error)
Add an error to the diagnostics.
virtual llvm::Optional< MatcherCtor > lookupMatcherCtor(StringRef MatcherName)=0
Look up a matcher by name.
Matcher descriptor interface.
Simple tokenizer for the parser.
static const char *const ID_Bind
Some known identifiers.
Sema - This implements semantic analysis and AST building for C.
Matcher expression parser.
The result type of a method or function.
const TokenInfo & peekNextToken() const
Returns but doesn't consume the next token.
Helper class to manage error messages.
static LLVM_READONLY bool isAlphanumeric(unsigned char c)
Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].
TokenKind
Different possible tokens.
unsigned Specificity
Value corresponding to the "specificity" of the converted matcher.
std::string TypedText
The text to type to select this matcher.
static llvm::ManagedStatic< Parser::RegistrySema > DefaultRegistrySema
Interface to connect the parser with the registry and more.
Simple structure to hold information for one token from the parser.
TokenInfo::TokenKind nextTokenKind() const
virtual std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> Context)
Compute the list of completion types for Context.
A variant matcher object.
static LLVM_READONLY char toLowercase(char c)
virtual std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > AcceptedTypes)
Compute the list of completions that match any of AcceptedTypes.
TokenInfo consumeNextToken()
Consumes and returns the next token.
const VariantMatcher & getMatcher() const
llvm::StringMap< VariantValue > NamedValueMap
llvm::Optional< DynTypedMatcher > getSingleMatcher() const
Return a single matcher, if there is no ambiguity.
static LLVM_READONLY bool isHexDigit(unsigned char c)
Return true if this character is an ASCII hex digit: [0-9a-fA-F].
ScopedContextEntry(Parser *P, MatcherCtor C)