Refactor validating jump statements out of glslang.y
Move the logic to ParseContext. This will simplify changing the logic for
the break statement that is needed to implement switch.
BUG=angle:921, angle:911
TEST=WebGL conformance tests
Change-Id: Ib8bbc7075c05d345e90377202b5446fb3307f94c
Reviewed-on: https://chromium-review.googlesource.com/251522
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index beac6b7..5c89a3b 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -2655,6 +2655,56 @@
return node;
}
+TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
+{
+ switch (op)
+ {
+ case EOpContinue:
+ if (mLoopNestingLevel <= 0)
+ {
+ error(loc, "continue statement only allowed in loops", "");
+ recover();
+ }
+ break;
+ case EOpBreak:
+ if (mLoopNestingLevel <= 0)
+ {
+ error(loc, "break statement only allowed in loops", "");
+ recover();
+ }
+ break;
+ case EOpReturn:
+ if (currentFunctionType->getBasicType() != EbtVoid)
+ {
+ error(loc, "non-void function must return a value", "return");
+ recover();
+ }
+ break;
+ default:
+ // No checks for discard
+ break;
+ }
+ return intermediate.addBranch(op, loc);
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
+{
+ ASSERT(op == EOpReturn);
+ mFunctionReturnsValue = true;
+ if (currentFunctionType->getBasicType() == EbtVoid)
+ {
+ error(loc, "void function cannot return a value", "return");
+ recover();
+ }
+ else if (*currentFunctionType != returnValue->getType())
+ {
+ error(loc, "function return is not matching type:", "return");
+ recover();
+ }
+ return intermediate.addBranch(op, returnValue, loc);
+}
+
+
//
// Parse an array of strings using yyparse.
//
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 2890bd0..b712730 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -32,10 +32,10 @@
shaderSpec(spec),
compileOptions(options),
treeRoot(0),
- loopNestingLevel(0),
+ mLoopNestingLevel(0),
structNestingLevel(0),
currentFunctionType(NULL),
- functionReturnsValue(false),
+ mFunctionReturnsValue(false),
checksPrecisionErrors(checksPrecErrors),
defaultMatrixPacking(EmpColumnMajor),
defaultBlockStorage(EbsShared),
@@ -51,10 +51,10 @@
int shaderVersion;
int compileOptions;
TIntermNode* treeRoot; // root of parse tree being created
- int loopNestingLevel; // 0 if outside all loops
+ int mLoopNestingLevel; // 0 if outside all loops
int structNestingLevel; // incremented while parsing a struct declaration
const TType* currentFunctionType; // the return type of the function that's currently being parsed
- bool functionReturnsValue; // true if a non-void function has a return
+ bool mFunctionReturnsValue; // true if a non-void function has a return
bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language.
TLayoutMatrixPacking defaultMatrixPacking;
@@ -170,6 +170,9 @@
const TSourceLoc &);
TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &);
+
+ TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
+ TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc);
};
int PaParseStrings(size_t count, const char* const string[], const int length[],
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index 3d857a1..12a410e 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -1625,22 +1625,22 @@
;
iteration_statement
- : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+ : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
context->symbolTable.pop();
$$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
- --context->loopNestingLevel;
+ --context->mLoopNestingLevel;
}
- | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ | DO { ++context->mLoopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
if (context->boolErrorCheck(@8, $6))
context->recover();
$$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
- --context->loopNestingLevel;
+ --context->mLoopNestingLevel;
}
- | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ | FOR LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
context->symbolTable.pop();
$$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
- --context->loopNestingLevel;
+ --context->mLoopNestingLevel;
}
;
@@ -1675,40 +1675,20 @@
jump_statement
: CONTINUE SEMICOLON {
- if (context->loopNestingLevel <= 0) {
- context->error(@1, "continue statement only allowed in loops", "");
- context->recover();
- }
- $$ = context->intermediate.addBranch(EOpContinue, @1);
+ $$ = context->addBranch(EOpContinue, @1);
}
| BREAK SEMICOLON {
- if (context->loopNestingLevel <= 0) {
- context->error(@1, "break statement only allowed in loops", "");
- context->recover();
- }
- $$ = context->intermediate.addBranch(EOpBreak, @1);
+ $$ = context->addBranch(EOpBreak, @1);
}
| RETURN SEMICOLON {
- $$ = context->intermediate.addBranch(EOpReturn, @1);
- if (context->currentFunctionType->getBasicType() != EbtVoid) {
- context->error(@1, "non-void function must return a value", "return");
- context->recover();
- }
+ $$ = context->addBranch(EOpReturn, @1);
}
| RETURN expression SEMICOLON {
- $$ = context->intermediate.addBranch(EOpReturn, $2, @1);
- context->functionReturnsValue = true;
- if (context->currentFunctionType->getBasicType() == EbtVoid) {
- context->error(@1, "void function cannot return a value", "return");
- context->recover();
- } else if (*(context->currentFunctionType) != $2->getType()) {
- context->error(@1, "function return is not matching type:", "return");
- context->recover();
- }
+ $$ = context->addBranch(EOpReturn, $2, @1);
}
| DISCARD SEMICOLON {
FRAG_ONLY("discard", @1);
- $$ = context->intermediate.addBranch(EOpKill, @1);
+ $$ = context->addBranch(EOpKill, @1);
}
;
@@ -1779,7 +1759,7 @@
// Remember the return type for later checking for RETURN statements.
//
context->currentFunctionType = &(prevDec->getReturnType());
- context->functionReturnsValue = false;
+ context->mFunctionReturnsValue = false;
//
// Insert parameters into the symbol table.
@@ -1818,12 +1798,12 @@
}
context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
$1.intermAggregate = paramNodes;
- context->loopNestingLevel = 0;
+ context->mLoopNestingLevel = 0;
}
compound_statement_no_new_scope {
//?? Check that all paths return a value if return type != void ?
// May be best done as post process phase on intermediate code
- if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) {
context->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
context->recover();
}
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 711bc52..2f85c46 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -712,8 +712,8 @@
1535, 1536, 1536, 1536, 1546, 1547, 1551, 1551, 1552, 1552,
1557, 1560, 1570, 1573, 1579, 1580, 1584, 1592, 1596, 1606,
1611, 1628, 1628, 1633, 1633, 1640, 1640, 1648, 1651, 1657,
- 1660, 1666, 1670, 1677, 1684, 1691, 1698, 1709, 1718, 1722,
- 1729, 1732, 1738, 1738
+ 1660, 1666, 1670, 1677, 1680, 1683, 1686, 1689, 1698, 1702,
+ 1709, 1712, 1718, 1718
};
#endif
@@ -4687,7 +4687,7 @@
case 241:
- { context->symbolTable.push(); ++context->loopNestingLevel; }
+ { context->symbolTable.push(); ++context->mLoopNestingLevel; }
break;
@@ -4696,14 +4696,14 @@
{
context->symbolTable.pop();
(yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
- --context->loopNestingLevel;
+ --context->mLoopNestingLevel;
}
break;
case 243:
- { ++context->loopNestingLevel; }
+ { ++context->mLoopNestingLevel; }
break;
@@ -4714,14 +4714,14 @@
context->recover();
(yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
- --context->loopNestingLevel;
+ --context->mLoopNestingLevel;
}
break;
case 245:
- { context->symbolTable.push(); ++context->loopNestingLevel; }
+ { context->symbolTable.push(); ++context->mLoopNestingLevel; }
break;
@@ -4730,7 +4730,7 @@
{
context->symbolTable.pop();
(yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[-3].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[-2].interm.nodePair).node2), (yyvsp[0].interm.intermNode), (yylsp[-6]));
- --context->loopNestingLevel;
+ --context->mLoopNestingLevel;
}
break;
@@ -4788,11 +4788,7 @@
case 253:
{
- if (context->loopNestingLevel <= 0) {
- context->error((yylsp[-1]), "continue statement only allowed in loops", "");
- context->recover();
- }
- (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yylsp[-1]));
+ (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1]));
}
break;
@@ -4800,11 +4796,7 @@
case 254:
{
- if (context->loopNestingLevel <= 0) {
- context->error((yylsp[-1]), "break statement only allowed in loops", "");
- context->recover();
- }
- (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yylsp[-1]));
+ (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1]));
}
break;
@@ -4812,11 +4804,7 @@
case 255:
{
- (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yylsp[-1]));
- if (context->currentFunctionType->getBasicType() != EbtVoid) {
- context->error((yylsp[-1]), "non-void function must return a value", "return");
- context->recover();
- }
+ (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1]));
}
break;
@@ -4824,15 +4812,7 @@
case 256:
{
- (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
- context->functionReturnsValue = true;
- if (context->currentFunctionType->getBasicType() == EbtVoid) {
- context->error((yylsp[-2]), "void function cannot return a value", "return");
- context->recover();
- } else if (*(context->currentFunctionType) != (yyvsp[-1].interm.intermTypedNode)->getType()) {
- context->error((yylsp[-2]), "function return is not matching type:", "return");
- context->recover();
- }
+ (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2]));
}
break;
@@ -4841,7 +4821,7 @@
{
FRAG_ONLY("discard", (yylsp[-1]));
- (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yylsp[-1]));
+ (yyval.interm.intermNode) = context->addBranch(EOpKill, (yylsp[-1]));
}
break;
@@ -4926,7 +4906,7 @@
// Remember the return type for later checking for RETURN statements.
//
context->currentFunctionType = &(prevDec->getReturnType());
- context->functionReturnsValue = false;
+ context->mFunctionReturnsValue = false;
//
// Insert parameters into the symbol table.
@@ -4965,7 +4945,7 @@
}
context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[0]));
(yyvsp[0].interm).intermAggregate = paramNodes;
- context->loopNestingLevel = 0;
+ context->mLoopNestingLevel = 0;
}
break;
@@ -4975,7 +4955,7 @@
{
//?? Check that all paths return a value if return type != void ?
// May be best done as post process phase on intermediate code
- if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) {
context->error((yylsp[-2]), "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str());
context->recover();
}