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