1 package parser
2
3 import (
4 "fmt"
5
6 log "github.com/sirupsen/logrus"
7
8 "github.com/pkg/errors"
9
10 "github.com/noirbizarre/gonja/nodes"
11 "github.com/noirbizarre/gonja/tokens"
12 )
13
14 type StatementParser func(parser *Parser, args *Parser) (nodes.Statement, error)
15
16
17 func (p *Parser) ParseStatement() (nodes.Statement, error) {
18 log.WithFields(log.Fields{
19 "current": p.Current(),
20 }).Trace("ParseStatement")
21
22 if p.Match(tokens.BlockBegin) == nil {
23 return nil, p.Error("'{%' expected here", p.Current())
24 }
25
26 name := p.Match(tokens.Name)
27 if name == nil {
28 return nil, p.Error("Expected a statement name here", p.Current())
29 }
30
31
32 stmtParser, exists := p.Statements[name.Val]
33 if !exists {
34
35 return nil, p.Error(fmt.Sprintf("Statement '%s' not found (or beginning not provided)", name.Val), name)
36 }
37
38
39
40
41
42
43 var args []*tokens.Token
44 for p.Peek(tokens.BlockEnd) == nil && !p.Stream.End() {
45
46 args = append(args, p.Next())
47
48 }
49
50
51
52
53
54
55 if p.Match(tokens.BlockEnd) == nil {
56 return nil, p.Error(fmt.Sprintf(`Expected end of block "%s"`, p.Config.BlockEndString), p.Current())
57 }
58
59 argParser := NewParser("statement", p.Config, tokens.NewStream(args))
60
61
62
63
64
65
66 p.Level++
67 defer func() { p.Level-- }()
68 return stmtParser(p, argParser)
69 }
70
71
72
73 func (p *Parser) ParseStatementBlock() (*nodes.StatementBlock, error) {
74 log.WithFields(log.Fields{
75 "current": p.Current(),
76 }).Trace("ParseStatementBlock")
77
78 begin := p.Match(tokens.BlockBegin)
79 if begin == nil {
80 return nil, errors.Errorf(`Expected "%s" got "%s"`, p.Config.BlockStartString, p.Current())
81 }
82
83 name := p.Match(tokens.Name)
84 if name == nil {
85 return nil, p.Error("Expected a statement name here", p.Current())
86 }
87
88
89 stmtParser, exists := p.Statements[name.Val]
90 if !exists {
91
92 return nil, p.Error(fmt.Sprintf("Statement '%s' not found (or beginning not provided)", name.Val), name)
93 }
94
95
96
97
98
99
100 log.Trace("args")
101 var args []*tokens.Token
102 for p.Peek(tokens.BlockEnd) == nil && !p.Stream.End() {
103 log.Trace("for args")
104
105 args = append(args, p.Next())
106
107 }
108 log.Trace("loop ended")
109
110
111
112
113
114
115 end := p.Match(tokens.BlockEnd)
116 if end == nil {
117 return nil, p.Error(fmt.Sprintf(`Expected end of block "%s"`, p.Config.BlockEndString), p.Current())
118 }
119 log.WithFields(log.Fields{
120 "args": args,
121 }).Trace("Matched end block")
122
123 stream := tokens.NewStream(args)
124 log.WithFields(log.Fields{
125 "stream": stream,
126 }).Trace("Got stream")
127 argParser := NewParser(fmt.Sprintf("%s:args", name.Val), p.Config, stream)
128 log.Trace("argparser")
129
130
131
132
133
134
135
136
137 stmt, err := stmtParser(p, argParser)
138 if err != nil {
139 return nil, errors.Wrapf(err, `Unable to parse statement "%s"`, name.Val)
140 }
141 log.Trace("got stmt and return")
142 return &nodes.StatementBlock{
143 Location: begin,
144 Name: name.Val,
145 Stmt: stmt,
146 LStrip: begin.Val[len(begin.Val)-1] == '+',
147 Trim: &nodes.Trim{
148 Left: begin.Val[len(begin.Val)-1] == '-',
149 Right: end.Val[0] == '-',
150 },
151 }, nil
152 }
153
View as plain text