1 /* 2 * Copyright 2021 Google LLC. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SKSL_DSL_FUNCTION 9 #define SKSL_DSL_FUNCTION 10 11 #include "include/sksl/DSLBlock.h" 12 #include "include/sksl/DSLExpression.h" 13 #include "include/sksl/DSLType.h" 14 #include "include/sksl/DSLVar.h" 15 #include "include/sksl/DSLWrapper.h" 16 17 namespace SkSL { 18 19 class Block; 20 class FunctionDeclaration; 21 class Variable; 22 23 namespace dsl { 24 25 class DSLType; 26 27 class DSLFunction { 28 public: 29 template<class... Parameters> DSLFunction(const DSLType & returnType,skstd::string_view name,Parameters &...parameters)30 DSLFunction(const DSLType& returnType, skstd::string_view name, Parameters&... parameters) 31 : DSLFunction(DSLModifiers(), returnType, name, parameters...) {} 32 33 template<class... Parameters> DSLFunction(const DSLModifiers & modifiers,const DSLType & returnType,skstd::string_view name,Parameters &...parameters)34 DSLFunction(const DSLModifiers& modifiers, const DSLType& returnType, skstd::string_view name, 35 Parameters&... parameters) { 36 SkTArray<DSLParameter*> parameterArray; 37 parameterArray.reserve_back(sizeof...(parameters)); 38 39 // in C++17, we could just do: 40 // (parameterArray.push_back(¶meters), ...); 41 int unused[] = {0, (static_cast<void>(parameterArray.push_back(¶meters)), 0)...}; 42 static_cast<void>(unused); 43 // We can't have a default parameter and a template parameter pack at the same time, so 44 // unfortunately we can't capture position info from this overload. 45 this->init(modifiers, returnType, name, std::move(parameterArray), PositionInfo()); 46 } 47 48 DSLFunction(const DSLType& returnType, skstd::string_view name, 49 SkTArray<DSLParameter*> parameters, PositionInfo pos = PositionInfo::Capture()) { 50 this->init(DSLModifiers(), returnType, name, std::move(parameters), pos); 51 } 52 53 DSLFunction(const DSLModifiers& modifiers, const DSLType& returnType, skstd::string_view name, 54 SkTArray<DSLParameter*> parameters, PositionInfo pos = PositionInfo::Capture()) { 55 this->init(modifiers, returnType, name, std::move(parameters), pos); 56 } 57 DSLFunction(const SkSL::FunctionDeclaration * decl)58 DSLFunction(const SkSL::FunctionDeclaration* decl) 59 : fDecl(decl) {} 60 61 virtual ~DSLFunction() = default; 62 63 template<class... Stmt> define(Stmt...stmts)64 void define(Stmt... stmts) { 65 DSLBlock block = DSLBlock(DSLStatement(std::move(stmts))...); 66 this->define(std::move(block)); 67 } 68 69 void define(DSLBlock block, PositionInfo pos = PositionInfo::Capture()); 70 71 /** 72 * Invokes the function with the given arguments. 73 */ 74 template<class... Args> operator()75 DSLExpression operator()(Args&&... args) { 76 ExpressionArray argArray; 77 argArray.reserve_back(sizeof...(args)); 78 this->collectArgs(argArray, std::forward<Args>(args)...); 79 return this->call(std::move(argArray)); 80 } 81 82 /** 83 * Invokes the function with the given arguments. 84 */ 85 DSLExpression call(SkTArray<DSLWrapper<DSLExpression>> args, 86 PositionInfo pos = PositionInfo::Capture()); 87 88 DSLExpression call(ExpressionArray args, PositionInfo pos = PositionInfo::Capture()); 89 90 private: collectArgs(ExpressionArray & args)91 void collectArgs(ExpressionArray& args) {} 92 93 template<class... RemainingArgs> collectArgs(ExpressionArray & args,DSLVar & var,RemainingArgs &&...remaining)94 void collectArgs(ExpressionArray& args, DSLVar& var, RemainingArgs&&... remaining) { 95 args.push_back(DSLExpression(var).release()); 96 collectArgs(args, std::forward<RemainingArgs>(remaining)...); 97 } 98 99 template<class... RemainingArgs> collectArgs(ExpressionArray & args,DSLExpression expr,RemainingArgs &&...remaining)100 void collectArgs(ExpressionArray& args, DSLExpression expr, RemainingArgs&&... remaining) { 101 args.push_back(expr.release()); 102 collectArgs(args, std::forward<RemainingArgs>(remaining)...); 103 } 104 105 void init(DSLModifiers modifiers, const DSLType& returnType, skstd::string_view name, 106 SkTArray<DSLParameter*> params, PositionInfo pos); 107 108 const SkSL::FunctionDeclaration* fDecl = nullptr; 109 SkSL::PositionInfo fPosition; 110 }; 111 112 } // namespace dsl 113 114 } // namespace SkSL 115 116 #endif 117