Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Transformer/Parsing.cpp
35266 views
//===--- Parsing.cpp - Parsing function implementations ---------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Tooling/Transformer/Parsing.h"9#include "clang/AST/Expr.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "clang/Basic/CharInfo.h"12#include "clang/Basic/SourceLocation.h"13#include "clang/Lex/Lexer.h"14#include "clang/Tooling/Transformer/RangeSelector.h"15#include "clang/Tooling/Transformer/SourceCode.h"16#include "llvm/ADT/StringMap.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/Errc.h"19#include "llvm/Support/Error.h"20#include <optional>21#include <string>22#include <utility>23#include <vector>2425using namespace clang;26using namespace transformer;2728// FIXME: This implementation is entirely separate from that of the AST29// matchers. Given the similarity of the languages and uses of the two parsers,30// the two should share a common parsing infrastructure, as should other31// Transformer types. We intend to unify this implementation soon to share as32// much as possible with the AST Matchers parsing.3334namespace {35using llvm::Expected;3637template <typename... Ts> using RangeSelectorOp = RangeSelector (*)(Ts...);3839struct ParseState {40// The remaining input to be processed.41StringRef Input;42// The original input. Not modified during parsing; only for reference in43// error reporting.44StringRef OriginalInput;45};4647// Represents an intermediate result returned by a parsing function. Functions48// that don't generate values should use `std::nullopt`49template <typename ResultType> struct ParseProgress {50ParseState State;51// Intermediate result generated by the Parser.52ResultType Value;53};5455template <typename T> using ExpectedProgress = llvm::Expected<ParseProgress<T>>;56template <typename T> using ParseFunction = ExpectedProgress<T> (*)(ParseState);5758class ParseError : public llvm::ErrorInfo<ParseError> {59public:60// Required field for all ErrorInfo derivatives.61static char ID;6263ParseError(size_t Pos, std::string ErrorMsg, std::string InputExcerpt)64: Pos(Pos), ErrorMsg(std::move(ErrorMsg)),65Excerpt(std::move(InputExcerpt)) {}6667void log(llvm::raw_ostream &OS) const override {68OS << "parse error at position (" << Pos << "): " << ErrorMsg69<< ": " + Excerpt;70}7172std::error_code convertToErrorCode() const override {73return llvm::inconvertibleErrorCode();74}7576// Position of the error in the input string.77size_t Pos;78std::string ErrorMsg;79// Excerpt of the input starting at the error position.80std::string Excerpt;81};8283char ParseError::ID;84} // namespace8586static const llvm::StringMap<RangeSelectorOp<std::string>> &87getUnaryStringSelectors() {88static const llvm::StringMap<RangeSelectorOp<std::string>> M = {89{"name", name},90{"node", node},91{"statement", statement},92{"statements", statements},93{"member", member},94{"callArgs", callArgs},95{"elseBranch", elseBranch},96{"initListElements", initListElements}};97return M;98}99100static const llvm::StringMap<RangeSelectorOp<RangeSelector>> &101getUnaryRangeSelectors() {102static const llvm::StringMap<RangeSelectorOp<RangeSelector>> M = {103{"before", before}, {"after", after}, {"expansion", expansion}};104return M;105}106107static const llvm::StringMap<RangeSelectorOp<std::string, std::string>> &108getBinaryStringSelectors() {109static const llvm::StringMap<RangeSelectorOp<std::string, std::string>> M = {110{"encloseNodes", encloseNodes}};111return M;112}113114static const llvm::StringMap<RangeSelectorOp<RangeSelector, RangeSelector>> &115getBinaryRangeSelectors() {116static const llvm::StringMap<RangeSelectorOp<RangeSelector, RangeSelector>>117M = {{"enclose", enclose}, {"between", between}};118return M;119}120121template <typename Element>122std::optional<Element> findOptional(const llvm::StringMap<Element> &Map,123llvm::StringRef Key) {124auto it = Map.find(Key);125if (it == Map.end())126return std::nullopt;127return it->second;128}129130template <typename ResultType>131ParseProgress<ResultType> makeParseProgress(ParseState State,132ResultType Result) {133return ParseProgress<ResultType>{State, std::move(Result)};134}135136static llvm::Error makeParseError(const ParseState &S, std::string ErrorMsg) {137size_t Pos = S.OriginalInput.size() - S.Input.size();138return llvm::make_error<ParseError>(Pos, std::move(ErrorMsg),139S.OriginalInput.substr(Pos, 20).str());140}141142// Returns a new ParseState that advances \c S by \c N characters.143static ParseState advance(ParseState S, size_t N) {144S.Input = S.Input.drop_front(N);145return S;146}147148static StringRef consumeWhitespace(StringRef S) {149return S.drop_while([](char c) { return isASCII(c) && isWhitespace(c); });150}151152// Parses a single expected character \c c from \c State, skipping preceding153// whitespace. Error if the expected character isn't found.154static ExpectedProgress<std::nullopt_t> parseChar(char c, ParseState State) {155State.Input = consumeWhitespace(State.Input);156if (State.Input.empty() || State.Input.front() != c)157return makeParseError(State,158("expected char not found: " + llvm::Twine(c)).str());159return makeParseProgress(advance(State, 1), std::nullopt);160}161162// Parses an identitifer "token" -- handles preceding whitespace.163static ExpectedProgress<std::string> parseId(ParseState State) {164State.Input = consumeWhitespace(State.Input);165auto Id = State.Input.take_while(166[](char c) { return isASCII(c) && isAsciiIdentifierContinue(c); });167if (Id.empty())168return makeParseError(State, "failed to parse name");169return makeParseProgress(advance(State, Id.size()), Id.str());170}171172// For consistency with the AST matcher parser and C++ code, node ids are173// written as strings. However, we do not support escaping in the string.174static ExpectedProgress<std::string> parseStringId(ParseState State) {175State.Input = consumeWhitespace(State.Input);176if (State.Input.empty())177return makeParseError(State, "unexpected end of input");178if (!State.Input.consume_front("\""))179return makeParseError(180State,181"expecting string, but encountered other character or end of input");182183StringRef Id = State.Input.take_until([](char c) { return c == '"'; });184if (State.Input.size() == Id.size())185return makeParseError(State, "unterminated string");186// Advance past the trailing quote as well.187return makeParseProgress(advance(State, Id.size() + 1), Id.str());188}189190// Parses a single element surrounded by parens. `Op` is applied to the parsed191// result to create the result of this function call.192template <typename T>193ExpectedProgress<RangeSelector> parseSingle(ParseFunction<T> ParseElement,194RangeSelectorOp<T> Op,195ParseState State) {196auto P = parseChar('(', State);197if (!P)198return P.takeError();199200auto E = ParseElement(P->State);201if (!E)202return E.takeError();203204P = parseChar(')', E->State);205if (!P)206return P.takeError();207208return makeParseProgress(P->State, Op(std::move(E->Value)));209}210211// Parses a pair of elements surrounded by parens and separated by comma. `Op`212// is applied to the parsed results to create the result of this function call.213template <typename T>214ExpectedProgress<RangeSelector> parsePair(ParseFunction<T> ParseElement,215RangeSelectorOp<T, T> Op,216ParseState State) {217auto P = parseChar('(', State);218if (!P)219return P.takeError();220221auto Left = ParseElement(P->State);222if (!Left)223return Left.takeError();224225P = parseChar(',', Left->State);226if (!P)227return P.takeError();228229auto Right = ParseElement(P->State);230if (!Right)231return Right.takeError();232233P = parseChar(')', Right->State);234if (!P)235return P.takeError();236237return makeParseProgress(P->State,238Op(std::move(Left->Value), std::move(Right->Value)));239}240241// Parses input for a stencil operator(single arg ops like AsValue, MemberOp or242// Id operator). Returns StencilType representing the operator on success and243// error if it fails to parse input for an operator.244static ExpectedProgress<RangeSelector>245parseRangeSelectorImpl(ParseState State) {246auto Id = parseId(State);247if (!Id)248return Id.takeError();249250std::string OpName = std::move(Id->Value);251if (auto Op = findOptional(getUnaryStringSelectors(), OpName))252return parseSingle(parseStringId, *Op, Id->State);253254if (auto Op = findOptional(getUnaryRangeSelectors(), OpName))255return parseSingle(parseRangeSelectorImpl, *Op, Id->State);256257if (auto Op = findOptional(getBinaryStringSelectors(), OpName))258return parsePair(parseStringId, *Op, Id->State);259260if (auto Op = findOptional(getBinaryRangeSelectors(), OpName))261return parsePair(parseRangeSelectorImpl, *Op, Id->State);262263return makeParseError(State, "unknown selector name: " + OpName);264}265266Expected<RangeSelector> transformer::parseRangeSelector(llvm::StringRef Input) {267ParseState State = {Input, Input};268ExpectedProgress<RangeSelector> Result = parseRangeSelectorImpl(State);269if (!Result)270return Result.takeError();271State = Result->State;272// Discard any potentially trailing whitespace.273State.Input = consumeWhitespace(State.Input);274if (State.Input.empty())275return Result->Value;276return makeParseError(State, "unexpected input after selector");277}278279280