44 : code(matcherCode), startOfLine(matcherCode), error(error) {
45 nextToken = getNextToken();
50 unsigned codeCompletionOffset)
51 : code(matcherCode), startOfLine(matcherCode), error(error),
52 codeCompletionLocation(matcherCode.data() + codeCompletionOffset) {
53 nextToken = getNextToken();
62 nextToken = getNextToken();
69 nextToken = getNextToken();
85 llvm::StringRef firstCharacterAndDrop(llvm::StringRef &str) {
87 llvm::StringRef firstChar = str.substr(0, 1);
88 str = str.drop_front();
93 TokenInfo getNextToken() {
96 result.range.start = currentLocation();
99 if (codeCompletionLocation && codeCompletionLocation <= code.data()) {
101 llvm::StringRef(codeCompletionLocation, 0));
102 codeCompletionLocation =
nullptr;
115 code = code.drop_until([](
char c) {
return c ==
'\n'; });
116 return getNextToken();
125 startOfLine = code.drop_front();
136 consumeStringLiteral(&result);
139 parseIdentifierOrInvalid(&result);
143 result.range.end = currentLocation();
149 void consumeStringLiteral(TokenInfo *result) {
150 bool inEscape =
false;
151 const char marker = code[0];
152 for (
size_t length = 1; length < code.size(); ++length) {
157 if (code[length] ==
'\\') {
161 if (code[length] == marker) {
163 result->text = code.substr(0, length + 1);
164 result->value = code.substr(1, length - 1);
165 code = code.drop_front(length + 1);
169 llvm::StringRef errorText = code;
170 code = code.drop_front(code.size());
172 range.start = result->range.start;
173 range.end = currentLocation();
178 void parseIdentifierOrInvalid(TokenInfo *result) {
179 if (isalnum(code[0])) {
181 size_t tokenLength = 1;
187 if (codeCompletionLocation == code.data() + tokenLength) {
188 codeCompletionLocation =
nullptr;
190 result->text = code.substr(0, tokenLength);
191 code = code.drop_front(tokenLength);
194 if (tokenLength == code.size() || !(isalnum(code[tokenLength])))
199 result->text = code.substr(0, tokenLength);
200 code = code.drop_front(tokenLength);
203 result->text = code.substr(0, 1);
204 code = code.drop_front(1);
209 void consumeWhitespace() { code = code.ltrim(
" \t\v\f\r"); }
212 SourceLocation currentLocation() {
213 SourceLocation location;
214 location.line = line;
215 location.column = code.data() - startOfLine.data() + 1;
219 llvm::StringRef code;
220 llvm::StringRef startOfLine;
224 const char *codeCompletionLocation =
nullptr;
234 std::vector<MatcherCompletion>
244 parser->contextStack.emplace_back(c, 0u);
249 void nextArg() { ++parser->contextStack.back().second; }
255 bool Parser::parseIdentifierPrefixImpl(
VariantValue *value) {
261 namedValues ? namedValues->lookup(nameToken.text) :
VariantValue();
263 if (!namedValue.isMatcher()) {
282 !sema->lookupMatcherCtor(nameToken.text)) {
300 std::optional<MatcherCtor> ctor = sema->lookupMatcherCtor(nameToken.text);
303 return parseMatcherExpressionImpl(nameToken, openToken, ctor, value);
306 bool Parser::parseChainedExpression(std::string &argument) {
320 !argumentToken.value.isString()) {
321 error->
addError(argumentToken.range,
332 argument = argumentToken.value.getString();
337 bool Parser::parseMatcherArgs(std::vector<ParserValue> &args,
MatcherCtor ctor,
338 const TokenInfo &nameToken, TokenInfo &endToken) {
339 ScopedContextEntry sce(
this, ctor);
358 ParserValue argValue;
363 if (!parseExpressionImpl(&argValue.value)) {
368 args.push_back(argValue);
376 bool Parser::parseMatcherExpressionImpl(
const TokenInfo &nameToken,
377 const TokenInfo &openToken,
378 std::optional<MatcherCtor> ctor,
379 VariantValue *value) {
386 std::vector<ParserValue> args;
391 if (!parseMatcherArgs(args, ctor.value_or(
nullptr), nameToken, endToken)) {
402 std::string functionName;
407 addCompletion(chainCallToken, MatcherCompletion(
"extract(\"",
"extract"));
413 error->
addError(chainCallToken.range,
419 !parseChainedExpression(functionName))
426 SourceRange matcherRange = nameToken.range;
427 matcherRange.end = endToken.range.end;
428 VariantMatcher result = sema->actOnMatcherExpression(
429 *ctor, matcherRange, functionName, args, error);
438 void Parser::addCompletion(
const TokenInfo &compToken,
439 const MatcherCompletion &completion) {
440 if (llvm::StringRef(completion.typedText).starts_with(compToken.text)) {
441 completions.emplace_back(completion.typedText.substr(compToken.text.size()),
442 completion.matcherDecl);
446 std::vector<MatcherCompletion>
451 std::vector<MatcherCompletion> result;
452 for (
const auto &entry : *namedValues) {
454 (entry.getValue().getTypeAsString() +
" " + entry.getKey()).str();
455 result.emplace_back(entry.getKey(), decl);
460 void Parser::addExpressionCompletions() {
466 for (
const auto &entry : contextStack) {
471 auto acceptedTypes = sema->getAcceptedCompletionTypes(contextStack);
472 for (
const auto &completion : sema->getMatcherCompletions(acceptedTypes)) {
473 addCompletion(compToken, completion);
476 for (
const auto &completion : getNamedValueCompletions(acceptedTypes)) {
477 addCompletion(compToken, completion);
482 bool Parser::parseExpressionImpl(VariantValue *value) {
488 return parseIdentifierPrefixImpl(value);
490 addExpressionCompletions();
512 llvm_unreachable(
"Unknown token kind.");
515 Parser::Parser(CodeTokenizer *tokenizer,
const Registry &matcherRegistry,
517 : tokenizer(tokenizer),
518 sema(std::make_unique<RegistrySema>(matcherRegistry)),
519 namedValues(namedValues), error(error) {}
523 std::optional<MatcherCtor>
550 Parser parser(&tokenizer, matcherRegistry, namedValues, error);
551 if (!parser.parseExpressionImpl(value))
563 std::vector<MatcherCompletion>
569 Parser parser(&tokenizer, matcherRegistry, namedValues, &error);
571 parser.parseExpressionImpl(&dummy);
573 return parser.completions;
577 llvm::StringRef &code,
const Registry &matcherRegistry,
580 if (!
parseExpression(code, matcherRegistry, namedValues, &value, error))
static std::vector< MatcherCompletion > getMatcherCompletions(ArrayRef< ArgKind > acceptedTypes, const Registry &matcherRegistry)
static std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> context)
static std::optional< MatcherCtor > lookupMatcherCtor(llvm::StringRef matcherName, const Registry &matcherRegistry)
static VariantMatcher constructMatcher(MatcherCtor ctor, internal::SourceRange nameRange, llvm::StringRef functionName, ArrayRef< ParserValue > args, internal::Diagnostics *error)
std::optional< DynMatcher > getDynMatcher() const
std::string getTypeAsString() const
const VariantMatcher & getMatcher() const
ArgStream addError(SourceRange range, ErrorType error)
TokenInfo consumeNextToken()
CodeTokenizer(llvm::StringRef matcherCode, Diagnostics *error, unsigned codeCompletionOffset)
TokenKind nextTokenKind() const
const TokenInfo & peekNextToken() const
CodeTokenizer(llvm::StringRef matcherCode, Diagnostics *error)
TokenInfo consumeNextTokenIgnoreNewlines()
std::optional< MatcherCtor > lookupMatcherCtor(llvm::StringRef matcherName) override
std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > acceptedTypes) override
std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> context) override
VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, SourceRange NameRange, StringRef functionName, ArrayRef< ParserValue > Args, Diagnostics *Error) override
virtual std::vector< MatcherCompletion > getMatcherCompletions(llvm::ArrayRef< ArgKind > acceptedTypes)
virtual std::vector< ArgKind > getAcceptedCompletionTypes(llvm::ArrayRef< std::pair< MatcherCtor, unsigned >> Context)
static bool parseExpression(llvm::StringRef &code, const Registry &matcherRegistry, const NamedValueMap *namedValues, VariantValue *value, Diagnostics *error)
llvm::StringMap< VariantValue > NamedValueMap
static std::vector< MatcherCompletion > completeExpression(llvm::StringRef &code, unsigned completionOffset, const Registry &matcherRegistry, const NamedValueMap *namedValues)
static std::optional< DynMatcher > parseMatcherExpression(llvm::StringRef &matcherCode, const Registry &matcherRegistry, const NamedValueMap *namedValues, Diagnostics *error)
@ ParserChainedExprNoOpenParen
@ RegistryMatcherNotFound
@ ParserChainedExprInvalidArg
@ ParserMalformedChainedExpr
@ ParserChainedExprNoCloseParen
const internal::MatcherDescriptor * MatcherCtor
ScopedContextEntry(Parser *parser, MatcherCtor c)
static const char *const ID_Extract
void set(TokenKind newKind, llvm::StringRef newText)