| Index: src/sksl/SkSLIRGenerator.cpp
|
| diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
|
| index d64684e62dc3312ed3c885c46f9d064026799664..6307087edd9d4f97233d1ea16f20aed848dc5b04 100644
|
| --- a/src/sksl/SkSLIRGenerator.cpp
|
| +++ b/src/sksl/SkSLIRGenerator.cpp
|
| @@ -42,8 +42,8 @@
|
| #include "ir/SkSLTernaryExpression.h"
|
| #include "ir/SkSLUnresolvedFunction.h"
|
| #include "ir/SkSLVariable.h"
|
| -#include "ir/SkSLVarDeclaration.h"
|
| -#include "ir/SkSLVarDeclarationStatement.h"
|
| +#include "ir/SkSLVarDeclarations.h"
|
| +#include "ir/SkSLVarDeclarationsStatement.h"
|
| #include "ir/SkSLVariableReference.h"
|
| #include "ir/SkSLWhileStatement.h"
|
|
|
| @@ -66,11 +66,26 @@ public:
|
| std::shared_ptr<SymbolTable> fPrevious;
|
| };
|
|
|
| +class AutoLoopLevel {
|
| +public:
|
| + AutoLoopLevel(IRGenerator* ir)
|
| + : fIR(ir) {
|
| + fIR->fLoopLevel++;
|
| + }
|
| +
|
| + ~AutoLoopLevel() {
|
| + fIR->fLoopLevel--;
|
| + }
|
| +
|
| + IRGenerator* fIR;
|
| +};
|
| +
|
| IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> symbolTable,
|
| ErrorReporter& errorReporter)
|
| : fContext(*context)
|
| , fCurrentFunction(nullptr)
|
| , fSymbolTable(std::move(symbolTable))
|
| +, fLoopLevel(0)
|
| , fErrors(errorReporter) {}
|
|
|
| void IRGenerator::pushSymbolTable() {
|
| @@ -235,21 +250,30 @@ std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
|
| }
|
|
|
| std::unique_ptr<Statement> IRGenerator::convertFor(const ASTForStatement& f) {
|
| + AutoLoopLevel level(this);
|
| AutoSymbolTable table(this);
|
| - std::unique_ptr<Statement> initializer = this->convertStatement(*f.fInitializer);
|
| - if (!initializer) {
|
| - return nullptr;
|
| + std::unique_ptr<Statement> initializer;
|
| + if (f.fInitializer) {
|
| + initializer = this->convertStatement(*f.fInitializer);
|
| + if (!initializer) {
|
| + return nullptr;
|
| + }
|
| }
|
| - std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*f.fTest),
|
| - *fContext.fBool_Type);
|
| - if (!test) {
|
| - return nullptr;
|
| + std::unique_ptr<Expression> test;
|
| + if (f.fTest) {
|
| + test = this->coerce(this->convertExpression(*f.fTest), *fContext.fBool_Type);
|
| + if (!test) {
|
| + return nullptr;
|
| + }
|
| }
|
| - std::unique_ptr<Expression> next = this->convertExpression(*f.fNext);
|
| - if (!next) {
|
| - return nullptr;
|
| + std::unique_ptr<Expression> next;
|
| + if (f.fNext) {
|
| + next = this->convertExpression(*f.fNext);
|
| + if (!next) {
|
| + return nullptr;
|
| + }
|
| + this->checkValid(*next);
|
| }
|
| - this->checkValid(*next);
|
| std::unique_ptr<Statement> statement = this->convertStatement(*f.fStatement);
|
| if (!statement) {
|
| return nullptr;
|
| @@ -260,6 +284,7 @@ std::unique_ptr<Statement> IRGenerator::convertFor(const ASTForStatement& f) {
|
| }
|
|
|
| std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTWhileStatement& w) {
|
| + AutoLoopLevel level(this);
|
| std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*w.fTest),
|
| *fContext.fBool_Type);
|
| if (!test) {
|
| @@ -274,6 +299,7 @@ std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTWhileStatement& w)
|
| }
|
|
|
| std::unique_ptr<Statement> IRGenerator::convertDo(const ASTDoStatement& d) {
|
| + AutoLoopLevel level(this);
|
| std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*d.fTest),
|
| *fContext.fBool_Type);
|
| if (!test) {
|
| @@ -323,11 +349,21 @@ std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTReturnStatement&
|
| }
|
|
|
| std::unique_ptr<Statement> IRGenerator::convertBreak(const ASTBreakStatement& b) {
|
| - return std::unique_ptr<Statement>(new BreakStatement(b.fPosition));
|
| + if (fLoopLevel > 0) {
|
| + return std::unique_ptr<Statement>(new BreakStatement(b.fPosition));
|
| + } else {
|
| + fErrors.error(b.fPosition, "break statement must be inside a loop");
|
| + return nullptr;
|
| + }
|
| }
|
|
|
| std::unique_ptr<Statement> IRGenerator::convertContinue(const ASTContinueStatement& c) {
|
| - return std::unique_ptr<Statement>(new ContinueStatement(c.fPosition));
|
| + if (fLoopLevel > 0) {
|
| + return std::unique_ptr<Statement>(new ContinueStatement(c.fPosition));
|
| + } else {
|
| + fErrors.error(c.fPosition, "continue statement must be inside a loop");
|
| + return nullptr;
|
| + }
|
| }
|
|
|
| std::unique_ptr<Statement> IRGenerator::convertDiscard(const ASTDiscardStatement& d) {
|
|
|