20 #include "llvm/ADT/Optional.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/Support/ErrorHandling.h" 23 #include "llvm/Support/ManagedStatic.h" 70 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
71 NextToken = getNextToken();
75 unsigned CodeCompletionOffset)
76 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
77 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
78 NextToken = getNextToken();
87 NextToken = getNextToken();
99 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
101 Result.
Text = StringRef(CodeCompletionLocation, 0);
102 CodeCompletionLocation =
nullptr;
119 Result.
Text = Code.substr(0, 1);
120 Code = Code.drop_front();
124 Result.
Text = Code.substr(0, 1);
125 Code = Code.drop_front();
129 Result.
Text = Code.substr(0, 1);
130 Code = Code.drop_front();
134 Result.
Text = Code.substr(0, 1);
135 Code = Code.drop_front();
141 consumeStringLiteral(&Result);
144 case '0':
case '1':
case '2':
case '3':
case '4':
145 case '5':
case '6':
case '7':
case '8':
case '9':
147 consumeNumberLiteral(&Result);
153 size_t TokenLength = 1;
158 if (CodeCompletionLocation == Code.data() + TokenLength) {
159 CodeCompletionLocation =
nullptr;
161 Result.
Text = Code.substr(0, TokenLength);
162 Code = Code.drop_front(TokenLength);
165 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
169 if (TokenLength == 4 && Code.startswith(
"true")) {
172 }
else if (TokenLength == 5 && Code.startswith(
"false")) {
174 Result.
Value =
false;
177 Result.
Text = Code.substr(0, TokenLength);
179 Code = Code.drop_front(TokenLength);
182 Result.
Text = Code.substr(0, 1);
183 Code = Code.drop_front(1);
188 Result.
Range.
End = currentLocation();
193 void consumeNumberLiteral(
TokenInfo *Result) {
194 bool isFloatingLiteral =
false;
196 if (Code.size() > 1) {
199 case 'x':
case 'b': Length = 2;
202 while (Length < Code.size() &&
isHexDigit(Code[Length]))
206 while (Length < Code.size()) {
207 char c = Code[Length];
208 if (c ==
'-' || c ==
'+' || c ==
'.' ||
isHexDigit(c)) {
209 isFloatingLiteral =
true;
216 Result->
Text = Code.substr(0, Length);
217 Code = Code.drop_front(Length);
219 if (isFloatingLiteral) {
222 std::string
Text = Result->
Text.str();
223 double doubleValue = strtod(Text.c_str(), &end);
224 if (*end == 0 && errno == 0) {
226 Result->
Value = doubleValue;
231 if (!Result->
Text.getAsInteger(0, Value)) {
240 Range.
End = currentLocation();
241 Error->addError(Range, Error->ET_ParserNumberError) << Result->
Text;
249 void consumeStringLiteral(
TokenInfo *Result) {
250 bool InEscape =
false;
251 const char Marker = Code[0];
252 for (
size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
257 if (Code[Length] ==
'\\') {
261 if (Code[Length] == Marker) {
263 Result->
Text = Code.substr(0, Length + 1);
264 Result->
Value = Code.substr(1, Length - 1);
265 Code = Code.drop_front(Length + 1);
270 StringRef ErrorText = Code;
271 Code = Code.drop_front(Code.size());
274 Range.
End = currentLocation();
275 Error->addError(Range, Error->ET_ParserStringError) << ErrorText;
280 void consumeWhitespace() {
282 if (Code[0] ==
'\n') {
284 StartOfLine = Code.drop_front();
286 Code = Code.drop_front();
293 Location.
Column = Code.data() - StartOfLine.data() + 1;
298 StringRef StartOfLine;
302 const char *CodeCompletionLocation =
nullptr;
312 std::vector<MatcherCompletion>
321 P->ContextStack.push_back(std::make_pair(C, 0u));
325 P->ContextStack.pop_back();
329 ++P->ContextStack.back().second;
339 const TokenInfo NameToken = Tokenizer->consumeNextToken();
344 NamedValues ? NamedValues->lookup(NameToken.
Text)
353 if (!parseBindID(BindID))
356 assert(NamedValue.isMatcher());
358 NamedValue.getMatcher().getSingleMatcher();
359 if (Result.hasValue()) {
361 if (Bound.hasValue()) {
373 !S->lookupMatcherCtor(NameToken.
Text)) {
374 Error->addError(NameToken.
Range, Error->ET_RegistryValueNotFound)
382 return parseMatcherExpressionImpl(NameToken, Value);
385 bool Parser::parseBindID(std::string &BindID) {
388 Tokenizer->consumeNextToken();
389 const TokenInfo BindToken = Tokenizer->consumeNextToken();
395 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
396 const TokenInfo IDToken = Tokenizer->consumeNextToken();
397 const TokenInfo CloseToken = Tokenizer->consumeNextToken();
403 Error->addError(BindToken.
Range, Error->ET_ParserMalformedBindExpr);
407 Error->addError(OpenToken.
Range, Error->ET_ParserMalformedBindExpr);
411 Error->addError(IDToken.
Range, Error->ET_ParserMalformedBindExpr);
415 Error->addError(CloseToken.
Range, Error->ET_ParserMalformedBindExpr);
426 bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
429 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
431 Error->addError(OpenToken.
Range, Error->ET_ParserNoOpenParen)
439 Error->addError(NameToken.
Range, Error->ET_RegistryMatcherNotFound)
444 std::vector<ParserValue> Args;
453 EndToken = Tokenizer->consumeNextToken();
458 const TokenInfo CommaToken = Tokenizer->consumeNextToken();
460 Error->addError(CommaToken.
Range, Error->ET_ParserNoComma)
470 ArgValue.
Text = Tokenizer->peekNextToken().Text;
471 ArgValue.Range = Tokenizer->peekNextToken().Range;
472 if (!parseExpressionImpl(&ArgValue.Value)) {
476 Args.push_back(ArgValue);
482 Error->addError(OpenToken.
Range, Error->ET_ParserNoCloseParen);
488 if (!parseBindID(BindID))
501 *Ctor, MatcherRange, BindID, Args, Error);
502 if (Result.
isNull())
return false;
510 void Parser::addCompletion(
const TokenInfo &CompToken,
512 if (StringRef(Completion.
TypedText).startswith(CompToken.
Text) &&
514 Completions.emplace_back(Completion.
TypedText.substr(CompToken.
Text.size()),
519 std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
521 if (!NamedValues)
return std::vector<MatcherCompletion>();
522 std::vector<MatcherCompletion> Result;
523 for (
const auto &Entry : *NamedValues) {
524 unsigned Specificity;
525 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
527 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).
str();
528 Result.emplace_back(Entry.getKey(), Decl, Specificity);
534 void Parser::addExpressionCompletions() {
535 const TokenInfo CompToken = Tokenizer->consumeNextToken();
540 for (ContextStackTy::iterator I = ContextStack.begin(),
541 E = ContextStack.end();
547 auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
548 for (
const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
549 addCompletion(CompToken, Completion);
552 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
553 addCompletion(CompToken, Completion);
559 switch (Tokenizer->nextTokenKind()) {
561 *Value = Tokenizer->consumeNextToken().Value;
565 return parseIdentifierPrefixImpl(Value);
568 addExpressionCompletions();
572 Error->addError(Tokenizer->consumeNextToken().Range,
573 Error->ET_ParserNoCode);
586 Error->addError(Token.
Range, Error->ET_ParserInvalidToken) << Token.
Text;
590 llvm_unreachable(
"Unknown token kind.");
595 Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
597 : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
598 NamedValues(NamedValues), Error(Error) {}
610 if (BindID.empty()) {
619 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
632 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
642 std::vector<MatcherCompletion>
647 Parser P(&Tokenizer, S, NamedValues, &Error);
649 P.parseExpressionImpl(&Dummy);
652 llvm::sort(P.Completions,
654 if (A.Specificity != B.Specificity)
655 return A.Specificity > B.Specificity;
656 return A.TypedText < B.TypedText;
659 return P.Completions;
675 if (!Result.hasValue()) {
static std::vector< MatcherCompletion > completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, const NamedValueMap *NamedValues)
Complete an expression at the given offset.
static VariantMatcher constructBoundMatcher(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error)
Construct a matcher from the registry and bind it.
Simple matcher expression parser.
static std::vector< MatcherCompletion > getMatcherCompletions(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.
Registry of all known matchers.
CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
Decl - This represents one declaration (or definition), e.g.
CodeTokenizer(StringRef MatcherCode, Diagnostics *Error, unsigned CodeCompletionOffset)
llvm::StringMap< VariantValue > NamedValueMap
llvm::Optional< DynTypedMatcher > getSingleMatcher() const
Return a single matcher, if there is no ambiguity.
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher)
Clones the provided matcher.
Token - This structure provides full information about a lexed token.
Matcher descriptor interface.
Simple tokenizer for the parser.
static std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> Context)
Compute the list of completion types for Context.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
static const char *const ID_Bind
Some known identifiers.
Class defining a parser context.
llvm::Optional< MatcherCtor > lookupMatcherCtor(StringRef MatcherName) override
Look up a matcher by name.
std::string MatcherDecl
The "declaration" of the matcher, with type information.
A VariantValue instance annotated with its parser context.
Sema - This implements semantic analysis and AST building for C.
static llvm::Optional< MatcherCtor > lookupMatcherCtor(StringRef MatcherName)
Look up a matcher in the registry by name,.
std::string getTypeAsString() const
String representation of the type of the value.
Matcher expression parser.
const AnnotatedLine * Line
LLVM_READONLY bool isAlphanumeric(unsigned char c)
Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].
Diagnostics class to manage error messages.
TokenInfo::TokenKind nextTokenKind() const
VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, SourceRange NameRange, StringRef BindID, ArrayRef< ParserValue > Args, Diagnostics *Error) override
Process a matcher expression.
Helper class to manage error messages.
std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> Context) override
Compute the list of completion types for Context.
ArgStream addError(SourceRange Range, ErrorType Error)
Add an error to the diagnostics.
static llvm::Optional< DynTypedMatcher > parseMatcherExpression(StringRef MatcherCode, Sema *S, const NamedValueMap *NamedValues, Diagnostics *Error)
Parse a matcher expression.
LLVM_READONLY char toLowercase(char c)
Converts the given ASCII character to its lowercase equivalent.
TokenKind
Different possible tokens.
const VariantMatcher & getMatcher() const
unsigned Specificity
Value corresponding to the "specificity" of the converted matcher.
const std::string & getString() const
std::string TypedText
The text to type to select this matcher.
static llvm::ManagedStatic< Parser::RegistrySema > DefaultRegistrySema
const TokenInfo & peekNextToken() const
Returns but doesn't consume the next token.
Dataflow Directional Tag Classes.
bool isMatcher() const
Matcher value functions.
Interface to connect the parser with the registry and more.
Simple structure to hold information for one token from the parser.
bool isNull() const
Whether the matcher is null.
LLVM_READONLY bool isHexDigit(unsigned char c)
Return true if this character is an ASCII hex digit: [0-9a-fA-F].
virtual std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> Context)
Compute the list of completion types for Context.
A variant matcher object.
std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > AcceptedTypes) override
Compute the list of completions that match any of AcceptedTypes.
virtual std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > AcceptedTypes)
Compute the list of completions that match any of AcceptedTypes.
TokenInfo consumeNextToken()
Consumes and returns the next token.
bool isString() const
String value functions.
static VariantMatcher constructMatcher(MatcherCtor Ctor, SourceRange NameRange, ArrayRef< ParserValue > Args, Diagnostics *Error)
Construct a matcher from the registry.
ScopedContextEntry(Parser *P, MatcherCtor C)