19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/ManagedStatic.h"
33namespace ast_matchers {
72 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
73 NextToken = getNextToken();
77 unsigned CodeCompletionOffset)
78 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
79 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
80 NextToken = getNextToken();
89 NextToken = getNextToken();
95 NextToken = getNextToken();
112 Result.Range.Start = currentLocation();
114 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
116 Result.Text = StringRef(CodeCompletionLocation, 0);
117 CodeCompletionLocation =
nullptr;
129 Code = Code.drop_until([](
char c) {
return c ==
'\n'; });
130 return getNextToken();
133 Result.Text = Code.substr(0, 1);
134 Code = Code.drop_front();
138 Result.Text = Code.substr(0, 1);
139 Code = Code.drop_front();
143 StartOfLine = Code.drop_front();
145 Result.Text = Code.substr(0, 1);
146 Code = Code.drop_front();
150 Result.Text = Code.substr(0, 1);
151 Code = Code.drop_front();
155 Result.Text = Code.substr(0, 1);
156 Code = Code.drop_front();
162 consumeStringLiteral(&
Result);
165 case '0':
case '1':
case '2':
case '3':
case '4':
166 case '5':
case '6':
case '7':
case '8':
case '9':
168 consumeNumberLiteral(&
Result);
174 size_t TokenLength = 1;
179 if (CodeCompletionLocation == Code.data() + TokenLength) {
180 CodeCompletionLocation =
nullptr;
182 Result.Text = Code.substr(0, TokenLength);
183 Code = Code.drop_front(TokenLength);
186 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
190 if (TokenLength == 4 && Code.startswith(
"true")) {
193 }
else if (TokenLength == 5 && Code.startswith(
"false")) {
198 Result.Text = Code.substr(0, TokenLength);
200 Code = Code.drop_front(TokenLength);
203 Result.Text = Code.substr(0, 1);
204 Code = Code.drop_front(1);
209 Result.Range.End = currentLocation();
214 void consumeNumberLiteral(TokenInfo *
Result) {
215 bool isFloatingLiteral =
false;
217 if (Code.size() > 1) {
220 case 'x':
case 'b': Length = 2;
223 while (Length < Code.size() &&
isHexDigit(Code[Length]))
227 while (Length < Code.size()) {
228 char c = Code[Length];
230 isFloatingLiteral =
true;
237 Result->Text = Code.substr(0, Length);
238 Code = Code.drop_front(Length);
240 if (isFloatingLiteral) {
244 double doubleValue = strtod(
Text.c_str(), &end);
245 if (*end == 0 && errno == 0) {
247 Result->Value = doubleValue;
261 Range.End = currentLocation();
270 void consumeStringLiteral(TokenInfo *
Result) {
271 bool InEscape =
false;
272 const char Marker = Code[0];
273 for (
size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
278 if (Code[Length] ==
'\\') {
282 if (Code[Length] == Marker) {
284 Result->Text = Code.substr(0, Length + 1);
285 Result->Value = Code.substr(1, Length - 1);
286 Code = Code.drop_front(Length + 1);
291 StringRef ErrorText = Code;
292 Code = Code.drop_front(Code.size());
295 Range.End = currentLocation();
301 void consumeWhitespace() {
302 Code = Code.drop_while([](
char c) {
304 return StringRef(
" \t\v\f\r").contains(
c);
308 SourceLocation currentLocation() {
309 SourceLocation Location;
310 Location.Line = Line;
311 Location.Column = Code.data() - StartOfLine.data() + 1;
316 StringRef StartOfLine;
320 const char *CodeCompletionLocation =
nullptr;
330std::vector<MatcherCompletion>
339 P->ContextStack.push_back(std::make_pair(C, 0u));
343 P->ContextStack.pop_back();
347 ++
P->ContextStack.back().second;
362 NamedValues ? NamedValues->lookup(NameToken.Text)
374 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
381 Error->
addError(ChainCallToken.Range,
388 NameToken.Text, NameToken.Range);
390 Error->
addError(ChainCallToken.Range,
394 if (!parseBindID(BindID))
397 assert(NamedValue.isMatcher());
398 std::optional<DynTypedMatcher>
Result =
399 NamedValue.getMatcher().getSingleMatcher();
401 std::optional<DynTypedMatcher> Bound =
Result->tryBind(BindID);
444 return parseMatcherExpressionImpl(NameToken, OpenToken, Ctor,
Value);
447bool Parser::parseBindID(std::string &BindID) {
467 BindID = IDToken.Value.getString();
471bool Parser::parseMatcherBuilder(
MatcherCtor Ctor,
const TokenInfo &NameToken,
472 const TokenInfo &OpenToken,
473 VariantValue *
Value) {
474 std::vector<ParserValue> Args;
480 ScopedContextEntry SCE(
this, Ctor);
499 NameToken.Text, NameToken.Range,
501 ParserValue ArgValue;
505 addExpressionCompletions();
517 ArgValue.Text = NodeMatcherToken.Text;
518 ArgValue.Range = NodeMatcherToken.Range;
520 std::optional<MatcherCtor> MappedMatcher =
523 if (!MappedMatcher) {
524 Error->
addError(NodeMatcherToken.Range,
526 << NodeMatcherToken.Text;
533 Error->
addError(NodeMatcherToken.Range,
535 << NodeMatcherToken.Text;
542 Args.push_back(ArgValue);
553 internal::MatcherDescriptorPtr BuiltCtor =
556 if (!BuiltCtor.get()) {
567 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
568 addCompletion(ChainCallToken, MatcherCompletion(
"with(",
"with", 1));
574 Error->
addError(ChainCallToken.Range,
579 if (!parseBindID(BindID))
582 NameToken.Text, NameToken.Range);
583 SourceRange MatcherRange = NameToken.Range;
584 MatcherRange.End = ChainCallToken.Range.End;
586 BuiltCtor.get(), MatcherRange, BindID, {}, Error);
598 : Tokenizer->peekNextToken().
Text;
607 return parseMatcherExpressionImpl(NameToken, WithOpenToken,
608 BuiltCtor.get(),
Value);
613 NameToken.Text, NameToken.Range);
614 SourceRange MatcherRange = NameToken.Range;
615 MatcherRange.End = EndToken.Range.End;
617 BuiltCtor.get(), MatcherRange, BindID, {}, Error);
629bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
630 const TokenInfo &OpenToken,
631 std::optional<MatcherCtor> Ctor,
632 VariantValue *
Value) {
640 return parseMatcherBuilder(*Ctor, NameToken, OpenToken,
Value);
642 std::vector<ParserValue> Args;
648 ScopedContextEntry SCE(
this, Ctor.value_or(
nullptr));
667 NameToken.Text, NameToken.Range,
669 ParserValue ArgValue;
673 if (!parseExpressionImpl(&ArgValue.Value)) {
678 Args.push_back(ArgValue);
693 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
698 Error->
addError(ChainCallToken.Range,
705 NameToken.Text, NameToken.Range);
707 Error->
addError(ChainCallToken.Range,
712 Error->
addError(ChainCallToken.Range,
716 if (!parseBindID(BindID))
725 NameToken.Text, NameToken.Range);
726 SourceRange MatcherRange = NameToken.Range;
727 MatcherRange.End = EndToken.Range.End;
729 *Ctor, MatcherRange, BindID, Args, Error);
730 if (
Result.isNull())
return false;
738void Parser::addCompletion(
const TokenInfo &CompToken,
739 const MatcherCompletion& Completion) {
740 if (StringRef(Completion.TypedText).startswith(CompToken.Text) &&
741 Completion.Specificity > 0) {
742 Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
743 Completion.MatcherDecl, Completion.Specificity);
747std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
748 ArrayRef<ArgKind> AcceptedTypes) {
749 if (!NamedValues)
return std::vector<MatcherCompletion>();
750 std::vector<MatcherCompletion>
Result;
751 for (
const auto &Entry : *NamedValues) {
752 unsigned Specificity;
753 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
755 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
756 Result.emplace_back(Entry.getKey(),
Decl, Specificity);
762void Parser::addExpressionCompletions() {
768 for (ContextStackTy::iterator I = ContextStack.begin(),
769 E = ContextStack.end();
777 addCompletion(CompToken, Completion);
780 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
781 addCompletion(CompToken, Completion);
786bool Parser::parseExpressionImpl(VariantValue *
Value) {
793 return parseIdentifierPrefixImpl(
Value);
796 addExpressionCompletions();
819 llvm_unreachable(
"Unknown token kind.");
824Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
827 NamedValues(NamedValues), Error(Error) {}
829Parser::RegistrySema::~RegistrySema() =
default;
831std::optional<MatcherCtor>
832Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
833 return Registry::lookupMatcherCtor(MatcherName);
839 if (BindID.empty()) {
840 return Registry::constructMatcher(Ctor, NameRange, Args, Error);
842 return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
847std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(
848 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
849 return Registry::getAcceptedCompletionTypes(Context);
852std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
854 return Registry::getMatcherCompletions(AcceptedTypes);
857bool Parser::RegistrySema::isBuilderMatcher(
MatcherCtor Ctor)
const {
858 return Registry::isBuilderMatcher(Ctor);
862 return Registry::nodeMatcherType(Ctor);
869 return Registry::buildMatcherCtor(Ctor, NameRange, Args, Error);
872bool Parser::parseExpression(StringRef &Code,
Sema *S,
876 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(
Value))
878 auto NT = Tokenizer.peekNextToken();
879 if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) {
880 Error->addError(Tokenizer.peekNextToken().Range,
881 Error->ET_ParserTrailingCode);
887std::vector<MatcherCompletion>
888Parser::completeExpression(StringRef &Code,
unsigned CompletionOffset,
Sema *S,
892 Parser P(&Tokenizer, S, NamedValues, &Error);
894 P.parseExpressionImpl(&Dummy);
897 llvm::sort(
P.Completions,
899 if (A.Specificity != B.Specificity)
900 return A.Specificity > B.Specificity;
901 return A.TypedText < B.TypedText;
904 return P.Completions;
907std::optional<DynTypedMatcher>
908Parser::parseMatcherExpression(StringRef &Code,
Sema *S,
912 if (!parseExpression(Code, S, NamedValues, &
Value, Error))
914 if (!
Value.isMatcher()) {
915 Error->addError(
SourceRange(), Error->ET_ParserNotAMatcher);
918 std::optional<DynTypedMatcher>
Result =
Value.getMatcher().getSingleMatcher();
920 Error->addError(
SourceRange(), Error->ET_ParserOverloadedType)
921 <<
Value.getTypeAsString();
Simple matcher expression parser.
Diagnostics class to manage error messages.
Registry of all known matchers.
__device__ __2f16 float c
Sema - This implements semantic analysis and AST building for C.
Helper class to manage error messages.
ArgStream addError(SourceRange Range, ErrorType Error)
Add an error to the diagnostics.
@ ET_ParserMalformedBindExpr
@ ET_RegistryValueNotFound
@ ET_ParserFailedToBuildMatcher
@ ET_RegistryMatcherNotFound
@ ET_RegistryNonNodeMatcher
@ ET_ParserMalformedChainedExpr
@ ET_RegistryMatcherNoWithSupport
Simple tokenizer for the parser.
TokenInfo consumeNextTokenIgnoreNewlines()
CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error, unsigned CodeCompletionOffset)
TokenInfo::TokenKind nextTokenKind() const
CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error)
TokenInfo consumeNextToken()
Consumes and returns the next token.
const TokenInfo & peekNextToken() const
Returns but doesn't consume the next token.
Interface to connect the parser with the registry and more.
virtual VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error)=0
Process a matcher expression.
virtual internal::MatcherDescriptorPtr buildMatcherCtor(MatcherCtor, SourceRange NameRange, ArrayRef< ParserValue > Args, Diagnostics *Error) const =0
virtual std::optional< MatcherCtor > lookupMatcherCtor(StringRef MatcherName)=0
Look up a matcher by name.
virtual std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned > > Context)
Compute the list of completion types for Context.
virtual bool isBuilderMatcher(MatcherCtor) const =0
virtual std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > AcceptedTypes)
Compute the list of completions that match any of AcceptedTypes.
virtual ASTNodeKind nodeMatcherType(MatcherCtor) const =0
Matcher expression parser.
llvm::StringMap< VariantValue > NamedValueMap
A variant matcher object.
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher)
Clones the provided matcher.
A smart (owning) pointer for MatcherDescriptor.
Matcher descriptor interface.
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
static llvm::ManagedStatic< Parser::RegistrySema > DefaultRegistrySema
const internal::MatcherDescriptor * MatcherCtor
LLVM_READONLY char toLowercase(char c)
Converts the given ASCII character to its lowercase equivalent.
LLVM_READONLY bool isAlphanumeric(unsigned char c)
Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].
@ Result
The result type of a method or function.
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)
Simple structure to hold information for one token from the parser.
TokenKind
Different possible tokens.
static const char *const ID_Bind
Some known identifiers.
static const char *const ID_With