19 #include "llvm/ADT/Optional.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/ErrorHandling.h" 22 #include "llvm/Support/ManagedStatic.h" 69 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
70 NextToken = getNextToken();
74 unsigned CodeCompletionOffset)
75 : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
76 CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
77 NextToken = getNextToken();
86 NextToken = getNextToken();
98 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
100 Result.
Text = StringRef(CodeCompletionLocation, 0);
101 CodeCompletionLocation =
nullptr;
118 Result.
Text = Code.substr(0, 1);
119 Code = Code.drop_front();
123 Result.
Text = Code.substr(0, 1);
124 Code = Code.drop_front();
128 Result.
Text = Code.substr(0, 1);
129 Code = Code.drop_front();
133 Result.
Text = Code.substr(0, 1);
134 Code = Code.drop_front();
140 consumeStringLiteral(&Result);
143 case '0':
case '1':
case '2':
case '3':
case '4':
144 case '5':
case '6':
case '7':
case '8':
case '9':
146 consumeNumberLiteral(&Result);
152 size_t TokenLength = 1;
157 if (CodeCompletionLocation == Code.data() + TokenLength) {
158 CodeCompletionLocation =
nullptr;
160 Result.
Text = Code.substr(0, TokenLength);
161 Code = Code.drop_front(TokenLength);
164 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
168 if (TokenLength == 4 && Code.startswith(
"true")) {
171 }
else if (TokenLength == 5 && Code.startswith(
"false")) {
173 Result.
Value =
false;
176 Result.
Text = Code.substr(0, TokenLength);
178 Code = Code.drop_front(TokenLength);
181 Result.
Text = Code.substr(0, 1);
182 Code = Code.drop_front(1);
187 Result.
Range.
End = currentLocation();
192 void consumeNumberLiteral(
TokenInfo *Result) {
193 bool isFloatingLiteral =
false;
195 if (Code.size() > 1) {
198 case 'x':
case 'b': Length = 2;
201 while (Length < Code.size() &&
isHexDigit(Code[Length]))
205 while (Length < Code.size()) {
206 char c = Code[Length];
207 if (c ==
'-' || c ==
'+' || c ==
'.' ||
isHexDigit(c)) {
208 isFloatingLiteral =
true;
215 Result->
Text = Code.substr(0, Length);
216 Code = Code.drop_front(Length);
218 if (isFloatingLiteral) {
221 std::string
Text = Result->
Text.str();
222 double doubleValue = strtod(Text.c_str(), &end);
223 if (*end == 0 && errno == 0) {
225 Result->
Value = doubleValue;
230 if (!Result->
Text.getAsInteger(0, Value)) {
239 Range.
End = currentLocation();
240 Error->addError(Range, Error->ET_ParserNumberError) << Result->
Text;
248 void consumeStringLiteral(
TokenInfo *Result) {
249 bool InEscape =
false;
250 const char Marker = Code[0];
251 for (
size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {
256 if (Code[Length] ==
'\\') {
260 if (Code[Length] == Marker) {
262 Result->
Text = Code.substr(0, Length + 1);
263 Result->
Value = Code.substr(1, Length - 1);
264 Code = Code.drop_front(Length + 1);
269 StringRef ErrorText = Code;
270 Code = Code.drop_front(Code.size());
273 Range.
End = currentLocation();
274 Error->addError(Range, Error->ET_ParserStringError) << ErrorText;
279 void consumeWhitespace() {
281 if (Code[0] ==
'\n') {
283 StartOfLine = Code.drop_front();
285 Code = Code.drop_front();
292 Location.
Column = Code.data() - StartOfLine.data() + 1;
297 StringRef StartOfLine;
301 const char *CodeCompletionLocation =
nullptr;
311 std::vector<MatcherCompletion>
320 P->ContextStack.push_back(std::make_pair(C, 0u));
324 P->ContextStack.pop_back();
328 ++P->ContextStack.back().second;
338 const TokenInfo NameToken = Tokenizer->consumeNextToken();
343 NamedValues ? NamedValues->lookup(NameToken.
Text)
352 if (!parseBindID(BindID))
355 assert(NamedValue.isMatcher());
357 NamedValue.getMatcher().getSingleMatcher();
358 if (Result.hasValue()) {
360 if (Bound.hasValue()) {
372 !S->lookupMatcherCtor(NameToken.
Text)) {
373 Error->addError(NameToken.
Range, Error->ET_RegistryValueNotFound)
381 return parseMatcherExpressionImpl(NameToken, Value);
384 bool Parser::parseBindID(std::string &BindID) {
387 Tokenizer->consumeNextToken();
388 const TokenInfo BindToken = Tokenizer->consumeNextToken();
394 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
395 const TokenInfo IDToken = Tokenizer->consumeNextToken();
396 const TokenInfo CloseToken = Tokenizer->consumeNextToken();
402 Error->addError(BindToken.
Range, Error->ET_ParserMalformedBindExpr);
406 Error->addError(OpenToken.
Range, Error->ET_ParserMalformedBindExpr);
410 Error->addError(IDToken.
Range, Error->ET_ParserMalformedBindExpr);
414 Error->addError(CloseToken.
Range, Error->ET_ParserMalformedBindExpr);
425 bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
428 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
430 Error->addError(OpenToken.
Range, Error->ET_ParserNoOpenParen)
438 Error->addError(NameToken.
Range, Error->ET_RegistryMatcherNotFound)
443 std::vector<ParserValue> Args;
452 EndToken = Tokenizer->consumeNextToken();
457 const TokenInfo CommaToken = Tokenizer->consumeNextToken();
459 Error->addError(CommaToken.
Range, Error->ET_ParserNoComma)
469 ArgValue.
Text = Tokenizer->peekNextToken().Text;
470 ArgValue.Range = Tokenizer->peekNextToken().Range;
471 if (!parseExpressionImpl(&ArgValue.Value)) {
475 Args.push_back(ArgValue);
481 Error->addError(OpenToken.
Range, Error->ET_ParserNoCloseParen);
487 if (!parseBindID(BindID))
500 *Ctor, MatcherRange, BindID, Args, Error);
501 if (Result.
isNull())
return false;
509 void Parser::addCompletion(
const TokenInfo &CompToken,
511 if (StringRef(Completion.
TypedText).startswith(CompToken.
Text) &&
513 Completions.emplace_back(Completion.
TypedText.substr(CompToken.
Text.size()),
518 std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
520 if (!NamedValues)
return std::vector<MatcherCompletion>();
521 std::vector<MatcherCompletion> Result;
522 for (
const auto &Entry : *NamedValues) {
523 unsigned Specificity;
524 if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {
526 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
527 Result.emplace_back(Entry.getKey(), Decl, Specificity);
533 void Parser::addExpressionCompletions() {
534 const TokenInfo CompToken = Tokenizer->consumeNextToken();
539 for (ContextStackTy::iterator I = ContextStack.begin(),
540 E = ContextStack.end();
546 auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
547 for (
const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
548 addCompletion(CompToken, Completion);
551 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
552 addCompletion(CompToken, Completion);
558 switch (Tokenizer->nextTokenKind()) {
560 *Value = Tokenizer->consumeNextToken().Value;
564 return parseIdentifierPrefixImpl(Value);
567 addExpressionCompletions();
571 Error->addError(Tokenizer->consumeNextToken().Range,
572 Error->ET_ParserNoCode);
585 Error->addError(Token.
Range, Error->ET_ParserInvalidToken) << Token.
Text;
589 llvm_unreachable(
"Unknown token kind.");
594 Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
596 : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
597 NamedValues(NamedValues), Error(Error) {}
609 if (BindID.empty()) {
618 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
631 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
641 std::vector<MatcherCompletion>
646 Parser P(&Tokenizer, S, NamedValues, &Error);
648 P.parseExpressionImpl(&Dummy);
651 llvm::sort(P.Completions,
653 if (A.Specificity != B.Specificity)
654 return A.Specificity > B.Specificity;
655 return A.TypedText < B.TypedText;
658 return P.Completions;
674 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)