...
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
46
47
48
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
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
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
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
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