19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/ManagedStatic.h"
71 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
72 NextToken = getNextToken();
76 unsigned CodeCompletionOffset)
77 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
78 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
79 NextToken = getNextToken();
88 NextToken = getNextToken();
94 NextToken = getNextToken();
111 Result.Range.Start = currentLocation();
113 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
115 Result.Text = StringRef(CodeCompletionLocation, 0);
116 CodeCompletionLocation =
nullptr;
128 Code = Code.drop_until([](
char c) {
return c ==
'\n'; });
129 return getNextToken();
132 Result.Text = Code.substr(0, 1);
133 Code = Code.drop_front();
137 Result.Text = Code.substr(0, 1);
138 Code = Code.drop_front();
142 StartOfLine = Code.drop_front();
144 Result.Text = Code.substr(0, 1);
145 Code = Code.drop_front();
149 Result.Text = Code.substr(0, 1);
150 Code = Code.drop_front();
154 Result.Text = Code.substr(0, 1);
155 Code = Code.drop_front();
161 consumeStringLiteral(&
Result);
164 case '0':
case '1':
case '2':
case '3':
case '4':
165 case '5':
case '6':
case '7':
case '8':
case '9':
167 consumeNumberLiteral(&
Result);
173 size_t TokenLength = 1;
178 if (CodeCompletionLocation == Code.data() + TokenLength) {
179 CodeCompletionLocation =
nullptr;
181 Result.Text = Code.substr(0, TokenLength);
182 Code = Code.drop_front(TokenLength);
185 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
189 if (TokenLength == 4 && Code.starts_with(
"true")) {
192 }
else if (TokenLength == 5 && Code.starts_with(
"false")) {
197 Result.Text = Code.substr(0, TokenLength);
199 Code = Code.drop_front(TokenLength);
202 Result.Text = Code.substr(0, 1);
203 Code = Code.drop_front(1);
208 Result.Range.End = currentLocation();
213 void consumeNumberLiteral(TokenInfo *
Result) {
214 bool isFloatingLiteral =
false;
216 if (Code.size() > 1) {
219 case 'x':
case 'b': Length = 2;
222 while (Length < Code.size() &&
isHexDigit(Code[Length]))
226 while (Length < Code.size()) {
227 char c = Code[Length];
229 isFloatingLiteral =
true;
236 Result->Text = Code.substr(0, Length);
237 Code = Code.drop_front(Length);
239 if (isFloatingLiteral) {
243 double doubleValue = strtod(
Text.c_str(), &end);
244 if (*end == 0 && errno == 0) {
246 Result->Value = doubleValue;
260 Range.End = currentLocation();
261 Error->addError(Range, Error->ET_ParserNumberError) <<
Result->Text;
269 void consumeStringLiteral(TokenInfo *
Result) {
270 bool InEscape =
false;
271 const char Marker = Code[0];
272 for (
size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
277 if (Code[Length] ==
'\\') {
281 if (Code[Length] == Marker) {
283 Result->Text = Code.substr(0, Length + 1);
284 Result->Value = Code.substr(1, Length - 1);
285 Code = Code.drop_front(Length + 1);
290 StringRef ErrorText = Code;
291 Code = Code.drop_front(Code.size());
294 Range.End = currentLocation();
295 Error->addError(Range, Error->ET_ParserStringError) << ErrorText;
300 void consumeWhitespace() {
302 Code = Code.ltrim(
" \t\v\f\r");
305 SourceLocation currentLocation() {
306 SourceLocation Location;
307 Location.Line = Line;
308 Location.Column = Code.data() - StartOfLine.data() + 1;
313 StringRef StartOfLine;
317 const char *CodeCompletionLocation =
nullptr;
327std::vector<MatcherCompletion>
336 P->ContextStack.push_back(std::make_pair(
C, 0u));
340 P->ContextStack.pop_back();
344 ++
P->ContextStack.back().second;
359 NamedValues ? NamedValues->lookup(NameToken.Text)
371 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
378 Error->addError(ChainCallToken.Range,
379 Error->ET_ParserMalformedChainedExpr);
385 NameToken.Text, NameToken.Range);
387 Error->addError(ChainCallToken.Range,
388 Error->ET_RegistryMatcherNoWithSupport);
391 if (!parseBindID(BindID))
394 assert(NamedValue.isMatcher());
395 std::optional<DynTypedMatcher>
Result =
396 NamedValue.getMatcher().getSingleMatcher();
398 std::optional<DynTypedMatcher> Bound =
Result->tryBind(BindID);
408 Error->addError(Tokenizer->peekNextToken().Range,
409 Error->ET_ParserNoOpenParen)
420 !S->lookupMatcherCtor(NameToken.Text)) {
421 Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)
428 Tokenizer->SkipNewlines();
431 TokenInfo OpenToken = Tokenizer->consumeNextToken();
433 Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen)
438 std::optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
441 return parseMatcherExpressionImpl(NameToken, OpenToken, Ctor,
Value);
444bool Parser::parseBindID(std::string &BindID) {
446 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
447 const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines();
448 const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines();
453 Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr);
457 Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr);
461 Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr);
470 VariantValue *
Value) {
471 std::vector<ParserValue> Args;
474 Tokenizer->SkipNewlines();
482 EndToken = Tokenizer->consumeNextToken();
487 TokenInfo CommaToken = Tokenizer->consumeNextToken();
489 Error->addError(CommaToken.Range, Error->ET_ParserNoComma)
494 Tokenizer->SkipNewlines();
501 NameToken.Text, NameToken.Range,
503 ParserValue ArgValue;
504 Tokenizer->SkipNewlines();
507 addExpressionCompletions();
511 TokenInfo NodeMatcherToken = Tokenizer->consumeNextToken();
514 Error->addError(NameToken.Range, Error->ET_ParserFailedToBuildMatcher)
519 ArgValue.
Text = NodeMatcherToken.Text;
520 ArgValue.Range = NodeMatcherToken.Range;
522 std::optional<MatcherCtor> MappedMatcher =
523 S->lookupMatcherCtor(ArgValue.Text);
525 if (!MappedMatcher) {
526 Error->addError(NodeMatcherToken.Range,
527 Error->ET_RegistryMatcherNotFound)
528 << NodeMatcherToken.Text;
532 ASTNodeKind NK = S->nodeMatcherType(*MappedMatcher);
535 Error->addError(NodeMatcherToken.Range,
536 Error->ET_RegistryNonNodeMatcher)
537 << NodeMatcherToken.Text;
543 Tokenizer->SkipNewlines();
544 Args.push_back(ArgValue);
551 Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);
555 internal::MatcherDescriptorPtr BuiltCtor =
556 S->buildMatcherCtor(Ctor, NameToken.Range, Args, Error);
558 if (!BuiltCtor.get()) {
559 Error->addError(NameToken.Range, Error->ET_ParserFailedToBuildMatcher)
566 Tokenizer->consumeNextToken();
567 TokenInfo ChainCallToken = Tokenizer->consumeNextToken();
569 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
570 addCompletion(ChainCallToken, MatcherCompletion(
"with(",
"with", 1));
576 Error->addError(ChainCallToken.Range,
577 Error->ET_ParserMalformedChainedExpr);
581 if (!parseBindID(BindID))
584 NameToken.Text, NameToken.Range);
585 SourceRange MatcherRange = NameToken.Range;
586 MatcherRange.End = ChainCallToken.Range.End;
587 VariantMatcher
Result = S->actOnMatcherExpression(
588 BuiltCtor.get(), MatcherRange, BindID, {}, Error);
595 Tokenizer->SkipNewlines();
600 : Tokenizer->peekNextToken().
Text;
601 Error->addError(Tokenizer->peekNextToken().Range,
602 Error->ET_ParserNoOpenParen)
607 TokenInfo WithOpenToken = Tokenizer->consumeNextToken();
609 return parseMatcherExpressionImpl(NameToken, WithOpenToken,
610 BuiltCtor.get(),
Value);
615 NameToken.Text, NameToken.Range);
616 SourceRange MatcherRange = NameToken.Range;
617 MatcherRange.End = EndToken.Range.End;
618 VariantMatcher
Result = S->actOnMatcherExpression(
619 BuiltCtor.get(), MatcherRange, BindID, {}, Error);
631bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
633 std::optional<MatcherCtor> Ctor,
634 VariantValue *
Value) {
636 Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)
641 if (Ctor && *Ctor && S->isBuilderMatcher(*Ctor))
642 return parseMatcherBuilder(*Ctor, NameToken, OpenToken,
Value);
644 std::vector<ParserValue> Args;
647 Tokenizer->SkipNewlines();
655 EndToken = Tokenizer->consumeNextToken();
660 const TokenInfo CommaToken = Tokenizer->consumeNextToken();
662 Error->addError(CommaToken.Range, Error->ET_ParserNoComma)
667 Tokenizer->SkipNewlines();
674 NameToken.Text, NameToken.Range,
676 ParserValue ArgValue;
677 Tokenizer->SkipNewlines();
678 ArgValue.Text = Tokenizer->peekNextToken().Text;
679 ArgValue.Range = Tokenizer->peekNextToken().Range;
680 if (!parseExpressionImpl(&ArgValue.Value)) {
684 Tokenizer->SkipNewlines();
685 Args.push_back(ArgValue);
691 Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);
697 Tokenizer->consumeNextToken();
698 TokenInfo ChainCallToken = Tokenizer->consumeNextToken();
700 addCompletion(ChainCallToken, MatcherCompletion(
"bind(\"",
"bind", 1));
705 Error->addError(ChainCallToken.Range,
706 Error->ET_ParserMalformedChainedExpr);
712 NameToken.Text, NameToken.Range);
714 Error->addError(ChainCallToken.Range,
715 Error->ET_RegistryMatcherNoWithSupport);
719 Error->addError(ChainCallToken.Range,
720 Error->ET_ParserMalformedChainedExpr);
723 if (!parseBindID(BindID))
732 NameToken.Text, NameToken.Range);
733 SourceRange MatcherRange = NameToken.Range;
734 MatcherRange.End = EndToken.Range.End;
735 VariantMatcher
Result = S->actOnMatcherExpression(
736 *Ctor, MatcherRange, BindID, Args, Error);
737 if (
Result.isNull())
return false;
745void Parser::addCompletion(
const TokenInfo &CompToken,
746 const MatcherCompletion& Completion) {
747 if (StringRef(Completion.TypedText).starts_with(CompToken.Text) &&
748 Completion.Specificity > 0) {
749 Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
750 Completion.MatcherDecl, Completion.Specificity);
754std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
755 ArrayRef<ArgKind> AcceptedTypes) {
756 if (!NamedValues)
return std::vector<MatcherCompletion>();
757 std::vector<MatcherCompletion>
Result;
758 for (
const auto &Entry : *NamedValues) {
759 unsigned Specificity;
760 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
762 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
763 Result.emplace_back(Entry.getKey(), Decl, Specificity);
769void Parser::addExpressionCompletions() {
770 const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines();
775 for (ContextStackTy::iterator I = ContextStack.begin(),
776 E = ContextStack.end();
782 auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
783 for (
const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
784 addCompletion(CompToken, Completion);
787 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
788 addCompletion(CompToken, Completion);
793bool Parser::parseExpressionImpl(VariantValue *
Value) {
794 switch (Tokenizer->nextTokenKind()) {
796 *
Value = Tokenizer->consumeNextToken().Value;
800 return parseIdentifierPrefixImpl(
Value);
803 addExpressionCompletions();
807 Error->addError(Tokenizer->consumeNextToken().Range,
808 Error->ET_ParserNoCode);
820 const TokenInfo Token = Tokenizer->consumeNextToken();
821 Error->addError(Token.Range, Error->ET_ParserInvalidToken)
826 llvm_unreachable(
"Unknown token kind.");
831Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
836Parser::RegistrySema::~RegistrySema() =
default;
838std::optional<MatcherCtor>
846 if (BindID.empty()) {
855 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
883 if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(
Value))
885 auto NT = Tokenizer.peekNextToken();
887 Error->addError(Tokenizer.peekNextToken().Range,
888 Error->ET_ParserTrailingCode);
894std::vector<MatcherCompletion>
899 Parser P(&Tokenizer, S, NamedValues, &Error);
901 P.parseExpressionImpl(&Dummy);
904 llvm::sort(P.Completions,
906 if (A.Specificity != B.Specificity)
907 return A.Specificity > B.Specificity;
908 return A.TypedText < B.TypedText;
911 return P.Completions;
914std::optional<DynTypedMatcher>
921 if (!
Value.isMatcher()) {
922 Error->addError(
SourceRange(), Error->ET_ParserNotAMatcher);
925 std::optional<DynTypedMatcher>
Result =
Value.getMatcher().getSingleMatcher();
927 Error->addError(
SourceRange(), Error->ET_ParserOverloadedType)
928 <<
Value.getTypeAsString();
Simple matcher expression parser.
Diagnostics class to manage error messages.
static StringRef consumeWhitespace(StringRef S)
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.
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.
ASTNodeKind nodeMatcherType(MatcherCtor) const override
std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned > > Context) override
Compute the list of completion types for Context.
std::optional< MatcherCtor > lookupMatcherCtor(StringRef MatcherName) override
Look up a matcher by name.
std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > AcceptedTypes) override
Compute the list of completions that match any of AcceptedTypes.
internal::MatcherDescriptorPtr buildMatcherCtor(MatcherCtor, SourceRange NameRange, ArrayRef< ParserValue > Args, Diagnostics *Error) const override
bool isBuilderMatcher(MatcherCtor Ctor) const override
VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error) override
Process a matcher expression.
Interface to connect the parser with the registry and more.
virtual std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned > > Context)
Compute the list of completion types for Context.
virtual std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > AcceptedTypes)
Compute the list of completions that match any of AcceptedTypes.
static bool parseExpression(StringRef &Code, Sema *S, const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error)
Parse an expression.
static std::vector< MatcherCompletion > completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S, const NamedValueMap *NamedValues)
Complete an expression at the given offset.
llvm::StringMap< VariantValue > NamedValueMap
static std::optional< DynTypedMatcher > parseMatcherExpression(StringRef &MatcherCode, Sema *S, const NamedValueMap *NamedValues, Diagnostics *Error)
Parse a matcher expression.
static std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned > > Context)
Compute the list of completion types for Context.
static bool isBuilderMatcher(MatcherCtor Ctor)
static ASTNodeKind nodeMatcherType(MatcherCtor)
static std::optional< MatcherCtor > lookupMatcherCtor(StringRef MatcherName)
Look up a matcher in the registry by name,.
static internal::MatcherDescriptorPtr buildMatcherCtor(MatcherCtor, SourceRange NameRange, ArrayRef< ParserValue > Args, Diagnostics *Error)
static std::vector< MatcherCompletion > getMatcherCompletions(ArrayRef< ArgKind > AcceptedTypes)
Compute the list of completions that match any of AcceptedTypes.
static VariantMatcher constructBoundMatcher(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error)
Construct a matcher from the registry and bind it.
static VariantMatcher constructMatcher(MatcherCtor Ctor, SourceRange NameRange, ArrayRef< ParserValue > Args, Diagnostics *Error)
Construct a matcher from the registry.
A variant matcher object.
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher)
Clones the provided matcher.
const std::string & getString() const
A smart (owning) pointer for MatcherDescriptor.
static llvm::ManagedStatic< Parser::RegistrySema > DefaultRegistrySema
const internal::MatcherDescriptor * MatcherCtor
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
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