mirror of
https://github.com/danog/liquid.git
synced 2025-01-22 22:51:13 +01:00
Implement loop tag
This commit is contained in:
parent
db5a3afce4
commit
babfc3e527
@ -20,7 +20,7 @@
|
||||
- [x] unless
|
||||
- [ ] case/when
|
||||
- [ ] Iteration
|
||||
- [ ] for
|
||||
- [x] for
|
||||
- [ ] limit, offset, range, reversed
|
||||
- [ ] break, continue
|
||||
- [ ] loop variables
|
||||
|
@ -21,6 +21,26 @@ func NewContext(scope map[string]interface{}) Context {
|
||||
return Context{vars}
|
||||
}
|
||||
|
||||
func (c *Context) Set(name string, value interface{}) {
|
||||
c.vars[name] = value
|
||||
}
|
||||
|
||||
// Evaluate evaluates an expression within the template context.
|
||||
func (c *Context) Evaluate(expr expressions.Expression) (out interface{}, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
switch e := r.(type) {
|
||||
case expressions.InterpreterError:
|
||||
err = e
|
||||
default:
|
||||
// fmt.Println(string(debug.Stack()))
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return expr.Evaluate(expressions.NewContext(c.vars))
|
||||
}
|
||||
|
||||
// EvaluateExpr evaluates an expression within the template context.
|
||||
func (c *Context) EvaluateExpr(source string) (out interface{}, err error) {
|
||||
defer func() {
|
||||
|
@ -29,3 +29,8 @@ func (c *context) Set(name string, value interface{}) {
|
||||
// }
|
||||
c.vars[name] = value
|
||||
}
|
||||
|
||||
type Loop struct {
|
||||
Name string
|
||||
Expr interface{}
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ func init() {
|
||||
val interface{}
|
||||
f func(Context) interface{}
|
||||
}
|
||||
%type <f> expr rel expr1
|
||||
%type <f> expr rel expr1 loop
|
||||
%token <val> LITERAL
|
||||
%token <name> IDENTIFIER KEYWORD RELATION
|
||||
%token ASSIGN
|
||||
%token EQ
|
||||
%token ASSIGN LOOP
|
||||
%token EQ FOR IN
|
||||
%left '.' '|'
|
||||
%left '<' '>'
|
||||
%%
|
||||
@ -34,7 +34,17 @@ start:
|
||||
ctx.Set(name, expr(ctx))
|
||||
return nil
|
||||
}
|
||||
};
|
||||
}
|
||||
| LOOP loop { yylex.(*lexer).val = $2 }
|
||||
;
|
||||
|
||||
loop: IDENTIFIER IN expr1 ';' {
|
||||
name, expr := $1, $3
|
||||
$$ = func(ctx Context) interface{} {
|
||||
return &Loop{name, expr(ctx)}
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
expr:
|
||||
LITERAL { val := $1; $$ = func(_ Context) interface{} { return val } }
|
||||
|
@ -9,151 +9,158 @@ import "strconv"
|
||||
|
||||
//line scanner.go:11
|
||||
var _expression_actions []byte = []byte{
|
||||
0, 1, 0, 1, 1, 1, 2, 1, 9,
|
||||
1, 10, 1, 11, 1, 12, 1, 13,
|
||||
1, 14, 1, 15, 1, 16, 1, 17,
|
||||
1, 18, 1, 19, 1, 20, 1, 21,
|
||||
0, 1, 0, 1, 1, 1, 2, 1, 10,
|
||||
1, 11, 1, 12, 1, 13, 1, 14,
|
||||
1, 15, 1, 16, 1, 17, 1, 18,
|
||||
1, 19, 1, 20, 1, 21, 1, 22,
|
||||
2, 2, 3, 2, 2, 4, 2, 2,
|
||||
5, 2, 2, 6, 2, 2, 7, 2,
|
||||
2, 8,
|
||||
2, 8, 2, 2, 9,
|
||||
}
|
||||
|
||||
var _expression_key_offsets []byte = []byte{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
9, 36, 39, 40, 41, 42, 43, 46,
|
||||
48, 51, 52, 60, 69, 78, 87, 96,
|
||||
105, 114, 123, 132, 141, 150, 159, 168,
|
||||
177, 186, 195,
|
||||
8, 9, 10, 12, 37, 40, 41, 42,
|
||||
44, 45, 48, 50, 53, 54, 62, 71,
|
||||
80, 89, 98, 107, 116, 125, 134, 143,
|
||||
153, 162, 171, 180, 189, 198, 207, 216,
|
||||
}
|
||||
|
||||
var _expression_trans_keys []byte = []byte{
|
||||
34, 115, 115, 105, 103, 110, 39, 48,
|
||||
57, 32, 33, 34, 37, 39, 45, 46,
|
||||
59, 61, 91, 93, 95, 97, 99, 102,
|
||||
111, 116, 9, 13, 48, 57, 60, 62,
|
||||
65, 90, 98, 122, 32, 9, 13, 61,
|
||||
34, 97, 39, 46, 48, 57, 48, 57,
|
||||
46, 48, 57, 61, 58, 95, 48, 57,
|
||||
65, 90, 97, 122, 58, 95, 110, 48,
|
||||
57, 65, 90, 97, 122, 58, 95, 100,
|
||||
34, 115, 115, 105, 103, 110, 111, 111,
|
||||
112, 39, 48, 57, 32, 33, 34, 37,
|
||||
39, 45, 46, 61, 95, 97, 99, 102,
|
||||
105, 111, 116, 9, 13, 48, 57, 60,
|
||||
62, 65, 90, 98, 122, 32, 9, 13,
|
||||
61, 34, 97, 108, 39, 46, 48, 57,
|
||||
48, 57, 46, 48, 57, 61, 58, 95,
|
||||
48, 57, 65, 90, 97, 122, 58, 95,
|
||||
111, 48, 57, 65, 90, 97, 122, 58,
|
||||
95, 110, 48, 57, 65, 90, 97, 122,
|
||||
58, 95, 116, 48, 57, 65, 90, 97,
|
||||
122, 58, 95, 97, 48, 57, 65, 90,
|
||||
98, 122, 58, 95, 105, 48, 57, 65,
|
||||
90, 97, 122, 58, 95, 110, 48, 57,
|
||||
65, 90, 97, 122, 58, 95, 115, 48,
|
||||
57, 65, 90, 97, 122, 58, 95, 97,
|
||||
48, 57, 65, 90, 98, 122, 58, 95,
|
||||
108, 48, 57, 65, 90, 97, 122, 58,
|
||||
95, 115, 48, 57, 65, 90, 97, 122,
|
||||
58, 95, 101, 48, 57, 65, 90, 97,
|
||||
122, 58, 95, 114, 48, 57, 65, 90,
|
||||
97, 122, 58, 95, 114, 48, 57, 65,
|
||||
90, 97, 122, 58, 95, 117, 48, 57,
|
||||
65, 90, 97, 122,
|
||||
110, 48, 57, 65, 90, 97, 122, 58,
|
||||
95, 100, 48, 57, 65, 90, 97, 122,
|
||||
58, 95, 111, 48, 57, 65, 90, 97,
|
||||
122, 58, 95, 110, 48, 57, 65, 90,
|
||||
97, 122, 58, 95, 116, 48, 57, 65,
|
||||
90, 97, 122, 58, 95, 97, 48, 57,
|
||||
65, 90, 98, 122, 58, 95, 105, 48,
|
||||
57, 65, 90, 97, 122, 58, 95, 110,
|
||||
48, 57, 65, 90, 97, 122, 58, 95,
|
||||
115, 48, 57, 65, 90, 97, 122, 58,
|
||||
95, 97, 111, 48, 57, 65, 90, 98,
|
||||
122, 58, 95, 108, 48, 57, 65, 90,
|
||||
97, 122, 58, 95, 115, 48, 57, 65,
|
||||
90, 97, 122, 58, 95, 101, 48, 57,
|
||||
65, 90, 97, 122, 58, 95, 114, 48,
|
||||
57, 65, 90, 97, 122, 58, 95, 110,
|
||||
48, 57, 65, 90, 97, 122, 58, 95,
|
||||
114, 48, 57, 65, 90, 97, 122, 58,
|
||||
95, 114, 48, 57, 65, 90, 97, 122,
|
||||
58, 95, 117, 48, 57, 65, 90, 97,
|
||||
122,
|
||||
}
|
||||
|
||||
var _expression_single_lengths []byte = []byte{
|
||||
1, 1, 1, 1, 1, 1, 1, 0,
|
||||
17, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 2, 3, 3, 3, 3, 3,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 0, 15, 1, 1, 1, 2,
|
||||
1, 1, 0, 1, 1, 2, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3,
|
||||
}
|
||||
|
||||
var _expression_range_lengths []byte = []byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 1,
|
||||
5, 1, 0, 0, 0, 0, 1, 1,
|
||||
1, 0, 3, 3, 3, 3, 3, 3,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 5, 1, 0, 0, 0,
|
||||
0, 1, 1, 1, 0, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3,
|
||||
}
|
||||
|
||||
var _expression_index_offsets []byte = []byte{
|
||||
0, 2, 4, 6, 8, 10, 12, 14,
|
||||
16, 39, 42, 44, 46, 48, 50, 53,
|
||||
55, 58, 60, 66, 73, 80, 87, 94,
|
||||
101, 108, 115, 122, 129, 136, 143, 150,
|
||||
157, 164, 171,
|
||||
16, 18, 20, 22, 43, 46, 48, 50,
|
||||
53, 55, 58, 60, 63, 65, 71, 78,
|
||||
85, 92, 99, 106, 113, 120, 127, 134,
|
||||
142, 149, 156, 163, 170, 177, 184, 191,
|
||||
}
|
||||
|
||||
var _expression_indicies []byte = []byte{
|
||||
2, 1, 3, 0, 4, 0, 5, 0,
|
||||
6, 0, 7, 0, 2, 8, 9, 0,
|
||||
11, 12, 13, 14, 15, 16, 17, 19,
|
||||
21, 19, 19, 22, 23, 24, 25, 26,
|
||||
27, 11, 18, 20, 22, 22, 10, 11,
|
||||
11, 28, 30, 29, 2, 1, 32, 31,
|
||||
2, 8, 33, 18, 31, 9, 29, 9,
|
||||
18, 34, 35, 31, 36, 22, 22, 22,
|
||||
22, 29, 36, 22, 38, 22, 22, 22,
|
||||
37, 36, 22, 39, 22, 22, 22, 37,
|
||||
36, 22, 40, 22, 22, 22, 37, 36,
|
||||
22, 41, 22, 22, 22, 37, 36, 22,
|
||||
42, 22, 22, 22, 37, 36, 22, 43,
|
||||
22, 22, 22, 37, 36, 22, 44, 22,
|
||||
22, 22, 37, 36, 22, 45, 22, 22,
|
||||
22, 37, 36, 22, 39, 22, 22, 22,
|
||||
37, 36, 22, 46, 22, 22, 22, 37,
|
||||
36, 22, 47, 22, 22, 22, 37, 36,
|
||||
22, 48, 22, 22, 22, 37, 36, 22,
|
||||
49, 22, 22, 22, 37, 36, 22, 39,
|
||||
22, 22, 22, 37, 36, 22, 50, 22,
|
||||
22, 22, 37, 36, 22, 48, 22, 22,
|
||||
22, 37,
|
||||
6, 0, 7, 0, 8, 0, 9, 0,
|
||||
10, 0, 2, 11, 12, 0, 14, 15,
|
||||
16, 17, 18, 19, 20, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 14, 21, 15,
|
||||
23, 23, 13, 14, 14, 30, 32, 31,
|
||||
2, 1, 33, 34, 31, 2, 11, 35,
|
||||
21, 31, 12, 36, 12, 21, 37, 38,
|
||||
31, 39, 23, 23, 23, 23, 36, 39,
|
||||
23, 41, 23, 23, 23, 40, 39, 23,
|
||||
42, 23, 23, 23, 40, 39, 23, 43,
|
||||
23, 23, 23, 40, 39, 23, 44, 23,
|
||||
23, 23, 40, 39, 23, 45, 23, 23,
|
||||
23, 40, 39, 23, 46, 23, 23, 23,
|
||||
40, 39, 23, 47, 23, 23, 23, 40,
|
||||
39, 23, 48, 23, 23, 23, 40, 39,
|
||||
23, 42, 23, 23, 23, 40, 39, 23,
|
||||
49, 50, 23, 23, 23, 40, 39, 23,
|
||||
51, 23, 23, 23, 40, 39, 23, 52,
|
||||
23, 23, 23, 40, 39, 23, 53, 23,
|
||||
23, 23, 40, 39, 23, 54, 23, 23,
|
||||
23, 40, 39, 23, 55, 23, 23, 23,
|
||||
40, 39, 23, 42, 23, 23, 23, 40,
|
||||
39, 23, 56, 23, 23, 23, 40, 39,
|
||||
23, 52, 23, 23, 23, 40,
|
||||
}
|
||||
|
||||
var _expression_trans_targs []byte = []byte{
|
||||
8, 0, 8, 2, 3, 4, 5, 8,
|
||||
6, 15, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 16, 8, 10, 17, 18, 19,
|
||||
21, 28, 32, 33, 8, 8, 8, 8,
|
||||
1, 7, 8, 8, 8, 8, 20, 18,
|
||||
22, 23, 24, 25, 26, 27, 29, 30,
|
||||
31, 18, 34,
|
||||
11, 0, 11, 2, 3, 4, 5, 11,
|
||||
7, 8, 11, 9, 18, 11, 12, 13,
|
||||
14, 15, 16, 17, 18, 19, 20, 21,
|
||||
22, 24, 31, 36, 37, 38, 11, 11,
|
||||
11, 1, 6, 10, 11, 11, 11, 11,
|
||||
11, 23, 21, 25, 26, 27, 28, 29,
|
||||
30, 32, 35, 33, 34, 21, 21, 21,
|
||||
39,
|
||||
}
|
||||
|
||||
var _expression_trans_actions []byte = []byte{
|
||||
29, 0, 9, 0, 0, 0, 0, 7,
|
||||
0, 33, 19, 0, 48, 5, 5, 5,
|
||||
5, 39, 0, 11, 39, 0, 45, 0,
|
||||
0, 0, 0, 0, 25, 31, 15, 27,
|
||||
0, 0, 21, 13, 17, 23, 0, 42,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 36, 0,
|
||||
29, 0, 11, 0, 0, 0, 0, 7,
|
||||
0, 0, 9, 0, 33, 19, 0, 0,
|
||||
5, 5, 5, 5, 51, 0, 0, 48,
|
||||
0, 0, 0, 0, 0, 0, 25, 27,
|
||||
15, 0, 0, 0, 31, 21, 13, 17,
|
||||
23, 0, 39, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 36, 42, 45,
|
||||
0,
|
||||
}
|
||||
|
||||
var _expression_to_state_actions []byte = []byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0,
|
||||
}
|
||||
|
||||
var _expression_from_state_actions []byte = []byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
3, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 3, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0,
|
||||
}
|
||||
|
||||
var _expression_eof_trans []byte = []byte{
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 29, 30, 32, 32, 32, 32, 30,
|
||||
35, 32, 30, 38, 38, 38, 38, 38,
|
||||
38, 38, 38, 38, 38, 38, 38, 38,
|
||||
38, 38, 38,
|
||||
1, 1, 1, 0, 31, 32, 32, 32,
|
||||
32, 32, 37, 38, 32, 37, 41, 41,
|
||||
41, 41, 41, 41, 41, 41, 41, 41,
|
||||
41, 41, 41, 41, 41, 41, 41, 41,
|
||||
}
|
||||
|
||||
const expression_start int = 8
|
||||
const expression_first_final int = 8
|
||||
const expression_start int = 11
|
||||
const expression_first_final int = 11
|
||||
const expression_error int = -1
|
||||
|
||||
const expression_en_main int = 8
|
||||
const expression_en_main int = 11
|
||||
|
||||
|
||||
//line scanner.rl:13
|
||||
@ -176,7 +183,7 @@ func newLexer(data []byte) *lexer {
|
||||
pe: len(data),
|
||||
}
|
||||
|
||||
//line scanner.go:180
|
||||
//line scanner.go:187
|
||||
{
|
||||
lex.cs = expression_start
|
||||
lex.ts = 0
|
||||
@ -193,7 +200,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
tok := 0
|
||||
|
||||
|
||||
//line scanner.go:197
|
||||
//line scanner.go:204
|
||||
{
|
||||
var _klen int
|
||||
var _trans int
|
||||
@ -213,7 +220,7 @@ _resume:
|
||||
//line NONE:1
|
||||
lex.ts = ( lex.p)
|
||||
|
||||
//line scanner.go:217
|
||||
//line scanner.go:224
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,28 +296,36 @@ _eof_trans:
|
||||
|
||||
case 3:
|
||||
//line scanner.rl:59
|
||||
lex.act = 3;
|
||||
lex.act = 4;
|
||||
case 4:
|
||||
//line scanner.rl:40
|
||||
lex.act = 5;
|
||||
case 5:
|
||||
//line scanner.rl:87
|
||||
lex.act = 6;
|
||||
case 6:
|
||||
case 5:
|
||||
//line scanner.rl:74
|
||||
lex.act = 9;
|
||||
case 6:
|
||||
//line scanner.rl:91
|
||||
lex.act = 10;
|
||||
case 7:
|
||||
//line scanner.rl:45
|
||||
//line scanner.rl:92
|
||||
lex.act = 11;
|
||||
case 8:
|
||||
//line scanner.rl:94
|
||||
//line scanner.rl:45
|
||||
lex.act = 13;
|
||||
case 9:
|
||||
//line scanner.rl:96
|
||||
lex.act = 15;
|
||||
case 10:
|
||||
//line scanner.rl:82
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = ASSIGN; ( lex.p)++; goto _out
|
||||
}
|
||||
case 10:
|
||||
case 11:
|
||||
//line scanner.rl:83
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = LOOP; ( lex.p)++; goto _out
|
||||
}
|
||||
case 12:
|
||||
//line scanner.rl:68
|
||||
lex.te = ( lex.p)+1
|
||||
{
|
||||
@ -320,32 +335,27 @@ _eof_trans:
|
||||
( lex.p)++; goto _out
|
||||
|
||||
}
|
||||
case 11:
|
||||
//line scanner.rl:87
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = int(lex.data[lex.ts]); ( lex.p)++; goto _out
|
||||
}
|
||||
case 12:
|
||||
case 13:
|
||||
//line scanner.rl:88
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = EQ; ( lex.p)++; goto _out
|
||||
}
|
||||
case 13:
|
||||
case 14:
|
||||
//line scanner.rl:74
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = RELATION; out.name = lex.token(); ( lex.p)++; goto _out
|
||||
}
|
||||
case 14:
|
||||
//line scanner.rl:91
|
||||
case 15:
|
||||
//line scanner.rl:93
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = KEYWORD; out.name = string(lex.data[lex.ts:lex.te-1]); ( lex.p)++; goto _out
|
||||
}
|
||||
case 15:
|
||||
//line scanner.rl:94
|
||||
case 16:
|
||||
//line scanner.rl:96
|
||||
lex.te = ( lex.p)+1
|
||||
{ tok = int(lex.data[lex.ts]); ( lex.p)++; goto _out
|
||||
}
|
||||
case 16:
|
||||
case 17:
|
||||
//line scanner.rl:50
|
||||
lex.te = ( lex.p)
|
||||
( lex.p)--
|
||||
@ -359,7 +369,7 @@ _eof_trans:
|
||||
( lex.p)++; goto _out
|
||||
|
||||
}
|
||||
case 17:
|
||||
case 18:
|
||||
//line scanner.rl:45
|
||||
lex.te = ( lex.p)
|
||||
( lex.p)--
|
||||
@ -369,26 +379,26 @@ _eof_trans:
|
||||
( lex.p)++; goto _out
|
||||
|
||||
}
|
||||
case 18:
|
||||
//line scanner.rl:93
|
||||
case 19:
|
||||
//line scanner.rl:95
|
||||
lex.te = ( lex.p)
|
||||
( lex.p)--
|
||||
|
||||
case 19:
|
||||
//line scanner.rl:94
|
||||
case 20:
|
||||
//line scanner.rl:96
|
||||
lex.te = ( lex.p)
|
||||
( lex.p)--
|
||||
{ tok = int(lex.data[lex.ts]); ( lex.p)++; goto _out
|
||||
}
|
||||
case 20:
|
||||
//line scanner.rl:94
|
||||
case 21:
|
||||
//line scanner.rl:96
|
||||
( lex.p) = ( lex.te) - 1
|
||||
{ tok = int(lex.data[lex.ts]); ( lex.p)++; goto _out
|
||||
}
|
||||
case 21:
|
||||
case 22:
|
||||
//line NONE:1
|
||||
switch lex.act {
|
||||
case 3:
|
||||
case 4:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
|
||||
tok = LITERAL
|
||||
@ -400,7 +410,7 @@ _eof_trans:
|
||||
( lex.p)++; goto _out
|
||||
|
||||
}
|
||||
case 5:
|
||||
case 6:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
|
||||
tok = LITERAL
|
||||
@ -408,15 +418,19 @@ _eof_trans:
|
||||
( lex.p)++; goto _out
|
||||
|
||||
}
|
||||
case 6:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
tok = int(lex.data[lex.ts]); ( lex.p)++; goto _out
|
||||
}
|
||||
case 9:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
tok = RELATION; out.name = lex.token(); ( lex.p)++; goto _out
|
||||
}
|
||||
case 10:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
tok = IN; ( lex.p)++; goto _out
|
||||
}
|
||||
case 11:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
tok = IN; ( lex.p)++; goto _out
|
||||
}
|
||||
case 13:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
|
||||
tok = IDENTIFIER
|
||||
@ -424,13 +438,13 @@ _eof_trans:
|
||||
( lex.p)++; goto _out
|
||||
|
||||
}
|
||||
case 13:
|
||||
case 15:
|
||||
{( lex.p) = ( lex.te) - 1
|
||||
tok = int(lex.data[lex.ts]); ( lex.p)++; goto _out
|
||||
}
|
||||
}
|
||||
|
||||
//line scanner.go:434
|
||||
//line scanner.go:448
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,7 +458,7 @@ _again:
|
||||
//line NONE:1
|
||||
lex.ts = 0
|
||||
|
||||
//line scanner.go:448
|
||||
//line scanner.go:462
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,7 +477,7 @@ _again:
|
||||
_out: {}
|
||||
}
|
||||
|
||||
//line scanner.rl:98
|
||||
//line scanner.rl:100
|
||||
|
||||
|
||||
return tok
|
||||
|
@ -80,14 +80,16 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
|
||||
main := |*
|
||||
"%assign" => { tok = ASSIGN; fbreak; };
|
||||
"%loop" => { tok = LOOP; fbreak; };
|
||||
int => Int;
|
||||
float => Float;
|
||||
string => String;
|
||||
("true" | "false") => Bool;
|
||||
[.;<>] | '[' | ']' => { tok = int(lex.data[lex.ts]); fbreak; };
|
||||
"==" => { tok = EQ; fbreak; };
|
||||
("!=" | ">" | ">" | ">=" | "<=") => Relation;
|
||||
("!=" | ">=" | "<=") => Relation;
|
||||
("and" | "or" | "contains") => Relation;
|
||||
"for" => { tok = IN; fbreak; };
|
||||
"in" => { tok = IN; fbreak; };
|
||||
ident ':' => { tok = KEYWORD; out.name = string(lex.data[lex.ts:lex.te-1]); fbreak; };
|
||||
ident => Ident;
|
||||
space+;
|
||||
|
112
expressions/y.go
112
expressions/y.go
@ -29,7 +29,10 @@ const IDENTIFIER = 57347
|
||||
const KEYWORD = 57348
|
||||
const RELATION = 57349
|
||||
const ASSIGN = 57350
|
||||
const EQ = 57351
|
||||
const LOOP = 57351
|
||||
const EQ = 57352
|
||||
const FOR = 57353
|
||||
const IN = 57354
|
||||
|
||||
var yyToknames = [...]string{
|
||||
"$end",
|
||||
@ -40,7 +43,10 @@ var yyToknames = [...]string{
|
||||
"KEYWORD",
|
||||
"RELATION",
|
||||
"ASSIGN",
|
||||
"LOOP",
|
||||
"EQ",
|
||||
"FOR",
|
||||
"IN",
|
||||
"'.'",
|
||||
"'|'",
|
||||
"'<'",
|
||||
@ -65,46 +71,50 @@ var yyExca = [...]int{
|
||||
|
||||
const yyPrivate = 57344
|
||||
|
||||
const yyLast = 35
|
||||
const yyLast = 42
|
||||
|
||||
var yyAct = [...]int{
|
||||
|
||||
5, 13, 11, 11, 14, 15, 11, 4, 12, 12,
|
||||
27, 8, 12, 20, 21, 22, 23, 25, 10, 26,
|
||||
16, 28, 10, 19, 24, 6, 7, 17, 18, 3,
|
||||
6, 7, 9, 1, 2,
|
||||
29, 6, 16, 14, 5, 14, 14, 17, 18, 15,
|
||||
32, 15, 15, 19, 9, 13, 24, 25, 26, 27,
|
||||
20, 21, 22, 31, 28, 30, 13, 13, 23, 34,
|
||||
33, 7, 8, 7, 8, 3, 4, 12, 10, 1,
|
||||
11, 2,
|
||||
}
|
||||
var yyPact = [...]int{
|
||||
|
||||
21, -1000, -3, 27, 11, -8, -1000, -1000, -1000, 5,
|
||||
22, 18, 26, 26, 26, 26, 26, -1000, 26, -1000,
|
||||
-7, -4, -4, -4, 7, -4, -4, -1000, -1000,
|
||||
27, -1000, -3, 33, 32, 1, -8, -1000, -1000, -1000,
|
||||
-5, -1000, 8, 16, 23, 29, 29, 29, 29, 29,
|
||||
29, -1000, 29, -1000, -10, -7, -7, -7, 13, -7,
|
||||
12, -7, -1000, -1000, -1000,
|
||||
}
|
||||
var yyPgo = [...]int{
|
||||
|
||||
0, 0, 34, 7, 33,
|
||||
0, 0, 41, 4, 40, 39,
|
||||
}
|
||||
var yyR1 = [...]int{
|
||||
|
||||
0, 4, 4, 1, 1, 1, 1, 3, 3, 3,
|
||||
2, 2, 2, 2,
|
||||
0, 5, 5, 5, 4, 1, 1, 1, 1, 3,
|
||||
3, 3, 2, 2, 2, 2,
|
||||
}
|
||||
var yyR2 = [...]int{
|
||||
|
||||
0, 2, 5, 1, 1, 3, 4, 1, 3, 4,
|
||||
1, 3, 3, 3,
|
||||
0, 2, 5, 2, 4, 1, 1, 3, 4, 1,
|
||||
3, 4, 1, 3, 3, 3,
|
||||
}
|
||||
var yyChk = [...]int{
|
||||
|
||||
-1000, -4, -2, 8, -3, -1, 4, 5, 14, 5,
|
||||
11, 10, 16, 9, 12, 13, 15, 5, 6, 5,
|
||||
-1, -1, -1, -1, -3, -1, -1, 17, 14,
|
||||
-1000, -5, -2, 8, 9, -3, -1, 4, 5, 17,
|
||||
5, -4, 5, 14, 13, 19, 10, 15, 16, 18,
|
||||
12, 5, 6, 5, -1, -1, -1, -1, -3, -1,
|
||||
-3, -1, 20, 17, 17,
|
||||
}
|
||||
var yyDef = [...]int{
|
||||
|
||||
0, -2, 0, 0, 10, 7, 3, 4, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 8, 0, 5,
|
||||
0, 11, 12, 13, 0, 7, 9, 6, 2,
|
||||
0, -2, 0, 0, 0, 12, 9, 5, 6, 1,
|
||||
0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 10, 0, 7, 0, 13, 14, 15, 0, 9,
|
||||
0, 11, 8, 2, 4,
|
||||
}
|
||||
var yyTok1 = [...]int{
|
||||
|
||||
@ -112,19 +122,20 @@ var yyTok1 = [...]int{
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 10, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 14,
|
||||
12, 15, 13, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 13, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 17,
|
||||
15, 18, 16, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 16, 3, 17, 3, 3, 3, 3, 3, 3,
|
||||
3, 19, 3, 20, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 11,
|
||||
3, 3, 3, 3, 14,
|
||||
}
|
||||
var yyTok2 = [...]int{
|
||||
|
||||
2, 3, 4, 5, 6, 7, 8, 9,
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12,
|
||||
}
|
||||
var yyTok3 = [...]int{
|
||||
0,
|
||||
@ -484,22 +495,37 @@ yydefault:
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line expressions.y:38
|
||||
{
|
||||
yylex.(*lexer).val = yyDollar[2].f
|
||||
}
|
||||
case 4:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:41
|
||||
{
|
||||
name, expr := yyDollar[1].name, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
return &Loop{name, expr(ctx)}
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line expressions.y:40
|
||||
//line expressions.y:50
|
||||
{
|
||||
val := yyDollar[1].val
|
||||
yyVAL.f = func(_ Context) interface{} { return val }
|
||||
}
|
||||
case 4:
|
||||
case 6:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line expressions.y:41
|
||||
//line expressions.y:51
|
||||
{
|
||||
name := yyDollar[1].name
|
||||
yyVAL.f = func(ctx Context) interface{} { return ctx.Get(name) }
|
||||
}
|
||||
case 5:
|
||||
case 7:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:42
|
||||
//line expressions.y:52
|
||||
{
|
||||
e, attr := yyDollar[1].f, yyDollar[3].name
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -515,9 +541,9 @@ yydefault:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case 6:
|
||||
case 8:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:57
|
||||
//line expressions.y:67
|
||||
{
|
||||
e, i := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -536,21 +562,21 @@ yydefault:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
case 10:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:78
|
||||
//line expressions.y:88
|
||||
{
|
||||
yyVAL.f = makeFilter(yyDollar[1].f, yyDollar[3].name, nil)
|
||||
}
|
||||
case 9:
|
||||
case 11:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:79
|
||||
//line expressions.y:89
|
||||
{
|
||||
yyVAL.f = makeFilter(yyDollar[1].f, yyDollar[3].name, yyDollar[4].f)
|
||||
}
|
||||
case 11:
|
||||
case 13:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:84
|
||||
//line expressions.y:94
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -558,9 +584,9 @@ yydefault:
|
||||
return generics.Equal(a, b)
|
||||
}
|
||||
}
|
||||
case 12:
|
||||
case 14:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:91
|
||||
//line expressions.y:101
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -568,9 +594,9 @@ yydefault:
|
||||
return generics.Less(a, b)
|
||||
}
|
||||
}
|
||||
case 13:
|
||||
case 15:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:98
|
||||
//line expressions.y:108
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
|
43
tags/loop.go
Normal file
43
tags/loop.go
Normal file
@ -0,0 +1,43 @@
|
||||
package tags
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/osteele/liquid/chunks"
|
||||
"github.com/osteele/liquid/expressions"
|
||||
)
|
||||
|
||||
func parseLoop(source string) (expressions.Expression, error) {
|
||||
expr, err := expressions.Parse("%loop " + source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return expr, nil
|
||||
}
|
||||
|
||||
func loopTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
|
||||
expr, err := parseLoop(node.Args)
|
||||
if err != nil {
|
||||
return func(io.Writer, chunks.Context) error { return err }
|
||||
}
|
||||
return func(w io.Writer, ctx chunks.Context) error {
|
||||
val, err := ctx.Evaluate(expr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
loop := val.(*expressions.Loop)
|
||||
rt := reflect.ValueOf(loop.Expr)
|
||||
if rt.Kind() != reflect.Array && rt.Kind() != reflect.Slice {
|
||||
return nil
|
||||
}
|
||||
for i := 0; i < rt.Len(); i++ {
|
||||
ctx.Set(loop.Name, rt.Index(i).Interface())
|
||||
err := ctx.RenderASTSequence(w, node.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ func DefineStandardTags() {
|
||||
chunks.DefineControlTag("if").Branch("else").Branch("elsif").Action(ifTagAction(true))
|
||||
chunks.DefineControlTag("unless").SameSyntaxAs("if").Action(ifTagAction(false))
|
||||
chunks.DefineControlTag("case").Branch("when")
|
||||
chunks.DefineControlTag("for").Governs(loopTags)
|
||||
chunks.DefineControlTag("for").Governs(loopTags).Action(loopTag)
|
||||
chunks.DefineControlTag("tablerow").Governs(loopTags)
|
||||
chunks.DefineControlTag("capture")
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ var tagTests = []struct{ in, expected string }{
|
||||
{"{%assign av = 1%}{{av}}", "1"},
|
||||
{"{%assign av = obj.a%}{{av}}", "1"},
|
||||
|
||||
// {"{%for a in ar%}{{a}} {{%endfor%}", "first second third "},
|
||||
{"{%for a in ar%}{{a}} {%endfor%}", "first second third "},
|
||||
}
|
||||
|
||||
var tagTestContext = chunks.NewContext(map[string]interface{}{
|
||||
|
Loading…
x
Reference in New Issue
Block a user