92 {
94 public:
98
99 for (
const Variable* var :
function.parameters()) {
100 this->addLocalVariable(var,
pos);
101 }
102 }
103
104 ~Finalizer() override {
106 SkASSERT(fContinuableLevel == std::forward_list<int>{0});
107 }
108
109 void addLocalVariable(
const Variable* var, Position
pos) {
110 if (var->type().isOrContainsUnsizedArray()) {
111 fContext.fErrors->error(
pos,
"unsized arrays are not permitted here");
112 return;
113 }
114
115
116
117
118 size_t prevSlotsUsed = fSlotsUsed;
120
121
123 fContext.fErrors->error(
pos,
"variable '" + std::string(var->name()) +
124 "' exceeds the stack size limit");
125 }
126 }
127
128 void fuseVariableDeclarationsWithInitialization(std::unique_ptr<Statement>& stmt) {
129 switch (stmt->kind()) {
131 case Statement::Kind::kBlock:
132
133
134
135 break;
136
137 case Statement::Kind::kVarDeclaration:
138
139 if (VarDeclaration& decl = stmt->as<VarDeclaration>(); !decl.value()) {
140 fUninitializedVarDecl = &decl;
141 break;
142 }
143 [[fallthrough]];
144
145 default:
146
147
148 fUninitializedVarDecl = nullptr;
149 break;
150
151 case Statement::Kind::kExpression: {
152
153
154 if (fUninitializedVarDecl) {
155 VarDeclaration* vardecl = fUninitializedVarDecl;
156 fUninitializedVarDecl = nullptr;
157
158 std::unique_ptr<Expression>& nextExpr = stmt->as<ExpressionStatement>()
159 .expression();
160
161 if (!nextExpr->is<BinaryExpression>()) {
162 break;
163 }
164
165 BinaryExpression& binaryExpr = nextExpr->as<BinaryExpression>();
167 break;
168 }
169
170 Expression& leftExpr = *binaryExpr.left();
171 if (!leftExpr.is<VariableReference>()) {
172 break;
173 }
174
175 VariableReference& varRef = leftExpr.as<VariableReference>();
176 if (varRef.variable() != vardecl->var()) {
177 break;
178 }
179
180
182 break;
183 }
184
185
186 vardecl->value() = std::move(binaryExpr.right());
187
188
190 }
191 break;
192 }
193 }
194 }
195
196 bool functionReturnsValue() const {
197 return !fFunction.returnType().isVoid();
198 }
199
200 bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override {
201
202 return false;
203 }
204
205 bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override {
206
207
208
209 if (
fContext.fConfig->fSettings.fOptimize) {
210 this->fuseVariableDeclarationsWithInitialization(stmt);
211 }
212
213
214 switch (stmt->kind()) {
215 case Statement::Kind::kVarDeclaration:
216 this->addLocalVariable(stmt->as<VarDeclaration>().var(), stmt->fPosition);
217 break;
218
219 case Statement::Kind::kReturn: {
220
221
222
225 stmt->fPosition,
226 "early returns from vertex programs are not supported");
227 }
228
229
230 ReturnStatement& returnStmt = stmt->as<ReturnStatement>();
231 if (returnStmt.expression()) {
232 if (this->functionReturnsValue()) {
233
234 returnStmt.setExpression(fFunction.returnType().coerceExpression(
235 std::move(returnStmt.expression()),
fContext));
236 } else {
237
238 fContext.fErrors->error(returnStmt.expression()->fPosition,
239 "may not return a value from a void function");
240 returnStmt.setExpression(nullptr);
241 }
242 } else {
243 if (this->functionReturnsValue()) {
244
245 fContext.fErrors->error(returnStmt.fPosition,
246 "expected function to return '" +
247 fFunction.returnType().displayName() + "'");
248 }
249 }
250 break;
251 }
252 case Statement::Kind::kDo:
253 case Statement::Kind::kFor: {
254 ++fBreakableLevel;
255 ++fContinuableLevel.front();
256 bool result = INHERITED::visitStatementPtr(stmt);
257 --fContinuableLevel.front();
258 --fBreakableLevel;
260 }
261 case Statement::Kind::kSwitch: {
262 ++fBreakableLevel;
263 fContinuableLevel.push_front(0);
264 bool result = INHERITED::visitStatementPtr(stmt);
265 fContinuableLevel.pop_front();
266 --fBreakableLevel;
268 }
269 case Statement::Kind::kBreak:
270 if (fBreakableLevel == 0) {
271 fContext.fErrors->error(stmt->fPosition,
272 "break statement must be inside a loop or switch");
273 }
274 break;
275
277 if (fContinuableLevel.front() == 0) {
278 if (std::any_of(fContinuableLevel.begin(),
279 fContinuableLevel.end(),
280 [](
int level) { return level > 0; })) {
281 fContext.fErrors->error(stmt->fPosition,
282 "continue statement cannot be used in a switch");
283 } else {
284 fContext.fErrors->error(stmt->fPosition,
285 "continue statement must be inside a loop");
286 }
287 }
288 break;
289
290 default:
291 break;
292 }
293 return INHERITED::visitStatementPtr(stmt);
294 }
295
296 private:
298 const FunctionDeclaration& fFunction;
299
300 int fBreakableLevel = 0;
301
302 size_t fSlotsUsed = 0;
303
304
305 std::forward_list<int> fContinuableLevel{0};
306
307
308 VarDeclaration* fUninitializedVarDecl = nullptr;
309
311 };
312
313
314
316 context.fErrors->error(
function.fPosition,
"Intrinsic function '" +
318 "' should not have a definition");
319 return nullptr;
320 }
321
322
323
325 context.fErrors->error(
function.fPosition,
"function body '" +
function.description() +
326 "' must be a braced block");
327 return nullptr;
328 }
329
330
332 context.fErrors->error(
function.fPosition,
"function '" +
function.description() +
333 "' was already defined");
334 return nullptr;
335 }
336
337
338
342 }
343
345 context.fErrors->error(
body->fPosition,
"function '" + std::string(
function.name()) +
346 "' can exit without returning a value");
347 }
348
350}
#define INHERITED(method,...)
static std::unique_ptr< FunctionDefinition > Make(const Context &context, Position pos, const FunctionDeclaration &function, std::unique_ptr< Statement > body, bool builtin)
static std::unique_ptr< Statement > Make()
static size_t Add(size_t x, size_t y)
Dart_NativeFunction function
bool ContainsVariable(const Expression &expr, const Variable &var)
bool CanExitWithoutReturningValue(const FunctionDeclaration &funcDecl, const Statement &body)
static constexpr int kVariableSlotLimit
static void append_rtadjust_fixup_to_vertex_main(const Context &context, const FunctionDeclaration &decl, Block &body)
static void Finalizer(void *isolate_callback_data, void *buffer)
static bool IsVertex(ProgramKind kind)