1 /*
2  * Copyright 2016 Google Inc.
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_EXPRESSION
9 #define SKSL_EXPRESSION
10 
11 #include "include/private/SkSLStatement.h"
12 #include "include/private/SkTHash.h"
13 #include "src/sksl/ir/SkSLType.h"
14 
15 #include <unordered_map>
16 
17 namespace SkSL {
18 
19 class AnyConstructor;
20 class Expression;
21 class IRGenerator;
22 class Variable;
23 
24 /**
25  * Abstract supertype of all expressions.
26  */
27 class Expression : public IRNode {
28 public:
29     enum class Kind {
30         kBinary = (int) Statement::Kind::kLast + 1,
31         kBoolLiteral,
32         kCodeString,
33         kConstructorArray,
34         kConstructorCompound,
35         kConstructorCompoundCast,
36         kConstructorDiagonalMatrix,
37         kConstructorMatrixResize,
38         kConstructorScalarCast,
39         kConstructorSplat,
40         kConstructorStruct,
41         kExternalFunctionCall,
42         kExternalFunctionReference,
43         kIntLiteral,
44         kFieldAccess,
45         kFloatLiteral,
46         kFunctionReference,
47         kFunctionCall,
48         kIndex,
49         kPrefix,
50         kPostfix,
51         kSetting,
52         kSwizzle,
53         kTernary,
54         kTypeReference,
55         kVariableReference,
56 
57         kFirst = kBinary,
58         kLast = kVariableReference
59     };
60 
61     enum class Property {
62         kSideEffects,
63         kContainsRTAdjust
64     };
65 
Expression(int offset,Kind kind,const Type * type)66     Expression(int offset, Kind kind, const Type* type)
67         : INHERITED(offset, (int) kind)
68         , fType(type) {
69         SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast);
70     }
71 
kind()72     Kind kind() const {
73         return (Kind) fKind;
74     }
75 
type()76     virtual const Type& type() const {
77         return *fType;
78     }
79 
80     /**
81      *  Use is<T> to check the type of an expression.
82      *  e.g. replace `e.kind() == Expression::Kind::kIntLiteral` with `e.is<IntLiteral>()`.
83      */
84     template <typename T>
is()85     bool is() const {
86         return this->kind() == T::kExpressionKind;
87     }
88 
isAnyConstructor()89     bool isAnyConstructor() const {
90         static_assert((int)Kind::kConstructorArray - 1 == (int)Kind::kCodeString);
91         static_assert((int)Kind::kConstructorStruct + 1 == (int)Kind::kExternalFunctionCall);
92         return this->kind() >= Kind::kConstructorArray && this->kind() <= Kind::kConstructorStruct;
93     }
94 
95     /**
96      *  Use as<T> to downcast expressions: e.g. replace `(IntLiteral&) i` with `i.as<IntLiteral>()`.
97      */
98     template <typename T>
as()99     const T& as() const {
100         SkASSERT(this->is<T>());
101         return static_cast<const T&>(*this);
102     }
103 
104     template <typename T>
as()105     T& as() {
106         SkASSERT(this->is<T>());
107         return static_cast<T&>(*this);
108     }
109 
110     AnyConstructor& asAnyConstructor();
111     const AnyConstructor& asAnyConstructor() const;
112 
113     /**
114      * Returns true if this expression is constant. compareConstant must be implemented for all
115      * constants!
116      */
isCompileTimeConstant()117     virtual bool isCompileTimeConstant() const {
118         return false;
119     }
120 
121     /**
122      * Compares this constant expression against another constant expression. Returns kUnknown if
123      * we aren't able to deduce a result (an expression isn't actually constant, the types are
124      * mismatched, etc).
125      */
126     enum class ComparisonResult {
127         kUnknown = -1,
128         kNotEqual,
129         kEqual
130     };
compareConstant(const Expression & other)131     virtual ComparisonResult compareConstant(const Expression& other) const {
132         return ComparisonResult::kUnknown;
133     }
134 
135     /**
136      * Returns true if, given fixed values for uniforms, this expression always evaluates to the
137      * same result with no side effects.
138      */
isConstantOrUniform()139     virtual bool isConstantOrUniform() const {
140         SkASSERT(!this->isCompileTimeConstant() || !this->hasSideEffects());
141         return this->isCompileTimeConstant();
142     }
143 
144     virtual bool hasProperty(Property property) const = 0;
145 
hasSideEffects()146     bool hasSideEffects() const {
147         return this->hasProperty(Property::kSideEffects);
148     }
149 
containsRTAdjust()150     bool containsRTAdjust() const {
151         return this->hasProperty(Property::kContainsRTAdjust);
152     }
153 
coercionCost(const Type & target)154     virtual CoercionCost coercionCost(const Type& target) const {
155         return this->type().coercionCost(target);
156     }
157 
158     /**
159      * Returns the n'th compile-time constant expression within a literal or constructor.
160      * Use Type::slotCount to determine the number of subexpressions within an expression.
161      * Subexpressions which are not compile-time constants will return null.
162      * `vec4(1, vec2(2), 3)` contains four subexpressions: (1, 2, 2, 3)
163      * `mat2(f)` contains four subexpressions: (null, 0,
164      *                                          0, null)
165      */
getConstantSubexpression(int n)166     virtual const Expression* getConstantSubexpression(int n) const {
167         return nullptr;
168     }
169 
170     virtual std::unique_ptr<Expression> clone() const = 0;
171 
172 private:
173     const Type* fType;
174 
175     using INHERITED = IRNode;
176 };
177 
178 }  // namespace SkSL
179 
180 #endif
181