1 //===- Parser.cpp - Matcher expression parser -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Recursive parser implementation for the matcher expression grammar.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/ASTMatchers/Dynamic/Parser.h"
15 #include "clang/ASTMatchers/ASTMatchersInternal.h"
16 #include "clang/ASTMatchers/Dynamic/Diagnostics.h"
17 #include "clang/ASTMatchers/Dynamic/Registry.h"
18 #include "clang/Basic/CharInfo.h"
19 #include "llvm/ADT/Optional.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/ManagedStatic.h"
23 #include <algorithm>
24 #include <cassert>
25 #include <cerrno>
26 #include <cstddef>
27 #include <cstdlib>
28 #include <string>
29 #include <utility>
30 #include <vector>
31
32 namespace clang {
33 namespace ast_matchers {
34 namespace dynamic {
35
36 /// Simple structure to hold information for one token from the parser.
37 struct Parser::TokenInfo {
38 /// Different possible tokens.
39 enum TokenKind {
40 TK_Eof,
41 TK_NewLine,
42 TK_OpenParen,
43 TK_CloseParen,
44 TK_Comma,
45 TK_Period,
46 TK_Literal,
47 TK_Ident,
48 TK_InvalidChar,
49 TK_Error,
50 TK_CodeCompletion
51 };
52
53 /// Some known identifiers.
54 static const char* const ID_Bind;
55
56 TokenInfo() = default;
57
58 StringRef Text;
59 TokenKind Kind = TK_Eof;
60 SourceRange Range;
61 VariantValue Value;
62 };
63
64 const char* const Parser::TokenInfo::ID_Bind = "bind";
65
66 /// Simple tokenizer for the parser.
67 class Parser::CodeTokenizer {
68 public:
CodeTokenizer(StringRef & MatcherCode,Diagnostics * Error)69 explicit CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error)
70 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
71 NextToken = getNextToken();
72 }
73
CodeTokenizer(StringRef & MatcherCode,Diagnostics * Error,unsigned CodeCompletionOffset)74 CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error,
75 unsigned CodeCompletionOffset)
76 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
77 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
78 NextToken = getNextToken();
79 }
80
81 /// Returns but doesn't consume the next token.
peekNextToken() const82 const TokenInfo &peekNextToken() const { return NextToken; }
83
84 /// Consumes and returns the next token.
consumeNextToken()85 TokenInfo consumeNextToken() {
86 TokenInfo ThisToken = NextToken;
87 NextToken = getNextToken();
88 return ThisToken;
89 }
90
SkipNewlines()91 TokenInfo SkipNewlines() {
92 while (NextToken.Kind == TokenInfo::TK_NewLine)
93 NextToken = getNextToken();
94 return NextToken;
95 }
96
consumeNextTokenIgnoreNewlines()97 TokenInfo consumeNextTokenIgnoreNewlines() {
98 SkipNewlines();
99 if (NextToken.Kind == TokenInfo::TK_Eof)
100 return NextToken;
101 return consumeNextToken();
102 }
103
nextTokenKind() const104 TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; }
105
106 private:
getNextToken()107 TokenInfo getNextToken() {
108 consumeWhitespace();
109 TokenInfo Result;
110 Result.Range.Start = currentLocation();
111
112 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
113 Result.Kind = TokenInfo::TK_CodeCompletion;
114 Result.Text = StringRef(CodeCompletionLocation, 0);
115 CodeCompletionLocation = nullptr;
116 return Result;
117 }
118
119 if (Code.empty()) {
120 Result.Kind = TokenInfo::TK_Eof;
121 Result.Text = "";
122 return Result;
123 }
124
125 switch (Code[0]) {
126 case '#':
127 Code = Code.drop_until([](char c) { return c == '\n'; });
128 return getNextToken();
129 case ',':
130 Result.Kind = TokenInfo::TK_Comma;
131 Result.Text = Code.substr(0, 1);
132 Code = Code.drop_front();
133 break;
134 case '.':
135 Result.Kind = TokenInfo::TK_Period;
136 Result.Text = Code.substr(0, 1);
137 Code = Code.drop_front();
138 break;
139 case '\n':
140 ++Line;
141 StartOfLine = Code.drop_front();
142 Result.Kind = TokenInfo::TK_NewLine;
143 Result.Text = Code.substr(0, 1);
144 Code = Code.drop_front();
145 break;
146 case '(':
147 Result.Kind = TokenInfo::TK_OpenParen;
148 Result.Text = Code.substr(0, 1);
149 Code = Code.drop_front();
150 break;
151 case ')':
152 Result.Kind = TokenInfo::TK_CloseParen;
153 Result.Text = Code.substr(0, 1);
154 Code = Code.drop_front();
155 break;
156
157 case '"':
158 case '\'':
159 // Parse a string literal.
160 consumeStringLiteral(&Result);
161 break;
162
163 case '0': case '1': case '2': case '3': case '4':
164 case '5': case '6': case '7': case '8': case '9':
165 // Parse an unsigned and float literal.
166 consumeNumberLiteral(&Result);
167 break;
168
169 default:
170 if (isAlphanumeric(Code[0])) {
171 // Parse an identifier
172 size_t TokenLength = 1;
173 while (true) {
174 // A code completion location in/immediately after an identifier will
175 // cause the portion of the identifier before the code completion
176 // location to become a code completion token.
177 if (CodeCompletionLocation == Code.data() + TokenLength) {
178 CodeCompletionLocation = nullptr;
179 Result.Kind = TokenInfo::TK_CodeCompletion;
180 Result.Text = Code.substr(0, TokenLength);
181 Code = Code.drop_front(TokenLength);
182 return Result;
183 }
184 if (TokenLength == Code.size() || !isAlphanumeric(Code[TokenLength]))
185 break;
186 ++TokenLength;
187 }
188 if (TokenLength == 4 && Code.startswith("true")) {
189 Result.Kind = TokenInfo::TK_Literal;
190 Result.Value = true;
191 } else if (TokenLength == 5 && Code.startswith("false")) {
192 Result.Kind = TokenInfo::TK_Literal;
193 Result.Value = false;
194 } else {
195 Result.Kind = TokenInfo::TK_Ident;
196 Result.Text = Code.substr(0, TokenLength);
197 }
198 Code = Code.drop_front(TokenLength);
199 } else {
200 Result.Kind = TokenInfo::TK_InvalidChar;
201 Result.Text = Code.substr(0, 1);
202 Code = Code.drop_front(1);
203 }
204 break;
205 }
206
207 Result.Range.End = currentLocation();
208 return Result;
209 }
210
211 /// Consume an unsigned and float literal.
consumeNumberLiteral(TokenInfo * Result)212 void consumeNumberLiteral(TokenInfo *Result) {
213 bool isFloatingLiteral = false;
214 unsigned Length = 1;
215 if (Code.size() > 1) {
216 // Consume the 'x' or 'b' radix modifier, if present.
217 switch (toLowercase(Code[1])) {
218 case 'x': case 'b': Length = 2;
219 }
220 }
221 while (Length < Code.size() && isHexDigit(Code[Length]))
222 ++Length;
223
224 // Try to recognize a floating point literal.
225 while (Length < Code.size()) {
226 char c = Code[Length];
227 if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) {
228 isFloatingLiteral = true;
229 Length++;
230 } else {
231 break;
232 }
233 }
234
235 Result->Text = Code.substr(0, Length);
236 Code = Code.drop_front(Length);
237
238 if (isFloatingLiteral) {
239 char *end;
240 errno = 0;
241 std::string Text = Result->Text.str();
242 double doubleValue = strtod(Text.c_str(), &end);
243 if (*end == 0 && errno == 0) {
244 Result->Kind = TokenInfo::TK_Literal;
245 Result->Value = doubleValue;
246 return;
247 }
248 } else {
249 unsigned Value;
250 if (!Result->Text.getAsInteger(0, Value)) {
251 Result->Kind = TokenInfo::TK_Literal;
252 Result->Value = Value;
253 return;
254 }
255 }
256
257 SourceRange Range;
258 Range.Start = Result->Range.Start;
259 Range.End = currentLocation();
260 Error->addError(Range, Error->ET_ParserNumberError) << Result->Text;
261 Result->Kind = TokenInfo::TK_Error;
262 }
263
264 /// Consume a string literal.
265 ///
266 /// \c Code must be positioned at the start of the literal (the opening
267 /// quote). Consumed until it finds the same closing quote character.
consumeStringLiteral(TokenInfo * Result)268 void consumeStringLiteral(TokenInfo *Result) {
269 bool InEscape = false;
270 const char Marker = Code[0];
271 for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
272 if (InEscape) {
273 InEscape = false;
274 continue;
275 }
276 if (Code[Length] == '\\') {
277 InEscape = true;
278 continue;
279 }
280 if (Code[Length] == Marker) {
281 Result->Kind = TokenInfo::TK_Literal;
282 Result->Text = Code.substr(0, Length + 1);
283 Result->Value = Code.substr(1, Length - 1);
284 Code = Code.drop_front(Length + 1);
285 return;
286 }
287 }
288
289 StringRef ErrorText = Code;
290 Code = Code.drop_front(Code.size());
291 SourceRange Range;
292 Range.Start = Result->Range.Start;
293 Range.End = currentLocation();
294 Error->addError(Range, Error->ET_ParserStringError) << ErrorText;
295 Result->Kind = TokenInfo::TK_Error;
296 }
297
298 /// Consume all leading whitespace from \c Code.
consumeWhitespace()299 void consumeWhitespace() {
300 Code = Code.drop_while([](char c) {
301 // Don't trim newlines.
302 return StringRef(" \t\v\f\r").contains(c);
303 });
304 }
305
currentLocation()306 SourceLocation currentLocation() {
307 SourceLocation Location;
308 Location.Line = Line;
309 Location.Column = Code.data() - StartOfLine.data() + 1;
310 return Location;
311 }
312
313 StringRef &Code;
314 StringRef StartOfLine;
315 unsigned Line = 1;
316 Diagnostics *Error;
317 TokenInfo NextToken;
318 const char *CodeCompletionLocation = nullptr;
319 };
320
321 Parser::Sema::~Sema() = default;
322
getAcceptedCompletionTypes(llvm::ArrayRef<std::pair<MatcherCtor,unsigned>> Context)323 std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes(
324 llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
325 return {};
326 }
327
328 std::vector<MatcherCompletion>
getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes)329 Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) {
330 return {};
331 }
332
333 struct Parser::ScopedContextEntry {
334 Parser *P;
335
ScopedContextEntryclang::ast_matchers::dynamic::Parser::ScopedContextEntry336 ScopedContextEntry(Parser *P, MatcherCtor C) : P(P) {
337 P->ContextStack.push_back(std::make_pair(C, 0u));
338 }
339
~ScopedContextEntryclang::ast_matchers::dynamic::Parser::ScopedContextEntry340 ~ScopedContextEntry() {
341 P->ContextStack.pop_back();
342 }
343
nextArgclang::ast_matchers::dynamic::Parser::ScopedContextEntry344 void nextArg() {
345 ++P->ContextStack.back().second;
346 }
347 };
348
349 /// Parse expressions that start with an identifier.
350 ///
351 /// This function can parse named values and matchers.
352 /// In case of failure it will try to determine the user's intent to give
353 /// an appropriate error message.
parseIdentifierPrefixImpl(VariantValue * Value)354 bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
355 const TokenInfo NameToken = Tokenizer->consumeNextToken();
356
357 if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {
358 // Parse as a named value.
359 if (const VariantValue NamedValue =
360 NamedValues ? NamedValues->lookup(NameToken.Text)
361 : VariantValue()) {
362
363 if (Tokenizer->nextTokenKind() != TokenInfo::TK_Period) {
364 *Value = NamedValue;
365 return true;
366 }
367
368 std::string BindID;
369 if (!parseBindID(BindID))
370 return false;
371
372 assert(NamedValue.isMatcher());
373 llvm::Optional<DynTypedMatcher> Result =
374 NamedValue.getMatcher().getSingleMatcher();
375 if (Result.hasValue()) {
376 llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
377 if (Bound.hasValue()) {
378 *Value = VariantMatcher::SingleMatcher(*Bound);
379 return true;
380 }
381 }
382 return false;
383 }
384
385 if (Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine) {
386 Error->addError(Tokenizer->peekNextToken().Range,
387 Error->ET_ParserNoOpenParen)
388 << "NewLine";
389 return false;
390 }
391
392 // If the syntax is correct and the name is not a matcher either, report
393 // unknown named value.
394 if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||
395 Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||
396 Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine ||
397 Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&
398 !S->lookupMatcherCtor(NameToken.Text)) {
399 Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)
400 << NameToken.Text;
401 return false;
402 }
403 // Otherwise, fallback to the matcher parser.
404 }
405
406 Tokenizer->SkipNewlines();
407
408 // Parse as a matcher expression.
409 return parseMatcherExpressionImpl(NameToken, Value);
410 }
411
parseBindID(std::string & BindID)412 bool Parser::parseBindID(std::string &BindID) {
413 // Parse .bind("foo")
414 assert(Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period);
415 Tokenizer->consumeNextToken(); // consume the period.
416 const TokenInfo BindToken = Tokenizer->consumeNextToken();
417 if (BindToken.Kind == TokenInfo::TK_CodeCompletion) {
418 addCompletion(BindToken, MatcherCompletion("bind(\"", "bind", 1));
419 return false;
420 }
421
422 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
423 const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines();
424 const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines();
425
426 // TODO: We could use different error codes for each/some to be more
427 // explicit about the syntax error.
428 if (BindToken.Kind != TokenInfo::TK_Ident ||
429 BindToken.Text != TokenInfo::ID_Bind) {
430 Error->addError(BindToken.Range, Error->ET_ParserMalformedBindExpr);
431 return false;
432 }
433 if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
434 Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr);
435 return false;
436 }
437 if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) {
438 Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr);
439 return false;
440 }
441 if (CloseToken.Kind != TokenInfo::TK_CloseParen) {
442 Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr);
443 return false;
444 }
445 BindID = IDToken.Value.getString();
446 return true;
447 }
448
449 /// Parse and validate a matcher expression.
450 /// \return \c true on success, in which case \c Value has the matcher parsed.
451 /// If the input is malformed, or some argument has an error, it
452 /// returns \c false.
parseMatcherExpressionImpl(const TokenInfo & NameToken,VariantValue * Value)453 bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
454 VariantValue *Value) {
455 assert(NameToken.Kind == TokenInfo::TK_Ident);
456 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
457 if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
458 Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen)
459 << OpenToken.Text;
460 return false;
461 }
462
463 llvm::Optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
464
465 if (!Ctor) {
466 Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)
467 << NameToken.Text;
468 // Do not return here. We need to continue to give completion suggestions.
469 }
470
471 std::vector<ParserValue> Args;
472 TokenInfo EndToken;
473
474 Tokenizer->SkipNewlines();
475
476 {
477 ScopedContextEntry SCE(this, Ctor ? *Ctor : nullptr);
478
479 while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {
480 if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {
481 // End of args.
482 EndToken = Tokenizer->consumeNextToken();
483 break;
484 }
485 if (!Args.empty()) {
486 // We must find a , token to continue.
487 const TokenInfo CommaToken = Tokenizer->consumeNextToken();
488 if (CommaToken.Kind != TokenInfo::TK_Comma) {
489 Error->addError(CommaToken.Range, Error->ET_ParserNoComma)
490 << CommaToken.Text;
491 return false;
492 }
493 }
494
495 Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,
496 NameToken.Text, NameToken.Range,
497 Args.size() + 1);
498 ParserValue ArgValue;
499 Tokenizer->SkipNewlines();
500 ArgValue.Text = Tokenizer->peekNextToken().Text;
501 ArgValue.Range = Tokenizer->peekNextToken().Range;
502 if (!parseExpressionImpl(&ArgValue.Value)) {
503 return false;
504 }
505
506 Tokenizer->SkipNewlines();
507 Args.push_back(ArgValue);
508 SCE.nextArg();
509 }
510 }
511
512 if (EndToken.Kind == TokenInfo::TK_Eof) {
513 Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);
514 return false;
515 }
516
517 std::string BindID;
518 if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {
519 if (!parseBindID(BindID))
520 return false;
521 }
522
523 if (!Ctor)
524 return false;
525
526 // Merge the start and end infos.
527 Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,
528 NameToken.Text, NameToken.Range);
529 SourceRange MatcherRange = NameToken.Range;
530 MatcherRange.End = EndToken.Range.End;
531 VariantMatcher Result = S->actOnMatcherExpression(
532 *Ctor, MatcherRange, BindID, Args, Error);
533 if (Result.isNull()) return false;
534
535 *Value = Result;
536 return true;
537 }
538
539 // If the prefix of this completion matches the completion token, add it to
540 // Completions minus the prefix.
addCompletion(const TokenInfo & CompToken,const MatcherCompletion & Completion)541 void Parser::addCompletion(const TokenInfo &CompToken,
542 const MatcherCompletion& Completion) {
543 if (StringRef(Completion.TypedText).startswith(CompToken.Text) &&
544 Completion.Specificity > 0) {
545 Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),
546 Completion.MatcherDecl, Completion.Specificity);
547 }
548 }
549
getNamedValueCompletions(ArrayRef<ArgKind> AcceptedTypes)550 std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
551 ArrayRef<ArgKind> AcceptedTypes) {
552 if (!NamedValues) return std::vector<MatcherCompletion>();
553 std::vector<MatcherCompletion> Result;
554 for (const auto &Entry : *NamedValues) {
555 unsigned Specificity;
556 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
557 std::string Decl =
558 (Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str();
559 Result.emplace_back(Entry.getKey(), Decl, Specificity);
560 }
561 }
562 return Result;
563 }
564
addExpressionCompletions()565 void Parser::addExpressionCompletions() {
566 const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines();
567 assert(CompToken.Kind == TokenInfo::TK_CodeCompletion);
568
569 // We cannot complete code if there is an invalid element on the context
570 // stack.
571 for (ContextStackTy::iterator I = ContextStack.begin(),
572 E = ContextStack.end();
573 I != E; ++I) {
574 if (!I->first)
575 return;
576 }
577
578 auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
579 for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
580 addCompletion(CompToken, Completion);
581 }
582
583 for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
584 addCompletion(CompToken, Completion);
585 }
586 }
587
588 /// Parse an <Expression>
parseExpressionImpl(VariantValue * Value)589 bool Parser::parseExpressionImpl(VariantValue *Value) {
590 switch (Tokenizer->nextTokenKind()) {
591 case TokenInfo::TK_Literal:
592 *Value = Tokenizer->consumeNextToken().Value;
593 return true;
594
595 case TokenInfo::TK_Ident:
596 return parseIdentifierPrefixImpl(Value);
597
598 case TokenInfo::TK_CodeCompletion:
599 addExpressionCompletions();
600 return false;
601
602 case TokenInfo::TK_Eof:
603 Error->addError(Tokenizer->consumeNextToken().Range,
604 Error->ET_ParserNoCode);
605 return false;
606
607 case TokenInfo::TK_Error:
608 // This error was already reported by the tokenizer.
609 return false;
610 case TokenInfo::TK_NewLine:
611 case TokenInfo::TK_OpenParen:
612 case TokenInfo::TK_CloseParen:
613 case TokenInfo::TK_Comma:
614 case TokenInfo::TK_Period:
615 case TokenInfo::TK_InvalidChar:
616 const TokenInfo Token = Tokenizer->consumeNextToken();
617 Error->addError(Token.Range, Error->ET_ParserInvalidToken)
618 << (Token.Kind == TokenInfo::TK_NewLine ? "NewLine" : Token.Text);
619 return false;
620 }
621
622 llvm_unreachable("Unknown token kind.");
623 }
624
625 static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema;
626
Parser(CodeTokenizer * Tokenizer,Sema * S,const NamedValueMap * NamedValues,Diagnostics * Error)627 Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
628 const NamedValueMap *NamedValues, Diagnostics *Error)
629 : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
630 NamedValues(NamedValues), Error(Error) {}
631
632 Parser::RegistrySema::~RegistrySema() = default;
633
634 llvm::Optional<MatcherCtor>
lookupMatcherCtor(StringRef MatcherName)635 Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
636 return Registry::lookupMatcherCtor(MatcherName);
637 }
638
actOnMatcherExpression(MatcherCtor Ctor,SourceRange NameRange,StringRef BindID,ArrayRef<ParserValue> Args,Diagnostics * Error)639 VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
640 MatcherCtor Ctor, SourceRange NameRange, StringRef BindID,
641 ArrayRef<ParserValue> Args, Diagnostics *Error) {
642 if (BindID.empty()) {
643 return Registry::constructMatcher(Ctor, NameRange, Args, Error);
644 } else {
645 return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
646 Error);
647 }
648 }
649
getAcceptedCompletionTypes(ArrayRef<std::pair<MatcherCtor,unsigned>> Context)650 std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(
651 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
652 return Registry::getAcceptedCompletionTypes(Context);
653 }
654
getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes)655 std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(
656 ArrayRef<ArgKind> AcceptedTypes) {
657 return Registry::getMatcherCompletions(AcceptedTypes);
658 }
659
parseExpression(StringRef & Code,Sema * S,const NamedValueMap * NamedValues,VariantValue * Value,Diagnostics * Error)660 bool Parser::parseExpression(StringRef &Code, Sema *S,
661 const NamedValueMap *NamedValues,
662 VariantValue *Value, Diagnostics *Error) {
663 CodeTokenizer Tokenizer(Code, Error);
664 if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
665 return false;
666 auto NT = Tokenizer.peekNextToken();
667 if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) {
668 Error->addError(Tokenizer.peekNextToken().Range,
669 Error->ET_ParserTrailingCode);
670 return false;
671 }
672 return true;
673 }
674
675 std::vector<MatcherCompletion>
completeExpression(StringRef & Code,unsigned CompletionOffset,Sema * S,const NamedValueMap * NamedValues)676 Parser::completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S,
677 const NamedValueMap *NamedValues) {
678 Diagnostics Error;
679 CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);
680 Parser P(&Tokenizer, S, NamedValues, &Error);
681 VariantValue Dummy;
682 P.parseExpressionImpl(&Dummy);
683
684 // Sort by specificity, then by name.
685 llvm::sort(P.Completions,
686 [](const MatcherCompletion &A, const MatcherCompletion &B) {
687 if (A.Specificity != B.Specificity)
688 return A.Specificity > B.Specificity;
689 return A.TypedText < B.TypedText;
690 });
691
692 return P.Completions;
693 }
694
695 llvm::Optional<DynTypedMatcher>
parseMatcherExpression(StringRef & Code,Sema * S,const NamedValueMap * NamedValues,Diagnostics * Error)696 Parser::parseMatcherExpression(StringRef &Code, Sema *S,
697 const NamedValueMap *NamedValues,
698 Diagnostics *Error) {
699 VariantValue Value;
700 if (!parseExpression(Code, S, NamedValues, &Value, Error))
701 return llvm::Optional<DynTypedMatcher>();
702 if (!Value.isMatcher()) {
703 Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);
704 return llvm::Optional<DynTypedMatcher>();
705 }
706 llvm::Optional<DynTypedMatcher> Result =
707 Value.getMatcher().getSingleMatcher();
708 if (!Result.hasValue()) {
709 Error->addError(SourceRange(), Error->ET_ParserOverloadedType)
710 << Value.getTypeAsString();
711 }
712 return Result;
713 }
714
715 } // namespace dynamic
716 } // namespace ast_matchers
717 } // namespace clang
718