reorganize AST

turn else, for(), defineTest() and defineReplace() into own node
types instead of treating them as magic conditionals/functions.
on top of that, introduce a proper branching node type, so finding
the alternative code paths can be moved into the parser instead of
burdening the evaluator with it.
This commit is contained in:
Oswald Buddenhagen
2010-04-19 22:35:58 +02:00
parent 583d688ee4
commit c63453d878
5 changed files with 569 additions and 431 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -51,8 +51,8 @@ class ProFileEvaluator
public: public:
struct FunctionDefs { struct FunctionDefs {
QHash<QString, ProBlock *> testFunctions; QHash<QString, ProFunctionDef *> testFunctions;
QHash<QString, ProBlock *> replaceFunctions; QHash<QString, ProFunctionDef *> replaceFunctions;
}; };
enum TemplateType { enum TemplateType {

View File

@@ -33,37 +33,55 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
ProBlock::ProBlock() void ProItem::disposeItems(ProItem *nitm)
: ProItem(BlockKind)
{ {
m_proitems = 0; for (ProItem *itm; (itm = nitm); ) {
m_blockKind = 0; nitm = itm->next();
m_refCount = 1; switch (itm->kind()) {
case ProItem::ConditionKind: delete static_cast<ProCondition *>(itm); break;
case ProItem::VariableKind: delete static_cast<ProVariable *>(itm); break;
case ProItem::BranchKind: delete static_cast<ProBranch *>(itm); break;
case ProItem::LoopKind: delete static_cast<ProLoop *>(itm); break;
case ProItem::FunctionDefKind: static_cast<ProFunctionDef *>(itm)->deref(); break;
case ProItem::OpNotKind:
case ProItem::OpAndKind:
case ProItem::OpOrKind:
delete itm;
break;
}
}
} }
ProBlock::~ProBlock() ProBranch::~ProBranch()
{ {
for (ProItem *itm, *nitm = m_proitems; (itm = nitm); ) { disposeItems(m_thenItems);
nitm = itm->m_next; disposeItems(m_elseItems);
switch (itm->kind()) { }
case BlockKind: static_cast<ProBlock *>(itm)->deref(); break;
case ConditionKind: delete static_cast<ProCondition *>(itm); break; ProLoop::~ProLoop()
case OperatorKind: delete static_cast<ProOperator *>(itm); break; {
case VariableKind: delete static_cast<ProVariable *>(itm); break; disposeItems(m_proitems);
} }
}
ProFunctionDef::~ProFunctionDef()
{
disposeItems(m_proitems);
} }
ProFile::ProFile(const QString &fileName) ProFile::ProFile(const QString &fileName)
: ProBlock() : m_proitems(0),
m_refCount(1),
m_fileName(fileName)
{ {
setBlockKind(ProBlock::ProFileKind);
m_fileName = fileName;
int nameOff = fileName.lastIndexOf(QLatin1Char('/')); int nameOff = fileName.lastIndexOf(QLatin1Char('/'));
m_displayFileName = QString(fileName.constData() + nameOff + 1, m_displayFileName = QString(fileName.constData() + nameOff + 1,
fileName.length() - nameOff - 1); fileName.length() - nameOff - 1);
m_directoryName = QString(fileName.constData(), nameOff); m_directoryName = QString(fileName.constData(), nameOff);
} }
ProFile::~ProFile()
{
ProItem::disposeItems(m_proitems);
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -40,7 +40,7 @@ typedef QAtomicInt ProItemRefCount;
#else #else
class ProItemRefCount { class ProItemRefCount {
public: public:
ProItemRefCount() : m_cnt(0) {} ProItemRefCount(int cnt = 0) : m_cnt(cnt) {}
bool ref() { return ++m_cnt != 0; } bool ref() { return ++m_cnt != 0; }
bool deref() { return --m_cnt != 0; } bool deref() { return --m_cnt != 0; }
ProItemRefCount &operator=(int value) { m_cnt = value; return *this; } ProItemRefCount &operator=(int value) { m_cnt = value; return *this; }
@@ -54,9 +54,13 @@ class ProItem
public: public:
enum ProItemKind { enum ProItemKind {
ConditionKind, ConditionKind,
OperatorKind, OpNotKind,
OpAndKind,
OpOrKind,
VariableKind, VariableKind,
BlockKind BranchKind,
LoopKind,
FunctionDefKind
}; };
enum ProItemReturn { enum ProItemReturn {
@@ -64,8 +68,6 @@ public:
ReturnTrue, ReturnTrue,
ReturnBreak, ReturnBreak,
ReturnNext, ReturnNext,
ReturnLoop,
ReturnSkip,
ReturnReturn ReturnReturn
}; };
@@ -79,43 +81,12 @@ public:
ProItem *next() const { return m_next; } ProItem *next() const { return m_next; }
ProItem **nextRef() { return &m_next; } ProItem **nextRef() { return &m_next; }
static void disposeItems(ProItem *nitm);
private: private:
ProItem *m_next; ProItem *m_next;
ProItemKind m_kind; ProItemKind m_kind;
int m_lineNumber; int m_lineNumber;
friend class ProBlock; // C++ is braindead ...
};
class ProBlock : public ProItem
{
public:
enum ProBlockKind {
NormalKind = 0x00,
ScopeKind = 0x01,
ScopeContentsKind = 0x02,
ProFileKind = 0x08,
FunctionBodyKind = 0x10,
SingleLine = 0x80
};
ProBlock();
~ProBlock();
void setBlockKind(int blockKind) { m_blockKind = blockKind; }
int blockKind() const { return m_blockKind; }
ProItem *items() const { return m_proitems; }
ProItem **itemsRef() { return &m_proitems; }
void ref() { m_refCount.ref(); }
void deref() { if (!m_refCount.deref()) delete this; }
private:
ProItem *m_proitems;
int m_blockKind;
friend class ProFile; // for the pseudo-virtual d'tor
ProItemRefCount m_refCount;
}; };
class ProVariable : public ProItem class ProVariable : public ProItem
@@ -154,35 +125,82 @@ private:
QString m_text; QString m_text;
}; };
class ProOperator : public ProItem class ProBranch : public ProItem
{ {
public: public:
enum OperatorKind { ProBranch() : ProItem(BranchKind) {}
OrOperator = 1, ~ProBranch();
NotOperator = 2
};
explicit ProOperator(OperatorKind operatorKind) : ProItem(ProItem::OperatorKind), m_operatorKind(operatorKind) {} ProItem *thenItems() const { return m_thenItems; }
void setOperatorKind(OperatorKind operatorKind) { m_operatorKind = operatorKind; } ProItem **thenItemsRef() { return &m_thenItems; }
OperatorKind operatorKind() const { return m_operatorKind; } ProItem *elseItems() const { return m_elseItems; }
ProItem **elseItemsRef() { return &m_elseItems; }
private: private:
OperatorKind m_operatorKind; ProItem *m_thenItems;
ProItem *m_elseItems;
}; };
class ProFile : public ProBlock class ProLoop : public ProItem
{
public:
ProLoop(const QString &var, const QString &expr)
: ProItem(LoopKind), m_variable(var), m_expression(expr) {}
~ProLoop();
QString variable() const { return m_variable; }
QString expression() const { return m_expression; }
ProItem *items() const { return m_proitems; }
ProItem **itemsRef() { return &m_proitems; }
private:
QString m_variable;
QString m_expression;
ProItem *m_proitems;
};
class ProFunctionDef : public ProItem
{
public:
enum FunctionType { TestFunction, ReplaceFunction };
ProFunctionDef(const QString &name, FunctionType type)
: ProItem(FunctionDefKind), m_name(name), m_type(type), m_refCount(1) {}
~ProFunctionDef();
QString name() const { return m_name; }
FunctionType type() const { return m_type; }
ProItem *items() const { return m_proitems; }
ProItem **itemsRef() { return &m_proitems; }
void ref() { m_refCount.ref(); }
void deref() { if (!m_refCount.deref()) delete this; }
private:
QString m_name;
FunctionType m_type;
ProItemRefCount m_refCount;
ProItem *m_proitems;
};
class ProFile
{ {
public: public:
explicit ProFile(const QString &fileName); explicit ProFile(const QString &fileName);
~ProFile();
QString displayFileName() const { return m_displayFileName; } QString displayFileName() const { return m_displayFileName; }
QString fileName() const { return m_fileName; } QString fileName() const { return m_fileName; }
QString directoryName() const { return m_directoryName; } QString directoryName() const { return m_directoryName; }
ProItem *items() const { return m_proitems; }
ProItem **itemsRef() { return &m_proitems; }
// d'tor is not virtual void ref() { m_refCount.ref(); }
void deref() { if (!m_refCount.deref()) delete this; } void deref() { if (!m_refCount.deref()) delete this; }
private: private:
ProItem *m_proitems;
ProItemRefCount m_refCount;
QString m_fileName; QString m_fileName;
QString m_displayFileName; QString m_displayFileName;
QString m_directoryName; QString m_directoryName;

View File

@@ -84,12 +84,13 @@ void ProWriter::addFiles(ProFile *profile, QStringList *lines,
*lines << added; *lines << added;
} }
static void findProVariables(ProBlock *block, const QStringList &vars, static void findProVariables(ProItem *item, const QStringList &vars,
QList<ProVariable *> *proVars) QList<ProVariable *> *proVars)
{ {
for (ProItem *item = block->items(); item; item = item->next()) { for (; item; item = item->next()) {
if (item->kind() == ProItem::BlockKind) { if (item->kind() == ProItem::BranchKind) {
findProVariables(static_cast<ProBlock*>(item), vars, proVars); findProVariables(static_cast<ProBranch*>(item)->thenItems(), vars, proVars);
findProVariables(static_cast<ProBranch*>(item)->elseItems(), vars, proVars);
} else if (item->kind() == ProItem::VariableKind) { } else if (item->kind() == ProItem::VariableKind) {
ProVariable *proVar = static_cast<ProVariable*>(item); ProVariable *proVar = static_cast<ProVariable*>(item);
if (vars.contains(proVar->variable())) if (vars.contains(proVar->variable()))
@@ -105,7 +106,7 @@ QStringList ProWriter::removeFiles(ProFile *profile, QStringList *lines,
QStringList notChanged = filePaths; QStringList notChanged = filePaths;
QList<ProVariable *> proVars; QList<ProVariable *> proVars;
findProVariables(profile, vars, &proVars); findProVariables(profile->items(), vars, &proVars);
// This is a tad stupid - basically, it can remove only entries which // This is a tad stupid - basically, it can remove only entries which
// the above code added. // the above code added.