2020-12-01 18:04:17 +00:00
|
|
|
// Copyright 2020 The Tint Authors.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2021-01-21 16:20:40 +00:00
|
|
|
#ifndef SRC_CLONE_CONTEXT_H_
|
|
|
|
#define SRC_CLONE_CONTEXT_H_
|
2020-12-01 18:04:17 +00:00
|
|
|
|
2021-03-31 21:00:26 +00:00
|
|
|
#include <algorithm>
|
2020-12-03 18:10:39 +00:00
|
|
|
#include <functional>
|
2020-12-01 18:04:17 +00:00
|
|
|
#include <unordered_map>
|
2021-05-18 14:26:17 +00:00
|
|
|
#include <unordered_set>
|
2021-03-04 10:42:55 +00:00
|
|
|
#include <utility>
|
2020-12-01 18:04:17 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2020-12-03 18:10:39 +00:00
|
|
|
#include "src/castable.h"
|
2021-02-17 20:13:34 +00:00
|
|
|
#include "src/debug.h"
|
2020-12-15 12:32:18 +00:00
|
|
|
#include "src/symbol.h"
|
2021-01-21 16:20:40 +00:00
|
|
|
#include "src/traits.h"
|
2020-12-01 18:04:17 +00:00
|
|
|
|
|
|
|
namespace tint {
|
|
|
|
|
2021-01-21 16:20:40 +00:00
|
|
|
// Forward declarations
|
2021-02-17 13:17:39 +00:00
|
|
|
class CloneContext;
|
2021-01-26 16:57:10 +00:00
|
|
|
class Program;
|
2021-01-26 16:57:10 +00:00
|
|
|
class ProgramBuilder;
|
|
|
|
namespace ast {
|
|
|
|
class FunctionList;
|
2021-04-19 16:50:23 +00:00
|
|
|
class Node;
|
2021-01-26 16:57:10 +00:00
|
|
|
} // namespace ast
|
2020-12-01 18:04:17 +00:00
|
|
|
|
2021-04-19 16:50:23 +00:00
|
|
|
ProgramID ProgramIDOf(const Program*);
|
|
|
|
ProgramID ProgramIDOf(const ast::Node*);
|
|
|
|
|
2021-02-17 13:17:39 +00:00
|
|
|
/// Cloneable is the base class for all objects that can be cloned
|
|
|
|
class Cloneable : public Castable<Cloneable> {
|
|
|
|
public:
|
|
|
|
/// Performs a deep clone of this object using the CloneContext `ctx`.
|
|
|
|
/// @param ctx the clone context
|
|
|
|
/// @return the newly cloned object
|
|
|
|
virtual Cloneable* Clone(CloneContext* ctx) const = 0;
|
|
|
|
};
|
|
|
|
|
2021-04-19 16:50:23 +00:00
|
|
|
/// @returns an invalid ProgramID
|
|
|
|
inline ProgramID ProgramIDOf(const Cloneable*) {
|
|
|
|
return ProgramID();
|
|
|
|
}
|
|
|
|
|
2021-05-19 13:25:08 +00:00
|
|
|
/// CloneContext holds the state used while cloning AST nodes.
|
2020-12-01 18:04:17 +00:00
|
|
|
class CloneContext {
|
2021-03-04 10:42:55 +00:00
|
|
|
/// ParamTypeIsPtrOf<F, T>::value is true iff the first parameter of
|
|
|
|
/// F is a pointer of (or derives from) type T.
|
|
|
|
template <typename F, typename T>
|
|
|
|
using ParamTypeIsPtrOf = traits::IsTypeOrDerived<
|
|
|
|
typename std::remove_pointer<traits::ParamTypeT<F, 0>>::type,
|
|
|
|
T>;
|
|
|
|
|
2020-12-01 18:04:17 +00:00
|
|
|
public:
|
2021-03-04 10:42:55 +00:00
|
|
|
/// SymbolTransform is a function that takes a symbol and returns a new
|
|
|
|
/// symbol.
|
|
|
|
using SymbolTransform = std::function<Symbol(Symbol)>;
|
|
|
|
|
2021-05-04 18:06:31 +00:00
|
|
|
/// Constructor for cloning objects from `from` into `to`.
|
2021-01-26 16:57:10 +00:00
|
|
|
/// @param to the target ProgramBuilder to clone into
|
|
|
|
/// @param from the source Program to clone from
|
2021-04-16 10:29:54 +00:00
|
|
|
/// @param auto_clone_symbols clone all symbols in `from` before returning
|
|
|
|
CloneContext(ProgramBuilder* to,
|
|
|
|
Program const* from,
|
|
|
|
bool auto_clone_symbols = true);
|
2020-12-03 18:10:39 +00:00
|
|
|
|
2021-05-04 18:06:31 +00:00
|
|
|
/// Constructor for cloning objects from and to the ProgramBuilder `builder`.
|
|
|
|
/// @param builder the ProgramBuilder
|
|
|
|
explicit CloneContext(ProgramBuilder* builder);
|
|
|
|
|
2020-12-01 18:04:17 +00:00
|
|
|
/// Destructor
|
|
|
|
~CloneContext();
|
|
|
|
|
2021-04-19 22:51:23 +00:00
|
|
|
/// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is
|
2021-01-26 16:57:10 +00:00
|
|
|
/// not null. If `a` is null, then Clone() returns null. If `a` has been
|
|
|
|
/// cloned already by this CloneContext then the same cloned pointer is
|
|
|
|
/// returned.
|
2020-12-03 18:10:39 +00:00
|
|
|
///
|
|
|
|
/// Clone() may use a function registered with ReplaceAll() to create a
|
|
|
|
/// transformed version of the object. See ReplaceAll() for more information.
|
|
|
|
///
|
2021-05-04 18:06:31 +00:00
|
|
|
/// If the CloneContext is cloning from a Program to a ProgramBuilder, then
|
|
|
|
/// the Node or sem::Type `a` must be owned by the Program #src.
|
2020-12-15 12:32:18 +00:00
|
|
|
///
|
2021-04-19 22:51:23 +00:00
|
|
|
/// @param a the `Node` or `sem::Type` to clone
|
2020-12-01 18:04:17 +00:00
|
|
|
/// @return the cloned node
|
|
|
|
template <typename T>
|
|
|
|
T* Clone(T* a) {
|
2020-12-03 18:10:39 +00:00
|
|
|
// If the input is nullptr, there's nothing to clone - just return nullptr.
|
2020-12-01 18:04:17 +00:00
|
|
|
if (a == nullptr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-05-04 18:06:31 +00:00
|
|
|
if (src) {
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
|
|
|
|
}
|
2021-04-19 16:50:23 +00:00
|
|
|
|
2021-05-19 13:25:08 +00:00
|
|
|
// Was Replace() called for this object?
|
|
|
|
auto it = replacements_.find(a);
|
|
|
|
if (it != replacements_.end()) {
|
2021-04-16 20:30:21 +00:00
|
|
|
return CheckedCast<T>(it->second);
|
2020-12-01 18:04:17 +00:00
|
|
|
}
|
2020-12-03 18:10:39 +00:00
|
|
|
|
2021-04-16 20:30:21 +00:00
|
|
|
Cloneable* cloned = nullptr;
|
|
|
|
|
|
|
|
// Attempt to clone using the registered replacer functions.
|
|
|
|
auto& typeinfo = a->TypeInfo();
|
|
|
|
for (auto& transform : transforms_) {
|
|
|
|
if (!typeinfo.Is(*transform.typeinfo)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
cloned = transform.function(a);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cloned) {
|
|
|
|
// No transform for this type, or the transform returned nullptr.
|
|
|
|
// Clone with T::Clone().
|
|
|
|
cloned = a->Clone(this);
|
|
|
|
}
|
|
|
|
|
2021-04-19 16:50:23 +00:00
|
|
|
auto* out = CheckedCast<T>(cloned);
|
|
|
|
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, out);
|
|
|
|
|
|
|
|
return out;
|
2021-02-16 22:27:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 22:51:23 +00:00
|
|
|
/// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is
|
2021-02-16 22:27:11 +00:00
|
|
|
/// not null. If `a` is null, then Clone() returns null. If `a` has been
|
|
|
|
/// cloned already by this CloneContext then the same cloned pointer is
|
|
|
|
/// returned.
|
|
|
|
///
|
|
|
|
/// Unlike Clone(), this method does not invoke or use any transformations
|
|
|
|
/// registered by ReplaceAll().
|
|
|
|
///
|
2021-05-04 18:06:31 +00:00
|
|
|
/// If the CloneContext is cloning from a Program to a ProgramBuilder, then
|
|
|
|
/// the Node or sem::Type `a` must be owned by the Program #src.
|
2021-02-16 22:27:11 +00:00
|
|
|
///
|
2021-04-19 22:51:23 +00:00
|
|
|
/// @param a the `Node` or `sem::Type` to clone
|
2021-02-16 22:27:11 +00:00
|
|
|
/// @return the cloned node
|
|
|
|
template <typename T>
|
|
|
|
T* CloneWithoutTransform(T* a) {
|
|
|
|
// If the input is nullptr, there's nothing to clone - just return nullptr.
|
|
|
|
if (a == nullptr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-05-04 18:06:31 +00:00
|
|
|
if (src) {
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, a);
|
|
|
|
}
|
2021-04-19 16:50:23 +00:00
|
|
|
|
2021-02-16 22:27:11 +00:00
|
|
|
// Have we seen this object before? If so, return the previously cloned
|
|
|
|
// version instead of making yet another copy.
|
2021-05-19 13:25:08 +00:00
|
|
|
auto it = replacements_.find(a);
|
|
|
|
if (it != replacements_.end()) {
|
2021-04-08 14:47:37 +00:00
|
|
|
return CheckedCast<T>(it->second);
|
2021-02-16 22:27:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// First time clone and no replacer transforms matched.
|
|
|
|
// Clone with T::Clone().
|
|
|
|
auto* c = a->Clone(this);
|
2021-05-19 13:25:08 +00:00
|
|
|
replacements_.emplace(a, c);
|
2021-04-08 14:47:37 +00:00
|
|
|
return CheckedCast<T>(c);
|
2020-12-01 18:04:17 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 20:07:57 +00:00
|
|
|
/// Clones the Source `s` into #dst
|
2020-12-01 18:04:17 +00:00
|
|
|
/// TODO(bclayton) - Currently this 'clone' is a shallow copy. If/when
|
2021-01-26 16:57:10 +00:00
|
|
|
/// `Source.File`s are owned by the Program this should make a copy of the
|
2020-12-01 18:04:17 +00:00
|
|
|
/// file.
|
|
|
|
/// @param s the `Source` to clone
|
|
|
|
/// @return the cloned source
|
2020-12-15 12:32:18 +00:00
|
|
|
Source Clone(const Source& s) const { return s; }
|
|
|
|
|
2021-04-13 20:07:57 +00:00
|
|
|
/// Clones the Symbol `s` into #dst
|
2020-12-15 12:32:18 +00:00
|
|
|
///
|
2021-01-26 16:57:10 +00:00
|
|
|
/// The Symbol `s` must be owned by the Program #src.
|
2020-12-15 12:32:18 +00:00
|
|
|
///
|
|
|
|
/// @param s the Symbol to clone
|
|
|
|
/// @return the cloned source
|
2021-04-07 11:16:01 +00:00
|
|
|
Symbol Clone(Symbol s);
|
2020-12-01 18:04:17 +00:00
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
/// Clones each of the elements of the vector `v` into the ProgramBuilder
|
|
|
|
/// #dst.
|
2020-12-15 12:32:18 +00:00
|
|
|
///
|
2021-01-26 16:57:10 +00:00
|
|
|
/// All the elements of the vector `v` must be owned by the Program #src.
|
2020-12-15 12:32:18 +00:00
|
|
|
///
|
2020-12-01 18:04:17 +00:00
|
|
|
/// @param v the vector to clone
|
|
|
|
/// @return the cloned vector
|
|
|
|
template <typename T>
|
|
|
|
std::vector<T> Clone(const std::vector<T>& v) {
|
|
|
|
std::vector<T> out;
|
|
|
|
out.reserve(v.size());
|
|
|
|
for (auto& el : v) {
|
|
|
|
out.emplace_back(Clone(el));
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2021-06-16 09:19:36 +00:00
|
|
|
/// Clones each of the elements of the vector `v` using the ProgramBuilder
|
2021-02-16 23:09:31 +00:00
|
|
|
/// #dst, inserting any additional elements into the list that were registered
|
|
|
|
/// with calls to InsertBefore().
|
|
|
|
///
|
|
|
|
/// All the elements of the vector `v` must be owned by the Program #src.
|
|
|
|
///
|
|
|
|
/// @param v the vector to clone
|
|
|
|
/// @return the cloned vector
|
|
|
|
template <typename T>
|
|
|
|
std::vector<T*> Clone(const std::vector<T*>& v) {
|
|
|
|
std::vector<T*> out;
|
2021-06-16 09:19:36 +00:00
|
|
|
Clone(out, v);
|
|
|
|
return out;
|
|
|
|
}
|
2021-03-31 21:00:26 +00:00
|
|
|
|
2021-06-16 09:19:36 +00:00
|
|
|
/// Clones each of the elements of the vector `from` into the vector `to`,
|
|
|
|
/// inserting any additional elements into the list that were registered with
|
|
|
|
/// calls to InsertBefore().
|
|
|
|
///
|
|
|
|
/// All the elements of the vector `from` must be owned by the Program #src.
|
|
|
|
///
|
|
|
|
/// @param from the vector to clone
|
|
|
|
/// @param to the cloned result
|
|
|
|
template <typename T>
|
|
|
|
void Clone(std::vector<T*>& to, const std::vector<T*>& from) {
|
|
|
|
to.reserve(from.size());
|
|
|
|
|
|
|
|
auto list_transform_it = list_transforms_.find(&from);
|
2021-03-31 21:00:26 +00:00
|
|
|
if (list_transform_it != list_transforms_.end()) {
|
|
|
|
const auto& transforms = list_transform_it->second;
|
2021-05-26 11:31:32 +00:00
|
|
|
for (auto* o : transforms.insert_front_) {
|
2021-06-16 09:19:36 +00:00
|
|
|
to.emplace_back(CheckedCast<T>(o));
|
2021-05-26 11:31:32 +00:00
|
|
|
}
|
2021-06-16 09:19:36 +00:00
|
|
|
for (auto& el : from) {
|
2021-03-31 21:00:26 +00:00
|
|
|
auto insert_before_it = transforms.insert_before_.find(el);
|
|
|
|
if (insert_before_it != transforms.insert_before_.end()) {
|
|
|
|
for (auto insert : insert_before_it->second) {
|
2021-06-16 09:19:36 +00:00
|
|
|
to.emplace_back(CheckedCast<T>(insert));
|
2021-03-31 21:00:26 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-18 21:28:58 +00:00
|
|
|
if (transforms.remove_.count(el) == 0) {
|
2021-06-16 09:19:36 +00:00
|
|
|
to.emplace_back(Clone(el));
|
2021-05-18 21:28:58 +00:00
|
|
|
}
|
2021-03-31 21:00:26 +00:00
|
|
|
auto insert_after_it = transforms.insert_after_.find(el);
|
|
|
|
if (insert_after_it != transforms.insert_after_.end()) {
|
|
|
|
for (auto insert : insert_after_it->second) {
|
2021-06-16 09:19:36 +00:00
|
|
|
to.emplace_back(CheckedCast<T>(insert));
|
2021-03-31 21:00:26 +00:00
|
|
|
}
|
2021-02-16 23:09:31 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-26 15:12:12 +00:00
|
|
|
for (auto* o : transforms.insert_back_) {
|
2021-06-16 09:19:36 +00:00
|
|
|
to.emplace_back(CheckedCast<T>(o));
|
2021-05-26 15:12:12 +00:00
|
|
|
}
|
2021-03-31 21:00:26 +00:00
|
|
|
} else {
|
2021-06-16 09:19:36 +00:00
|
|
|
for (auto& el : from) {
|
|
|
|
to.emplace_back(Clone(el));
|
2021-03-31 21:00:26 +00:00
|
|
|
}
|
2021-02-16 23:09:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
/// Clones each of the elements of the vector `v` into the ProgramBuilder
|
|
|
|
/// #dst.
|
2021-01-26 16:57:10 +00:00
|
|
|
///
|
|
|
|
/// All the elements of the vector `v` must be owned by the Program #src.
|
|
|
|
///
|
|
|
|
/// @param v the vector to clone
|
|
|
|
/// @return the cloned vector
|
|
|
|
ast::FunctionList Clone(const ast::FunctionList& v);
|
|
|
|
|
2020-12-03 18:10:39 +00:00
|
|
|
/// ReplaceAll() registers `replacer` to be called whenever the Clone() method
|
2021-02-26 19:33:56 +00:00
|
|
|
/// is called with a Cloneable type that matches (or derives from) the type of
|
|
|
|
/// the single parameter of `replacer`.
|
|
|
|
/// The returned Cloneable of `replacer` will be used as the replacement for
|
|
|
|
/// all references to the object that's being cloned. This returned Cloneable
|
|
|
|
/// must be owned by the Program #dst.
|
2020-12-03 18:10:39 +00:00
|
|
|
///
|
2021-02-26 19:33:56 +00:00
|
|
|
/// `replacer` must be function-like with the signature: `T* (T*)`
|
2021-02-17 13:17:39 +00:00
|
|
|
/// where `T` is a type deriving from Cloneable.
|
2020-12-03 18:10:39 +00:00
|
|
|
///
|
2021-03-04 10:42:55 +00:00
|
|
|
/// If `replacer` returns a nullptr then Clone() will call `T::Clone()` to
|
|
|
|
/// clone the object.
|
2020-12-03 18:10:39 +00:00
|
|
|
///
|
|
|
|
/// Example:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// // Replace all ast::UintLiterals with the number 42
|
2021-02-26 19:33:56 +00:00
|
|
|
/// CloneCtx ctx(&out, in);
|
|
|
|
/// ctx.ReplaceAll([&] (ast::UintLiteral* l) {
|
2021-01-26 16:57:10 +00:00
|
|
|
/// return ctx->dst->create<ast::UintLiteral>(
|
|
|
|
/// ctx->Clone(l->source()),
|
|
|
|
/// ctx->Clone(l->type()),
|
|
|
|
/// 42);
|
2021-02-26 19:33:56 +00:00
|
|
|
/// });
|
|
|
|
/// ctx.Clone();
|
2020-12-03 18:10:39 +00:00
|
|
|
/// ```
|
|
|
|
///
|
2021-03-04 10:42:55 +00:00
|
|
|
/// @warning a single handler can only be registered for any given type.
|
|
|
|
/// Attempting to register two handlers for the same type will result in an
|
|
|
|
/// ICE.
|
2021-02-16 22:27:11 +00:00
|
|
|
/// @warning The replacement object must be of the correct type for all
|
|
|
|
/// references of the original object. A type mismatch will result in an
|
|
|
|
/// assertion in debug builds, and undefined behavior in release builds.
|
2020-12-03 18:10:39 +00:00
|
|
|
/// @param replacer a function or function-like object with the signature
|
2021-02-26 19:33:56 +00:00
|
|
|
/// `T* (T*)`, where `T` derives from Cloneable
|
2020-12-15 12:32:18 +00:00
|
|
|
/// @returns this CloneContext so calls can be chained
|
2020-12-03 18:10:39 +00:00
|
|
|
template <typename F>
|
2021-03-04 10:42:55 +00:00
|
|
|
traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>::value, CloneContext>&
|
|
|
|
ReplaceAll(F&& replacer) {
|
2021-02-26 19:33:56 +00:00
|
|
|
using TPtr = traits::ParamTypeT<F, 0>;
|
2020-12-03 18:10:39 +00:00
|
|
|
using T = typename std::remove_pointer<TPtr>::type;
|
2021-03-04 10:42:55 +00:00
|
|
|
for (auto& transform : transforms_) {
|
|
|
|
if (transform.typeinfo->Is(TypeInfo::Of<T>()) ||
|
|
|
|
TypeInfo::Of<T>().Is(*transform.typeinfo)) {
|
|
|
|
TINT_ICE(Diagnostics())
|
|
|
|
<< "ReplaceAll() called with a handler for type "
|
|
|
|
<< TypeInfo::Of<T>().name
|
|
|
|
<< " that is already handled by a handler for type "
|
|
|
|
<< transform.typeinfo->name;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CloneableTransform transform;
|
|
|
|
transform.typeinfo = &TypeInfo::Of<T>();
|
|
|
|
transform.function = [=](Cloneable* in) { return replacer(in->As<T>()); };
|
|
|
|
transforms_.emplace_back(std::move(transform));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ReplaceAll() registers `replacer` to be called whenever the Clone() method
|
|
|
|
/// is called with a Symbol.
|
|
|
|
/// The returned symbol of `replacer` will be used as the replacement for
|
|
|
|
/// all references to the symbol that's being cloned. This returned Symbol
|
|
|
|
/// must be owned by the Program #dst.
|
|
|
|
/// @param replacer a function the signature `Symbol(Symbol)`.
|
|
|
|
/// @warning a SymbolTransform can only be registered once. Attempting to
|
|
|
|
/// register a SymbolTransform more than once will result in an ICE.
|
|
|
|
/// @returns this CloneContext so calls can be chained
|
|
|
|
CloneContext& ReplaceAll(const SymbolTransform& replacer) {
|
|
|
|
if (symbol_transform_) {
|
|
|
|
TINT_ICE(Diagnostics()) << "ReplaceAll(const SymbolTransform&) called "
|
|
|
|
"multiple times on the same CloneContext";
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
symbol_transform_ = replacer;
|
2020-12-15 12:32:18 +00:00
|
|
|
return *this;
|
2020-12-03 18:10:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
/// Replace replaces all occurrences of `what` in #src with `with` in #dst
|
|
|
|
/// when calling Clone().
|
|
|
|
/// @param what a pointer to the object in #src that will be replaced with
|
|
|
|
/// `with`
|
2021-02-16 22:27:11 +00:00
|
|
|
/// @param with a pointer to the replacement object owned by #dst that will be
|
|
|
|
/// used as a replacement for `what`
|
|
|
|
/// @warning The replacement object must be of the correct type for all
|
|
|
|
/// references of the original object. A type mismatch will result in an
|
|
|
|
/// assertion in debug builds, and undefined behavior in release builds.
|
2021-01-26 16:57:10 +00:00
|
|
|
/// @returns this CloneContext so calls can be chained
|
2021-02-16 22:27:11 +00:00
|
|
|
template <typename WHAT, typename WITH>
|
|
|
|
CloneContext& Replace(WHAT* what, WITH* with) {
|
2021-05-18 14:26:17 +00:00
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, what);
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, with);
|
2021-05-19 13:25:08 +00:00
|
|
|
replacements_[what] = with;
|
2021-01-26 16:57:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-05-18 14:26:17 +00:00
|
|
|
/// Removes `object` from the cloned copy of `vector`.
|
|
|
|
/// @param vector the vector in #src
|
|
|
|
/// @param object a pointer to the object in #src that will be omitted from
|
|
|
|
/// the cloned vector.
|
|
|
|
/// @returns this CloneContext so calls can be chained
|
|
|
|
template <typename T, typename OBJECT>
|
|
|
|
CloneContext& Remove(const std::vector<T>& vector, OBJECT* object) {
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, object);
|
|
|
|
if (std::find(vector.begin(), vector.end(), object) == vector.end()) {
|
|
|
|
TINT_ICE(Diagnostics())
|
|
|
|
<< "CloneContext::Remove() vector does not contain object";
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_transforms_[&vector].remove_.emplace(object);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-05-26 11:31:32 +00:00
|
|
|
/// Inserts `object` before any other objects of `vector`, when it is cloned.
|
|
|
|
/// @param vector the vector in #src
|
|
|
|
/// @param object a pointer to the object in #dst that will be inserted at the
|
|
|
|
/// front of the vector
|
|
|
|
/// @returns this CloneContext so calls can be chained
|
|
|
|
template <typename T, typename OBJECT>
|
|
|
|
CloneContext& InsertFront(const std::vector<T>& vector, OBJECT* object) {
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, object);
|
|
|
|
auto& transforms = list_transforms_[&vector];
|
|
|
|
auto& list = transforms.insert_front_;
|
|
|
|
list.emplace_back(object);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-05-26 15:12:12 +00:00
|
|
|
/// Inserts `object` after any other objects of `vector`, when it is cloned.
|
|
|
|
/// @param vector the vector in #src
|
|
|
|
/// @param object a pointer to the object in #dst that will be inserted at the
|
|
|
|
/// end of the vector
|
|
|
|
/// @returns this CloneContext so calls can be chained
|
|
|
|
template <typename T, typename OBJECT>
|
|
|
|
CloneContext& InsertBack(const std::vector<T>& vector, OBJECT* object) {
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, object);
|
|
|
|
auto& transforms = list_transforms_[&vector];
|
|
|
|
auto& list = transforms.insert_back_;
|
|
|
|
list.emplace_back(object);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-03-31 21:00:26 +00:00
|
|
|
/// Inserts `object` before `before` whenever `vector` is cloned.
|
|
|
|
/// @param vector the vector in #src
|
2021-02-16 23:09:31 +00:00
|
|
|
/// @param before a pointer to the object in #src
|
|
|
|
/// @param object a pointer to the object in #dst that will be inserted before
|
|
|
|
/// any occurrence of the clone of `before`
|
|
|
|
/// @returns this CloneContext so calls can be chained
|
2021-03-31 21:00:26 +00:00
|
|
|
template <typename T, typename BEFORE, typename OBJECT>
|
|
|
|
CloneContext& InsertBefore(const std::vector<T>& vector,
|
2021-05-04 18:06:31 +00:00
|
|
|
const BEFORE* before,
|
2021-03-31 21:00:26 +00:00
|
|
|
OBJECT* object) {
|
2021-05-18 14:26:17 +00:00
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, before);
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, object);
|
2021-03-31 21:00:26 +00:00
|
|
|
if (std::find(vector.begin(), vector.end(), before) == vector.end()) {
|
|
|
|
TINT_ICE(Diagnostics())
|
|
|
|
<< "CloneContext::InsertBefore() vector does not contain before";
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& transforms = list_transforms_[&vector];
|
|
|
|
auto& list = transforms.insert_before_[before];
|
|
|
|
list.emplace_back(object);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Inserts `object` after `after` whenever `vector` is cloned.
|
|
|
|
/// @param vector the vector in #src
|
|
|
|
/// @param after a pointer to the object in #src
|
|
|
|
/// @param object a pointer to the object in #dst that will be inserted after
|
|
|
|
/// any occurrence of the clone of `after`
|
|
|
|
/// @returns this CloneContext so calls can be chained
|
|
|
|
template <typename T, typename AFTER, typename OBJECT>
|
|
|
|
CloneContext& InsertAfter(const std::vector<T>& vector,
|
2021-05-04 18:06:31 +00:00
|
|
|
const AFTER* after,
|
2021-03-31 21:00:26 +00:00
|
|
|
OBJECT* object) {
|
2021-05-18 14:26:17 +00:00
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(src, after);
|
|
|
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, object);
|
2021-03-31 21:00:26 +00:00
|
|
|
if (std::find(vector.begin(), vector.end(), after) == vector.end()) {
|
|
|
|
TINT_ICE(Diagnostics())
|
|
|
|
<< "CloneContext::InsertAfter() vector does not contain after";
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& transforms = list_transforms_[&vector];
|
|
|
|
auto& list = transforms.insert_after_[after];
|
2021-02-16 23:09:31 +00:00
|
|
|
list.emplace_back(object);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-02-17 01:01:03 +00:00
|
|
|
/// Clone performs the clone of the Program's AST nodes, types and symbols
|
|
|
|
/// from #src to #dst. Semantic nodes are not cloned, as these will be rebuilt
|
|
|
|
/// when the ProgramBuilder #dst builds its Program.
|
2020-12-15 12:32:18 +00:00
|
|
|
void Clone();
|
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
/// The target ProgramBuilder to clone into.
|
|
|
|
ProgramBuilder* const dst;
|
2020-12-01 18:04:17 +00:00
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
/// The source Program to clone from.
|
2021-01-26 16:57:10 +00:00
|
|
|
Program const* const src;
|
2020-12-15 12:32:18 +00:00
|
|
|
|
2020-12-01 18:04:17 +00:00
|
|
|
private:
|
2021-03-04 10:42:55 +00:00
|
|
|
struct CloneableTransform {
|
|
|
|
/// Constructor
|
|
|
|
CloneableTransform();
|
|
|
|
/// Copy constructor
|
|
|
|
/// @param other the CloneableTransform to copy
|
|
|
|
CloneableTransform(const CloneableTransform& other);
|
|
|
|
/// Destructor
|
|
|
|
~CloneableTransform();
|
|
|
|
|
|
|
|
// TypeInfo of the Cloneable that the transform operates on
|
|
|
|
const TypeInfo* typeinfo;
|
|
|
|
std::function<Cloneable*(Cloneable*)> function;
|
|
|
|
};
|
2020-12-03 18:10:39 +00:00
|
|
|
|
2020-12-15 12:32:18 +00:00
|
|
|
CloneContext(const CloneContext&) = delete;
|
|
|
|
CloneContext& operator=(const CloneContext&) = delete;
|
|
|
|
|
2021-02-16 22:27:11 +00:00
|
|
|
/// Cast `obj` from type `FROM` to type `TO`, returning the cast object.
|
2021-02-17 20:13:34 +00:00
|
|
|
/// Reports an internal compiler error if the cast failed.
|
2021-02-16 22:27:11 +00:00
|
|
|
template <typename TO, typename FROM>
|
|
|
|
TO* CheckedCast(FROM* obj) {
|
2021-04-16 20:30:21 +00:00
|
|
|
if (TO* cast = As<TO>(obj)) {
|
|
|
|
return cast;
|
2021-02-17 20:13:34 +00:00
|
|
|
}
|
2021-05-18 14:26:17 +00:00
|
|
|
TINT_ICE(Diagnostics())
|
|
|
|
<< "Cloned object was not of the expected type\n"
|
|
|
|
<< "got: " << (obj ? obj->TypeInfo().name : "<null>") << "\n"
|
|
|
|
<< "expected: " << TypeInfo::Of<TO>().name;
|
2021-04-16 20:30:21 +00:00
|
|
|
return nullptr;
|
2021-02-16 22:27:11 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 20:13:34 +00:00
|
|
|
/// @returns the diagnostic list of #dst
|
|
|
|
diag::List& Diagnostics() const;
|
|
|
|
|
2021-02-17 13:17:39 +00:00
|
|
|
/// A vector of Cloneable*
|
|
|
|
using CloneableList = std::vector<Cloneable*>;
|
2021-02-16 23:09:31 +00:00
|
|
|
|
2021-03-31 21:00:26 +00:00
|
|
|
// Transformations to be applied to a list (vector)
|
|
|
|
struct ListTransforms {
|
|
|
|
/// Constructor
|
|
|
|
ListTransforms();
|
|
|
|
/// Destructor
|
|
|
|
~ListTransforms();
|
|
|
|
|
2021-05-18 14:26:17 +00:00
|
|
|
/// A map of object in #src to omit when cloned into #dst.
|
|
|
|
std::unordered_set<const Cloneable*> remove_;
|
|
|
|
|
2021-05-26 11:31:32 +00:00
|
|
|
/// A list of objects in #dst to insert before any others when the vector is
|
|
|
|
/// cloned.
|
|
|
|
CloneableList insert_front_;
|
|
|
|
|
2021-05-26 15:12:12 +00:00
|
|
|
/// A list of objects in #dst to insert befor after any others when the
|
|
|
|
/// vector is cloned.
|
|
|
|
CloneableList insert_back_;
|
|
|
|
|
2021-03-31 21:00:26 +00:00
|
|
|
/// A map of object in #src to the list of cloned objects in #dst.
|
|
|
|
/// Clone(const std::vector<T*>& v) will use this to insert the map-value
|
|
|
|
/// list into the target vector before cloning and inserting the map-key.
|
|
|
|
std::unordered_map<const Cloneable*, CloneableList> insert_before_;
|
|
|
|
|
|
|
|
/// A map of object in #src to the list of cloned objects in #dst.
|
|
|
|
/// Clone(const std::vector<T*>& v) will use this to insert the map-value
|
|
|
|
/// list into the target vector after cloning and inserting the map-key.
|
|
|
|
std::unordered_map<const Cloneable*, CloneableList> insert_after_;
|
|
|
|
};
|
|
|
|
|
2021-05-19 13:25:08 +00:00
|
|
|
/// A map of object in #src to their replacement in #dst
|
|
|
|
std::unordered_map<const Cloneable*, Cloneable*> replacements_;
|
2021-02-16 23:09:31 +00:00
|
|
|
|
2021-04-07 11:16:01 +00:00
|
|
|
/// A map of symbol in #src to their cloned equivalent in #dst
|
|
|
|
std::unordered_map<Symbol, Symbol> cloned_symbols_;
|
|
|
|
|
2021-03-04 10:42:55 +00:00
|
|
|
/// Cloneable transform functions registered with ReplaceAll()
|
|
|
|
std::vector<CloneableTransform> transforms_;
|
|
|
|
|
2021-03-31 21:00:26 +00:00
|
|
|
/// Map of std::vector pointer to transforms for that list
|
|
|
|
std::unordered_map<const void*, ListTransforms> list_transforms_;
|
|
|
|
|
2021-03-04 10:42:55 +00:00
|
|
|
/// Symbol transform registered with ReplaceAll()
|
|
|
|
SymbolTransform symbol_transform_;
|
2020-12-01 18:04:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace tint
|
|
|
|
|
2021-01-21 16:20:40 +00:00
|
|
|
#endif // SRC_CLONE_CONTEXT_H_
|