qmake: introduce magic bypassNesting() scope
will be needed by configure. Change-Id: If14e6944fe84767bd67604ecde98076f873749ef Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
169a40d511
commit
b6b44b368c
@ -329,6 +329,9 @@ enum ProToken {
|
||||
// - function name: hash (2), length (1), chars (length)
|
||||
// - body length (2)
|
||||
// - body + TokTerminator (body length)
|
||||
TokBypassNesting, // escape from function local variable scopes:
|
||||
// - block length (2)
|
||||
// - block + TokTerminator (block length)
|
||||
TokMask = 0xff,
|
||||
TokQuoted = 0x100, // The expression is quoted => join expanded stringlist
|
||||
TokNewStr = 0x200 // Next stringlist element
|
||||
|
@ -594,6 +594,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
|
||||
tokPtr += blockLen;
|
||||
okey = true, or_op = false; // force next evaluation
|
||||
break;
|
||||
case TokBypassNesting:
|
||||
blockLen = getBlockLen(tokPtr);
|
||||
if ((m_cumulative || okey != or_op) && blockLen) {
|
||||
ProValueMapStack savedValuemapStack = m_valuemapStack;
|
||||
m_valuemapStack.clear();
|
||||
m_valuemapStack.append(savedValuemapStack.takeFirst());
|
||||
traceMsg("visiting nesting-bypassing block");
|
||||
ret = visitProBlock(tokPtr);
|
||||
traceMsg("visited nesting-bypassing block");
|
||||
savedValuemapStack.prepend(m_valuemapStack.first());
|
||||
m_valuemapStack = savedValuemapStack;
|
||||
} else {
|
||||
traceMsg("skipped nesting-bypassing block");
|
||||
ret = ReturnTrue;
|
||||
}
|
||||
tokPtr += blockLen;
|
||||
okey = true, or_op = false; // force next evaluation
|
||||
break;
|
||||
case TokTestDef:
|
||||
case TokReplaceDef:
|
||||
if (m_cumulative || okey != or_op) {
|
||||
|
@ -118,6 +118,7 @@ static struct {
|
||||
QString strfor;
|
||||
QString strdefineTest;
|
||||
QString strdefineReplace;
|
||||
QString strbypassNesting;
|
||||
QString stroption;
|
||||
QString strreturn;
|
||||
QString strnext;
|
||||
@ -141,6 +142,7 @@ void QMakeParser::initialize()
|
||||
statics.strfor = QLatin1String("for");
|
||||
statics.strdefineTest = QLatin1String("defineTest");
|
||||
statics.strdefineReplace = QLatin1String("defineReplace");
|
||||
statics.strbypassNesting = QLatin1String("bypassNesting");
|
||||
statics.stroption = QLatin1String("option");
|
||||
statics.strreturn = QLatin1String("return");
|
||||
statics.strnext = QLatin1String("next");
|
||||
@ -1157,6 +1159,25 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
|
||||
}
|
||||
parseError(fL1S("%1(function) requires one literal argument.").arg(*defName));
|
||||
return;
|
||||
} else if (m_tmp == statics.strbypassNesting) {
|
||||
if (*uce != TokFuncTerminator) {
|
||||
bogusTest(tokPtr, fL1S("%1() requires zero arguments.").arg(m_tmp));
|
||||
return;
|
||||
}
|
||||
if (!(m_blockstack.top().nest & NestFunction)) {
|
||||
bogusTest(tokPtr, fL1S("Unexpected %1().").arg(m_tmp));
|
||||
return;
|
||||
}
|
||||
if (m_invert) {
|
||||
bogusTest(tokPtr, fL1S("Unexpected NOT operator in front of %1().").arg(m_tmp));
|
||||
return;
|
||||
}
|
||||
flushScopes(tokPtr);
|
||||
putLineMarker(tokPtr);
|
||||
putOperator(tokPtr);
|
||||
putTok(tokPtr, TokBypassNesting);
|
||||
enterScope(tokPtr, true, StCtrl);
|
||||
return;
|
||||
} else if (m_tmp == statics.strreturn) {
|
||||
if (m_blockstack.top().nest & NestFunction) {
|
||||
if (argc > 1) {
|
||||
@ -1425,7 +1446,7 @@ static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outS
|
||||
"TokReturn", "TokBreak", "TokNext",
|
||||
"TokNot", "TokAnd", "TokOr",
|
||||
"TokBranch", "TokForLoop",
|
||||
"TokTestDef", "TokReplaceDef"
|
||||
"TokTestDef", "TokReplaceDef", "TokBypassNesting"
|
||||
};
|
||||
|
||||
while (offset != limit) {
|
||||
@ -1509,6 +1530,9 @@ static bool getBlock(const ushort *tokens, int limit, int &offset, QString *outS
|
||||
if (ok)
|
||||
ok = getSubBlock(tokens, limit, offset, outStr, indent, "body");
|
||||
break;
|
||||
case TokBypassNesting:
|
||||
ok = getSubBlock(tokens, limit, offset, outStr, indent, "block");
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(!"unhandled token");
|
||||
}
|
||||
|
@ -633,6 +633,31 @@ void tst_qmakelib::addControlStructs()
|
||||
<< ""
|
||||
<< true;
|
||||
|
||||
QTest::newRow("bypassNesting()")
|
||||
<< "defineTest(func) {\n"
|
||||
"LOCAL = 1\n"
|
||||
"bypassNesting() {\n"
|
||||
"OUT = 1\n"
|
||||
"!isEmpty(GLOBAL): OUT1 = 1\n"
|
||||
"!isEmpty(LOCAL): OUT2 = 1\n"
|
||||
"}\n"
|
||||
"}\n"
|
||||
"GLOBAL = 1\n"
|
||||
"func()"
|
||||
<< "GLOBAL = 1\nLOCAL = UNDEF\nOUT = 1\nOUT1 = 1\nOUT2 = UNDEF"
|
||||
<< ""
|
||||
<< true;
|
||||
|
||||
QTest::newRow("error() from bypassNesting()")
|
||||
<< "defineTest(func) {\n"
|
||||
"bypassNesting() { error(error) }\n"
|
||||
"}\n"
|
||||
"func()\n"
|
||||
"OKE = 1"
|
||||
<< "OKE = UNDEF"
|
||||
<< "Project ERROR: error"
|
||||
<< false;
|
||||
|
||||
QTest::newRow("top-level return()")
|
||||
<< "VAR = good\nreturn()\nVAR = bad"
|
||||
<< "VAR = good"
|
||||
|
@ -1684,6 +1684,57 @@ void tst_qmakelib::addParseCustomFunctions()
|
||||
/* 22 */ << H(TokTerminator))
|
||||
<< ""
|
||||
<< true;
|
||||
|
||||
QTest::newRow("bypassNesting()-{return}")
|
||||
<< "defineTest(test) { bypassNesting() { return(true) } }"
|
||||
<< TS(
|
||||
/* 0 */ << H(TokLine) << H(1)
|
||||
/* 2 */ << H(TokTestDef) << HS(L"test")
|
||||
/* 10 */ /* body */ << I(16)
|
||||
/* 12 */ << H(TokLine) << H(1)
|
||||
/* 14 */ << H(TokBypassNesting)
|
||||
/* 15 */ /* block */ << I(10)
|
||||
/* 17 */ << H(TokLine) << H(1)
|
||||
/* 19 */ << H(TokLiteral | TokNewStr) << S(L"true")
|
||||
/* 25 */ << H(TokReturn)
|
||||
/* 26 */ << H(TokTerminator)
|
||||
/* 27 */ << H(TokTerminator))
|
||||
<< ""
|
||||
<< true;
|
||||
|
||||
QTest::newRow("test-AND-bypassNesting()-{}")
|
||||
<< "defineTest(test) { test: bypassNesting() {} }"
|
||||
<< TS(
|
||||
/* 0 */ << H(TokLine) << H(1)
|
||||
/* 2 */ << H(TokTestDef) << HS(L"test")
|
||||
/* 10 */ /* body */ << I(17)
|
||||
/* 12 */ << H(TokLine) << H(1)
|
||||
/* 14 */ << H(TokHashLiteral) << HS(L"test")
|
||||
/* 22 */ << H(TokCondition)
|
||||
/* 23 */ << H(TokAnd)
|
||||
/* 24 */ << H(TokBypassNesting)
|
||||
/* 25 */ /* block */ << I(1)
|
||||
/* 27 */ << H(TokTerminator)
|
||||
/* 28 */ << H(TokTerminator))
|
||||
<< ""
|
||||
<< true;
|
||||
|
||||
QTest::newRow("test-OR-bypassNesting()-{}")
|
||||
<< "defineTest(test) { test| bypassNesting() {} }"
|
||||
<< TS(
|
||||
/* 0 */ << H(TokLine) << H(1)
|
||||
/* 2 */ << H(TokTestDef) << HS(L"test")
|
||||
/* 10 */ /* body */ << I(17)
|
||||
/* 12 */ << H(TokLine) << H(1)
|
||||
/* 14 */ << H(TokHashLiteral) << HS(L"test")
|
||||
/* 22 */ << H(TokCondition)
|
||||
/* 23 */ << H(TokOr)
|
||||
/* 24 */ << H(TokBypassNesting)
|
||||
/* 25 */ /* block */ << I(1)
|
||||
/* 27 */ << H(TokTerminator)
|
||||
/* 28 */ << H(TokTerminator))
|
||||
<< ""
|
||||
<< true;
|
||||
}
|
||||
|
||||
void tst_qmakelib::addParseAbuse()
|
||||
@ -1736,6 +1787,24 @@ void tst_qmakelib::addParseAbuse()
|
||||
<< "in:1: Unexpected NOT operator in front of function definition."
|
||||
<< false;
|
||||
|
||||
QTest::newRow("outer-bypassNesting()-{}")
|
||||
<< "bypassNesting() {}"
|
||||
<< TS()
|
||||
<< "in:1: Unexpected bypassNesting()."
|
||||
<< false;
|
||||
|
||||
QTest::newRow("bypassNesting(arg)-{}")
|
||||
<< "defineTest(test) { bypassNesting(arg) {} }"
|
||||
<< TS()
|
||||
<< "in:1: bypassNesting() requires zero arguments."
|
||||
<< false;
|
||||
|
||||
QTest::newRow("NOT-bypassNesting()-{}")
|
||||
<< "defineTest(test) { !bypassNesting() {} }"
|
||||
<< TS()
|
||||
<< "in:1: Unexpected NOT operator in front of bypassNesting()."
|
||||
<< false;
|
||||
|
||||
QTest::newRow("AND-test")
|
||||
<< ":test"
|
||||
<< TS(
|
||||
|
Loading…
Reference in New Issue
Block a user