text: //===--- Stencil.h - Stencil class ------------------------------*- C++ -*-===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  ///
  /// \file
  /// This file defines the *Stencil* abstraction: a code-generating object,
  /// parameterized by named references to (bound) AST nodes.  Given a match
  /// result, a stencil can be evaluated to a string of source code.
  ///
  /// A stencil is similar in spirit to a format string: it is composed of a
  /// series of raw text strings, references to nodes (the parameters) and helper
  /// code-generation operations.
  ///
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
  #define LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
  
  #include "clang/AST/ASTContext.h"
  #include "clang/AST/ASTTypeTraits.h"
  #include "clang/ASTMatchers/ASTMatchFinder.h"
  #include "clang/Tooling/Transformer/MatchConsumer.h"
  #include "clang/Tooling/Transformer/RangeSelector.h"
  #include "llvm/ADT/StringRef.h"
  #include "llvm/Support/Error.h"
  #include <string>
  #include <vector>
  
  namespace clang {
  namespace transformer {
  /// A stencil is represented as a sequence of "parts" that can each individually
  /// generate a code string based on a match result.  The different kinds of
  /// parts include (raw) text, references to bound nodes and assorted operations
  /// on bound nodes.
  ///
  /// Users can create custom Stencil operations by implementing this interface.
  class StencilPartInterface {
  public:
    virtual ~StencilPartInterface() = default;
  
    /// Evaluates this part to a string and appends it to \c Result.  \c Result is
    /// undefined in the case of an error.
    virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
                             std::string *Result) const = 0;
  
    /// Constructs a string representation of the StencilPart. StencilParts
    /// generated by the `selection` and `run` functions do not have a unique
    /// string representation.
    virtual std::string toString() const = 0;
  
  protected:
    StencilPartInterface() = default;
  
    // Since this is an abstract class, copying/assigning only make sense for
    // derived classes implementing `clone()`.
    StencilPartInterface(const StencilPartInterface &) = default;
    StencilPartInterface &operator=(const StencilPartInterface &) = default;
  };
  
  /// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result
  /// in a copy of the underlying pointee object.
  class StencilPart {
  public:
    explicit StencilPart(std::shared_ptr<StencilPartInterface> Impl)
        : Impl(std::move(Impl)) {}
  
    /// See `StencilPartInterface::eval()`.
    llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
                     std::string *Result) const {
      return Impl->eval(Match, Result);
    }
  
    std::string toString() const {
      if (Impl == nullptr)
        return "";
      return Impl->toString();
    }
  
  private:
    std::shared_ptr<StencilPartInterface> Impl;
  };
  
  /// A sequence of code fragments, references to parameters and code-generation
  /// operations that together can be evaluated to (a fragment of) source code,
  /// given a match result.
  class Stencil {
  public:
    Stencil() = default;
  
    /// Composes a stencil from a series of parts.
    template <typename... Ts> static Stencil cat(Ts &&... Parts) {
      Stencil S;
      S.Parts = {wrap(std::forward<Ts>(Parts))...};
      return S;
    }
  
    /// Appends data from a \p OtherStencil to this stencil.
    void append(Stencil OtherStencil);
  
    // Evaluates the stencil given a match result. Requires that the nodes in the
    // result includes any ids referenced in the stencil. References to missing
    // nodes will result in an invalid_argument error.
    llvm::Expected<std::string>
    eval(const ast_matchers::MatchFinder::MatchResult &Match) const;
  
    // Allow Stencils to operate as std::function, for compatibility with
    // Transformer's TextGenerator.
    llvm::Expected<std::string>
    operator()(const ast_matchers::MatchFinder::MatchResult &Result) const {
      return eval(Result);
    }
  
    /// Constructs a string representation of the Stencil. The string is not
    /// guaranteed to be unique.
    std::string toString() const {
      std::vector<std::string> PartStrings;
      PartStrings.reserve(Parts.size());
      for (const auto &Part : Parts)
        PartStrings.push_back(Part.toString());
      return llvm::join(PartStrings, ", ");
    }
  
  private:
    static StencilPart wrap(llvm::StringRef Text);
    static StencilPart wrap(RangeSelector Selector);
    static StencilPart wrap(StencilPart Part) { return Part; }
  
    std::vector<StencilPart> Parts;
  };
  
  //
  // Functions for conveniently building stencils.
  //
  
  /// Convenience wrapper for Stencil::cat that can be imported with a using decl.
  template <typename... Ts> Stencil cat(Ts &&... Parts) {
    return Stencil::cat(std::forward<Ts>(Parts)...);
  }
  
  /// \returns exactly the text provided.
  StencilPart text(llvm::StringRef Text);
  
  /// \returns the source corresponding to the selected range.
  StencilPart selection(RangeSelector Selector);
  
  /// Generates the source of the expression bound to \p Id, wrapping it in
  /// parentheses if it may parse differently depending on context. For example, a
  /// binary operation is always wrapped, while a variable reference is never
  /// wrapped.
  StencilPart expression(llvm::StringRef Id);
  
  /// Constructs an idiomatic dereferencing of the expression bound to \p ExprId.
  /// \p ExprId is wrapped in parentheses, if needed.
  StencilPart deref(llvm::StringRef ExprId);
  
  /// Constructs an expression that idiomatically takes the address of the
  /// expression bound to \p ExprId. \p ExprId is wrapped in parentheses, if
  /// needed.
  StencilPart addressOf(llvm::StringRef ExprId);
  
  /// Constructs a `MemberExpr` that accesses the named member (\p Member) of the
  /// object bound to \p BaseId. The access is constructed idiomatically: if \p
  /// BaseId is bound to `e` and \p Member identifies member `m`, then returns
  /// `e->m`, when e is a pointer, `e2->m` when e = `*e2` and `e.m` otherwise.
  /// Additionally, `e` is wrapped in parentheses, if needed.
  StencilPart access(llvm::StringRef BaseId, StencilPart Member);
  inline StencilPart access(llvm::StringRef BaseId, llvm::StringRef Member) {
    return access(BaseId, text(Member));
  }
  
  /// Chooses between the two stencil parts, based on whether \p ID is bound in
  /// the match.
  StencilPart ifBound(llvm::StringRef Id, StencilPart TruePart,
                      StencilPart FalsePart);
  
  /// Chooses between the two strings, based on whether \p ID is bound in the
  /// match.
  inline StencilPart ifBound(llvm::StringRef Id, llvm::StringRef TrueText,
                             llvm::StringRef FalseText) {
    return ifBound(Id, text(TrueText), text(FalseText));
  }
  
  /// Wraps a MatchConsumer in a StencilPart, so that it can be used in a Stencil.
  /// This supports user-defined extensions to the Stencil language.
  StencilPart run(MatchConsumer<std::string> C);
  
  /// For debug use only; semantics are not guaranteed.
  ///
  /// \returns the string resulting from calling the node's print() method.
  StencilPart dPrint(llvm::StringRef Id);
  } // namespace transformer
  
  namespace tooling {
  // DEPRECATED: These are temporary aliases supporting client migration to the
  // `transformer` namespace.
  using Stencil = transformer::Stencil;
  using StencilPart = transformer::StencilPart;
  namespace stencil {
  using transformer::access;
  using transformer::addressOf;
  using transformer::cat;
  using transformer::deref;
  using transformer::dPrint;
  using transformer::expression;
  using transformer::ifBound;
  using transformer::run;
  using transformer::selection;
  using transformer::text;
  /// \returns the source corresponding to the identified node.
  /// FIXME: Deprecated. Write `selection(node(Id))` instead.
  inline transformer::StencilPart node(llvm::StringRef Id) {
    return selection(tooling::node(Id));
  }
  } // namespace stencil
  } // namespace tooling
  } // namespace clang
  #endif // LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
  