Consistent formatting for Dawn/Tint. This CL updates the clang format files to have a single shared format between Dawn and Tint. The major changes are tabs are 4 spaces, lines are 100 columns and namespaces are not indented. Bug: dawn:1339 Change-Id: I4208742c95643998d9fd14e77a9cc558071ded39 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87603 Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index 249a55c..0b26ede 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h
@@ -113,2685 +113,2535 @@ /// To construct a Program, populate the builder and then `std::move` it to a /// Program. class ProgramBuilder { - /// A helper used to disable overloads if the first type in `TYPES` is a - /// Source. Used to avoid ambiguities in overloads that take a Source as the - /// first parameter and those that perfectly-forward the first argument. - template <typename... TYPES> - using DisableIfSource = traits::EnableIfIsNotType< - traits::Decay<traits::NthTypeOf<0, TYPES..., void>>, - Source>; + /// A helper used to disable overloads if the first type in `TYPES` is a + /// Source. Used to avoid ambiguities in overloads that take a Source as the + /// first parameter and those that perfectly-forward the first argument. + template <typename... TYPES> + using DisableIfSource = + traits::EnableIfIsNotType<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>, Source>; - /// VarOptionals is a helper for accepting a number of optional, extra - /// arguments for Var() and Global(). - struct VarOptionals { - template <typename... ARGS> - explicit VarOptionals(ARGS&&... args) { - Apply(std::forward<ARGS>(args)...); - } - ~VarOptionals(); + /// VarOptionals is a helper for accepting a number of optional, extra + /// arguments for Var() and Global(). + struct VarOptionals { + template <typename... ARGS> + explicit VarOptionals(ARGS&&... args) { + Apply(std::forward<ARGS>(args)...); + } + ~VarOptionals(); - ast::StorageClass storage = ast::StorageClass::kNone; - ast::Access access = ast::Access::kUndefined; - const ast::Expression* constructor = nullptr; - ast::AttributeList attributes = {}; + ast::StorageClass storage = ast::StorageClass::kNone; + ast::Access access = ast::Access::kUndefined; + const ast::Expression* constructor = nullptr; + ast::AttributeList attributes = {}; - private: - void Set(ast::StorageClass sc) { storage = sc; } - void Set(ast::Access ac) { access = ac; } - void Set(const ast::Expression* c) { constructor = c; } - void Set(const ast::AttributeList& l) { attributes = l; } + private: + void Set(ast::StorageClass sc) { storage = sc; } + void Set(ast::Access ac) { access = ac; } + void Set(const ast::Expression* c) { constructor = c; } + void Set(const ast::AttributeList& l) { attributes = l; } - template <typename FIRST, typename... ARGS> - void Apply(FIRST&& first, ARGS&&... args) { - Set(std::forward<FIRST>(first)); - Apply(std::forward<ARGS>(args)...); - } - void Apply() {} - }; + template <typename FIRST, typename... ARGS> + void Apply(FIRST&& first, ARGS&&... args) { + Set(std::forward<FIRST>(first)); + Apply(std::forward<ARGS>(args)...); + } + void Apply() {} + }; - public: - /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node> - using ASTNodeAllocator = utils::BlockAllocator<ast::Node>; + public: + /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node> + using ASTNodeAllocator = utils::BlockAllocator<ast::Node>; - /// SemNodeAllocator is an alias to BlockAllocator<sem::Node> - using SemNodeAllocator = utils::BlockAllocator<sem::Node>; + /// SemNodeAllocator is an alias to BlockAllocator<sem::Node> + using SemNodeAllocator = utils::BlockAllocator<sem::Node>; - /// `i32` is a type alias to `int`. - /// Useful for passing to template methods such as `vec2<i32>()` to imitate - /// WGSL syntax. - /// Note: this is intentionally not aliased to uint32_t as we want integer - /// literals passed to the builder to match WGSL's integer literal types. - using i32 = decltype(1); - /// `u32` is a type alias to `unsigned int`. - /// Useful for passing to template methods such as `vec2<u32>()` to imitate - /// WGSL syntax. - /// Note: this is intentionally not aliased to uint32_t as we want integer - /// literals passed to the builder to match WGSL's integer literal types. - using u32 = decltype(1u); - /// `f32` is a type alias to `float` - /// Useful for passing to template methods such as `vec2<f32>()` to imitate - /// WGSL syntax. - using f32 = float; + /// `i32` is a type alias to `int`. + /// Useful for passing to template methods such as `vec2<i32>()` to imitate + /// WGSL syntax. + /// Note: this is intentionally not aliased to uint32_t as we want integer + /// literals passed to the builder to match WGSL's integer literal types. + using i32 = decltype(1); + /// `u32` is a type alias to `unsigned int`. + /// Useful for passing to template methods such as `vec2<u32>()` to imitate + /// WGSL syntax. + /// Note: this is intentionally not aliased to uint32_t as we want integer + /// literals passed to the builder to match WGSL's integer literal types. + using u32 = decltype(1u); + /// `f32` is a type alias to `float` + /// Useful for passing to template methods such as `vec2<f32>()` to imitate + /// WGSL syntax. + using f32 = float; - /// Constructor - ProgramBuilder(); - - /// Move constructor - /// @param rhs the builder to move - ProgramBuilder(ProgramBuilder&& rhs); - - /// Destructor - virtual ~ProgramBuilder(); - - /// Move assignment operator - /// @param rhs the builder to move - /// @return this builder - ProgramBuilder& operator=(ProgramBuilder&& rhs); - - /// Wrap returns a new ProgramBuilder wrapping the Program `program` without - /// making a deep clone of the Program contents. - /// ProgramBuilder returned by Wrap() is intended to temporarily extend an - /// existing immutable program. - /// As the returned ProgramBuilder wraps `program`, `program` must not be - /// destructed or assigned while using the returned ProgramBuilder. - /// TODO(bclayton) - Evaluate whether there are safer alternatives to this - /// function. See crbug.com/tint/460. - /// @param program the immutable Program to wrap - /// @return the ProgramBuilder that wraps `program` - static ProgramBuilder Wrap(const Program* program); - - /// @returns the unique identifier for this program - ProgramID ID() const { return id_; } - - /// @returns a reference to the program's types - sem::Manager& Types() { - AssertNotMoved(); - return types_; - } - - /// @returns a reference to the program's types - const sem::Manager& Types() const { - AssertNotMoved(); - return types_; - } - - /// @returns a reference to the program's AST nodes storage - ASTNodeAllocator& ASTNodes() { - AssertNotMoved(); - return ast_nodes_; - } - - /// @returns a reference to the program's AST nodes storage - const ASTNodeAllocator& ASTNodes() const { - AssertNotMoved(); - return ast_nodes_; - } - - /// @returns a reference to the program's semantic nodes storage - SemNodeAllocator& SemNodes() { - AssertNotMoved(); - return sem_nodes_; - } - - /// @returns a reference to the program's semantic nodes storage - const SemNodeAllocator& SemNodes() const { - AssertNotMoved(); - return sem_nodes_; - } - - /// @returns a reference to the program's AST root Module - ast::Module& AST() { - AssertNotMoved(); - return *ast_; - } - - /// @returns a reference to the program's AST root Module - const ast::Module& AST() const { - AssertNotMoved(); - return *ast_; - } - - /// @returns a reference to the program's semantic info - sem::Info& Sem() { - AssertNotMoved(); - return sem_; - } - - /// @returns a reference to the program's semantic info - const sem::Info& Sem() const { - AssertNotMoved(); - return sem_; - } - - /// @returns a reference to the program's SymbolTable - SymbolTable& Symbols() { - AssertNotMoved(); - return symbols_; - } - - /// @returns a reference to the program's SymbolTable - const SymbolTable& Symbols() const { - AssertNotMoved(); - return symbols_; - } - - /// @returns a reference to the program's diagnostics - diag::List& Diagnostics() { - AssertNotMoved(); - return diagnostics_; - } - - /// @returns a reference to the program's diagnostics - const diag::List& Diagnostics() const { - AssertNotMoved(); - return diagnostics_; - } - - /// Controls whether the Resolver will be run on the program when it is built. - /// @param enable the new flag value (defaults to true) - void SetResolveOnBuild(bool enable) { resolve_on_build_ = enable; } - - /// @return true if the Resolver will be run on the program when it is - /// built. - bool ResolveOnBuild() const { return resolve_on_build_; } - - /// @returns true if the program has no error diagnostics and is not missing - /// information - bool IsValid() const; - - /// Creates a new ast::Node owned by the ProgramBuilder. When the - /// ProgramBuilder is destructed, the ast::Node will also be destructed. - /// @param source the Source of the node - /// @param args the arguments to pass to the type constructor - /// @returns the node pointer - template <typename T, typename... ARGS> - traits::EnableIfIsType<T, ast::Node>* create(const Source& source, - ARGS&&... args) { - AssertNotMoved(); - return ast_nodes_.Create<T>(id_, source, std::forward<ARGS>(args)...); - } - - /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current - /// Source as set by the last call to SetSource() as the only argument to the - /// constructor. - /// When the ProgramBuilder is destructed, the ast::Node will also be - /// destructed. - /// @returns the node pointer - template <typename T> - traits::EnableIfIsType<T, ast::Node>* create() { - AssertNotMoved(); - return ast_nodes_.Create<T>(id_, source_); - } - - /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current - /// Source as set by the last call to SetSource() as the first argument to the - /// constructor. - /// When the ProgramBuilder is destructed, the ast::Node will also be - /// destructed. - /// @param arg0 the first arguments to pass to the type constructor - /// @param args the remaining arguments to pass to the type constructor - /// @returns the node pointer - template <typename T, typename ARG0, typename... ARGS> - traits::EnableIf</* T is ast::Node and ARG0 is not Source */ - traits::IsTypeOrDerived<T, ast::Node> && - !traits::IsTypeOrDerived<ARG0, Source>, - T>* - create(ARG0&& arg0, ARGS&&... args) { - AssertNotMoved(); - return ast_nodes_.Create<T>(id_, source_, std::forward<ARG0>(arg0), - std::forward<ARGS>(args)...); - } - - /// Creates a new sem::Node owned by the ProgramBuilder. - /// When the ProgramBuilder is destructed, the sem::Node will also be - /// destructed. - /// @param args the arguments to pass to the type constructor - /// @returns the node pointer - template <typename T, typename... ARGS> - traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> && - !traits::IsTypeOrDerived<T, sem::Type>, - T>* - create(ARGS&&... args) { - AssertNotMoved(); - return sem_nodes_.Create<T>(std::forward<ARGS>(args)...); - } - - /// Creates a new sem::Type owned by the ProgramBuilder. - /// When the ProgramBuilder is destructed, owned ProgramBuilder and the - /// returned`Type` will also be destructed. - /// Types are unique (de-aliased), and so calling create() for the same `T` - /// and arguments will return the same pointer. - /// @warning Use this method to acquire a type only if all of its type - /// information is provided in the constructor arguments `args`.<br> - /// If the type requires additional configuration after construction that - /// affect its fundamental type, build the type with `std::make_unique`, make - /// any necessary alterations and then call unique_type() instead. - /// @param args the arguments to pass to the type constructor - /// @returns the de-aliased type pointer - template <typename T, typename... ARGS> - traits::EnableIfIsType<T, sem::Type>* create(ARGS&&... args) { - static_assert(std::is_base_of<sem::Type, T>::value, - "T does not derive from sem::Type"); - AssertNotMoved(); - return types_.Get<T>(std::forward<ARGS>(args)...); - } - - /// Marks this builder as moved, preventing any further use of the builder. - void MarkAsMoved(); - - ////////////////////////////////////////////////////////////////////////////// - // TypesBuilder - ////////////////////////////////////////////////////////////////////////////// - - /// TypesBuilder holds basic `tint` types and methods for constructing - /// complex types. - class TypesBuilder { - public: /// Constructor - /// @param builder the program builder - explicit TypesBuilder(ProgramBuilder* builder); + ProgramBuilder(); - /// @return the tint AST type for the C type `T`. - template <typename T> - const ast::Type* Of() const { - return CToAST<T>::get(this); + /// Move constructor + /// @param rhs the builder to move + ProgramBuilder(ProgramBuilder&& rhs); + + /// Destructor + virtual ~ProgramBuilder(); + + /// Move assignment operator + /// @param rhs the builder to move + /// @return this builder + ProgramBuilder& operator=(ProgramBuilder&& rhs); + + /// Wrap returns a new ProgramBuilder wrapping the Program `program` without + /// making a deep clone of the Program contents. + /// ProgramBuilder returned by Wrap() is intended to temporarily extend an + /// existing immutable program. + /// As the returned ProgramBuilder wraps `program`, `program` must not be + /// destructed or assigned while using the returned ProgramBuilder. + /// TODO(bclayton) - Evaluate whether there are safer alternatives to this + /// function. See crbug.com/tint/460. + /// @param program the immutable Program to wrap + /// @return the ProgramBuilder that wraps `program` + static ProgramBuilder Wrap(const Program* program); + + /// @returns the unique identifier for this program + ProgramID ID() const { return id_; } + + /// @returns a reference to the program's types + sem::Manager& Types() { + AssertNotMoved(); + return types_; } - /// @returns a boolean type - const ast::Bool* bool_() const { return builder->create<ast::Bool>(); } + /// @returns a reference to the program's types + const sem::Manager& Types() const { + AssertNotMoved(); + return types_; + } + /// @returns a reference to the program's AST nodes storage + ASTNodeAllocator& ASTNodes() { + AssertNotMoved(); + return ast_nodes_; + } + + /// @returns a reference to the program's AST nodes storage + const ASTNodeAllocator& ASTNodes() const { + AssertNotMoved(); + return ast_nodes_; + } + + /// @returns a reference to the program's semantic nodes storage + SemNodeAllocator& SemNodes() { + AssertNotMoved(); + return sem_nodes_; + } + + /// @returns a reference to the program's semantic nodes storage + const SemNodeAllocator& SemNodes() const { + AssertNotMoved(); + return sem_nodes_; + } + + /// @returns a reference to the program's AST root Module + ast::Module& AST() { + AssertNotMoved(); + return *ast_; + } + + /// @returns a reference to the program's AST root Module + const ast::Module& AST() const { + AssertNotMoved(); + return *ast_; + } + + /// @returns a reference to the program's semantic info + sem::Info& Sem() { + AssertNotMoved(); + return sem_; + } + + /// @returns a reference to the program's semantic info + const sem::Info& Sem() const { + AssertNotMoved(); + return sem_; + } + + /// @returns a reference to the program's SymbolTable + SymbolTable& Symbols() { + AssertNotMoved(); + return symbols_; + } + + /// @returns a reference to the program's SymbolTable + const SymbolTable& Symbols() const { + AssertNotMoved(); + return symbols_; + } + + /// @returns a reference to the program's diagnostics + diag::List& Diagnostics() { + AssertNotMoved(); + return diagnostics_; + } + + /// @returns a reference to the program's diagnostics + const diag::List& Diagnostics() const { + AssertNotMoved(); + return diagnostics_; + } + + /// Controls whether the Resolver will be run on the program when it is built. + /// @param enable the new flag value (defaults to true) + void SetResolveOnBuild(bool enable) { resolve_on_build_ = enable; } + + /// @return true if the Resolver will be run on the program when it is + /// built. + bool ResolveOnBuild() const { return resolve_on_build_; } + + /// @returns true if the program has no error diagnostics and is not missing + /// information + bool IsValid() const; + + /// Creates a new ast::Node owned by the ProgramBuilder. When the + /// ProgramBuilder is destructed, the ast::Node will also be destructed. /// @param source the Source of the node - /// @returns a boolean type - const ast::Bool* bool_(const Source& source) const { - return builder->create<ast::Bool>(source); + /// @param args the arguments to pass to the type constructor + /// @returns the node pointer + template <typename T, typename... ARGS> + traits::EnableIfIsType<T, ast::Node>* create(const Source& source, ARGS&&... args) { + AssertNotMoved(); + return ast_nodes_.Create<T>(id_, source, std::forward<ARGS>(args)...); } - /// @returns a f32 type - const ast::F32* f32() const { return builder->create<ast::F32>(); } - - /// @param source the Source of the node - /// @returns a f32 type - const ast::F32* f32(const Source& source) const { - return builder->create<ast::F32>(source); - } - - /// @returns a i32 type - const ast::I32* i32() const { return builder->create<ast::I32>(); } - - /// @param source the Source of the node - /// @returns a i32 type - const ast::I32* i32(const Source& source) const { - return builder->create<ast::I32>(source); - } - - /// @returns a u32 type - const ast::U32* u32() const { return builder->create<ast::U32>(); } - - /// @param source the Source of the node - /// @returns a u32 type - const ast::U32* u32(const Source& source) const { - return builder->create<ast::U32>(source); - } - - /// @returns a void type - const ast::Void* void_() const { return builder->create<ast::Void>(); } - - /// @param source the Source of the node - /// @returns a void type - const ast::Void* void_(const Source& source) const { - return builder->create<ast::Void>(source); - } - - /// @param type vector subtype - /// @param n vector width in elements - /// @return the tint AST type for a `n`-element vector of `type`. - const ast::Vector* vec(const ast::Type* type, uint32_t n) const { - return builder->create<ast::Vector>(type, n); - } - - /// @param source the Source of the node - /// @param type vector subtype - /// @param n vector width in elements - /// @return the tint AST type for a `n`-element vector of `type`. - const ast::Vector* vec(const Source& source, - const ast::Type* type, - uint32_t n) const { - return builder->create<ast::Vector>(source, type, n); - } - - /// @param type vector subtype - /// @return the tint AST type for a 2-element vector of `type`. - const ast::Vector* vec2(const ast::Type* type) const { - return vec(type, 2u); - } - - /// @param type vector subtype - /// @return the tint AST type for a 3-element vector of `type`. - const ast::Vector* vec3(const ast::Type* type) const { - return vec(type, 3u); - } - - /// @param type vector subtype - /// @return the tint AST type for a 4-element vector of `type`. - const ast::Vector* vec4(const ast::Type* type) const { - return vec(type, 4u); - } - - /// @param n vector width in elements - /// @return the tint AST type for a `n`-element vector of `type`. + /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current + /// Source as set by the last call to SetSource() as the only argument to the + /// constructor. + /// When the ProgramBuilder is destructed, the ast::Node will also be + /// destructed. + /// @returns the node pointer template <typename T> - const ast::Vector* vec(uint32_t n) const { - return vec(Of<T>(), n); + traits::EnableIfIsType<T, ast::Node>* create() { + AssertNotMoved(); + return ast_nodes_.Create<T>(id_, source_); } - /// @return the tint AST type for a 2-element vector of the C type `T`. + /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current + /// Source as set by the last call to SetSource() as the first argument to the + /// constructor. + /// When the ProgramBuilder is destructed, the ast::Node will also be + /// destructed. + /// @param arg0 the first arguments to pass to the type constructor + /// @param args the remaining arguments to pass to the type constructor + /// @returns the node pointer + template <typename T, typename ARG0, typename... ARGS> + traits::EnableIf</* T is ast::Node and ARG0 is not Source */ + traits::IsTypeOrDerived<T, ast::Node> && + !traits::IsTypeOrDerived<ARG0, Source>, + T>* + create(ARG0&& arg0, ARGS&&... args) { + AssertNotMoved(); + return ast_nodes_.Create<T>(id_, source_, std::forward<ARG0>(arg0), + std::forward<ARGS>(args)...); + } + + /// Creates a new sem::Node owned by the ProgramBuilder. + /// When the ProgramBuilder is destructed, the sem::Node will also be + /// destructed. + /// @param args the arguments to pass to the type constructor + /// @returns the node pointer + template <typename T, typename... ARGS> + traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> && + !traits::IsTypeOrDerived<T, sem::Type>, + T>* + create(ARGS&&... args) { + AssertNotMoved(); + return sem_nodes_.Create<T>(std::forward<ARGS>(args)...); + } + + /// Creates a new sem::Type owned by the ProgramBuilder. + /// When the ProgramBuilder is destructed, owned ProgramBuilder and the + /// returned`Type` will also be destructed. + /// Types are unique (de-aliased), and so calling create() for the same `T` + /// and arguments will return the same pointer. + /// @warning Use this method to acquire a type only if all of its type + /// information is provided in the constructor arguments `args`.<br> + /// If the type requires additional configuration after construction that + /// affect its fundamental type, build the type with `std::make_unique`, make + /// any necessary alterations and then call unique_type() instead. + /// @param args the arguments to pass to the type constructor + /// @returns the de-aliased type pointer + template <typename T, typename... ARGS> + traits::EnableIfIsType<T, sem::Type>* create(ARGS&&... args) { + static_assert(std::is_base_of<sem::Type, T>::value, "T does not derive from sem::Type"); + AssertNotMoved(); + return types_.Get<T>(std::forward<ARGS>(args)...); + } + + /// Marks this builder as moved, preventing any further use of the builder. + void MarkAsMoved(); + + ////////////////////////////////////////////////////////////////////////////// + // TypesBuilder + ////////////////////////////////////////////////////////////////////////////// + + /// TypesBuilder holds basic `tint` types and methods for constructing + /// complex types. + class TypesBuilder { + public: + /// Constructor + /// @param builder the program builder + explicit TypesBuilder(ProgramBuilder* builder); + + /// @return the tint AST type for the C type `T`. + template <typename T> + const ast::Type* Of() const { + return CToAST<T>::get(this); + } + + /// @returns a boolean type + const ast::Bool* bool_() const { return builder->create<ast::Bool>(); } + + /// @param source the Source of the node + /// @returns a boolean type + const ast::Bool* bool_(const Source& source) const { + return builder->create<ast::Bool>(source); + } + + /// @returns a f32 type + const ast::F32* f32() const { return builder->create<ast::F32>(); } + + /// @param source the Source of the node + /// @returns a f32 type + const ast::F32* f32(const Source& source) const { + return builder->create<ast::F32>(source); + } + + /// @returns a i32 type + const ast::I32* i32() const { return builder->create<ast::I32>(); } + + /// @param source the Source of the node + /// @returns a i32 type + const ast::I32* i32(const Source& source) const { + return builder->create<ast::I32>(source); + } + + /// @returns a u32 type + const ast::U32* u32() const { return builder->create<ast::U32>(); } + + /// @param source the Source of the node + /// @returns a u32 type + const ast::U32* u32(const Source& source) const { + return builder->create<ast::U32>(source); + } + + /// @returns a void type + const ast::Void* void_() const { return builder->create<ast::Void>(); } + + /// @param source the Source of the node + /// @returns a void type + const ast::Void* void_(const Source& source) const { + return builder->create<ast::Void>(source); + } + + /// @param type vector subtype + /// @param n vector width in elements + /// @return the tint AST type for a `n`-element vector of `type`. + const ast::Vector* vec(const ast::Type* type, uint32_t n) const { + return builder->create<ast::Vector>(type, n); + } + + /// @param source the Source of the node + /// @param type vector subtype + /// @param n vector width in elements + /// @return the tint AST type for a `n`-element vector of `type`. + const ast::Vector* vec(const Source& source, const ast::Type* type, uint32_t n) const { + return builder->create<ast::Vector>(source, type, n); + } + + /// @param type vector subtype + /// @return the tint AST type for a 2-element vector of `type`. + const ast::Vector* vec2(const ast::Type* type) const { return vec(type, 2u); } + + /// @param type vector subtype + /// @return the tint AST type for a 3-element vector of `type`. + const ast::Vector* vec3(const ast::Type* type) const { return vec(type, 3u); } + + /// @param type vector subtype + /// @return the tint AST type for a 4-element vector of `type`. + const ast::Vector* vec4(const ast::Type* type) const { return vec(type, 4u); } + + /// @param n vector width in elements + /// @return the tint AST type for a `n`-element vector of `type`. + template <typename T> + const ast::Vector* vec(uint32_t n) const { + return vec(Of<T>(), n); + } + + /// @return the tint AST type for a 2-element vector of the C type `T`. + template <typename T> + const ast::Vector* vec2() const { + return vec2(Of<T>()); + } + + /// @return the tint AST type for a 3-element vector of the C type `T`. + template <typename T> + const ast::Vector* vec3() const { + return vec3(Of<T>()); + } + + /// @return the tint AST type for a 4-element vector of the C type `T`. + template <typename T> + const ast::Vector* vec4() const { + return vec4(Of<T>()); + } + + /// @param type matrix subtype + /// @param columns number of columns for the matrix + /// @param rows number of rows for the matrix + /// @return the tint AST type for a matrix of `type` + const ast::Matrix* mat(const ast::Type* type, uint32_t columns, uint32_t rows) const { + return builder->create<ast::Matrix>(type, rows, columns); + } + + /// @param source the Source of the node + /// @param type matrix subtype + /// @param columns number of columns for the matrix + /// @param rows number of rows for the matrix + /// @return the tint AST type for a matrix of `type` + const ast::Matrix* mat(const Source& source, + const ast::Type* type, + uint32_t columns, + uint32_t rows) const { + return builder->create<ast::Matrix>(source, type, rows, columns); + } + + /// @param type matrix subtype + /// @return the tint AST type for a 2x3 matrix of `type`. + const ast::Matrix* mat2x2(const ast::Type* type) const { return mat(type, 2u, 2u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 2x3 matrix of `type`. + const ast::Matrix* mat2x3(const ast::Type* type) const { return mat(type, 2u, 3u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 2x4 matrix of `type`. + const ast::Matrix* mat2x4(const ast::Type* type) const { return mat(type, 2u, 4u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 3x2 matrix of `type`. + const ast::Matrix* mat3x2(const ast::Type* type) const { return mat(type, 3u, 2u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 3x3 matrix of `type`. + const ast::Matrix* mat3x3(const ast::Type* type) const { return mat(type, 3u, 3u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 3x4 matrix of `type`. + const ast::Matrix* mat3x4(const ast::Type* type) const { return mat(type, 3u, 4u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 4x2 matrix of `type`. + const ast::Matrix* mat4x2(const ast::Type* type) const { return mat(type, 4u, 2u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 4x3 matrix of `type`. + const ast::Matrix* mat4x3(const ast::Type* type) const { return mat(type, 4u, 3u); } + + /// @param type matrix subtype + /// @return the tint AST type for a 4x4 matrix of `type`. + const ast::Matrix* mat4x4(const ast::Type* type) const { return mat(type, 4u, 4u); } + + /// @param columns number of columns for the matrix + /// @param rows number of rows for the matrix + /// @return the tint AST type for a matrix of `type` + template <typename T> + const ast::Matrix* mat(uint32_t columns, uint32_t rows) const { + return mat(Of<T>(), columns, rows); + } + + /// @return the tint AST type for a 2x3 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat2x2() const { + return mat2x2(Of<T>()); + } + + /// @return the tint AST type for a 2x3 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat2x3() const { + return mat2x3(Of<T>()); + } + + /// @return the tint AST type for a 2x4 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat2x4() const { + return mat2x4(Of<T>()); + } + + /// @return the tint AST type for a 3x2 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat3x2() const { + return mat3x2(Of<T>()); + } + + /// @return the tint AST type for a 3x3 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat3x3() const { + return mat3x3(Of<T>()); + } + + /// @return the tint AST type for a 3x4 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat3x4() const { + return mat3x4(Of<T>()); + } + + /// @return the tint AST type for a 4x2 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat4x2() const { + return mat4x2(Of<T>()); + } + + /// @return the tint AST type for a 4x3 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat4x3() const { + return mat4x3(Of<T>()); + } + + /// @return the tint AST type for a 4x4 matrix of the C type `T`. + template <typename T> + const ast::Matrix* mat4x4() const { + return mat4x4(Of<T>()); + } + + /// @param subtype the array element type + /// @param n the array size. nullptr represents a runtime-array + /// @param attrs the optional attributes for the array + /// @return the tint AST type for a array of size `n` of type `T` + template <typename EXPR = ast::Expression*> + const ast::Array* array(const ast::Type* subtype, + EXPR&& n = nullptr, + ast::AttributeList attrs = {}) const { + return builder->create<ast::Array>(subtype, builder->Expr(std::forward<EXPR>(n)), + attrs); + } + + /// @param source the Source of the node + /// @param subtype the array element type + /// @param n the array size. nullptr represents a runtime-array + /// @param attrs the optional attributes for the array + /// @return the tint AST type for a array of size `n` of type `T` + template <typename EXPR = ast::Expression*> + const ast::Array* array(const Source& source, + const ast::Type* subtype, + EXPR&& n = nullptr, + ast::AttributeList attrs = {}) const { + return builder->create<ast::Array>(source, subtype, + builder->Expr(std::forward<EXPR>(n)), attrs); + } + + /// @param subtype the array element type + /// @param n the array size. nullptr represents a runtime-array + /// @param stride the array stride. 0 represents implicit stride + /// @return the tint AST type for a array of size `n` of type `T` + template <typename EXPR> + const ast::Array* array(const ast::Type* subtype, EXPR&& n, uint32_t stride) const { + ast::AttributeList attrs; + if (stride) { + attrs.emplace_back(builder->create<ast::StrideAttribute>(stride)); + } + return array(subtype, std::forward<EXPR>(n), std::move(attrs)); + } + + /// @param source the Source of the node + /// @param subtype the array element type + /// @param n the array size. nullptr represents a runtime-array + /// @param stride the array stride. 0 represents implicit stride + /// @return the tint AST type for a array of size `n` of type `T` + template <typename EXPR> + const ast::Array* array(const Source& source, + const ast::Type* subtype, + EXPR&& n, + uint32_t stride) const { + ast::AttributeList attrs; + if (stride) { + attrs.emplace_back(builder->create<ast::StrideAttribute>(stride)); + } + return array(source, subtype, std::forward<EXPR>(n), std::move(attrs)); + } + + /// @return the tint AST type for a runtime-sized array of type `T` + template <typename T> + const ast::Array* array() const { + return array(Of<T>(), nullptr); + } + + /// @return the tint AST type for an array of size `N` of type `T` + template <typename T, int N> + const ast::Array* array() const { + return array(Of<T>(), builder->Expr(N)); + } + + /// @param stride the array stride + /// @return the tint AST type for a runtime-sized array of type `T` + template <typename T> + const ast::Array* array(uint32_t stride) const { + return array(Of<T>(), nullptr, stride); + } + + /// @param stride the array stride + /// @return the tint AST type for an array of size `N` of type `T` + template <typename T, int N> + const ast::Array* array(uint32_t stride) const { + return array(Of<T>(), builder->Expr(N), stride); + } + + /// Creates a type name + /// @param name the name + /// @returns the type name + template <typename NAME> + const ast::TypeName* type_name(NAME&& name) const { + return builder->create<ast::TypeName>(builder->Sym(std::forward<NAME>(name))); + } + + /// Creates a type name + /// @param source the Source of the node + /// @param name the name + /// @returns the type name + template <typename NAME> + const ast::TypeName* type_name(const Source& source, NAME&& name) const { + return builder->create<ast::TypeName>(source, builder->Sym(std::forward<NAME>(name))); + } + + /// Creates an alias type + /// @param name the alias name + /// @param type the alias type + /// @returns the alias pointer + template <typename NAME> + const ast::Alias* alias(NAME&& name, const ast::Type* type) const { + auto sym = builder->Sym(std::forward<NAME>(name)); + return builder->create<ast::Alias>(sym, type); + } + + /// Creates an alias type + /// @param source the Source of the node + /// @param name the alias name + /// @param type the alias type + /// @returns the alias pointer + template <typename NAME> + const ast::Alias* alias(const Source& source, NAME&& name, const ast::Type* type) const { + auto sym = builder->Sym(std::forward<NAME>(name)); + return builder->create<ast::Alias>(source, sym, type); + } + + /// @param type the type of the pointer + /// @param storage_class the storage class of the pointer + /// @param access the optional access control of the pointer + /// @return the pointer to `type` with the given ast::StorageClass + const ast::Pointer* pointer(const ast::Type* type, + ast::StorageClass storage_class, + ast::Access access = ast::Access::kUndefined) const { + return builder->create<ast::Pointer>(type, storage_class, access); + } + + /// @param source the Source of the node + /// @param type the type of the pointer + /// @param storage_class the storage class of the pointer + /// @param access the optional access control of the pointer + /// @return the pointer to `type` with the given ast::StorageClass + const ast::Pointer* pointer(const Source& source, + const ast::Type* type, + ast::StorageClass storage_class, + ast::Access access = ast::Access::kUndefined) const { + return builder->create<ast::Pointer>(source, type, storage_class, access); + } + + /// @param storage_class the storage class of the pointer + /// @param access the optional access control of the pointer + /// @return the pointer to type `T` with the given ast::StorageClass. + template <typename T> + const ast::Pointer* pointer(ast::StorageClass storage_class, + ast::Access access = ast::Access::kUndefined) const { + return pointer(Of<T>(), storage_class, access); + } + + /// @param source the Source of the node + /// @param type the type of the atomic + /// @return the atomic to `type` + const ast::Atomic* atomic(const Source& source, const ast::Type* type) const { + return builder->create<ast::Atomic>(source, type); + } + + /// @param type the type of the atomic + /// @return the atomic to `type` + const ast::Atomic* atomic(const ast::Type* type) const { + return builder->create<ast::Atomic>(type); + } + + /// @return the atomic to type `T` + template <typename T> + const ast::Atomic* atomic() const { + return atomic(Of<T>()); + } + + /// @param kind the kind of sampler + /// @returns the sampler + const ast::Sampler* sampler(ast::SamplerKind kind) const { + return builder->create<ast::Sampler>(kind); + } + + /// @param source the Source of the node + /// @param kind the kind of sampler + /// @returns the sampler + const ast::Sampler* sampler(const Source& source, ast::SamplerKind kind) const { + return builder->create<ast::Sampler>(source, kind); + } + + /// @param dims the dimensionality of the texture + /// @returns the depth texture + const ast::DepthTexture* depth_texture(ast::TextureDimension dims) const { + return builder->create<ast::DepthTexture>(dims); + } + + /// @param source the Source of the node + /// @param dims the dimensionality of the texture + /// @returns the depth texture + const ast::DepthTexture* depth_texture(const Source& source, + ast::TextureDimension dims) const { + return builder->create<ast::DepthTexture>(source, dims); + } + + /// @param dims the dimensionality of the texture + /// @returns the multisampled depth texture + const ast::DepthMultisampledTexture* depth_multisampled_texture( + ast::TextureDimension dims) const { + return builder->create<ast::DepthMultisampledTexture>(dims); + } + + /// @param source the Source of the node + /// @param dims the dimensionality of the texture + /// @returns the multisampled depth texture + const ast::DepthMultisampledTexture* depth_multisampled_texture( + const Source& source, + ast::TextureDimension dims) const { + return builder->create<ast::DepthMultisampledTexture>(source, dims); + } + + /// @param dims the dimensionality of the texture + /// @param subtype the texture subtype. + /// @returns the sampled texture + const ast::SampledTexture* sampled_texture(ast::TextureDimension dims, + const ast::Type* subtype) const { + return builder->create<ast::SampledTexture>(dims, subtype); + } + + /// @param source the Source of the node + /// @param dims the dimensionality of the texture + /// @param subtype the texture subtype. + /// @returns the sampled texture + const ast::SampledTexture* sampled_texture(const Source& source, + ast::TextureDimension dims, + const ast::Type* subtype) const { + return builder->create<ast::SampledTexture>(source, dims, subtype); + } + + /// @param dims the dimensionality of the texture + /// @param subtype the texture subtype. + /// @returns the multisampled texture + const ast::MultisampledTexture* multisampled_texture(ast::TextureDimension dims, + const ast::Type* subtype) const { + return builder->create<ast::MultisampledTexture>(dims, subtype); + } + + /// @param source the Source of the node + /// @param dims the dimensionality of the texture + /// @param subtype the texture subtype. + /// @returns the multisampled texture + const ast::MultisampledTexture* multisampled_texture(const Source& source, + ast::TextureDimension dims, + const ast::Type* subtype) const { + return builder->create<ast::MultisampledTexture>(source, dims, subtype); + } + + /// @param dims the dimensionality of the texture + /// @param format the texel format of the texture + /// @param access the access control of the texture + /// @returns the storage texture + const ast::StorageTexture* storage_texture(ast::TextureDimension dims, + ast::TexelFormat format, + ast::Access access) const { + auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); + return builder->create<ast::StorageTexture>(dims, format, subtype, access); + } + + /// @param source the Source of the node + /// @param dims the dimensionality of the texture + /// @param format the texel format of the texture + /// @param access the access control of the texture + /// @returns the storage texture + const ast::StorageTexture* storage_texture(const Source& source, + ast::TextureDimension dims, + ast::TexelFormat format, + ast::Access access) const { + auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); + return builder->create<ast::StorageTexture>(source, dims, format, subtype, access); + } + + /// @returns the external texture + const ast::ExternalTexture* external_texture() const { + return builder->create<ast::ExternalTexture>(); + } + + /// @param source the Source of the node + /// @returns the external texture + const ast::ExternalTexture* external_texture(const Source& source) const { + return builder->create<ast::ExternalTexture>(source); + } + + /// Constructs a TypeName for the type declaration. + /// @param type the type + /// @return either type or a pointer to a new ast::TypeName + const ast::TypeName* Of(const ast::TypeDecl* type) const; + + /// The ProgramBuilder + ProgramBuilder* const builder; + + private: + /// CToAST<T> is specialized for various `T` types and each specialization + /// contains a single static `get()` method for obtaining the corresponding + /// AST type for the C type `T`. + /// `get()` has the signature: + /// `static const ast::Type* get(Types* t)` + template <typename T> + struct CToAST {}; + }; + + ////////////////////////////////////////////////////////////////////////////// + // AST helper methods + ////////////////////////////////////////////////////////////////////////////// + + /// @return a new unnamed symbol + Symbol Sym() { return Symbols().New(); } + + /// @param name the symbol string + /// @return a Symbol with the given name + Symbol Sym(const std::string& name) { return Symbols().Register(name); } + + /// @param sym the symbol + /// @return `sym` + Symbol Sym(Symbol sym) { return sym; } + + /// @param expr the expression + /// @return expr template <typename T> - const ast::Vector* vec2() const { - return vec2(Of<T>()); + traits::EnableIfIsType<T, ast::Expression>* Expr(T* expr) { + return expr; } - /// @return the tint AST type for a 3-element vector of the C type `T`. - template <typename T> - const ast::Vector* vec3() const { - return vec3(Of<T>()); + /// Passthrough for nullptr + /// @return nullptr + const ast::IdentifierExpression* Expr(std::nullptr_t) { return nullptr; } + + /// @param source the source information + /// @param symbol the identifier symbol + /// @return an ast::IdentifierExpression with the given symbol + const ast::IdentifierExpression* Expr(const Source& source, Symbol symbol) { + return create<ast::IdentifierExpression>(source, symbol); } - /// @return the tint AST type for a 4-element vector of the C type `T`. - template <typename T> - const ast::Vector* vec4() const { - return vec4(Of<T>()); + /// @param symbol the identifier symbol + /// @return an ast::IdentifierExpression with the given symbol + const ast::IdentifierExpression* Expr(Symbol symbol) { + return create<ast::IdentifierExpression>(symbol); } - /// @param type matrix subtype - /// @param columns number of columns for the matrix - /// @param rows number of rows for the matrix - /// @return the tint AST type for a matrix of `type` - const ast::Matrix* mat(const ast::Type* type, - uint32_t columns, - uint32_t rows) const { - return builder->create<ast::Matrix>(type, rows, columns); + /// @param source the source information + /// @param variable the AST variable + /// @return an ast::IdentifierExpression with the variable's symbol + const ast::IdentifierExpression* Expr(const Source& source, const ast::Variable* variable) { + return create<ast::IdentifierExpression>(source, variable->symbol); } - /// @param source the Source of the node - /// @param type matrix subtype - /// @param columns number of columns for the matrix - /// @param rows number of rows for the matrix - /// @return the tint AST type for a matrix of `type` - const ast::Matrix* mat(const Source& source, - const ast::Type* type, - uint32_t columns, - uint32_t rows) const { - return builder->create<ast::Matrix>(source, type, rows, columns); + /// @param variable the AST variable + /// @return an ast::IdentifierExpression with the variable's symbol + const ast::IdentifierExpression* Expr(const ast::Variable* variable) { + return create<ast::IdentifierExpression>(variable->symbol); } - /// @param type matrix subtype - /// @return the tint AST type for a 2x3 matrix of `type`. - const ast::Matrix* mat2x2(const ast::Type* type) const { - return mat(type, 2u, 2u); + /// @param source the source information + /// @param name the identifier name + /// @return an ast::IdentifierExpression with the given name + const ast::IdentifierExpression* Expr(const Source& source, const char* name) { + return create<ast::IdentifierExpression>(source, Symbols().Register(name)); } - /// @param type matrix subtype - /// @return the tint AST type for a 2x3 matrix of `type`. - const ast::Matrix* mat2x3(const ast::Type* type) const { - return mat(type, 2u, 3u); + /// @param name the identifier name + /// @return an ast::IdentifierExpression with the given name + const ast::IdentifierExpression* Expr(const char* name) { + return create<ast::IdentifierExpression>(Symbols().Register(name)); } - /// @param type matrix subtype - /// @return the tint AST type for a 2x4 matrix of `type`. - const ast::Matrix* mat2x4(const ast::Type* type) const { - return mat(type, 2u, 4u); + /// @param source the source information + /// @param name the identifier name + /// @return an ast::IdentifierExpression with the given name + const ast::IdentifierExpression* Expr(const Source& source, const std::string& name) { + return create<ast::IdentifierExpression>(source, Symbols().Register(name)); } - /// @param type matrix subtype - /// @return the tint AST type for a 3x2 matrix of `type`. - const ast::Matrix* mat3x2(const ast::Type* type) const { - return mat(type, 3u, 2u); + /// @param name the identifier name + /// @return an ast::IdentifierExpression with the given name + const ast::IdentifierExpression* Expr(const std::string& name) { + return create<ast::IdentifierExpression>(Symbols().Register(name)); } - /// @param type matrix subtype - /// @return the tint AST type for a 3x3 matrix of `type`. - const ast::Matrix* mat3x3(const ast::Type* type) const { - return mat(type, 3u, 3u); + /// @param source the source information + /// @param value the boolean value + /// @return a Scalar constructor for the given value + const ast::BoolLiteralExpression* Expr(const Source& source, bool value) { + return create<ast::BoolLiteralExpression>(source, value); } - /// @param type matrix subtype - /// @return the tint AST type for a 3x4 matrix of `type`. - const ast::Matrix* mat3x4(const ast::Type* type) const { - return mat(type, 3u, 4u); + /// @param value the boolean value + /// @return a Scalar constructor for the given value + const ast::BoolLiteralExpression* Expr(bool value) { + return create<ast::BoolLiteralExpression>(value); } - /// @param type matrix subtype - /// @return the tint AST type for a 4x2 matrix of `type`. - const ast::Matrix* mat4x2(const ast::Type* type) const { - return mat(type, 4u, 2u); + /// @param source the source information + /// @param value the float value + /// @return a Scalar constructor for the given value + const ast::FloatLiteralExpression* Expr(const Source& source, f32 value) { + return create<ast::FloatLiteralExpression>(source, value); } - /// @param type matrix subtype - /// @return the tint AST type for a 4x3 matrix of `type`. - const ast::Matrix* mat4x3(const ast::Type* type) const { - return mat(type, 4u, 3u); + /// @param value the float value + /// @return a Scalar constructor for the given value + const ast::FloatLiteralExpression* Expr(f32 value) { + return create<ast::FloatLiteralExpression>(value); } - /// @param type matrix subtype - /// @return the tint AST type for a 4x4 matrix of `type`. - const ast::Matrix* mat4x4(const ast::Type* type) const { - return mat(type, 4u, 4u); + /// @param source the source information + /// @param value the integer value + /// @return a Scalar constructor for the given value + const ast::SintLiteralExpression* Expr(const Source& source, i32 value) { + return create<ast::SintLiteralExpression>(source, value); } - /// @param columns number of columns for the matrix - /// @param rows number of rows for the matrix - /// @return the tint AST type for a matrix of `type` - template <typename T> - const ast::Matrix* mat(uint32_t columns, uint32_t rows) const { - return mat(Of<T>(), columns, rows); + /// @param value the integer value + /// @return a Scalar constructor for the given value + const ast::SintLiteralExpression* Expr(i32 value) { + return create<ast::SintLiteralExpression>(value); } - /// @return the tint AST type for a 2x3 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat2x2() const { - return mat2x2(Of<T>()); + /// @param source the source information + /// @param value the unsigned int value + /// @return a Scalar constructor for the given value + const ast::UintLiteralExpression* Expr(const Source& source, u32 value) { + return create<ast::UintLiteralExpression>(source, value); } - /// @return the tint AST type for a 2x3 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat2x3() const { - return mat2x3(Of<T>()); + /// @param value the unsigned int value + /// @return a Scalar constructor for the given value + const ast::UintLiteralExpression* Expr(u32 value) { + return create<ast::UintLiteralExpression>(value); } - /// @return the tint AST type for a 2x4 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat2x4() const { - return mat2x4(Of<T>()); + /// Converts `arg` to an `ast::Expression` using `Expr()`, then appends it to + /// `list`. + /// @param list the list to append too + /// @param arg the arg to create + template <typename ARG> + void Append(ast::ExpressionList& list, ARG&& arg) { + list.emplace_back(Expr(std::forward<ARG>(arg))); } - /// @return the tint AST type for a 3x2 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat3x2() const { - return mat3x2(Of<T>()); + /// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`, + /// then appends them to `list`. + /// @param list the list to append too + /// @param arg0 the first argument + /// @param args the rest of the arguments + template <typename ARG0, typename... ARGS> + void Append(ast::ExpressionList& list, ARG0&& arg0, ARGS&&... args) { + Append(list, std::forward<ARG0>(arg0)); + Append(list, std::forward<ARGS>(args)...); } - /// @return the tint AST type for a 3x3 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat3x3() const { - return mat3x3(Of<T>()); + /// @return an empty list of expressions + ast::ExpressionList ExprList() { return {}; } + + /// @param args the list of expressions + /// @return the list of expressions converted to `ast::Expression`s using + /// `Expr()`, + template <typename... ARGS> + ast::ExpressionList ExprList(ARGS&&... args) { + ast::ExpressionList list; + list.reserve(sizeof...(args)); + Append(list, std::forward<ARGS>(args)...); + return list; } - /// @return the tint AST type for a 3x4 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat3x4() const { - return mat3x4(Of<T>()); + /// @param list the list of expressions + /// @return `list` + ast::ExpressionList ExprList(ast::ExpressionList list) { return list; } + + /// @param args the arguments for the type constructor + /// @return an `ast::CallExpression` of type `ty`, with the values + /// of `args` converted to `ast::Expression`s using `Expr()` + template <typename T, typename... ARGS> + const ast::CallExpression* Construct(ARGS&&... args) { + return Construct(ty.Of<T>(), std::forward<ARGS>(args)...); } - /// @return the tint AST type for a 4x2 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat4x2() const { - return mat4x2(Of<T>()); + /// @param type the type to construct + /// @param args the arguments for the constructor + /// @return an `ast::CallExpression` of `type` constructed with the + /// values `args`. + template <typename... ARGS> + const ast::CallExpression* Construct(const ast::Type* type, ARGS&&... args) { + return Construct(source_, type, std::forward<ARGS>(args)...); } - /// @return the tint AST type for a 4x3 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat4x3() const { - return mat4x3(Of<T>()); + /// @param source the source information + /// @param type the type to construct + /// @param args the arguments for the constructor + /// @return an `ast::CallExpression` of `type` constructed with the + /// values `args`. + template <typename... ARGS> + const ast::CallExpression* Construct(const Source& source, + const ast::Type* type, + ARGS&&... args) { + return create<ast::CallExpression>(source, type, ExprList(std::forward<ARGS>(args)...)); } - /// @return the tint AST type for a 4x4 matrix of the C type `T`. - template <typename T> - const ast::Matrix* mat4x4() const { - return mat4x4(Of<T>()); + /// @param expr the expression for the bitcast + /// @return an `ast::BitcastExpression` of type `ty`, with the values of + /// `expr` converted to `ast::Expression`s using `Expr()` + template <typename T, typename EXPR> + const ast::BitcastExpression* Bitcast(EXPR&& expr) { + return Bitcast(ty.Of<T>(), std::forward<EXPR>(expr)); } - /// @param subtype the array element type - /// @param n the array size. nullptr represents a runtime-array - /// @param attrs the optional attributes for the array - /// @return the tint AST type for a array of size `n` of type `T` - template <typename EXPR = ast::Expression*> - const ast::Array* array(const ast::Type* subtype, - EXPR&& n = nullptr, - ast::AttributeList attrs = {}) const { - return builder->create<ast::Array>( - subtype, builder->Expr(std::forward<EXPR>(n)), attrs); - } - - /// @param source the Source of the node - /// @param subtype the array element type - /// @param n the array size. nullptr represents a runtime-array - /// @param attrs the optional attributes for the array - /// @return the tint AST type for a array of size `n` of type `T` - template <typename EXPR = ast::Expression*> - const ast::Array* array(const Source& source, - const ast::Type* subtype, - EXPR&& n = nullptr, - ast::AttributeList attrs = {}) const { - return builder->create<ast::Array>( - source, subtype, builder->Expr(std::forward<EXPR>(n)), attrs); - } - - /// @param subtype the array element type - /// @param n the array size. nullptr represents a runtime-array - /// @param stride the array stride. 0 represents implicit stride - /// @return the tint AST type for a array of size `n` of type `T` + /// @param type the type to cast to + /// @param expr the expression for the bitcast + /// @return an `ast::BitcastExpression` of `type` constructed with the values + /// `expr`. template <typename EXPR> - const ast::Array* array(const ast::Type* subtype, - EXPR&& n, - uint32_t stride) const { - ast::AttributeList attrs; - if (stride) { - attrs.emplace_back(builder->create<ast::StrideAttribute>(stride)); - } - return array(subtype, std::forward<EXPR>(n), std::move(attrs)); + const ast::BitcastExpression* Bitcast(const ast::Type* type, EXPR&& expr) { + return create<ast::BitcastExpression>(type, Expr(std::forward<EXPR>(expr))); } - /// @param source the Source of the node - /// @param subtype the array element type - /// @param n the array size. nullptr represents a runtime-array - /// @param stride the array stride. 0 represents implicit stride - /// @return the tint AST type for a array of size `n` of type `T` + /// @param source the source information + /// @param type the type to cast to + /// @param expr the expression for the bitcast + /// @return an `ast::BitcastExpression` of `type` constructed with the values + /// `expr`. template <typename EXPR> - const ast::Array* array(const Source& source, - const ast::Type* subtype, - EXPR&& n, - uint32_t stride) const { - ast::AttributeList attrs; - if (stride) { - attrs.emplace_back(builder->create<ast::StrideAttribute>(stride)); - } - return array(source, subtype, std::forward<EXPR>(n), std::move(attrs)); + const ast::BitcastExpression* Bitcast(const Source& source, + const ast::Type* type, + EXPR&& expr) { + return create<ast::BitcastExpression>(source, type, Expr(std::forward<EXPR>(expr))); } - /// @return the tint AST type for a runtime-sized array of type `T` - template <typename T> - const ast::Array* array() const { - return array(Of<T>(), nullptr); + /// @param args the arguments for the vector constructor + /// @param type the vector type + /// @param size the vector size + /// @return an `ast::CallExpression` of a `size`-element vector of + /// type `type`, constructed with the values `args`. + template <typename... ARGS> + const ast::CallExpression* vec(const ast::Type* type, uint32_t size, ARGS&&... args) { + return Construct(ty.vec(type, size), std::forward<ARGS>(args)...); } - /// @return the tint AST type for an array of size `N` of type `T` - template <typename T, int N> - const ast::Array* array() const { - return array(Of<T>(), builder->Expr(N)); + /// @param args the arguments for the vector constructor + /// @return an `ast::CallExpression` of a 2-element vector of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* vec2(ARGS&&... args) { + return Construct(ty.vec2<T>(), std::forward<ARGS>(args)...); } - /// @param stride the array stride - /// @return the tint AST type for a runtime-sized array of type `T` - template <typename T> - const ast::Array* array(uint32_t stride) const { - return array(Of<T>(), nullptr, stride); + /// @param args the arguments for the vector constructor + /// @return an `ast::CallExpression` of a 3-element vector of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* vec3(ARGS&&... args) { + return Construct(ty.vec3<T>(), std::forward<ARGS>(args)...); } - /// @param stride the array stride - /// @return the tint AST type for an array of size `N` of type `T` - template <typename T, int N> - const ast::Array* array(uint32_t stride) const { - return array(Of<T>(), builder->Expr(N), stride); + /// @param args the arguments for the vector constructor + /// @return an `ast::CallExpression` of a 4-element vector of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* vec4(ARGS&&... args) { + return Construct(ty.vec4<T>(), std::forward<ARGS>(args)...); } - /// Creates a type name - /// @param name the name - /// @returns the type name - template <typename NAME> - const ast::TypeName* type_name(NAME&& name) const { - return builder->create<ast::TypeName>( - builder->Sym(std::forward<NAME>(name))); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 2x2 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat2x2(ARGS&&... args) { + return Construct(ty.mat2x2<T>(), std::forward<ARGS>(args)...); } - /// Creates a type name - /// @param source the Source of the node - /// @param name the name - /// @returns the type name - template <typename NAME> - const ast::TypeName* type_name(const Source& source, NAME&& name) const { - return builder->create<ast::TypeName>( - source, builder->Sym(std::forward<NAME>(name))); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 2x3 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat2x3(ARGS&&... args) { + return Construct(ty.mat2x3<T>(), std::forward<ARGS>(args)...); } - /// Creates an alias type - /// @param name the alias name - /// @param type the alias type - /// @returns the alias pointer - template <typename NAME> - const ast::Alias* alias(NAME&& name, const ast::Type* type) const { - auto sym = builder->Sym(std::forward<NAME>(name)); - return builder->create<ast::Alias>(sym, type); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 2x4 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat2x4(ARGS&&... args) { + return Construct(ty.mat2x4<T>(), std::forward<ARGS>(args)...); } - /// Creates an alias type - /// @param source the Source of the node - /// @param name the alias name - /// @param type the alias type - /// @returns the alias pointer - template <typename NAME> - const ast::Alias* alias(const Source& source, - NAME&& name, - const ast::Type* type) const { - auto sym = builder->Sym(std::forward<NAME>(name)); - return builder->create<ast::Alias>(source, sym, type); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 3x2 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat3x2(ARGS&&... args) { + return Construct(ty.mat3x2<T>(), std::forward<ARGS>(args)...); } - /// @param type the type of the pointer - /// @param storage_class the storage class of the pointer - /// @param access the optional access control of the pointer - /// @return the pointer to `type` with the given ast::StorageClass - const ast::Pointer* pointer( - const ast::Type* type, - ast::StorageClass storage_class, - ast::Access access = ast::Access::kUndefined) const { - return builder->create<ast::Pointer>(type, storage_class, access); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 3x3 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat3x3(ARGS&&... args) { + return Construct(ty.mat3x3<T>(), std::forward<ARGS>(args)...); } - /// @param source the Source of the node - /// @param type the type of the pointer - /// @param storage_class the storage class of the pointer - /// @param access the optional access control of the pointer - /// @return the pointer to `type` with the given ast::StorageClass - const ast::Pointer* pointer( - const Source& source, - const ast::Type* type, - ast::StorageClass storage_class, - ast::Access access = ast::Access::kUndefined) const { - return builder->create<ast::Pointer>(source, type, storage_class, access); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 3x4 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat3x4(ARGS&&... args) { + return Construct(ty.mat3x4<T>(), std::forward<ARGS>(args)...); } - /// @param storage_class the storage class of the pointer - /// @param access the optional access control of the pointer - /// @return the pointer to type `T` with the given ast::StorageClass. - template <typename T> - const ast::Pointer* pointer( - ast::StorageClass storage_class, - ast::Access access = ast::Access::kUndefined) const { - return pointer(Of<T>(), storage_class, access); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 4x2 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat4x2(ARGS&&... args) { + return Construct(ty.mat4x2<T>(), std::forward<ARGS>(args)...); } - /// @param source the Source of the node - /// @param type the type of the atomic - /// @return the atomic to `type` - const ast::Atomic* atomic(const Source& source, - const ast::Type* type) const { - return builder->create<ast::Atomic>(source, type); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 4x3 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat4x3(ARGS&&... args) { + return Construct(ty.mat4x3<T>(), std::forward<ARGS>(args)...); } - /// @param type the type of the atomic - /// @return the atomic to `type` - const ast::Atomic* atomic(const ast::Type* type) const { - return builder->create<ast::Atomic>(type); + /// @param args the arguments for the matrix constructor + /// @return an `ast::CallExpression` of a 4x4 matrix of type + /// `T`, constructed with the values `args`. + template <typename T, typename... ARGS> + const ast::CallExpression* mat4x4(ARGS&&... args) { + return Construct(ty.mat4x4<T>(), std::forward<ARGS>(args)...); } - /// @return the atomic to type `T` - template <typename T> - const ast::Atomic* atomic() const { - return atomic(Of<T>()); + /// @param args the arguments for the array constructor + /// @return an `ast::CallExpression` of an array with element type + /// `T` and size `N`, constructed with the values `args`. + template <typename T, int N, typename... ARGS> + const ast::CallExpression* array(ARGS&&... args) { + return Construct(ty.array<T, N>(), std::forward<ARGS>(args)...); } - /// @param kind the kind of sampler - /// @returns the sampler - const ast::Sampler* sampler(ast::SamplerKind kind) const { - return builder->create<ast::Sampler>(kind); + /// @param subtype the array element type + /// @param n the array size. nullptr represents a runtime-array. + /// @param args the arguments for the array constructor + /// @return an `ast::CallExpression` of an array with element type + /// `subtype`, constructed with the values `args`. + template <typename EXPR, typename... ARGS> + const ast::CallExpression* array(const ast::Type* subtype, EXPR&& n, ARGS&&... args) { + return Construct(ty.array(subtype, std::forward<EXPR>(n)), std::forward<ARGS>(args)...); } - /// @param source the Source of the node - /// @param kind the kind of sampler - /// @returns the sampler - const ast::Sampler* sampler(const Source& source, - ast::SamplerKind kind) const { - return builder->create<ast::Sampler>(source, kind); + /// @param name the variable name + /// @param type the variable type + /// @param optional the optional variable settings. + /// Can be any of the following, in any order: + /// * ast::StorageClass - specifies the variable storage class + /// * ast::Access - specifies the variable's access control + /// * ast::Expression* - specifies the variable's initializer expression + /// * ast::AttributeList - specifies the variable's attributes + /// Note that repeated arguments of the same type will use the last argument's + /// value. + /// @returns a `ast::Variable` with the given name, type and additional + /// options + template <typename NAME, typename... OPTIONAL> + const ast::Variable* Var(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) { + VarOptionals opts(std::forward<OPTIONAL>(optional)...); + return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage, opts.access, type, + false /* is_const */, false /* is_overridable */, + opts.constructor, std::move(opts.attributes)); } - /// @param dims the dimensionality of the texture - /// @returns the depth texture - const ast::DepthTexture* depth_texture(ast::TextureDimension dims) const { - return builder->create<ast::DepthTexture>(dims); - } - - /// @param source the Source of the node - /// @param dims the dimensionality of the texture - /// @returns the depth texture - const ast::DepthTexture* depth_texture(const Source& source, - ast::TextureDimension dims) const { - return builder->create<ast::DepthTexture>(source, dims); - } - - /// @param dims the dimensionality of the texture - /// @returns the multisampled depth texture - const ast::DepthMultisampledTexture* depth_multisampled_texture( - ast::TextureDimension dims) const { - return builder->create<ast::DepthMultisampledTexture>(dims); - } - - /// @param source the Source of the node - /// @param dims the dimensionality of the texture - /// @returns the multisampled depth texture - const ast::DepthMultisampledTexture* depth_multisampled_texture( - const Source& source, - ast::TextureDimension dims) const { - return builder->create<ast::DepthMultisampledTexture>(source, dims); - } - - /// @param dims the dimensionality of the texture - /// @param subtype the texture subtype. - /// @returns the sampled texture - const ast::SampledTexture* sampled_texture(ast::TextureDimension dims, - const ast::Type* subtype) const { - return builder->create<ast::SampledTexture>(dims, subtype); - } - - /// @param source the Source of the node - /// @param dims the dimensionality of the texture - /// @param subtype the texture subtype. - /// @returns the sampled texture - const ast::SampledTexture* sampled_texture(const Source& source, - ast::TextureDimension dims, - const ast::Type* subtype) const { - return builder->create<ast::SampledTexture>(source, dims, subtype); - } - - /// @param dims the dimensionality of the texture - /// @param subtype the texture subtype. - /// @returns the multisampled texture - const ast::MultisampledTexture* multisampled_texture( - ast::TextureDimension dims, - const ast::Type* subtype) const { - return builder->create<ast::MultisampledTexture>(dims, subtype); - } - - /// @param source the Source of the node - /// @param dims the dimensionality of the texture - /// @param subtype the texture subtype. - /// @returns the multisampled texture - const ast::MultisampledTexture* multisampled_texture( - const Source& source, - ast::TextureDimension dims, - const ast::Type* subtype) const { - return builder->create<ast::MultisampledTexture>(source, dims, subtype); - } - - /// @param dims the dimensionality of the texture - /// @param format the texel format of the texture - /// @param access the access control of the texture - /// @returns the storage texture - const ast::StorageTexture* storage_texture(ast::TextureDimension dims, - ast::TexelFormat format, - ast::Access access) const { - auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); - return builder->create<ast::StorageTexture>(dims, format, subtype, - access); - } - - /// @param source the Source of the node - /// @param dims the dimensionality of the texture - /// @param format the texel format of the texture - /// @param access the access control of the texture - /// @returns the storage texture - const ast::StorageTexture* storage_texture(const Source& source, - ast::TextureDimension dims, - ast::TexelFormat format, - ast::Access access) const { - auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); - return builder->create<ast::StorageTexture>(source, dims, format, subtype, - access); - } - - /// @returns the external texture - const ast::ExternalTexture* external_texture() const { - return builder->create<ast::ExternalTexture>(); - } - - /// @param source the Source of the node - /// @returns the external texture - const ast::ExternalTexture* external_texture(const Source& source) const { - return builder->create<ast::ExternalTexture>(source); - } - - /// Constructs a TypeName for the type declaration. - /// @param type the type - /// @return either type or a pointer to a new ast::TypeName - const ast::TypeName* Of(const ast::TypeDecl* type) const; - - /// The ProgramBuilder - ProgramBuilder* const builder; - - private: - /// CToAST<T> is specialized for various `T` types and each specialization - /// contains a single static `get()` method for obtaining the corresponding - /// AST type for the C type `T`. - /// `get()` has the signature: - /// `static const ast::Type* get(Types* t)` - template <typename T> - struct CToAST {}; - }; - - ////////////////////////////////////////////////////////////////////////////// - // AST helper methods - ////////////////////////////////////////////////////////////////////////////// - - /// @return a new unnamed symbol - Symbol Sym() { return Symbols().New(); } - - /// @param name the symbol string - /// @return a Symbol with the given name - Symbol Sym(const std::string& name) { return Symbols().Register(name); } - - /// @param sym the symbol - /// @return `sym` - Symbol Sym(Symbol sym) { return sym; } - - /// @param expr the expression - /// @return expr - template <typename T> - traits::EnableIfIsType<T, ast::Expression>* Expr(T* expr) { - return expr; - } - - /// Passthrough for nullptr - /// @return nullptr - const ast::IdentifierExpression* Expr(std::nullptr_t) { return nullptr; } - - /// @param source the source information - /// @param symbol the identifier symbol - /// @return an ast::IdentifierExpression with the given symbol - const ast::IdentifierExpression* Expr(const Source& source, Symbol symbol) { - return create<ast::IdentifierExpression>(source, symbol); - } - - /// @param symbol the identifier symbol - /// @return an ast::IdentifierExpression with the given symbol - const ast::IdentifierExpression* Expr(Symbol symbol) { - return create<ast::IdentifierExpression>(symbol); - } - - /// @param source the source information - /// @param variable the AST variable - /// @return an ast::IdentifierExpression with the variable's symbol - const ast::IdentifierExpression* Expr(const Source& source, - const ast::Variable* variable) { - return create<ast::IdentifierExpression>(source, variable->symbol); - } - - /// @param variable the AST variable - /// @return an ast::IdentifierExpression with the variable's symbol - const ast::IdentifierExpression* Expr(const ast::Variable* variable) { - return create<ast::IdentifierExpression>(variable->symbol); - } - - /// @param source the source information - /// @param name the identifier name - /// @return an ast::IdentifierExpression with the given name - const ast::IdentifierExpression* Expr(const Source& source, - const char* name) { - return create<ast::IdentifierExpression>(source, Symbols().Register(name)); - } - - /// @param name the identifier name - /// @return an ast::IdentifierExpression with the given name - const ast::IdentifierExpression* Expr(const char* name) { - return create<ast::IdentifierExpression>(Symbols().Register(name)); - } - - /// @param source the source information - /// @param name the identifier name - /// @return an ast::IdentifierExpression with the given name - const ast::IdentifierExpression* Expr(const Source& source, - const std::string& name) { - return create<ast::IdentifierExpression>(source, Symbols().Register(name)); - } - - /// @param name the identifier name - /// @return an ast::IdentifierExpression with the given name - const ast::IdentifierExpression* Expr(const std::string& name) { - return create<ast::IdentifierExpression>(Symbols().Register(name)); - } - - /// @param source the source information - /// @param value the boolean value - /// @return a Scalar constructor for the given value - const ast::BoolLiteralExpression* Expr(const Source& source, bool value) { - return create<ast::BoolLiteralExpression>(source, value); - } - - /// @param value the boolean value - /// @return a Scalar constructor for the given value - const ast::BoolLiteralExpression* Expr(bool value) { - return create<ast::BoolLiteralExpression>(value); - } - - /// @param source the source information - /// @param value the float value - /// @return a Scalar constructor for the given value - const ast::FloatLiteralExpression* Expr(const Source& source, f32 value) { - return create<ast::FloatLiteralExpression>(source, value); - } - - /// @param value the float value - /// @return a Scalar constructor for the given value - const ast::FloatLiteralExpression* Expr(f32 value) { - return create<ast::FloatLiteralExpression>(value); - } - - /// @param source the source information - /// @param value the integer value - /// @return a Scalar constructor for the given value - const ast::SintLiteralExpression* Expr(const Source& source, i32 value) { - return create<ast::SintLiteralExpression>(source, value); - } - - /// @param value the integer value - /// @return a Scalar constructor for the given value - const ast::SintLiteralExpression* Expr(i32 value) { - return create<ast::SintLiteralExpression>(value); - } - - /// @param source the source information - /// @param value the unsigned int value - /// @return a Scalar constructor for the given value - const ast::UintLiteralExpression* Expr(const Source& source, u32 value) { - return create<ast::UintLiteralExpression>(source, value); - } - - /// @param value the unsigned int value - /// @return a Scalar constructor for the given value - const ast::UintLiteralExpression* Expr(u32 value) { - return create<ast::UintLiteralExpression>(value); - } - - /// Converts `arg` to an `ast::Expression` using `Expr()`, then appends it to - /// `list`. - /// @param list the list to append too - /// @param arg the arg to create - template <typename ARG> - void Append(ast::ExpressionList& list, ARG&& arg) { - list.emplace_back(Expr(std::forward<ARG>(arg))); - } - - /// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`, - /// then appends them to `list`. - /// @param list the list to append too - /// @param arg0 the first argument - /// @param args the rest of the arguments - template <typename ARG0, typename... ARGS> - void Append(ast::ExpressionList& list, ARG0&& arg0, ARGS&&... args) { - Append(list, std::forward<ARG0>(arg0)); - Append(list, std::forward<ARGS>(args)...); - } - - /// @return an empty list of expressions - ast::ExpressionList ExprList() { return {}; } - - /// @param args the list of expressions - /// @return the list of expressions converted to `ast::Expression`s using - /// `Expr()`, - template <typename... ARGS> - ast::ExpressionList ExprList(ARGS&&... args) { - ast::ExpressionList list; - list.reserve(sizeof...(args)); - Append(list, std::forward<ARGS>(args)...); - return list; - } - - /// @param list the list of expressions - /// @return `list` - ast::ExpressionList ExprList(ast::ExpressionList list) { return list; } - - /// @param args the arguments for the type constructor - /// @return an `ast::CallExpression` of type `ty`, with the values - /// of `args` converted to `ast::Expression`s using `Expr()` - template <typename T, typename... ARGS> - const ast::CallExpression* Construct(ARGS&&... args) { - return Construct(ty.Of<T>(), std::forward<ARGS>(args)...); - } - - /// @param type the type to construct - /// @param args the arguments for the constructor - /// @return an `ast::CallExpression` of `type` constructed with the - /// values `args`. - template <typename... ARGS> - const ast::CallExpression* Construct(const ast::Type* type, ARGS&&... args) { - return Construct(source_, type, std::forward<ARGS>(args)...); - } - - /// @param source the source information - /// @param type the type to construct - /// @param args the arguments for the constructor - /// @return an `ast::CallExpression` of `type` constructed with the - /// values `args`. - template <typename... ARGS> - const ast::CallExpression* Construct(const Source& source, - const ast::Type* type, - ARGS&&... args) { - return create<ast::CallExpression>(source, type, - ExprList(std::forward<ARGS>(args)...)); - } - - /// @param expr the expression for the bitcast - /// @return an `ast::BitcastExpression` of type `ty`, with the values of - /// `expr` converted to `ast::Expression`s using `Expr()` - template <typename T, typename EXPR> - const ast::BitcastExpression* Bitcast(EXPR&& expr) { - return Bitcast(ty.Of<T>(), std::forward<EXPR>(expr)); - } - - /// @param type the type to cast to - /// @param expr the expression for the bitcast - /// @return an `ast::BitcastExpression` of `type` constructed with the values - /// `expr`. - template <typename EXPR> - const ast::BitcastExpression* Bitcast(const ast::Type* type, EXPR&& expr) { - return create<ast::BitcastExpression>(type, Expr(std::forward<EXPR>(expr))); - } - - /// @param source the source information - /// @param type the type to cast to - /// @param expr the expression for the bitcast - /// @return an `ast::BitcastExpression` of `type` constructed with the values - /// `expr`. - template <typename EXPR> - const ast::BitcastExpression* Bitcast(const Source& source, - const ast::Type* type, - EXPR&& expr) { - return create<ast::BitcastExpression>(source, type, - Expr(std::forward<EXPR>(expr))); - } - - /// @param args the arguments for the vector constructor - /// @param type the vector type - /// @param size the vector size - /// @return an `ast::CallExpression` of a `size`-element vector of - /// type `type`, constructed with the values `args`. - template <typename... ARGS> - const ast::CallExpression* vec(const ast::Type* type, - uint32_t size, - ARGS&&... args) { - return Construct(ty.vec(type, size), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the vector constructor - /// @return an `ast::CallExpression` of a 2-element vector of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* vec2(ARGS&&... args) { - return Construct(ty.vec2<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the vector constructor - /// @return an `ast::CallExpression` of a 3-element vector of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* vec3(ARGS&&... args) { - return Construct(ty.vec3<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the vector constructor - /// @return an `ast::CallExpression` of a 4-element vector of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* vec4(ARGS&&... args) { - return Construct(ty.vec4<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 2x2 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat2x2(ARGS&&... args) { - return Construct(ty.mat2x2<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 2x3 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat2x3(ARGS&&... args) { - return Construct(ty.mat2x3<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 2x4 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat2x4(ARGS&&... args) { - return Construct(ty.mat2x4<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 3x2 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat3x2(ARGS&&... args) { - return Construct(ty.mat3x2<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 3x3 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat3x3(ARGS&&... args) { - return Construct(ty.mat3x3<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 3x4 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat3x4(ARGS&&... args) { - return Construct(ty.mat3x4<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 4x2 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat4x2(ARGS&&... args) { - return Construct(ty.mat4x2<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 4x3 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat4x3(ARGS&&... args) { - return Construct(ty.mat4x3<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the matrix constructor - /// @return an `ast::CallExpression` of a 4x4 matrix of type - /// `T`, constructed with the values `args`. - template <typename T, typename... ARGS> - const ast::CallExpression* mat4x4(ARGS&&... args) { - return Construct(ty.mat4x4<T>(), std::forward<ARGS>(args)...); - } - - /// @param args the arguments for the array constructor - /// @return an `ast::CallExpression` of an array with element type - /// `T` and size `N`, constructed with the values `args`. - template <typename T, int N, typename... ARGS> - const ast::CallExpression* array(ARGS&&... args) { - return Construct(ty.array<T, N>(), std::forward<ARGS>(args)...); - } - - /// @param subtype the array element type - /// @param n the array size. nullptr represents a runtime-array. - /// @param args the arguments for the array constructor - /// @return an `ast::CallExpression` of an array with element type - /// `subtype`, constructed with the values `args`. - template <typename EXPR, typename... ARGS> - const ast::CallExpression* array(const ast::Type* subtype, - EXPR&& n, - ARGS&&... args) { - return Construct(ty.array(subtype, std::forward<EXPR>(n)), - std::forward<ARGS>(args)...); - } - - /// @param name the variable name - /// @param type the variable type - /// @param optional the optional variable settings. - /// Can be any of the following, in any order: - /// * ast::StorageClass - specifies the variable storage class - /// * ast::Access - specifies the variable's access control - /// * ast::Expression* - specifies the variable's initializer expression - /// * ast::AttributeList - specifies the variable's attributes - /// Note that repeated arguments of the same type will use the last argument's - /// value. - /// @returns a `ast::Variable` with the given name, type and additional - /// options - template <typename NAME, typename... OPTIONAL> - const ast::Variable* Var(NAME&& name, - const ast::Type* type, - OPTIONAL&&... optional) { - VarOptionals opts(std::forward<OPTIONAL>(optional)...); - return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage, - opts.access, type, false /* is_const */, - false /* is_overridable */, opts.constructor, - std::move(opts.attributes)); - } - - /// @param source the variable source - /// @param name the variable name - /// @param type the variable type - /// @param optional the optional variable settings. - /// Can be any of the following, in any order: - /// * ast::StorageClass - specifies the variable storage class - /// * ast::Access - specifies the variable's access control - /// * ast::Expression* - specifies the variable's initializer expression - /// * ast::AttributeList - specifies the variable's attributes - /// Note that repeated arguments of the same type will use the last argument's - /// value. - /// @returns a `ast::Variable` with the given name, storage and type - template <typename NAME, typename... OPTIONAL> - const ast::Variable* Var(const Source& source, - NAME&& name, - const ast::Type* type, - OPTIONAL&&... optional) { - VarOptionals opts(std::forward<OPTIONAL>(optional)...); - return create<ast::Variable>( - source, Sym(std::forward<NAME>(name)), opts.storage, opts.access, type, - false /* is_const */, false /* is_overridable */, opts.constructor, - std::move(opts.attributes)); - } - - /// @param name the variable name - /// @param type the variable type - /// @param constructor constructor expression - /// @param attributes optional variable attributes - /// @returns an immutable `ast::Variable` with the given name and type - template <typename NAME> - const ast::Variable* Let(NAME&& name, - const ast::Type* type, - const ast::Expression* constructor, - ast::AttributeList attributes = {}) { - return create<ast::Variable>( - Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, - ast::Access::kUndefined, type, true /* is_const */, - false /* is_overridable */, constructor, attributes); - } - - /// @param source the variable source - /// @param name the variable name - /// @param type the variable type - /// @param constructor constructor expression - /// @param attributes optional variable attributes - /// @returns an immutable `ast::Variable` with the given name and type - template <typename NAME> - const ast::Variable* Let(const Source& source, - NAME&& name, - const ast::Type* type, - const ast::Expression* constructor, - ast::AttributeList attributes = {}) { - return create<ast::Variable>( - source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, - ast::Access::kUndefined, type, true /* is_const */, - false /* is_overridable */, constructor, attributes); - } - - /// @param name the parameter name - /// @param type the parameter type - /// @param attributes optional parameter attributes - /// @returns an immutable `ast::Variable` with the given name and type - template <typename NAME> - const ast::Variable* Param(NAME&& name, - const ast::Type* type, - ast::AttributeList attributes = {}) { - return create<ast::Variable>( - Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, - ast::Access::kUndefined, type, true /* is_const */, - false /* is_overridable */, nullptr, attributes); - } - - /// @param source the parameter source - /// @param name the parameter name - /// @param type the parameter type - /// @param attributes optional parameter attributes - /// @returns an immutable `ast::Variable` with the given name and type - template <typename NAME> - const ast::Variable* Param(const Source& source, + /// @param source the variable source + /// @param name the variable name + /// @param type the variable type + /// @param optional the optional variable settings. + /// Can be any of the following, in any order: + /// * ast::StorageClass - specifies the variable storage class + /// * ast::Access - specifies the variable's access control + /// * ast::Expression* - specifies the variable's initializer expression + /// * ast::AttributeList - specifies the variable's attributes + /// Note that repeated arguments of the same type will use the last argument's + /// value. + /// @returns a `ast::Variable` with the given name, storage and type + template <typename NAME, typename... OPTIONAL> + const ast::Variable* Var(const Source& source, NAME&& name, const ast::Type* type, + OPTIONAL&&... optional) { + VarOptionals opts(std::forward<OPTIONAL>(optional)...); + return create<ast::Variable>(source, Sym(std::forward<NAME>(name)), opts.storage, + opts.access, type, false /* is_const */, + false /* is_overridable */, opts.constructor, + std::move(opts.attributes)); + } + + /// @param name the variable name + /// @param type the variable type + /// @param constructor constructor expression + /// @param attributes optional variable attributes + /// @returns an immutable `ast::Variable` with the given name and type + template <typename NAME> + const ast::Variable* Let(NAME&& name, + const ast::Type* type, + const ast::Expression* constructor, ast::AttributeList attributes = {}) { - return create<ast::Variable>( - source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, - ast::Access::kUndefined, type, true /* is_const */, - false /* is_overridable */, nullptr, attributes); - } + return create<ast::Variable>(Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, + ast::Access::kUndefined, type, true /* is_const */, + false /* is_overridable */, constructor, attributes); + } - /// @param name the variable name - /// @param type the variable type - /// @param optional the optional variable settings. - /// Can be any of the following, in any order: - /// * ast::StorageClass - specifies the variable storage class - /// * ast::Access - specifies the variable's access control - /// * ast::Expression* - specifies the variable's initializer expression - /// * ast::AttributeList - specifies the variable's attributes - /// Note that repeated arguments of the same type will use the last argument's - /// value. - /// @returns a new `ast::Variable`, which is automatically registered as a - /// global variable with the ast::Module. - template <typename NAME, - typename... OPTIONAL, - typename = DisableIfSource<NAME>> - const ast::Variable* Global(NAME&& name, - const ast::Type* type, - OPTIONAL&&... optional) { - auto* var = Var(std::forward<NAME>(name), type, - std::forward<OPTIONAL>(optional)...); - AST().AddGlobalVariable(var); - return var; - } + /// @param source the variable source + /// @param name the variable name + /// @param type the variable type + /// @param constructor constructor expression + /// @param attributes optional variable attributes + /// @returns an immutable `ast::Variable` with the given name and type + template <typename NAME> + const ast::Variable* Let(const Source& source, + NAME&& name, + const ast::Type* type, + const ast::Expression* constructor, + ast::AttributeList attributes = {}) { + return create<ast::Variable>(source, Sym(std::forward<NAME>(name)), + ast::StorageClass::kNone, ast::Access::kUndefined, type, + true /* is_const */, false /* is_overridable */, constructor, + attributes); + } - /// @param source the variable source - /// @param name the variable name - /// @param type the variable type - /// @param optional the optional variable settings. - /// Can be any of the following, in any order: - /// * ast::StorageClass - specifies the variable storage class - /// * ast::Access - specifies the variable's access control - /// * ast::Expression* - specifies the variable's initializer expression - /// * ast::AttributeList - specifies the variable's attributes - /// Note that repeated arguments of the same type will use the last argument's - /// value. - /// @returns a new `ast::Variable`, which is automatically registered as a - /// global variable with the ast::Module. - template <typename NAME, typename... OPTIONAL> - const ast::Variable* Global(const Source& source, - NAME&& name, - const ast::Type* type, - OPTIONAL&&... optional) { - auto* var = Var(source, std::forward<NAME>(name), type, - std::forward<OPTIONAL>(optional)...); - AST().AddGlobalVariable(var); - return var; - } + /// @param name the parameter name + /// @param type the parameter type + /// @param attributes optional parameter attributes + /// @returns an immutable `ast::Variable` with the given name and type + template <typename NAME> + const ast::Variable* Param(NAME&& name, + const ast::Type* type, + ast::AttributeList attributes = {}) { + return create<ast::Variable>(Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, + ast::Access::kUndefined, type, true /* is_const */, + false /* is_overridable */, nullptr, attributes); + } - /// @param name the variable name - /// @param type the variable type - /// @param constructor constructor expression - /// @param attributes optional variable attributes - /// @returns a const `ast::Variable` constructed by calling Var() with the - /// arguments of `args`, which is automatically registered as a global - /// variable with the ast::Module. - template <typename NAME> - const ast::Variable* GlobalConst(NAME&& name, - const ast::Type* type, - const ast::Expression* constructor, - ast::AttributeList attributes = {}) { - auto* var = - Let(std::forward<NAME>(name), type, constructor, std::move(attributes)); - AST().AddGlobalVariable(var); - return var; - } + /// @param source the parameter source + /// @param name the parameter name + /// @param type the parameter type + /// @param attributes optional parameter attributes + /// @returns an immutable `ast::Variable` with the given name and type + template <typename NAME> + const ast::Variable* Param(const Source& source, + NAME&& name, + const ast::Type* type, + ast::AttributeList attributes = {}) { + return create<ast::Variable>(source, Sym(std::forward<NAME>(name)), + ast::StorageClass::kNone, ast::Access::kUndefined, type, + true /* is_const */, false /* is_overridable */, nullptr, + attributes); + } - /// @param source the variable source - /// @param name the variable name - /// @param type the variable type - /// @param constructor constructor expression - /// @param attributes optional variable attributes - /// @returns a const `ast::Variable` constructed by calling Var() with the - /// arguments of `args`, which is automatically registered as a global - /// variable with the ast::Module. - template <typename NAME> - const ast::Variable* GlobalConst(const Source& source, - NAME&& name, - const ast::Type* type, - const ast::Expression* constructor, - ast::AttributeList attributes = {}) { - auto* var = Let(source, std::forward<NAME>(name), type, constructor, - std::move(attributes)); - AST().AddGlobalVariable(var); - return var; - } + /// @param name the variable name + /// @param type the variable type + /// @param optional the optional variable settings. + /// Can be any of the following, in any order: + /// * ast::StorageClass - specifies the variable storage class + /// * ast::Access - specifies the variable's access control + /// * ast::Expression* - specifies the variable's initializer expression + /// * ast::AttributeList - specifies the variable's attributes + /// Note that repeated arguments of the same type will use the last argument's + /// value. + /// @returns a new `ast::Variable`, which is automatically registered as a + /// global variable with the ast::Module. + template <typename NAME, typename... OPTIONAL, typename = DisableIfSource<NAME>> + const ast::Variable* Global(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) { + auto* var = Var(std::forward<NAME>(name), type, std::forward<OPTIONAL>(optional)...); + AST().AddGlobalVariable(var); + return var; + } - /// @param name the variable name - /// @param type the variable type - /// @param constructor optional constructor expression - /// @param attributes optional variable attributes - /// @returns an overridable const `ast::Variable` which is automatically - /// registered as a global variable with the ast::Module. - template <typename NAME> - const ast::Variable* Override(NAME&& name, - const ast::Type* type, - const ast::Expression* constructor, - ast::AttributeList attributes = {}) { - auto* var = create<ast::Variable>( - source_, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, - ast::Access::kUndefined, type, true /* is_const */, - true /* is_overridable */, constructor, std::move(attributes)); - AST().AddGlobalVariable(var); - return var; - } - - /// @param source the variable source - /// @param name the variable name - /// @param type the variable type - /// @param constructor constructor expression - /// @param attributes optional variable attributes - /// @returns a const `ast::Variable` constructed by calling Var() with the - /// arguments of `args`, which is automatically registered as a global - /// variable with the ast::Module. - template <typename NAME> - const ast::Variable* Override(const Source& source, + /// @param source the variable source + /// @param name the variable name + /// @param type the variable type + /// @param optional the optional variable settings. + /// Can be any of the following, in any order: + /// * ast::StorageClass - specifies the variable storage class + /// * ast::Access - specifies the variable's access control + /// * ast::Expression* - specifies the variable's initializer expression + /// * ast::AttributeList - specifies the variable's attributes + /// Note that repeated arguments of the same type will use the last argument's + /// value. + /// @returns a new `ast::Variable`, which is automatically registered as a + /// global variable with the ast::Module. + template <typename NAME, typename... OPTIONAL> + const ast::Variable* Global(const Source& source, NAME&& name, const ast::Type* type, - const ast::Expression* constructor, - ast::AttributeList attributes = {}) { - auto* var = create<ast::Variable>( - source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, - ast::Access::kUndefined, type, true /* is_const */, - true /* is_overridable */, constructor, std::move(attributes)); - AST().AddGlobalVariable(var); - return var; - } + OPTIONAL&&... optional) { + auto* var = + Var(source, std::forward<NAME>(name), type, std::forward<OPTIONAL>(optional)...); + AST().AddGlobalVariable(var); + return var; + } - /// @param source the source information - /// @param expr the expression to take the address of - /// @return an ast::UnaryOpExpression that takes the address of `expr` - template <typename EXPR> - const ast::UnaryOpExpression* AddressOf(const Source& source, EXPR&& expr) { - return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kAddressOf, - Expr(std::forward<EXPR>(expr))); - } + /// @param name the variable name + /// @param type the variable type + /// @param constructor constructor expression + /// @param attributes optional variable attributes + /// @returns a const `ast::Variable` constructed by calling Var() with the + /// arguments of `args`, which is automatically registered as a global + /// variable with the ast::Module. + template <typename NAME> + const ast::Variable* GlobalConst(NAME&& name, + const ast::Type* type, + const ast::Expression* constructor, + ast::AttributeList attributes = {}) { + auto* var = Let(std::forward<NAME>(name), type, constructor, std::move(attributes)); + AST().AddGlobalVariable(var); + return var; + } - /// @param expr the expression to take the address of - /// @return an ast::UnaryOpExpression that takes the address of `expr` - template <typename EXPR> - const ast::UnaryOpExpression* AddressOf(EXPR&& expr) { - return create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, - Expr(std::forward<EXPR>(expr))); - } + /// @param source the variable source + /// @param name the variable name + /// @param type the variable type + /// @param constructor constructor expression + /// @param attributes optional variable attributes + /// @returns a const `ast::Variable` constructed by calling Var() with the + /// arguments of `args`, which is automatically registered as a global + /// variable with the ast::Module. + template <typename NAME> + const ast::Variable* GlobalConst(const Source& source, + NAME&& name, + const ast::Type* type, + const ast::Expression* constructor, + ast::AttributeList attributes = {}) { + auto* var = Let(source, std::forward<NAME>(name), type, constructor, std::move(attributes)); + AST().AddGlobalVariable(var); + return var; + } - /// @param source the source information - /// @param expr the expression to perform an indirection on - /// @return an ast::UnaryOpExpression that dereferences the pointer `expr` - template <typename EXPR> - const ast::UnaryOpExpression* Deref(const Source& source, EXPR&& expr) { - return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kIndirection, - Expr(std::forward<EXPR>(expr))); - } + /// @param name the variable name + /// @param type the variable type + /// @param constructor optional constructor expression + /// @param attributes optional variable attributes + /// @returns an overridable const `ast::Variable` which is automatically + /// registered as a global variable with the ast::Module. + template <typename NAME> + const ast::Variable* Override(NAME&& name, + const ast::Type* type, + const ast::Expression* constructor, + ast::AttributeList attributes = {}) { + auto* var = + create<ast::Variable>(source_, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, + ast::Access::kUndefined, type, true /* is_const */, + true /* is_overridable */, constructor, std::move(attributes)); + AST().AddGlobalVariable(var); + return var; + } - /// @param expr the expression to perform an indirection on - /// @return an ast::UnaryOpExpression that dereferences the pointer `expr` - template <typename EXPR> - const ast::UnaryOpExpression* Deref(EXPR&& expr) { - return create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, - Expr(std::forward<EXPR>(expr))); - } - - /// @param expr the expression to perform a unary not on - /// @return an ast::UnaryOpExpression that is the unary not of the input - /// expression - template <typename EXPR> - const ast::UnaryOpExpression* Not(EXPR&& expr) { - return create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, - Expr(std::forward<EXPR>(expr))); - } - - /// @param expr the expression to perform a unary complement on - /// @return an ast::UnaryOpExpression that is the unary complement of the - /// input expression - template <typename EXPR> - const ast::UnaryOpExpression* Complement(EXPR&& expr) { - return create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, - Expr(std::forward<EXPR>(expr))); - } - - /// @param source the source information - /// @param func the function name - /// @param args the function call arguments - /// @returns a `ast::CallExpression` to the function `func`, with the - /// arguments of `args` converted to `ast::Expression`s using `Expr()`. - template <typename NAME, typename... ARGS> - const ast::CallExpression* Call(const Source& source, - NAME&& func, - ARGS&&... args) { - return create<ast::CallExpression>(source, Expr(func), - ExprList(std::forward<ARGS>(args)...)); - } - - /// @param func the function name - /// @param args the function call arguments - /// @returns a `ast::CallExpression` to the function `func`, with the - /// arguments of `args` converted to `ast::Expression`s using `Expr()`. - template <typename NAME, typename... ARGS, typename = DisableIfSource<NAME>> - const ast::CallExpression* Call(NAME&& func, ARGS&&... args) { - return create<ast::CallExpression>(Expr(func), - ExprList(std::forward<ARGS>(args)...)); - } - - /// @param source the source information - /// @param call the call expression to wrap in a call statement - /// @returns a `ast::CallStatement` for the given call expression - const ast::CallStatement* CallStmt(const Source& source, - const ast::CallExpression* call) { - return create<ast::CallStatement>(source, call); - } - - /// @param call the call expression to wrap in a call statement - /// @returns a `ast::CallStatement` for the given call expression - const ast::CallStatement* CallStmt(const ast::CallExpression* call) { - return create<ast::CallStatement>(call); - } - - /// @param source the source information - /// @returns a `ast::PhonyExpression` - const ast::PhonyExpression* Phony(const Source& source) { - return create<ast::PhonyExpression>(source); - } - - /// @returns a `ast::PhonyExpression` - const ast::PhonyExpression* Phony() { return create<ast::PhonyExpression>(); } - - /// @param expr the expression to ignore - /// @returns a `ast::AssignmentStatement` that assigns 'expr' to the phony - /// (underscore) variable. - template <typename EXPR> - const ast::AssignmentStatement* Ignore(EXPR&& expr) { - return create<ast::AssignmentStatement>(Phony(), Expr(expr)); - } - - /// @param lhs the left hand argument to the addition operation - /// @param rhs the right hand argument to the addition operation - /// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Add(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kAdd, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the and operation - /// @param rhs the right hand argument to the and operation - /// @returns a `ast::BinaryExpression` bitwise anding `lhs` and `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* And(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kAnd, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the or operation - /// @param rhs the right hand argument to the or operation - /// @returns a `ast::BinaryExpression` bitwise or-ing `lhs` and `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Or(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kOr, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the subtraction operation - /// @param rhs the right hand argument to the subtraction operation - /// @returns a `ast::BinaryExpression` subtracting `rhs` from `lhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Sub(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kSubtract, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the multiplication operation - /// @param rhs the right hand argument to the multiplication operation - /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Mul(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param source the source information - /// @param lhs the left hand argument to the multiplication operation - /// @param rhs the right hand argument to the multiplication operation - /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Mul(const Source& source, LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(source, ast::BinaryOp::kMultiply, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the division operation - /// @param rhs the right hand argument to the division operation - /// @returns a `ast::BinaryExpression` dividing `lhs` by `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Div(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kDivide, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the modulo operation - /// @param rhs the right hand argument to the modulo operation - /// @returns a `ast::BinaryExpression` applying modulo of `lhs` by `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Mod(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kModulo, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the bit shift right operation - /// @param rhs the right hand argument to the bit shift right operation - /// @returns a `ast::BinaryExpression` bit shifting right `lhs` by `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Shr(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kShiftRight, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the bit shift left operation - /// @param rhs the right hand argument to the bit shift left operation - /// @returns a `ast::BinaryExpression` bit shifting left `lhs` by `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Shl(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kShiftLeft, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the xor operation - /// @param rhs the right hand argument to the xor operation - /// @returns a `ast::BinaryExpression` bitwise xor-ing `lhs` and `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Xor(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kXor, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the logical and operation - /// @param rhs the right hand argument to the logical and operation - /// @returns a `ast::BinaryExpression` of `lhs` && `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* LogicalAnd(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the logical or operation - /// @param rhs the right hand argument to the logical or operation - /// @returns a `ast::BinaryExpression` of `lhs` || `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* LogicalOr(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the greater than operation - /// @param rhs the right hand argument to the greater than operation - /// @returns a `ast::BinaryExpression` of `lhs` > `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* GreaterThan(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the greater than or equal operation - /// @param rhs the right hand argument to the greater than or equal operation - /// @returns a `ast::BinaryExpression` of `lhs` >= `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* GreaterThanEqual(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThanEqual, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the less than operation - /// @param rhs the right hand argument to the less than operation - /// @returns a `ast::BinaryExpression` of `lhs` < `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* LessThan(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kLessThan, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the less than or equal operation - /// @param rhs the right hand argument to the less than or equal operation - /// @returns a `ast::BinaryExpression` of `lhs` <= `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* LessThanEqual(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kLessThanEqual, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the equal expression - /// @param rhs the right hand argument to the equal expression - /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs` - template <typename LHS, typename RHS> - const ast::BinaryExpression* Equal(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kEqual, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param lhs the left hand argument to the not-equal expression - /// @param rhs the right hand argument to the not-equal expression - /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs` for - /// disequality - template <typename LHS, typename RHS> - const ast::BinaryExpression* NotEqual(LHS&& lhs, RHS&& rhs) { - return create<ast::BinaryExpression>(ast::BinaryOp::kNotEqual, - Expr(std::forward<LHS>(lhs)), - Expr(std::forward<RHS>(rhs))); - } - - /// @param source the source information - /// @param obj the object for the index accessor expression - /// @param idx the index argument for the index accessor expression - /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx` - template <typename OBJ, typename IDX> - const ast::IndexAccessorExpression* IndexAccessor(const Source& source, - OBJ&& obj, - IDX&& idx) { - return create<ast::IndexAccessorExpression>( - source, Expr(std::forward<OBJ>(obj)), Expr(std::forward<IDX>(idx))); - } - - /// @param obj the object for the index accessor expression - /// @param idx the index argument for the index accessor expression - /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx` - template <typename OBJ, typename IDX> - const ast::IndexAccessorExpression* IndexAccessor(OBJ&& obj, IDX&& idx) { - return create<ast::IndexAccessorExpression>(Expr(std::forward<OBJ>(obj)), - Expr(std::forward<IDX>(idx))); - } - - /// @param source the source information - /// @param obj the object for the member accessor expression - /// @param idx the index argument for the member accessor expression - /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx` - template <typename OBJ, typename IDX> - const ast::MemberAccessorExpression* MemberAccessor(const Source& source, - OBJ&& obj, - IDX&& idx) { - return create<ast::MemberAccessorExpression>( - source, Expr(std::forward<OBJ>(obj)), Expr(std::forward<IDX>(idx))); - } - - /// @param obj the object for the member accessor expression - /// @param idx the index argument for the member accessor expression - /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx` - template <typename OBJ, typename IDX> - const ast::MemberAccessorExpression* MemberAccessor(OBJ&& obj, IDX&& idx) { - return create<ast::MemberAccessorExpression>(Expr(std::forward<OBJ>(obj)), - Expr(std::forward<IDX>(idx))); - } - - /// Creates a ast::StructMemberOffsetAttribute - /// @param val the offset value - /// @returns the offset attribute pointer - const ast::StructMemberOffsetAttribute* MemberOffset(uint32_t val) { - return create<ast::StructMemberOffsetAttribute>(source_, val); - } - - /// Creates a ast::StructMemberSizeAttribute - /// @param source the source information - /// @param val the size value - /// @returns the size attribute pointer - const ast::StructMemberSizeAttribute* MemberSize(const Source& source, - uint32_t val) { - return create<ast::StructMemberSizeAttribute>(source, val); - } - - /// Creates a ast::StructMemberSizeAttribute - /// @param val the size value - /// @returns the size attribute pointer - const ast::StructMemberSizeAttribute* MemberSize(uint32_t val) { - return create<ast::StructMemberSizeAttribute>(source_, val); - } - - /// Creates a ast::StructMemberAlignAttribute - /// @param source the source information - /// @param val the align value - /// @returns the align attribute pointer - const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, - uint32_t val) { - return create<ast::StructMemberAlignAttribute>(source, val); - } - - /// Creates a ast::StructMemberAlignAttribute - /// @param val the align value - /// @returns the align attribute pointer - const ast::StructMemberAlignAttribute* MemberAlign(uint32_t val) { - return create<ast::StructMemberAlignAttribute>(source_, val); - } - - /// Creates the ast::GroupAttribute - /// @param value group attribute index - /// @returns the group attribute pointer - const ast::GroupAttribute* Group(uint32_t value) { - return create<ast::GroupAttribute>(value); - } - - /// Creates the ast::BindingAttribute - /// @param value the binding index - /// @returns the binding deocration pointer - const ast::BindingAttribute* Binding(uint32_t value) { - return create<ast::BindingAttribute>(value); - } - - /// Convenience function to create both a ast::GroupAttribute and - /// ast::BindingAttribute - /// @param group the group index - /// @param binding the binding index - /// @returns a attribute list with both the group and binding attributes - ast::AttributeList GroupAndBinding(uint32_t group, uint32_t binding) { - return {Group(group), Binding(binding)}; - } - - /// Creates an ast::Function and registers it with the ast::Module. - /// @param source the source information - /// @param name the function name - /// @param params the function parameters - /// @param type the function return type - /// @param body the function body - /// @param attributes the optional function attributes - /// @param return_type_attributes the optional function return type - /// attributes - /// @returns the function pointer - template <typename NAME> - const ast::Function* Func(const Source& source, - NAME&& name, - ast::VariableList params, - const ast::Type* type, - ast::StatementList body, - ast::AttributeList attributes = {}, - ast::AttributeList return_type_attributes = {}) { - auto* func = create<ast::Function>( - source, Sym(std::forward<NAME>(name)), params, type, - create<ast::BlockStatement>(body), attributes, return_type_attributes); - AST().AddFunction(func); - return func; - } - - /// Creates an ast::Function and registers it with the ast::Module. - /// @param name the function name - /// @param params the function parameters - /// @param type the function return type - /// @param body the function body - /// @param attributes the optional function attributes - /// @param return_type_attributes the optional function return type - /// attributes - /// @returns the function pointer - template <typename NAME> - const ast::Function* Func(NAME&& name, - ast::VariableList params, - const ast::Type* type, - ast::StatementList body, - ast::AttributeList attributes = {}, - ast::AttributeList return_type_attributes = {}) { - auto* func = create<ast::Function>(Sym(std::forward<NAME>(name)), params, - type, create<ast::BlockStatement>(body), - attributes, return_type_attributes); - AST().AddFunction(func); - return func; - } - - /// Creates an ast::BreakStatement - /// @param source the source information - /// @returns the break statement pointer - const ast::BreakStatement* Break(const Source& source) { - return create<ast::BreakStatement>(source); - } - - /// Creates an ast::BreakStatement - /// @returns the break statement pointer - const ast::BreakStatement* Break() { return create<ast::BreakStatement>(); } - - /// Creates an ast::ContinueStatement - /// @param source the source information - /// @returns the continue statement pointer - const ast::ContinueStatement* Continue(const Source& source) { - return create<ast::ContinueStatement>(source); - } - - /// Creates an ast::ContinueStatement - /// @returns the continue statement pointer - const ast::ContinueStatement* Continue() { - return create<ast::ContinueStatement>(); - } - - /// Creates an ast::ReturnStatement with no return value - /// @param source the source information - /// @returns the return statement pointer - const ast::ReturnStatement* Return(const Source& source) { - return create<ast::ReturnStatement>(source); - } - - /// Creates an ast::ReturnStatement with no return value - /// @returns the return statement pointer - const ast::ReturnStatement* Return() { - return create<ast::ReturnStatement>(); - } - - /// Creates an ast::ReturnStatement with the given return value - /// @param source the source information - /// @param val the return value - /// @returns the return statement pointer - template <typename EXPR> - const ast::ReturnStatement* Return(const Source& source, EXPR&& val) { - return create<ast::ReturnStatement>(source, Expr(std::forward<EXPR>(val))); - } - - /// Creates an ast::ReturnStatement with the given return value - /// @param val the return value - /// @returns the return statement pointer - template <typename EXPR, typename = DisableIfSource<EXPR>> - const ast::ReturnStatement* Return(EXPR&& val) { - return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val))); - } - - /// Creates an ast::DiscardStatement - /// @param source the source information - /// @returns the discard statement pointer - const ast::DiscardStatement* Discard(const Source& source) { - return create<ast::DiscardStatement>(source); - } - - /// Creates an ast::DiscardStatement - /// @returns the discard statement pointer - const ast::DiscardStatement* Discard() { - return create<ast::DiscardStatement>(); - } - - /// Creates a ast::Alias registering it with the AST().TypeDecls(). - /// @param source the source information - /// @param name the alias name - /// @param type the alias target type - /// @returns the alias type - template <typename NAME> - const ast::Alias* Alias(const Source& source, - NAME&& name, - const ast::Type* type) { - auto* out = ty.alias(source, std::forward<NAME>(name), type); - AST().AddTypeDecl(out); - return out; - } - - /// Creates a ast::Alias registering it with the AST().TypeDecls(). - /// @param name the alias name - /// @param type the alias target type - /// @returns the alias type - template <typename NAME> - const ast::Alias* Alias(NAME&& name, const ast::Type* type) { - auto* out = ty.alias(std::forward<NAME>(name), type); - AST().AddTypeDecl(out); - return out; - } - - /// Creates a ast::Struct registering it with the AST().TypeDecls(). - /// @param source the source information - /// @param name the struct name - /// @param members the struct members - /// @returns the struct type - template <typename NAME> - const ast::Struct* Structure(const Source& source, - NAME&& name, - ast::StructMemberList members) { - auto sym = Sym(std::forward<NAME>(name)); - auto* type = create<ast::Struct>(source, sym, std::move(members), - ast::AttributeList{}); - AST().AddTypeDecl(type); - return type; - } - - /// Creates a ast::Struct registering it with the AST().TypeDecls(). - /// @param name the struct name - /// @param members the struct members - /// @returns the struct type - template <typename NAME> - const ast::Struct* Structure(NAME&& name, ast::StructMemberList members) { - auto sym = Sym(std::forward<NAME>(name)); - auto* type = - create<ast::Struct>(sym, std::move(members), ast::AttributeList{}); - AST().AddTypeDecl(type); - return type; - } - - /// Creates a ast::StructMember - /// @param source the source information - /// @param name the struct member name - /// @param type the struct member type - /// @param attributes the optional struct member attributes - /// @returns the struct member pointer - template <typename NAME> - const ast::StructMember* Member(const Source& source, + /// @param source the variable source + /// @param name the variable name + /// @param type the variable type + /// @param constructor constructor expression + /// @param attributes optional variable attributes + /// @returns a const `ast::Variable` constructed by calling Var() with the + /// arguments of `args`, which is automatically registered as a global + /// variable with the ast::Module. + template <typename NAME> + const ast::Variable* Override(const Source& source, NAME&& name, const ast::Type* type, + const ast::Expression* constructor, ast::AttributeList attributes = {}) { - return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)), - type, std::move(attributes)); - } + auto* var = + create<ast::Variable>(source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone, + ast::Access::kUndefined, type, true /* is_const */, + true /* is_overridable */, constructor, std::move(attributes)); + AST().AddGlobalVariable(var); + return var; + } - /// Creates a ast::StructMember - /// @param name the struct member name - /// @param type the struct member type - /// @param attributes the optional struct member attributes - /// @returns the struct member pointer - template <typename NAME> - const ast::StructMember* Member(NAME&& name, - const ast::Type* type, - ast::AttributeList attributes = {}) { - return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), - type, std::move(attributes)); - } + /// @param source the source information + /// @param expr the expression to take the address of + /// @return an ast::UnaryOpExpression that takes the address of `expr` + template <typename EXPR> + const ast::UnaryOpExpression* AddressOf(const Source& source, EXPR&& expr) { + return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kAddressOf, + Expr(std::forward<EXPR>(expr))); + } - /// Creates a ast::StructMember with the given byte offset - /// @param offset the offset to use in the StructMemberOffsetattribute - /// @param name the struct member name - /// @param type the struct member type - /// @returns the struct member pointer - template <typename NAME> - const ast::StructMember* Member(uint32_t offset, - NAME&& name, - const ast::Type* type) { - return create<ast::StructMember>( - source_, Sym(std::forward<NAME>(name)), type, - ast::AttributeList{ - create<ast::StructMemberOffsetAttribute>(offset), - }); - } + /// @param expr the expression to take the address of + /// @return an ast::UnaryOpExpression that takes the address of `expr` + template <typename EXPR> + const ast::UnaryOpExpression* AddressOf(EXPR&& expr) { + return create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, + Expr(std::forward<EXPR>(expr))); + } - /// Creates a ast::BlockStatement with input statements - /// @param source the source information for the block - /// @param statements statements of block - /// @returns the block statement pointer - template <typename... Statements> - const ast::BlockStatement* Block(const Source& source, - Statements&&... statements) { - return create<ast::BlockStatement>( - source, ast::StatementList{std::forward<Statements>(statements)...}); - } + /// @param source the source information + /// @param expr the expression to perform an indirection on + /// @return an ast::UnaryOpExpression that dereferences the pointer `expr` + template <typename EXPR> + const ast::UnaryOpExpression* Deref(const Source& source, EXPR&& expr) { + return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kIndirection, + Expr(std::forward<EXPR>(expr))); + } - /// Creates a ast::BlockStatement with input statements - /// @param statements statements of block - /// @returns the block statement pointer - template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>> - const ast::BlockStatement* Block(STATEMENTS&&... statements) { - return create<ast::BlockStatement>( - ast::StatementList{std::forward<STATEMENTS>(statements)...}); - } + /// @param expr the expression to perform an indirection on + /// @return an ast::UnaryOpExpression that dereferences the pointer `expr` + template <typename EXPR> + const ast::UnaryOpExpression* Deref(EXPR&& expr) { + return create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, + Expr(std::forward<EXPR>(expr))); + } - /// Creates a ast::IfStatement with input condition, body, and optional - /// else statement - /// @param source the source information for the if statement - /// @param condition the if statement condition expression - /// @param body the if statement body - /// @param else_stmt optional else statement - /// @returns the if statement pointer - template <typename CONDITION> - const ast::IfStatement* If(const Source& source, - CONDITION&& condition, - const ast::BlockStatement* body, - const ast::Statement* else_stmt = nullptr) { - return create<ast::IfStatement>( - source, Expr(std::forward<CONDITION>(condition)), body, else_stmt); - } + /// @param expr the expression to perform a unary not on + /// @return an ast::UnaryOpExpression that is the unary not of the input + /// expression + template <typename EXPR> + const ast::UnaryOpExpression* Not(EXPR&& expr) { + return create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(std::forward<EXPR>(expr))); + } - /// Creates a ast::IfStatement with input condition, body, and optional - /// else statement - /// @param condition the if statement condition expression - /// @param body the if statement body - /// @param else_stmt optional else statement - /// @returns the if statement pointer - template <typename CONDITION> - const ast::IfStatement* If(CONDITION&& condition, - const ast::BlockStatement* body, - const ast::Statement* else_stmt = nullptr) { - return create<ast::IfStatement>(Expr(std::forward<CONDITION>(condition)), - body, else_stmt); - } + /// @param expr the expression to perform a unary complement on + /// @return an ast::UnaryOpExpression that is the unary complement of the + /// input expression + template <typename EXPR> + const ast::UnaryOpExpression* Complement(EXPR&& expr) { + return create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, + Expr(std::forward<EXPR>(expr))); + } - /// Creates a ast::AssignmentStatement with input lhs and rhs expressions - /// @param source the source information - /// @param lhs the left hand side expression initializer - /// @param rhs the right hand side expression initializer - /// @returns the assignment statement pointer - template <typename LhsExpressionInit, typename RhsExpressionInit> - const ast::AssignmentStatement* Assign(const Source& source, - LhsExpressionInit&& lhs, - RhsExpressionInit&& rhs) { - return create<ast::AssignmentStatement>( - source, Expr(std::forward<LhsExpressionInit>(lhs)), - Expr(std::forward<RhsExpressionInit>(rhs))); - } + /// @param source the source information + /// @param func the function name + /// @param args the function call arguments + /// @returns a `ast::CallExpression` to the function `func`, with the + /// arguments of `args` converted to `ast::Expression`s using `Expr()`. + template <typename NAME, typename... ARGS> + const ast::CallExpression* Call(const Source& source, NAME&& func, ARGS&&... args) { + return create<ast::CallExpression>(source, Expr(func), + ExprList(std::forward<ARGS>(args)...)); + } - /// Creates a ast::AssignmentStatement with input lhs and rhs expressions - /// @param lhs the left hand side expression initializer - /// @param rhs the right hand side expression initializer - /// @returns the assignment statement pointer - template <typename LhsExpressionInit, typename RhsExpressionInit> - const ast::AssignmentStatement* Assign(LhsExpressionInit&& lhs, - RhsExpressionInit&& rhs) { - return create<ast::AssignmentStatement>( - Expr(std::forward<LhsExpressionInit>(lhs)), - Expr(std::forward<RhsExpressionInit>(rhs))); - } + /// @param func the function name + /// @param args the function call arguments + /// @returns a `ast::CallExpression` to the function `func`, with the + /// arguments of `args` converted to `ast::Expression`s using `Expr()`. + template <typename NAME, typename... ARGS, typename = DisableIfSource<NAME>> + const ast::CallExpression* Call(NAME&& func, ARGS&&... args) { + return create<ast::CallExpression>(Expr(func), ExprList(std::forward<ARGS>(args)...)); + } - /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs - /// expressions, and a binary operator. - /// @param source the source information - /// @param lhs the left hand side expression initializer - /// @param rhs the right hand side expression initializer - /// @param op the binary operator - /// @returns the compound assignment statement pointer - template <typename LhsExpressionInit, typename RhsExpressionInit> - const ast::CompoundAssignmentStatement* CompoundAssign( - const Source& source, - LhsExpressionInit&& lhs, - RhsExpressionInit&& rhs, - ast::BinaryOp op) { - return create<ast::CompoundAssignmentStatement>( - source, Expr(std::forward<LhsExpressionInit>(lhs)), - Expr(std::forward<RhsExpressionInit>(rhs)), op); - } + /// @param source the source information + /// @param call the call expression to wrap in a call statement + /// @returns a `ast::CallStatement` for the given call expression + const ast::CallStatement* CallStmt(const Source& source, const ast::CallExpression* call) { + return create<ast::CallStatement>(source, call); + } - /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs - /// expressions, and a binary operator. - /// @param lhs the left hand side expression initializer - /// @param rhs the right hand side expression initializer - /// @param op the binary operator - /// @returns the compound assignment statement pointer - template <typename LhsExpressionInit, typename RhsExpressionInit> - const ast::CompoundAssignmentStatement* CompoundAssign( - LhsExpressionInit&& lhs, - RhsExpressionInit&& rhs, - ast::BinaryOp op) { - return create<ast::CompoundAssignmentStatement>( - Expr(std::forward<LhsExpressionInit>(lhs)), - Expr(std::forward<RhsExpressionInit>(rhs)), op); - } + /// @param call the call expression to wrap in a call statement + /// @returns a `ast::CallStatement` for the given call expression + const ast::CallStatement* CallStmt(const ast::CallExpression* call) { + return create<ast::CallStatement>(call); + } - /// Creates an ast::IncrementDecrementStatement with input lhs. - /// @param source the source information - /// @param lhs the left hand side expression initializer - /// @returns the increment decrement statement pointer - template <typename LhsExpressionInit> - const ast::IncrementDecrementStatement* Increment(const Source& source, - LhsExpressionInit&& lhs) { - return create<ast::IncrementDecrementStatement>( - source, Expr(std::forward<LhsExpressionInit>(lhs)), true); - } + /// @param source the source information + /// @returns a `ast::PhonyExpression` + const ast::PhonyExpression* Phony(const Source& source) { + return create<ast::PhonyExpression>(source); + } - /// Creates a ast::IncrementDecrementStatement with input lhs. - /// @param lhs the left hand side expression initializer - /// @returns the increment decrement statement pointer - template <typename LhsExpressionInit> - const ast::IncrementDecrementStatement* Increment(LhsExpressionInit&& lhs) { - return create<ast::IncrementDecrementStatement>( - Expr(std::forward<LhsExpressionInit>(lhs)), true); - } + /// @returns a `ast::PhonyExpression` + const ast::PhonyExpression* Phony() { return create<ast::PhonyExpression>(); } - /// Creates an ast::IncrementDecrementStatement with input lhs. - /// @param source the source information - /// @param lhs the left hand side expression initializer - /// @returns the increment decrement statement pointer - template <typename LhsExpressionInit> - const ast::IncrementDecrementStatement* Decrement(const Source& source, - LhsExpressionInit&& lhs) { - return create<ast::IncrementDecrementStatement>( - source, Expr(std::forward<LhsExpressionInit>(lhs)), false); - } + /// @param expr the expression to ignore + /// @returns a `ast::AssignmentStatement` that assigns 'expr' to the phony + /// (underscore) variable. + template <typename EXPR> + const ast::AssignmentStatement* Ignore(EXPR&& expr) { + return create<ast::AssignmentStatement>(Phony(), Expr(expr)); + } - /// Creates a ast::IncrementDecrementStatement with input lhs. - /// @param lhs the left hand side expression initializer - /// @returns the increment decrement statement pointer - template <typename LhsExpressionInit> - const ast::IncrementDecrementStatement* Decrement(LhsExpressionInit&& lhs) { - return create<ast::IncrementDecrementStatement>( - Expr(std::forward<LhsExpressionInit>(lhs)), false); - } + /// @param lhs the left hand argument to the addition operation + /// @param rhs the right hand argument to the addition operation + /// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Add(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kAdd, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::LoopStatement with input body and optional continuing - /// @param source the source information - /// @param body the loop body - /// @param continuing the optional continuing block - /// @returns the loop statement pointer - const ast::LoopStatement* Loop( - const Source& source, - const ast::BlockStatement* body, - const ast::BlockStatement* continuing = nullptr) { - return create<ast::LoopStatement>(source, body, continuing); - } + /// @param lhs the left hand argument to the and operation + /// @param rhs the right hand argument to the and operation + /// @returns a `ast::BinaryExpression` bitwise anding `lhs` and `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* And(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kAnd, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::LoopStatement with input body and optional continuing - /// @param body the loop body - /// @param continuing the optional continuing block - /// @returns the loop statement pointer - const ast::LoopStatement* Loop( - const ast::BlockStatement* body, - const ast::BlockStatement* continuing = nullptr) { - return create<ast::LoopStatement>(body, continuing); - } + /// @param lhs the left hand argument to the or operation + /// @param rhs the right hand argument to the or operation + /// @returns a `ast::BinaryExpression` bitwise or-ing `lhs` and `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Or(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kOr, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::ForLoopStatement with input body and optional initializer, - /// condition and continuing. - /// @param source the source information - /// @param init the optional loop initializer - /// @param cond the optional loop condition - /// @param cont the optional loop continuing - /// @param body the loop body - /// @returns the for loop statement pointer - template <typename COND> - const ast::ForLoopStatement* For(const Source& source, - const ast::Statement* init, - COND&& cond, - const ast::Statement* cont, - const ast::BlockStatement* body) { - return create<ast::ForLoopStatement>( - source, init, Expr(std::forward<COND>(cond)), cont, body); - } + /// @param lhs the left hand argument to the subtraction operation + /// @param rhs the right hand argument to the subtraction operation + /// @returns a `ast::BinaryExpression` subtracting `rhs` from `lhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Sub(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kSubtract, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::ForLoopStatement with input body and optional initializer, - /// condition and continuing. - /// @param init the optional loop initializer - /// @param cond the optional loop condition - /// @param cont the optional loop continuing - /// @param body the loop body - /// @returns the for loop statement pointer - template <typename COND> - const ast::ForLoopStatement* For(const ast::Statement* init, - COND&& cond, - const ast::Statement* cont, - const ast::BlockStatement* body) { - return create<ast::ForLoopStatement>(init, Expr(std::forward<COND>(cond)), - cont, body); - } + /// @param lhs the left hand argument to the multiplication operation + /// @param rhs the right hand argument to the multiplication operation + /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Mul(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::VariableDeclStatement for the input variable - /// @param source the source information - /// @param var the variable to wrap in a decl statement - /// @returns the variable decl statement pointer - const ast::VariableDeclStatement* Decl(const Source& source, - const ast::Variable* var) { - return create<ast::VariableDeclStatement>(source, var); - } + /// @param source the source information + /// @param lhs the left hand argument to the multiplication operation + /// @param rhs the right hand argument to the multiplication operation + /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Mul(const Source& source, LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(source, ast::BinaryOp::kMultiply, + Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::VariableDeclStatement for the input variable - /// @param var the variable to wrap in a decl statement - /// @returns the variable decl statement pointer - const ast::VariableDeclStatement* Decl(const ast::Variable* var) { - return create<ast::VariableDeclStatement>(var); - } + /// @param lhs the left hand argument to the division operation + /// @param rhs the right hand argument to the division operation + /// @returns a `ast::BinaryExpression` dividing `lhs` by `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Div(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kDivide, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::SwitchStatement with input expression and cases - /// @param source the source information - /// @param condition the condition expression initializer - /// @param cases case statements - /// @returns the switch statement pointer - template <typename ExpressionInit, typename... Cases> - const ast::SwitchStatement* Switch(const Source& source, - ExpressionInit&& condition, - Cases&&... cases) { - return create<ast::SwitchStatement>( - source, Expr(std::forward<ExpressionInit>(condition)), - ast::CaseStatementList{std::forward<Cases>(cases)...}); - } + /// @param lhs the left hand argument to the modulo operation + /// @param rhs the right hand argument to the modulo operation + /// @returns a `ast::BinaryExpression` applying modulo of `lhs` by `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Mod(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::SwitchStatement with input expression and cases - /// @param condition the condition expression initializer - /// @param cases case statements - /// @returns the switch statement pointer - template <typename ExpressionInit, - typename... Cases, - typename = DisableIfSource<ExpressionInit>> - const ast::SwitchStatement* Switch(ExpressionInit&& condition, - Cases&&... cases) { - return create<ast::SwitchStatement>( - Expr(std::forward<ExpressionInit>(condition)), - ast::CaseStatementList{std::forward<Cases>(cases)...}); - } + /// @param lhs the left hand argument to the bit shift right operation + /// @param rhs the right hand argument to the bit shift right operation + /// @returns a `ast::BinaryExpression` bit shifting right `lhs` by `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Shr(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>( + ast::BinaryOp::kShiftRight, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::CaseStatement with input list of selectors, and body - /// @param source the source information - /// @param selectors list of selectors - /// @param body the case body - /// @returns the case statement pointer - const ast::CaseStatement* Case(const Source& source, - ast::CaseSelectorList selectors, - const ast::BlockStatement* body = nullptr) { - return create<ast::CaseStatement>(source, std::move(selectors), - body ? body : Block()); - } + /// @param lhs the left hand argument to the bit shift left operation + /// @param rhs the right hand argument to the bit shift left operation + /// @returns a `ast::BinaryExpression` bit shifting left `lhs` by `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Shl(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>( + ast::BinaryOp::kShiftLeft, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs))); + } - /// Creates a ast::CaseStatement with input list of selectors, and body - /// @param selectors list of selectors - /// @param body the case body - /// @returns the case statement pointer - const ast::CaseStatement* Case(ast::CaseSelectorList selectors, - const ast::BlockStatement* body = nullptr) { - return create<ast::CaseStatement>(std::move(selectors), - body ? body : Block()); - } + /// @param lhs the left hand argument to the xor operation + /// @param rhs the right hand argument to the xor operation + /// @returns a `ast::BinaryExpression` bitwise xor-ing `lhs` and `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Xor(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kXor, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Convenient overload that takes a single selector - /// @param selector a single case selector - /// @param body the case body - /// @returns the case statement pointer - const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector, - const ast::BlockStatement* body = nullptr) { - return Case(ast::CaseSelectorList{selector}, body); - } + /// @param lhs the left hand argument to the logical and operation + /// @param rhs the right hand argument to the logical and operation + /// @returns a `ast::BinaryExpression` of `lhs` && `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* LogicalAnd(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>( + ast::BinaryOp::kLogicalAnd, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs))); + } - /// Convenience function that creates a 'default' ast::CaseStatement - /// @param source the source information - /// @param body the case body - /// @returns the case statement pointer - const ast::CaseStatement* DefaultCase( - const Source& source, - const ast::BlockStatement* body = nullptr) { - return Case(source, ast::CaseSelectorList{}, body); - } + /// @param lhs the left hand argument to the logical or operation + /// @param rhs the right hand argument to the logical or operation + /// @returns a `ast::BinaryExpression` of `lhs` || `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* LogicalOr(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>( + ast::BinaryOp::kLogicalOr, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs))); + } - /// Convenience function that creates a 'default' ast::CaseStatement - /// @param body the case body - /// @returns the case statement pointer - const ast::CaseStatement* DefaultCase( - const ast::BlockStatement* body = nullptr) { - return Case(ast::CaseSelectorList{}, body); - } + /// @param lhs the left hand argument to the greater than operation + /// @param rhs the right hand argument to the greater than operation + /// @returns a `ast::BinaryExpression` of `lhs` > `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* GreaterThan(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan, + Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates an ast::FallthroughStatement - /// @param source the source information - /// @returns the fallthrough statement pointer - const ast::FallthroughStatement* Fallthrough(const Source& source) { - return create<ast::FallthroughStatement>(source); - } + /// @param lhs the left hand argument to the greater than or equal operation + /// @param rhs the right hand argument to the greater than or equal operation + /// @returns a `ast::BinaryExpression` of `lhs` >= `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* GreaterThanEqual(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThanEqual, + Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates an ast::FallthroughStatement - /// @returns the fallthrough statement pointer - const ast::FallthroughStatement* Fallthrough() { - return create<ast::FallthroughStatement>(); - } + /// @param lhs the left hand argument to the less than operation + /// @param rhs the right hand argument to the less than operation + /// @returns a `ast::BinaryExpression` of `lhs` < `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* LessThan(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kLessThan, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates an ast::BuiltinAttribute - /// @param source the source information - /// @param builtin the builtin value - /// @returns the builtin attribute pointer - const ast::BuiltinAttribute* Builtin(const Source& source, - ast::Builtin builtin) { - return create<ast::BuiltinAttribute>(source, builtin); - } + /// @param lhs the left hand argument to the less than or equal operation + /// @param rhs the right hand argument to the less than or equal operation + /// @returns a `ast::BinaryExpression` of `lhs` <= `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* LessThanEqual(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kLessThanEqual, + Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates an ast::BuiltinAttribute - /// @param builtin the builtin value - /// @returns the builtin attribute pointer - const ast::BuiltinAttribute* Builtin(ast::Builtin builtin) { - return create<ast::BuiltinAttribute>(source_, builtin); - } + /// @param lhs the left hand argument to the equal expression + /// @param rhs the right hand argument to the equal expression + /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs` + template <typename LHS, typename RHS> + const ast::BinaryExpression* Equal(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates an ast::InterpolateAttribute - /// @param source the source information - /// @param type the interpolation type - /// @param sampling the interpolation sampling - /// @returns the interpolate attribute pointer - const ast::InterpolateAttribute* Interpolate( - const Source& source, - ast::InterpolationType type, - ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) { - return create<ast::InterpolateAttribute>(source, type, sampling); - } + /// @param lhs the left hand argument to the not-equal expression + /// @param rhs the right hand argument to the not-equal expression + /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs` for + /// disequality + template <typename LHS, typename RHS> + const ast::BinaryExpression* NotEqual(LHS&& lhs, RHS&& rhs) { + return create<ast::BinaryExpression>(ast::BinaryOp::kNotEqual, Expr(std::forward<LHS>(lhs)), + Expr(std::forward<RHS>(rhs))); + } - /// Creates an ast::InterpolateAttribute - /// @param type the interpolation type - /// @param sampling the interpolation sampling - /// @returns the interpolate attribute pointer - const ast::InterpolateAttribute* Interpolate( - ast::InterpolationType type, - ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) { - return create<ast::InterpolateAttribute>(source_, type, sampling); - } + /// @param source the source information + /// @param obj the object for the index accessor expression + /// @param idx the index argument for the index accessor expression + /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx` + template <typename OBJ, typename IDX> + const ast::IndexAccessorExpression* IndexAccessor(const Source& source, OBJ&& obj, IDX&& idx) { + return create<ast::IndexAccessorExpression>(source, Expr(std::forward<OBJ>(obj)), + Expr(std::forward<IDX>(idx))); + } - /// Creates an ast::InterpolateAttribute using flat interpolation - /// @param source the source information - /// @returns the interpolate attribute pointer - const ast::InterpolateAttribute* Flat(const Source& source) { - return Interpolate(source, ast::InterpolationType::kFlat); - } + /// @param obj the object for the index accessor expression + /// @param idx the index argument for the index accessor expression + /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx` + template <typename OBJ, typename IDX> + const ast::IndexAccessorExpression* IndexAccessor(OBJ&& obj, IDX&& idx) { + return create<ast::IndexAccessorExpression>(Expr(std::forward<OBJ>(obj)), + Expr(std::forward<IDX>(idx))); + } - /// Creates an ast::InterpolateAttribute using flat interpolation - /// @returns the interpolate attribute pointer - const ast::InterpolateAttribute* Flat() { - return Interpolate(ast::InterpolationType::kFlat); - } + /// @param source the source information + /// @param obj the object for the member accessor expression + /// @param idx the index argument for the member accessor expression + /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx` + template <typename OBJ, typename IDX> + const ast::MemberAccessorExpression* MemberAccessor(const Source& source, + OBJ&& obj, + IDX&& idx) { + return create<ast::MemberAccessorExpression>(source, Expr(std::forward<OBJ>(obj)), + Expr(std::forward<IDX>(idx))); + } - /// Creates an ast::InvariantAttribute - /// @param source the source information - /// @returns the invariant attribute pointer - const ast::InvariantAttribute* Invariant(const Source& source) { - return create<ast::InvariantAttribute>(source); - } + /// @param obj the object for the member accessor expression + /// @param idx the index argument for the member accessor expression + /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx` + template <typename OBJ, typename IDX> + const ast::MemberAccessorExpression* MemberAccessor(OBJ&& obj, IDX&& idx) { + return create<ast::MemberAccessorExpression>(Expr(std::forward<OBJ>(obj)), + Expr(std::forward<IDX>(idx))); + } - /// Creates an ast::InvariantAttribute - /// @returns the invariant attribute pointer - const ast::InvariantAttribute* Invariant() { - return create<ast::InvariantAttribute>(source_); - } + /// Creates a ast::StructMemberOffsetAttribute + /// @param val the offset value + /// @returns the offset attribute pointer + const ast::StructMemberOffsetAttribute* MemberOffset(uint32_t val) { + return create<ast::StructMemberOffsetAttribute>(source_, val); + } - /// Creates an ast::LocationAttribute - /// @param source the source information - /// @param location the location value - /// @returns the location attribute pointer - const ast::LocationAttribute* Location(const Source& source, - uint32_t location) { - return create<ast::LocationAttribute>(source, location); - } + /// Creates a ast::StructMemberSizeAttribute + /// @param source the source information + /// @param val the size value + /// @returns the size attribute pointer + const ast::StructMemberSizeAttribute* MemberSize(const Source& source, uint32_t val) { + return create<ast::StructMemberSizeAttribute>(source, val); + } - /// Creates an ast::LocationAttribute - /// @param location the location value - /// @returns the location attribute pointer - const ast::LocationAttribute* Location(uint32_t location) { - return create<ast::LocationAttribute>(source_, location); - } + /// Creates a ast::StructMemberSizeAttribute + /// @param val the size value + /// @returns the size attribute pointer + const ast::StructMemberSizeAttribute* MemberSize(uint32_t val) { + return create<ast::StructMemberSizeAttribute>(source_, val); + } - /// Creates an ast::IdAttribute - /// @param source the source information - /// @param id the id value - /// @returns the override attribute pointer - const ast::IdAttribute* Id(const Source& source, uint32_t id) { - return create<ast::IdAttribute>(source, id); - } + /// Creates a ast::StructMemberAlignAttribute + /// @param source the source information + /// @param val the align value + /// @returns the align attribute pointer + const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, uint32_t val) { + return create<ast::StructMemberAlignAttribute>(source, val); + } - /// Creates an ast::IdAttribute with a constant ID - /// @param id the optional id value - /// @returns the override attribute pointer - const ast::IdAttribute* Id(uint32_t id) { return Id(source_, id); } + /// Creates a ast::StructMemberAlignAttribute + /// @param val the align value + /// @returns the align attribute pointer + const ast::StructMemberAlignAttribute* MemberAlign(uint32_t val) { + return create<ast::StructMemberAlignAttribute>(source_, val); + } - /// Creates an ast::StageAttribute - /// @param source the source information - /// @param stage the pipeline stage - /// @returns the stage attribute pointer - const ast::StageAttribute* Stage(const Source& source, - ast::PipelineStage stage) { - return create<ast::StageAttribute>(source, stage); - } + /// Creates the ast::GroupAttribute + /// @param value group attribute index + /// @returns the group attribute pointer + const ast::GroupAttribute* Group(uint32_t value) { return create<ast::GroupAttribute>(value); } - /// Creates an ast::StageAttribute - /// @param stage the pipeline stage - /// @returns the stage attribute pointer - const ast::StageAttribute* Stage(ast::PipelineStage stage) { - return create<ast::StageAttribute>(source_, stage); - } + /// Creates the ast::BindingAttribute + /// @param value the binding index + /// @returns the binding deocration pointer + const ast::BindingAttribute* Binding(uint32_t value) { + return create<ast::BindingAttribute>(value); + } - /// Creates an ast::WorkgroupAttribute - /// @param x the x dimension expression - /// @returns the workgroup attribute pointer - template <typename EXPR_X> - const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x) { - return WorkgroupSize(std::forward<EXPR_X>(x), nullptr, nullptr); - } + /// Convenience function to create both a ast::GroupAttribute and + /// ast::BindingAttribute + /// @param group the group index + /// @param binding the binding index + /// @returns a attribute list with both the group and binding attributes + ast::AttributeList GroupAndBinding(uint32_t group, uint32_t binding) { + return {Group(group), Binding(binding)}; + } - /// Creates an ast::WorkgroupAttribute - /// @param x the x dimension expression - /// @param y the y dimension expression - /// @returns the workgroup attribute pointer - template <typename EXPR_X, typename EXPR_Y> - const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, EXPR_Y&& y) { - return WorkgroupSize(std::forward<EXPR_X>(x), std::forward<EXPR_Y>(y), - nullptr); - } + /// Creates an ast::Function and registers it with the ast::Module. + /// @param source the source information + /// @param name the function name + /// @param params the function parameters + /// @param type the function return type + /// @param body the function body + /// @param attributes the optional function attributes + /// @param return_type_attributes the optional function return type + /// attributes + /// @returns the function pointer + template <typename NAME> + const ast::Function* Func(const Source& source, + NAME&& name, + ast::VariableList params, + const ast::Type* type, + ast::StatementList body, + ast::AttributeList attributes = {}, + ast::AttributeList return_type_attributes = {}) { + auto* func = create<ast::Function>(source, Sym(std::forward<NAME>(name)), params, type, + create<ast::BlockStatement>(body), attributes, + return_type_attributes); + AST().AddFunction(func); + return func; + } - /// Creates an ast::WorkgroupAttribute - /// @param source the source information - /// @param x the x dimension expression - /// @param y the y dimension expression - /// @param z the z dimension expression - /// @returns the workgroup attribute pointer - template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z> - const ast::WorkgroupAttribute* WorkgroupSize(const Source& source, - EXPR_X&& x, - EXPR_Y&& y, - EXPR_Z&& z) { - return create<ast::WorkgroupAttribute>( - source, Expr(std::forward<EXPR_X>(x)), Expr(std::forward<EXPR_Y>(y)), - Expr(std::forward<EXPR_Z>(z))); - } + /// Creates an ast::Function and registers it with the ast::Module. + /// @param name the function name + /// @param params the function parameters + /// @param type the function return type + /// @param body the function body + /// @param attributes the optional function attributes + /// @param return_type_attributes the optional function return type + /// attributes + /// @returns the function pointer + template <typename NAME> + const ast::Function* Func(NAME&& name, + ast::VariableList params, + const ast::Type* type, + ast::StatementList body, + ast::AttributeList attributes = {}, + ast::AttributeList return_type_attributes = {}) { + auto* func = create<ast::Function>(Sym(std::forward<NAME>(name)), params, type, + create<ast::BlockStatement>(body), attributes, + return_type_attributes); + AST().AddFunction(func); + return func; + } - /// Creates an ast::WorkgroupAttribute - /// @param x the x dimension expression - /// @param y the y dimension expression - /// @param z the z dimension expression - /// @returns the workgroup attribute pointer - template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z> - const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, - EXPR_Y&& y, - EXPR_Z&& z) { - return create<ast::WorkgroupAttribute>( - source_, Expr(std::forward<EXPR_X>(x)), Expr(std::forward<EXPR_Y>(y)), - Expr(std::forward<EXPR_Z>(z))); - } + /// Creates an ast::BreakStatement + /// @param source the source information + /// @returns the break statement pointer + const ast::BreakStatement* Break(const Source& source) { + return create<ast::BreakStatement>(source); + } - /// Creates an ast::DisableValidationAttribute - /// @param validation the validation to disable - /// @returns the disable validation attribute pointer - const ast::DisableValidationAttribute* Disable( - ast::DisabledValidation validation) { - return ASTNodes().Create<ast::DisableValidationAttribute>(ID(), validation); - } + /// Creates an ast::BreakStatement + /// @returns the break statement pointer + const ast::BreakStatement* Break() { return create<ast::BreakStatement>(); } - /// Sets the current builder source to `src` - /// @param src the Source used for future create() calls - void SetSource(const Source& src) { - AssertNotMoved(); - source_ = src; - } + /// Creates an ast::ContinueStatement + /// @param source the source information + /// @returns the continue statement pointer + const ast::ContinueStatement* Continue(const Source& source) { + return create<ast::ContinueStatement>(source); + } - /// Sets the current builder source to `loc` - /// @param loc the Source used for future create() calls - void SetSource(const Source::Location& loc) { - AssertNotMoved(); - source_ = Source(loc); - } + /// Creates an ast::ContinueStatement + /// @returns the continue statement pointer + const ast::ContinueStatement* Continue() { return create<ast::ContinueStatement>(); } - /// Helper for returning the resolved semantic type of the expression `expr`. - /// @note As the Resolver is run when the Program is built, this will only be - /// useful for the Resolver itself and tests that use their own Resolver. - /// @param expr the AST expression - /// @return the resolved semantic type for the expression, or nullptr if the - /// expression has no resolved type. - const sem::Type* TypeOf(const ast::Expression* expr) const; + /// Creates an ast::ReturnStatement with no return value + /// @param source the source information + /// @returns the return statement pointer + const ast::ReturnStatement* Return(const Source& source) { + return create<ast::ReturnStatement>(source); + } - /// Helper for returning the resolved semantic type of the variable `var`. - /// @note As the Resolver is run when the Program is built, this will only be - /// useful for the Resolver itself and tests that use their own Resolver. - /// @param var the AST variable - /// @return the resolved semantic type for the variable, or nullptr if the - /// variable has no resolved type. - const sem::Type* TypeOf(const ast::Variable* var) const; + /// Creates an ast::ReturnStatement with no return value + /// @returns the return statement pointer + const ast::ReturnStatement* Return() { return create<ast::ReturnStatement>(); } - /// Helper for returning the resolved semantic type of the AST type `type`. - /// @note As the Resolver is run when the Program is built, this will only be - /// useful for the Resolver itself and tests that use their own Resolver. - /// @param type the AST type - /// @return the resolved semantic type for the type, or nullptr if the type - /// has no resolved type. - const sem::Type* TypeOf(const ast::Type* type) const; + /// Creates an ast::ReturnStatement with the given return value + /// @param source the source information + /// @param val the return value + /// @returns the return statement pointer + template <typename EXPR> + const ast::ReturnStatement* Return(const Source& source, EXPR&& val) { + return create<ast::ReturnStatement>(source, Expr(std::forward<EXPR>(val))); + } - /// Helper for returning the resolved semantic type of the AST type - /// declaration `type_decl`. - /// @note As the Resolver is run when the Program is built, this will only be - /// useful for the Resolver itself and tests that use their own Resolver. - /// @param type_decl the AST type declaration - /// @return the resolved semantic type for the type declaration, or nullptr if - /// the type declaration has no resolved type. - const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const; + /// Creates an ast::ReturnStatement with the given return value + /// @param val the return value + /// @returns the return statement pointer + template <typename EXPR, typename = DisableIfSource<EXPR>> + const ast::ReturnStatement* Return(EXPR&& val) { + return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val))); + } - /// Wraps the ast::Expression in a statement. This is used by tests that - /// construct a partial AST and require the Resolver to reach these - /// nodes. - /// @param expr the ast::Expression to be wrapped by an ast::Statement - /// @return the ast::Statement that wraps the ast::Expression - const ast::Statement* WrapInStatement(const ast::Expression* expr); - /// Wraps the ast::Variable in a ast::VariableDeclStatement. This is used by - /// tests that construct a partial AST and require the Resolver to reach - /// these nodes. - /// @param v the ast::Variable to be wrapped by an ast::VariableDeclStatement - /// @return the ast::VariableDeclStatement that wraps the ast::Variable - const ast::VariableDeclStatement* WrapInStatement(const ast::Variable* v); - /// Returns the statement argument. Used as a passthrough-overload by - /// WrapInFunction(). - /// @param stmt the ast::Statement - /// @return `stmt` - const ast::Statement* WrapInStatement(const ast::Statement* stmt); - /// Wraps the list of arguments in a simple function so that each is reachable - /// by the Resolver. - /// @param args a mix of ast::Expression, ast::Statement, ast::Variables. - /// @returns the function - template <typename... ARGS> - const ast::Function* WrapInFunction(ARGS&&... args) { - ast::StatementList stmts{WrapInStatement(std::forward<ARGS>(args))...}; - return WrapInFunction(std::move(stmts)); - } - /// @param stmts a list of ast::Statement that will be wrapped by a function, - /// so that each statement is reachable by the Resolver. - /// @returns the function - const ast::Function* WrapInFunction(ast::StatementList stmts); + /// Creates an ast::DiscardStatement + /// @param source the source information + /// @returns the discard statement pointer + const ast::DiscardStatement* Discard(const Source& source) { + return create<ast::DiscardStatement>(source); + } - /// The builder types - TypesBuilder const ty{this}; + /// Creates an ast::DiscardStatement + /// @returns the discard statement pointer + const ast::DiscardStatement* Discard() { return create<ast::DiscardStatement>(); } - protected: - /// Asserts that the builder has not been moved. - void AssertNotMoved() const; + /// Creates a ast::Alias registering it with the AST().TypeDecls(). + /// @param source the source information + /// @param name the alias name + /// @param type the alias target type + /// @returns the alias type + template <typename NAME> + const ast::Alias* Alias(const Source& source, NAME&& name, const ast::Type* type) { + auto* out = ty.alias(source, std::forward<NAME>(name), type); + AST().AddTypeDecl(out); + return out; + } - private: - ProgramID id_; - sem::Manager types_; - ASTNodeAllocator ast_nodes_; - SemNodeAllocator sem_nodes_; - ast::Module* ast_; - sem::Info sem_; - SymbolTable symbols_{id_}; - diag::List diagnostics_; + /// Creates a ast::Alias registering it with the AST().TypeDecls(). + /// @param name the alias name + /// @param type the alias target type + /// @returns the alias type + template <typename NAME> + const ast::Alias* Alias(NAME&& name, const ast::Type* type) { + auto* out = ty.alias(std::forward<NAME>(name), type); + AST().AddTypeDecl(out); + return out; + } - /// The source to use when creating AST nodes without providing a Source as - /// the first argument. - Source source_; + /// Creates a ast::Struct registering it with the AST().TypeDecls(). + /// @param source the source information + /// @param name the struct name + /// @param members the struct members + /// @returns the struct type + template <typename NAME> + const ast::Struct* Structure(const Source& source, NAME&& name, ast::StructMemberList members) { + auto sym = Sym(std::forward<NAME>(name)); + auto* type = create<ast::Struct>(source, sym, std::move(members), ast::AttributeList{}); + AST().AddTypeDecl(type); + return type; + } - /// Set by SetResolveOnBuild(). If set, the Resolver will be run on the - /// program when built. - bool resolve_on_build_ = true; + /// Creates a ast::Struct registering it with the AST().TypeDecls(). + /// @param name the struct name + /// @param members the struct members + /// @returns the struct type + template <typename NAME> + const ast::Struct* Structure(NAME&& name, ast::StructMemberList members) { + auto sym = Sym(std::forward<NAME>(name)); + auto* type = create<ast::Struct>(sym, std::move(members), ast::AttributeList{}); + AST().AddTypeDecl(type); + return type; + } - /// Set by MarkAsMoved(). Once set, no methods may be called on this builder. - bool moved_ = false; + /// Creates a ast::StructMember + /// @param source the source information + /// @param name the struct member name + /// @param type the struct member type + /// @param attributes the optional struct member attributes + /// @returns the struct member pointer + template <typename NAME> + const ast::StructMember* Member(const Source& source, + NAME&& name, + const ast::Type* type, + ast::AttributeList attributes = {}) { + return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)), type, + std::move(attributes)); + } + + /// Creates a ast::StructMember + /// @param name the struct member name + /// @param type the struct member type + /// @param attributes the optional struct member attributes + /// @returns the struct member pointer + template <typename NAME> + const ast::StructMember* Member(NAME&& name, + const ast::Type* type, + ast::AttributeList attributes = {}) { + return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type, + std::move(attributes)); + } + + /// Creates a ast::StructMember with the given byte offset + /// @param offset the offset to use in the StructMemberOffsetattribute + /// @param name the struct member name + /// @param type the struct member type + /// @returns the struct member pointer + template <typename NAME> + const ast::StructMember* Member(uint32_t offset, NAME&& name, const ast::Type* type) { + return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type, + ast::AttributeList{ + create<ast::StructMemberOffsetAttribute>(offset), + }); + } + + /// Creates a ast::BlockStatement with input statements + /// @param source the source information for the block + /// @param statements statements of block + /// @returns the block statement pointer + template <typename... Statements> + const ast::BlockStatement* Block(const Source& source, Statements&&... statements) { + return create<ast::BlockStatement>( + source, ast::StatementList{std::forward<Statements>(statements)...}); + } + + /// Creates a ast::BlockStatement with input statements + /// @param statements statements of block + /// @returns the block statement pointer + template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>> + const ast::BlockStatement* Block(STATEMENTS&&... statements) { + return create<ast::BlockStatement>( + ast::StatementList{std::forward<STATEMENTS>(statements)...}); + } + + /// Creates a ast::IfStatement with input condition, body, and optional + /// else statement + /// @param source the source information for the if statement + /// @param condition the if statement condition expression + /// @param body the if statement body + /// @param else_stmt optional else statement + /// @returns the if statement pointer + template <typename CONDITION> + const ast::IfStatement* If(const Source& source, + CONDITION&& condition, + const ast::BlockStatement* body, + const ast::Statement* else_stmt = nullptr) { + return create<ast::IfStatement>(source, Expr(std::forward<CONDITION>(condition)), body, + else_stmt); + } + + /// Creates a ast::IfStatement with input condition, body, and optional + /// else statement + /// @param condition the if statement condition expression + /// @param body the if statement body + /// @param else_stmt optional else statement + /// @returns the if statement pointer + template <typename CONDITION> + const ast::IfStatement* If(CONDITION&& condition, + const ast::BlockStatement* body, + const ast::Statement* else_stmt = nullptr) { + return create<ast::IfStatement>(Expr(std::forward<CONDITION>(condition)), body, else_stmt); + } + + /// Creates a ast::AssignmentStatement with input lhs and rhs expressions + /// @param source the source information + /// @param lhs the left hand side expression initializer + /// @param rhs the right hand side expression initializer + /// @returns the assignment statement pointer + template <typename LhsExpressionInit, typename RhsExpressionInit> + const ast::AssignmentStatement* Assign(const Source& source, + LhsExpressionInit&& lhs, + RhsExpressionInit&& rhs) { + return create<ast::AssignmentStatement>(source, Expr(std::forward<LhsExpressionInit>(lhs)), + Expr(std::forward<RhsExpressionInit>(rhs))); + } + + /// Creates a ast::AssignmentStatement with input lhs and rhs expressions + /// @param lhs the left hand side expression initializer + /// @param rhs the right hand side expression initializer + /// @returns the assignment statement pointer + template <typename LhsExpressionInit, typename RhsExpressionInit> + const ast::AssignmentStatement* Assign(LhsExpressionInit&& lhs, RhsExpressionInit&& rhs) { + return create<ast::AssignmentStatement>(Expr(std::forward<LhsExpressionInit>(lhs)), + Expr(std::forward<RhsExpressionInit>(rhs))); + } + + /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs + /// expressions, and a binary operator. + /// @param source the source information + /// @param lhs the left hand side expression initializer + /// @param rhs the right hand side expression initializer + /// @param op the binary operator + /// @returns the compound assignment statement pointer + template <typename LhsExpressionInit, typename RhsExpressionInit> + const ast::CompoundAssignmentStatement* CompoundAssign(const Source& source, + LhsExpressionInit&& lhs, + RhsExpressionInit&& rhs, + ast::BinaryOp op) { + return create<ast::CompoundAssignmentStatement>( + source, Expr(std::forward<LhsExpressionInit>(lhs)), + Expr(std::forward<RhsExpressionInit>(rhs)), op); + } + + /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs + /// expressions, and a binary operator. + /// @param lhs the left hand side expression initializer + /// @param rhs the right hand side expression initializer + /// @param op the binary operator + /// @returns the compound assignment statement pointer + template <typename LhsExpressionInit, typename RhsExpressionInit> + const ast::CompoundAssignmentStatement* CompoundAssign(LhsExpressionInit&& lhs, + RhsExpressionInit&& rhs, + ast::BinaryOp op) { + return create<ast::CompoundAssignmentStatement>(Expr(std::forward<LhsExpressionInit>(lhs)), + Expr(std::forward<RhsExpressionInit>(rhs)), + op); + } + + /// Creates an ast::IncrementDecrementStatement with input lhs. + /// @param source the source information + /// @param lhs the left hand side expression initializer + /// @returns the increment decrement statement pointer + template <typename LhsExpressionInit> + const ast::IncrementDecrementStatement* Increment(const Source& source, + LhsExpressionInit&& lhs) { + return create<ast::IncrementDecrementStatement>( + source, Expr(std::forward<LhsExpressionInit>(lhs)), true); + } + + /// Creates a ast::IncrementDecrementStatement with input lhs. + /// @param lhs the left hand side expression initializer + /// @returns the increment decrement statement pointer + template <typename LhsExpressionInit> + const ast::IncrementDecrementStatement* Increment(LhsExpressionInit&& lhs) { + return create<ast::IncrementDecrementStatement>(Expr(std::forward<LhsExpressionInit>(lhs)), + true); + } + + /// Creates an ast::IncrementDecrementStatement with input lhs. + /// @param source the source information + /// @param lhs the left hand side expression initializer + /// @returns the increment decrement statement pointer + template <typename LhsExpressionInit> + const ast::IncrementDecrementStatement* Decrement(const Source& source, + LhsExpressionInit&& lhs) { + return create<ast::IncrementDecrementStatement>( + source, Expr(std::forward<LhsExpressionInit>(lhs)), false); + } + + /// Creates a ast::IncrementDecrementStatement with input lhs. + /// @param lhs the left hand side expression initializer + /// @returns the increment decrement statement pointer + template <typename LhsExpressionInit> + const ast::IncrementDecrementStatement* Decrement(LhsExpressionInit&& lhs) { + return create<ast::IncrementDecrementStatement>(Expr(std::forward<LhsExpressionInit>(lhs)), + false); + } + + /// Creates a ast::LoopStatement with input body and optional continuing + /// @param source the source information + /// @param body the loop body + /// @param continuing the optional continuing block + /// @returns the loop statement pointer + const ast::LoopStatement* Loop(const Source& source, + const ast::BlockStatement* body, + const ast::BlockStatement* continuing = nullptr) { + return create<ast::LoopStatement>(source, body, continuing); + } + + /// Creates a ast::LoopStatement with input body and optional continuing + /// @param body the loop body + /// @param continuing the optional continuing block + /// @returns the loop statement pointer + const ast::LoopStatement* Loop(const ast::BlockStatement* body, + const ast::BlockStatement* continuing = nullptr) { + return create<ast::LoopStatement>(body, continuing); + } + + /// Creates a ast::ForLoopStatement with input body and optional initializer, + /// condition and continuing. + /// @param source the source information + /// @param init the optional loop initializer + /// @param cond the optional loop condition + /// @param cont the optional loop continuing + /// @param body the loop body + /// @returns the for loop statement pointer + template <typename COND> + const ast::ForLoopStatement* For(const Source& source, + const ast::Statement* init, + COND&& cond, + const ast::Statement* cont, + const ast::BlockStatement* body) { + return create<ast::ForLoopStatement>(source, init, Expr(std::forward<COND>(cond)), cont, + body); + } + + /// Creates a ast::ForLoopStatement with input body and optional initializer, + /// condition and continuing. + /// @param init the optional loop initializer + /// @param cond the optional loop condition + /// @param cont the optional loop continuing + /// @param body the loop body + /// @returns the for loop statement pointer + template <typename COND> + const ast::ForLoopStatement* For(const ast::Statement* init, + COND&& cond, + const ast::Statement* cont, + const ast::BlockStatement* body) { + return create<ast::ForLoopStatement>(init, Expr(std::forward<COND>(cond)), cont, body); + } + + /// Creates a ast::VariableDeclStatement for the input variable + /// @param source the source information + /// @param var the variable to wrap in a decl statement + /// @returns the variable decl statement pointer + const ast::VariableDeclStatement* Decl(const Source& source, const ast::Variable* var) { + return create<ast::VariableDeclStatement>(source, var); + } + + /// Creates a ast::VariableDeclStatement for the input variable + /// @param var the variable to wrap in a decl statement + /// @returns the variable decl statement pointer + const ast::VariableDeclStatement* Decl(const ast::Variable* var) { + return create<ast::VariableDeclStatement>(var); + } + + /// Creates a ast::SwitchStatement with input expression and cases + /// @param source the source information + /// @param condition the condition expression initializer + /// @param cases case statements + /// @returns the switch statement pointer + template <typename ExpressionInit, typename... Cases> + const ast::SwitchStatement* Switch(const Source& source, + ExpressionInit&& condition, + Cases&&... cases) { + return create<ast::SwitchStatement>(source, Expr(std::forward<ExpressionInit>(condition)), + ast::CaseStatementList{std::forward<Cases>(cases)...}); + } + + /// Creates a ast::SwitchStatement with input expression and cases + /// @param condition the condition expression initializer + /// @param cases case statements + /// @returns the switch statement pointer + template <typename ExpressionInit, + typename... Cases, + typename = DisableIfSource<ExpressionInit>> + const ast::SwitchStatement* Switch(ExpressionInit&& condition, Cases&&... cases) { + return create<ast::SwitchStatement>(Expr(std::forward<ExpressionInit>(condition)), + ast::CaseStatementList{std::forward<Cases>(cases)...}); + } + + /// Creates a ast::CaseStatement with input list of selectors, and body + /// @param source the source information + /// @param selectors list of selectors + /// @param body the case body + /// @returns the case statement pointer + const ast::CaseStatement* Case(const Source& source, + ast::CaseSelectorList selectors, + const ast::BlockStatement* body = nullptr) { + return create<ast::CaseStatement>(source, std::move(selectors), body ? body : Block()); + } + + /// Creates a ast::CaseStatement with input list of selectors, and body + /// @param selectors list of selectors + /// @param body the case body + /// @returns the case statement pointer + const ast::CaseStatement* Case(ast::CaseSelectorList selectors, + const ast::BlockStatement* body = nullptr) { + return create<ast::CaseStatement>(std::move(selectors), body ? body : Block()); + } + + /// Convenient overload that takes a single selector + /// @param selector a single case selector + /// @param body the case body + /// @returns the case statement pointer + const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector, + const ast::BlockStatement* body = nullptr) { + return Case(ast::CaseSelectorList{selector}, body); + } + + /// Convenience function that creates a 'default' ast::CaseStatement + /// @param source the source information + /// @param body the case body + /// @returns the case statement pointer + const ast::CaseStatement* DefaultCase(const Source& source, + const ast::BlockStatement* body = nullptr) { + return Case(source, ast::CaseSelectorList{}, body); + } + + /// Convenience function that creates a 'default' ast::CaseStatement + /// @param body the case body + /// @returns the case statement pointer + const ast::CaseStatement* DefaultCase(const ast::BlockStatement* body = nullptr) { + return Case(ast::CaseSelectorList{}, body); + } + + /// Creates an ast::FallthroughStatement + /// @param source the source information + /// @returns the fallthrough statement pointer + const ast::FallthroughStatement* Fallthrough(const Source& source) { + return create<ast::FallthroughStatement>(source); + } + + /// Creates an ast::FallthroughStatement + /// @returns the fallthrough statement pointer + const ast::FallthroughStatement* Fallthrough() { return create<ast::FallthroughStatement>(); } + + /// Creates an ast::BuiltinAttribute + /// @param source the source information + /// @param builtin the builtin value + /// @returns the builtin attribute pointer + const ast::BuiltinAttribute* Builtin(const Source& source, ast::Builtin builtin) { + return create<ast::BuiltinAttribute>(source, builtin); + } + + /// Creates an ast::BuiltinAttribute + /// @param builtin the builtin value + /// @returns the builtin attribute pointer + const ast::BuiltinAttribute* Builtin(ast::Builtin builtin) { + return create<ast::BuiltinAttribute>(source_, builtin); + } + + /// Creates an ast::InterpolateAttribute + /// @param source the source information + /// @param type the interpolation type + /// @param sampling the interpolation sampling + /// @returns the interpolate attribute pointer + const ast::InterpolateAttribute* Interpolate( + const Source& source, + ast::InterpolationType type, + ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) { + return create<ast::InterpolateAttribute>(source, type, sampling); + } + + /// Creates an ast::InterpolateAttribute + /// @param type the interpolation type + /// @param sampling the interpolation sampling + /// @returns the interpolate attribute pointer + const ast::InterpolateAttribute* Interpolate( + ast::InterpolationType type, + ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) { + return create<ast::InterpolateAttribute>(source_, type, sampling); + } + + /// Creates an ast::InterpolateAttribute using flat interpolation + /// @param source the source information + /// @returns the interpolate attribute pointer + const ast::InterpolateAttribute* Flat(const Source& source) { + return Interpolate(source, ast::InterpolationType::kFlat); + } + + /// Creates an ast::InterpolateAttribute using flat interpolation + /// @returns the interpolate attribute pointer + const ast::InterpolateAttribute* Flat() { return Interpolate(ast::InterpolationType::kFlat); } + + /// Creates an ast::InvariantAttribute + /// @param source the source information + /// @returns the invariant attribute pointer + const ast::InvariantAttribute* Invariant(const Source& source) { + return create<ast::InvariantAttribute>(source); + } + + /// Creates an ast::InvariantAttribute + /// @returns the invariant attribute pointer + const ast::InvariantAttribute* Invariant() { return create<ast::InvariantAttribute>(source_); } + + /// Creates an ast::LocationAttribute + /// @param source the source information + /// @param location the location value + /// @returns the location attribute pointer + const ast::LocationAttribute* Location(const Source& source, uint32_t location) { + return create<ast::LocationAttribute>(source, location); + } + + /// Creates an ast::LocationAttribute + /// @param location the location value + /// @returns the location attribute pointer + const ast::LocationAttribute* Location(uint32_t location) { + return create<ast::LocationAttribute>(source_, location); + } + + /// Creates an ast::IdAttribute + /// @param source the source information + /// @param id the id value + /// @returns the override attribute pointer + const ast::IdAttribute* Id(const Source& source, uint32_t id) { + return create<ast::IdAttribute>(source, id); + } + + /// Creates an ast::IdAttribute with a constant ID + /// @param id the optional id value + /// @returns the override attribute pointer + const ast::IdAttribute* Id(uint32_t id) { return Id(source_, id); } + + /// Creates an ast::StageAttribute + /// @param source the source information + /// @param stage the pipeline stage + /// @returns the stage attribute pointer + const ast::StageAttribute* Stage(const Source& source, ast::PipelineStage stage) { + return create<ast::StageAttribute>(source, stage); + } + + /// Creates an ast::StageAttribute + /// @param stage the pipeline stage + /// @returns the stage attribute pointer + const ast::StageAttribute* Stage(ast::PipelineStage stage) { + return create<ast::StageAttribute>(source_, stage); + } + + /// Creates an ast::WorkgroupAttribute + /// @param x the x dimension expression + /// @returns the workgroup attribute pointer + template <typename EXPR_X> + const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x) { + return WorkgroupSize(std::forward<EXPR_X>(x), nullptr, nullptr); + } + + /// Creates an ast::WorkgroupAttribute + /// @param x the x dimension expression + /// @param y the y dimension expression + /// @returns the workgroup attribute pointer + template <typename EXPR_X, typename EXPR_Y> + const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, EXPR_Y&& y) { + return WorkgroupSize(std::forward<EXPR_X>(x), std::forward<EXPR_Y>(y), nullptr); + } + + /// Creates an ast::WorkgroupAttribute + /// @param source the source information + /// @param x the x dimension expression + /// @param y the y dimension expression + /// @param z the z dimension expression + /// @returns the workgroup attribute pointer + template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z> + const ast::WorkgroupAttribute* WorkgroupSize(const Source& source, + EXPR_X&& x, + EXPR_Y&& y, + EXPR_Z&& z) { + return create<ast::WorkgroupAttribute>(source, Expr(std::forward<EXPR_X>(x)), + Expr(std::forward<EXPR_Y>(y)), + Expr(std::forward<EXPR_Z>(z))); + } + + /// Creates an ast::WorkgroupAttribute + /// @param x the x dimension expression + /// @param y the y dimension expression + /// @param z the z dimension expression + /// @returns the workgroup attribute pointer + template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z> + const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, EXPR_Y&& y, EXPR_Z&& z) { + return create<ast::WorkgroupAttribute>(source_, Expr(std::forward<EXPR_X>(x)), + Expr(std::forward<EXPR_Y>(y)), + Expr(std::forward<EXPR_Z>(z))); + } + + /// Creates an ast::DisableValidationAttribute + /// @param validation the validation to disable + /// @returns the disable validation attribute pointer + const ast::DisableValidationAttribute* Disable(ast::DisabledValidation validation) { + return ASTNodes().Create<ast::DisableValidationAttribute>(ID(), validation); + } + + /// Sets the current builder source to `src` + /// @param src the Source used for future create() calls + void SetSource(const Source& src) { + AssertNotMoved(); + source_ = src; + } + + /// Sets the current builder source to `loc` + /// @param loc the Source used for future create() calls + void SetSource(const Source::Location& loc) { + AssertNotMoved(); + source_ = Source(loc); + } + + /// Helper for returning the resolved semantic type of the expression `expr`. + /// @note As the Resolver is run when the Program is built, this will only be + /// useful for the Resolver itself and tests that use their own Resolver. + /// @param expr the AST expression + /// @return the resolved semantic type for the expression, or nullptr if the + /// expression has no resolved type. + const sem::Type* TypeOf(const ast::Expression* expr) const; + + /// Helper for returning the resolved semantic type of the variable `var`. + /// @note As the Resolver is run when the Program is built, this will only be + /// useful for the Resolver itself and tests that use their own Resolver. + /// @param var the AST variable + /// @return the resolved semantic type for the variable, or nullptr if the + /// variable has no resolved type. + const sem::Type* TypeOf(const ast::Variable* var) const; + + /// Helper for returning the resolved semantic type of the AST type `type`. + /// @note As the Resolver is run when the Program is built, this will only be + /// useful for the Resolver itself and tests that use their own Resolver. + /// @param type the AST type + /// @return the resolved semantic type for the type, or nullptr if the type + /// has no resolved type. + const sem::Type* TypeOf(const ast::Type* type) const; + + /// Helper for returning the resolved semantic type of the AST type + /// declaration `type_decl`. + /// @note As the Resolver is run when the Program is built, this will only be + /// useful for the Resolver itself and tests that use their own Resolver. + /// @param type_decl the AST type declaration + /// @return the resolved semantic type for the type declaration, or nullptr if + /// the type declaration has no resolved type. + const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const; + + /// Wraps the ast::Expression in a statement. This is used by tests that + /// construct a partial AST and require the Resolver to reach these + /// nodes. + /// @param expr the ast::Expression to be wrapped by an ast::Statement + /// @return the ast::Statement that wraps the ast::Expression + const ast::Statement* WrapInStatement(const ast::Expression* expr); + /// Wraps the ast::Variable in a ast::VariableDeclStatement. This is used by + /// tests that construct a partial AST and require the Resolver to reach + /// these nodes. + /// @param v the ast::Variable to be wrapped by an ast::VariableDeclStatement + /// @return the ast::VariableDeclStatement that wraps the ast::Variable + const ast::VariableDeclStatement* WrapInStatement(const ast::Variable* v); + /// Returns the statement argument. Used as a passthrough-overload by + /// WrapInFunction(). + /// @param stmt the ast::Statement + /// @return `stmt` + const ast::Statement* WrapInStatement(const ast::Statement* stmt); + /// Wraps the list of arguments in a simple function so that each is reachable + /// by the Resolver. + /// @param args a mix of ast::Expression, ast::Statement, ast::Variables. + /// @returns the function + template <typename... ARGS> + const ast::Function* WrapInFunction(ARGS&&... args) { + ast::StatementList stmts{WrapInStatement(std::forward<ARGS>(args))...}; + return WrapInFunction(std::move(stmts)); + } + /// @param stmts a list of ast::Statement that will be wrapped by a function, + /// so that each statement is reachable by the Resolver. + /// @returns the function + const ast::Function* WrapInFunction(ast::StatementList stmts); + + /// The builder types + TypesBuilder const ty{this}; + + protected: + /// Asserts that the builder has not been moved. + void AssertNotMoved() const; + + private: + ProgramID id_; + sem::Manager types_; + ASTNodeAllocator ast_nodes_; + SemNodeAllocator sem_nodes_; + ast::Module* ast_; + sem::Info sem_; + SymbolTable symbols_{id_}; + diag::List diagnostics_; + + /// The source to use when creating AST nodes without providing a Source as + /// the first argument. + Source source_; + + /// Set by SetResolveOnBuild(). If set, the Resolver will be run on the + /// program when built. + bool resolve_on_build_ = true; + + /// Set by MarkAsMoved(). Once set, no methods may be called on this builder. + bool moved_ = false; }; //! @cond Doxygen_Suppress // Various template specializations for ProgramBuilder::TypesBuilder::CToAST. template <> struct ProgramBuilder::TypesBuilder::CToAST<ProgramBuilder::i32> { - static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { - return t->i32(); - } + static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->i32(); } }; template <> struct ProgramBuilder::TypesBuilder::CToAST<ProgramBuilder::u32> { - static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { - return t->u32(); - } + static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->u32(); } }; template <> struct ProgramBuilder::TypesBuilder::CToAST<ProgramBuilder::f32> { - static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { - return t->f32(); - } + static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->f32(); } }; template <> struct ProgramBuilder::TypesBuilder::CToAST<bool> { - static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { - return t->bool_(); - } + static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->bool_(); } }; template <> struct ProgramBuilder::TypesBuilder::CToAST<void> { - static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { - return t->void_(); - } + static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->void_(); } }; //! @endcond /// @param builder the ProgramBuilder /// @returns the ProgramID of the ProgramBuilder inline ProgramID ProgramIDOf(const ProgramBuilder* builder) { - return builder->ID(); + return builder->ID(); } } // namespace tint