1/*
2 * Copyright 2019 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#include "src/sksl/SkSLSectionAndParameterHelper.h"
9#include "src/sksl/ir/SkSLBinaryExpression.h"
10#include "src/sksl/ir/SkSLConstructor.h"
11#include "src/sksl/ir/SkSLDoStatement.h"
12#include "src/sksl/ir/SkSLExpressionStatement.h"
13#include "src/sksl/ir/SkSLFieldAccess.h"
14#include "src/sksl/ir/SkSLForStatement.h"
15#include "src/sksl/ir/SkSLFunctionCall.h"
16#include "src/sksl/ir/SkSLIfStatement.h"
17#include "src/sksl/ir/SkSLIndexExpression.h"
18#include "src/sksl/ir/SkSLPostfixExpression.h"
19#include "src/sksl/ir/SkSLPrefixExpression.h"
20#include "src/sksl/ir/SkSLReturnStatement.h"
21#include "src/sksl/ir/SkSLSwitchStatement.h"
22#include "src/sksl/ir/SkSLSwizzle.h"
23#include "src/sksl/ir/SkSLTernaryExpression.h"
24#include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
25#include "src/sksl/ir/SkSLWhileStatement.h"
26
27namespace SkSL {
28
29SectionAndParameterHelper::SectionAndParameterHelper(const Program* program, ErrorReporter& errors)
30 : fProgram(*program) {
31 for (const auto& p : fProgram) {
32 switch (p.fKind) {
33 case ProgramElement::kVar_Kind: {
34 const VarDeclarations& decls = (const VarDeclarations&) p;
35 for (const auto& raw : decls.fVars) {
36 const VarDeclaration& decl = (VarDeclaration&) *raw;
37 if (IsParameter(*decl.fVar)) {
38 fParameters.push_back(decl.fVar);
39 }
40 }
41 break;
42 }
43 case ProgramElement::kSection_Kind: {
44 const Section& s = (const Section&) p;
45 if (IsSupportedSection(s.fName.c_str())) {
46 if (SectionRequiresArgument(s.fName.c_str()) && !s.fArgument.size()) {
47 errors.error(s.fOffset,
48 ("section '@" + s.fName +
49 "' requires one parameter").c_str());
50 }
51 if (!SectionAcceptsArgument(s.fName.c_str()) && s.fArgument.size()) {
52 errors.error(s.fOffset,
53 ("section '@" + s.fName + "' has no parameters").c_str());
54 }
55 } else {
56 errors.error(s.fOffset,
57 ("unsupported section '@" + s.fName + "'").c_str());
58 }
59 if (!SectionPermitsDuplicates(s.fName.c_str()) &&
60 fSections.find(s.fName) != fSections.end()) {
61 errors.error(s.fOffset,
62 ("duplicate section '@" + s.fName + "'").c_str());
63 }
64 fSections[s.fName].push_back(&s);
65 break;
66 }
67 default:
68 break;
69 }
70 }
71}
72
73bool SectionAndParameterHelper::hasCoordOverrides(const Variable& fp) {
74 for (const auto& pe : fProgram) {
75 if (this->hasCoordOverrides(pe, fp)) {
76 return true;
77 }
78 }
79 return false;
80}
81
82bool SectionAndParameterHelper::hasCoordOverrides(const ProgramElement& pe, const Variable& fp) {
83 if (pe.fKind == ProgramElement::kFunction_Kind) {
84 return this->hasCoordOverrides(*((const FunctionDefinition&) pe).fBody, fp);
85 }
86 return false;
87}
88
89bool SectionAndParameterHelper::hasCoordOverrides(const Expression& e, const Variable& fp) {
90 switch (e.fKind) {
91 case Expression::kFunctionCall_Kind: {
92 const FunctionCall& fc = (const FunctionCall&) e;
93 const FunctionDeclaration& f = fc.fFunction;
94 if (f.fBuiltin && f.fName == "sample" && fc.fArguments.size() >= 2 &&
95 fc.fArguments.back()->fType == *fProgram.fContext->fFloat2_Type &&
96 fc.fArguments[0]->fKind == Expression::kVariableReference_Kind &&
97 &((VariableReference&) *fc.fArguments[0]).fVariable == &fp) {
98 return true;
99 }
100 for (const auto& e : fc.fArguments) {
101 if (this->hasCoordOverrides(*e, fp)) {
102 return true;
103 }
104 }
105 return false;
106 }
107 case Expression::kConstructor_Kind: {
108 const Constructor& c = (const Constructor&) e;
109 for (const auto& e : c.fArguments) {
110 if (this->hasCoordOverrides(*e, fp)) {
111 return true;
112 }
113 }
114 return false;
115 }
116 case Expression::kFieldAccess_Kind: {
117 return this->hasCoordOverrides(*((const FieldAccess&) e).fBase, fp);
118 }
119 case Expression::kSwizzle_Kind:
120 return this->hasCoordOverrides(*((const Swizzle&) e).fBase, fp);
121 case Expression::kBinary_Kind: {
122 const BinaryExpression& b = (const BinaryExpression&) e;
123 return this->hasCoordOverrides(*b.fLeft, fp) ||
124 this->hasCoordOverrides(*b.fRight, fp);
125 }
126 case Expression::kIndex_Kind: {
127 const IndexExpression& idx = (const IndexExpression&) e;
128 return this->hasCoordOverrides(*idx.fBase, fp) ||
129 this->hasCoordOverrides(*idx.fIndex, fp);
130 }
131 case Expression::kPrefix_Kind:
132 return this->hasCoordOverrides(*((const PrefixExpression&) e).fOperand, fp);
133 case Expression::kPostfix_Kind:
134 return this->hasCoordOverrides(*((const PostfixExpression&) e).fOperand, fp);
135 case Expression::kTernary_Kind: {
136 const TernaryExpression& t = (const TernaryExpression&) e;
137 return this->hasCoordOverrides(*t.fTest, fp) ||
138 this->hasCoordOverrides(*t.fIfTrue, fp) ||
139 this->hasCoordOverrides(*t.fIfFalse, fp);
140 }
141 case Expression::kVariableReference_Kind:
142 return false;
143 case Expression::kBoolLiteral_Kind:
144 case Expression::kDefined_Kind:
145 case Expression::kExternalFunctionCall_Kind:
146 case Expression::kExternalValue_Kind:
147 case Expression::kFloatLiteral_Kind:
148 case Expression::kFunctionReference_Kind:
149 case Expression::kIntLiteral_Kind:
150 case Expression::kNullLiteral_Kind:
151 case Expression::kSetting_Kind:
152 case Expression::kTypeReference_Kind:
153 return false;
154 }
155 SkASSERT(false);
156 return false;
157}
158
159bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Variable& fp) {
160 switch (s.fKind) {
161 case Statement::kBlock_Kind: {
162 for (const auto& child : ((const Block&) s).fStatements) {
163 if (this->hasCoordOverrides(*child, fp)) {
164 return true;
165 }
166 }
167 return false;
168 }
169 case Statement::kVarDeclaration_Kind: {
170 const VarDeclaration& var = (const VarDeclaration&) s;
171 if (var.fValue) {
172 return hasCoordOverrides(*var.fValue, fp);
173 }
174 return false;
175 }
176 case Statement::kVarDeclarations_Kind: {
177 const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration;
178 for (const auto& stmt : decls.fVars) {
179 if (this->hasCoordOverrides(*stmt, fp)) {
180 return true;
181 }
182 }
183 return false;
184 }
185 case Statement::kExpression_Kind:
186 return this->hasCoordOverrides(*((const ExpressionStatement&) s).fExpression, fp);
187 case Statement::kReturn_Kind: {
188 const ReturnStatement& r = (const ReturnStatement&) s;
189 if (r.fExpression) {
190 return this->hasCoordOverrides(*r.fExpression, fp);
191 }
192 return false;
193 }
194 case Statement::kIf_Kind: {
195 const IfStatement& i = (const IfStatement&) s;
196 return this->hasCoordOverrides(*i.fTest, fp) ||
197 this->hasCoordOverrides(*i.fIfTrue, fp) ||
198 (i.fIfFalse && this->hasCoordOverrides(*i.fIfFalse, fp));
199 }
200 case Statement::kFor_Kind: {
201 const ForStatement& f = (const ForStatement&) s;
202 return this->hasCoordOverrides(*f.fInitializer, fp) ||
203 this->hasCoordOverrides(*f.fTest, fp) ||
204 this->hasCoordOverrides(*f.fNext, fp) ||
205 this->hasCoordOverrides(*f.fStatement, fp);
206 }
207 case Statement::kWhile_Kind: {
208 const WhileStatement& w = (const WhileStatement&) s;
209 return this->hasCoordOverrides(*w.fTest, fp) ||
210 this->hasCoordOverrides(*w.fStatement, fp);
211 }
212 case Statement::kDo_Kind: {
213 const DoStatement& d = (const DoStatement&) s;
214 return this->hasCoordOverrides(*d.fTest, fp) ||
215 this->hasCoordOverrides(*d.fStatement, fp);
216 }
217 case Statement::kSwitch_Kind: {
218 const SwitchStatement& sw = (const SwitchStatement&) s;
219 for (const auto& c : sw.fCases) {
220 for (const auto& st : c->fStatements) {
221 if (this->hasCoordOverrides(*st, fp)) {
222 return true;
223 }
224 }
225 }
226 return this->hasCoordOverrides(*sw.fValue, fp);
227 }
228 case Statement::kBreak_Kind:
229 case Statement::kContinue_Kind:
230 case Statement::kDiscard_Kind:
231 case Statement::kGroup_Kind:
232 case Statement::kNop_Kind:
233 return false;
234 }
235 SkASSERT(false);
236 return false;
237}
238
239}
240