Commit b98846d0 authored by Dimitri van Heesch's avatar Dimitri van Heesch
Browse files

Added support for range tag in the template language

parent 9434ecb1
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -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;
+173 −1
Original line number Diff line number Diff line
@@ -2169,6 +2169,176 @@ class TemplateNodeRepeat : public TemplateNodeCreator<TemplateNodeRepeat>

//----------------------------------------------------------

/** @brief Class representing a 'range' tag in a template */
class TemplateNodeRange : public TemplateNodeCreator<TemplateNodeRange>
{
  public:
    TemplateNodeRange(TemplateParser *parser,TemplateNode *parent,int line,const QCString &data)
      : TemplateNodeCreator<TemplateNodeRange>(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<TemplateContextImpl*>(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 = i<e;
              }
              else
              {
                i++;
                done = i>e;
              }
            }
            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<TemplateNodeFor>
{
@@ -3141,6 +3311,7 @@ static TemplateNodeFactory::AutoRegister<TemplateNodeTree> autoRefTree("rec
static TemplateNodeFactory::AutoRegister<TemplateNodeWith>      autoRefWith("with");
static TemplateNodeFactory::AutoRegister<TemplateNodeBlock>     autoRefBlock("block");
static TemplateNodeFactory::AutoRegister<TemplateNodeCycle>     autoRefCycle("cycle");
static TemplateNodeFactory::AutoRegister<TemplateNodeRange>     autoRefRange("range");
static TemplateNodeFactory::AutoRegister<TemplateNodeExtend>    autoRefExtend("extend");
static TemplateNodeFactory::AutoRegister<TemplateNodeCreate>    autoRefCreate("create");
static TemplateNodeFactory::AutoRegister<TemplateNodeRepeat>    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());
          }