diff options
author | Ethan Nicholas <ethannicholas@google.com> | 2017-05-10 15:06:17 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-05-10 19:31:34 +0000 |
commit | 5ac13c23628c6ee8c3f6056f38527706b403e502 (patch) | |
tree | c8a96588eed9009037bd368bb155a0f990cd4cc3 | |
parent | 37c5a96bbdeac2000c8b31d40f4786b31c39f2dd (diff) |
sksl support for static ifs & switches
Bug: skia:
Change-Id: Ic9e01a3a18efddb19bab26e92bfb473cad294fc1
Reviewed-on: https://skia-review.googlesource.com/16144
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Ben Wagner <benjaminwagner@google.com>
-rw-r--r-- | gn/tests.gni | 1 | ||||
-rw-r--r-- | src/sksl/README | 3 | ||||
-rw-r--r-- | src/sksl/SkSLCFGGenerator.cpp | 2 | ||||
-rw-r--r-- | src/sksl/SkSLCompiler.cpp | 160 | ||||
-rw-r--r-- | src/sksl/SkSLIRGenerator.cpp | 6 | ||||
-rw-r--r-- | src/sksl/SkSLParser.cpp | 23 | ||||
-rw-r--r-- | src/sksl/SkSLToken.h | 2 | ||||
-rw-r--r-- | src/sksl/ast/SkSLASTIfStatement.h | 10 | ||||
-rw-r--r-- | src/sksl/ast/SkSLASTSwitchStatement.h | 10 | ||||
-rw-r--r-- | src/sksl/ir/SkSLBlock.h | 2 | ||||
-rw-r--r-- | src/sksl/ir/SkSLIfStatement.h | 10 | ||||
-rw-r--r-- | src/sksl/ir/SkSLSwitchStatement.h | 10 | ||||
-rw-r--r-- | src/sksl/lex.sksl.c | 591 | ||||
-rw-r--r-- | src/sksl/sksl.flex | 4 | ||||
-rw-r--r-- | tests/SkSLErrorTest.cpp | 57 | ||||
-rw-r--r-- | tests/SkSLGLSLTest.cpp | 118 | ||||
-rw-r--r-- | tests/SkSLSPIRVTest.cpp | 42 |
17 files changed, 715 insertions, 336 deletions
diff --git a/gn/tests.gni b/gn/tests.gni index a0343f5b26..f48662933f 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -217,6 +217,7 @@ tests_sources = [ "$_tests/SkSLErrorTest.cpp", "$_tests/SkSLGLSLTest.cpp", "$_tests/SkSLMemoryLayoutTest.cpp", + "$_tests/SkSLSPIRVTest.cpp", "$_tests/SortTest.cpp", "$_tests/SpecialImageTest.cpp", "$_tests/SpecialSurfaceTest.cpp", diff --git a/src/sksl/README b/src/sksl/README index 5e8e21b92f..a16dd80858 100644 --- a/src/sksl/README +++ b/src/sksl/README @@ -18,6 +18,9 @@ differences (for instance, you always use "in" and "out", and skslc will handle translating them to "varying" and "attribute" as appropriate). Be aware of the following differences between SkSL and GLSL: +* "@if" and "@switch" are static versions of if and switch. They behave exactly + the same as if and switch in all respects other than it being a compile-time + error to use a non-constant expression as a test. * GLSL caps can be referenced via the syntax 'sk_Caps.<name>', e.g. sk_Caps.sampleVariablesSupport. The value will be a constant boolean or int, as appropriate. As SkSL supports constant folding and branch elimination, this diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp index 6438d59366..b756f2d762 100644 --- a/src/sksl/SkSLCFGGenerator.cpp +++ b/src/sksl/SkSLCFGGenerator.cpp @@ -560,6 +560,8 @@ void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr<Statement>* s) { case Statement::kSwitch_Kind: { SwitchStatement& ss = (SwitchStatement&) **s; this->addExpression(cfg, &ss.fValue, true); + cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false, + nullptr, s }); BlockId start = cfg.fCurrent; BlockId switchExit = cfg.newIsolatedBlock(); fLoopExits.push(switchExit); diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp index c6140d3a6a..a283e3051d 100644 --- a/src/sksl/SkSLCompiler.cpp +++ b/src/sksl/SkSLCompiler.cpp @@ -764,12 +764,70 @@ void Compiler::simplifyExpression(DefinitionMap& definitions, } } + +// returns true if this statement could potentially execute a break at the current level (we ignore +// nested loops and switches, since any breaks inside of them will merely break the loop / switch) +static bool contains_break(Statement& s) { + switch (s.fKind) { + case Statement::kBlock_Kind: + for (const auto& sub : ((Block&) s).fStatements) { + if (contains_break(*sub)) { + return true; + } + } + return false; + case Statement::kBreak_Kind: + return true; + case Statement::kIf_Kind: { + const IfStatement& i = (IfStatement&) s; + return contains_break(*i.fIfTrue) || (i.fIfFalse && contains_break(*i.fIfFalse)); + } + default: + return false; + } +} + +// Returns a block containing all of the statements that will be run if the given case matches +// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be +// broken by this call and must then be discarded). +// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as +// when break statements appear inside conditionals. +static std::unique_ptr<Statement> block_for_case(SwitchStatement* s, SwitchCase* c) { + bool capturing = false; + std::vector<std::unique_ptr<Statement>*> statementPtrs; + for (const auto& current : s->fCases) { + if (current.get() == c) { + capturing = true; + } + if (capturing) { + for (auto& stmt : current->fStatements) { + if (stmt->fKind == Statement::kBreak_Kind) { + capturing = false; + break; + } + if (contains_break(*stmt)) { + return nullptr; + } + statementPtrs.push_back(&stmt); + } + if (!capturing) { + break; + } + } + } + std::vector<std::unique_ptr<Statement>> statements; + for (const auto& s : statementPtrs) { + statements.push_back(std::move(*s)); + } + return std::unique_ptr<Statement>(new Block(Position(), std::move(statements))); +} + void Compiler::simplifyStatement(DefinitionMap& definitions, - BasicBlock& b, - std::vector<BasicBlock::Node>::iterator* iter, - std::unordered_set<const Variable*>* undefinedVariables, - bool* outUpdated, - bool* outNeedsRescan) { + BasicBlock& b, + std::vector<BasicBlock::Node>::iterator* iter, + std::unordered_set<const Variable*>* undefinedVariables, + bool* outUpdated, + bool* outNeedsRescan) { Statement* stmt = (*iter)->statement()->get(); switch (stmt->fKind) { case Statement::kVarDeclarations_Kind: { @@ -798,6 +856,22 @@ void Compiler::simplifyStatement(DefinitionMap& definitions, } case Statement::kIf_Kind: { IfStatement& i = (IfStatement&) *stmt; + if (i.fTest->fKind == Expression::kBoolLiteral_Kind) { + // constant if, collapse down to a single branch + if (((BoolLiteral&) *i.fTest).fValue) { + ASSERT(i.fIfTrue); + (*iter)->setStatement(std::move(i.fIfTrue)); + } else { + if (i.fIfFalse) { + (*iter)->setStatement(std::move(i.fIfFalse)); + } else { + (*iter)->setStatement(std::unique_ptr<Statement>(new Nop())); + } + } + *outUpdated = true; + *outNeedsRescan = true; + break; + } if (i.fIfFalse && i.fIfFalse->isEmpty()) { // else block doesn't do anything, remove it i.fIfFalse.reset(); @@ -820,6 +894,57 @@ void Compiler::simplifyStatement(DefinitionMap& definitions, } break; } + case Statement::kSwitch_Kind: { + SwitchStatement& s = (SwitchStatement&) *stmt; + if (s.fValue->isConstant()) { + // switch is constant, replace it with the case that matches + bool found = false; + SwitchCase* defaultCase = nullptr; + for (const auto& c : s.fCases) { + if (!c->fValue) { + defaultCase = c.get(); + continue; + } + ASSERT(c->fValue->fKind == s.fValue->fKind); + found = c->fValue->compareConstant(fContext, *s.fValue); + if (found) { + std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get()); + if (newBlock) { + (*iter)->setStatement(std::move(newBlock)); + break; + } else { + if (s.fIsStatic) { + this->error(s.fPosition, + "static switch contains non-static conditional break"); + s.fIsStatic = false; + } + return; // can't simplify + } + } + } + if (!found) { + // no matching case. use default if it exists, or kill the whole thing + if (defaultCase) { + std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase); + if (newBlock) { + (*iter)->setStatement(std::move(newBlock)); + } else { + if (s.fIsStatic) { + this->error(s.fPosition, + "static switch contains non-static conditional break"); + s.fIsStatic = false; + } + return; // can't simplify + } + } else { + (*iter)->setStatement(std::unique_ptr<Statement>(new Nop())); + } + } + *outUpdated = true; + *outNeedsRescan = true; + } + break; + } case Statement::kExpression_Kind: { ExpressionStatement& e = (ExpressionStatement&) *stmt; ASSERT((*iter)->statement()->get() == &e); @@ -892,6 +1017,31 @@ void Compiler::scanCFG(FunctionDefinition& f) { } while (updated); ASSERT(!needsRescan); + // verify static ifs & switches + for (BasicBlock& b : cfg.fBlocks) { + DefinitionMap definitions = b.fBefore; + + for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) { + if (iter->fKind == BasicBlock::Node::kStatement_Kind) { + const Statement& s = **iter->statement(); + switch (s.fKind) { + case Statement::kIf_Kind: + if (((const IfStatement&) s).fIsStatic) { + this->error(s.fPosition, "static if has non-static test"); + } + break; + case Statement::kSwitch_Kind: + if (((const SwitchStatement&) s).fIsStatic) { + this->error(s.fPosition, "static switch has non-static test"); + } + break; + default: + break; + } + } + } + } + // check for missing return if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) { if (cfg.fBlocks[cfg.fExit].fEntrances.size()) { diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index b167d1e01b..e160a71474 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -311,7 +311,7 @@ std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) { fSymbolTable)); } } - return std::unique_ptr<Statement>(new IfStatement(s.fPosition, std::move(test), + return std::unique_ptr<Statement>(new IfStatement(s.fPosition, s.fIsStatic, std::move(test), std::move(ifTrue), std::move(ifFalse))); } @@ -429,8 +429,8 @@ std::unique_ptr<Statement> IRGenerator::convertSwitch(const ASTSwitchStatement& cases.emplace_back(new SwitchCase(c->fPosition, std::move(caseValue), std::move(statements))); } - return std::unique_ptr<Statement>(new SwitchStatement(s.fPosition, std::move(value), - std::move(cases))); + return std::unique_ptr<Statement>(new SwitchStatement(s.fPosition, s.fIsStatic, + std::move(value), std::move(cases))); } std::unique_ptr<Statement> IRGenerator::convertExpressionStatement( diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp index f466f6fdca..04e25175cb 100644 --- a/src/sksl/SkSLParser.cpp +++ b/src/sksl/SkSLParser.cpp @@ -167,7 +167,11 @@ Token Parser::nextToken() { #endif break; } - return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token, text); + Position p = Position(skslget_lineno(fScanner), -1); + if (token == Token::INVALID_TOKEN) { + this->error(p, "invalid token: '" + text + "'"); + } + return Token(p, (Token::Kind) token, text); } void Parser::pushback(Token t) { @@ -746,7 +750,8 @@ Modifiers Parser::modifiersWithDefaults(int defaultFlags) { std::unique_ptr<ASTStatement> Parser::statement() { Token start = this->peek(); switch (start.fKind) { - case Token::IF: + case Token::IF: // fall through + case Token::STATIC_IF: return this->ifStatement(); case Token::FOR: return this->forStatement(); @@ -754,7 +759,8 @@ std::unique_ptr<ASTStatement> Parser::statement() { return this->doStatement(); case Token::WHILE: return this->whileStatement(); - case Token::SWITCH: + case Token::SWITCH: // fall through + case Token::STATIC_SWITCH: return this->switchStatement(); case Token::RETURN: return this->returnStatement(); @@ -872,7 +878,8 @@ std::unique_ptr<ASTDeclaration> Parser::interfaceBlock(Modifiers mods) { /* IF LPAREN expression RPAREN statement (ELSE statement)? */ std::unique_ptr<ASTIfStatement> Parser::ifStatement() { Token start; - if (!this->expect(Token::IF, "'if'", &start)) { + bool isStatic = this->checkNext(Token::STATIC_IF, &start); + if (!isStatic && !this->expect(Token::IF, "'if'", &start)) { return nullptr; } if (!this->expect(Token::LPAREN, "'('")) { @@ -896,7 +903,9 @@ std::unique_ptr<ASTIfStatement> Parser::ifStatement() { return nullptr; } } - return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, std::move(test), + return std::unique_ptr<ASTIfStatement>(new ASTIfStatement(start.fPosition, + isStatic, + std::move(test), std::move(ifTrue), std::move(ifFalse))); } @@ -986,7 +995,8 @@ std::unique_ptr<ASTSwitchCase> Parser::switchCase() { /* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */ std::unique_ptr<ASTStatement> Parser::switchStatement() { Token start; - if (!this->expect(Token::SWITCH, "'switch'", &start)) { + bool isStatic = this->checkNext(Token::STATIC_SWITCH, &start); + if (!isStatic && !this->expect(Token::SWITCH, "'switch'", &start)) { return nullptr; } if (!this->expect(Token::LPAREN, "'('")) { @@ -1033,6 +1043,7 @@ std::unique_ptr<ASTStatement> Parser::switchStatement() { return nullptr; } return std::unique_ptr<ASTStatement>(new ASTSwitchStatement(start.fPosition, + isStatic, std::move(value), std::move(cases))); } diff --git a/src/sksl/SkSLToken.h b/src/sksl/SkSLToken.h index a5b1754099..07eb8567a1 100644 --- a/src/sksl/SkSLToken.h +++ b/src/sksl/SkSLToken.h @@ -78,11 +78,13 @@ struct Token { LOGICALANDEQ, SEMICOLON, IF, + STATIC_IF, ELSE, FOR, WHILE, DO, SWITCH, + STATIC_SWITCH, CASE, DEFAULT, RETURN, diff --git a/src/sksl/ast/SkSLASTIfStatement.h b/src/sksl/ast/SkSLASTIfStatement.h index 684bea00d9..2752b2b750 100644 --- a/src/sksl/ast/SkSLASTIfStatement.h +++ b/src/sksl/ast/SkSLASTIfStatement.h @@ -16,15 +16,20 @@ namespace SkSL { * An 'if' statement. */ struct ASTIfStatement : public ASTStatement { - ASTIfStatement(Position position, std::unique_ptr<ASTExpression> test, + ASTIfStatement(Position position, bool isStatic, std::unique_ptr<ASTExpression> test, std::unique_ptr<ASTStatement> ifTrue, std::unique_ptr<ASTStatement> ifFalse) : INHERITED(position, kIf_Kind) + , fIsStatic(isStatic) , fTest(std::move(test)) , fIfTrue(std::move(ifTrue)) , fIfFalse(std::move(ifFalse)) {} String description() const override { - String result("if ("); + String result; + if (fIsStatic) { + result += "@"; + } + result += "if ("; result += fTest->description(); result += ") "; result += fIfTrue->description(); @@ -35,6 +40,7 @@ struct ASTIfStatement : public ASTStatement { return result; } + const bool fIsStatic; const std::unique_ptr<ASTExpression> fTest; const std::unique_ptr<ASTStatement> fIfTrue; const std::unique_ptr<ASTStatement> fIfFalse; diff --git a/src/sksl/ast/SkSLASTSwitchStatement.h b/src/sksl/ast/SkSLASTSwitchStatement.h index 4a963ebc7a..ecd0a6755d 100644 --- a/src/sksl/ast/SkSLASTSwitchStatement.h +++ b/src/sksl/ast/SkSLASTSwitchStatement.h @@ -17,14 +17,19 @@ namespace SkSL { * A 'switch' statement. */ struct ASTSwitchStatement : public ASTStatement { - ASTSwitchStatement(Position position, std::unique_ptr<ASTExpression> value, + ASTSwitchStatement(Position position, bool isStatic, std::unique_ptr<ASTExpression> value, std::vector<std::unique_ptr<ASTSwitchCase>> cases) : INHERITED(position, kSwitch_Kind) + , fIsStatic(isStatic) , fValue(std::move(value)) , fCases(std::move(cases)) {} String description() const override { - String result = String::printf("switch (%s) {\n", + fValue->description().c_str()); + String result; + if (fIsStatic) { + result += "@"; + } + result += String::printf("switch (%s) {\n", fValue->description().c_str()); for (const auto& c : fCases) { result += c->description(); } @@ -32,6 +37,7 @@ struct ASTSwitchStatement : public ASTStatement { return result; } + bool fIsStatic; const std::unique_ptr<ASTExpression> fValue; const std::vector<std::unique_ptr<ASTSwitchCase>> fCases; diff --git a/src/sksl/ir/SkSLBlock.h b/src/sksl/ir/SkSLBlock.h index 11976660b7..bcd4bb1b59 100644 --- a/src/sksl/ir/SkSLBlock.h +++ b/src/sksl/ir/SkSLBlock.h @@ -18,7 +18,7 @@ namespace SkSL { */ struct Block : public Statement { Block(Position position, std::vector<std::unique_ptr<Statement>> statements, - const std::shared_ptr<SymbolTable> symbols) + const std::shared_ptr<SymbolTable> symbols = nullptr) : INHERITED(position, kBlock_Kind) , fSymbols(std::move(symbols)) , fStatements(std::move(statements)) {} diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h index 0377b1253d..b09c10ee95 100644 --- a/src/sksl/ir/SkSLIfStatement.h +++ b/src/sksl/ir/SkSLIfStatement.h @@ -17,21 +17,27 @@ namespace SkSL { * An 'if' statement. */ struct IfStatement : public Statement { - IfStatement(Position position, std::unique_ptr<Expression> test, + IfStatement(Position position, bool isStatic, std::unique_ptr<Expression> test, std::unique_ptr<Statement> ifTrue, std::unique_ptr<Statement> ifFalse) : INHERITED(position, kIf_Kind) + , fIsStatic(isStatic) , fTest(std::move(test)) , fIfTrue(std::move(ifTrue)) , fIfFalse(std::move(ifFalse)) {} String description() const override { - String result = "if (" + fTest->description() + ") " + fIfTrue->description(); + String result; + if (fIsStatic) { + result += "@"; + } + result += "if (" + fTest->description() + ") " + fIfTrue->description(); if (fIfFalse) { result += " else " + fIfFalse->description(); } return result; } + bool fIsStatic; std::unique_ptr<Expression> fTest; std::unique_ptr<Statement> fIfTrue; // may be null diff --git a/src/sksl/ir/SkSLSwitchStatement.h b/src/sksl/ir/SkSLSwitchStatement.h index 88e1e70019..3837554b0d 100644 --- a/src/sksl/ir/SkSLSwitchStatement.h +++ b/src/sksl/ir/SkSLSwitchStatement.h @@ -17,14 +17,19 @@ namespace SkSL { * A 'switch' statement. */ struct SwitchStatement : public Statement { - SwitchStatement(Position position, std::unique_ptr<Expression> value, + SwitchStatement(Position position, bool isStatic, std::unique_ptr<Expression> value, std::vector<std::unique_ptr<SwitchCase>> cases) : INHERITED(position, kSwitch_Kind) + , fIsStatic(isStatic) , fValue(std::move(value)) , fCases(std::move(cases)) {} String description() const override { - String result = String::printf("switch (%s) {\n", + fValue->description().c_str()); + String result; + if (fIsStatic) { + result += "@"; + } + result += String::printf("switch (%s) {\n", fValue->description().c_str()); for (const auto& c : fCases) { result += c->description(); } @@ -32,6 +37,7 @@ struct SwitchStatement : public Statement { return result; } + bool fIsStatic; std::unique_ptr<Expression> fValue; std::vector<std::unique_ptr<SwitchCase>> fCases; diff --git a/src/sksl/lex.sksl.c b/src/sksl/lex.sksl.c index bfb6c5e38a..ebf94edaf7 100644 --- a/src/sksl/lex.sksl.c +++ b/src/sksl/lex.sksl.c @@ -362,8 +362,8 @@ static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner ); *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 94 -#define YY_END_OF_BUFFER 95 +#define YY_NUM_RULES 96 +#define YY_END_OF_BUFFER 97 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -371,38 +371,39 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[276] = +static yyconst flex_int16_t yy_accept[285] = { 0, - 0, 0, 95, 93, 92, 92, 66, 93, 40, 56, - 61, 42, 43, 54, 52, 49, 53, 48, 55, 4, - 4, 68, 89, 73, 69, 72, 67, 46, 47, 60, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 44, 59, - 45, 62, 92, 71, 41, 40, 80, 65, 85, 78, - 50, 76, 51, 77, 1, 0, 90, 79, 2, 4, - 0, 0, 57, 75, 70, 74, 58, 84, 64, 40, - 40, 40, 40, 40, 40, 12, 40, 40, 40, 40, - 40, 8, 20, 40, 40, 40, 40, 40, 40, 40, - - 40, 40, 40, 40, 40, 40, 40, 40, 83, 63, - 41, 88, 0, 0, 0, 90, 1, 0, 0, 3, - 5, 81, 82, 87, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 10, 40, 40, 40, 40, 40, - 40, 21, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 86, 0, 1, 91, 0, 0, - 2, 40, 40, 14, 40, 40, 40, 40, 40, 9, - 40, 28, 40, 40, 40, 25, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 6, 40, 40, 40, 40, - 0, 1, 16, 40, 40, 24, 40, 40, 40, 7, - - 27, 22, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 11, 40, 35, 40, 40, 40, - 40, 38, 40, 40, 40, 40, 40, 19, 40, 37, - 13, 40, 40, 40, 40, 40, 15, 18, 26, 40, - 40, 40, 40, 40, 23, 40, 40, 32, 17, 40, - 40, 30, 34, 40, 33, 40, 40, 39, 40, 31, - 40, 40, 40, 40, 40, 40, 29, 40, 40, 40, - 40, 40, 40, 36, 0 + 0, 0, 97, 95, 94, 94, 68, 95, 42, 58, + 63, 44, 45, 56, 54, 51, 55, 50, 57, 4, + 4, 70, 91, 75, 71, 74, 69, 95, 48, 49, + 62, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 46, + 61, 47, 64, 94, 73, 43, 42, 82, 67, 87, + 80, 52, 78, 53, 79, 1, 0, 92, 81, 2, + 4, 0, 0, 59, 77, 72, 76, 60, 0, 0, + 86, 66, 42, 42, 42, 42, 42, 42, 13, 42, + 42, 42, 42, 42, 8, 22, 42, 42, 42, 42, + + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 85, 65, 43, 90, 0, 0, 0, 92, 1, + 0, 0, 3, 5, 83, 84, 9, 0, 89, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 11, + 42, 42, 42, 42, 42, 42, 23, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 88, + 0, 1, 93, 0, 0, 2, 0, 42, 42, 16, + 42, 42, 42, 42, 42, 10, 42, 30, 42, 42, + 42, 27, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 6, 42, 42, 42, 42, 0, 1, 0, 18, + + 42, 42, 26, 42, 42, 42, 7, 29, 24, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 12, 42, 0, 37, 42, 42, 42, 42, 40, + 42, 42, 42, 42, 42, 21, 42, 39, 14, 42, + 42, 42, 15, 42, 42, 17, 20, 28, 42, 42, + 42, 42, 42, 25, 42, 42, 34, 19, 42, 42, + 32, 36, 42, 35, 42, 42, 41, 42, 33, 42, + 42, 42, 42, 42, 42, 31, 42, 42, 42, 42, + 42, 42, 38, 0 } ; static yyconst YY_CHAR yy_ec[256] = @@ -413,14 +414,14 @@ static yyconst YY_CHAR yy_ec[256] = 1, 2, 4, 1, 5, 6, 7, 8, 1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, - 22, 23, 24, 1, 25, 25, 25, 25, 26, 25, + 22, 23, 24, 25, 26, 26, 26, 26, 27, 26, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 27, 1, 28, 29, 30, 1, 31, 32, 33, 34, + 28, 1, 29, 30, 31, 1, 32, 33, 34, 35, - 35, 36, 37, 38, 39, 6, 40, 41, 42, 43, - 44, 45, 6, 46, 47, 48, 49, 50, 51, 52, - 53, 6, 54, 55, 56, 57, 1, 1, 1, 1, + 36, 37, 38, 39, 40, 6, 41, 42, 43, 44, + 45, 46, 6, 47, 48, 49, 50, 51, 52, 53, + 54, 6, 55, 56, 57, 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -437,192 +438,194 @@ static yyconst YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst YY_CHAR yy_meta[58] = +static yyconst YY_CHAR yy_meta[59] = { 0, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, - 1, 1, 1, 1, 5, 5, 1, 1, 1, 3, - 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, + 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 1, 1, 1, 1 + 3, 3, 3, 3, 1, 1, 1, 1 } ; -static yyconst flex_uint16_t yy_base[282] = +static yyconst flex_uint16_t yy_base[291] = { 0, - 0, 0, 344, 345, 56, 58, 321, 0, 0, 320, - 54, 345, 345, 319, 51, 345, 50, 48, 58, 53, - 60, 345, 345, 60, 318, 61, 345, 345, 345, 63, - 41, 58, 59, 298, 60, 299, 57, 65, 302, 292, - 286, 288, 298, 59, 286, 288, 286, 68, 345, 75, - 345, 345, 109, 345, 0, 0, 345, 307, 345, 345, - 345, 345, 345, 345, 98, 317, 0, 345, 100, 105, - 120, 0, 305, 345, 345, 345, 304, 345, 303, 289, - 287, 275, 70, 285, 273, 0, 272, 277, 286, 270, - 278, 0, 270, 260, 261, 277, 265, 261, 273, 94, - - 277, 260, 266, 255, 264, 261, 262, 261, 345, 277, - 0, 345, 131, 287, 281, 0, 129, 139, 110, 141, - 0, 345, 345, 345, 265, 259, 259, 258, 113, 261, - 258, 255, 242, 240, 0, 249, 237, 241, 239, 244, - 247, 0, 248, 246, 231, 229, 239, 227, 227, 239, - 237, 241, 230, 222, 345, 145, 148, 345, 155, 153, - 157, 229, 233, 0, 221, 218, 226, 215, 232, 0, - 227, 0, 216, 212, 210, 0, 209, 211, 217, 211, - 208, 207, 221, 218, 217, 0, 205, 200, 212, 211, - 159, 161, 0, 199, 209, 0, 200, 201, 195, 0, - - 0, 0, 192, 197, 191, 190, 193, 196, 191, 186, - 184, 193, 184, 190, 0, 184, 0, 184, 177, 177, - 190, 0, 178, 177, 182, 179, 186, 0, 188, 0, - 0, 175, 175, 172, 166, 178, 0, 0, 0, 177, - 167, 157, 161, 161, 0, 172, 165, 0, 0, 172, - 161, 0, 0, 164, 0, 149, 153, 0, 161, 0, - 142, 133, 104, 122, 115, 109, 0, 103, 100, 94, - 88, 71, 20, 0, 345, 177, 180, 183, 188, 193, - 195 + 0, 0, 353, 354, 57, 59, 330, 0, 0, 329, + 55, 354, 354, 328, 52, 354, 51, 49, 59, 61, + 65, 354, 354, 47, 327, 49, 354, 45, 354, 354, + 64, 37, 57, 55, 306, 64, 307, 61, 58, 310, + 300, 294, 296, 306, 58, 294, 296, 294, 65, 354, + 86, 354, 354, 113, 354, 0, 0, 354, 316, 354, + 354, 354, 354, 354, 354, 100, 326, 0, 354, 102, + 107, 114, 0, 314, 354, 354, 354, 313, 297, 281, + 354, 310, 295, 293, 281, 91, 291, 279, 0, 278, + 283, 292, 276, 284, 0, 276, 266, 267, 283, 271, + + 267, 279, 91, 283, 266, 272, 261, 270, 267, 268, + 267, 354, 284, 0, 354, 132, 294, 288, 0, 130, + 141, 134, 143, 0, 354, 354, 354, 263, 354, 270, + 264, 264, 263, 114, 266, 263, 260, 247, 245, 0, + 254, 242, 246, 244, 249, 252, 0, 253, 251, 236, + 234, 244, 232, 232, 244, 242, 246, 235, 227, 354, + 147, 150, 354, 157, 155, 159, 226, 233, 237, 0, + 225, 222, 230, 219, 236, 0, 231, 0, 220, 216, + 214, 0, 213, 215, 221, 215, 212, 211, 225, 222, + 221, 0, 209, 204, 216, 215, 161, 163, 216, 0, + + 202, 212, 0, 203, 204, 198, 0, 0, 0, 195, + 200, 194, 193, 196, 199, 194, 189, 187, 196, 187, + 193, 0, 187, 192, 0, 186, 179, 179, 192, 0, + 180, 179, 184, 181, 188, 0, 190, 0, 0, 177, + 177, 174, 354, 168, 180, 0, 0, 0, 179, 169, + 159, 163, 163, 0, 174, 167, 0, 0, 174, 163, + 0, 0, 166, 0, 151, 155, 0, 168, 0, 157, + 147, 119, 125, 118, 109, 0, 104, 100, 97, 87, + 64, 63, 0, 354, 179, 182, 185, 190, 195, 197 } ; -static yyconst flex_int16_t yy_def[282] = +static yyconst flex_int16_t yy_def[291] = { 0, - 275, 1, 275, 275, 275, 275, 275, 276, 277, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 275, 275, - 275, 275, 275, 275, 278, 277, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 279, 280, 275, 275, 275, - 275, 281, 275, 275, 275, 275, 275, 275, 275, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - - 277, 277, 277, 277, 277, 277, 277, 277, 275, 275, - 278, 275, 275, 279, 279, 280, 275, 275, 275, 275, - 281, 275, 275, 275, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 275, 275, 275, 275, 275, 275, - 275, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 275, 275, 277, 277, 277, 277, 277, 277, 277, 277, - - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 0, 275, 275, 275, 275, 275, - 275 + 284, 1, 284, 284, 284, 284, 284, 285, 286, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 284, + 284, 284, 284, 284, 284, 287, 286, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 288, 289, 284, 284, + 284, 284, 290, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 284, 284, 287, 284, 284, 288, 288, 289, 284, + 284, 284, 284, 290, 284, 284, 284, 284, 284, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 284, + 284, 284, 284, 284, 284, 284, 284, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 284, 284, 284, 286, + + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 284, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 284, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, + 286, 286, 286, 0, 284, 284, 284, 284, 284, 284 } ; -static yyconst flex_uint16_t yy_nxt[403] = +static yyconst flex_uint16_t yy_nxt[413] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 9, 9, 28, 29, 30, 9, - 9, 31, 32, 33, 34, 35, 9, 36, 37, 9, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 9, 9, 49, 50, 51, 52, 53, 53, 53, - 53, 58, 61, 63, 65, 65, 274, 69, 66, 70, - 70, 64, 62, 67, 69, 59, 70, 70, 71, 68, - 73, 74, 76, 77, 78, 71, 80, 71, 82, 81, - 88, 79, 92, 84, 71, 94, 109, 85, 101, 93, - - 89, 83, 86, 90, 72, 107, 102, 128, 95, 103, - 53, 53, 129, 108, 65, 65, 117, 117, 273, 69, - 272, 70, 70, 113, 144, 118, 120, 120, 271, 110, - 71, 119, 113, 119, 118, 270, 120, 120, 269, 71, - 145, 146, 156, 268, 156, 117, 117, 157, 157, 267, - 160, 266, 160, 265, 159, 161, 161, 120, 120, 166, - 167, 157, 157, 159, 157, 157, 191, 264, 191, 161, - 161, 192, 192, 161, 161, 192, 192, 192, 192, 55, - 263, 55, 56, 56, 56, 111, 111, 111, 114, 114, - 114, 114, 114, 116, 262, 116, 116, 116, 121, 121, - - 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, - 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, - 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, - 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, - 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, - 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, - 201, 200, 199, 198, 197, 196, 195, 194, 193, 190, - 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, - 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, - 169, 168, 165, 164, 163, 162, 158, 115, 155, 154, - - 153, 152, 151, 150, 149, 148, 147, 143, 142, 141, - 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, - 130, 127, 126, 125, 124, 123, 122, 115, 112, 106, - 105, 104, 100, 99, 98, 97, 96, 91, 87, 75, - 60, 57, 54, 275, 3, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - - 275, 275 + 24, 25, 26, 27, 28, 9, 9, 29, 30, 31, + 9, 9, 32, 33, 34, 35, 36, 9, 37, 38, + 9, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 9, 9, 50, 51, 52, 53, 54, 54, + 54, 54, 59, 62, 64, 66, 66, 74, 75, 67, + 77, 78, 65, 63, 68, 70, 60, 71, 71, 70, + 69, 71, 71, 83, 79, 81, 84, 72, 85, 97, + 87, 72, 80, 82, 88, 91, 72, 95, 104, 89, + + 72, 86, 98, 110, 96, 92, 105, 112, 93, 106, + 283, 111, 282, 73, 54, 54, 66, 66, 120, 120, + 281, 70, 149, 71, 71, 122, 116, 122, 121, 133, + 123, 123, 280, 72, 134, 116, 279, 121, 150, 151, + 278, 113, 72, 161, 277, 161, 120, 120, 162, 162, + 123, 123, 165, 276, 165, 275, 164, 166, 166, 123, + 123, 172, 173, 162, 162, 164, 162, 162, 197, 274, + 197, 166, 166, 198, 198, 166, 166, 198, 198, 198, + 198, 56, 273, 56, 57, 57, 57, 114, 114, 114, + 117, 117, 117, 117, 117, 119, 272, 119, 119, 119, + + 124, 124, 271, 270, 269, 268, 267, 266, 265, 264, + 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, + 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, + 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, + 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, + 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, + 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, + 203, 202, 201, 200, 199, 196, 195, 194, 193, 192, + 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, + 181, 180, 179, 178, 177, 176, 175, 174, 171, 170, + + 169, 168, 167, 163, 118, 160, 159, 158, 157, 156, + 155, 154, 153, 152, 148, 147, 146, 145, 144, 143, + 142, 141, 140, 139, 138, 137, 136, 135, 132, 131, + 130, 129, 128, 127, 126, 125, 118, 115, 109, 108, + 107, 103, 102, 101, 100, 99, 94, 90, 76, 61, + 58, 55, 284, 3, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284 } ; -static yyconst flex_int16_t yy_chk[403] = +static yyconst flex_int16_t yy_chk[413] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 5, 5, 6, - 6, 11, 15, 17, 18, 18, 273, 20, 19, 20, - 20, 17, 15, 19, 21, 11, 21, 21, 20, 19, - 24, 24, 26, 26, 30, 21, 31, 20, 32, 31, - 35, 30, 37, 33, 21, 38, 50, 33, 44, 37, - - 35, 32, 33, 35, 20, 48, 44, 83, 38, 44, - 53, 53, 83, 48, 65, 65, 69, 69, 272, 70, - 271, 70, 70, 65, 100, 69, 119, 119, 270, 50, - 70, 71, 65, 71, 69, 269, 71, 71, 268, 70, - 100, 100, 113, 266, 113, 117, 117, 113, 113, 265, - 118, 264, 118, 263, 117, 118, 118, 120, 120, 129, - 129, 156, 156, 117, 157, 157, 159, 262, 159, 160, - 160, 159, 159, 161, 161, 191, 191, 192, 192, 276, - 261, 276, 277, 277, 277, 278, 278, 278, 279, 279, - 279, 279, 279, 280, 259, 280, 280, 280, 281, 281, - - 257, 256, 254, 251, 250, 247, 246, 244, 243, 242, - 241, 240, 236, 235, 234, 233, 232, 229, 227, 226, - 225, 224, 223, 221, 220, 219, 218, 216, 214, 213, - 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, - 199, 198, 197, 195, 194, 190, 189, 188, 187, 185, - 184, 183, 182, 181, 180, 179, 178, 177, 175, 174, - 173, 171, 169, 168, 167, 166, 165, 163, 162, 154, - 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, - 143, 141, 140, 139, 138, 137, 136, 134, 133, 132, - 131, 130, 128, 127, 126, 125, 115, 114, 110, 108, - - 107, 106, 105, 104, 103, 102, 101, 99, 98, 97, - 96, 95, 94, 93, 91, 90, 89, 88, 87, 85, - 84, 82, 81, 80, 79, 77, 73, 66, 58, 47, - 46, 45, 43, 42, 41, 40, 39, 36, 34, 25, - 14, 10, 7, 3, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - - 275, 275 + 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, + 6, 6, 11, 15, 17, 18, 18, 24, 24, 19, + 26, 26, 17, 15, 19, 20, 11, 20, 20, 21, + 19, 21, 21, 32, 28, 31, 32, 20, 33, 39, + 34, 21, 28, 31, 34, 36, 20, 38, 45, 34, + + 21, 33, 39, 49, 38, 36, 45, 51, 36, 45, + 282, 49, 281, 20, 54, 54, 66, 66, 70, 70, + 280, 71, 103, 71, 71, 72, 66, 72, 70, 86, + 72, 72, 279, 71, 86, 66, 278, 70, 103, 103, + 277, 51, 71, 116, 275, 116, 120, 120, 116, 116, + 122, 122, 121, 274, 121, 273, 120, 121, 121, 123, + 123, 134, 134, 161, 161, 120, 162, 162, 164, 272, + 164, 165, 165, 164, 164, 166, 166, 197, 197, 198, + 198, 285, 271, 285, 286, 286, 286, 287, 287, 287, + 288, 288, 288, 288, 288, 289, 270, 289, 289, 289, + + 290, 290, 268, 266, 265, 263, 260, 259, 256, 255, + 253, 252, 251, 250, 249, 245, 244, 242, 241, 240, + 237, 235, 234, 233, 232, 231, 229, 228, 227, 226, + 224, 223, 221, 220, 219, 218, 217, 216, 215, 214, + 213, 212, 211, 210, 206, 205, 204, 202, 201, 199, + 196, 195, 194, 193, 191, 190, 189, 188, 187, 186, + 185, 184, 183, 181, 180, 179, 177, 175, 174, 173, + 172, 171, 169, 168, 167, 159, 158, 157, 156, 155, + 154, 153, 152, 151, 150, 149, 148, 146, 145, 144, + 143, 142, 141, 139, 138, 137, 136, 135, 133, 132, + + 131, 130, 128, 118, 117, 113, 111, 110, 109, 108, + 107, 106, 105, 104, 102, 101, 100, 99, 98, 97, + 96, 94, 93, 92, 91, 90, 88, 87, 85, 84, + 83, 82, 80, 79, 78, 74, 67, 59, 48, 47, + 46, 44, 43, 42, 41, 40, 37, 35, 25, 14, + 10, 7, 3, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[95] = +static yyconst flex_int32_t yy_rule_can_match_eol[97] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. @@ -651,7 +654,7 @@ static yyconst flex_int32_t yy_rule_can_match_eol[95] = */ #define YY_NO_UNISTD_H 1 -#line 655 "lex.sksl.c" +#line 658 "lex.sksl.c" #define INITIAL 0 @@ -915,7 +918,7 @@ YY_DECL #line 30 "sksl.flex" -#line 919 "lex.sksl.c" +#line 922 "lex.sksl.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -942,13 +945,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 276 ) + if ( yy_current_state >= 285 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } - while ( yy_current_state != 275 ); + while ( yy_current_state != 284 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -1023,436 +1026,446 @@ YY_RULE_SETUP case 9: YY_RULE_SETUP #line 48 "sksl.flex" -{ return SkSL::Token::ELSE; } +{ return SkSL::Token::STATIC_IF; } YY_BREAK case 10: YY_RULE_SETUP #line 50 "sksl.flex" -{ return SkSL::Token::FOR; } +{ return SkSL::Token::ELSE; } YY_BREAK case 11: YY_RULE_SETUP #line 52 "sksl.flex" -{ return SkSL::Token::WHILE; } +{ return SkSL::Token::FOR; } YY_BREAK case 12: YY_RULE_SETUP #line 54 "sksl.flex" -{ return SkSL::Token::DO; } +{ return SkSL::Token::WHILE; } YY_BREAK case 13: YY_RULE_SETUP #line 56 "sksl.flex" -{ return SkSL::Token::SWITCH; } +{ return SkSL::Token::DO; } YY_BREAK case 14: YY_RULE_SETUP #line 58 "sksl.flex" -{ return SkSL::Token::CASE; } +{ return SkSL::Token::SWITCH; } YY_BREAK case 15: YY_RULE_SETUP #line 60 "sksl.flex" -{ return SkSL::Token::DEFAULT; } +{ return SkSL::Token::STATIC_SWITCH; } YY_BREAK case 16: YY_RULE_SETUP #line 62 "sksl.flex" -{ return SkSL::Token::BREAK; } +{ return SkSL::Token::CASE; } YY_BREAK case 17: YY_RULE_SETUP #line 64 "sksl.flex" -{ return SkSL::Token::CONTINUE; } +{ return SkSL::Token::DEFAULT; } YY_BREAK case 18: YY_RULE_SETUP #line 66 "sksl.flex" -{ return SkSL::Token::DISCARD; } +{ return SkSL::Token::BREAK; } YY_BREAK case 19: YY_RULE_SETUP #line 68 "sksl.flex" -{ return SkSL::Token::RETURN; } +{ return SkSL::Token::CONTINUE; } YY_BREAK case 20: YY_RULE_SETUP #line 70 "sksl.flex" -{ return SkSL::Token::IN; } +{ return SkSL::Token::DISCARD; } YY_BREAK case 21: YY_RULE_SETUP #line 72 "sksl.flex" -{ return SkSL::Token::OUT; } +{ return SkSL::Token::RETURN; } YY_BREAK case 22: YY_RULE_SETUP #line 74 "sksl.flex" -{ return SkSL::Token::INOUT; } +{ return SkSL::Token::IN; } YY_BREAK case 23: YY_RULE_SETUP #line 76 "sksl.flex" -{ return SkSL::Token::UNIFORM; } +{ return SkSL::Token::OUT; } YY_BREAK case 24: YY_RULE_SETUP #line 78 "sksl.flex" -{ return SkSL::Token::CONST; } +{ return SkSL::Token::INOUT; } YY_BREAK case 25: YY_RULE_SETUP #line 80 "sksl.flex" -{ return SkSL::Token::LOWP; } +{ return SkSL::Token::UNIFORM; } YY_BREAK case 26: YY_RULE_SETUP #line 82 "sksl.flex" -{ return SkSL::Token::MEDIUMP; } +{ return SkSL::Token::CONST; } YY_BREAK case 27: YY_RULE_SETUP #line 84 "sksl.flex" -{ return SkSL::Token::HIGHP; } +{ return SkSL::Token::LOWP; } YY_BREAK case 28: YY_RULE_SETUP #line 86 "sksl.flex" -{ return SkSL::Token::FLAT; } +{ return SkSL::Token::MEDIUMP; } YY_BREAK case 29: YY_RULE_SETUP #line 88 "sksl.flex" -{ return SkSL::Token::NOPERSPECTIVE; } +{ return SkSL::Token::HIGHP; } YY_BREAK case 30: YY_RULE_SETUP #line 90 "sksl.flex" -{ return SkSL::Token::READONLY; } +{ return SkSL::Token::FLAT; } YY_BREAK case 31: YY_RULE_SETUP #line 92 "sksl.flex" -{ return SkSL::Token::WRITEONLY; } +{ return SkSL::Token::NOPERSPECTIVE; } YY_BREAK case 32: YY_RULE_SETUP #line 94 "sksl.flex" -{ return SkSL::Token::COHERENT; } +{ return SkSL::Token::READONLY; } YY_BREAK case 33: YY_RULE_SETUP #line 96 "sksl.flex" -{ return SkSL::Token::VOLATILE; } +{ return SkSL::Token::WRITEONLY; } YY_BREAK case 34: YY_RULE_SETUP #line 98 "sksl.flex" -{ return SkSL::Token::RESTRICT; } +{ return SkSL::Token::COHERENT; } YY_BREAK case 35: YY_RULE_SETUP #line 100 "sksl.flex" -{ return SkSL::Token::BUFFER; } +{ return SkSL::Token::VOLATILE; } YY_BREAK case 36: YY_RULE_SETUP #line 102 "sksl.flex" -{ return SkSL::Token::HASSIDEEFFECTS; } +{ return SkSL::Token::RESTRICT; } YY_BREAK case 37: YY_RULE_SETUP #line 104 "sksl.flex" -{ return SkSL::Token::STRUCT; } +{ return SkSL::Token::BUFFER; } YY_BREAK case 38: YY_RULE_SETUP #line 106 "sksl.flex" -{ return SkSL::Token::LAYOUT; } +{ return SkSL::Token::HASSIDEEFFECTS; } YY_BREAK case 39: YY_RULE_SETUP #line 108 "sksl.flex" -{ return SkSL::Token::PRECISION; } +{ return SkSL::Token::STRUCT; } YY_BREAK case 40: YY_RULE_SETUP #line 110 "sksl.flex" -{ return SkSL::Token::IDENTIFIER; } +{ return SkSL::Token::LAYOUT; } YY_BREAK case 41: YY_RULE_SETUP #line 112 "sksl.flex" -{ return SkSL::Token::DIRECTIVE; } +{ return SkSL::Token::PRECISION; } YY_BREAK case 42: YY_RULE_SETUP #line 114 "sksl.flex" -{ return SkSL::Token::LPAREN; } +{ return SkSL::Token::IDENTIFIER; } YY_BREAK case 43: YY_RULE_SETUP #line 116 "sksl.flex" -{ return SkSL::Token::RPAREN; } +{ return SkSL::Token::DIRECTIVE; } YY_BREAK case 44: YY_RULE_SETUP #line 118 "sksl.flex" -{ return SkSL::Token::LBRACE; } +{ return SkSL::Token::LPAREN; } YY_BREAK case 45: YY_RULE_SETUP #line 120 "sksl.flex" -{ return SkSL::Token::RBRACE; } +{ return SkSL::Token::RPAREN; } YY_BREAK case 46: YY_RULE_SETUP #line 122 "sksl.flex" -{ return SkSL::Token::LBRACKET; } +{ return SkSL::Token::LBRACE; } YY_BREAK case 47: YY_RULE_SETUP #line 124 "sksl.flex" -{ return SkSL::Token::RBRACKET; } +{ return SkSL::Token::RBRACE; } YY_BREAK case 48: YY_RULE_SETUP #line 126 "sksl.flex" -{ return SkSL::Token::DOT; } +{ return SkSL::Token::LBRACKET; } YY_BREAK case 49: YY_RULE_SETUP #line 128 "sksl.flex" -{ return SkSL::Token::COMMA; } +{ return SkSL::Token::RBRACKET; } YY_BREAK case 50: YY_RULE_SETUP #line 130 "sksl.flex" -{ return SkSL::Token::PLUSPLUS; } +{ return SkSL::Token::DOT; } YY_BREAK case 51: YY_RULE_SETUP #line 132 "sksl.flex" -{ return SkSL::Token::MINUSMINUS; } +{ return SkSL::Token::COMMA; } YY_BREAK case 52: YY_RULE_SETUP #line 134 "sksl.flex" -{ return SkSL::Token::PLUS; } +{ return SkSL::Token::PLUSPLUS; } YY_BREAK case 53: YY_RULE_SETUP #line 136 "sksl.flex" -{ return SkSL::Token::MINUS; } +{ return SkSL::Token::MINUSMINUS; } YY_BREAK case 54: YY_RULE_SETUP #line 138 "sksl.flex" -{ return SkSL::Token::STAR; } +{ return SkSL::Token::PLUS; } YY_BREAK case 55: YY_RULE_SETUP #line 140 "sksl.flex" -{ return SkSL::Token::SLASH; } +{ return SkSL::Token::MINUS; } YY_BREAK case 56: YY_RULE_SETUP #line 142 "sksl.flex" -{ return SkSL::Token::PERCENT; } +{ return SkSL::Token::STAR; } YY_BREAK case 57: YY_RULE_SETUP #line 144 "sksl.flex" -{ return SkSL::Token::SHL; } +{ return SkSL::Token::SLASH; } YY_BREAK case 58: YY_RULE_SETUP #line 146 "sksl.flex" -{ return SkSL::Token::SHR; } +{ return SkSL::Token::PERCENT; } YY_BREAK case 59: YY_RULE_SETUP #line 148 "sksl.flex" -{ return SkSL::Token::BITWISEOR; } +{ return SkSL::Token::SHL; } YY_BREAK case 60: YY_RULE_SETUP #line 150 "sksl.flex" -{ return SkSL::Token::BITWISEXOR; } +{ return SkSL::Token::SHR; } YY_BREAK case 61: YY_RULE_SETUP #line 152 "sksl.flex" -{ return SkSL::Token::BITWISEAND; } +{ return SkSL::Token::BITWISEOR; } YY_BREAK case 62: YY_RULE_SETUP #line 154 "sksl.flex" -{ return SkSL::Token::BITWISENOT; } +{ return SkSL::Token::BITWISEXOR; } YY_BREAK case 63: YY_RULE_SETUP #line 156 "sksl.flex" -{ return SkSL::Token::LOGICALOR; } +{ return SkSL::Token::BITWISEAND; } YY_BREAK case 64: YY_RULE_SETUP #line 158 "sksl.flex" -{ return SkSL::Token::LOGICALXOR; } +{ return SkSL::Token::BITWISENOT; } YY_BREAK case 65: YY_RULE_SETUP #line 160 "sksl.flex" -{ return SkSL::Token::LOGICALAND; } +{ return SkSL::Token::LOGICALOR; } YY_BREAK case 66: YY_RULE_SETUP #line 162 "sksl.flex" -{ return SkSL::Token::LOGICALNOT; } +{ return SkSL::Token::LOGICALXOR; } YY_BREAK case 67: YY_RULE_SETUP #line 164 "sksl.flex" -{ return SkSL::Token::QUESTION; } +{ return SkSL::Token::LOGICALAND; } YY_BREAK case 68: YY_RULE_SETUP #line 166 "sksl.flex" -{ return SkSL::Token::COLON; } +{ return SkSL::Token::LOGICALNOT; } YY_BREAK case 69: YY_RULE_SETUP #line 168 "sksl.flex" -{ return SkSL::Token::EQ; } +{ return SkSL::Token::QUESTION; } YY_BREAK case 70: YY_RULE_SETUP #line 170 "sksl.flex" -{ return SkSL::Token::EQEQ; } +{ return SkSL::Token::COLON; } YY_BREAK case 71: YY_RULE_SETUP #line 172 "sksl.flex" -{ return SkSL::Token::NEQ; } +{ return SkSL::Token::EQ; } YY_BREAK case 72: YY_RULE_SETUP #line 174 "sksl.flex" -{ return SkSL::Token::GT; } +{ return SkSL::Token::EQEQ; } YY_BREAK case 73: YY_RULE_SETUP #line 176 "sksl.flex" -{ return SkSL::Token::LT; } +{ return SkSL::Token::NEQ; } YY_BREAK case 74: YY_RULE_SETUP #line 178 "sksl.flex" -{ return SkSL::Token::GTEQ; } +{ return SkSL::Token::GT; } YY_BREAK case 75: YY_RULE_SETUP #line 180 "sksl.flex" -{ return SkSL::Token::LTEQ; } +{ return SkSL::Token::LT; } YY_BREAK case 76: YY_RULE_SETUP #line 182 "sksl.flex" -{ return SkSL::Token::PLUSEQ; } +{ return SkSL::Token::GTEQ; } YY_BREAK case 77: YY_RULE_SETUP #line 184 "sksl.flex" -{ return SkSL::Token::MINUSEQ; } +{ return SkSL::Token::LTEQ; } YY_BREAK case 78: YY_RULE_SETUP #line 186 "sksl.flex" -{ return SkSL::Token::STAREQ; } +{ return SkSL::Token::PLUSEQ; } YY_BREAK case 79: YY_RULE_SETUP #line 188 "sksl.flex" -{ return SkSL::Token::SLASHEQ; } +{ return SkSL::Token::MINUSEQ; } YY_BREAK case 80: YY_RULE_SETUP #line 190 "sksl.flex" -{ return SkSL::Token::PERCENTEQ; } +{ return SkSL::Token::STAREQ; } YY_BREAK case 81: YY_RULE_SETUP #line 192 "sksl.flex" -{ return SkSL::Token::SHLEQ; } +{ return SkSL::Token::SLASHEQ; } YY_BREAK case 82: YY_RULE_SETUP #line 194 "sksl.flex" -{ return SkSL::Token::SHREQ; } +{ return SkSL::Token::PERCENTEQ; } YY_BREAK case 83: YY_RULE_SETUP #line 196 "sksl.flex" -{ return SkSL::Token::BITWISEOREQ; } +{ return SkSL::Token::SHLEQ; } YY_BREAK case 84: YY_RULE_SETUP #line 198 "sksl.flex" -{ return SkSL::Token::BITWISEXOREQ; } +{ return SkSL::Token::SHREQ; } YY_BREAK case 85: YY_RULE_SETUP #line 200 "sksl.flex" -{ return SkSL::Token::BITWISEANDEQ; } +{ return SkSL::Token::BITWISEOREQ; } YY_BREAK case 86: YY_RULE_SETUP #line 202 "sksl.flex" -{ return SkSL::Token::LOGICALOREQ; } +{ return SkSL::Token::BITWISEXOREQ; } YY_BREAK case 87: YY_RULE_SETUP #line 204 "sksl.flex" -{ return SkSL::Token::LOGICALXOREQ; } +{ return SkSL::Token::BITWISEANDEQ; } YY_BREAK case 88: YY_RULE_SETUP #line 206 "sksl.flex" -{ return SkSL::Token::LOGICALANDEQ; } +{ return SkSL::Token::LOGICALOREQ; } YY_BREAK case 89: YY_RULE_SETUP #line 208 "sksl.flex" -{ return SkSL::Token::SEMICOLON; } +{ return SkSL::Token::LOGICALXOREQ; } YY_BREAK case 90: YY_RULE_SETUP #line 210 "sksl.flex" -/* line comment */ +{ return SkSL::Token::LOGICALANDEQ; } YY_BREAK case 91: -/* rule 91 can match eol */ YY_RULE_SETUP #line 212 "sksl.flex" -/* block comment */ +{ return SkSL::Token::SEMICOLON; } YY_BREAK case 92: -/* rule 92 can match eol */ YY_RULE_SETUP #line 214 "sksl.flex" -/* whitespace */ +/* line comment */ YY_BREAK case 93: +/* rule 93 can match eol */ YY_RULE_SETUP #line 216 "sksl.flex" -{ return SkSL::Token::INVALID_TOKEN; } +/* block comment */ YY_BREAK case 94: +/* rule 94 can match eol */ YY_RULE_SETUP #line 218 "sksl.flex" +/* whitespace */ + YY_BREAK +case 95: +YY_RULE_SETUP +#line 220 "sksl.flex" +{ return SkSL::Token::INVALID_TOKEN; } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 222 "sksl.flex" ECHO; YY_BREAK -#line 1456 "lex.sksl.c" +#line 1469 "lex.sksl.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1748,7 +1761,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 276 ) + if ( yy_current_state >= 285 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; @@ -1777,11 +1790,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 276 ) + if ( yy_current_state >= 285 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; - yy_is_jam = (yy_current_state == 275); + yy_is_jam = (yy_current_state == 284); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -2633,7 +2646,7 @@ void skslfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 218 "sksl.flex" +#line 222 "sksl.flex" diff --git a/src/sksl/sksl.flex b/src/sksl/sksl.flex index c35ce5dc42..c5d5ec34d0 100644 --- a/src/sksl/sksl.flex +++ b/src/sksl/sksl.flex @@ -45,6 +45,8 @@ false { return SkSL::Token::FALSE_LITERAL; } if { return SkSL::Token::IF; } +@if { return SkSL::Token::STATIC_IF; } + else { return SkSL::Token::ELSE; } for { return SkSL::Token::FOR; } @@ -55,6 +57,8 @@ do { return SkSL::Token::DO; } switch { return SkSL::Token::SWITCH; } +@switch { return SkSL::Token::STATIC_SWITCH; } + case { return SkSL::Token::CASE; } default { return SkSL::Token::DEFAULT; } diff --git a/tests/SkSLErrorTest.cpp b/tests/SkSLErrorTest.cpp index d443b1844f..453a8f84c9 100644 --- a/tests/SkSLErrorTest.cpp +++ b/tests/SkSLErrorTest.cpp @@ -16,12 +16,7 @@ static void test_failure(skiatest::Reporter* r, const char* src, const char* err SkSL::Program::Settings settings; sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default(); settings.fCaps = caps.get(); - std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind, - SkString(src), settings); - if (program) { - SkSL::String ignored; - compiler.toSPIRV(*program, &ignored); - } + compiler.convertProgram(SkSL::Program::kFragment_Kind, SkString(src), settings); SkSL::String skError(error); if (compiler.errorText() != skError) { SkDebugf("SKSL ERROR:\n source: %s\n expected: %s received: %s", src, error, @@ -38,8 +33,6 @@ static void test_success(skiatest::Reporter* r, const char* src) { std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind, SkString(src), settings); REPORTER_ASSERT(r, program); - SkSL::String ignored; - REPORTER_ASSERT(r, compiler.toSPIRV(*program, &ignored)); } DEF_TEST(SkSLUndefinedSymbol, r) { @@ -405,15 +398,6 @@ DEF_TEST(SkSLBadCap, r) { "error: 1: unknown capability flag 'bugFreeDriver'\n1 error\n"); } -DEF_TEST(SkSLBadOffset, r) { - test_failure(r, - "struct Bad { layout (offset = 5) int x; } bad; void main() { bad.x = 5; }", - "error: 1: offset of field 'x' must be a multiple of 4\n1 error\n"); - test_failure(r, - "struct Bad { int x; layout (offset = 0) int y; } bad; void main() { bad.x = 5; }", - "error: 1: offset of field 'y' must be at least 4\n1 error\n"); -} - DEF_TEST(SkSLDivByZero, r) { test_failure(r, "int x = 1 / 0;", @@ -466,4 +450,43 @@ DEF_TEST(SkSLFieldAfterRuntimeArray, r) { "array\n1 error\n"); } +DEF_TEST(SkSLStaticIf, r) { + test_success(r, + "void main() { float x = 5; float y = 10;" + "@if (x < y) { sk_FragColor = vec4(1); } }"); + test_failure(r, + "void main() { float x = sqrt(25); float y = 10;" + "@if (x < y) { sk_FragColor = vec4(1); } }", + "error: 1: static if has non-static test\n1 error\n"); +} + +DEF_TEST(SkSLStaticSwitch, r) { + test_success(r, + "void main() {" + "int x = 1;" + "@switch (x) {" + "case 1: sk_FragColor = vec4(1); break;" + "default: sk_FragColor = vec4(0);" + "}" + "}"); + test_failure(r, + "void main() {" + "int x = int(sqrt(1));" + "@switch (x) {" + "case 1: sk_FragColor = vec4(1); break;" + "default: sk_FragColor = vec4(0);" + "}" + "}", + "error: 1: static switch has non-static test\n1 error\n"); + test_failure(r, + "void main() {" + "int x = 1;" + "@switch (x) {" + "case 1: sk_FragColor = vec4(1); if (sqrt(0) < sqrt(1)) break;" + "default: sk_FragColor = vec4(0);" + "}" + "}", + "error: 1: static switch contains non-static conditional break\n1 error\n"); +} + #endif diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp index 32fd668dda..ff1d5f5972 100644 --- a/tests/SkSLGLSLTest.cpp +++ b/tests/SkSLGLSLTest.cpp @@ -831,7 +831,7 @@ DEF_TEST(SkSLMatFolding, r) { "}\n"); } -DEF_TEST(SkSLStaticIf, r) { +DEF_TEST(SkSLConstantIf, r) { test(r, "void main() {" "int x;" @@ -1067,10 +1067,11 @@ DEF_TEST(SkSLGeometry, r) { } DEF_TEST(SkSLSwitch, r) { + // basic "does a switch even work" test test(r, "void main() {" " float x;" - " switch (1) {" + " switch (int(sqrt(1))) {" " case 0:" " x = 0.0;" " break;" @@ -1087,7 +1088,7 @@ DEF_TEST(SkSLSwitch, r) { "out vec4 sk_FragColor;\n" "void main() {\n" " float x;\n" - " switch (1) {\n" + " switch (int(sqrt(1.0))) {\n" " case 0:\n" " x = 0.0;\n" " break;\n" @@ -1099,10 +1100,11 @@ DEF_TEST(SkSLSwitch, r) { " }\n" " sk_FragColor = vec4(x);\n" "}\n"); + // dead code inside of switch test(r, "void main() {" " float x;" - " switch (2) {" + " switch (int(sqrt(2))) {" " case 0:" " x = 0.0;" " case 1:" @@ -1116,7 +1118,7 @@ DEF_TEST(SkSLSwitch, r) { "#version 400\n" "out vec4 sk_FragColor;\n" "void main() {\n" - " switch (2) {\n" + " switch (int(sqrt(2.0))) {\n" " case 0:\n" " ;\n" " case 1:\n" @@ -1126,12 +1128,113 @@ DEF_TEST(SkSLSwitch, r) { " }\n" " sk_FragColor = vec4(2.0);\n" "}\n"); + // non-static test w/ fallthrough + test(r, + "void main() {" + " float x = 0.0;" + " switch (int(sqrt(3))) {" + " case 0:" + " x = 0.0;" + " case 1:" + " x = 1.0;" + " }" + " sk_FragColor = vec4(x);" + "}", + *SkSL::ShaderCapsFactory::Default(), + "#version 400\n" + "out vec4 sk_FragColor;\n" + "void main() {\n" + " float x = 0.0;\n" + " switch (int(sqrt(3.0))) {\n" + " case 0:\n" + " x = 0.0;\n" + " case 1:\n" + " x = 1.0;\n" + " }\n" + " sk_FragColor = vec4(x);\n" + "}\n"); + // static test w/ fallthrough + test(r, + "void main() {" + " float x = 0.0;" + " switch (0) {" + " case 0:" + " x = 0.0;" + " case 1:" + " x = 1.0;" + " }" + " sk_FragColor = vec4(x);" + "}", + *SkSL::ShaderCapsFactory::Default(), + "#version 400\n" + "out vec4 sk_FragColor;\n" + "void main() {\n" + " sk_FragColor = vec4(1.0);\n" + "}\n"); + // static test w/ fallthrough, different entry point + test(r, + "void main() {" + " float x = 0.0;" + " switch (1) {" + " case 0:" + " x = 0.0;" + " case 1:" + " x = 1.0;" + " }" + " sk_FragColor = vec4(x);" + "}", + *SkSL::ShaderCapsFactory::Default(), + "#version 400\n" + "out vec4 sk_FragColor;\n" + "void main() {\n" + " sk_FragColor = vec4(1.0);\n" + "}\n"); + // static test w/ break + test(r, + "void main() {" + " float x = 0.0;" + " switch (0) {" + " case 0:" + " x = 0.0;" + " break;" + " case 1:" + " x = 1.0;" + " }" + " sk_FragColor = vec4(x);" + "}", + *SkSL::ShaderCapsFactory::Default(), + "#version 400\n" + "out vec4 sk_FragColor;\n" + "void main() {\n" + " sk_FragColor = vec4(0.0);\n" + "}\n"); + // static test w/ static conditional break + test(r, + "void main() {" + " float x = 0.0;" + " switch (0) {" + " case 0:" + " x = 0.0;" + " if (x < 1) break;" + " case 1:" + " x = 1.0;" + " }" + " sk_FragColor = vec4(x);" + "}", + *SkSL::ShaderCapsFactory::Default(), + "#version 400\n" + "out vec4 sk_FragColor;\n" + "void main() {\n" + " sk_FragColor = vec4(0.0);\n" + "}\n"); + // static test w/ non-static conditional break test(r, "void main() {" " float x = 0.0;" - " switch (3) {" + " switch (0) {" " case 0:" " x = 0.0;" + " if (x < sqrt(1)) break;" " case 1:" " x = 1.0;" " }" @@ -1142,9 +1245,10 @@ DEF_TEST(SkSLSwitch, r) { "out vec4 sk_FragColor;\n" "void main() {\n" " float x = 0.0;\n" - " switch (3) {\n" + " switch (0) {\n" " case 0:\n" " x = 0.0;\n" + " if (0.0 < sqrt(1.0)) break;\n" " case 1:\n" " x = 1.0;\n" " }\n" diff --git a/tests/SkSLSPIRVTest.cpp b/tests/SkSLSPIRVTest.cpp new file mode 100644 index 0000000000..4d5457f339 --- /dev/null +++ b/tests/SkSLSPIRVTest.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSLCompiler.h" + +#include "Test.h" + +#if SK_SUPPORT_GPU + +static void test_failure(skiatest::Reporter* r, const char* src, const char* error) { + SkSL::Compiler compiler; + SkSL::Program::Settings settings; + sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default(); + settings.fCaps = caps.get(); + std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind, + SkString(src), settings); + if (program) { + SkSL::String ignored; + compiler.toSPIRV(*program, &ignored); + } + SkSL::String skError(error); + if (compiler.errorText() != skError) { + SkDebugf("SKSL ERROR:\n source: %s\n expected: %s received: %s", src, error, + compiler.errorText().c_str()); + } + REPORTER_ASSERT(r, compiler.errorText() == skError); +} + +DEF_TEST(SkSLBadOffset, r) { + test_failure(r, + "struct Bad { layout (offset = 5) int x; } bad; void main() { bad.x = 5; }", + "error: 1: offset of field 'x' must be a multiple of 4\n1 error\n"); + test_failure(r, + "struct Bad { int x; layout (offset = 0) int y; } bad; void main() { bad.x = 5; }", + "error: 1: offset of field 'y' must be at least 4\n1 error\n"); +} + +#endif |