19 #include "llvm/ADT/Optional.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/ErrorHandling.h" 22 #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();
93 NextToken = getNextToken();
101 return consumeNextToken();
112 if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
114 Result.
Text = StringRef(CodeCompletionLocation, 0);
115 CodeCompletionLocation =
nullptr;
127 Code = Code.drop_until([](
char c) {
return c ==
'\n'; });
128 return getNextToken();
131 Result.
Text = Code.substr(0, 1);
132 Code = Code.drop_front();
136 Result.
Text = Code.substr(0, 1);
137 Code = Code.drop_front();
141 StartOfLine = Code.drop_front();
143 Result.
Text = Code.substr(0, 1);
144 Code = Code.drop_front();
148 Result.
Text = Code.substr(0, 1);
149 Code = Code.drop_front();
153 Result.
Text = Code.substr(0, 1);
154 Code = Code.drop_front();
160 consumeStringLiteral(&Result);
163 case '0':
case '1':
case '2':
case '3':
case '4':
164 case '5':
case '6':
case '7':
case '8':
case '9':
166 consumeNumberLiteral(&Result);
172 size_t TokenLength = 1;
177 if (CodeCompletionLocation == Code.data() + TokenLength) {
178 CodeCompletionLocation =
nullptr;
180 Result.
Text = Code.substr(0, TokenLength);
181 Code = Code.drop_front(TokenLength);
184 if (TokenLength == Code.size() || !
isAlphanumeric(Code[TokenLength]))
188 if (TokenLength == 4 && Code.startswith(
"true")) {
191 }
else if (TokenLength == 5 && Code.startswith(
"false")) {
193 Result.
Value =
false;
196 Result.
Text = Code.substr(0, TokenLength);
198 Code = Code.drop_front(TokenLength);
201 Result.
Text = Code.substr(0, 1);
202 Code = Code.drop_front(1);
207 Result.
Range.
End = currentLocation();
212 void consumeNumberLiteral(
TokenInfo *Result) {
213 bool isFloatingLiteral =
false;
215 if (Code.size() > 1) {
218 case 'x':
case 'b': Length = 2;
221 while (Length < Code.size() &&
isHexDigit(Code[Length]))
225 while (Length < Code.size()) {
226 char c = Code[Length];
227 if (c ==
'-' || c ==
'+' || c ==
'.' ||
isHexDigit(c)) {
228 isFloatingLiteral =
true;
235 Result->
Text = Code.substr(0, Length);
236 Code = Code.drop_front(Length);
238 if (isFloatingLiteral) {
241 std::string
Text = Result->
Text.str();
242 double doubleValue = strtod(Text.c_str(), &end);
243 if (*end == 0 && errno == 0) {
245 Result->
Value = doubleValue;
250 if (!Result->
Text.getAsInteger(0, Value)) {
259 Range.
End = currentLocation();
260 Error->addError(Range,
Error->ET_ParserNumberError) << Result->
Text;
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) {
276 if (Code[Length] ==
'\\') {
280 if (Code[Length] == Marker) {
282 Result->
Text = Code.substr(0, Length + 1);
283 Result->
Value = Code.substr(1, Length - 1);
284 Code = Code.drop_front(Length + 1);
289 StringRef ErrorText = Code;
290 Code = Code.drop_front(Code.size());
293 Range.
End = currentLocation();
294 Error->addError(Range,
Error->ET_ParserStringError) << ErrorText;
299 void consumeWhitespace() {
300 Code = Code.drop_while([](
char c) {
302 return StringRef(
" \t\v\f\r").contains(c);
309 Location.
Column = Code.data() - StartOfLine.data() + 1;
314 StringRef StartOfLine;
318 const char *CodeCompletionLocation =
nullptr;
328 std::vector<MatcherCompletion>
337 P->ContextStack.push_back(std::make_pair(C, 0u));
341 P->ContextStack.pop_back();
345 ++P->ContextStack.back().second;
355 const TokenInfo NameToken = Tokenizer->consumeNextToken();
360 NamedValues ? NamedValues->lookup(NameToken.
Text)
369 if (!parseBindID(BindID))
372 assert(NamedValue.isMatcher());
374 NamedValue.getMatcher().getSingleMatcher();
375 if (Result.hasValue()) {
377 if (Bound.hasValue()) {
386 Error->addError(Tokenizer->peekNextToken().Range,
387 Error->ET_ParserNoOpenParen)
398 !S->lookupMatcherCtor(NameToken.
Text)) {
406 Tokenizer->SkipNewlines();
409 return parseMatcherExpressionImpl(NameToken, Value);
412 bool Parser::parseBindID(std::string &BindID) {
415 Tokenizer->consumeNextToken();
416 const TokenInfo BindToken = Tokenizer->consumeNextToken();
422 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
423 const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines();
424 const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines();
453 bool Parser::parseMatcherExpressionImpl(
const TokenInfo &NameToken,
456 const TokenInfo OpenToken = Tokenizer->consumeNextToken();
471 std::vector<ParserValue> Args;
474 Tokenizer->SkipNewlines();
482 EndToken = Tokenizer->consumeNextToken();
487 const TokenInfo CommaToken = Tokenizer->consumeNextToken();
499 Tokenizer->SkipNewlines();
500 ArgValue.Text = Tokenizer->peekNextToken().Text;
501 ArgValue.Range = Tokenizer->peekNextToken().Range;
502 if (!parseExpressionImpl(&ArgValue.Value)) {
506 Tokenizer->SkipNewlines();
507 Args.push_back(ArgValue);
519 if (!parseBindID(BindID))
532 *Ctor, MatcherRange, BindID, Args,
Error);
533 if (Result.
isNull())
return false;
541 void Parser::addCompletion(
const TokenInfo &CompToken,
543 if (StringRef(Completion.
TypedText).startswith(CompToken.
Text) &&
545 Completions.emplace_back(Completion.
TypedText.substr(CompToken.
Text.size()),
550 std::vector<MatcherCompletion> Parser::getNamedValueCompletions(
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)) {
558 (Entry.getValue().getTypeAsString() +
" " + Entry.getKey()).str();
559 Result.emplace_back(Entry.getKey(), Decl, Specificity);
565 void Parser::addExpressionCompletions() {
566 const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines();
571 for (ContextStackTy::iterator I = ContextStack.begin(),
572 E = ContextStack.end();
578 auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);
579 for (
const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {
580 addCompletion(CompToken, Completion);
583 for (
const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {
584 addCompletion(CompToken, Completion);
590 switch (Tokenizer->nextTokenKind()) {
592 *Value = Tokenizer->consumeNextToken().Value;
596 return parseIdentifierPrefixImpl(Value);
599 addExpressionCompletions();
603 Error->addError(Tokenizer->consumeNextToken().Range,
604 Error->ET_ParserNoCode);
622 llvm_unreachable(
"Unknown token kind.");
627 Parser::Parser(CodeTokenizer *Tokenizer,
Sema *S,
629 : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
630 NamedValues(NamedValues), Error(Error) {}
642 if (BindID.empty()) {
651 ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
664 if (!
Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))
675 std::vector<MatcherCompletion>
680 Parser P(&Tokenizer, S, NamedValues, &Error);
682 P.parseExpressionImpl(&Dummy);
685 llvm::sort(P.Completions,
687 if (A.Specificity != B.Specificity)
688 return A.Specificity > B.Specificity;
689 return A.TypedText < B.TypedText;
692 return P.Completions;
708 if (!Result.hasValue()) {
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.
Registry of all known matchers.
static llvm::Optional< DynTypedMatcher > parseMatcherExpression(StringRef &MatcherCode, Sema *S, const NamedValueMap *NamedValues, Diagnostics *Error)
Parse a matcher expression.
Decl - This represents one declaration (or definition), e.g.
llvm::StringMap< VariantValue > NamedValueMap
llvm::Optional< DynTypedMatcher > getSingleMatcher() const
Return a single matcher, if there is no ambiguity.
CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error)
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher)
Clones the provided matcher.
TokenInfo consumeNextTokenIgnoreNewlines()
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.
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.
static bool parseExpression(StringRef &Code, Sema *S, const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error)
Parse an expression.
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.
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.
static std::vector< MatcherCompletion > completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S, const NamedValueMap *NamedValues)
Complete an expression at the given offset.
bool isNull() const
Whether the matcher is null.
CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error, unsigned CodeCompletionOffset)
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)