make QMakeParser take a QStringRef as input

the only place where this actually saves a deep copy is the evaluation
of if(), but as a side effect the parser is now able to deal with not
null-terminated strings, which is kinda nice as well.

Change-Id: Ib6d08617aa79d2f9eaecd4906d4d548f34bf377d
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
This commit is contained in:
Oswald Buddenhagen 2016-05-13 15:32:50 +02:00
parent 11d957d043
commit ad17a35853
9 changed files with 35 additions and 31 deletions

View File

@ -1210,7 +1210,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse; // Another qmake breakage return ReturnFalse; // Another qmake breakage
case T_EVAL: { case T_EVAL: {
VisitReturn ret = ReturnFalse; VisitReturn ret = ReturnFalse;
ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), QString contents = args.join(statics.field_sep);
ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents),
m_current.pro->fileName(), m_current.line); m_current.pro->fileName(), m_current.line);
if (m_cumulative || pro->isOk()) { if (m_cumulative || pro->isOk()) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
@ -1226,7 +1227,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("if(condition) requires one argument.")); evalError(fL1S("if(condition) requires one argument."));
return ReturnFalse; return ReturnFalse;
} }
return returnBool(evaluateConditional(args.at(0).toQString(), return returnBool(evaluateConditional(args.at(0).toQStringRef(),
m_current.pro->fileName(), m_current.line)); m_current.pro->fileName(), m_current.line));
} }
case T_CONFIG: { case T_CONFIG: {

View File

@ -1277,7 +1277,7 @@ void QMakeEvaluator::setupProject()
void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where)
{ {
if (!cmds.isEmpty()) { if (!cmds.isEmpty()) {
ProFile *pro = m_parser->parsedProBlock(cmds, where, -1); ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1);
if (pro->isOk()) { if (pro->isOk()) {
m_locationStack.push(m_current); m_locationStack.push(m_current);
visitProBlock(pro, pro->tokPtr()); visitProBlock(pro, pro->tokPtr());
@ -1760,7 +1760,7 @@ ProStringList QMakeEvaluator::evaluateExpandFunction(
return ProStringList(); return ProStringList();
} }
bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line) bool QMakeEvaluator::evaluateConditional(const QStringRef &cond, const QString &where, int line)
{ {
bool ret = false; bool ret = false;
ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar);
@ -1778,7 +1778,7 @@ void QMakeEvaluator::checkRequirements(const ProStringList &deps)
{ {
ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS")); ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS"));
for (const ProString &dep : deps) for (const ProString &dep : deps)
if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line)) if (!evaluateConditional(dep.toQStringRef(), m_current.pro->fileName(), m_current.line))
failed << dep; failed << dep;
} }
#endif #endif

View File

@ -216,7 +216,7 @@ public:
ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args); ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args);
VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args); VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args);
bool evaluateConditional(const QString &cond, const QString &where, int line = -1); bool evaluateConditional(const QStringRef &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL #ifdef PROEVALUATOR_FULL
void checkRequirements(const ProStringList &deps); void checkRequirements(const ProStringList &deps);
#endif #endif

View File

@ -224,7 +224,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
} }
ProFile *QMakeParser::parsedProBlock( ProFile *QMakeParser::parsedProBlock(
const QString &contents, const QString &name, int line, SubGrammar grammar) const QStringRef &contents, const QString &name, int line, SubGrammar grammar)
{ {
ProFile *pro = new ProFile(name); ProFile *pro = new ProFile(name);
read(pro, contents, line, grammar); read(pro, contents, line, grammar);
@ -247,7 +247,7 @@ bool QMakeParser::read(ProFile *pro, ParseFlags flags)
fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr));
return false; return false;
} }
read(pro, content, 1, FullGrammar); read(pro, QStringRef(&content), 1, FullGrammar);
return true; return true;
} }
@ -289,7 +289,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len)
buf[-2] = (ushort)(hash >> 16); buf[-2] = (ushort)(hash >> 16);
} }
void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar) void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar grammar)
{ {
m_proFile = pro; m_proFile = pro;
m_lineNo = line; m_lineNo = line;
@ -334,8 +334,8 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
QStack<ParseCtx> xprStack; QStack<ParseCtx> xprStack;
xprStack.reserve(10); xprStack.reserve(10);
// We rely on QStrings being null-terminated, so don't maintain a global end pointer.
const ushort *cur = (const ushort *)in.unicode(); const ushort *cur = (const ushort *)in.unicode();
const ushort *inend = cur + in.length();
m_canElse = false; m_canElse = false;
freshLine: freshLine:
m_state = StNew; m_state = StNew;
@ -418,7 +418,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
int indent; int indent;
if (context == CtxPureValue) { if (context == CtxPureValue) {
end = (const ushort *)in.unicode() + in.length(); end = inend;
cptr = 0; cptr = 0;
lineCont = false; lineCont = false;
indent = 0; // just gcc being stupid indent = 0; // just gcc being stupid
@ -430,24 +430,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
// First, skip leading whitespace // First, skip leading whitespace
for (indent = 0; ; ++cur, ++indent) { for (indent = 0; ; ++cur, ++indent) {
if (cur == inend) {
cur = 0;
goto flushLine;
}
c = *cur; c = *cur;
if (c == '\n') { if (c == '\n') {
++cur; ++cur;
goto flushLine; goto flushLine;
} else if (!c) {
cur = 0;
goto flushLine;
} else if (c != ' ' && c != '\t' && c != '\r') {
break;
} }
if (c != ' ' && c != '\t' && c != '\r')
break;
} }
// Then strip comments. Yep - no escaping is possible. // Then strip comments. Yep - no escaping is possible.
for (cptr = cur;; ++cptr) { for (cptr = cur;; ++cptr) {
if (cptr == inend) {
end = cptr;
break;
}
c = *cptr; c = *cptr;
if (c == '#') { if (c == '#') {
for (end = cptr; (c = *++cptr);) { end = cptr;
if (c == '\n') { while (++cptr < inend) {
if (*cptr == '\n') {
++cptr; ++cptr;
break; break;
} }
@ -460,10 +466,6 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
} }
break; break;
} }
if (!c) {
end = cptr;
break;
}
if (c == '\n') { if (c == '\n') {
end = cptr++; end = cptr++;
break; break;
@ -1215,7 +1217,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg
bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
ushort **buf, QString *xprBuff, ushort **buf, QString *xprBuff,
ushort **tokPtr, QString *tokBuff, ushort **tokPtr, QString *tokBuff,
const ushort *cur, const QString &in) const ushort *cur, const QStringRef &in)
{ {
QString out; QString out;
m_tmp.setRawData((const QChar *)xprPtr, tlen); m_tmp.setRawData((const QChar *)xprPtr, tlen);

View File

@ -87,7 +87,7 @@ public:
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
// fileName is expected to be absolute and cleanPath()ed. // fileName is expected to be absolute and cleanPath()ed.
ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault);
ProFile *parsedProBlock(const QString &contents, const QString &name, int line = 0, ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0,
SubGrammar grammar = FullGrammar); SubGrammar grammar = FullGrammar);
void discardFileFromCache(const QString &fileName); void discardFileFromCache(const QString &fileName);
@ -130,7 +130,7 @@ private:
}; };
bool read(ProFile *pro, ParseFlags flags); bool read(ProFile *pro, ParseFlags flags);
void read(ProFile *pro, const QString &content, int line, SubGrammar grammar); void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar);
ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len); ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
@ -141,7 +141,7 @@ private:
ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
ushort **buf, QString *xprBuff, ushort **buf, QString *xprBuff,
ushort **tokPtr, QString *tokBuff, ushort **tokPtr, QString *tokBuff,
const ushort *cur, const QString &in); const ushort *cur, const QStringRef &in);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount); void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc); void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void warnOperator(const char *msg); void warnOperator(const char *msg);

View File

@ -120,7 +120,8 @@ QStringList QMakeProject::expand(const ProKey &func, const QList<ProStringList>
ProString QMakeProject::expand(const QString &expr, const QString &where, int line) ProString QMakeProject::expand(const QString &expr, const QString &where, int line)
{ {
ProString ret; ProString ret;
ProFile *pro = m_parser->parsedProBlock(expr, where, line, QMakeParser::ValueGrammar); ProFile *pro = m_parser->parsedProBlock(QStringRef(&expr), where, line,
QMakeParser::ValueGrammar);
if (pro->isOk()) { if (pro->isOk()) {
m_current.pro = pro; m_current.pro = pro;
m_current.line = 0; m_current.line = 0;

View File

@ -55,7 +55,7 @@ public:
ProString expand(const QString &v, const QString &file, int line); ProString expand(const QString &v, const QString &file, int line);
QStringList expand(const ProKey &func, const QList<ProStringList> &args); QStringList expand(const ProKey &func, const QList<ProStringList> &args);
bool test(const QString &v, const QString &file, int line) bool test(const QString &v, const QString &file, int line)
{ m_current.clear(); return evaluateConditional(v, file, line); } { m_current.clear(); return evaluateConditional(QStringRef(&v), file, line); }
bool test(const ProKey &func, const QList<ProStringList> &args); bool test(const ProKey &func, const QList<ProStringList> &args);
bool isSet(const ProKey &v) const { return m_valuemapStack.first().contains(v); } bool isSet(const ProKey &v) const { return m_valuemapStack.first().contains(v); }

View File

@ -2477,12 +2477,12 @@ void tst_qmakelib::proEval()
globals.environment = m_env; globals.environment = m_env;
globals.setProperties(m_prop); globals.setProperties(m_prop);
globals.setDirectories(m_indir, m_outdir); globals.setDirectories(m_indir, m_outdir);
ProFile *outPro = parser.parsedProBlock(out, "out", 1, QMakeParser::FullGrammar); ProFile *outPro = parser.parsedProBlock(QStringRef(&out), "out", 1, QMakeParser::FullGrammar);
if (!outPro->isOk()) { if (!outPro->isOk()) {
qWarning("Expected output is malformed"); qWarning("Expected output is malformed");
verified = false; verified = false;
} }
ProFile *pro = parser.parsedProBlock(in, infile, 1, QMakeParser::FullGrammar); ProFile *pro = parser.parsedProBlock(QStringRef(&in), infile, 1, QMakeParser::FullGrammar);
QMakeEvaluator visitor(&globals, &parser, &vfs, &handler); QMakeEvaluator visitor(&globals, &parser, &vfs, &handler);
visitor.setOutputDir(m_outdir); visitor.setOutputDir(m_outdir);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN

View File

@ -1955,7 +1955,7 @@ void tst_qmakelib::proParser()
handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts)); handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts));
QMakeVfs vfs; QMakeVfs vfs;
QMakeParser parser(0, &vfs, &handler); QMakeParser parser(0, &vfs, &handler);
ProFile *pro = parser.parsedProBlock(in, "in", 1, QMakeParser::FullGrammar); ProFile *pro = parser.parsedProBlock(QStringRef(&in), "in", 1, QMakeParser::FullGrammar);
if (handler.printedMessages()) { if (handler.printedMessages()) {
qWarning("Got unexpected message(s)"); qWarning("Got unexpected message(s)");
verified = false; verified = false;