...

Source file src/github.com/noirbizarre/gonja/ext/django/statements/cycle.go

Documentation: github.com/noirbizarre/gonja/ext/django/statements

     1  package statements
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/noirbizarre/gonja/exec"
     7  	"github.com/noirbizarre/gonja/nodes"
     8  	"github.com/noirbizarre/gonja/parser"
     9  	"github.com/noirbizarre/gonja/tokens"
    10  )
    11  
    12  type cycleValue struct {
    13  	node  *CycleStatement
    14  	value *exec.Value
    15  }
    16  
    17  type CycleStatement struct {
    18  	position *tokens.Token
    19  	args     []nodes.Expression
    20  	idx      int
    21  	asName   string
    22  	silent   bool
    23  }
    24  
    25  func (stmt *CycleStatement) Position() *tokens.Token { return stmt.position }
    26  func (stmt *CycleStatement) String() string {
    27  	t := stmt.Position()
    28  	return fmt.Sprintf("CycleStmt(Line=%d Col=%d)", t.Line, t.Col)
    29  }
    30  
    31  func (cv *cycleValue) String() string {
    32  	return cv.value.String()
    33  }
    34  
    35  func (stmt *CycleStatement) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
    36  	item := stmt.args[stmt.idx%len(stmt.args)]
    37  	stmt.idx++
    38  
    39  	val := r.Eval(item)
    40  	if val.IsError() {
    41  		return val
    42  	}
    43  
    44  	if t, ok := val.Interface().(*cycleValue); ok {
    45  		// {% cycle "test1" "test2"
    46  		// {% cycle cycleitem %}
    47  
    48  		// Update the cycle value with next value
    49  		item := t.node.args[t.node.idx%len(t.node.args)]
    50  		t.node.idx++
    51  
    52  		val := r.Eval(item)
    53  		if val.IsError() {
    54  			return val
    55  		}
    56  
    57  		t.value = val
    58  
    59  		if !t.node.silent {
    60  			r.WriteString(val.String())
    61  		}
    62  	} else {
    63  		// Regular call
    64  
    65  		cycleValue := &cycleValue{
    66  			node:  stmt,
    67  			value: val,
    68  		}
    69  
    70  		if stmt.asName != "" {
    71  			r.Ctx.Set(stmt.asName, cycleValue)
    72  		}
    73  		if !stmt.silent {
    74  			r.WriteString(val.String())
    75  		}
    76  	}
    77  
    78  	return nil
    79  }
    80  
    81  // HINT: We're not supporting the old comma-separated list of expressions argument-style
    82  func cycleParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
    83  	cycleNode := &CycleStatement{
    84  		position: p.Current(),
    85  	}
    86  
    87  	for !args.End() {
    88  		node, err := args.ParseExpression()
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  		cycleNode.args = append(cycleNode.args, node)
    93  
    94  		if args.MatchName("as") != nil {
    95  			// as
    96  
    97  			name := args.Match(tokens.Name)
    98  			if name == nil {
    99  				return nil, args.Error("Name (identifier) expected after 'as'.", nil)
   100  			}
   101  			cycleNode.asName = name.Val
   102  
   103  			if args.MatchName("silent") != nil {
   104  				cycleNode.silent = true
   105  			}
   106  
   107  			// Now we're finished
   108  			break
   109  		}
   110  	}
   111  
   112  	if !args.End() {
   113  		return nil, args.Error("Malformed cycle-tag.", nil)
   114  	}
   115  
   116  	return cycleNode, nil
   117  }
   118  
   119  func init() {
   120  	All.Register("cycle", cycleParser)
   121  }
   122  

View as plain text