Commit 49300865 by Olli Etuaho

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/251522Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org>
parent f3cc4aef
......@@ -2655,6 +2655,56 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyp
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.
//
......
......@@ -32,10 +32,10 @@ struct TParseContext {
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 @@ struct TParseContext {
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 @@ struct TParseContext {
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[],
......
......@@ -1625,22 +1625,22 @@ condition
;
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 @@ for_rest_statement
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 @@ function_definition
// 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 @@ function_definition
}
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();
}
......
......@@ -712,8 +712,8 @@ static const yytype_uint16 yyrline[] =
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 @@ yyreduce:
case 241:
{ context->symbolTable.push(); ++context->loopNestingLevel; }
{ context->symbolTable.push(); ++context->mLoopNestingLevel; }
break;
......@@ -4696,14 +4696,14 @@ yyreduce:
{
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 @@ yyreduce:
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 @@ yyreduce:
{
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 @@ yyreduce:
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 @@ yyreduce:
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 @@ yyreduce:
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 @@ yyreduce:
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 @@ yyreduce:
{
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 @@ yyreduce:
// 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 @@ yyreduce:
}
context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[0]));
(yyvsp[0].interm).intermAggregate = paramNodes;
context->loopNestingLevel = 0;
context->mLoopNestingLevel = 0;
}
break;
......@@ -4975,7 +4955,7 @@ yyreduce:
{
//?? 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();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment