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:
struct FunctionDefs {
QHash<QString, ProBlock *> testFunctions;
QHash<QString, ProBlock *> replaceFunctions;
QHash<QString, ProFunctionDef *> testFunctions;
QHash<QString, ProFunctionDef *> replaceFunctions;
};
enum TemplateType {

View File

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

View File

@@ -40,7 +40,7 @@ typedef QAtomicInt ProItemRefCount;
#else
class ProItemRefCount {
public:
ProItemRefCount() : m_cnt(0) {}
ProItemRefCount(int cnt = 0) : m_cnt(cnt) {}
bool ref() { return ++m_cnt != 0; }
bool deref() { return --m_cnt != 0; }
ProItemRefCount &operator=(int value) { m_cnt = value; return *this; }
@@ -54,9 +54,13 @@ class ProItem
public:
enum ProItemKind {
ConditionKind,
OperatorKind,
OpNotKind,
OpAndKind,
OpOrKind,
VariableKind,
BlockKind
BranchKind,
LoopKind,
FunctionDefKind
};
enum ProItemReturn {
@@ -64,8 +68,6 @@ public:
ReturnTrue,
ReturnBreak,
ReturnNext,
ReturnLoop,
ReturnSkip,
ReturnReturn
};
@@ -79,43 +81,12 @@ public:
ProItem *next() const { return m_next; }
ProItem **nextRef() { return &m_next; }
static void disposeItems(ProItem *nitm);
private:
ProItem *m_next;
ProItemKind m_kind;
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
@@ -154,35 +125,82 @@ private:
QString m_text;
};
class ProOperator : public ProItem
class ProBranch : public ProItem
{
public:
enum OperatorKind {
OrOperator = 1,
NotOperator = 2
};
ProBranch() : ProItem(BranchKind) {}
~ProBranch();
explicit ProOperator(OperatorKind operatorKind) : ProItem(ProItem::OperatorKind), m_operatorKind(operatorKind) {}
void setOperatorKind(OperatorKind operatorKind) { m_operatorKind = operatorKind; }
OperatorKind operatorKind() const { return m_operatorKind; }
ProItem *thenItems() const { return m_thenItems; }
ProItem **thenItemsRef() { return &m_thenItems; }
ProItem *elseItems() const { return m_elseItems; }
ProItem **elseItemsRef() { return &m_elseItems; }
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:
explicit ProFile(const QString &fileName);
~ProFile();
QString displayFileName() const { return m_displayFileName; }
QString fileName() const { return m_fileName; }
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; }
private:
ProItem *m_proitems;
ProItemRefCount m_refCount;
QString m_fileName;
QString m_displayFileName;
QString m_directoryName;

View File

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