forked from qt-creator/qt-creator
		
	Nicer implementation of CPlusPlus::Macro.
This commit is contained in:
		| @@ -40,7 +40,6 @@ | ||||
| #include <Control.h> | ||||
| #include <cplusplus/Overview.h> | ||||
|  | ||||
| #include <QFile> | ||||
| #include <QtDebug> | ||||
|  | ||||
| using namespace CPlusPlus; | ||||
|   | ||||
| @@ -600,19 +600,15 @@ void Preprocessor::operator()(const QByteArray &source, QByteArray *result) | ||||
|                 if (! m) { | ||||
|                     result->append(spell); | ||||
|                 } else { | ||||
|                     if (! m->function_like) { | ||||
|                     if (! m->isFunctionLike()) { | ||||
|                         if (_dot->isNot(T_LPAREN)) { | ||||
|                             if (client) | ||||
|                                 client->startExpandingMacro(identifierToken->offset, | ||||
|                                                             *m, spell); | ||||
|  | ||||
|                             m->hidden = true; | ||||
|  | ||||
|                             expand(m->definition.constBegin(), | ||||
|                                    m->definition.constEnd(), | ||||
|                                    result); | ||||
|  | ||||
|                             m->hidden = false; | ||||
|                             m->setHidden(true); | ||||
|                             expand(m->definition(), result); | ||||
|                             m->setHidden(false); | ||||
|  | ||||
|                             if (client) | ||||
|                                 client->stopExpandingMacro(_dot->offset, *m); | ||||
| @@ -624,13 +620,9 @@ void Preprocessor::operator()(const QByteArray &source, QByteArray *result) | ||||
|                             if (client) | ||||
|                                 client->startExpandingMacro(identifierToken->offset, | ||||
|                                                             *m, spell); | ||||
|                             m->hidden = true; | ||||
|  | ||||
|                             expand(m->definition.constBegin(), | ||||
|                                    m->definition.constEnd(), | ||||
|                                    &tmp); | ||||
|  | ||||
|                             m->hidden = false; | ||||
|                             m->setHidden(true); | ||||
|                             expand(m->definition(), &tmp); | ||||
|                             m->setHidden(false); | ||||
|  | ||||
|                             if (client) | ||||
|                                 client->stopExpandingMacro(_dot->offset, *m); | ||||
| @@ -641,7 +633,7 @@ void Preprocessor::operator()(const QByteArray &source, QByteArray *result) | ||||
|                             if (_dot->is(T_IDENTIFIER)) { | ||||
|                                 const QByteArray id = tokenSpell(*_dot); | ||||
|                                 Macro *macro = env.resolve(id); | ||||
|                                 if (macro && macro->function_like) | ||||
|                                 if (macro && macro->isFunctionLike()) | ||||
|                                     m = macro; | ||||
|                             } | ||||
|                             popState(); | ||||
| @@ -656,7 +648,7 @@ void Preprocessor::operator()(const QByteArray &source, QByteArray *result) | ||||
|                     // collect the actual arguments | ||||
|                     if (_dot->isNot(T_LPAREN)) { | ||||
|                         // ### warnng expected T_LPAREN | ||||
|                         result->append(m->name); | ||||
|                         result->append(m->name()); | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
| @@ -852,30 +844,30 @@ void Preprocessor::processDefine(TokenIterator firstToken, TokenIterator lastTok | ||||
|     } | ||||
|  | ||||
|     Macro macro; | ||||
|     macro.fileName = env.currentFile; | ||||
|     macro.line = env.currentLine; | ||||
|     macro.name = tokenText(*tk); | ||||
|     macro.setFileName(env.currentFile); | ||||
|     macro.setLine(env.currentLine); | ||||
|     macro.setName(tokenText(*tk)); | ||||
|     ++tk; // skip T_IDENTIFIER | ||||
|  | ||||
|     if (tk->is(T_LPAREN) && ! tk->whitespace) { | ||||
|         // a function-like macro definition | ||||
|         macro.function_like = true; | ||||
|         macro.setFunctionLike(true); | ||||
|  | ||||
|         ++tk; // skip T_LPAREN | ||||
|         if (tk->is(T_IDENTIFIER)) { | ||||
|             macro.formals.append(tokenText(*tk)); | ||||
|             macro.addFormal(tokenText(*tk)); | ||||
|             ++tk; // skip T_IDENTIFIER | ||||
|             while (tk->is(T_COMMA)) { | ||||
|                 ++tk;// skip T_COMMA | ||||
|                 if (tk->isNot(T_IDENTIFIER)) | ||||
|                     break; | ||||
|                 macro.formals.append(tokenText(*tk)); | ||||
|                 macro.addFormal(tokenText(*tk)); | ||||
|                 ++tk; // skip T_IDENTIFIER | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (tk->is(T_DOT_DOT_DOT)) { | ||||
|             macro.variadics = true; | ||||
|             macro.setVariadic(true); | ||||
|             ++tk; // skip T_DOT_DOT_DOT | ||||
|         } | ||||
|  | ||||
| @@ -887,32 +879,31 @@ void Preprocessor::processDefine(TokenIterator firstToken, TokenIterator lastTok | ||||
|         ++tk; // skip T_RPAREN | ||||
|     } | ||||
|  | ||||
|     QByteArray macroId = macro.name; | ||||
|     const bool isQtWord = isQtReservedWord(macroId); | ||||
|     if (isQtReservedWord(macro.name())) { | ||||
|         QByteArray macroId = macro.name(); | ||||
|  | ||||
|     if (macro.function_like) { | ||||
|         macroId += '('; | ||||
|         for (int i = 0; i < macro.formals.size(); ++i) { | ||||
|             if (i != 0) | ||||
|                 macroId += ", "; | ||||
|  | ||||
|             const QByteArray formal = macro.formals.at(i); | ||||
|             macroId += formal; | ||||
|         if (macro.isFunctionLike()) { | ||||
|             macroId += '('; | ||||
|             bool fst = true; | ||||
|             foreach (const QByteArray formal, macro.formals()) { | ||||
|                 if (! fst) | ||||
|                     macroId += ", "; | ||||
|                 fst = false; | ||||
|                 macroId += formal; | ||||
|             } | ||||
|             macroId += ')'; | ||||
|         } | ||||
|         macroId += ')'; | ||||
|     } | ||||
|  | ||||
|     if (isQtWord) | ||||
|         macro.definition = macroId; | ||||
|     else { | ||||
|         macro.setDefinition(macroId); | ||||
|     } else { | ||||
|         // ### make me fast! | ||||
|         const char *startOfDefinition = startOfToken(*tk); | ||||
|         const char *endOfDefinition = startOfToken(*lastToken); | ||||
|         macro.definition.append(startOfDefinition, | ||||
|                                 endOfDefinition - startOfDefinition); | ||||
|         macro.definition.replace("\\\n", " "); | ||||
|         macro.definition.replace('\n', ' '); | ||||
|         macro.definition = macro.definition.trimmed(); | ||||
|         QByteArray definition(startOfDefinition, | ||||
|                               endOfDefinition - startOfDefinition); | ||||
|         definition.replace("\\\n", " "); | ||||
|         definition.replace('\n', ' '); | ||||
|         macro.setDefinition(definition.trimmed()); | ||||
|     } | ||||
|  | ||||
|     env.bind(macro); | ||||
|   | ||||
| @@ -91,10 +91,10 @@ Macro *Environment::macroAt(unsigned index) const | ||||
|  | ||||
| Macro *Environment::bind(const Macro &__macro) | ||||
| { | ||||
|     Q_ASSERT(! __macro.name.isEmpty()); | ||||
|     Q_ASSERT(! __macro.name().isEmpty()); | ||||
|  | ||||
|     Macro *m = new Macro (__macro); | ||||
|     m->hashcode = hash_code(m->name); | ||||
|     m->_hashcode = hash_code(m->name()); | ||||
|  | ||||
|     if (++_macro_count == _allocated_macros) { | ||||
|         if (! _allocated_macros) | ||||
| @@ -110,8 +110,8 @@ Macro *Environment::bind(const Macro &__macro) | ||||
|     if (! _hash || _macro_count > (_hash_count >> 1)) { | ||||
|         rehash(); | ||||
|     } else { | ||||
|         const unsigned h = m->hashcode % _hash_count; | ||||
|         m->next = _hash[h]; | ||||
|         const unsigned h = m->_hashcode % _hash_count; | ||||
|         m->_next = _hash[h]; | ||||
|         _hash[h] = m; | ||||
|     } | ||||
|  | ||||
| @@ -121,10 +121,10 @@ Macro *Environment::bind(const Macro &__macro) | ||||
| Macro *Environment::remove(const QByteArray &name) | ||||
| { | ||||
|     Macro macro; | ||||
|     macro.name = name; | ||||
|     macro.hidden = true; | ||||
|     macro.fileName = currentFile; | ||||
|     macro.line = currentLine; | ||||
|     macro.setName(name); | ||||
|     macro.setHidden(true); | ||||
|     macro.setFileName(currentFile); | ||||
|     macro.setLine(currentLine); | ||||
|     return bind(macro); | ||||
| } | ||||
|  | ||||
| @@ -198,10 +198,10 @@ Macro *Environment::resolve (const QByteArray &name) const | ||||
|         return 0; | ||||
|  | ||||
|     Macro *it = _hash[hash_code (name) % _hash_count]; | ||||
|     for (; it; it = it->next) { | ||||
|         if (it->name != name) | ||||
|     for (; it; it = it->_next) { | ||||
|         if (it->name() != name) | ||||
|             continue; | ||||
|         else if (it->hidden) | ||||
|         else if (it->isHidden()) | ||||
|             return 0; | ||||
|         else break; | ||||
|     } | ||||
| @@ -229,8 +229,8 @@ void Environment::rehash() | ||||
|  | ||||
|     for (Macro **it = firstMacro(); it != lastMacro(); ++it) { | ||||
|         Macro *m= *it; | ||||
|         const unsigned h = m->hashcode % _hash_count; | ||||
|         m->next = _hash[h]; | ||||
|         const unsigned h = m->_hashcode % _hash_count; | ||||
|         m->_next = _hash[h]; | ||||
|         _hash[h] = m; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -62,7 +62,7 @@ const QByteArray *MacroExpander::resolve_formal(const QByteArray &__name) | ||||
|     if (! (frame && frame->expanding_macro)) | ||||
|         return 0; | ||||
|  | ||||
|     const QVector<QByteArray> &formals = frame->expanding_macro->formals; | ||||
|     const QVector<QByteArray> formals = frame->expanding_macro->formals(); | ||||
|     for (int index = 0; index < formals.size(); ++index) { | ||||
|         const QByteArray formal = formals.at(index); | ||||
|  | ||||
| @@ -213,7 +213,7 @@ const char *MacroExpander::operator () (const char *__first, const char *__last, | ||||
|             } | ||||
|  | ||||
|             Macro *macro = env.resolve (fast_name); | ||||
|             if (! macro || macro->hidden || env.hide_next) | ||||
|             if (! macro || macro->isHidden() || env.hide_next) | ||||
|             { | ||||
|                 if (fast_name.size () == 7 && fast_name [0] == 'd' && fast_name == "defined") | ||||
|                     env.hide_next = true; | ||||
| @@ -260,19 +260,19 @@ const char *MacroExpander::operator () (const char *__first, const char *__last, | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (! macro->function_like) | ||||
|             if (! macro->isFunctionLike()) | ||||
|             { | ||||
|                 Macro *m = 0; | ||||
|  | ||||
|                 if (! macro->definition.isEmpty()) | ||||
|                 if (! macro->definition().isEmpty()) | ||||
|                 { | ||||
|                     macro->hidden = true; | ||||
|                     macro->setHidden(true); | ||||
|  | ||||
|                     QByteArray __tmp; | ||||
|                     __tmp.reserve (256); | ||||
|  | ||||
|                     MacroExpander expand_macro (env); | ||||
|                     expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), &__tmp); | ||||
|                     expand_macro (macro->definition(), &__tmp); | ||||
|                     generated_lines += expand_macro.lines; | ||||
|  | ||||
|                     if (! __tmp.isEmpty ()) | ||||
| @@ -292,7 +292,7 @@ const char *MacroExpander::operator () (const char *__first, const char *__last, | ||||
|                             *__result += __tmp; | ||||
|                     } | ||||
|  | ||||
|                     macro->hidden = false; | ||||
|                     macro->setHidden(false); | ||||
|                 } | ||||
|  | ||||
|                 if (! m) | ||||
| @@ -348,9 +348,9 @@ const char *MacroExpander::operator () (const char *__first, const char *__last, | ||||
|  | ||||
|             pp_frame frame (macro, actuals); | ||||
|             MacroExpander expand_macro (env, &frame); | ||||
|             macro->hidden = true; | ||||
|             expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), __result); | ||||
|             macro->hidden = false; | ||||
|             macro->setHidden(true); | ||||
|             expand_macro (macro->definition(), __result); | ||||
|             macro->setHidden(false); | ||||
|             generated_lines += expand_macro.lines; | ||||
|         } | ||||
|         else | ||||
| @@ -366,8 +366,8 @@ const char *MacroExpander::skip_argument_variadics (QVector<QByteArray> const &_ | ||||
| { | ||||
|     const char *arg_end = skip_argument (__first, __last); | ||||
|  | ||||
|     while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ',' | ||||
|            && (__actuals.size () + 1) == __macro->formals.size ()) | ||||
|     while (__macro->isVariadic() && __first != arg_end && arg_end != __last && *arg_end == ',' | ||||
|            && (__actuals.size () + 1) == __macro->formals().size ()) | ||||
|     { | ||||
|         arg_end = skip_argument (++arg_end, __last); | ||||
|     } | ||||
|   | ||||
| @@ -88,6 +88,10 @@ namespace CPlusPlus { | ||||
|         const char *operator () (const char *first, const char *last, | ||||
|                                  QByteArray *result); | ||||
|  | ||||
|         const char *operator () (const QByteArray &source, | ||||
|                                  QByteArray *result) | ||||
|         { return operator()(source.constBegin(), source.constEnd(), result); } | ||||
|  | ||||
|         const char *skip_argument_variadics (const QVector<QByteArray> &actuals, | ||||
|                                              Macro *macro, | ||||
|                                              const char *first, const char *last); | ||||
|   | ||||
| @@ -64,59 +64,110 @@ namespace CPlusPlus { | ||||
| class CPLUSPLUS_EXPORT Macro | ||||
| { | ||||
| public: | ||||
|     QByteArray name; | ||||
|     QByteArray definition; | ||||
|     QVector<QByteArray> formals; | ||||
|     QByteArray fileName; | ||||
|     int line; | ||||
|     Macro *next; | ||||
|     unsigned hashcode; | ||||
|  | ||||
|     union | ||||
|     { | ||||
|         unsigned state; | ||||
|  | ||||
|         struct | ||||
|         { | ||||
|             unsigned hidden: 1; | ||||
|             unsigned function_like: 1; | ||||
|             unsigned variadics: 1; | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     inline Macro(): | ||||
|             line(0), | ||||
|             next(0), | ||||
|             hashcode(0), | ||||
|             state(0) | ||||
|     Macro() | ||||
|         : _next(0), | ||||
|           _hashcode(0), | ||||
|           _line(0), | ||||
|           _state(0) | ||||
|     { } | ||||
|  | ||||
|     QByteArray name() const | ||||
|     { return _name; } | ||||
|  | ||||
|     void setName(const QByteArray &name) | ||||
|     { _name = name; } | ||||
|  | ||||
|     QByteArray definition() const | ||||
|     { return _definition; } | ||||
|  | ||||
|     void setDefinition(const QByteArray &definition) | ||||
|     { _definition = definition; } | ||||
|  | ||||
|     QVector<QByteArray> formals() const | ||||
|     { return _formals; } | ||||
|  | ||||
|     void addFormal(const QByteArray &formal) | ||||
|     { _formals.append(formal); } | ||||
|  | ||||
|     QByteArray fileName() const | ||||
|     { return _fileName; } | ||||
|  | ||||
|     void setFileName(const QByteArray &fileName) | ||||
|     { _fileName = fileName; } | ||||
|  | ||||
|     unsigned line() const | ||||
|     { return _line; } | ||||
|  | ||||
|     void setLine(unsigned line) | ||||
|     { _line = line; } | ||||
|  | ||||
|     bool isHidden() const | ||||
|     { return _hidden; } | ||||
|  | ||||
|     void setHidden(bool isHidden) | ||||
|     { _hidden = isHidden; } | ||||
|  | ||||
|     bool isFunctionLike() const | ||||
|     { return _functionLike; } | ||||
|  | ||||
|     void setFunctionLike(bool isFunctionLike) | ||||
|     { _functionLike = isFunctionLike; } | ||||
|  | ||||
|     bool isVariadic() const | ||||
|     { return _variadic; } | ||||
|  | ||||
|     void setVariadic(bool isVariadic) | ||||
|     { _variadic = isVariadic; } | ||||
|  | ||||
|     QString toString() const | ||||
|     { | ||||
|         QString text; | ||||
|         if (hidden) | ||||
|         if (_hidden) | ||||
|             text += QLatin1String("#undef "); | ||||
|         else | ||||
|             text += QLatin1String("#define "); | ||||
|         text += QString::fromUtf8(name.constData(), name.size()); | ||||
|         if (function_like) { | ||||
|         text += QString::fromUtf8(_name.constData(), _name.size()); | ||||
|         if (_functionLike) { | ||||
|             text += QLatin1Char('('); | ||||
|             bool first = true; | ||||
|             foreach (const QByteArray formal, formals) { | ||||
|             foreach (const QByteArray formal, _formals) { | ||||
|                 if (! first) | ||||
|                     text += QLatin1String(", "); | ||||
|                 else | ||||
|                     first = false; | ||||
|                 text += QString::fromUtf8(formal.constData(), formal.size()); | ||||
|             } | ||||
|             if (variadics) | ||||
|             if (_variadic) | ||||
|                 text += QLatin1String("..."); | ||||
|             text += QLatin1Char(')'); | ||||
|         } | ||||
|         text += QLatin1Char(' '); | ||||
|         text += QString::fromUtf8(definition.constData(), definition.size()); | ||||
|         text += QString::fromUtf8(_definition.constData(), _definition.size()); | ||||
|         return text; | ||||
|     } | ||||
|  | ||||
| // ### private | ||||
|     Macro *_next; | ||||
|     unsigned _hashcode; | ||||
|  | ||||
| private: | ||||
|     QByteArray _name; | ||||
|     QByteArray _definition; | ||||
|     QVector<QByteArray> _formals; | ||||
|     QByteArray _fileName; | ||||
|     unsigned _line; | ||||
|  | ||||
|     union | ||||
|     { | ||||
|         unsigned _state; | ||||
|  | ||||
|         struct | ||||
|         { | ||||
|             unsigned _hidden: 1; | ||||
|             unsigned _functionLike: 1; | ||||
|             unsigned _variadic: 1; | ||||
|         }; | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| } // namespace CPlusPlus | ||||
|   | ||||
		Reference in New Issue
	
	Block a user