Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkSLBinaryExpression.cpp
Go to the documentation of this file.
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
9
21
22namespace SkSL {
23
24std::unique_ptr<Expression> BinaryExpression::Convert(const Context& context,
26 std::unique_ptr<Expression> left,
27 Operator op,
28 std::unique_ptr<Expression> right) {
29 if (!left || !right) {
30 return nullptr;
31 }
32 const Type* rawLeftType = (left->isIntLiteral() && right->type().isInteger())
33 ? &right->type()
34 : &left->type();
35 const Type* rawRightType = (right->isIntLiteral() && left->type().isInteger())
36 ? &left->type()
37 : &right->type();
38
39 bool isAssignment = op.isAssignment();
40 if (isAssignment &&
42 op.kind() != Operator::Kind::EQ
43 ? VariableReference::RefKind::kReadWrite
44 : VariableReference::RefKind::kWrite,
45 context.fErrors)) {
46 return nullptr;
47 }
48
49 const Type* leftType;
50 const Type* rightType;
51 const Type* resultType;
52 if (!op.determineBinaryType(context, *rawLeftType, *rawRightType,
53 &leftType, &rightType, &resultType)) {
54 context.fErrors->error(pos, "type mismatch: '" + std::string(op.tightOperatorName()) +
55 "' cannot operate on '" + left->type().displayName() + "', '" +
56 right->type().displayName() + "'");
57 return nullptr;
58 }
59
60 if (isAssignment && (leftType->componentType().isOpaque() || leftType->isOrContainsAtomic())) {
61 context.fErrors->error(pos, "assignments to opaque type '" + left->type().displayName() +
62 "' are not permitted");
63 return nullptr;
64 }
65 if (context.fConfig->strictES2Mode() && !op.isAllowedInStrictES2Mode()) {
66 context.fErrors->error(pos, "operator '" + std::string(op.tightOperatorName()) +
67 "' is not allowed");
68 return nullptr;
69 }
70 if (context.fConfig->strictES2Mode() || op.kind() == OperatorKind::COMMA) {
71 // Most operators are already rejected on arrays, but GLSL ES 1.0 is very explicit that the
72 // *only* operator allowed on arrays is subscripting (and the rules against assignment,
73 // comparison, and even sequence apply to structs containing arrays as well).
74 // WebGL2 also restricts the usage of the sequence operator with arrays (section 5.26,
75 // "Disallowed variants of GLSL ES 3.00 operators"). Since there is very little practical
76 // application for sequenced array expressions, we disallow it in SkSL.
77 const Expression* arrayExpr = leftType->isOrContainsArray() ? left.get() :
78 rightType->isOrContainsArray() ? right.get() :
79 nullptr;
80 if (arrayExpr) {
81 context.fErrors->error(arrayExpr->position(),
82 "operator '" + std::string(op.tightOperatorName()) +
83 "' can not operate on arrays (or structs containing arrays)");
84 return nullptr;
85 }
86 }
87
88 left = leftType->coerceExpression(std::move(left), context);
89 right = rightType->coerceExpression(std::move(right), context);
90 if (!left || !right) {
91 return nullptr;
92 }
93
94 return BinaryExpression::Make(context, pos, std::move(left), op, std::move(right), resultType);
95}
96
97std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
99 std::unique_ptr<Expression> left,
100 Operator op,
101 std::unique_ptr<Expression> right) {
102 // Determine the result type of the binary expression.
103 const Type* leftType;
104 const Type* rightType;
105 const Type* resultType;
106 SkAssertResult(op.determineBinaryType(context, left->type(), right->type(),
107 &leftType, &rightType, &resultType));
108
109 return BinaryExpression::Make(context, pos, std::move(left), op, std::move(right), resultType);
110}
111
112std::unique_ptr<Expression> BinaryExpression::Make(const Context& context,
114 std::unique_ptr<Expression> left,
115 Operator op,
116 std::unique_ptr<Expression> right,
117 const Type* resultType) {
118 // We should have detected non-ES2 compliant behavior in Convert.
120 SkASSERT(!context.fConfig->strictES2Mode() || !left->type().isOrContainsArray());
121
122 // We should have detected non-assignable assignment expressions in Convert.
124 SkASSERT(!op.isAssignment() || !left->type().componentType().isOpaque());
125
126 // For simple assignments, detect and report out-of-range literal values.
127 if (op.kind() == Operator::Kind::EQ) {
128 left->type().checkForOutOfRangeLiteral(context, *right);
129 }
130
131 // Perform constant-folding on the expression.
132 if (std::unique_ptr<Expression> result = ConstantFolder::Simplify(context, pos, *left,
133 op, *right, *resultType)) {
134 return result;
135 }
136
137 return std::make_unique<BinaryExpression>(pos, std::move(left), op,
138 std::move(right), resultType);
139}
140
141bool BinaryExpression::CheckRef(const Expression& expr) {
142 switch (expr.kind()) {
143 case Expression::Kind::kFieldAccess:
144 return CheckRef(*expr.as<FieldAccess>().base());
145
146 case Expression::Kind::kIndex:
147 return CheckRef(*expr.as<IndexExpression>().base());
148
149 case Expression::Kind::kSwizzle:
150 return CheckRef(*expr.as<Swizzle>().base());
151
152 case Expression::Kind::kTernary: {
153 const TernaryExpression& t = expr.as<TernaryExpression>();
154 return CheckRef(*t.ifTrue()) && CheckRef(*t.ifFalse());
155 }
156 case Expression::Kind::kVariableReference: {
157 const VariableReference& ref = expr.as<VariableReference>();
158 return ref.refKind() == VariableRefKind::kWrite ||
159 ref.refKind() == VariableRefKind::kReadWrite;
160 }
161 default:
162 return false;
163 }
164}
165
166std::unique_ptr<Expression> BinaryExpression::clone(Position pos) const {
167 return std::make_unique<BinaryExpression>(pos,
168 this->left()->clone(),
169 this->getOperator(),
170 this->right()->clone(),
171 &this->type());
172}
173
174std::string BinaryExpression::description(OperatorPrecedence parentPrecedence) const {
175 OperatorPrecedence operatorPrecedence = this->getOperator().getBinaryPrecedence();
176 bool needsParens = (operatorPrecedence >= parentPrecedence);
177 return std::string(needsParens ? "(" : "") +
178 this->left()->description(operatorPrecedence) +
179 this->getOperator().operatorName() +
180 this->right()->description(operatorPrecedence) +
181 std::string(needsParens ? ")" : "");
182}
183
185 if (this->getOperator().isAssignment()) {
186 Analysis::AssignmentInfo assignmentInfo;
187 if (Analysis::IsAssignable(*this->left(), &assignmentInfo, /*errors=*/nullptr)) {
188 return assignmentInfo.fAssignedVar;
189 }
190 }
191 return nullptr;
192}
193
194} // namespace SkSL
SkPoint pos
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, std::unique_ptr< Expression > left, Operator op, std::unique_ptr< Expression > right)
std::unique_ptr< Expression > & left()
std::unique_ptr< Expression > & right()
static std::unique_ptr< Expression > Make(const Context &context, Position pos, std::unique_ptr< Expression > left, Operator op, std::unique_ptr< Expression > right)
VariableReference * isAssignmentIntoVariable()
static std::unique_ptr< Expression > Simplify(const Context &context, Position pos, const Expression &left, Operator op, const Expression &right, const Type &resultType)
ErrorReporter * fErrors
Definition SkSLContext.h:36
ProgramConfig * fConfig
Definition SkSLContext.h:33
void error(Position position, std::string_view msg)
Kind kind() const
virtual const Type & type() const
std::unique_ptr< Expression > clone() const
std::string description() const final
std::unique_ptr< Expression > & base()
Position position() const
Definition SkSLIRNode.h:111
const T & as() const
Definition SkSLIRNode.h:133
std::unique_ptr< Expression > & base()
Kind kind() const
std::string_view tightOperatorName() const
OperatorPrecedence getBinaryPrecedence() const
const char * operatorName() const
bool determineBinaryType(const Context &context, const Type &left, const Type &right, const Type **outLeftType, const Type **outRightType, const Type **outResultType) const
bool isAllowedInStrictES2Mode() const
bool isAssignment() const
std::unique_ptr< Expression > & base()
Definition SkSLSwizzle.h:82
std::unique_ptr< Expression > & ifTrue()
std::unique_ptr< Expression > & ifFalse()
std::unique_ptr< Expression > coerceExpression(std::unique_ptr< Expression > expr, const Context &context) const
virtual const Type & componentType() const
Definition SkSLType.h:404
virtual bool isOrContainsArray() const
Definition SkSLType.h:578
bool isOpaque() const
Definition SkSLType.h:353
virtual bool isOrContainsAtomic() const
Definition SkSLType.h:586
GAsyncResult * result
bool UpdateVariableRefKind(Expression *expr, VariableRefKind kind, ErrorReporter *errors=nullptr)
bool IsAssignable(Expression &expr, AssignmentInfo *info=nullptr, ErrorReporter *errors=nullptr)
OperatorPrecedence
VariableReference * fAssignedVar