continue parsing line despite errors

as far as possible, anyway. and suppress messages after the first one.
this avoids that scope nesting gets thrown off and thus spurious
followup-errors crop up.

as a "side effect", this fixes a crash resulting from us rewinding the
token stream but ignoring the block stack on the way.

Task-number: QTCREATORBUG-4368
This commit is contained in:
Oswald Buddenhagen
2011-04-06 21:26:20 +02:00
parent d9e5f676ef
commit 17740d2ec3
3 changed files with 53 additions and 34 deletions

View File

@@ -909,7 +909,8 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
case TokCondition:
if (!m_skipLevel && okey != or_op) {
if (curr.size() != 1) {
evalError(fL1S("Conditional must expand to exactly one word."));
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Conditional must expand to exactly one word."));
okey = false;
} else {
okey = isActiveConfig(curr.at(0).toQString(m_tmp2), true) ^ invert;
@@ -922,7 +923,8 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
case TokTestCall:
if (!m_skipLevel && okey != or_op) {
if (curr.size() != 1) {
evalError(fL1S("Test name must expand to exactly one word."));
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Test name must expand to exactly one word."));
skipExpression(tokPtr);
okey = false;
} else {
@@ -1067,7 +1069,8 @@ void ProFileEvaluator::Private::visitProVariable(
if (curr.size() != 1) {
skipExpression(tokPtr);
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
return;
}
const ProString &varName = map(curr.first());

View File

@@ -286,11 +286,11 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
m_invert = false;
m_operator = NoOperator;
m_markLine = m_lineNo;
m_inError = false;
Context context = CtxTest;
int parens = 0; // Braces in value context
int argc = 0;
int wordCount = 0; // Number of words in currently accumulated expression
bool inError = false;
bool putSpace = false; // Only ever true inside quoted string
bool lineMarked = true; // For in-expression markers
ushort needSep = TokNewStr; // Complementary to putSpace: separator outside quotes
@@ -301,8 +301,6 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
ptr += 4;
ushort *xprPtr = ptr;
ushort *oldTokPtr = tokPtr;
#define FLUSH_LHS_LITERAL() \
do { \
if ((tlen = ptr - xprPtr)) { \
@@ -360,14 +358,9 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
c = *cur;
if (c == '\n') {
++cur;
if (!inError)
goto flushLine;
++m_lineNo;
goto freshLine;
goto flushLine;
} else if (!c) {
if (!inError)
goto flushLine;
goto flushFile;
goto flushLine;
} else if (c != ' ' && c != '\t' && c != '\r') {
break;
}
@@ -421,7 +414,6 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
--end;
}
if (!inError) {
// Finally, do the tokenization
ushort tok, rtok;
int tlen;
@@ -530,12 +522,11 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
parseError(fL1S("Missing %1 terminator [found %2]")
.arg(QChar(term))
.arg(c ? QString(c) : QString::fromLatin1("end-of-line")));
parseErr:
pro->setOk(false);
xprStack.resize(0);
tokPtr = oldTokPtr;
inError = true;
goto skip;
m_inError = true;
if (c)
cur--;
// Just parse on, as if there was a terminator ...
}
}
joinToken:
@@ -617,7 +608,8 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
parseError(fL1S("Extra characters after test expression."));
else
parseError(fL1S("Opening parenthesis without prior test name."));
goto parseErr;
pro->setOk(false);
ptr = buf; // Put empty function name
}
*ptr++ = TokTestCall;
term = ':';
@@ -688,9 +680,11 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
putLineMarker(tokPtr);
if (wordCount != 1) {
parseError(fL1S("Assignment needs exactly one word on the left hand side."));
goto parseErr;
pro->setOk(false);
// Put empty variable name.
} else {
putBlock(tokPtr, buf, ptr - buf);
}
putBlock(tokPtr, buf, ptr - buf);
putTok(tokPtr, tok);
context = CtxValue;
ptr = ++tokPtr;
@@ -737,23 +731,34 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
FLUSH_LITERAL();
if (quote) {
parseError(fL1S("Missing closing %1 quote").arg(QChar(quote)));
goto parseErr;
}
if (!xprStack.isEmpty()) {
if (!xprStack.isEmpty()) {
context = xprStack.at(0).context;
xprStack.clear();
}
goto flErr;
} else if (!xprStack.isEmpty()) {
parseError(fL1S("Missing closing parenthesis in function call"));
goto parseErr;
}
if (context == CtxValue)
context = xprStack.at(0).context;
xprStack.clear();
flErr:
pro->setOk(false);
if (context == CtxValue) {
tokPtr[-1] = 0; // sizehint
putTok(tokPtr, TokValueTerminator);
} else {
bogusTest(tokPtr);
}
} else if (context == CtxValue) {
FLUSH_VALUE_LIST();
else
} else {
finalizeCond(tokPtr, buf, ptr, wordCount);
}
if (!c)
break;
++m_lineNo;
goto freshLine;
}
} // !inError
skip:
if (!lineCont) {
cur = cptr;
++m_lineNo;
@@ -765,7 +770,6 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
++m_lineNo;
}
flushFile:
flushScopes(tokPtr);
if (m_blockstack.size() > 1) {
parseError(fL1S("Missing closing brace(s)."));
@@ -862,12 +866,22 @@ void ProFileParser::finalizeTest(ushort *&tokPtr)
m_canElse = true;
}
void ProFileParser::bogusTest(ushort *&tokPtr)
{
flushScopes(tokPtr);
m_operator = NoOperator;
m_invert = false;
m_state = StCond;
m_canElse = true;
m_proFile->setOk(false);
}
void ProFileParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount)
{
if (wordCount != 1) {
if (wordCount) {
parseError(fL1S("Extra characters after test expression."));
m_proFile->setOk(false);
bogusTest(tokPtr);
}
return;
}
@@ -1008,7 +1022,7 @@ void ProFileParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int a
void ProFileParser::parseError(const QString &msg) const
{
if (m_handler)
if (!m_inError && m_handler)
m_handler->parseError(m_proFile->fileName(), m_lineNo, msg);
}

View File

@@ -116,6 +116,7 @@ private:
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void finalizeTest(ushort *&tokPtr);
void bogusTest(ushort *&tokPtr);
void enterScope(ushort *&tokPtr, bool special, ScopeState state);
void leaveScope(ushort *&tokPtr);
void flushCond(ushort *&tokPtr);
@@ -130,6 +131,7 @@ private:
QStack<BlockScope> m_blockstack;
ScopeState m_state;
int m_markLine; // Put marker for this line
bool m_inError; // Current line had a parsing error; suppress followup error messages
bool m_canElse; // Conditionals met on previous line, but no scope was opened
bool m_invert; // Pending conditional is negated
enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed