1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SKSL_EXPRESSION 9*c8dee2aaSAndroid Build Coastguard Worker #define SKSL_EXPRESSION 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLPosition.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLIRNode.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLType.h" 15*c8dee2aaSAndroid Build Coastguard Worker 16*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 17*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 18*c8dee2aaSAndroid Build Coastguard Worker #include <optional> 19*c8dee2aaSAndroid Build Coastguard Worker #include <string> 20*c8dee2aaSAndroid Build Coastguard Worker 21*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL { 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker class AnyConstructor; 24*c8dee2aaSAndroid Build Coastguard Worker class Context; 25*c8dee2aaSAndroid Build Coastguard Worker enum class OperatorPrecedence : uint8_t; 26*c8dee2aaSAndroid Build Coastguard Worker 27*c8dee2aaSAndroid Build Coastguard Worker /** 28*c8dee2aaSAndroid Build Coastguard Worker * Abstract supertype of all expressions. 29*c8dee2aaSAndroid Build Coastguard Worker */ 30*c8dee2aaSAndroid Build Coastguard Worker class Expression : public IRNode { 31*c8dee2aaSAndroid Build Coastguard Worker public: 32*c8dee2aaSAndroid Build Coastguard Worker using Kind = ExpressionKind; 33*c8dee2aaSAndroid Build Coastguard Worker Expression(Position pos,Kind kind,const Type * type)34*c8dee2aaSAndroid Build Coastguard Worker Expression(Position pos, Kind kind, const Type* type) 35*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(pos, (int) kind) 36*c8dee2aaSAndroid Build Coastguard Worker , fType(type) { 37*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast); 38*c8dee2aaSAndroid Build Coastguard Worker } 39*c8dee2aaSAndroid Build Coastguard Worker kind()40*c8dee2aaSAndroid Build Coastguard Worker Kind kind() const { 41*c8dee2aaSAndroid Build Coastguard Worker return (Kind)fKind; 42*c8dee2aaSAndroid Build Coastguard Worker } 43*c8dee2aaSAndroid Build Coastguard Worker type()44*c8dee2aaSAndroid Build Coastguard Worker const Type& type() const { 45*c8dee2aaSAndroid Build Coastguard Worker return *fType; 46*c8dee2aaSAndroid Build Coastguard Worker } 47*c8dee2aaSAndroid Build Coastguard Worker isAnyConstructor()48*c8dee2aaSAndroid Build Coastguard Worker bool isAnyConstructor() const { 49*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)Kind::kConstructorArray - 1 == (int)Kind::kChildCall); 50*c8dee2aaSAndroid Build Coastguard Worker static_assert((int)Kind::kConstructorStruct + 1 == (int)Kind::kEmpty); 51*c8dee2aaSAndroid Build Coastguard Worker return this->kind() >= Kind::kConstructorArray && this->kind() <= Kind::kConstructorStruct; 52*c8dee2aaSAndroid Build Coastguard Worker } 53*c8dee2aaSAndroid Build Coastguard Worker isIntLiteral()54*c8dee2aaSAndroid Build Coastguard Worker bool isIntLiteral() const { 55*c8dee2aaSAndroid Build Coastguard Worker return this->kind() == Kind::kLiteral && this->type().isInteger(); 56*c8dee2aaSAndroid Build Coastguard Worker } 57*c8dee2aaSAndroid Build Coastguard Worker isFloatLiteral()58*c8dee2aaSAndroid Build Coastguard Worker bool isFloatLiteral() const { 59*c8dee2aaSAndroid Build Coastguard Worker return this->kind() == Kind::kLiteral && this->type().isFloat(); 60*c8dee2aaSAndroid Build Coastguard Worker } 61*c8dee2aaSAndroid Build Coastguard Worker isBoolLiteral()62*c8dee2aaSAndroid Build Coastguard Worker bool isBoolLiteral() const { 63*c8dee2aaSAndroid Build Coastguard Worker return this->kind() == Kind::kLiteral && this->type().isBoolean(); 64*c8dee2aaSAndroid Build Coastguard Worker } 65*c8dee2aaSAndroid Build Coastguard Worker 66*c8dee2aaSAndroid Build Coastguard Worker AnyConstructor& asAnyConstructor(); 67*c8dee2aaSAndroid Build Coastguard Worker const AnyConstructor& asAnyConstructor() const; 68*c8dee2aaSAndroid Build Coastguard Worker 69*c8dee2aaSAndroid Build Coastguard Worker /** 70*c8dee2aaSAndroid Build Coastguard Worker * Returns true if this expression is incomplete. Specifically, dangling function/method-call 71*c8dee2aaSAndroid Build Coastguard Worker * references that were never invoked, or type references that were never constructed, are 72*c8dee2aaSAndroid Build Coastguard Worker * considered incomplete expressions and should result in an error. 73*c8dee2aaSAndroid Build Coastguard Worker */ 74*c8dee2aaSAndroid Build Coastguard Worker bool isIncomplete(const Context& context) const; 75*c8dee2aaSAndroid Build Coastguard Worker 76*c8dee2aaSAndroid Build Coastguard Worker /** 77*c8dee2aaSAndroid Build Coastguard Worker * Compares this constant expression against another constant expression. Returns kUnknown if 78*c8dee2aaSAndroid Build Coastguard Worker * we aren't able to deduce a result (an expression isn't actually constant, the types are 79*c8dee2aaSAndroid Build Coastguard Worker * mismatched, etc). 80*c8dee2aaSAndroid Build Coastguard Worker */ 81*c8dee2aaSAndroid Build Coastguard Worker enum class ComparisonResult { 82*c8dee2aaSAndroid Build Coastguard Worker kUnknown = -1, 83*c8dee2aaSAndroid Build Coastguard Worker kNotEqual, 84*c8dee2aaSAndroid Build Coastguard Worker kEqual 85*c8dee2aaSAndroid Build Coastguard Worker }; compareConstant(const Expression & other)86*c8dee2aaSAndroid Build Coastguard Worker virtual ComparisonResult compareConstant(const Expression& other) const { 87*c8dee2aaSAndroid Build Coastguard Worker return ComparisonResult::kUnknown; 88*c8dee2aaSAndroid Build Coastguard Worker } 89*c8dee2aaSAndroid Build Coastguard Worker coercionCost(const Type & target)90*c8dee2aaSAndroid Build Coastguard Worker CoercionCost coercionCost(const Type& target) const { 91*c8dee2aaSAndroid Build Coastguard Worker return this->type().coercionCost(target); 92*c8dee2aaSAndroid Build Coastguard Worker } 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker /** 95*c8dee2aaSAndroid Build Coastguard Worker * Returns true if this expression type supports `getConstantValue`. (This particular expression 96*c8dee2aaSAndroid Build Coastguard Worker * may or may not actually contain a constant value.) It's harmless to call `getConstantValue` 97*c8dee2aaSAndroid Build Coastguard Worker * on expressions which don't support constant values or don't contain any constant values, but 98*c8dee2aaSAndroid Build Coastguard Worker * if `supportsConstantValues` returns false, you can assume that `getConstantValue` will return 99*c8dee2aaSAndroid Build Coastguard Worker * nullopt for every slot of this expression. This allows for early-out opportunities in some 100*c8dee2aaSAndroid Build Coastguard Worker * cases. (Some expressions have tons of slots but never hold a constant value; e.g. a variable 101*c8dee2aaSAndroid Build Coastguard Worker * holding a very large array.) 102*c8dee2aaSAndroid Build Coastguard Worker */ supportsConstantValues()103*c8dee2aaSAndroid Build Coastguard Worker virtual bool supportsConstantValues() const { 104*c8dee2aaSAndroid Build Coastguard Worker return false; 105*c8dee2aaSAndroid Build Coastguard Worker } 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker /** 108*c8dee2aaSAndroid Build Coastguard Worker * Returns the n'th compile-time constant value within a literal or constructor. 109*c8dee2aaSAndroid Build Coastguard Worker * Use Type::slotCount to determine the number of slots within an expression. 110*c8dee2aaSAndroid Build Coastguard Worker * Slots which do not contain compile-time constant values will return nullopt. 111*c8dee2aaSAndroid Build Coastguard Worker * `vec4(1, vec2(2), 3)` contains four compile-time constants: (1, 2, 2, 3) 112*c8dee2aaSAndroid Build Coastguard Worker * `mat2(f)` contains four slots, and two are constant: (nullopt, 0, 113*c8dee2aaSAndroid Build Coastguard Worker * 0, nullopt) 114*c8dee2aaSAndroid Build Coastguard Worker * All classes which override this function must also implement `supportsConstantValues`. 115*c8dee2aaSAndroid Build Coastguard Worker */ getConstantValue(int n)116*c8dee2aaSAndroid Build Coastguard Worker virtual std::optional<double> getConstantValue(int n) const { 117*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->supportsConstantValues()); 118*c8dee2aaSAndroid Build Coastguard Worker return std::nullopt; 119*c8dee2aaSAndroid Build Coastguard Worker } 120*c8dee2aaSAndroid Build Coastguard Worker 121*c8dee2aaSAndroid Build Coastguard Worker virtual std::unique_ptr<Expression> clone(Position pos) const = 0; 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker /** 124*c8dee2aaSAndroid Build Coastguard Worker * Returns a clone at the same position. 125*c8dee2aaSAndroid Build Coastguard Worker */ clone()126*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<Expression> clone() const { return this->clone(fPosition); } 127*c8dee2aaSAndroid Build Coastguard Worker 128*c8dee2aaSAndroid Build Coastguard Worker /** 129*c8dee2aaSAndroid Build Coastguard Worker * Returns a description of the expression. 130*c8dee2aaSAndroid Build Coastguard Worker */ 131*c8dee2aaSAndroid Build Coastguard Worker std::string description() const final; 132*c8dee2aaSAndroid Build Coastguard Worker virtual std::string description(OperatorPrecedence parentPrecedence) const = 0; 133*c8dee2aaSAndroid Build Coastguard Worker 134*c8dee2aaSAndroid Build Coastguard Worker 135*c8dee2aaSAndroid Build Coastguard Worker private: 136*c8dee2aaSAndroid Build Coastguard Worker const Type* fType; 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = IRNode; 139*c8dee2aaSAndroid Build Coastguard Worker }; 140*c8dee2aaSAndroid Build Coastguard Worker 141*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkSL 142*c8dee2aaSAndroid Build Coastguard Worker 143*c8dee2aaSAndroid Build Coastguard Worker #endif 144