1 //===--- Parser.h - Matcher expression parser -------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Simple matcher expression parser. 10 // 11 // This file contains the Parser class, which is responsible for parsing 12 // expressions in a specific format: matcherName(Arg0, Arg1, ..., ArgN). The 13 // parser can also interpret simple types, like strings. 14 // 15 // The actual processing of the matchers is handled by a Sema object that is 16 // provided to the parser. 17 // 18 // The grammar for the supported expressions is as follows: 19 // <Expression> := <StringLiteral> | <MatcherExpression> 20 // <StringLiteral> := "quoted string" 21 // <MatcherExpression> := <MatcherName>(<ArgumentList>) 22 // <MatcherName> := [a-zA-Z]+ 23 // <ArgumentList> := <Expression> | <Expression>,<ArgumentList> 24 // 25 //===----------------------------------------------------------------------===// 26 27 #ifndef MLIR_TOOLS_MLIRQUERY_MATCHER_PARSER_H 28 #define MLIR_TOOLS_MLIRQUERY_MATCHER_PARSER_H 29 30 #include "Diagnostics.h" 31 #include "RegistryManager.h" 32 #include "llvm/ADT/ArrayRef.h" 33 #include "llvm/ADT/StringMap.h" 34 #include "llvm/ADT/StringRef.h" 35 #include <memory> 36 #include <vector> 37 38 namespace mlir::query::matcher::internal { 39 40 // Matcher expression parser. 41 class Parser { 42 public: 43 // Different possible tokens. 44 enum class TokenKind { 45 Eof, 46 NewLine, 47 OpenParen, 48 CloseParen, 49 Comma, 50 Period, 51 Literal, 52 Ident, 53 InvalidChar, 54 CodeCompletion, 55 Error 56 }; 57 58 // Interface to connect the parser with the registry and more. The parser uses 59 // the Sema instance passed into parseMatcherExpression() to handle all 60 // matcher tokens. 61 class Sema { 62 public: 63 virtual ~Sema(); 64 65 // Process a matcher expression. The caller takes ownership of the Matcher 66 // object returned. 67 virtual VariantMatcher actOnMatcherExpression( 68 MatcherCtor ctor, SourceRange nameRange, llvm::StringRef functionName, 69 llvm::ArrayRef<ParserValue> args, Diagnostics *error) = 0; 70 71 // Look up a matcher by name in the matcher name found by the parser. 72 virtual std::optional<MatcherCtor> 73 lookupMatcherCtor(llvm::StringRef matcherName) = 0; 74 75 // Compute the list of completion types for Context. 76 virtual std::vector<ArgKind> getAcceptedCompletionTypes( 77 llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context); 78 79 // Compute the list of completions that match any of acceptedTypes. 80 virtual std::vector<MatcherCompletion> 81 getMatcherCompletions(llvm::ArrayRef<ArgKind> acceptedTypes); 82 }; 83 84 // An implementation of the Sema interface that uses the matcher registry to 85 // process tokens. 86 class RegistrySema : public Parser::Sema { 87 public: RegistrySema(const Registry & matcherRegistry)88 RegistrySema(const Registry &matcherRegistry) 89 : matcherRegistry(matcherRegistry) {} 90 ~RegistrySema() override; 91 92 std::optional<MatcherCtor> 93 lookupMatcherCtor(llvm::StringRef matcherName) override; 94 95 VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, 96 SourceRange NameRange, 97 StringRef functionName, 98 ArrayRef<ParserValue> Args, 99 Diagnostics *Error) override; 100 101 std::vector<ArgKind> getAcceptedCompletionTypes( 102 llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> context) override; 103 104 std::vector<MatcherCompletion> 105 getMatcherCompletions(llvm::ArrayRef<ArgKind> acceptedTypes) override; 106 107 private: 108 const Registry &matcherRegistry; 109 }; 110 111 using NamedValueMap = llvm::StringMap<VariantValue>; 112 113 // Methods to parse a matcher expression and return a DynMatcher object, 114 // transferring ownership to the caller. 115 static std::optional<DynMatcher> 116 parseMatcherExpression(llvm::StringRef &matcherCode, 117 const Registry &matcherRegistry, 118 const NamedValueMap *namedValues, Diagnostics *error); 119 static std::optional<DynMatcher> parseMatcherExpression(llvm::StringRef & matcherCode,const Registry & matcherRegistry,Diagnostics * error)120 parseMatcherExpression(llvm::StringRef &matcherCode, 121 const Registry &matcherRegistry, Diagnostics *error) { 122 return parseMatcherExpression(matcherCode, matcherRegistry, nullptr, error); 123 } 124 125 // Methods to parse any expression supported by this parser. 126 static bool parseExpression(llvm::StringRef &code, 127 const Registry &matcherRegistry, 128 const NamedValueMap *namedValues, 129 VariantValue *value, Diagnostics *error); 130 parseExpression(llvm::StringRef & code,const Registry & matcherRegistry,VariantValue * value,Diagnostics * error)131 static bool parseExpression(llvm::StringRef &code, 132 const Registry &matcherRegistry, 133 VariantValue *value, Diagnostics *error) { 134 return parseExpression(code, matcherRegistry, nullptr, value, error); 135 } 136 137 // Methods to complete an expression at a given offset. 138 static std::vector<MatcherCompletion> 139 completeExpression(llvm::StringRef &code, unsigned completionOffset, 140 const Registry &matcherRegistry, 141 const NamedValueMap *namedValues); 142 static std::vector<MatcherCompletion> completeExpression(llvm::StringRef & code,unsigned completionOffset,const Registry & matcherRegistry)143 completeExpression(llvm::StringRef &code, unsigned completionOffset, 144 const Registry &matcherRegistry) { 145 return completeExpression(code, completionOffset, matcherRegistry, nullptr); 146 } 147 148 private: 149 class CodeTokenizer; 150 struct ScopedContextEntry; 151 struct TokenInfo; 152 153 Parser(CodeTokenizer *tokenizer, const Registry &matcherRegistry, 154 const NamedValueMap *namedValues, Diagnostics *error); 155 156 bool parseChainedExpression(std::string &argument); 157 158 bool parseExpressionImpl(VariantValue *value); 159 160 bool parseMatcherArgs(std::vector<ParserValue> &args, MatcherCtor ctor, 161 const TokenInfo &nameToken, TokenInfo &endToken); 162 163 bool parseMatcherExpressionImpl(const TokenInfo &nameToken, 164 const TokenInfo &openToken, 165 std::optional<MatcherCtor> ctor, 166 VariantValue *value); 167 168 bool parseIdentifierPrefixImpl(VariantValue *value); 169 170 void addCompletion(const TokenInfo &compToken, 171 const MatcherCompletion &completion); 172 void addExpressionCompletions(); 173 174 std::vector<MatcherCompletion> 175 getNamedValueCompletions(llvm::ArrayRef<ArgKind> acceptedTypes); 176 177 CodeTokenizer *const tokenizer; 178 std::unique_ptr<RegistrySema> sema; 179 const NamedValueMap *const namedValues; 180 Diagnostics *const error; 181 182 using ContextStackTy = std::vector<std::pair<MatcherCtor, unsigned>>; 183 184 ContextStackTy contextStack; 185 std::vector<MatcherCompletion> completions; 186 }; 187 188 } // namespace mlir::query::matcher::internal 189 190 #endif // MLIR_TOOLS_MLIRQUERY_MATCHER_PARSER_H 191