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

Merge branch 'template'

parents bfc2c287 12cd22f4
Loading
Loading
Loading
Loading
+269 −13
Original line number Original line Diff line number Diff line
@@ -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
    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
    { 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
    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
    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


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,...
  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>
    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
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");


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


+3 −3
Original line number Original line Diff line number Diff line
@@ -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
 *  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
{
{