Add recursive loop to support tree-like structures
authorteodor <teodor>
Fri, 3 Oct 2008 22:57:17 +0000 (22:57 +0000)
committerteodor <teodor>
Fri, 3 Oct 2008 22:57:17 +0000 (22:57 +0000)
data/template.tmpl
expected/tmpl
template.c
template.h
tmpl_gram.y
tmpl_scan.l
tmpltest.c

index 95e0060..7a2db76 100644 (file)
@@ -58,9 +58,8 @@ str ? "yes" : -1 = <% str ? "yes" : -1 %>
        <@ENDIF@>
 <@ENDIF@>
 
-
 <@ LOOP outerLoop @>
-       <% __COUNTER %>/<% __SIZE %>. odd:<% __ODD %> even:<% __EVEN %> <# <@if __FIRST @>FIRST<@endif@> <@if __LAST @>LAST<@endif@> id: <% ^ID %> <% DATA1 %>:<% DATA2 # "Data is absent" %>/<% DATA1 %> #>
+       <% __COUNTER %>/<% __SIZE %>. odd:<% __ODD %> even:<% __EVEN %>
        
        <& data/template_include.tmpl &>
        <@ LOOP innerLoop @>
@@ -69,3 +68,10 @@ str ? "yes" : -1 = <% str ? "yes" : -1 %>
                <@ IF __LAST @></ol><@ ENDIF @>
        <@ ENDLOOP @>
 <@ ENDLOOP @>
+
+<@ LOOP selfLoop@>
+       <@if __FIRST @><ul><@endif@><li><% __COUNTER %> <% NODE %>#<% CNT %>
+       <@ SELF @>
+       <@ LOOP oneloop@><@if __FIRST @><ol><@endif@><li><% __COUNTER %> oneloop:<% NODE %>#<% CNT %><@if __LAST @></ol><@endif@><@ ENDLOOP @>
+       <@if __LAST @></ul><@endif@>
+<@ ENDLOOP @>
index 57095bd..21b8c27 100644 (file)
@@ -51,14 +51,13 @@ str ? "yes" : -1 = yes
 
 
 
-
-       1/3. odd:true even:false 
+       1/3. odd:true even:false
        
        FIRST  id: 17 ha1:Data is absent/ha1
 
        
 
-       2/3. odd:false even:true 
+       2/3. odd:false even:true
        
          id: 17 10:WOW/10
 
@@ -72,12 +71,14 @@ str ? "yes" : -1 = yes
                </ol>
        
 
-       3/3. odd:true even:false 
+       3/3. odd:true even:false
        
         LAST id: 17 ha3:Data is absent/ha3
 
        
 
+
+
 ================================================
 id: 23 - <i>simple</i>
 idhex: 0x00000017 - <b>HEX
@@ -131,8 +132,7 @@ str ? "yes" : -1 = -1
 
 
 
-
-       1/1. odd:true even:false 
+       1/1. odd:true even:false
        
        FIRST LAST id: 23 1234:FOO/1234
 
@@ -142,3 +142,70 @@ str ? "yes" : -1 = -1
                </ol>
        
 
+
+
+       <ul><li>1 outer#1
+       
+       <ul><li>1 inner#4
+       
+       
+       
+
+       <li>2 inner#5
+       
+       
+       </ul>
+
+       <ol><li>1 oneloop:subloop1#2<li>2 oneloop:subloop2#3</ol>
+       
+
+       <li>2 outer#6
+       
+       <ul><li>1 inner#8
+       
+       <ol><li>1 oneloop:subloop3#9</ol>
+       
+
+       <li>2 inner#10
+       
+       
+       </ul>
+
+       <ol><li>1 oneloop:subloop2#7</ol>
+       
+
+       <li>3 outer#11
+       
+       <ul><li>1 inner#12
+       
+       
+       
+
+       <li>2 inner#13
+       
+       <ul><li>1 innerst#14
+       
+       
+       
+
+       <li>2 innerst#15
+       
+       
+       
+
+       <li>3 innerst#16
+       
+       <ol><li>1 oneloop:subloop4#17</ol>
+       
+
+       <li>4 innerst#18
+       
+       
+       </ul>
+
+       
+       </ul>
+
+       
+       </ul>
+
index 45b366b..5651124 100644 (file)
@@ -389,6 +389,7 @@ findIncludes(ParseState *state, TemplateNode *node) {
                case    ConstNode:
                case    VariableNode:
                case    TextNode:
+               case    NestNode:
                        break;
                default:
                        tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", (*node)->type);
@@ -488,13 +489,7 @@ findVariable( Template tmpl, TemplateNode loopParentNode, int flags, char *varNa
                         * copy special flags to support new inform loopParentNode
                         */
                        pdata->flags |=  flags & TND__SPECIALMASK;
-
-                       if ( flags & ( TND___FIRST | TND___LAST | TND___ODD | TND___EVEN ) )
-                               pdata->type = valueBool;
-                       else if ( flags & (TND___COUNTER | TND___SIZE) )
-                               pdata->type = valueInt;
-                       else
-                               pdata->type = valuePointer;
+                       pdata->type = valuePointer;
 
                        loopParentNode->nodeData.loop.listVarValues = 
                                        GListPush( loopParentNode->nodeData.loop.listVarValues, pdata ); 
@@ -521,10 +516,15 @@ addLoop(Template tmpl, TemplateNode node, TemplateNode loopParentNode) {
 
        SFSAdd(&tmpl->variables, &in);
 
-       if ( loopParentNode ) 
+       if ( loopParentNode ) 
                loopParentNode->nodeData.loop.childrenLoop = 
                        GListPush( loopParentNode->nodeData.loop.childrenLoop, node );
 
+               if ( loopParentNode->nodeData.loop.selfNode )
+                       loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf =
+                               GListPush( loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf, node );
+       }
+
        return 0;
 }
 
@@ -567,6 +567,16 @@ compileTree( Template tmpl, TemplateNode node, TemplateNode loopParentNode ) {
                        if ( addLoop( tmpl, node, loopParentNode ) )
                                return 1;
                        break;
+               case NestNode:
+                       node->nodeData.nest.loop = loopParentNode;
+                       if ( loopParentNode ) {
+                               if ( loopParentNode->nodeData.loop.selfNode )
+                                       tlog(TL_WARN,"Loop '%s' has duplicated nested call", node->nodeData.loop.varName);
+                               else
+                                       loopParentNode->nodeData.loop.selfNode = node;
+                       } else
+                               tlog(TL_WARN,"SELF tag without loop");
+                       break;
                case ConditionNode:
                        if ( compileTree(tmpl, node->nodeData.condition.expressionNode, loopParentNode) )
                                        return 1;
@@ -709,6 +719,7 @@ freeNode( TemplateNode node ) {
        switch (node->type) {
                case    LoopNode:
                        freeNode( node->nodeData.loop.bodyNode );
+                       freeNode( node->nodeData.loop.selfNode );
                        GListFree( node->nodeData.loop.childrenLoop );
                        GListFree( node->nodeData.loop.listVarValues );
 
@@ -737,6 +748,9 @@ freeNode( TemplateNode node ) {
                                freeNode( GLCELL_DATA(cell) );
                        GListFree( node->nodeData.expression.argsNode );
                        break;
+               case    NestNode:
+                       GListFree( node->nodeData.nest.childrenLoopAfterSelf ); 
+                       break;  
                case    VariableNode:
                case    IncludeNode:
                case    TextNode:
@@ -758,19 +772,29 @@ freeTemplate( Template tmpl ) {
 
 static void
 newLoopInstance( Template tmpl, TemplateNode node ) {
+       LoopInstance    upper = NULL;
+
+       if ( node->nodeData.loop.currentInstance )
+               upper = node->nodeData.loop.currentInstance->upperInstance;
+
+       node->nodeData.loop.currentInstance = 
+                               mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
+       node->nodeData.loop.currentInstance->upperInstance = upper;
+
        node->nodeData.loop.listInstance = GListPush( 
                                node->nodeData.loop.listInstance,
-                               mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) ) ); 
+                               node->nodeData.loop.currentInstance );
+
+       node->nodeData.loop.lastRow = NULL;
 }
 
 int
-addTemplateRow( Template tmpl, char * key ) {
+addTemplateRow( Template tmpl, char * key) {
        TemplateNode    *pnode, node;
        char            *lkey = strlower(mcstrdup(tmpl->templateContext, key));
        GListCell               *cell;
-       VariableValue   varvals;
        int                             i=0, nvar;
-       LoopInstance    instance;
+       LoopRow                 rowData;
 
        pnode = SFSFindData(&tmpl->variables, lkey, 0);
        mcfree(lkey);
@@ -794,21 +818,90 @@ addTemplateRow( Template tmpl, char * key ) {
        GListForeach( cell, node->nodeData.loop.childrenLoop )
                newLoopInstance( tmpl, GLCELL_DATA(cell) );
 
-       varvals = mcalloc( tmpl->templateContext, sizeof(VariableValueData) * nvar );
+       node->nodeData.loop.lastRow = rowData = mcalloc( tmpl->templateContext, LRDHDRSZ + sizeof(VariableValueData) * nvar );
+       rowData->loop = node;
+       rowData->nestedInstance = NULL;
+
        GListForeach( cell, node->nodeData.loop.listVarValues ) {       
                VariableValue   vv = GLCELL_DATA(cell);
 
-               vv->value.ptrValue = varvals + i;
-               varvals[i].flags = 0;
+               vv->value.ptrValue = rowData->varvals + i;
+               rowData->varvals[i].flags = 0;
                i++;
        }
 
-       instance = GLCELL_DATA(GLIST_TAIL(node->nodeData.loop.listInstance));
+       node->nodeData.loop.currentInstance->nrow++;
+       node->nodeData.loop.currentInstance->rowValues = 
+                               GListPush( node->nodeData.loop.currentInstance->rowValues, rowData );
+
+       return TVAR_OK;
+}
+
+int 
+addTemplateNestedLoop( Template tmpl, char * key) {
+       TemplateNode    *pnode, node;
+       char            *lkey = strlower(mcstrdup(tmpl->templateContext, key));
+       GListCell               *cell;
+
+       pnode = SFSFindData(&tmpl->variables, lkey, 0);
+       mcfree(lkey);
+
+       if ( pnode == NULL )
+               return TVAR_NOTFOUND;
+
+       node = *pnode;
+
+       if ( node->type != LoopNode || node->nodeData.loop.selfNode == 0 )
+               return TVAR_FORBIDDEN;
+
+       if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 || node->nodeData.loop.lastRow == NULL )
+               return TVAR_NOROW;
+
+       GListForeach( cell, node->nodeData.loop.childrenLoop )
+               ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.lastRow = NULL;        
+
+       node->nodeData.loop.lastRow->nestedInstance = 
+                               mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
+       node->nodeData.loop.lastRow->nestedInstance->upperInstance = 
+                               node->nodeData.loop.currentInstance;
+       node->nodeData.loop.currentInstance =  
+                               node->nodeData.loop.lastRow->nestedInstance;
+       node->nodeData.loop.lastRow = NULL;
+
+       return TVAR_OK;
+}
+
+int
+returnTemplateNestedLoop( Template tmpl, char * key) {
+       TemplateNode    *pnode, node;
+       char            *lkey = strlower(mcstrdup(tmpl->templateContext, key));
+       GListCell               *cell;
+
+       pnode = SFSFindData(&tmpl->variables, lkey, 0);
+       mcfree(lkey);
+
+       if ( pnode == NULL )
+               return TVAR_NOTFOUND;
 
-       instance->nrow++;
-       instance->rowValues = GListPush( instance->rowValues, varvals );
+       node = *pnode;
+
+       if ( node->type != LoopNode || node->nodeData.loop.selfNode == 0 )
+               return TVAR_FORBIDDEN;
+
+       if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 )
+               return TVAR_NOROW;
+
+       if ( node->nodeData.loop.currentInstance == NULL )
+               return TVAR_NOROW;
+
+       GListForeach( cell, node->nodeData.loop.childrenLoop )
+               ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.lastRow = NULL;        
+
+       node->nodeData.loop.currentInstance = node->nodeData.loop.currentInstance->upperInstance; 
+       node->nodeData.loop.lastRow = NULL;
 
        return TVAR_OK;
+
 }
 
 static VariableValueData storage;
@@ -1004,6 +1097,7 @@ executeExpression( Template tmpl, TemplateNode node ) {
                case ConditionNode:
                case CollectionNode:
                case PrintNode:
+               case NestNode:
                        tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type); 
                        break;
                default:
@@ -1017,9 +1111,10 @@ executeExpression( Template tmpl, TemplateNode node ) {
 }
 
 static void
-printNode( Template tmpl, TemplateNode node ) {
-       GListCell   *cell;
+printNode( Template tmpl, TemplateNode node, LoopInstance loopInstance ) {
+       GListCell       *cell;
        VariableValue   value;
+       int                             i;
 
        if (!node)
                return;
@@ -1027,79 +1122,143 @@ printNode( Template tmpl, TemplateNode node ) {
        switch (node->type) {
                case    LoopNode:
                        {
-                               GListCell               *cell = GListShift( node->nodeData.loop.listInstance );
+                               GListCell               *cell;
                                LoopInstance    instance;
-                               int                             i;
 
-                               if ( cell == NULL )
-                                       return;
+                               if ( loopInstance ) {
+                                       instance = loopInstance;
+                               } else {
+                                       cell = GListShift( node->nodeData.loop.listInstance );
+                                       if ( cell == NULL )
+                                               return;
 
-                               instance = GLCELL_DATA(cell);
-                               GListFreeCell( node->nodeData.loop.listInstance, cell );
+                                       instance = GLCELL_DATA(cell);
+                                       GListFreeCell( node->nodeData.loop.listInstance, cell );
+                               }
 
                                for(i=0; i<instance->nrow;i++) {
-                                       VariableValue   varvals;
+                                       LoopRow                 rowData;
                                        int                             j = 0;
+                                       VariableValue   realValue;
 
                                        cell = GListShift( instance->rowValues );
-                                       varvals = GLCELL_DATA(cell);
+                                       rowData = GLCELL_DATA(cell);
                                        GListFreeCell( instance->rowValues, cell );
 
                                        GListForeach( cell, node->nodeData.loop.listVarValues ) {
                                                value = (VariableValue)GLCELL_DATA(cell);
                                
+                                               tassert( value->type == valuePointer );
+                                               realValue = value->value.ptrValue = rowData->varvals+j;
+
                                                if ( value->flags & TND___FIRST ) {
+                                                       realValue->type = valueInt;
                                                        if ( i==0 ) {
-                                                               value->flags |= TND_DEFINED;
-                                                               value->value.intValue = 1; 
+                                                               realValue->flags |= TND_DEFINED;
+                                                               realValue->value.intValue = 1; 
                                                        }  else {
-                                                               value->flags &= ~TND_DEFINED;
-                                                               value->value.intValue = 0;
+                                                               realValue->flags &= ~TND_DEFINED;
+                                                               realValue->value.intValue = 0;
                                                        }
                                                } else if ( value->flags & TND___LAST ) {
+                                                       realValue->type = valueInt;
                                                        if ( i==instance->nrow - 1 ) {
-                                                               value->flags |= TND_DEFINED;
-                                                               value->value.intValue = 1; 
+                                                               realValue->flags |= TND_DEFINED;
+                                                               realValue->value.intValue = 1; 
                                                        }  else {
-                                                               value->flags &= ~TND_DEFINED;
-                                                               value->value.intValue = 0;
+                                                               realValue->flags &= ~TND_DEFINED;
+                                                               realValue->value.intValue = 0;
                                                        }
                                                } else if ( value->flags & TND___COUNTER ) {
-                                                       value->flags |= TND_DEFINED;
-                                                       value->value.intValue = i+1;
+                                                       realValue->type = valueInt;
+                                                       realValue->flags |= TND_DEFINED;
+                                                       realValue->value.intValue = i+1;
                                                } else if ( value->flags & TND___SIZE ) {
-                                                       value->flags |= TND_DEFINED;
-                                                       value->value.intValue = instance->nrow;
+                                                       realValue->type = valueInt;
+                                                       realValue->flags |= TND_DEFINED;
+                                                       realValue->value.intValue = instance->nrow;
                                                } else if ( value->flags & TND___ODD ) {
-                                                       value->flags |= TND_DEFINED;
-                                                       value->value.boolValue = (i%2) ? 0 : 1 ;
+                                                       realValue->type = valueBool;
+                                                       realValue->flags |= TND_DEFINED;
+                                                       realValue->value.boolValue = (i%2) ? 0 : 1 ;
                                                } else if ( value->flags & TND___EVEN ) {
-                                                       value->flags |= TND_DEFINED;
-                                                       value->value.boolValue = (i%2) ? 1 : 0 ;
-                                               } else {
-                                                       tassert( value->type == valuePointer );
-                                                       value->value.ptrValue = varvals+j;
+                                                       realValue->type = valueBool;
+                                                       realValue->flags |= TND_DEFINED;
+                                                       realValue->value.boolValue = (i%2) ? 1 : 0 ;
                                                }
 
                                                j++;
                                        }
-                                       printNode( tmpl, node->nodeData.loop.bodyNode );
+
+                                       if ( node->nodeData.loop.selfNode ) 
+                                               node->nodeData.loop.selfNode->nodeData.nest.savedRowData = rowData;
+
+                                       printNode( tmpl, node->nodeData.loop.bodyNode, NULL );
                                }
 
                                GListFree( instance->rowValues );
                        }
                        break;
+               case    NestNode:
+                       if ( node->nodeData.nest.loop && node->nodeData.nest.savedRowData ) {
+                               LoopRow                 savedRowData = node->nodeData.nest.savedRowData; /* save current row */
+                               LoopInstance    *savedChildrenInstance = NULL;
+
+                               /*
+                                *   Save child's instances for current loop
+                                */
+                               if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
+                                       savedChildrenInstance = mcalloc(tmpl->templateContext, sizeof(LoopInstance) * 
+                                                                                                       GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf));
+
+                                       i=0;
+                                       GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
+                                               TemplateNode    chld = GLCELL_DATA(cell);
+                                               GListCell               *cellInstance = GListShift( chld->nodeData.loop.listInstance );
+
+                                               if ( cellInstance == NULL )
+                                                       savedChildrenInstance[i++] = NULL;
+                                               else {
+                                                       savedChildrenInstance[i++] = GLCELL_DATA(cellInstance);
+                                                       GListFreeCell( chld->nodeData.loop.listInstance, cellInstance );
+                                               }
+                                       }
+                               }
+
+                               printNode( tmpl, node->nodeData.nest.loop, savedRowData->nestedInstance );
+
+                               /*
+                                * Restore saved datas
+                                */
+                               i=0;
+                               GListForeach( cell, node->nodeData.nest.loop->nodeData.loop.listVarValues ) {
+                                       ((VariableValue)GLCELL_DATA(cell))->value.ptrValue = savedRowData->varvals + i;
+                                       i++;
+                               }
+
+                               if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
+                                       i=0;
+                                       GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
+                                               TemplateNode    chld = GLCELL_DATA(cell);
+
+                                               if ( savedChildrenInstance[i] )
+                                                       GListUnshift( chld->nodeData.loop.listInstance, savedChildrenInstance[i]);
+                                               i++;
+                                       }
+                               }
+                       }
+                       break;
                case    ConditionNode:
                        value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
 
                        if ( isVariable(value) ) 
-                               printNode( tmpl, node->nodeData.condition.ifNode );
+                               printNode( tmpl, node->nodeData.condition.ifNode, loopInstance );
                        else
-                               printNode( tmpl, node->nodeData.condition.elseNode );
+                               printNode( tmpl, node->nodeData.condition.elseNode, loopInstance );
                        break;
                case    CollectionNode:
                        GListForeach( cell, node->nodeData.children ) 
-                               printNode( tmpl, (TemplateNode)GLCELL_DATA(cell) );
+                               printNode( tmpl, (TemplateNode)GLCELL_DATA(cell), loopInstance );
                        break;
                case    PrintNode:
                        value = executeExpression( tmpl, node->nodeData.condition.expressionNode ); 
@@ -1144,7 +1303,7 @@ printTemplate( Template tmpl ) {
        if (!tmpl->printString)
                return 1;
 
-       printNode(tmpl, tmpl->tree);
+       printNode(tmpl, tmpl->tree, NULL);
 
        return 0;
 }
@@ -1201,6 +1360,9 @@ recursiveDump(Template tmpl,  TemplateNode node, int level) {
                case    ConstNode:
                        printf("ConstNode\n");
                        break;
+               case    NestNode:
+                       printf("NestNode\n");
+                       break;
                default:
                        tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
        }
index 9061e30..6f88989 100644 (file)
@@ -63,6 +63,7 @@
  *      C-level.
  *
  * <@LOOP MARKNAME@>
+ *             <@ SELF @>
  * <@ENDLOOP@>
  * Loop has predefined variables:
  *    __FIRST   - true for first iteration
@@ -135,6 +136,7 @@ typedef     enum TemplateNodeType {
        ExpressionNode,
        PrintNode,
        ConstNode,
+       NestNode,
 
        /* value's types of variables */
        valueInt = 200, /* smallest of any values type */
@@ -188,9 +190,20 @@ typedef struct executeFunctionDescData {
 } executeFunctionDescData;
 
 typedef struct LoopInstanceData * LoopInstance;
+
+typedef struct LoopRowData *LoopRow;
+
+typedef struct LoopRowData {
+       TemplateNode            loop;
+       LoopInstance            nestedInstance;
+       VariableValueData       varvals[1];
+} LoopRowData;
+#define LRDHDRSZ       (offsetof(LoopRowData, varvals))
+
 typedef struct LoopInstanceData {
        int                             nrow;
-       GList                   *rowValues;
+       LoopInstance    upperInstance;
+       GList                   *rowValues; /*list of LoopRow */
 } LoopInstanceData;
 
 typedef struct  TemplateNodeData {
@@ -234,14 +247,31 @@ typedef struct  TemplateNodeData {
                /* IncludeNode */
                char    *includeFile;
 
+               /* NestNode */
+               struct {
+                       TemplateNode    loop;
+                       LoopRow                 savedRowData;
+                       GList                   *childrenLoopAfterSelf;
+               } nest;
+
                /* LoopNode */
                struct {
                        char                    *varName;
                        int                     varNameLength;
                        TemplateNode    bodyNode;
+                       TemplateNode    selfNode;
                        GList                   *childrenLoop;  /* to reset loop's instance  */
                        GList                   *listVarValues; /* list of loop variables */
                        GList                   *listInstance;
+                       /*      listInstace -+
+                                                        +->instance-+
+                                                                                +->row
+                                                                                |
+                                                                                |
+                                                                                +->row->nestedinstance
+                        */
+                       LoopRow                 lastRow;
+                       LoopInstance    currentInstance;                
                } loop;
 
                /* ConditionNode */
@@ -292,6 +322,7 @@ int setTemplateValueBool( Template tmpl, char * key, int val );
 int setTemplateValueUndefined( Template tmpl, char * key );
 int setTemplateValueDouble( Template tmpl, char * key, double val );
 int addTemplateRow( Template tmpl, char * key );
-
+int addTemplateNestedLoop( Template tmpl, char * key);
+int returnTemplateNestedLoop( Template tmpl, char * key);
 void dumpTemplate( Template tmpl );
 #endif
index 3335903..9bc2f71 100644 (file)
@@ -49,7 +49,7 @@ static GList *makeList2(void *a, void *b);
 %token <str>                   LEXEME
 %token <str>                   VAR_OPEN VAR_CLOSE EXPR_OPEN EXPR_CLOSE 
                                                INCLUDE_OPEN INCLUDE_CLOSE
-%token <str>                   HTMLESCAPE URLESCAPE IF_P ELSE_P LOOP_P ENDIF_P ENDLOOP_P 
+%token <str>                   HTMLESCAPE URLESCAPE IF_P ELSE_P LOOP_P ENDIF_P ENDLOOP_P SELF_P 
 %token         <str>                   CMP_P
 
 %token <intval>                        INTEGER
@@ -225,6 +225,10 @@ node:
                                $$->type = IncludeNode;
                                $$->nodeData.includeFile = $2;
                        }
+       | EXPR_OPEN     SELF_P EXPR_CLOSE {
+                               $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
+                               $$->type = NestNode;
+                       }
        | EXPR_OPEN     LOOP_P varname EXPR_CLOSE listnodes EXPR_OPEN ENDLOOP_P EXPR_CLOSE {
                                $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
                                $$->type = LoopNode;
index 318736c..5024589 100644 (file)
@@ -205,6 +205,7 @@ static KeyWord keywords[] = {
        { "IF",                 0,      IF_P            },
        { "ELSE",               0,      ELSE_P          },
        { "LOOP",               0,      LOOP_P          },
+       { "SELF",               0,      SELF_P          },
        { "ENDIF",              0,      ENDIF_P         },
        { "ENDLOOP",    0,      ENDLOOP_P       } 
 };
index c5aef19..a605f0b 100644 (file)
@@ -75,7 +75,8 @@ main(int argn, char *argv[]) {
        MemoryContext   *base;
        char                    *name = NULL;
        TemplateData    template;
-       int                     i;
+       int                     i,j,k;
+       int                             cnt=0;
        executeFunctionDescData funcs[] = {
                {"callcounter", 0, localCounter},
                {NULL,0,NULL}
@@ -142,9 +143,57 @@ main(int argn, char *argv[]) {
        addTemplateRow(&template, "outerLoop.innerLoop");
                setTemplateValueString(&template, "outerLoop.innerLoop.camenty", "Again 1");
 
+       for(i=0;i<3;i++) {
+               addTemplateRow(&template,"selfLoop");
+               setTemplateValueInt(&template, "selfLoop.CNT", ++cnt);
+               setTemplateValueString(&template, "selfLoop.NODE", "outer");
+
+               if (i<1) {
+                       addTemplateRow(&template,"selfLoop.oneloop");
+                       setTemplateValueInt(&template, "selfLoop.oneloop.CNT", ++cnt);
+                       setTemplateValueString(&template, "selfLoop.oneloop.NODE", "subloop1");
+               }
+               if (i<2) {
+                       addTemplateRow(&template,"selfLoop.oneloop");
+                       setTemplateValueInt(&template, "selfLoop.oneloop.CNT", ++cnt);
+                       setTemplateValueString(&template, "selfLoop.oneloop.NODE", "subloop2");
+               }
+
+               addTemplateNestedLoop(&template, "selfLoop");
+       
+               for(j=0;j<2;j++) {
+                       addTemplateRow(&template,"selfLoop");
+                       setTemplateValueInt(&template, "selfLoop.CNT", ++cnt);
+                       setTemplateValueString(&template, "selfLoop.NODE", "inner");
+                       if ( i==1 && j==0 ) {
+                               addTemplateRow(&template,"selfLoop.oneloop");
+                               setTemplateValueInt(&template, "selfLoop.oneloop.CNT", ++cnt);
+                               setTemplateValueString(&template, "selfLoop.oneloop.NODE", "subloop3");
+                       }
+                       if (i==2 && j==1) {
+                               addTemplateNestedLoop(&template, "selfLoop");
+                               for(k=0;k<4;k++) {
+                                       addTemplateRow(&template,"selfLoop");
+                                       setTemplateValueInt(&template, "selfLoop.CNT", ++cnt);
+                                       setTemplateValueString(&template, "selfLoop.NODE", "innerst");
+                                       if ( k==2 ) {
+                                               addTemplateRow(&template,"selfLoop.oneloop");
+                                               setTemplateValueInt(&template, "selfLoop.oneloop.CNT", ++cnt);
+                                               setTemplateValueString(&template, "selfLoop.oneloop.NODE", "subloop4");
+                                       }
+                               }
+                               returnTemplateNestedLoop(&template, "selfLoop");
+                       }
+               }
+       
+
+               returnTemplateNestedLoop(&template, "selfLoop");
+       }
+
        fputs("================================================\n", stdout);
        printTemplate( &template );
 
+
        resetTemplate(&template);
        freeTemplate(&template);