be more strict about bogus operators

we now warn about the pointless ones, and error out in cases that
already were semantically bogus.

Change-Id: Ifd80014af0fc53e3cc42561c4270d1dca234568f
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
Oswald Buddenhagen 2015-02-18 11:20:01 +01:00
parent 7dcc2b3246
commit 73c84fb32b
2 changed files with 59 additions and 6 deletions

View File

@ -671,6 +671,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} else if (c == ':') {
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
warnOperator("in front of AND operator");
if (m_state == StNew)
parseError(fL1S("AND operator without prior condition."));
else
@ -681,6 +682,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} else if (c == '|') {
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
warnOperator("in front of OR operator");
if (m_state != StCond)
parseError(fL1S("OR operator without prior condition."));
else
@ -689,7 +691,13 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} else if (c == '{') {
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
if (m_operator == AndOperator) {
languageWarning(fL1S("Excess colon in front of opening brace."));
m_operator = NoOperator;
}
failOperator("in front of opening brace");
flushCond(tokPtr);
m_state = StNew; // Reset possible StCtrl, so colons get rejected.
++m_blockstack.top().braceLevel;
if (grammar == TestGrammar)
parseError(fL1S("Opening scope not permitted in this context."));
@ -700,6 +708,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
m_state = StNew; // De-facto newline
closeScope:
flushScopes(tokPtr);
failOperator("in front of closing brace");
if (!m_blockstack.top().braceLevel) {
parseError(fL1S("Excess closing brace."));
} else if (!--m_blockstack.top().braceLevel
@ -731,6 +740,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
doOp:
FLUSH_LHS_LITERAL();
flushCond(tokPtr);
acceptColon("in front of assignment");
putLineMarker(tokPtr);
if (grammar == TestGrammar) {
parseError(fL1S("Assignment not permitted in this context."));
@ -815,6 +825,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
putTok(tokPtr, TokValueTerminator);
} else {
finalizeCond(tokPtr, buf, ptr, wordCount);
warnOperator("at end of line");
}
if (!cur)
break;
@ -908,6 +919,48 @@ void QMakeParser::flushCond(ushort *&tokPtr)
}
}
void QMakeParser::warnOperator(const char *msg)
{
if (m_invert) {
languageWarning(fL1S("Stray NOT operator %1.").arg(fL1S(msg)));
m_invert = false;
}
if (m_operator == AndOperator) {
languageWarning(fL1S("Stray AND operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
} else if (m_operator == OrOperator) {
languageWarning(fL1S("Stray OR operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
}
}
bool QMakeParser::failOperator(const char *msg)
{
bool fail = false;
if (m_invert) {
parseError(fL1S("Unexpected NOT operator %1.").arg(fL1S(msg)));
m_invert = false;
fail = true;
}
if (m_operator == AndOperator) {
parseError(fL1S("Unexpected AND operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
fail = true;
} else if (m_operator == OrOperator) {
parseError(fL1S("Unexpected OR operator %1.").arg(fL1S(msg)));
m_operator = NoOperator;
fail = true;
}
return fail;
}
bool QMakeParser::acceptColon(const char *msg)
{
if (m_operator == AndOperator)
m_operator = NoOperator;
return !failOperator(msg);
}
void QMakeParser::putOperator(ushort *&tokPtr)
{
if (m_operator== AndOperator) {
@ -961,10 +1014,8 @@ void QMakeParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wor
if (uce == ptr) {
m_tmp.setRawData((QChar *)uc + 4, nlen);
if (!m_tmp.compare(statics.strelse, Qt::CaseInsensitive)) {
if (m_invert || m_operator != NoOperator) {
parseError(fL1S("Unexpected operator in front of else."));
if (failOperator("in front of else"))
return;
}
BlockScope &top = m_blockstack.top();
if (m_canElse && (!top.special || top.braceLevel)) {
// A list of tests (the last one likely with side effects),
@ -1009,9 +1060,8 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
const QString *defName;
ushort defType;
if (m_tmp == statics.strfor) {
if (m_invert || m_operator == OrOperator) {
// '|' could actually work reasonably, but qmake does nonsense here.
bogusTest(tokPtr, fL1S("Unexpected operator in front of for()."));
if (!acceptColon("in front of for()")) {
bogusTest(tokPtr, QString());
return;
}
flushCond(tokPtr);

View File

@ -144,6 +144,9 @@ private:
const ushort *cur, const QString &in);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void warnOperator(const char *msg);
bool failOperator(const char *msg);
bool acceptColon(const char *msg);
void putOperator(ushort *&tokPtr);
void finalizeTest(ushort *&tokPtr);
void bogusTest(ushort *&tokPtr, const QString &msg);