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 ...@@ -2655,6 +2655,56 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyp
return node; 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. // Parse an array of strings using yyparse.
// //
......
...@@ -32,10 +32,10 @@ struct TParseContext { ...@@ -32,10 +32,10 @@ struct TParseContext {
shaderSpec(spec), shaderSpec(spec),
compileOptions(options), compileOptions(options),
treeRoot(0), treeRoot(0),
loopNestingLevel(0), mLoopNestingLevel(0),
structNestingLevel(0), structNestingLevel(0),
currentFunctionType(NULL), currentFunctionType(NULL),
functionReturnsValue(false), mFunctionReturnsValue(false),
checksPrecisionErrors(checksPrecErrors), checksPrecisionErrors(checksPrecErrors),
defaultMatrixPacking(EmpColumnMajor), defaultMatrixPacking(EmpColumnMajor),
defaultBlockStorage(EbsShared), defaultBlockStorage(EbsShared),
...@@ -51,10 +51,10 @@ struct TParseContext { ...@@ -51,10 +51,10 @@ struct TParseContext {
int shaderVersion; int shaderVersion;
int compileOptions; int compileOptions;
TIntermNode* treeRoot; // root of parse tree being created 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 int structNestingLevel; // incremented while parsing a struct declaration
const TType* currentFunctionType; // the return type of the function that's currently being parsed 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 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. bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language.
TLayoutMatrixPacking defaultMatrixPacking; TLayoutMatrixPacking defaultMatrixPacking;
...@@ -170,6 +170,9 @@ struct TParseContext { ...@@ -170,6 +170,9 @@ struct TParseContext {
const TSourceLoc &); const TSourceLoc &);
TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &); 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[], int PaParseStrings(size_t count, const char* const string[], const int length[],
......
...@@ -1625,22 +1625,22 @@ condition ...@@ -1625,22 +1625,22 @@ condition
; ;
iteration_statement 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->symbolTable.pop();
$$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1); $$ = 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)) if (context->boolErrorCheck(@8, $6))
context->recover(); context->recover();
$$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); $$ = 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->symbolTable.pop();
$$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1); $$ = 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 ...@@ -1675,40 +1675,20 @@ for_rest_statement
jump_statement jump_statement
: CONTINUE SEMICOLON { : CONTINUE SEMICOLON {
if (context->loopNestingLevel <= 0) { $$ = context->addBranch(EOpContinue, @1);
context->error(@1, "continue statement only allowed in loops", "");
context->recover();
}
$$ = context->intermediate.addBranch(EOpContinue, @1);
} }
| BREAK SEMICOLON { | BREAK SEMICOLON {
if (context->loopNestingLevel <= 0) { $$ = context->addBranch(EOpBreak, @1);
context->error(@1, "break statement only allowed in loops", "");
context->recover();
}
$$ = context->intermediate.addBranch(EOpBreak, @1);
} }
| RETURN SEMICOLON { | RETURN SEMICOLON {
$$ = context->intermediate.addBranch(EOpReturn, @1); $$ = context->addBranch(EOpReturn, @1);
if (context->currentFunctionType->getBasicType() != EbtVoid) {
context->error(@1, "non-void function must return a value", "return");
context->recover();
}
} }
| RETURN expression SEMICOLON { | RETURN expression SEMICOLON {
$$ = context->intermediate.addBranch(EOpReturn, $2, @1); $$ = context->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();
}
} }
| DISCARD SEMICOLON { | DISCARD SEMICOLON {
FRAG_ONLY("discard", @1); FRAG_ONLY("discard", @1);
$$ = context->intermediate.addBranch(EOpKill, @1); $$ = context->addBranch(EOpKill, @1);
} }
; ;
...@@ -1779,7 +1759,7 @@ function_definition ...@@ -1779,7 +1759,7 @@ function_definition
// Remember the return type for later checking for RETURN statements. // Remember the return type for later checking for RETURN statements.
// //
context->currentFunctionType = &(prevDec->getReturnType()); context->currentFunctionType = &(prevDec->getReturnType());
context->functionReturnsValue = false; context->mFunctionReturnsValue = false;
// //
// Insert parameters into the symbol table. // Insert parameters into the symbol table.
...@@ -1818,12 +1798,12 @@ function_definition ...@@ -1818,12 +1798,12 @@ function_definition
} }
context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1); context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
$1.intermAggregate = paramNodes; $1.intermAggregate = paramNodes;
context->loopNestingLevel = 0; context->mLoopNestingLevel = 0;
} }
compound_statement_no_new_scope { compound_statement_no_new_scope {
//?? Check that all paths return a value if return type != void ? //?? Check that all paths return a value if return type != void ?
// May be best done as post process phase on intermediate code // 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->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
context->recover(); context->recover();
} }
......
...@@ -712,8 +712,8 @@ static const yytype_uint16 yyrline[] = ...@@ -712,8 +712,8 @@ static const yytype_uint16 yyrline[] =
1535, 1536, 1536, 1536, 1546, 1547, 1551, 1551, 1552, 1552, 1535, 1536, 1536, 1536, 1546, 1547, 1551, 1551, 1552, 1552,
1557, 1560, 1570, 1573, 1579, 1580, 1584, 1592, 1596, 1606, 1557, 1560, 1570, 1573, 1579, 1580, 1584, 1592, 1596, 1606,
1611, 1628, 1628, 1633, 1633, 1640, 1640, 1648, 1651, 1657, 1611, 1628, 1628, 1633, 1633, 1640, 1640, 1648, 1651, 1657,
1660, 1666, 1670, 1677, 1684, 1691, 1698, 1709, 1718, 1722, 1660, 1666, 1670, 1677, 1680, 1683, 1686, 1689, 1698, 1702,
1729, 1732, 1738, 1738 1709, 1712, 1718, 1718
}; };
#endif #endif
...@@ -4687,7 +4687,7 @@ yyreduce: ...@@ -4687,7 +4687,7 @@ yyreduce:
case 241: case 241:
{ context->symbolTable.push(); ++context->loopNestingLevel; } { context->symbolTable.push(); ++context->mLoopNestingLevel; }
break; break;
...@@ -4696,14 +4696,14 @@ yyreduce: ...@@ -4696,14 +4696,14 @@ yyreduce:
{ {
context->symbolTable.pop(); context->symbolTable.pop();
(yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5])); (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[0].interm.intermNode), (yylsp[-5]));
--context->loopNestingLevel; --context->mLoopNestingLevel;
} }
break; break;
case 243: case 243:
{ ++context->loopNestingLevel; } { ++context->mLoopNestingLevel; }
break; break;
...@@ -4714,14 +4714,14 @@ yyreduce: ...@@ -4714,14 +4714,14 @@ yyreduce:
context->recover(); context->recover();
(yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4])); (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4]));
--context->loopNestingLevel; --context->mLoopNestingLevel;
} }
break; break;
case 245: case 245:
{ context->symbolTable.push(); ++context->loopNestingLevel; } { context->symbolTable.push(); ++context->mLoopNestingLevel; }
break; break;
...@@ -4730,7 +4730,7 @@ yyreduce: ...@@ -4730,7 +4730,7 @@ yyreduce:
{ {
context->symbolTable.pop(); 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])); (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; break;
...@@ -4788,11 +4788,7 @@ yyreduce: ...@@ -4788,11 +4788,7 @@ yyreduce:
case 253: case 253:
{ {
if (context->loopNestingLevel <= 0) { (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1]));
context->error((yylsp[-1]), "continue statement only allowed in loops", "");
context->recover();
}
(yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yylsp[-1]));
} }
break; break;
...@@ -4800,11 +4796,7 @@ yyreduce: ...@@ -4800,11 +4796,7 @@ yyreduce:
case 254: case 254:
{ {
if (context->loopNestingLevel <= 0) { (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1]));
context->error((yylsp[-1]), "break statement only allowed in loops", "");
context->recover();
}
(yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yylsp[-1]));
} }
break; break;
...@@ -4812,11 +4804,7 @@ yyreduce: ...@@ -4812,11 +4804,7 @@ yyreduce:
case 255: case 255:
{ {
(yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yylsp[-1])); (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1]));
if (context->currentFunctionType->getBasicType() != EbtVoid) {
context->error((yylsp[-1]), "non-void function must return a value", "return");
context->recover();
}
} }
break; break;
...@@ -4824,15 +4812,7 @@ yyreduce: ...@@ -4824,15 +4812,7 @@ yyreduce:
case 256: case 256:
{ {
(yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2])); (yyval.interm.intermNode) = context->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();
}
} }
break; break;
...@@ -4841,7 +4821,7 @@ yyreduce: ...@@ -4841,7 +4821,7 @@ yyreduce:
{ {
FRAG_ONLY("discard", (yylsp[-1])); FRAG_ONLY("discard", (yylsp[-1]));
(yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yylsp[-1])); (yyval.interm.intermNode) = context->addBranch(EOpKill, (yylsp[-1]));
} }
break; break;
...@@ -4926,7 +4906,7 @@ yyreduce: ...@@ -4926,7 +4906,7 @@ yyreduce:
// Remember the return type for later checking for RETURN statements. // Remember the return type for later checking for RETURN statements.
// //
context->currentFunctionType = &(prevDec->getReturnType()); context->currentFunctionType = &(prevDec->getReturnType());
context->functionReturnsValue = false; context->mFunctionReturnsValue = false;
// //
// Insert parameters into the symbol table. // Insert parameters into the symbol table.
...@@ -4965,7 +4945,7 @@ yyreduce: ...@@ -4965,7 +4945,7 @@ yyreduce:
} }
context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[0])); context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[0]));
(yyvsp[0].interm).intermAggregate = paramNodes; (yyvsp[0].interm).intermAggregate = paramNodes;
context->loopNestingLevel = 0; context->mLoopNestingLevel = 0;
} }
break; break;
...@@ -4975,7 +4955,7 @@ yyreduce: ...@@ -4975,7 +4955,7 @@ yyreduce:
{ {
//?? Check that all paths return a value if return type != void ? //?? Check that all paths return a value if return type != void ?
// May be best done as post process phase on intermediate code // 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->error((yylsp[-2]), "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str());
context->recover(); 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