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.starts_with(
"true")) {
193 }
else if (TokenLength == 5 && Code.starts_with(
"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() {
303 Code = Code.ltrim(
" \t\v\f\r");
306 SourceLocation currentLocation() {
307 SourceLocation Location;
308 Location.Line = Line;
309 Location.Column = Code.data() - StartOfLine.data() + 1;
314 StringRef StartOfLine;
318 const char *CodeCompletionLocation =
nullptr;
328std::vector<MatcherCompletion>
337 P->ContextStack.push_back(std::make_pair(C, 0u));
341 P->ContextStack.pop_back();
345 ++
P->ContextStack.back().second;
360 NamedValues ? NamedValues->lookup(NameToken.Text)
372 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
379 Error->
addError(ChainCallToken.Range,
386 NameToken.Text, NameToken.Range);
388 Error->
addError(ChainCallToken.Range,
392 if (!parseBindID(BindID))
395 assert(NamedValue.isMatcher());
396 std::optional<DynTypedMatcher>
Result =
397 NamedValue.getMatcher().getSingleMatcher();
399 std::optional<DynTypedMatcher> Bound =
Result->tryBind(BindID);
442 return parseMatcherExpressionImpl(NameToken, OpenToken, Ctor,
Value);
445bool Parser::parseBindID(std::string &BindID) {
465 BindID = IDToken.Value.getString();
469bool Parser::parseMatcherBuilder(
MatcherCtor Ctor,
const TokenInfo &NameToken,
470 const TokenInfo &OpenToken,
471 VariantValue *
Value) {
472 std::vector<ParserValue> Args;
478 ScopedContextEntry SCE(
this, Ctor);
497 NameToken.Text, NameToken.Range,
499 ParserValue ArgValue;
503 addExpressionCompletions();
515 ArgValue.Text = NodeMatcherToken.Text;
516 ArgValue.Range = NodeMatcherToken.Range;
518 std::optional<MatcherCtor> MappedMatcher =
521 if (!MappedMatcher) {
522 Error->
addError(NodeMatcherToken.Range,
524 << NodeMatcherToken.Text;
531 Error->
addError(NodeMatcherToken.Range,
533 << NodeMatcherToken.Text;
540 Args.push_back(ArgValue);
551 internal::MatcherDescriptorPtr BuiltCtor =
554 if (!BuiltCtor.get()) {
565 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
566 addCompletion(ChainCallToken, MatcherCompletion(
"with(",
"with", 1));
572 Error->
addError(ChainCallToken.Range,
577 if (!parseBindID(BindID))
580 NameToken.Text, NameToken.Range);
581 SourceRange MatcherRange = NameToken.Range;
582 MatcherRange.End = ChainCallToken.Range.End;
584 BuiltCtor.get(), MatcherRange, BindID, {}, Error);
596 : Tokenizer->peekNextToken().
Text;
605 return parseMatcherExpressionImpl(NameToken, WithOpenToken,
606 BuiltCtor.get(),
Value);
611 NameToken.Text, NameToken.Range);
612 SourceRange MatcherRange = NameToken.Range;
613 MatcherRange.End = EndToken.Range.End;
615 BuiltCtor.get(), MatcherRange, BindID, {}, Error);
627bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
628 const TokenInfo &OpenToken,
629 std::optional<MatcherCtor> Ctor,
630 VariantValue *
Value) {
638 return parseMatcherBuilder(*Ctor, NameToken, OpenToken,
Value);
640 std::vector<ParserValue> Args;
646 ScopedContextEntry SCE(
this, Ctor.value_or(
nullptr));
665 NameToken.Text, NameToken.Range,
667 ParserValue ArgValue;
671 if (!parseExpressionImpl(&ArgValue.Value)) {
676 Args.push_back(ArgValue);
691 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
696 Error->
addError(ChainCallToken.Range,
703 NameToken.Text, NameToken.Range);
705 Error->
addError(ChainCallToken.Range,
710 Error->
addError(ChainCallToken.Range,
714 if (!parseBindID(BindID))
723 NameToken.Text, NameToken.Range);
724 SourceRange MatcherRange = NameToken.Range;
725 MatcherRange.End = EndToken.Range.End;
727 *Ctor, MatcherRange, BindID, Args, Error);
728 if (
Result.isNull())
return false;
736void Parser::addCompletion(
const TokenInfo &CompToken,
737 const MatcherCompletion& Completion) {
738 if (StringRef(Completion.TypedText).starts_with(CompToken.Text) &&
739 Completion.Specificity > 0) {
740 Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
741 Completion.MatcherDecl, Completion.Specificity);
745std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
746 ArrayRef<ArgKind> AcceptedTypes) {
747 if (!NamedValues)
return std::vector<MatcherCompletion>();
748 std::vector<MatcherCompletion>
Result;
749 for (
const auto &Entry : *NamedValues) {
750 unsigned Specificity;
751 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
753 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
754 Result.emplace_back(Entry.getKey(),
Decl, Specificity);
760void Parser::addExpressionCompletions() {
766 for (ContextStackTy::iterator I = ContextStack.begin(),
767 E = ContextStack.end();
775 addCompletion(CompToken, Completion);
778 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
779 addCompletion(CompToken, Completion);
784bool Parser::parseExpressionImpl(VariantValue *
Value) {
791 return parseIdentifierPrefixImpl(
Value);
794 addExpressionCompletions();
817 llvm_unreachable(
"Unknown token kind.");
822Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
825 NamedValues(NamedValues), Error(Error) {}
827Parser::RegistrySema::~RegistrySema() =
default;
829std::optional<MatcherCtor>
830Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
831 return Registry::lookupMatcherCtor(MatcherName);
837 if (BindID.empty()) {
838 return Registry::constructMatcher(Ctor, NameRange, Args, Error);
840 return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
845std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(
846 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
847 return Registry::getAcceptedCompletionTypes(Context);
850std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
852 return Registry::getMatcherCompletions(AcceptedTypes);
855bool Parser::RegistrySema::isBuilderMatcher(
MatcherCtor Ctor)
const {
856 return Registry::isBuilderMatcher(Ctor);
860 return Registry::nodeMatcherType(Ctor);
867 return Registry::buildMatcherCtor(Ctor, NameRange, Args, Error);
870bool Parser::parseExpression(StringRef &Code,
Sema *S,
874 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(
Value))
876 auto NT = Tokenizer.peekNextToken();
877 if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) {
878 Error->addError(Tokenizer.peekNextToken().Range,
879 Error->ET_ParserTrailingCode);
885std::vector<MatcherCompletion>
886Parser::completeExpression(StringRef &Code,
unsigned CompletionOffset,
Sema *S,
890 Parser P(&Tokenizer, S, NamedValues, &Error);
892 P.parseExpressionImpl(&Dummy);
895 llvm::sort(
P.Completions,
897 if (A.Specificity != B.Specificity)
898 return A.Specificity > B.Specificity;
899 return A.TypedText < B.TypedText;
902 return P.Completions;
905std::optional<DynTypedMatcher>
906Parser::parseMatcherExpression(StringRef &Code,
Sema *S,
910 if (!parseExpression(Code, S, NamedValues, &
Value, Error))
912 if (!
Value.isMatcher()) {
913 Error->addError(
SourceRange(), Error->ET_ParserNotAMatcher);
916 std::optional<DynTypedMatcher>
Result =
Value.getMatcher().getSingleMatcher();
918 Error->addError(
SourceRange(), Error->ET_ParserOverloadedType)
919 <<
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
The JSON file list parser is used to communicate input to InstallAPI.
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