| /* |
| * Copyright 2021 Google LLC. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SKSL_DSL_FUNCTION |
| #define SKSL_DSL_FUNCTION |
| |
| #include "include/sksl/DSLBlock.h" |
| #include "include/sksl/DSLExpression.h" |
| #include "include/sksl/DSLType.h" |
| #include "include/sksl/DSLVar.h" |
| #include "include/sksl/DSLWrapper.h" |
| |
| namespace SkSL { |
| |
| class Block; |
| class FunctionDeclaration; |
| class Variable; |
| |
| namespace dsl { |
| |
| class DSLType; |
| |
| class DSLFunction { |
| public: |
| template<class... Parameters> |
| DSLFunction(const DSLType& returnType, std::string_view name, Parameters&... parameters) |
| : DSLFunction(DSLModifiers(), returnType, name, parameters...) {} |
| |
| template<class... Parameters> |
| DSLFunction(const DSLModifiers& modifiers, const DSLType& returnType, std::string_view name, |
| Parameters&... parameters) { |
| SkTArray<DSLParameter*> parameterArray; |
| parameterArray.reserve_back(sizeof...(parameters)); |
| |
| // in C++17, we could just do: |
| // (parameterArray.push_back(¶meters), ...); |
| int unused[] = {0, (static_cast<void>(parameterArray.push_back(¶meters)), 0)...}; |
| static_cast<void>(unused); |
| // We can't have a default parameter and a template parameter pack at the same time, so |
| // unfortunately we can't capture position info from this overload. |
| this->init(modifiers, returnType, name, std::move(parameterArray), PositionInfo()); |
| } |
| |
| DSLFunction(const DSLType& returnType, std::string_view name, |
| SkTArray<DSLParameter*> parameters, PositionInfo pos = PositionInfo::Capture()) { |
| this->init(DSLModifiers(), returnType, name, std::move(parameters), pos); |
| } |
| |
| DSLFunction(const DSLModifiers& modifiers, const DSLType& returnType, std::string_view name, |
| SkTArray<DSLParameter*> parameters, PositionInfo pos = PositionInfo::Capture()) { |
| this->init(modifiers, returnType, name, std::move(parameters), pos); |
| } |
| |
| DSLFunction(const SkSL::FunctionDeclaration* decl) |
| : fDecl(decl) {} |
| |
| virtual ~DSLFunction() = default; |
| |
| template<class... Stmt> |
| void define(Stmt... stmts) { |
| DSLBlock block = DSLBlock(DSLStatement(std::move(stmts))...); |
| this->define(std::move(block)); |
| } |
| |
| void define(DSLBlock block, PositionInfo pos = PositionInfo::Capture()); |
| |
| /** |
| * Invokes the function with the given arguments. |
| */ |
| template<class... Args> |
| DSLExpression operator()(Args&&... args) { |
| ExpressionArray argArray; |
| argArray.reserve_back(sizeof...(args)); |
| this->collectArgs(argArray, std::forward<Args>(args)...); |
| return this->call(std::move(argArray)); |
| } |
| |
| /** |
| * Invokes the function with the given arguments. |
| */ |
| DSLExpression call(SkTArray<DSLWrapper<DSLExpression>> args, |
| PositionInfo pos = PositionInfo::Capture()); |
| |
| DSLExpression call(ExpressionArray args, PositionInfo pos = PositionInfo::Capture()); |
| |
| private: |
| void collectArgs(ExpressionArray& args) {} |
| |
| template<class... RemainingArgs> |
| void collectArgs(ExpressionArray& args, DSLVar& var, RemainingArgs&&... remaining) { |
| args.push_back(DSLExpression(var).release()); |
| collectArgs(args, std::forward<RemainingArgs>(remaining)...); |
| } |
| |
| template<class... RemainingArgs> |
| void collectArgs(ExpressionArray& args, DSLExpression expr, RemainingArgs&&... remaining) { |
| args.push_back(expr.release()); |
| collectArgs(args, std::forward<RemainingArgs>(remaining)...); |
| } |
| |
| void init(DSLModifiers modifiers, const DSLType& returnType, std::string_view name, |
| SkTArray<DSLParameter*> params, PositionInfo pos); |
| |
| const SkSL::FunctionDeclaration* fDecl = nullptr; |
| SkSL::PositionInfo fPosition; |
| }; |
| |
| } // namespace dsl |
| |
| } // namespace SkSL |
| |
| #endif |