diff options
author | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2012-07-27 21:26:10 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2012-08-01 16:44:55 +0200 |
commit | e739841c6314bfd5021320083823ee030d938773 (patch) | |
tree | 9083baafc72068ca293a7528e4e04611ded3adfb /src/shared | |
parent | 75cc8575b411cb268abccd743ecf55baf1c66a42 (diff) | |
download | qt-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.cpp | 81 | ||||
-rw-r--r-- | src/shared/proparser/qmakeevaluator.cpp | 339 | ||||
-rw-r--r-- | src/shared/proparser/qmakeevaluator.h | 7 | ||||
-rw-r--r-- | src/shared/proparser/qmakeparser.cpp | 17 | ||||
-rw-r--r-- | src/shared/proparser/qmakeparser.h | 6 |
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 ¤t, 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(' ', ¤t, &ptr, &pending); - } - appendString(ProString(replacement.join(statics.field_sep), NoHash), - ¤t, &ptr, &pending); - } else { - appendString(replacement.at(0), ¤t, &ptr, &pending); - if (replacement.size() > 1) { - flushCurrent(&ret, ¤t, &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, ¤t, &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, ¤t, &ptr, &pending, true); - putSpace = false; - continue; - } - } - } - if (putSpace) { - putSpace = false; - appendChar(' ', ¤t, &ptr, &pending); - } - appendChar(unicode, ¤t, &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); |