support custom functions: implement defineTest(), defineReplace(), defined(), return() & export()

This commit is contained in:
Oswald Buddenhagen
2009-05-18 17:46:30 +02:00
parent 6ca93b31fd
commit d077ba29c3
4 changed files with 284 additions and 111 deletions

View File

@@ -37,17 +37,18 @@ QT_BEGIN_NAMESPACE
struct AbstractProItemVisitor struct AbstractProItemVisitor
{ {
virtual ~AbstractProItemVisitor() {} virtual ~AbstractProItemVisitor() {}
virtual void visitBeginProBlock(ProBlock *block) = 0;
virtual ProItem::ProItemReturn visitBeginProBlock(ProBlock *block) = 0;
virtual void visitEndProBlock(ProBlock *block) = 0; virtual void visitEndProBlock(ProBlock *block) = 0;
virtual void visitBeginProVariable(ProVariable *variable) = 0; virtual void visitBeginProVariable(ProVariable *variable) = 0;
virtual void visitEndProVariable(ProVariable *variable) = 0; virtual void visitEndProVariable(ProVariable *variable) = 0;
virtual bool visitBeginProFile(ProFile *value) = 0; virtual ProItem::ProItemReturn visitBeginProFile(ProFile *value) = 0;
virtual bool visitEndProFile(ProFile *value) = 0; virtual ProItem::ProItemReturn visitEndProFile(ProFile *value) = 0;
virtual void visitProValue(ProValue *value) = 0; virtual void visitProValue(ProValue *value) = 0;
virtual void visitProFunction(ProFunction *function) = 0; virtual ProItem::ProItemReturn visitProFunction(ProFunction *function) = 0;
virtual void visitProOperator(ProOperator *function) = 0; virtual void visitProOperator(ProOperator *function) = 0;
virtual void visitProCondition(ProCondition *function) = 0; virtual void visitProCondition(ProCondition *function) = 0;
}; };

View File

@@ -157,14 +157,14 @@ public:
/////////////// Evaluating pro file contents /////////////// Evaluating pro file contents
// implementation of AbstractProItemVisitor // implementation of AbstractProItemVisitor
void visitBeginProBlock(ProBlock *block); ProItem::ProItemReturn visitBeginProBlock(ProBlock *block);
void visitEndProBlock(ProBlock *block); void visitEndProBlock(ProBlock *block);
void visitBeginProVariable(ProVariable *variable); void visitBeginProVariable(ProVariable *variable);
void visitEndProVariable(ProVariable *variable); void visitEndProVariable(ProVariable *variable);
bool visitBeginProFile(ProFile *value); ProItem::ProItemReturn visitBeginProFile(ProFile *value);
bool visitEndProFile(ProFile *value); ProItem::ProItemReturn visitEndProFile(ProFile *value);
void visitProValue(ProValue *value); void visitProValue(ProValue *value);
void visitProFunction(ProFunction *function); ProItem::ProItemReturn visitProFunction(ProFunction *function);
void visitProOperator(ProOperator *oper); void visitProOperator(ProOperator *oper);
void visitProCondition(ProCondition *condition); void visitProCondition(ProCondition *condition);
@@ -187,10 +187,15 @@ public:
QString currentDirectory() const; QString currentDirectory() const;
ProFile *currentProFile() const; ProFile *currentProFile() const;
bool evaluateConditionalFunction(const QString &function, const QString &arguments); ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments);
bool evaluateFile(const QString &fileName); bool evaluateFile(const QString &fileName);
bool evaluateFeatureFile(const QString &fileName); bool evaluateFeatureFile(const QString &fileName);
static inline ProItem::ProItemReturn returnBool(bool b)
{ return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; }
QStringList evaluateFunction(ProBlock *funcPtr, const QStringList &argumentsList, bool *ok);
QStringList qmakeFeaturePaths(); QStringList qmakeFeaturePaths();
struct State { struct State {
@@ -217,6 +222,14 @@ public:
QHash<QString, QString> m_properties; QHash<QString, QString> m_properties;
QString m_outputDir; QString m_outputDir;
bool m_definingTest;
QString m_definingFunc;
QHash<QString, ProBlock *> m_testFunctions;
QHash<QString, ProBlock *> m_replaceFunctions;
QStringList m_returnValue;
QStack<QHash<QString, QStringList> > m_valuemapStack;
QStack<QHash<const ProFile*, QHash<QString, QStringList> > > m_filevaluemapStack;
int m_prevLineNo; // Checking whether we're assigning the same TARGET int m_prevLineNo; // Checking whether we're assigning the same TARGET
ProFile *m_prevProFile; // See m_prevLineNo ProFile *m_prevProFile; // See m_prevLineNo
QStringList m_addUserConfigCmdArgs; QStringList m_addUserConfigCmdArgs;
@@ -236,6 +249,7 @@ ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
// Configuration, more or less // Configuration, more or less
m_verbose = true; m_verbose = true;
m_cumulative = true; m_cumulative = true;
m_parsePreAndPostFiles = true;
// Evaluator state // Evaluator state
m_sts.condition = false; m_sts.condition = false;
@@ -243,7 +257,7 @@ ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
m_invertNext = false; m_invertNext = false;
m_skipLevel = 0; m_skipLevel = 0;
m_isFirstVariableValue = true; m_isFirstVariableValue = true;
m_parsePreAndPostFiles = true; m_definingFunc.clear();
} }
bool ProFileEvaluator::Private::read(ProFile *pro) bool ProFileEvaluator::Private::read(ProFile *pro)
@@ -555,13 +569,27 @@ void ProFileEvaluator::Private::updateItem()
} }
void ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
{ {
if (block->blockKind() & ProBlock::ScopeContentsKind) { if (block->blockKind() & ProBlock::ScopeContentsKind) {
if (!m_definingFunc.isEmpty()) {
if (!m_skipLevel || m_cumulative) {
QHash<QString, ProBlock *> *hash =
(m_definingTest ? &m_testFunctions : &m_replaceFunctions);
if (ProBlock *def = hash->value(m_definingFunc))
def->deref();
hash->insert(m_definingFunc, block);
block->ref();
block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind);
}
m_definingFunc.clear();
return ProItem::ReturnSkip;
} else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) {
if (!m_sts.condition) if (!m_sts.condition)
++m_skipLevel; ++m_skipLevel;
else else
Q_ASSERT(!m_skipLevel); Q_ASSERT(!m_skipLevel);
}
} else { } else {
if (!m_skipLevel) { if (!m_skipLevel) {
if (m_sts.condition) { if (m_sts.condition) {
@@ -572,11 +600,13 @@ void ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
Q_ASSERT(!m_sts.condition); Q_ASSERT(!m_sts.condition);
} }
} }
return ProItem::ReturnTrue;
} }
void ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) void ProFileEvaluator::Private::visitEndProBlock(ProBlock *block)
{ {
if (block->blockKind() & ProBlock::ScopeContentsKind) { if ((block->blockKind() & ProBlock::ScopeContentsKind)
&& !(block->blockKind() & ProBlock::FunctionBodyKind)) {
if (m_skipLevel) { if (m_skipLevel) {
Q_ASSERT(!m_sts.condition); Q_ASSERT(!m_sts.condition);
--m_skipLevel; --m_skipLevel;
@@ -624,10 +654,9 @@ void ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
m_invertNext = false; m_invertNext = false;
} }
bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
{ {
PRE(pro); PRE(pro);
bool ok = true;
m_lineNo = pro->lineNumber(); m_lineNo = pro->lineNumber();
if (m_origfile.isEmpty()) if (m_origfile.isEmpty())
m_origfile = pro->fileName(); m_origfile = pro->fileName();
@@ -655,16 +684,15 @@ bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
m_cumulative = cumulative; m_cumulative = cumulative;
} }
ok = QDir::setCurrent(pro->directoryName()); return returnBool(QDir::setCurrent(pro->directoryName()));
} }
return ok; return ProItem::ReturnTrue;
} }
bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) ProItem::ProItemReturn ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
{ {
PRE(pro); PRE(pro);
bool ok = true;
m_lineNo = pro->lineNumber(); m_lineNo = pro->lineNumber();
if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) { if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) {
const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
@@ -693,13 +721,21 @@ bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
break; break;
} }
foreach (ProBlock *itm, m_replaceFunctions)
itm->deref();
m_replaceFunctions.clear();
foreach (ProBlock *itm, m_testFunctions)
itm->deref();
m_testFunctions.clear();
m_cumulative = cumulative; m_cumulative = cumulative;
} }
m_profileStack.pop(); m_profileStack.pop();
ok = QDir::setCurrent(m_oldPath); return returnBool(QDir::setCurrent(m_oldPath));
} }
return ok;
return ProItem::ReturnTrue;
} }
static void replaceInList(QStringList *varlist, static void replaceInList(QStringList *varlist,
@@ -854,7 +890,7 @@ void ProFileEvaluator::Private::visitProValue(ProValue *value)
m_isFirstVariableValue = false; m_isFirstVariableValue = false;
} }
void ProFileEvaluator::Private::visitProFunction(ProFunction *func) ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func)
{ {
// Make sure that called subblocks don't inherit & destroy the state // Make sure that called subblocks don't inherit & destroy the state
bool invertThis = m_invertNext; bool invertThis = m_invertNext;
@@ -869,10 +905,13 @@ void ProFileEvaluator::Private::visitProFunction(ProFunction *func)
QString arguments = text.mid(lparen + 1, rparen - lparen - 1); QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
QString funcName = text.left(lparen); QString funcName = text.left(lparen);
m_lineNo = func->lineNumber(); m_lineNo = func->lineNumber();
bool result = evaluateConditionalFunction(funcName.trimmed(), arguments); ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments);
if (!m_skipLevel && (result ^ invertThis)) if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue)
return result;
if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis))
m_sts.condition = true; m_sts.condition = true;
} }
return ProItem::ReturnTrue;
} }
@@ -1212,10 +1251,49 @@ bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex
return false; return false;
} }
QStringList ProFileEvaluator::Private::evaluateFunction(
ProBlock *funcPtr, const QStringList &argumentsList, bool *ok)
{
bool oki;
QStringList ret;
if (m_valuemapStack.count() >= 100) {
q->errorMessage(format("ran into infinite recursion (depth > 100)."));
ok = false;
} else {
State sts = m_sts;
m_valuemapStack.push(m_valuemap);
m_filevaluemapStack.push(m_filevaluemap);
QStringList args;
for (int i = 0; i < argumentsList.count(); ++i) {
QStringList theArgs = expandVariableReferences(argumentsList[i]);
args += theArgs;
m_valuemap[QString::number(i+1)] = theArgs;
}
m_valuemap[QLatin1String("ARGS")] = args;
oki = (funcPtr->Accept(this) != ProItem::ReturnFalse); // True || Return
ret = m_returnValue;
m_returnValue.clear();
m_valuemap = m_valuemapStack.pop();
m_filevaluemap = m_filevaluemapStack.pop();
m_sts = sts;
}
if (ok)
*ok = oki;
if (oki)
return ret;
return QStringList();
}
QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments) QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments)
{ {
QStringList argumentsList = split_arg_list(arguments); QStringList argumentsList = split_arg_list(arguments);
if (ProBlock *funcPtr = m_replaceFunctions.value(func, 0))
return evaluateFunction(funcPtr, argumentsList, 0);
QStringList args; QStringList args;
for (int i = 0; i < argumentsList.count(); ++i) for (int i = 0; i < argumentsList.count(); ++i)
args += expandVariableReferences(argumentsList[i]).join(Option::field_sep); args += expandVariableReferences(argumentsList[i]).join(Option::field_sep);
@@ -1618,13 +1696,40 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun
return ret; return ret;
} }
bool ProFileEvaluator::Private::evaluateConditionalFunction( ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction(
const QString &function, const QString &arguments) const QString &function, const QString &arguments)
{ {
QStringList argumentsList = split_arg_list(arguments); QStringList argumentsList = split_arg_list(arguments);
if (ProBlock *funcPtr = m_testFunctions.value(function, 0)) {
bool ok;
QStringList ret = evaluateFunction(funcPtr, argumentsList, &ok);
if (ok) {
if (ret.isEmpty()) {
return ProItem::ReturnTrue;
} else {
if (ret.first() != QLatin1String("false")) {
if (ret.first() == QLatin1String("true")) {
return ProItem::ReturnTrue;
} else {
bool ok;
int val = ret.first().toInt(&ok);
if (ok) {
if (val)
return ProItem::ReturnTrue;
} else {
q->logMessage(format("Unexpected return value from test '%1': %2")
.arg(function).arg(ret.join(QLatin1String(" :: "))));
}
}
}
}
}
return ProItem::ReturnFalse;
}
QString sep; QString sep;
sep.append(Option::field_sep); sep.append(Option::field_sep);
QStringList args; QStringList args;
for (int i = 0; i < argumentsList.count(); ++i) for (int i = 0; i < argumentsList.count(); ++i)
args += expandVariableReferences(argumentsList[i]).join(sep); args += expandVariableReferences(argumentsList[i]).join(sep);
@@ -1632,7 +1737,8 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE, T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF }; T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF,
T_DEFINE_TEST, T_DEFINE_REPLACE };
static QHash<QString, int> *functions = 0; static QHash<QString, int> *functions = 0;
if (!functions) { if (!functions) {
@@ -1665,35 +1771,87 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
functions->insert(QLatin1String("message"), T_MESSAGE); //v functions->insert(QLatin1String("message"), T_MESSAGE); //v
functions->insert(QLatin1String("warning"), T_MESSAGE); //v functions->insert(QLatin1String("warning"), T_MESSAGE); //v
functions->insert(QLatin1String("error"), T_MESSAGE); //v functions->insert(QLatin1String("error"), T_MESSAGE); //v
functions->insert(QLatin1String("defineTest"), T_DEFINE_TEST); //v
functions->insert(QLatin1String("defineReplace"), T_DEFINE_REPLACE); //v
} }
TestFunc func_t = (TestFunc)functions->value(function); TestFunc func_t = (TestFunc)functions->value(function);
switch (func_t) { switch (func_t) {
case T_DEFINE_TEST:
m_definingTest = true;
goto defineFunc;
case T_DEFINE_REPLACE:
m_definingTest = false;
defineFunc:
if (args.count() != 1) {
q->logMessage(format("%s(function) requires one argument.").arg(function));
return ProItem::ReturnFalse;
}
m_definingFunc = args.first();
return ProItem::ReturnTrue;
case T_DEFINED:
if (args.count() < 1 || args.count() > 2) {
q->logMessage(format("defined(function, [\"test\"|\"replace\"])"
" requires one or two arguments."));
return ProItem::ReturnFalse;
}
if (args.count() > 1) {
if (args[1] == QLatin1String("test"))
return returnBool(m_testFunctions.contains(args[0]));
else if (args[1] == QLatin1String("replace"))
return returnBool(m_replaceFunctions.contains(args[0]));
q->logMessage(format("defined(function, type):"
" unexpected type [%1].\n").arg(args[1]));
return ProItem::ReturnFalse;
}
return returnBool(m_replaceFunctions.contains(args[0])
|| m_testFunctions.contains(args[0]));
case T_RETURN:
m_returnValue = args;
// It is "safe" to ignore returns - due to qmake brokeness
// they cannot be used to terminate loops anyway.
if (m_skipLevel || m_cumulative)
return ProItem::ReturnTrue;
if (m_valuemapStack.isEmpty()) {
q->logMessage(format("unexpected return()."));
return ProItem::ReturnFalse;
}
return ProItem::ReturnReturn;
case T_EXPORT:
if (m_skipLevel && !m_cumulative)
return ProItem::ReturnTrue;
if (args.count() != 1) {
q->logMessage(format("export(variable) requires one argument."));
return ProItem::ReturnFalse;
}
for (int i = 0; i < m_valuemapStack.size(); ++i) {
m_valuemapStack[i][args[0]] = m_valuemap[args[0]];
m_filevaluemapStack[i][currentProFile()][args[0]] =
m_filevaluemap[currentProFile()][args[0]];
}
return ProItem::ReturnTrue;
#if 0 #if 0
case T_INFILE: case T_INFILE:
case T_REQUIRES: case T_REQUIRES:
case T_GREATERTHAN: case T_GREATERTHAN:
case T_LESSTHAN: case T_LESSTHAN:
case T_EQUALS: case T_EQUALS:
case T_EXPORT:
case T_CLEAR: case T_CLEAR:
case T_UNSET: case T_UNSET:
case T_EVAL: case T_EVAL:
case T_IF: case T_IF:
case T_RETURN:
case T_BREAK: case T_BREAK:
case T_NEXT: case T_NEXT:
case T_DEFINED:
#endif #endif
case T_CONFIG: { case T_CONFIG: {
if (args.count() < 1 || args.count() > 2) { if (args.count() < 1 || args.count() > 2) {
q->logMessage(format("CONFIG(config) requires one or two arguments.")); q->logMessage(format("CONFIG(config) requires one or two arguments."));
return false; return ProItem::ReturnFalse;
} }
if (args.count() == 1) { if (args.count() == 1) {
//cond = isActiveConfig(args.first()); XXX //cond = isActiveConfig(args.first()); XXX
return false; return ProItem::ReturnFalse;
} }
const QStringList mutuals = args[1].split(QLatin1Char('|')); const QStringList mutuals = args[1].split(QLatin1Char('|'));
const QStringList &configs = valuesDirect(QLatin1String("CONFIG")); const QStringList &configs = valuesDirect(QLatin1String("CONFIG"));
@@ -1701,16 +1859,16 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
for (int i = configs.size() - 1; i >= 0; i--) { for (int i = configs.size() - 1; i >= 0; i--) {
for (int mut = 0; mut < mutuals.count(); mut++) { for (int mut = 0; mut < mutuals.count(); mut++) {
if (configs[i] == mutuals[mut].trimmed()) { if (configs[i] == mutuals[mut].trimmed()) {
return (configs[i] == args[0]); return returnBool(configs[i] == args[0]);
} }
} }
} }
return false; return ProItem::ReturnFalse;
} }
case T_CONTAINS: { case T_CONTAINS: {
if (args.count() < 2 || args.count() > 3) { if (args.count() < 2 || args.count() > 3) {
q->logMessage(format("contains(var, val) requires two or three arguments.")); q->logMessage(format("contains(var, val) requires two or three arguments."));
return false; return ProItem::ReturnFalse;
} }
QRegExp regx(args[1]); QRegExp regx(args[1]);
@@ -1719,7 +1877,7 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
for (int i = 0; i < l.size(); ++i) { for (int i = 0; i < l.size(); ++i) {
const QString val = l[i]; const QString val = l[i];
if (regx.exactMatch(val) || val == args[1]) { if (regx.exactMatch(val) || val == args[1]) {
return true; return ProItem::ReturnTrue;
} }
} }
} else { } else {
@@ -1728,47 +1886,47 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
const QString val = l[i]; const QString val = l[i];
for (int mut = 0; mut < mutuals.count(); mut++) { for (int mut = 0; mut < mutuals.count(); mut++) {
if (val == mutuals[mut].trimmed()) { if (val == mutuals[mut].trimmed()) {
return (regx.exactMatch(val) || val == args[1]); return returnBool(regx.exactMatch(val) || val == args[1]);
} }
} }
} }
} }
return false; return ProItem::ReturnFalse;
} }
case T_COUNT: { case T_COUNT: {
if (args.count() != 2 && args.count() != 3) { if (args.count() != 2 && args.count() != 3) {
q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments.")); q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments."));
return false; return ProItem::ReturnFalse;
} }
if (args.count() == 3) { if (args.count() == 3) {
QString comp = args[2]; QString comp = args[2];
if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) { if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
return (values(args.first()).count() > args[1].toInt()); return returnBool(values(args.first()).count() > args[1].toInt());
} else if (comp == QLatin1String(">=")) { } else if (comp == QLatin1String(">=")) {
return (values(args.first()).count() >= args[1].toInt()); return returnBool(values(args.first()).count() >= args[1].toInt());
} else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) { } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
return (values(args.first()).count() < args[1].toInt()); return returnBool(values(args.first()).count() < args[1].toInt());
} else if (comp == QLatin1String("<=")) { } else if (comp == QLatin1String("<=")) {
return (values(args.first()).count() <= args[1].toInt()); return returnBool(values(args.first()).count() <= args[1].toInt());
} else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
|| comp == QLatin1String("=") || comp == QLatin1String("==")) { || comp == QLatin1String("=") || comp == QLatin1String("==")) {
return (values(args.first()).count() == args[1].toInt()); return returnBool(values(args.first()).count() == args[1].toInt());
} else { } else {
q->logMessage(format("unexpected modifier to count(%2)").arg(comp)); q->logMessage(format("unexpected modifier to count(%2)").arg(comp));
return false; return ProItem::ReturnFalse;
} }
} }
return (values(args.first()).count() == args[1].toInt()); return returnBool(values(args.first()).count() == args[1].toInt());
} }
case T_INCLUDE: { case T_INCLUDE: {
if (m_skipLevel && !m_cumulative) if (m_skipLevel && !m_cumulative)
return false; return ProItem::ReturnFalse;
QString parseInto; QString parseInto;
if (args.count() == 2) { if (args.count() == 2) {
parseInto = args[1]; parseInto = args[1];
} else if (args.count() != 1) { } else if (args.count() != 1) {
q->logMessage(format("include(file) requires one or two arguments.")); q->logMessage(format("include(file) requires one or two arguments."));
return false; return ProItem::ReturnFalse;
} }
QString fileName = args.first(); QString fileName = args.first();
// ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style. // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style.
@@ -1777,11 +1935,11 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
State sts = m_sts; State sts = m_sts;
bool ok = evaluateFile(fileName); bool ok = evaluateFile(fileName);
m_sts = sts; m_sts = sts;
return ok; return returnBool(ok);
} }
case T_LOAD: { case T_LOAD: {
if (m_skipLevel && !m_cumulative) if (m_skipLevel && !m_cumulative)
return false; return ProItem::ReturnFalse;
QString parseInto; QString parseInto;
bool ignore_error = false; bool ignore_error = false;
if (args.count() == 2) { if (args.count() == 2) {
@@ -1789,18 +1947,18 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt()); ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt());
} else if (args.count() != 1) { } else if (args.count() != 1) {
q->logMessage(format("load(feature) requires one or two arguments.")); q->logMessage(format("load(feature) requires one or two arguments."));
return false; return ProItem::ReturnFalse;
} }
// XXX ignore_error unused // XXX ignore_error unused
return evaluateFeatureFile(args.first()); return returnBool(evaluateFeatureFile(args.first()));
} }
case T_DEBUG: case T_DEBUG:
// Yup - do nothing. Nothing is going to enable debug output anyway. // Yup - do nothing. Nothing is going to enable debug output anyway.
return false; return ProItem::ReturnFalse;
case T_MESSAGE: { case T_MESSAGE: {
if (args.count() != 1) { if (args.count() != 1) {
q->logMessage(format("%1(message) requires one argument.").arg(function)); q->logMessage(format("%1(message) requires one argument.").arg(function));
return false; return ProItem::ReturnFalse;
} }
QString msg = fixEnvVariables(args.first()); QString msg = fixEnvVariables(args.first());
if (function == QLatin1String("error")) { if (function == QLatin1String("error")) {
@@ -1817,42 +1975,42 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
} else { } else {
q->fileMessage(format("Project MESSAGE: %1").arg(msg)); q->fileMessage(format("Project MESSAGE: %1").arg(msg));
} }
return false; return ProItem::ReturnFalse;
} }
#if 0 // Way too dangerous to enable. #if 0 // Way too dangerous to enable.
case T_SYSTEM: { case T_SYSTEM: {
if (args.count() != 1) { if (args.count() != 1) {
q->logMessage(format("system(exec) requires one argument.")); q->logMessage(format("system(exec) requires one argument."));
false; ProItem::ReturnFalse;
} }
return (system(args.first().toLatin1().constData()) == 0); return returnBool(system(args.first().toLatin1().constData()) == 0);
} }
#endif #endif
case T_ISEMPTY: { case T_ISEMPTY: {
if (args.count() != 1) { if (args.count() != 1) {
q->logMessage(format("isEmpty(var) requires one argument.")); q->logMessage(format("isEmpty(var) requires one argument."));
return false; return ProItem::ReturnFalse;
} }
QStringList sl = values(args.first()); QStringList sl = values(args.first());
if (sl.count() == 0) { if (sl.count() == 0) {
return true; return ProItem::ReturnTrue;
} else if (sl.count() > 0) { } else if (sl.count() > 0) {
QString var = sl.first(); QString var = sl.first();
if (var.isEmpty()) if (var.isEmpty())
return true; return ProItem::ReturnTrue;
} }
return false; return ProItem::ReturnFalse;
} }
case T_EXISTS: { case T_EXISTS: {
if (args.count() != 1) { if (args.count() != 1) {
q->logMessage(format("exists(file) requires one argument.")); q->logMessage(format("exists(file) requires one argument."));
return false; return ProItem::ReturnFalse;
} }
QString file = args.first(); QString file = args.first();
file = Option::fixPathToLocalOS(file); file = Option::fixPathToLocalOS(file);
if (QFile::exists(file)) { if (QFile::exists(file)) {
return true; return ProItem::ReturnTrue;
} }
//regular expression I guess //regular expression I guess
QString dirstr = currentDirectory(); QString dirstr = currentDirectory();
@@ -1863,17 +2021,16 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(
} }
if (file.contains(QLatin1Char('*')) || file.contains(QLatin1Char('?'))) if (file.contains(QLatin1Char('*')) || file.contains(QLatin1Char('?')))
if (!QDir(dirstr).entryList(QStringList(file)).isEmpty()) if (!QDir(dirstr).entryList(QStringList(file)).isEmpty())
return true; return ProItem::ReturnTrue;
return false; return ProItem::ReturnFalse;
} }
case 0: case 0:
// This is too chatty currently (missing defineTest and defineReplace) q->logMessage(format("'%1' is not a recognized test function").arg(function));
//q->logMessage(format("'%1' is not a recognized test function").arg(function)); return ProItem::ReturnFalse;
return false;
default: default:
q->logMessage(format("Function '%1' is not implemented").arg(function)); q->logMessage(format("Function '%1' is not implemented").arg(function));
return false; return ProItem::ReturnFalse;
} }
} }
@@ -2032,7 +2189,7 @@ bool ProFileEvaluator::Private::evaluateFile(const QString &fileName)
ProFile *pro = q->parsedProFile(fileName); ProFile *pro = q->parsedProFile(fileName);
if (pro) { if (pro) {
m_profileStack.push(pro); m_profileStack.push(pro);
bool ok = pro->Accept(this); bool ok = (pro->Accept(this) == ProItem::ReturnTrue);
m_profileStack.pop(); m_profileStack.pop();
q->releaseParsedProFile(pro); q->releaseParsedProFile(pro);
return ok; return ok;

View File

@@ -46,15 +46,21 @@ QString ProItem::comment() const
} }
// --------------- ProBlock ---------------- // --------------- ProBlock ----------------
ProBlock::ProBlock(ProBlock *parent) ProBlock::ProBlock(ProBlock *parent)
{ {
m_blockKind = 0; m_blockKind = 0;
m_parent = parent; m_parent = parent;
m_refCount = 1;
} }
ProBlock::~ProBlock() ProBlock::~ProBlock()
{ {
qDeleteAll(m_proitems); foreach (ProItem *itm, m_proitems)
if (itm->kind() == BlockKind)
static_cast<ProBlock *>(itm)->deref();
else
delete itm;
} }
void ProBlock::appendItem(ProItem *proitem) void ProBlock::appendItem(ProItem *proitem)
@@ -97,15 +103,16 @@ ProItem::ProItemKind ProBlock::kind() const
return ProItem::BlockKind; return ProItem::BlockKind;
} }
bool ProBlock::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProBlock::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitBeginProBlock(this); if (visitor->visitBeginProBlock(this) == ReturnSkip)
foreach (ProItem *item, m_proitems) { return ReturnTrue;
if (!item->Accept(visitor)) ProItemReturn rt = ReturnTrue;
return false; foreach (ProItem *item, m_proitems)
} if ((rt = item->Accept(visitor)) != ReturnTrue && rt != ReturnFalse)
break;
visitor->visitEndProBlock(this); visitor->visitEndProBlock(this);
return true; return rt;
} }
// --------------- ProVariable ---------------- // --------------- ProVariable ----------------
@@ -137,15 +144,13 @@ QString ProVariable::variable() const
return m_variable; return m_variable;
} }
bool ProVariable::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProVariable::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitBeginProVariable(this); visitor->visitBeginProVariable(this);
foreach (ProItem *item, m_proitems) { foreach (ProItem *item, m_proitems)
if (!item->Accept(visitor)) item->Accept(visitor); // cannot fail
return false;
}
visitor->visitEndProVariable(this); visitor->visitEndProVariable(this);
return true; return ReturnTrue;
} }
// --------------- ProValue ---------------- // --------------- ProValue ----------------
@@ -180,10 +185,10 @@ ProItem::ProItemKind ProValue::kind() const
return ProItem::ValueKind; return ProItem::ValueKind;
} }
bool ProValue::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProValue::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitProValue(this); visitor->visitProValue(this);
return true; return ReturnTrue;
} }
// --------------- ProFunction ---------------- // --------------- ProFunction ----------------
@@ -207,10 +212,9 @@ ProItem::ProItemKind ProFunction::kind() const
return ProItem::FunctionKind; return ProItem::FunctionKind;
} }
bool ProFunction::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProFunction::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitProFunction(this); return visitor->visitProFunction(this);
return true;
} }
// --------------- ProCondition ---------------- // --------------- ProCondition ----------------
@@ -234,10 +238,10 @@ ProItem::ProItemKind ProCondition::kind() const
return ProItem::ConditionKind; return ProItem::ConditionKind;
} }
bool ProCondition::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProCondition::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitProCondition(this); visitor->visitProCondition(this);
return true; return ReturnTrue;
} }
// --------------- ProOperator ---------------- // --------------- ProOperator ----------------
@@ -261,10 +265,10 @@ ProItem::ProItemKind ProOperator::kind() const
return ProItem::OperatorKind; return ProItem::OperatorKind;
} }
bool ProOperator::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProOperator::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitProOperator(this); visitor->visitProOperator(this);
return true; return ReturnTrue;
} }
// --------------- ProFile ---------------- // --------------- ProFile ----------------
@@ -309,13 +313,12 @@ bool ProFile::isModified() const
return m_modified; return m_modified;
} }
bool ProFile::Accept(AbstractProItemVisitor *visitor) ProItem::ProItemReturn ProFile::Accept(AbstractProItemVisitor *visitor)
{ {
visitor->visitBeginProFile(this); ProItemReturn rt;
foreach (ProItem *item, m_proitems) { if ((rt = visitor->visitBeginProFile(this)) != ReturnTrue)
if (!item->Accept(visitor)) return rt;
return false; ProBlock::Accept(visitor); // cannot fail
}
return visitor->visitEndProFile(this); return visitor->visitEndProFile(this);
} }

View File

@@ -49,6 +49,13 @@ public:
BlockKind BlockKind
}; };
enum ProItemReturn {
ReturnFalse,
ReturnTrue,
ReturnSkip,
ReturnReturn
};
ProItem() : m_lineNumber(0) {} ProItem() : m_lineNumber(0) {}
virtual ~ProItem() {} virtual ~ProItem() {}
@@ -57,7 +64,7 @@ public:
void setComment(const QString &comment); void setComment(const QString &comment);
QString comment() const; QString comment() const;
virtual bool Accept(AbstractProItemVisitor *visitor) = 0; virtual ProItemReturn Accept(AbstractProItemVisitor *visitor) = 0;
int lineNumber() const { return m_lineNumber; } int lineNumber() const { return m_lineNumber; }
void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; } void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; }
@@ -75,7 +82,8 @@ public:
ScopeContentsKind = 0x02, ScopeContentsKind = 0x02,
VariableKind = 0x04, VariableKind = 0x04,
ProFileKind = 0x08, ProFileKind = 0x08,
SingleLine = 0x10 FunctionBodyKind = 0x10,
SingleLine = 0x80
}; };
ProBlock(ProBlock *parent); ProBlock(ProBlock *parent);
@@ -91,14 +99,18 @@ public:
void setParent(ProBlock *parent); void setParent(ProBlock *parent);
ProBlock *parent() const; ProBlock *parent() const;
void ref() { ++m_refCount; }
void deref() { if (!--m_refCount) delete this; }
ProItem::ProItemKind kind() const; ProItem::ProItemKind kind() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
protected: protected:
QList<ProItem *> m_proitems; QList<ProItem *> m_proitems;
private: private:
ProBlock *m_parent; ProBlock *m_parent;
int m_blockKind; int m_blockKind;
int m_refCount;
}; };
class ProVariable : public ProBlock class ProVariable : public ProBlock
@@ -120,7 +132,7 @@ public:
void setVariable(const QString &name); void setVariable(const QString &name);
QString variable() const; QString variable() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
private: private:
VariableOperator m_variableKind; VariableOperator m_variableKind;
QString m_variable; QString m_variable;
@@ -139,7 +151,7 @@ public:
ProItem::ProItemKind kind() const; ProItem::ProItemKind kind() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
private: private:
QString m_value; QString m_value;
ProVariable *m_variable; ProVariable *m_variable;
@@ -155,7 +167,7 @@ public:
ProItem::ProItemKind kind() const; ProItem::ProItemKind kind() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
private: private:
QString m_text; QString m_text;
}; };
@@ -170,7 +182,7 @@ public:
ProItem::ProItemKind kind() const; ProItem::ProItemKind kind() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
private: private:
QString m_text; QString m_text;
}; };
@@ -190,7 +202,7 @@ public:
ProItem::ProItemKind kind() const; ProItem::ProItemKind kind() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
private: private:
OperatorKind m_operatorKind; OperatorKind m_operatorKind;
}; };
@@ -210,7 +222,7 @@ public:
void setModified(bool modified); void setModified(bool modified);
bool isModified() const; bool isModified() const;
virtual bool Accept(AbstractProItemVisitor *visitor); virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
private: private:
QString m_fileName; QString m_fileName;