1
package parser
2

3
import (
4
	// "fmt"
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 4
func (p *Parser) parseNumber() (nodes.Expression, error) {
14 4
	log.WithFields(log.Fields{
15 4
		"current": p.Current(),
16 4
	}).Trace("parseNumber")
17 4
	t := p.Match(tokens.Integer, tokens.Float)
18 4
	if t == nil {
19 0
		return nil, p.Error("Expected a number", t)
20 0
	}
21

22 4
	if t.Type == tokens.Integer {
23 4
		i, err := strconv.Atoi(t.Val)
24 4
		if err != nil {
25 0
			return nil, p.Error(err.Error(), t)
26 0
		}
27 4
		nr := &nodes.Integer{
28 4
			Location: t,
29 4
			Val:      i,
30 1
		}
31 4
		return nr, nil
32
	}
33 4
	f, err := strconv.ParseFloat(t.Val, 64)
34 4
	if err != nil {
35 0
		return nil, p.Error(err.Error(), t)
36 0
	}
37 4
	fr := &nodes.Float{
38 4
		Location: t,
39 4
		Val:      f,
40 1
	}
41 4
	return fr, nil
42
}
43

44 4
func (p *Parser) parseString() (nodes.Expression, error) {
45 4
	log.WithFields(log.Fields{
46 4
		"current": p.Current(),
47 4
	}).Trace("parseString")
48 4
	t := p.Match(tokens.String)
49 4
	if t == nil {
50 0
		return nil, p.Error("Expected a string", t)
51 0
	}
52 4
	str := strconv.Quote(t.Val)
53 4
	replaced := strings.Replace(str, `\\`, "\\", -1)
54 4
	newstr, err := strconv.Unquote(replaced)
55 4
	if err != nil {
56 0
		return nil, p.Error(err.Error(), t)
57 0
	}
58 4
	sr := &nodes.String{
59 4
		Location: t,
60 4
		Val:      newstr,
61 1
	}
62 4
	return sr, nil
63
}
64

65 4
func (p *Parser) parseCollection() (nodes.Expression, error) {
66 4
	switch p.Current().Type {
67 4
	case tokens.Lbracket:
68 4
		return p.parseList()
69 4
	case tokens.Lparen:
70 4
		return p.parseTuple()
71 4
	case tokens.Lbrace:
72 4
		return p.parseDict()
73 0
	default:
74 0
		return nil, nil
75
	}
76
}
77

78 4
func (p *Parser) parseList() (nodes.Expression, error) {
79 4
	log.WithFields(log.Fields{
80 4
		"current": p.Current(),
81 4
	}).Trace("parseList")
82 4
	t := p.Match(tokens.Lbracket)
83 4
	if t == nil {
84 0
		return nil, p.Error("Expected [", t)
85 0
	}
86

87 4
	if p.Match(tokens.Rbracket) != nil {
88 1
		// Empty list
89 4
		return &nodes.List{t, []nodes.Expression{}}, nil
90 1
	}
91

92 4
	expr, err := p.ParseExpression()
93 4
	if err != nil {
94 0
		return nil, err
95 0
	}
96 4
	list := []nodes.Expression{expr}
97 1

98 4
	for p.Match(tokens.Comma) != nil {
99 4
		if p.Peek(tokens.Rbracket) != nil {
100 1
			// Trailing coma
101 4
			break
102
		}
103 4
		expr, err := p.ParseExpression()
104 4
		if err != nil {
105 0
			return nil, err
106 0
		}
107 4
		if expr == nil {
108 0
			return nil, p.Error("Expected a value", p.Current())
109 0
		}
110 4
		list = append(list, expr)
111
	}
112

113 4
	if p.Match(tokens.Rbracket) == nil {
114 0
		return nil, p.Error("Expected ]", p.Current())
115 0
	}
116

117 4
	return &nodes.List{t, list}, nil
118
}
119

120 4
func (p *Parser) parseTuple() (nodes.Expression, error) {
121 4
	log.WithFields(log.Fields{
122 4
		"current": p.Current(),
123 4
	}).Trace("parseTuple")
124 4
	t := p.Match(tokens.Lparen)
125 4
	if t == nil {
126 0
		return nil, p.Error("Expected (", t)
127 0
	}
128 4
	expr, err := p.ParseExpression()
129 4
	if err != nil {
130 0
		return nil, err
131 0
	}
132 4
	list := []nodes.Expression{expr}
133 1

134 4
	trailingComa := false
135 1

136 4
	for p.Match(tokens.Comma) != nil {
137 4
		if p.Peek(tokens.Rparen) != nil {
138 1
			// Trailing coma
139 4
			trailingComa = true
140 4
			break
141
		}
142 4
		expr, err := p.ParseExpression()
143 4
		if err != nil {
144 0
			return nil, err
145 0
		}
146 4
		if expr == nil {
147 0
			return nil, p.Error("Expected a value", p.Current())
148 0
		}
149 4
		list = append(list, expr)
150
	}
151

152 4
	if p.Match(tokens.Rparen) == nil {
153 0
		return nil, p.Error("Unbalanced parenthesis", t)
154 0
		// return nil, p.Error("Expected )", p.Current())
155 0
	}
156

157 4
	if len(list) > 1 || trailingComa {
158 4
		return &nodes.Tuple{t, list}, nil
159 1
	}
160 4
	return expr, nil
161
}
162

163 4
func (p *Parser) parsePair() (*nodes.Pair, error) {
164 4
	log.WithFields(log.Fields{
165 4
		"current": p.Current(),
166 4
	}).Trace("parsePair")
167 4
	key, err := p.ParseExpression()
168 4
	if err != nil {
169 0
		return nil, err
170 0
	}
171

172 4
	if p.Match(tokens.Colon) == nil {
173 0
		return nil, p.Error("Expected \":\"", p.Current())
174 0
	}
175 4
	value, err := p.ParseExpression()
176 4
	if err != nil {
177 0
		return nil, err
178 0
	}
179 4
	return &nodes.Pair{
180 4
		Key:   key,
181 4
		Value: value,
182 4
	}, nil
183
}
184

185 4
func (p *Parser) parseDict() (nodes.Expression, error) {
186 4
	log.WithFields(log.Fields{
187 4
		"current": p.Current(),
188 4
	}).Trace("parseDict")
189 4
	t := p.Match(tokens.Lbrace)
190 4
	if t == nil {
191 0
		return nil, p.Error("Expected {", t)
192 0
	}
193

194 4
	dict := &nodes.Dict{
195 4
		Token: t,
196 4
		Pairs: []*nodes.Pair{},
197 1
	}
198 1

199 4
	if p.Peek(tokens.Rbrace) == nil {
200 4
		pair, err := p.parsePair()
201 4
		if err != nil {
202 0
			return nil, err
203 0
		}
204 4
		dict.Pairs = append(dict.Pairs, pair)
205
	}
206

207 4
	for p.Match(tokens.Comma) != nil {
208 4
		pair, err := p.parsePair()
209 4
		if err != nil {
210 0
			return nil, err
211 0
		}
212 4
		dict.Pairs = append(dict.Pairs, pair)
213
	}
214

215 4
	if p.Match(tokens.Rbrace) == nil {
216 0
		return nil, p.Error("Expected }", p.Current())
217 0
	}
218

219 4
	return dict, nil
220
}
221

222 4
func (p *Parser) ParseVariable() (nodes.Expression, error) {
223 4
	log.WithFields(log.Fields{
224 4
		"current": p.Current(),
225 4
	}).Trace("ParseVariable")
226 1

227 4
	t := p.Match(tokens.Name)
228 4
	if t == nil {
229 0
		return nil, p.Error("Expected an identifier.", t)
230 0
	}
231

232 4
	switch t.Val {
233 4
	case "true", "True":
234 4
		br := &nodes.Bool{
235 4
			Location: t,
236 4
			Val:      true,
237 1
		}
238 4
		return br, nil
239 4
	case "false", "False":
240 4
		br := &nodes.Bool{
241 4
			Location: t,
242 4
			Val:      false,
243 1
		}
244 4
		return br, nil
245
	}
246

247 4
	var variable nodes.Node = &nodes.Name{t}
248 1

249 4
	for !p.Stream.EOF() {
250 4
		if dot := p.Match(tokens.Dot); dot != nil {
251 4
			getattr := &nodes.Getattr{
252 4
				Location: dot,
253 4
				Node:     variable,
254 1
			}
255 4
			tok := p.Match(tokens.Name, tokens.Integer)
256 4
			switch tok.Type {
257 4
			case tokens.Name:
258 4
				getattr.Attr = tok.Val
259 4
			case tokens.Integer:
260 4
				i, err := strconv.Atoi(tok.Val)
261 4
				if err != nil {
262 0
					return nil, p.Error(err.Error(), tok)
263 0
				}
264 4
				getattr.Index = i
265 0
			default:
266 0
				return nil, p.Error("This token is not allowed within a variable name.", p.Current())
267
			}
268 4
			variable = getattr
269 4
			continue
270 4
		} else if bracket := p.Match(tokens.Lbracket); bracket != nil {
271 4
			getitem := &nodes.Getitem{
272 4
				Location: dot,
273 4
				Node:     variable,
274 1
			}
275 4
			tok := p.Match(tokens.String, tokens.Integer)
276 4
			switch tok.Type {
277 4
			case tokens.String:
278 4
				getitem.Arg = tok.Val
279 0
			case tokens.Integer:
280 0
				i, err := strconv.Atoi(tok.Val)
281 0
				if err != nil {
282 0
					return nil, p.Error(err.Error(), tok)
283 0
				}
284 0
				getitem.Index = i
285 0
			default:
286 0
				return nil, p.Error("This token is not allowed within a variable name.", p.Current())
287
			}
288 4
			variable = getitem
289 4
			if p.Match(tokens.Rbracket) == nil {
290 0
				return nil, p.Error("Unbalanced bracket", bracket)
291 0
			}
292 4
			continue
293

294 4
		} else if lparen := p.Match(tokens.Lparen); lparen != nil {
295 4
			call := &nodes.Call{
296 4
				Location: lparen,
297 4
				Func:     variable,
298 4
				Args:     []nodes.Expression{},
299 4
				Kwargs:   map[string]nodes.Expression{},
300 1
			}
301 1
			// if p.Peek(tokens.VariableEnd) != nil {
302 1
			// 	return nil, p.Error("Filter parameter required after '('.", nil)
303 1
			// }
304 1

305 4
			for p.Match(tokens.Comma) != nil || p.Match(tokens.Rparen) == nil {
306 1
				// TODO: Handle multiple args and kwargs
307 4
				v, err := p.ParseExpression()
308 4
				if err != nil {
309 0
					return nil, err
310 0
				}
311

312 4
				if p.Match(tokens.Assign) != nil {
313 4
					key := v.Position().Val
314 4
					value, errValue := p.ParseExpression()
315 4
					if errValue != nil {
316 0
						return nil, errValue
317 0
					}
318 4
					call.Kwargs[key] = value
319 4
				} else {
320 4
					call.Args = append(call.Args, v)
321 1
				}
322
			}
323 4
			variable = call
324 1
			// We're done parsing the function call, next variable part
325 4
			continue
326
		}
327

328
		// No dot or function call? Then we're done with the variable parsing
329 4
		break
330
	}
331

332 4
	return variable, nil
333
}
334

335
// IDENT | IDENT.(IDENT|NUMBER)...
336 4
func (p *Parser) ParseVariableOrLiteral() (nodes.Expression, error) {
337 4
	log.WithFields(log.Fields{
338 4
		"current": p.Current(),
339 4
	}).Trace("ParseVariableOrLiteral")
340 4
	t := p.Current()
341 1

342 4
	if t == nil {
343 0
		return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.Current())
344 0
	}
345

346
	// Is first part a number or a string, there's nothing to resolve (because there's only to return the value then)
347 4
	switch t.Type {
348 4
	case tokens.Integer, tokens.Float:
349 4
		return p.parseNumber()
350

351 4
	case tokens.String:
352 4
		return p.parseString()
353

354 4
	case tokens.Lparen, tokens.Lbrace, tokens.Lbracket:
355 4
		return p.parseCollection()
356

357 4
	case tokens.Name:
358 4
		return p.ParseVariable()
359

360 4
	default:
361 4
		return nil, p.Error("Expected either a number, string, keyword or identifier.", t)
362
	}
363
}

Read our documentation on viewing source code .

Loading