1 package parser
2
3 import (
4
5 "strconv"
6 "strings"
7
8 "github.com/noirbizarre/gonja/nodes"
9 "github.com/noirbizarre/gonja/tokens"
10 log "github.com/sirupsen/logrus"
11 )
12
13 func (p *Parser) parseNumber() (nodes.Expression, error) {
14 log.WithFields(log.Fields{
15 "current": p.Current(),
16 }).Trace("parseNumber")
17 t := p.Match(tokens.Integer, tokens.Float)
18 if t == nil {
19 return nil, p.Error("Expected a number", t)
20 }
21
22 if t.Type == tokens.Integer {
23 i, err := strconv.Atoi(t.Val)
24 if err != nil {
25 return nil, p.Error(err.Error(), t)
26 }
27 nr := &nodes.Integer{
28 Location: t,
29 Val: i,
30 }
31 return nr, nil
32 } else {
33 f, err := strconv.ParseFloat(t.Val, 64)
34 if err != nil {
35 return nil, p.Error(err.Error(), t)
36 }
37 fr := &nodes.Float{
38 Location: t,
39 Val: f,
40 }
41 return fr, nil
42 }
43 }
44
45 func (p *Parser) parseString() (nodes.Expression, error) {
46 log.WithFields(log.Fields{
47 "current": p.Current(),
48 }).Trace("parseString")
49 t := p.Match(tokens.String)
50 if t == nil {
51 return nil, p.Error("Expected a string", t)
52 }
53 str := strconv.Quote(t.Val)
54 replaced := strings.Replace(str, `\\`, "\\", -1)
55 newstr, err := strconv.Unquote(replaced)
56 if err != nil {
57 return nil, p.Error(err.Error(), t)
58 }
59 sr := &nodes.String{
60 Location: t,
61 Val: newstr,
62 }
63 return sr, nil
64 }
65
66 func (p *Parser) parseCollection() (nodes.Expression, error) {
67 switch p.Current().Type {
68 case tokens.Lbracket:
69 return p.parseList()
70 case tokens.Lparen:
71 return p.parseTuple()
72 case tokens.Lbrace:
73 return p.parseDict()
74 default:
75 return nil, nil
76 }
77 }
78
79 func (p *Parser) parseList() (nodes.Expression, error) {
80 log.WithFields(log.Fields{
81 "current": p.Current(),
82 }).Trace("parseList")
83 t := p.Match(tokens.Lbracket)
84 if t == nil {
85 return nil, p.Error("Expected [", t)
86 }
87
88 if p.Match(tokens.Rbracket) != nil {
89
90 return &nodes.List{t, []nodes.Expression{}}, nil
91 }
92
93 expr, err := p.ParseExpression()
94 if err != nil {
95 return nil, err
96 }
97 list := []nodes.Expression{expr}
98
99 for p.Match(tokens.Comma) != nil {
100 if p.Peek(tokens.Rbracket) != nil {
101
102 break
103 }
104 expr, err := p.ParseExpression()
105 if err != nil {
106 return nil, err
107 }
108 if expr == nil {
109 return nil, p.Error("Expected a value", p.Current())
110 }
111 list = append(list, expr)
112 }
113
114 if p.Match(tokens.Rbracket) == nil {
115 return nil, p.Error("Expected ]", p.Current())
116 }
117
118 return &nodes.List{t, list}, nil
119 }
120
121 func (p *Parser) parseTuple() (nodes.Expression, error) {
122 log.WithFields(log.Fields{
123 "current": p.Current(),
124 }).Trace("parseTuple")
125 t := p.Match(tokens.Lparen)
126 if t == nil {
127 return nil, p.Error("Expected (", t)
128 }
129 expr, err := p.ParseExpression()
130 if err != nil {
131 return nil, err
132 }
133 list := []nodes.Expression{expr}
134
135 trailingComa := false
136
137 for p.Match(tokens.Comma) != nil {
138 if p.Peek(tokens.Rparen) != nil {
139
140 trailingComa = true
141 break
142 }
143 expr, err := p.ParseExpression()
144 if err != nil {
145 return nil, err
146 }
147 if expr == nil {
148 return nil, p.Error("Expected a value", p.Current())
149 }
150 list = append(list, expr)
151 }
152
153 if p.Match(tokens.Rparen) == nil {
154 return nil, p.Error("Unbalanced parenthesis", t)
155
156 }
157
158 if len(list) > 1 || trailingComa {
159 return &nodes.Tuple{t, list}, nil
160 } else {
161 return expr, nil
162 }
163 }
164
165 func (p *Parser) parsePair() (*nodes.Pair, error) {
166 log.WithFields(log.Fields{
167 "current": p.Current(),
168 }).Trace("parsePair")
169 key, err := p.ParseExpression()
170 if err != nil {
171 return nil, err
172 }
173
174 if p.Match(tokens.Colon) == nil {
175 return nil, p.Error("Expected \":\"", p.Current())
176 }
177 value, err := p.ParseExpression()
178 if err != nil {
179 return nil, err
180 }
181 return &nodes.Pair{
182 Key: key,
183 Value: value,
184 }, nil
185 }
186
187 func (p *Parser) parseDict() (nodes.Expression, error) {
188 log.WithFields(log.Fields{
189 "current": p.Current(),
190 }).Trace("parseDict")
191 t := p.Match(tokens.Lbrace)
192 if t == nil {
193 return nil, p.Error("Expected {", t)
194 }
195
196 dict := &nodes.Dict{
197 Token: t,
198 Pairs: []*nodes.Pair{},
199 }
200
201 if p.Peek(tokens.Rbrace) == nil {
202 pair, err := p.parsePair()
203 if err != nil {
204 return nil, err
205 }
206 dict.Pairs = append(dict.Pairs, pair)
207 }
208
209 for p.Match(tokens.Comma) != nil {
210 pair, err := p.parsePair()
211 if err != nil {
212 return nil, err
213 }
214 dict.Pairs = append(dict.Pairs, pair)
215 }
216
217 if p.Match(tokens.Rbrace) == nil {
218 return nil, p.Error("Expected }", p.Current())
219 }
220
221 return dict, nil
222 }
223
224 func (p *Parser) ParseVariable() (nodes.Expression, error) {
225 log.WithFields(log.Fields{
226 "current": p.Current(),
227 }).Trace("ParseVariable")
228
229 t := p.Match(tokens.Name)
230 if t == nil {
231 return nil, p.Error("Expected an identifier.", t)
232 }
233
234 switch t.Val {
235 case "true", "True":
236 br := &nodes.Bool{
237 Location: t,
238 Val: true,
239 }
240 return br, nil
241 case "false", "False":
242 br := &nodes.Bool{
243 Location: t,
244 Val: false,
245 }
246 return br, nil
247 }
248
249 var variable nodes.Node = &nodes.Name{t}
250
251 for !p.Stream.EOF() {
252 if dot := p.Match(tokens.Dot); dot != nil {
253 getattr := &nodes.Getattr{
254 Location: dot,
255 Node: variable,
256 }
257 tok := p.Match(tokens.Name, tokens.Integer)
258 switch tok.Type {
259 case tokens.Name:
260 getattr.Attr = tok.Val
261 case tokens.Integer:
262 i, err := strconv.Atoi(tok.Val)
263 if err != nil {
264 return nil, p.Error(err.Error(), tok)
265 }
266 getattr.Index = i
267 default:
268 return nil, p.Error("This token is not allowed within a variable name.", p.Current())
269 }
270 variable = getattr
271 continue
272 } else if bracket := p.Match(tokens.Lbracket); bracket != nil {
273 getitem := &nodes.Getitem{
274 Location: dot,
275 Node: variable,
276 }
277 tok := p.Match(tokens.String, tokens.Integer)
278 switch tok.Type {
279 case tokens.String:
280 getitem.Arg = tok.Val
281 case tokens.Integer:
282 i, err := strconv.Atoi(tok.Val)
283 if err != nil {
284 return nil, p.Error(err.Error(), tok)
285 }
286 getitem.Index = i
287 default:
288 return nil, p.Error("This token is not allowed within a variable name.", p.Current())
289 }
290 variable = getitem
291 if p.Match(tokens.Rbracket) == nil {
292 return nil, p.Error("Unbalanced bracket", bracket)
293 }
294 continue
295
296 } else if lparen := p.Match(tokens.Lparen); lparen != nil {
297 call := &nodes.Call{
298 Location: lparen,
299 Func: variable,
300 Args: []nodes.Expression{},
301 Kwargs: map[string]nodes.Expression{},
302 }
303
304
305
306
307 for p.Match(tokens.Comma) != nil || p.Match(tokens.Rparen) == nil {
308
309 v, err := p.ParseExpression()
310 if err != nil {
311 return nil, err
312 }
313
314 if p.Match(tokens.Assign) != nil {
315 key := v.Position().Val
316 value, errValue := p.ParseExpression()
317 if errValue != nil {
318 return nil, errValue
319 }
320 call.Kwargs[key] = value
321 } else {
322 call.Args = append(call.Args, v)
323 }
324 }
325 variable = call
326
327 continue
328 }
329
330
331 break
332 }
333
334 return variable, nil
335 }
336
337
338 func (p *Parser) ParseVariableOrLiteral() (nodes.Expression, error) {
339 log.WithFields(log.Fields{
340 "current": p.Current(),
341 }).Trace("ParseVariableOrLiteral")
342 t := p.Current()
343
344 if t == nil {
345 return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.Current())
346 }
347
348
349 switch t.Type {
350 case tokens.Integer, tokens.Float:
351 return p.parseNumber()
352
353 case tokens.String:
354 return p.parseString()
355
356 case tokens.Lparen, tokens.Lbrace, tokens.Lbracket:
357 return p.parseCollection()
358
359 case tokens.Name:
360 return p.ParseVariable()
361
362 default:
363 return nil, p.Error("Expected either a number, string, keyword or identifier.", t)
364 }
365 }
366
View as plain text