Commit e325aa38 authored by Roberto Raggi's avatar Roberto Raggi

Nicer implementation of CPlusPlus::Macro.

parent 1e0f06e4
......@@ -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 (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 (isQtReservedWord(macro.name())) {
QByteArray macroId = macro.name();
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;
Macro()
: _next(0),
_hashcode(0),
_line(0),
_state(0)
{ }
union
{
unsigned state;
QByteArray name() const
{ return _name; }
struct
{
unsigned hidden: 1;
unsigned function_like: 1;
unsigned variadics: 1;
};
};
void setName(const QByteArray &name)
{ _name = name; }
inline Macro():
line(0),
next(0),
hashcode(0),
state(0)
{ }
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
......
......@@ -543,8 +543,8 @@ void CPPEditor::jumpToDefinition()
foreach (const Document::MacroUse use, doc->macroUses()) {
if (use.contains(endOfName - 1)) {
const Macro &macro = use.macro();
const QString fileName = QString::fromUtf8(macro.fileName);
if (openCppEditorAt(fileName, macro.line, 0))
const QString fileName = QString::fromUtf8(macro.fileName());
if (openCppEditorAt(fileName, macro.line(), 0))
return; // done
}
}
......
......@@ -271,8 +271,9 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
if (m_toolTip.isEmpty()) {
foreach (const Document::MacroUse &use, doc->macroUses()) {
if (use.contains(pos)) {
m_toolTip = use.macro().toString();
m_helpId = use.macro().name;
const Macro m = use.macro();
m_toolTip = m.toString();
m_helpId = m.name();
break;
}
}
......
......@@ -741,7 +741,7 @@ void CppCodeCompletion::addMacros(const LookupContext &context)
processed.insert(fn);
if (Document::Ptr doc = context.document(fn)) {
foreach (const Macro &macro, doc->definedMacros()) {
macroNames.insert(macro.name);
macroNames.insert(macro.name());
}
todo += doc->includedFiles();
}
......@@ -749,7 +749,7 @@ void CppCodeCompletion::addMacros(const LookupContext &context)
foreach (const QByteArray &macroName, macroNames) {
TextEditor::CompletionItem item(this);
item.m_text = QString::fromLatin1(macroName.constData(), macroName.length());
item.m_text = QString::fromUtf8(macroName.constData(), macroName.length());
item.m_icon = m_icons.macroIcon();
m_completions.append(item);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment