18 #include "llvm/ADT/Optional.h"
19 #include "llvm/Support/ManagedStatic.h"
24 namespace ast_matchers {
60 : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
61 CodeCompletionLocation(nullptr) {
62 NextToken = getNextToken();
66 unsigned CodeCompletionOffset)
67 : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
68 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
69 NextToken = getNextToken();
78 NextToken = getNextToken();
90 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
92 Result.
Text = StringRef(CodeCompletionLocation, 0);
93 CodeCompletionLocation =
nullptr;
106 Result.
Text = Code.substr(0, 1);
107 Code = Code.drop_front();
111 Result.
Text = Code.substr(0, 1);
112 Code = Code.drop_front();
116 Result.
Text = Code.substr(0, 1);
117 Code = Code.drop_front();
121 Result.
Text = Code.substr(0, 1);
122 Code = Code.drop_front();
128 consumeStringLiteral(&Result);
131 case '0':
case '1':
case '2':
case '3':
case '4':
132 case '5':
case '6':
case '7':
case '8':
case '9':
134 consumeNumberLiteral(&Result);
140 size_t TokenLength = 1;
145 if (CodeCompletionLocation == Code.data() + TokenLength) {
146 CodeCompletionLocation =
nullptr;
148 Result.
Text = Code.substr(0, TokenLength);
149 Code = Code.drop_front(TokenLength);
152 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
156 if (TokenLength == 4 && Code.startswith(
"true")) {
159 }
else if (TokenLength == 5 && Code.startswith(
"false")) {
161 Result.
Value =
false;
164 Result.
Text = Code.substr(0, TokenLength);
166 Code = Code.drop_front(TokenLength);
169 Result.
Text = Code.substr(0, 1);
170 Code = Code.drop_front(1);
175 Result.
Range.
End = currentLocation();
180 void consumeNumberLiteral(TokenInfo *Result) {
181 bool isFloatingLiteral =
false;
183 if (Code.size() > 1) {
186 case 'x':
case 'b': Length = 2;
189 while (Length < Code.size() &&
isHexDigit(Code[Length]))
193 while (Length < Code.size()) {
195 if (c ==
'-' || c ==
'+' || c ==
'.' ||
isHexDigit(c)) {
196 isFloatingLiteral =
true;
203 Result->Text = Code.substr(0, Length);
204 Code = Code.drop_front(Length);
206 if (isFloatingLiteral) {
209 std::string
Text = Result->Text.str();
210 double doubleValue = strtod(Text.c_str(), &end);
211 if (*end == 0 && errno == 0) {
213 Result->Value = doubleValue;
218 if (!Result->Text.getAsInteger(0, Value)) {
220 Result->Value =
Value;
226 Range.Start = Result->Range.Start;
227 Range.End = currentLocation();
236 void consumeStringLiteral(TokenInfo *Result) {
237 bool InEscape =
false;
238 const char Marker = Code[0];
239 for (
size_t Length = 1, Size = Code.size(); Length != Size; ++
Length) {
244 if (Code[Length] ==
'\\') {
248 if (Code[Length] == Marker) {
250 Result->Text = Code.substr(0, Length + 1);
251 Result->Value = Code.substr(1, Length - 1);
252 Code = Code.drop_front(Length + 1);
257 StringRef ErrorText = Code;
258 Code = Code.drop_front(Code.size());
260 Range.Start = Result->Range.Start;
261 Range.End = currentLocation();
267 void consumeWhitespace() {
269 if (Code[0] ==
'\n') {
271 StartOfLine = Code.drop_front();
273 Code = Code.drop_front();
277 SourceLocation currentLocation() {
278 SourceLocation Location;
279 Location.Line = Line;
280 Location.Column = Code.data() - StartOfLine.data() + 1;
285 StringRef StartOfLine;
289 const char *CodeCompletionLocation;
296 return std::vector<ArgKind>();
299 std::vector<MatcherCompletion>
301 return std::vector<MatcherCompletion>();
308 P->ContextStack.push_back(std::make_pair(C, 0u));
312 P->ContextStack.pop_back();
316 ++
P->ContextStack.back().second;
325 bool Parser::parseIdentifierPrefixImpl(
VariantValue *Value) {
331 NamedValues ? NamedValues->lookup(NameToken.Text)
350 return parseMatcherExpressionImpl(NameToken, Value);
357 bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
358 VariantValue *Value) {
375 std::vector<ParserValue> Args;
379 ScopedContextEntry SCE(
this, Ctor ? *Ctor :
nullptr);
387 if (Args.size() > 0) {
398 NameToken.Text, NameToken.Range,
400 ParserValue ArgValue;
403 if (!parseExpressionImpl(&ArgValue.Value)) {
407 Args.push_back(ArgValue);
423 addCompletion(BindToken, MatcherCompletion(
"bind(\"",
"bind", 1));
450 BindID = IDToken.Value.getString();
458 NameToken.Text, NameToken.Range);
459 SourceRange MatcherRange = NameToken.Range;
460 MatcherRange.End = EndToken.Range.End;
462 *Ctor, MatcherRange, BindID, Args, Error);
463 if (Result.isNull())
return false;
471 void Parser::addCompletion(
const TokenInfo &CompToken,
472 const MatcherCompletion& Completion) {
473 if (StringRef(Completion.TypedText).startswith(CompToken.Text) &&
474 Completion.Specificity > 0) {
475 Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
476 Completion.MatcherDecl, Completion.Specificity);
480 std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
481 ArrayRef<ArgKind> AcceptedTypes) {
482 if (!NamedValues)
return std::vector<MatcherCompletion>();
483 std::vector<MatcherCompletion> Result;
484 for (
const auto &Entry : *NamedValues) {
485 unsigned Specificity;
486 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
488 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
489 Result.emplace_back(Entry.getKey(), Decl, Specificity);
495 void Parser::addExpressionCompletions() {
501 for (ContextStackTy::iterator
I = ContextStack.begin(),
502 E = ContextStack.end();
510 addCompletion(CompToken, Completion);
513 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
514 addCompletion(CompToken, Completion);
519 bool Parser::parseExpressionImpl(VariantValue *Value) {
526 return parseIdentifierPrefixImpl(Value);
529 addExpressionCompletions();
551 llvm_unreachable(
"Unknown token kind.");
556 Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
559 NamedValues(NamedValues), Error(Error) {}
561 Parser::RegistrySema::~RegistrySema() {}
564 Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
565 return Registry::lookupMatcherCtor(MatcherName);
571 if (BindID.empty()) {
572 return Registry::constructMatcher(Ctor, NameRange, Args, Error);
574 return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
579 std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(
581 return Registry::getAcceptedCompletionTypes(
Context);
584 std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
586 return Registry::getMatcherCompletions(AcceptedTypes);
589 bool Parser::parseExpression(StringRef Code,
Sema *
S,
593 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
603 std::vector<MatcherCompletion>
604 Parser::completeExpression(StringRef Code,
unsigned CompletionOffset,
Sema *
S,
608 Parser P(&Tokenizer, S, NamedValues, &Error);
610 P.parseExpressionImpl(&Dummy);
613 std::sort(P.Completions.begin(), P.Completions.end(),
620 return P.Completions;
624 Parser::parseMatcherExpression(StringRef Code,
Sema *
S,
628 if (!parseExpression(Code, S, NamedValues, &Value, Error))
636 if (!Result.hasValue()) {
Simple matcher expression parser.
bool isMatcher() const
Matcher value functions.
static LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
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)
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
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.
detail::InMemoryDirectory::const_iterator I
Sema - This implements semantic analysis and AST building for C.
Matcher expression parser.
virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error)=0
Process a matcher expression.
const TokenInfo & peekNextToken() const
Returns but doesn't consume the next token.
Helper class to manage error messages.
ArgStream addError(SourceRange Range, ErrorType Error)
Add an error to the diagnostics.
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
detail::InMemoryDirectory::const_iterator E
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)
Converts the given ASCII character to its lowercase equivalent.
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)