diff --git a/src/context.cpp b/src/context.cpp index d741f487733..3641d1d4654 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -717,6 +717,10 @@ class TranslateContext::Private : public PropertyMapper { return theTranslator->trCompoundMembers(); } + TemplateVariant detailLevel() const + { + return theTranslator->trDetailLevel(); + } Private() { //%% string generatedBy @@ -825,6 +829,8 @@ class TranslateContext::Private : public PropertyMapper addProperty("classDocumentation", this,&Private::classDocumentation); //%% string compoundMembers addProperty("compoundMembers", this,&Private::compoundMembers); + //%% strint detailLevel + addProperty("detailLevel", this,&Private::detailLevel); m_javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); m_fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); @@ -4070,7 +4076,6 @@ class NestingNodeContext::Private : public PropertyMapper Definition *d,int index,int level,bool addCls) : m_parent(parent), m_def(d), m_children(thisNode,level+1), m_level(level), m_index(index) { - printf("Node %s level=%d\n",d->name().data(),level); //%% bool is_leaf_node: true if this node does not have any children addProperty("is_leaf_node",this,&Private::isLeafNode); //%% Nesting children: list of nested classes/namespaces @@ -4079,6 +4084,10 @@ class NestingNodeContext::Private : public PropertyMapper addProperty("class",this,&Private::getClass); //%% [optional] Namespace namespace: namespace info (if this node represents a namespace) addProperty("namespace",this,&Private::getNamespace); + //%% [optional] File file: file info (if this node represents a file) + addProperty("file",this,&Private::file); + //%% [optional] Dir dir: directory info (if this node represents a directory) + addProperty("dir",this,&Private::dir); //%% int id addProperty("id",this,&Private::id); //%% string level @@ -4133,6 +4142,14 @@ class NestingNodeContext::Private : public PropertyMapper return TemplateVariant(FALSE); } } + TemplateVariant file() const + { + return FALSE; + } + TemplateVariant dir() const + { + return FALSE; + } TemplateVariant level() const { return m_level; diff --git a/src/template.cpp b/src/template.cpp index 71d208f9f12..da4ff6ab1df 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -2169,6 +2169,176 @@ class TemplateNodeRepeat : public TemplateNodeCreator //---------------------------------------------------------- +/** @brief Class representing a 'range' tag in a template */ +class TemplateNodeRange : public TemplateNodeCreator +{ + public: + TemplateNodeRange(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data) + : TemplateNodeCreator(parser,parent,line) + { + TRACE(("{TemplateNodeRange(%s)\n",data.data())); + QCString start,end; + int i1 = data.find(" from "); + int i2 = data.find(" to "); + int i3 = data.find(" downto "); + if (i1==-1) + { + if (data.right(5)==" from") + { + parser->warn(m_templateName,line,"range missing after 'from' keyword"); + } + else if (data=="from") + { + parser->warn(m_templateName,line,"range needs an iterator variable and a range"); + } + else + { + parser->warn(m_templateName,line,"range is missing 'from' keyword"); + } + } + else if (i2==-1 && i3==-1) + { + if (data.right(3)==" to") + { + parser->warn(m_templateName,line,"range is missing end value after 'to' keyword"); + } + else if (data.right(7)==" downto") + { + parser->warn(m_templateName,line,"range is missing end value after 'downto' keyword"); + } + else + { + parser->warn(m_templateName,line,"range is missing 'to' or 'downto' keyword"); + } + } + else + { + m_var = data.left(i1).stripWhiteSpace(); + if (m_var.isEmpty()) + { + parser->warn(m_templateName,line,"range needs an iterator variable"); + } + start = data.mid(i1+6,i2-i1-6).stripWhiteSpace(); + if (i2!=-1) + { + end = data.right(data.length()-i2-4).stripWhiteSpace(); + m_down = FALSE; + } + else if (i3!=-1) + { + end = data.right(data.length()-i3-8).stripWhiteSpace(); + m_down = TRUE; + } + } + ExpressionParser expParser(parser,line); + m_startExpr = expParser.parse(start); + m_endExpr = expParser.parse(end); + + QStrList stopAt; + stopAt.append("endrange"); + parser->parse(this,line,stopAt,m_loopNodes); + parser->removeNextToken(); // skip over endrange + TRACE(("}TemplateNodeRange(%s)\n",data.data())); + } + + ~TemplateNodeRange() + { + delete m_startExpr; + delete m_endExpr; + } + + void render(FTextStream &ts, TemplateContext *c) + { + TemplateContextImpl* ci = dynamic_cast(c); + ci->setLocation(m_templateName,m_line); + //printf("TemplateNodeRange::render #loopNodes=%d\n", + // m_loopNodes.count()); + if (m_startExpr && m_endExpr) + { + TemplateVariant vs = m_startExpr->resolve(c); + TemplateVariant ve = m_endExpr->resolve(c); + if (vs.type()==TemplateVariant::Integer && ve.type()==TemplateVariant::Integer) + { + int s = vs.toInt(); + int e = ve.toInt(); + int l = m_down ? s-e+1 : e-s+1; + if (l>0) + { + c->push(); + //int index = m_reversed ? list.count() : 0; + TemplateVariant v; + const TemplateVariant *parentLoop = c->getRef("forloop"); + uint index = 0; + int i = m_down ? e : s; + bool done=false; + while (!done) + { + // set the forloop meta-data variable + TemplateStruct s; + s.set("counter0", (int)index); + s.set("counter", (int)(index+1)); + s.set("revcounter", (int)(l-index)); + s.set("revcounter0", (int)(l-index-1)); + s.set("first",index==0); + s.set("last", (int)index==l-1); + s.set("parentloop",parentLoop ? *parentLoop : TemplateVariant()); + c->set("forloop",&s); + + // set the iterator variable + c->set(m_var,i); + + // render all items for this iteration of the loop + m_loopNodes.render(ts,c); + + index++; + if (m_down) + { + i--; + done = ie; + } + } + c->pop(); + } + else + { + ci->warn(m_templateName,m_line,"range %d %s %d is empty!", + s,m_down?"downto":"to",e); + } + } + else if (vs.type()!=TemplateVariant::Integer) + { + ci->warn(m_templateName,m_line,"range requires a start value of integer type!"); + } + else if (ve.type()!=TemplateVariant::Integer) + { + ci->warn(m_templateName,m_line,"range requires an end value of integer type!"); + } + } + else if (!m_startExpr) + { + ci->warn(m_templateName,m_line,"range has empty start value"); + } + else if (!m_endExpr) + { + ci->warn(m_templateName,m_line,"range has empty end value"); + } + } + + private: + bool m_down; + ExprAst *m_startExpr; + ExprAst *m_endExpr; + QCString m_var; + TemplateNodeList m_loopNodes; +}; + +//---------------------------------------------------------- + /** @brief Class representing a 'for' tag in a template */ class TemplateNodeFor : public TemplateNodeCreator { @@ -3141,6 +3311,7 @@ static TemplateNodeFactory::AutoRegister autoRefTree("rec static TemplateNodeFactory::AutoRegister autoRefWith("with"); static TemplateNodeFactory::AutoRegister autoRefBlock("block"); static TemplateNodeFactory::AutoRegister autoRefCycle("cycle"); +static TemplateNodeFactory::AutoRegister autoRefRange("range"); static TemplateNodeFactory::AutoRegister autoRefExtend("extend"); static TemplateNodeFactory::AutoRegister autoRefCreate("create"); static TemplateNodeFactory::AutoRegister autoRefRepeat("repeat"); @@ -3515,7 +3686,8 @@ void TemplateParser::parse( command=="endblock" || command=="endwith" || command=="endrecursetree" || command=="endspaceless" || command=="endmarkers" || command=="endmsg" || - command=="endrepeat" || command=="elif") + command=="endrepeat" || command=="elif" || + command=="endrange") { warn(m_templateName,tok->line,"Found tag '%s' without matching start tag",command.data()); }