Commit 2bd3c0ef authored by Dimitri van Heesch's avatar Dimitri van Heesch

Merge branch 'template'

parents bfc2c287 12cd22f4
...@@ -305,12 +305,12 @@ int TemplateVariant::toInt() const ...@@ -305,12 +305,12 @@ int TemplateVariant::toInt() const
return result; return result;
} }
const TemplateStructIntf *TemplateVariant::toStruct() const TemplateStructIntf *TemplateVariant::toStruct() const
{ {
return p->type==Struct ? p->strukt : 0; return p->type==Struct ? p->strukt : 0;
} }
const TemplateListIntf *TemplateVariant::toList() const TemplateListIntf *TemplateVariant::toList() const
{ {
return p->type==List ? p->list : 0; return p->type==List ? p->list : 0;
} }
...@@ -624,6 +624,14 @@ class TemplateBlockContext ...@@ -624,6 +624,14 @@ class TemplateBlockContext
QDict< QList<TemplateNodeBlock> > m_blocks; QDict< QList<TemplateNodeBlock> > m_blocks;
}; };
/** @brief A container to store a key-value pair */
struct TemplateKeyValue
{
TemplateKeyValue() {}
TemplateKeyValue(const QCString &k,const TemplateVariant &v) : key(k), value(v) {}
QCString key;
TemplateVariant value;
};
/** @brief Internal class representing the implementation of a template /** @brief Internal class representing the implementation of a template
* context */ * context */
...@@ -650,10 +658,8 @@ class TemplateContextImpl : public TemplateContext ...@@ -650,10 +658,8 @@ class TemplateContextImpl : public TemplateContext
{ TemplateEscapeIntf **ppIntf = m_escapeIntfDict.find(ext); { TemplateEscapeIntf **ppIntf = m_escapeIntfDict.find(ext);
m_activeEscapeIntf = ppIntf ? *ppIntf : 0; m_activeEscapeIntf = ppIntf ? *ppIntf : 0;
} }
void setActiveEscapeIntf(TemplateEscapeIntf *intf) void setActiveEscapeIntf(TemplateEscapeIntf *intf) { m_activeEscapeIntf = intf; }
{ m_activeEscapeIntf = intf; } void setSpacelessIntf(TemplateSpacelessIntf *intf) { m_spacelessIntf = intf; }
void setSpacelessIntf(TemplateSpacelessIntf *intf)
{ m_spacelessIntf = intf; }
// internal methods // internal methods
TemplateBlockContext *blockContext(); TemplateBlockContext *blockContext();
...@@ -669,6 +675,11 @@ class TemplateContextImpl : public TemplateContext ...@@ -669,6 +675,11 @@ class TemplateContextImpl : public TemplateContext
bool spacelessEnabled() const { return m_spacelessEnabled && m_spacelessIntf; } bool spacelessEnabled() const { return m_spacelessEnabled && m_spacelessIntf; }
void warn(const char *fileName,int line,const char *fmt,...) const; void warn(const char *fileName,int line,const char *fmt,...) const;
// index related functions
void openSubIndex(const QCString &indexName);
void closeSubIndex(const QCString &indexName);
void addIndexEntry(const QCString &indexName,const QValueList<TemplateKeyValue> &arguments);
private: private:
const TemplateEngine *m_engine; const TemplateEngine *m_engine;
QCString m_templateName; QCString m_templateName;
...@@ -680,6 +691,8 @@ class TemplateContextImpl : public TemplateContext ...@@ -680,6 +691,8 @@ class TemplateContextImpl : public TemplateContext
TemplateEscapeIntf *m_activeEscapeIntf; TemplateEscapeIntf *m_activeEscapeIntf;
TemplateSpacelessIntf *m_spacelessIntf; TemplateSpacelessIntf *m_spacelessIntf;
bool m_spacelessEnabled; bool m_spacelessEnabled;
TemplateAutoRef<TemplateStruct> m_indices;
QDict< QStack<TemplateVariant> > m_indexStacks;
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -1831,11 +1844,13 @@ class TemplateImpl : public TemplateNode, public Template ...@@ -1831,11 +1844,13 @@ class TemplateImpl : public TemplateNode, public Template
TemplateContextImpl::TemplateContextImpl(const TemplateEngine *e) TemplateContextImpl::TemplateContextImpl(const TemplateEngine *e)
: m_engine(e), m_templateName("<unknown>"), m_line(1), m_activeEscapeIntf(0), : m_engine(e), m_templateName("<unknown>"), m_line(1), m_activeEscapeIntf(0),
m_spacelessIntf(0), m_spacelessEnabled(FALSE) m_spacelessIntf(0), m_spacelessEnabled(FALSE), m_indices(TemplateStruct::alloc())
{ {
m_indexStacks.setAutoDelete(TRUE);
m_contextStack.setAutoDelete(TRUE); m_contextStack.setAutoDelete(TRUE);
m_escapeIntfDict.setAutoDelete(TRUE); m_escapeIntfDict.setAutoDelete(TRUE);
push(); push();
set("index",m_indices.get());
} }
TemplateContextImpl::~TemplateContextImpl() TemplateContextImpl::~TemplateContextImpl()
...@@ -1969,6 +1984,102 @@ void TemplateContextImpl::warn(const char *fileName,int line,const char *fmt,... ...@@ -1969,6 +1984,102 @@ void TemplateContextImpl::warn(const char *fileName,int line,const char *fmt,...
m_engine->printIncludeContext(fileName,line); m_engine->printIncludeContext(fileName,line);
} }
void TemplateContextImpl::openSubIndex(const QCString &indexName)
{
//printf("TemplateContextImpl::openSubIndex(%s)\n",indexName.data());
QStack<TemplateVariant> *stack = m_indexStacks.find(indexName);
if (!stack || stack->isEmpty() || stack->top()->type()==TemplateVariant::List) // error: no stack yet or no entry
{
warn(m_templateName,m_line,"opensubindex for index %s without preceding indexentry",indexName.data());
return;
}
// get the parent entry to add the list to
TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack->top()->toStruct());
if (entry)
{
// add new list to the stack
TemplateList *list = TemplateList::alloc();
stack->push(new TemplateVariant(list));
entry->set("children",list);
entry->set("is_leaf_node",false);
}
}
void TemplateContextImpl::closeSubIndex(const QCString &indexName)
{
//printf("TemplateContextImpl::closeSubIndex(%s)\n",indexName.data());
QStack<TemplateVariant> *stack = m_indexStacks.find(indexName);
if (!stack || stack->count()<3)
{
warn(m_templateName,m_line,"closesubindex for index %s without matching open",indexName.data());
}
else // stack->count()>=2
{
if (stack->top()->type()==TemplateVariant::Struct)
{
delete stack->pop(); // pop struct
delete stack->pop(); // pop list
}
else // empty list! correct "is_left_node" attribute of the parent entry
{
delete stack->pop(); // pop list
TemplateStruct *entry = dynamic_cast<TemplateStruct*>(stack->top()->toStruct());
if (entry)
{
entry->set("is_leaf_node",true);
}
}
}
}
void TemplateContextImpl::addIndexEntry(const QCString &indexName,const QValueList<TemplateKeyValue> &arguments)
{
QValueListConstIterator<TemplateKeyValue> it = arguments.begin();
//printf("TemplateContextImpl::addIndexEntry(%s)\n",indexName.data());
//while (it!=arguments.end())
//{
// printf(" key=%s value=%s\n",(*it).key.data(),(*it).value.toString().data());
// ++it;
//}
QStack<TemplateVariant> *stack = m_indexStacks.find(indexName);
if (!stack) // no stack yet, create it!
{
stack = new QStack<TemplateVariant>;
stack->setAutoDelete(TRUE);
m_indexStacks.insert(indexName,stack);
}
TemplateList *list = 0;
if (stack->isEmpty()) // first item, create empty list and add it to the index
{
list = TemplateList::alloc();
stack->push(new TemplateVariant(list));
m_indices->set(indexName,list); // make list available under index
}
else // stack not empty
{
if (stack->top()->type()==TemplateVariant::Struct) // already an entry in the list
{
// remove current entry from the stack
delete stack->pop();
}
else // first entry after opensubindex
{
ASSERT(stack->top()->type()==TemplateVariant::List);
}
// get list to add new item
list = dynamic_cast<TemplateList*>(stack->top()->toList());
}
TemplateStruct *entry = TemplateStruct::alloc();
// add user specified fields to the entry
for (it=arguments.begin();it!=arguments.end();++it)
{
entry->set((*it).key,(*it).value);
}
entry->set("is_leaf_node",true);
stack->push(new TemplateVariant(entry));
list->append(entry);
}
//---------------------------------------------------------- //----------------------------------------------------------
/** @brief Class representing a piece of plain text in a template */ /** @brief Class representing a piece of plain text in a template */
...@@ -3020,6 +3131,148 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree> ...@@ -3020,6 +3131,148 @@ class TemplateNodeTree : public TemplateNodeCreator<TemplateNodeTree>
TemplateNodeList m_treeNodes; TemplateNodeList m_treeNodes;
}; };
//----------------------------------------------------------
/** @brief Class representing an 'indexentry' tag in a template */
class TemplateNodeIndexEntry : public TemplateNodeCreator<TemplateNodeIndexEntry>
{
struct Mapping
{
Mapping(const QCString &n,ExprAst *e) : name(n), value(e) {}
~Mapping() { delete value; }
QCString name;
ExprAst *value;
};
public:
TemplateNodeIndexEntry(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
: TemplateNodeCreator<TemplateNodeIndexEntry>(parser,parent,line)
{
TRACE(("{TemplateNodeIndexEntry(%s)\n",data.data()));
m_args.setAutoDelete(TRUE);
ExpressionParser expParser(parser,line);
QValueList<QCString> args = split(data," ");
QValueListIterator<QCString> it = args.begin();
if (it==args.end() || (*it).find('=')!=-1)
{
parser->warn(parser->templateName(),line,"Missing name for indexentry tag");
}
else
{
m_name = *it;
++it;
while (it!=args.end())
{
QCString arg = *it;
int j=arg.find('=');
if (j>0)
{
ExprAst *expr = expParser.parse(arg.mid(j+1));
if (expr)
{
m_args.append(new Mapping(arg.left(j),expr));
}
}
else
{
parser->warn(parser->templateName(),line,"invalid argument '%s' for indexentry tag",arg.data());
}
++it;
}
}
TRACE(("}TemplateNodeIndexEntry(%s)\n",data.data()));
}
void render(FTextStream &, TemplateContext *c)
{
if (!m_name.isEmpty())
{
TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
ci->setLocation(m_templateName,m_line);
QListIterator<Mapping> it(m_args);
Mapping *mapping;
QValueList<TemplateKeyValue> list;
for (it.toFirst();(mapping=it.current());++it)
{
list.append(TemplateKeyValue(mapping->name,mapping->value->resolve(c)));
}
ci->addIndexEntry(m_name,list);
}
}
private:
QCString m_name;
QList<Mapping> m_args;
};
//----------------------------------------------------------
/** @brief Class representing an 'opensubindex' tag in a template */
class TemplateNodeOpenSubIndex : public TemplateNodeCreator<TemplateNodeOpenSubIndex>
{
public:
TemplateNodeOpenSubIndex(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
: TemplateNodeCreator<TemplateNodeOpenSubIndex>(parser,parent,line)
{
TRACE(("{TemplateNodeOpenSubIndex(%s)\n",data.data()));
m_name = data.stripWhiteSpace();
if (m_name.isEmpty())
{
parser->warn(parser->templateName(),line,"Missing argument for opensubindex tag");
}
else if (m_name.find(' ')!=-1)
{
parser->warn(parser->templateName(),line,"Expected single argument for opensubindex tag got '%s'",data.data());
m_name="";
}
TRACE(("}TemplateNodeOpenSubIndex(%s)\n",data.data()));
}
void render(FTextStream &, TemplateContext *c)
{
if (!m_name.isEmpty())
{
TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
ci->setLocation(m_templateName,m_line);
ci->openSubIndex(m_name);
}
}
private:
QCString m_name;
};
//----------------------------------------------------------
/** @brief Class representing an 'closesubindex' tag in a template */
class TemplateNodeCloseSubIndex : public TemplateNodeCreator<TemplateNodeCloseSubIndex>
{
public:
TemplateNodeCloseSubIndex(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
: TemplateNodeCreator<TemplateNodeCloseSubIndex>(parser,parent,line)
{
TRACE(("{TemplateNodeCloseSubIndex(%s)\n",data.data()));
m_name = data.stripWhiteSpace();
if (m_name.isEmpty())
{
parser->warn(parser->templateName(),line,"Missing argument for closesubindex tag");
}
else if (m_name.find(' ')!=-1 || m_name.isEmpty())
{
parser->warn(parser->templateName(),line,"Expected single argument for closesubindex tag got '%s'",data.data());
m_name="";
}
TRACE(("}TemplateNodeCloseSubIndex(%s)\n",data.data()));
}
void render(FTextStream &, TemplateContext *c)
{
if (!m_name.isEmpty())
{
TemplateContextImpl *ci = dynamic_cast<TemplateContextImpl*>(c);
ci->setLocation(m_templateName,m_line);
ci->closeSubIndex(m_name);
}
}
private:
QCString m_name;
};
//---------------------------------------------------------- //----------------------------------------------------------
/** @brief Class representing an 'with' tag in a template */ /** @brief Class representing an 'with' tag in a template */
...@@ -3395,6 +3648,9 @@ static TemplateNodeFactory::AutoRegister<TemplateNodeRepeat> autoRefRepeat("r ...@@ -3395,6 +3648,9 @@ static TemplateNodeFactory::AutoRegister<TemplateNodeRepeat> autoRefRepeat("r
static TemplateNodeFactory::AutoRegister<TemplateNodeInclude> autoRefInclude("include"); static TemplateNodeFactory::AutoRegister<TemplateNodeInclude> autoRefInclude("include");
static TemplateNodeFactory::AutoRegister<TemplateNodeMarkers> autoRefMarkers("markers"); static TemplateNodeFactory::AutoRegister<TemplateNodeMarkers> autoRefMarkers("markers");
static TemplateNodeFactory::AutoRegister<TemplateNodeSpaceless> autoRefSpaceless("spaceless"); static TemplateNodeFactory::AutoRegister<TemplateNodeSpaceless> autoRefSpaceless("spaceless");
static TemplateNodeFactory::AutoRegister<TemplateNodeIndexEntry> autoRefIndexEntry("indexentry");
static TemplateNodeFactory::AutoRegister<TemplateNodeOpenSubIndex> autoRefOpenSubIndex("opensubindex");
static TemplateNodeFactory::AutoRegister<TemplateNodeCloseSubIndex> autoRefCloseSubIndex("closesubindex");
//---------------------------------------------------------- //----------------------------------------------------------
......
...@@ -191,12 +191,12 @@ class TemplateVariant ...@@ -191,12 +191,12 @@ class TemplateVariant
/** Returns the pointer to list referenced by this variant /** Returns the pointer to list referenced by this variant
* or 0 if this variant does not have list type. * or 0 if this variant does not have list type.
*/ */
const TemplateListIntf *toList() const; TemplateListIntf *toList() const;
/** Returns the pointer to struct referenced by this variant /** Returns the pointer to struct referenced by this variant
* or 0 if this variant does not have struct type. * or 0 if this variant does not have struct type.
*/ */
const TemplateStructIntf *toStruct() const; TemplateStructIntf *toStruct() const;
/** Return the result of apply this function with \a args. /** Return the result of apply this function with \a args.
* Returns an empty string if the variant type is not a function. * Returns an empty string if the variant type is not a function.
...@@ -399,7 +399,7 @@ class TemplateSpacelessIntf ...@@ -399,7 +399,7 @@ class TemplateSpacelessIntf
* A key is searched starting with the dictionary at the top of the stack * A key is searched starting with the dictionary at the top of the stack
* and searching downwards until it is found. The stack is used to create * and searching downwards until it is found. The stack is used to create
* local scopes. * local scopes.
* @note This object must be created by TemplateEngine * @note This object must be created by TemplateEngine::createContext()
*/ */
class TemplateContext class TemplateContext
{ {
......
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