...
1 package parser
2
3 import (
4 "fmt"
5 "strings"
6
7 "github.com/noirbizarre/gonja/config"
8 "github.com/noirbizarre/gonja/nodes"
9 "github.com/noirbizarre/gonja/tokens"
10 )
11
12
13
14
15
16
17
18
19
20
21 type Parser struct {
22 Name string
23 Stream *tokens.Stream
24 Config *config.Config
25
26 Template *nodes.Template
27 Statements map[string]StatementParser
28 Level int8
29 TemplateParser TemplateParser
30 }
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 func NewParser(name string, cfg *config.Config, stream *tokens.Stream) *Parser {
50 return &Parser{
51 Name: name,
52 Stream: stream,
53 Config: cfg,
54 }
55 }
56
57 func Parse(input string) (*nodes.Template, error) {
58 stream := tokens.Lex(input)
59 p := NewParser("parser", config.DefaultConfig, stream)
60 return p.Parse()
61 }
62
63 func (p *Parser) Parse() (*nodes.Template, error) {
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 return p.ParseTemplate()
81 }
82
83
84 func (p *Parser) Consume() {
85 p.Stream.Next()
86 }
87
88
89
90
91
92
93
94 func (p *Parser) Current() *tokens.Token {
95 return p.Stream.Current()
96 }
97
98
99 func (p *Parser) Next() *tokens.Token {
100
101
102
103 return p.Stream.Next()
104 }
105
106 func (p *Parser) End() bool {
107 return p.Stream.End()
108 }
109
110
111
112 func (p *Parser) Match(types ...tokens.Type) *tokens.Token {
113 tok := p.Stream.Current()
114 for _, t := range types {
115 if tok.Type == t {
116 p.Stream.Next()
117 return tok
118 }
119 }
120 return nil
121 }
122
123 func (p *Parser) MatchName(names ...string) *tokens.Token {
124 t := p.Peek(tokens.Name)
125 if t != nil {
126 for _, name := range names {
127 if t.Val == name {
128 return p.Pop()
129 }
130 }
131 }
132
133 return nil
134 }
135
136
137 func (p *Parser) Pop() *tokens.Token {
138 t := p.Stream.Current()
139 p.Stream.Next()
140 return t
141 }
142
143
144
145 func (p *Parser) Peek(types ...tokens.Type) *tokens.Token {
146 tok := p.Stream.Current()
147 for _, t := range types {
148 if tok.Type == t {
149 return tok
150 }
151 }
152 return nil
153 }
154
155 func (p *Parser) PeekName(names ...string) *tokens.Token {
156 t := p.Peek(tokens.Name)
157 if t != nil {
158 for _, name := range names {
159 if t.Val == name {
160 return t
161 }
162 }
163 }
164
165 return nil
166 }
167
168
169
170
171 func (p *Parser) WrapUntil(names ...string) (*nodes.Wrapper, *Parser, error) {
172 wrapper := &nodes.Wrapper{
173 Location: p.Current(),
174 Trim: &nodes.Trim{},
175 }
176
177 var args []*tokens.Token
178
179 for !p.Stream.End() {
180
181 if begin := p.Match(tokens.BlockBegin); begin != nil {
182 ident := p.Peek(tokens.Name)
183
184 if ident != nil {
185
186
187 found := false
188 for _, n := range names {
189 if ident.Val == n {
190 found = true
191 break
192 }
193 }
194
195
196 if found {
197
198 p.Consume()
199 wrapper.Trim.Left = begin.Val[len(begin.Val)-1] == '-'
200 wrapper.LStrip = begin.Val[len(begin.Val)-1] == '+'
201
202 for {
203 if end := p.Match(tokens.BlockEnd); end != nil {
204
205 wrapper.EndTag = ident.Val
206 wrapper.Trim.Right = end.Val[0] == '-'
207 stream := tokens.NewStream(args)
208 return wrapper, NewParser(p.Name, p.Config, stream), nil
209 }
210 t := p.Next()
211
212 if t == nil {
213 return nil, nil, p.Error("Unexpected EOF.", p.Current())
214 }
215 args = append(args, t)
216 }
217 }
218 }
219 p.Stream.Backup()
220 }
221
222
223 node, err := p.parseDocElement()
224 if err != nil {
225 return nil, nil, err
226 }
227 wrapper.Nodes = append(wrapper.Nodes, node)
228 }
229
230 return nil, nil, p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")),
231 p.Current())
232 }
233
234
235 func (p *Parser) SkipUntil(names ...string) error {
236 for !p.End() {
237
238 if p.Match(tokens.BlockBegin) != nil {
239 ident := p.Peek(tokens.Name)
240
241 if ident != nil {
242
243
244 found := false
245 for _, n := range names {
246 if ident.Val == n {
247 found = true
248 break
249 }
250 }
251
252
253 if found {
254
255 p.Consume()
256
257 for {
258 if p.Match(tokens.BlockEnd) != nil {
259
260 return nil
261 }
262 }
263 }
264 } else {
265 p.Stream.Backup()
266 }
267 }
268 t := p.Next()
269 if t == nil {
270 return p.Error("Unexpected EOF.", p.Current())
271 }
272 }
273
274 return p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")), p.Current())
275 }
276
View as plain text