Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad876c3

Browse files
authored
add the ability to set variables through inline definitions (#311)
1 parent 8400540 commit ad876c3

File tree

3 files changed

+145
-20
lines changed

3 files changed

+145
-20
lines changed

template_tests/set.tpl

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,28 @@
33
{{ new_var }}{% for item in simple.misc_list %}
44
{% set new_var = item %}{{ new_var }}{% endfor %}
55
{{ new_var }}
6-
{% set car=someUndefinedVar %}{{ car.Drive }}No Panic
6+
{% set car=someUndefinedVar %}{{ car.Drive }}No Panic
7+
8+
{% set new_var = ["hello", "val2"] %}
9+
10+
{% for var in new_var %}{{ var }}
11+
{% endfor %}
12+
13+
{% set int_variables = [1, 2, 3] %}{% for var in int_variables %}{{ var }}
14+
{% endfor %}
15+
16+
{% set mixed_variables = [1, "two", 3.5, "4"] %}{% for var in mixed_variables %}{{ var }}
17+
{% endfor %}
18+
19+
{% set empty_set = [] %}{% for var in empty_set %}{{ var }}
20+
{% endfor %}
21+
22+
{% set item = "item1" %}
23+
{% set ref_set = [item, "item2", some_random_variable] %}{% for var in ref_set %}{{ var }}
24+
{% endfor %}
25+
26+
{% set nil_item_set = [nil] %}{% for var in nil_item_set %}-{{ var }}-{# printing an additional dash here to show the loop over the array with a nil item #}
27+
{% endfor %}
28+
29+
{% set nil_set = nil %}{% for var in nil_set %}-{{ var }} {# printing an additional dash here to show that the nil array won't be looped #}
30+
{% endfor %}

template_tests/set.tpl.out

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,34 @@ Hello
66
3.140000
77
good
88
world
9-
No Panic
9+
No Panic
10+
11+
12+
13+
hello
14+
val2
15+
16+
17+
1
18+
2
19+
3
20+
21+
22+
1
23+
two
24+
3.500000
25+
4
26+
27+
28+
29+
30+
31+
item1
32+
item2
33+
34+
35+
36+
--
37+
38+
39+

variable.go

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package pongo2
22

33
import (
4+
"errors"
45
"fmt"
56
"reflect"
67
"strconv"
@@ -11,6 +12,7 @@ const (
1112
varTypeInt = iota
1213
varTypeIdent
1314
varTypeSubscript
15+
varTypeArray
1416
varTypeNil
1517
)
1618

@@ -234,6 +236,29 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
234236
var current reflect.Value
235237
var isSafe bool
236238

239+
// we are resolving an in-template array definition
240+
if len(vr.parts) > 0 && vr.parts[0].typ == varTypeArray {
241+
items := make([]*Value, 0)
242+
for _, part := range vr.parts {
243+
switch v := part.subscript.(type) {
244+
case *nodeFilteredVariable:
245+
item, err := v.resolver.Evaluate(ctx)
246+
if err != nil {
247+
return nil, err
248+
}
249+
250+
items = append(items, item)
251+
default:
252+
return nil, errors.New("unknown variable type is given")
253+
}
254+
}
255+
256+
return &Value{
257+
val: reflect.ValueOf(items),
258+
safe: true,
259+
}, nil
260+
}
261+
237262
for idx, part := range vr.parts {
238263
if idx == 0 {
239264
// We're looking up the first part of the variable.
@@ -593,17 +618,21 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
593618
locationToken: t,
594619
}
595620

596-
// First part of a variable MUST be an identifier
597-
if t.Typ != TokenIdentifier {
621+
isArrayDefinition := false
622+
if t.Typ == TokenSymbol && t.Val != "}}" {
623+
isArrayDefinition = true
624+
} else if t.Typ != TokenIdentifier {
625+
// First part of a variable MUST be an identifier
598626
return nil, p.Error("Expected either a number, string, keyword or identifier.", t)
599627
}
600628

601-
resolver.parts = append(resolver.parts, &variablePart{
602-
typ: varTypeIdent,
603-
s: t.Val,
604-
})
605-
606-
p.Consume() // we consumed the first identifier of the variable name
629+
if t.Typ == TokenIdentifier {
630+
resolver.parts = append(resolver.parts, &variablePart{
631+
typ: varTypeIdent,
632+
s: t.Val,
633+
})
634+
p.Consume() // we consumed the first identifier of the variable name
635+
}
607636

608637
variableLoop:
609638
for p.Remaining() > 0 {
@@ -652,17 +681,59 @@ variableLoop:
652681
if p.Remaining() == 0 {
653682
return nil, p.Error("Unexpected EOF, expected subscript subscript.", p.lastToken)
654683
}
655-
exprSubscript, err := p.ParseExpression()
656-
if err != nil {
657-
return nil, err
658-
}
659-
resolver.parts = append(resolver.parts, &variablePart{
660-
typ: varTypeSubscript,
661-
subscript: exprSubscript,
662-
})
663-
if p.Match(TokenSymbol, "]") == nil {
664-
return nil, p.Error("Missing closing bracket after subscript argument.", nil)
684+
685+
if !isArrayDefinition {
686+
exprSubscript, err := p.ParseExpression()
687+
if err != nil {
688+
return nil, err
689+
}
690+
resolver.parts = append(resolver.parts, &variablePart{
691+
typ: varTypeSubscript,
692+
subscript: exprSubscript,
693+
})
694+
if p.Match(TokenSymbol, "]") == nil {
695+
return nil, p.Error("Missing closing bracket after subscript argument.", nil)
696+
}
697+
} else {
698+
// parsing an array declaration
699+
arrayLoop:
700+
for {
701+
if p.Remaining() == 0 {
702+
return nil, p.Error("Unexpected EOF, expected function call argument list.", p.lastToken)
703+
}
704+
705+
if p.Peek(TokenSymbol, "]") != nil {
706+
// We got a closing bracket, so stop parsing arguments
707+
p.Consume()
708+
break arrayLoop
709+
}
710+
711+
// No closing bracket, so we're parsing an expression
712+
exprArg, err := p.ParseExpression()
713+
if err != nil {
714+
return nil, err
715+
}
716+
717+
resolver.parts = append(resolver.parts, &variablePart{
718+
typ: varTypeArray,
719+
subscript: exprArg,
720+
})
721+
722+
if p.Match(TokenSymbol, "]") != nil {
723+
// If there's a closing bracket after an expression, we will stop parsing the arguments
724+
break arrayLoop
725+
} else {
726+
// If there's NO closing bracket, there MUST be an comma
727+
if p.Match(TokenSymbol, ",") == nil {
728+
return nil, p.Error("Missing comma or closing bracket after argument.", nil)
729+
}
730+
}
731+
732+
}
733+
734+
continue variableLoop
665735
}
736+
666737
} else if p.Match(TokenSymbol, "(") != nil {
667738
// Function call
668739
// FunctionName '(' Comma-separated list of expressions ')'

0 commit comments

Comments
 (0)