summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>2012-07-27 21:26:10 +0200
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>2012-08-01 16:44:55 +0200
commite739841c6314bfd5021320083823ee030d938773 (patch)
tree9083baafc72068ca293a7528e4e04611ded3adfb /src/shared
parent75cc8575b411cb268abccd743ecf55baf1c66a42 (diff)
downloadqt-creator-e739841c6314bfd5021320083823ee030d938773.tar.gz
implement if() by means of precompilation
the performance is about the same (depending on the expression type it's better or worse), but a lot of code just disappears. Change-Id: I60eb9b87f23cc811d3f9577841c38966ecfd8e43 Reviewed-by: Daniel Teske <daniel.teske@nokia.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/proparser/qmakebuiltins.cpp81
-rw-r--r--src/shared/proparser/qmakeevaluator.cpp339
-rw-r--r--src/shared/proparser/qmakeevaluator.h7
-rw-r--r--src/shared/proparser/qmakeparser.cpp17
-rw-r--r--src/shared/proparser/qmakeparser.h6
5 files changed, 48 insertions, 402 deletions
diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp
index 8488f5f2da..7c8f4e716e 100644
--- a/src/shared/proparser/qmakebuiltins.cpp
+++ b/src/shared/proparser/qmakebuiltins.cpp
@@ -293,8 +293,13 @@ void QMakeEvaluator::populateDeps(
}
ProStringList QMakeEvaluator::evaluateExpandFunction(
- const ProString &func, const ProStringList &args)
+ const ProString &func, const ushort *&tokPtr)
{
+ QHash<ProString, ProFunctionDef>::ConstIterator it =
+ m_functionDefs.replaceFunctions.constFind(func);
+ if (it != m_functionDefs.replaceFunctions.constEnd())
+ return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0);
+
ExpandFunc func_t = ExpandFunc(statics.expands.value(func));
if (func_t == 0) {
const QString &fn = func.toQString(m_tmp1);
@@ -306,6 +311,8 @@ ProStringList QMakeEvaluator::evaluateExpandFunction(
}
}
+ //why don't the builtin functions just use args_list? --Sam
+ const ProStringList &args = expandVariableReferences(tokPtr, 5, true);
ProStringList ret;
switch (func_t) {
@@ -924,10 +931,18 @@ ProStringList QMakeEvaluator::evaluateExpandFunction(
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
- const ProString &function, const ProStringList &args)
+ const ProString &function, const ushort *&tokPtr)
{
+ QHash<ProString, ProFunctionDef>::ConstIterator it =
+ m_functionDefs.testFunctions.constFind(function);
+ if (it != m_functionDefs.testFunctions.constEnd())
+ return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function);
+
TestFunc func_t = (TestFunc)statics.functions.value(function);
+ //why don't the builtin functions just use args_list? --Sam
+ const ProStringList &args = expandVariableReferences(tokPtr, 5, true);
+
switch (func_t) {
case T_DEFINED:
if (args.count() < 1 || args.count() > 2) {
@@ -1047,67 +1062,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
evalError(fL1S("if(condition) requires one argument."));
return ReturnFalse;
}
- const ProString &cond = args.at(0);
- bool quoted = false;
- bool ret = true;
- bool orOp = false;
- bool invert = false;
- bool isFunc = false;
- int parens = 0;
- QString test;
- test.reserve(20);
- QString argsString;
- argsString.reserve(50);
- const QChar *d = cond.constData();
- const QChar *ed = d + cond.size();
- while (d < ed) {
- ushort c = (d++)->unicode();
- bool isOp = false;
- if (quoted) {
- if (c == '"')
- quoted = false;
- else if (c == '!' && test.isEmpty())
- invert = true;
- else
- test += c;
- } else if (c == '(') {
- isFunc = true;
- if (parens)
- argsString += c;
- ++parens;
- } else if (c == ')') {
- --parens;
- if (parens)
- argsString += c;
- } else if (!parens) {
- if (c == '"')
- quoted = true;
- else if (c == ':' || c == '|')
- isOp = true;
- else if (c == '!' && test.isEmpty())
- invert = true;
- else
- test += c;
- } else {
- argsString += c;
- }
- if (!quoted && !parens && (isOp || d == ed)) {
- if (m_cumulative || (orOp != ret)) {
- test = test.trimmed();
- if (isFunc)
- ret = evaluateConditionalFunction(ProString(test), ProString(argsString, NoHash));
- else
- ret = isActiveConfig(test, true);
- ret ^= invert;
- }
- orOp = (c == '|');
- invert = false;
- isFunc = false;
- test.clear();
- argsString.clear();
- }
- }
- return returnBool(ret);
+ return returnBool(evaluateConditional(args.at(0).toQString(), fL1S("(if)")));
}
case T_CONFIG: {
if (args.count() < 1 || args.count() > 2) {
diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp
index d9d9cc1115..fb0587b434 100644
--- a/src/shared/proparser/qmakeevaluator.cpp
+++ b/src/shared/proparser/qmakeevaluator.cpp
@@ -1368,278 +1368,6 @@ QString QMakeEvaluator::currentDirectory() const
return QString();
}
-// The (QChar*)current->constData() constructs below avoid pointless detach() calls
-// FIXME: This is inefficient. Should not make new string if it is a straight subsegment
-static ALWAYS_INLINE void appendChar(ushort unicode,
- QString *current, QChar **ptr, ProString *pending)
-{
- if (!pending->isEmpty()) {
- int len = pending->size();
- current->resize(current->size() + len);
- ::memcpy((QChar*)current->constData(), pending->constData(), len * 2);
- pending->clear();
- *ptr = (QChar*)current->constData() + len;
- }
- *(*ptr)++ = QChar(unicode);
-}
-
-static void appendString(const ProString &string,
- QString *current, QChar **ptr, ProString *pending)
-{
- if (string.isEmpty())
- return;
- QChar *uc = (QChar*)current->constData();
- int len;
- if (*ptr != uc) {
- len = *ptr - uc;
- current->resize(current->size() + string.size());
- } else if (!pending->isEmpty()) {
- len = pending->size();
- current->resize(current->size() + len + string.size());
- ::memcpy((QChar*)current->constData(), pending->constData(), len * 2);
- pending->clear();
- } else {
- *pending = string;
- return;
- }
- *ptr = (QChar*)current->constData() + len;
- ::memcpy(*ptr, string.constData(), string.size() * 2);
- *ptr += string.size();
-}
-
-static void flushCurrent(ProStringList *ret,
- QString *current, QChar **ptr, ProString *pending, bool joined)
-{
- QChar *uc = (QChar*)current->constData();
- int len = *ptr - uc;
- if (len) {
- ret->append(ProString(QString(uc, len), NoHash));
- *ptr = uc;
- } else if (!pending->isEmpty()) {
- ret->append(*pending);
- pending->clear();
- } else if (joined) {
- ret->append(ProString());
- }
-}
-
-static inline void flushFinal(ProStringList *ret,
- const QString &current, const QChar *ptr, const ProString &pending,
- const ProString &str, bool replaced, bool joined)
-{
- int len = ptr - current.data();
- if (len) {
- if (!replaced && len == str.size())
- ret->append(str);
- else
- ret->append(ProString(QString(current.data(), len), NoHash));
- } else if (!pending.isEmpty()) {
- ret->append(pending);
- } else if (joined) {
- ret->append(ProString());
- }
-}
-
-ProStringList QMakeEvaluator::expandVariableReferences(
- const ProString &str, int *pos, bool joined)
-{
- ProStringList ret;
-// if (ok)
-// *ok = true;
- if (str.isEmpty() && !pos)
- return ret;
-
- const ushort LSQUARE = '[';
- const ushort RSQUARE = ']';
- const ushort LCURLY = '{';
- const ushort RCURLY = '}';
- const ushort LPAREN = '(';
- const ushort RPAREN = ')';
- const ushort DOLLAR = '$';
- const ushort BACKSLASH = '\\';
- const ushort UNDERSCORE = '_';
- const ushort DOT = '.';
- const ushort SPACE = ' ';
- const ushort TAB = '\t';
- const ushort COMMA = ',';
- const ushort SINGLEQUOTE = '\'';
- const ushort DOUBLEQUOTE = '"';
-
- ushort unicode, quote = 0, parens = 0;
- const ushort *str_data = (const ushort *)str.constData();
- const int str_len = str.size();
-
- ProString var, args;
-
- bool replaced = false;
- bool putSpace = false;
- QString current; // Buffer for successively assembled string segments
- current.resize(str.size());
- QChar *ptr = current.data();
- ProString pending; // Buffer for string segments from variables
- // Only one of the above buffers can be filled at a given time.
- for (int i = pos ? *pos : 0; i < str_len; ++i) {
- unicode = str_data[i];
- if (unicode == DOLLAR) {
- if (str_len > i+2 && str_data[i+1] == DOLLAR) {
- ++i;
- ushort term = 0;
- enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR;
- unicode = str_data[++i];
- if (unicode == LSQUARE) {
- unicode = str_data[++i];
- term = RSQUARE;
- var_type = PROPERTY;
- } else if (unicode == LCURLY) {
- unicode = str_data[++i];
- var_type = VAR;
- term = RCURLY;
- } else if (unicode == LPAREN) {
- unicode = str_data[++i];
- var_type = ENVIRON;
- term = RPAREN;
- }
- int name_start = i;
- forever {
- if (!(unicode & (0xFF<<8)) &&
- unicode != DOT && unicode != UNDERSCORE &&
- //unicode != SINGLEQUOTE && unicode != DOUBLEQUOTE &&
- (unicode < 'a' || unicode > 'z') && (unicode < 'A' || unicode > 'Z') &&
- (unicode < '0' || unicode > '9'))
- break;
- if (++i == str_len)
- break;
- unicode = str_data[i];
- // at this point, i points to either the 'term' or 'next' character (which is in unicode)
- }
- var = str.mid(name_start, i - name_start);
- if (var_type == VAR && unicode == LPAREN) {
- var_type = FUNCTION;
- name_start = i + 1;
- int depth = 0;
- forever {
- if (++i == str_len)
- break;
- unicode = str_data[i];
- if (unicode == LPAREN) {
- depth++;
- } else if (unicode == RPAREN) {
- if (!depth)
- break;
- --depth;
- }
- }
- args = str.mid(name_start, i - name_start);
- if (++i < str_len)
- unicode = str_data[i];
- else
- unicode = 0;
- // at this point i is pointing to the 'next' character (which is in unicode)
- // this might actually be a term character since you can do $${func()}
- }
- if (term) {
- if (unicode != term) {
- evalError(fL1S("Missing %1 terminator [found %2]")
- .arg(QChar(term))
- .arg(unicode ? QString(unicode) : fL1S("end-of-line")));
-// if (ok)
-// *ok = false;
- if (pos)
- *pos = str_len;
- return ProStringList();
- }
- } else {
- // move the 'cursor' back to the last char of the thing we were looking at
- --i;
- }
-
- ProStringList replacement;
- if (var_type == ENVIRON) {
- replacement = split_value_list(m_option->getEnv(var.toQString(m_tmp1)));
- } else if (var_type == PROPERTY) {
- replacement << propertyValue(var);
- } else if (var_type == FUNCTION) {
- replacement += evaluateExpandFunction(var, args);
- } else if (var_type == VAR) {
- replacement = values(map(var));
- }
- if (!replacement.isEmpty()) {
- if (quote || joined) {
- if (putSpace) {
- putSpace = false;
- if (!replacement.at(0).isEmpty()) // Bizarre, indeed
- appendChar(' ', &current, &ptr, &pending);
- }
- appendString(ProString(replacement.join(statics.field_sep), NoHash),
- &current, &ptr, &pending);
- } else {
- appendString(replacement.at(0), &current, &ptr, &pending);
- if (replacement.size() > 1) {
- flushCurrent(&ret, &current, &ptr, &pending, false);
- int j = 1;
- if (replacement.size() > 2) {
- // FIXME: ret.reserve(ret.size() + replacement.size() - 2);
- for (; j < replacement.size() - 1; ++j)
- ret << replacement.at(j);
- }
- pending = replacement.at(j);
- }
- }
- replaced = true;
- }
- continue;
- }
- } else if (unicode == BACKSLASH) {
- static const char symbols[] = "[]{}()$\\'\"";
- ushort unicode2 = str_data[i+1];
- if (!(unicode2 & 0xff00) && strchr(symbols, unicode2)) {
- unicode = unicode2;
- ++i;
- }
- } else if (quote) {
- if (unicode == quote) {
- quote = 0;
- continue;
- }
- } else {
- if (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE) {
- quote = unicode;
- continue;
- } else if (unicode == SPACE || unicode == TAB) {
- if (!joined)
- flushCurrent(&ret, &current, &ptr, &pending, false);
- else if ((ptr - (QChar*)current.constData()) || !pending.isEmpty())
- putSpace = true;
- continue;
- } else if (pos) {
- if (unicode == LPAREN) {
- ++parens;
- } else if (unicode == RPAREN) {
- --parens;
- } else if (!parens && unicode == COMMA) {
- if (!joined) {
- *pos = i + 1;
- flushFinal(&ret, current, ptr, pending, str, replaced, false);
- return ret;
- }
- flushCurrent(&ret, &current, &ptr, &pending, true);
- putSpace = false;
- continue;
- }
- }
- }
- if (putSpace) {
- putSpace = false;
- appendChar(' ', &current, &ptr, &pending);
- }
- appendChar(unicode, &current, &ptr, &pending);
- }
- if (pos)
- *pos = str_len;
- flushFinal(&ret, current, ptr, pending, str, replaced, joined);
- return ret;
-}
-
bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
{
// magic types for easy flipping
@@ -1722,14 +1450,6 @@ QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr)
return args_list;
}
-QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ProString &arguments)
-{
- QList<ProStringList> args_list;
- for (int pos = 0; pos < arguments.size(); )
- args_list << expandVariableReferences(arguments, &pos);
- return args_list;
-}
-
ProStringList QMakeEvaluator::evaluateFunction(
const ProFunctionDef &func, const QList<ProStringList> &argumentsList, bool *ok)
{
@@ -1792,54 +1512,19 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
return ReturnFalse;
}
-ProStringList QMakeEvaluator::evaluateExpandFunction(
- const ProString &func, const ushort *&tokPtr)
+bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &context)
{
- QHash<ProString, ProFunctionDef>::ConstIterator it =
- m_functionDefs.replaceFunctions.constFind(func);
- if (it != m_functionDefs.replaceFunctions.constEnd())
- return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0);
-
- //why don't the builtin functions just use args_list? --Sam
- return evaluateExpandFunction(func, expandVariableReferences(tokPtr, 5, true));
-}
-
-ProStringList QMakeEvaluator::evaluateExpandFunction(
- const ProString &func, const ProString &arguments)
-{
- QHash<ProString, ProFunctionDef>::ConstIterator it =
- m_functionDefs.replaceFunctions.constFind(func);
- if (it != m_functionDefs.replaceFunctions.constEnd())
- return evaluateFunction(*it, prepareFunctionArgs(arguments), 0);
-
- //why don't the builtin functions just use args_list? --Sam
- int pos = 0;
- return evaluateExpandFunction(func, expandVariableReferences(arguments, &pos, true));
-}
-
-QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
- const ProString &function, const ProString &arguments)
-{
- QHash<ProString, ProFunctionDef>::ConstIterator it =
- m_functionDefs.testFunctions.constFind(function);
- if (it != m_functionDefs.testFunctions.constEnd())
- return evaluateBoolFunction(*it, prepareFunctionArgs(arguments), function);
-
- //why don't the builtin functions just use args_list? --Sam
- int pos = 0;
- return evaluateConditionalFunction(function, expandVariableReferences(arguments, &pos, true));
-}
-
-QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
- const ProString &function, const ushort *&tokPtr)
-{
- QHash<ProString, ProFunctionDef>::ConstIterator it =
- m_functionDefs.testFunctions.constFind(function);
- if (it != m_functionDefs.testFunctions.constEnd())
- return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function);
-
- //why don't the builtin functions just use args_list? --Sam
- return evaluateConditionalFunction(function, expandVariableReferences(tokPtr, 5, true));
+ bool ret = false;
+ ProFile *pro = m_parser->parsedProBlock(context, cond, QMakeParser::TestGrammar);
+ if (pro) {
+ if (pro->isOk()) {
+ m_locationStack.push(m_current);
+ ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue;
+ m_current = m_locationStack.pop();
+ }
+ pro->deref();
+ }
+ return ret;
}
ProValueMap *QMakeEvaluator::findValues(const ProString &variableName, ProValueMap::Iterator *rit)
diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h
index 1122bf6f7a..eb8daf46e8 100644
--- a/src/shared/proparser/qmakeevaluator.h
+++ b/src/shared/proparser/qmakeevaluator.h
@@ -156,19 +156,16 @@ public:
{ message(QMakeHandler::EvalWarnDeprecated, msg); }
QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
- QList<ProStringList> prepareFunctionArgs(const ProString &arguments);
ProStringList evaluateFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList, bool *ok);
VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList,
const ProString &function);
- ProStringList evaluateExpandFunction(const ProString &function, const ProString &arguments);
ProStringList evaluateExpandFunction(const ProString &function, const ushort *&tokPtr);
- ProStringList evaluateExpandFunction(const ProString &function, const ProStringList &args);
- VisitReturn evaluateConditionalFunction(const ProString &function, const ProString &arguments);
VisitReturn evaluateConditionalFunction(const ProString &function, const ushort *&tokPtr);
- VisitReturn evaluateConditionalFunction(const ProString &function, const ProStringList &args);
+
+ bool evaluateConditional(const QString &cond, const QString &context);
QStringList qmakeMkspecPaths() const;
QStringList qmakeFeaturePaths() const;
diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp
index b126983d3a..adb1f7892e 100644
--- a/src/shared/proparser/qmakeparser.cpp
+++ b/src/shared/proparser/qmakeparser.cpp
@@ -194,10 +194,10 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, bool cache)
return pro;
}
-ProFile *QMakeParser::parsedProBlock(const QString &name, const QString &contents)
+ProFile *QMakeParser::parsedProBlock(const QString &name, const QString &contents, SubGrammar grammar)
{
ProFile *pro = new ProFile(name);
- if (!read(pro, contents)) {
+ if (!read(pro, contents, grammar)) {
delete pro;
pro = 0;
}
@@ -216,7 +216,7 @@ bool QMakeParser::read(ProFile *pro)
QString content(QString::fromLocal8Bit(file.readAll()));
file.close();
- return read(pro, content);
+ return read(pro, content, FullGrammar);
}
void QMakeParser::putTok(ushort *&tokPtr, ushort tok)
@@ -256,7 +256,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len)
buf[-2] = (ushort)(hash >> 16);
}
-bool QMakeParser::read(ProFile *pro, const QString &in)
+bool QMakeParser::read(ProFile *pro, const QString &in, SubGrammar grammar)
{
m_proFile = pro;
m_lineNo = 1;
@@ -670,6 +670,10 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
finalizeCond(tokPtr, buf, ptr, wordCount);
flushCond(tokPtr);
++m_blockstack.top().braceLevel;
+ if (grammar == TestGrammar) {
+ parseError(fL1S("Opening scope not permitted in this context."));
+ pro->setOk(false);
+ }
goto nextItem;
} else if (c == '}') {
FLUSH_LHS_LITERAL();
@@ -708,7 +712,10 @@ bool QMakeParser::read(ProFile *pro, const QString &in)
FLUSH_LHS_LITERAL();
flushCond(tokPtr);
putLineMarker(tokPtr);
- if (wordCount != 1) {
+ if (grammar == TestGrammar) {
+ parseError(fL1S("Assignment not permitted in this context."));
+ pro->setOk(false);
+ } else if (wordCount != 1) {
parseError(fL1S("Assignment needs exactly one word on the left hand side."));
pro->setOk(false);
// Put empty variable name.
diff --git a/src/shared/proparser/qmakeparser.h b/src/shared/proparser/qmakeparser.h
index 9c1a386654..824c78106b 100644
--- a/src/shared/proparser/qmakeparser.h
+++ b/src/shared/proparser/qmakeparser.h
@@ -76,9 +76,11 @@ public:
QMakeParser(ProFileCache *cache, QMakeParserHandler *handler);
+ enum SubGrammar { FullGrammar, TestGrammar };
// fileName is expected to be absolute and cleanPath()ed.
ProFile *parsedProFile(const QString &fileName, bool cache = false);
- ProFile *parsedProBlock(const QString &name, const QString &contents);
+ ProFile *parsedProBlock(const QString &name, const QString &contents,
+ SubGrammar grammar = FullGrammar);
private:
struct BlockScope {
@@ -107,7 +109,7 @@ private:
};
bool read(ProFile *pro);
- bool read(ProFile *pro, const QString &content);
+ bool read(ProFile *pro, const QString &content, SubGrammar grammar);
ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);