mirror of
https://github.com/danog/liquid.git
synced 2024-11-30 06:08:57 +01:00
Start #2 cycle tag
This commit is contained in:
parent
3c242c40f1
commit
a637d2710a
@ -30,7 +30,8 @@ The [feature parity board](https://github.com/osteele/liquid/projects/1) lists d
|
||||
|
||||
In brief, these aren't implemented:
|
||||
|
||||
- The `cycle` and `tablerow` tags
|
||||
- The group property of the `cycle` tag
|
||||
- The `tablerow` tag
|
||||
- `{% when a or b %}`
|
||||
- Loop ranges `{% for a in 1...10 %}`
|
||||
- Error modes
|
||||
|
@ -16,15 +16,17 @@ func init() {
|
||||
name string
|
||||
val interface{}
|
||||
f func(Context) interface{}
|
||||
arglist []func(Context) interface{}
|
||||
loopmods loopModifiers
|
||||
filter_params []valueFn
|
||||
}
|
||||
%type <f> expr rel filtered cond loop
|
||||
%type<filter_params> filter_params
|
||||
%type<loopmods> loop_modifiers
|
||||
%type<arglist> arglist moreargs
|
||||
%token <val> LITERAL
|
||||
%token <name> IDENTIFIER KEYWORD PROPERTY
|
||||
%token ASSIGN LOOP
|
||||
%token ARGLIST ASSIGN LOOP
|
||||
%token EQ NEQ GE LE FOR IN AND OR CONTAINS
|
||||
%left '.' '|'
|
||||
%left '<' '>'
|
||||
@ -38,10 +40,27 @@ start:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
| LOOP loop { yylex.(*lexer).val = $2 }
|
||||
| ARGLIST arglist ';' {
|
||||
args := $2
|
||||
yylex.(*lexer).val = func(ctx Context) interface{} {
|
||||
result := make([]interface{}, len(args))
|
||||
for i, fn := range args {
|
||||
result[i] = fn(ctx)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
| LOOP loop ';' { yylex.(*lexer).val = $2 }
|
||||
;
|
||||
|
||||
loop: IDENTIFIER IN filtered loop_modifiers ';' {
|
||||
arglist:
|
||||
expr moreargs { $$ = append([]func(Context) interface{}{$1}, $2...) };
|
||||
|
||||
moreargs : /* empty */ { $$ = []func(Context) interface{}{}}
|
||||
| ',' expr moreargs { $$ = append([]func(Context) interface{}{$2}, $3...) }
|
||||
;
|
||||
|
||||
loop: IDENTIFIER IN filtered loop_modifiers {
|
||||
name, expr, mods := $1, $3, $4
|
||||
$$ = func(ctx Context) interface{} {
|
||||
return &Loop{name, expr(ctx), mods}
|
||||
|
@ -7,8 +7,14 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var parseTests = []struct{ in, expected string }{
|
||||
{"a | filter: b", "parse error"},
|
||||
var parseTests = []struct {
|
||||
in string
|
||||
expect interface{}
|
||||
}{
|
||||
{`a | filter: b`, 3},
|
||||
{`%assign a = 3`, nil},
|
||||
{`{%cycle 'a'`, []interface{}{"a"}},
|
||||
{`{%cycle 'a', 'b'`, []interface{}{"a", "b"}},
|
||||
}
|
||||
|
||||
var parseErrorTests = []struct{ in, expected string }{
|
||||
@ -25,7 +31,7 @@ func TestParse(t *testing.T) {
|
||||
require.NoError(t, err, test.in)
|
||||
value, err := expr.Evaluate(ctx)
|
||||
require.NoError(t, err, test.in)
|
||||
require.Equal(t, 3, value, test.in)
|
||||
require.Equal(t, test.expect, value, test.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -10,186 +10,207 @@ var _expression_actions []byte = []byte{
|
||||
1, 16, 1, 17, 1, 18, 1, 19,
|
||||
1, 20, 1, 21, 1, 22, 1, 23,
|
||||
1, 24, 1, 25, 1, 26, 1, 27,
|
||||
1, 28, 2, 2, 3, 2, 2, 4,
|
||||
2, 2, 5, 2, 2, 6, 2, 2,
|
||||
7, 2, 2, 8, 2, 2, 9, 2,
|
||||
2, 10,
|
||||
1, 28, 1, 29, 2, 2, 3, 2,
|
||||
2, 4, 2, 2, 5, 2, 2, 6,
|
||||
2, 2, 7, 2, 2, 8, 2, 2,
|
||||
9, 2, 2, 10,
|
||||
}
|
||||
|
||||
var _expression_key_offsets []int16 = []int16{
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 12, 38, 41, 42, 43,
|
||||
45, 46, 49, 51, 54, 62, 71, 80,
|
||||
81, 82, 83, 93, 94, 105, 116, 127,
|
||||
138, 149, 160, 171, 182, 193, 205, 216,
|
||||
227, 238, 249, 260, 271, 282, 293, 304,
|
||||
8, 9, 10, 11, 12, 14, 15, 16,
|
||||
17, 18, 19, 20, 47, 50, 51, 52,
|
||||
54, 55, 58, 60, 63, 71, 80, 89,
|
||||
90, 91, 92, 102, 103, 114, 125, 136,
|
||||
147, 158, 169, 180, 191, 202, 214, 225,
|
||||
236, 247, 258, 269, 280, 291, 302, 313,
|
||||
324,
|
||||
}
|
||||
|
||||
var _expression_trans_keys []byte = []byte{
|
||||
34, 115, 115, 105, 103, 110, 111, 111,
|
||||
112, 39, 48, 57, 32, 33, 34, 37,
|
||||
34, 115, 115, 105, 103, 110, 32, 111,
|
||||
111, 112, 32, 39, 48, 57, 99, 121,
|
||||
99, 108, 101, 32, 32, 33, 34, 37,
|
||||
39, 45, 46, 60, 61, 62, 95, 97,
|
||||
99, 102, 105, 110, 111, 116, 9, 13,
|
||||
48, 57, 65, 90, 98, 122, 32, 9,
|
||||
13, 61, 34, 97, 108, 39, 46, 48,
|
||||
57, 48, 57, 46, 48, 57, 45, 95,
|
||||
48, 57, 65, 90, 97, 122, 45, 63,
|
||||
99, 102, 105, 110, 111, 116, 123, 9,
|
||||
13, 48, 57, 65, 90, 98, 122, 32,
|
||||
9, 13, 61, 34, 97, 108, 39, 46,
|
||||
48, 57, 48, 57, 46, 48, 57, 45,
|
||||
95, 48, 57, 65, 90, 97, 122, 45,
|
||||
63, 95, 48, 57, 65, 90, 97, 122,
|
||||
61, 61, 61, 45, 58, 63, 95, 48,
|
||||
57, 65, 90, 97, 122, 58, 45, 58,
|
||||
63, 95, 110, 48, 57, 65, 90, 97,
|
||||
122, 45, 58, 63, 95, 100, 48, 57,
|
||||
65, 90, 97, 122, 45, 58, 63, 95,
|
||||
111, 48, 57, 65, 90, 97, 122, 45,
|
||||
45, 63, 95, 48, 57, 65, 90, 97,
|
||||
122, 61, 61, 61, 45, 58, 63, 95,
|
||||
48, 57, 65, 90, 97, 122, 58, 45,
|
||||
58, 63, 95, 110, 48, 57, 65, 90,
|
||||
97, 122, 45, 58, 63, 95, 116, 48,
|
||||
97, 122, 45, 58, 63, 95, 100, 48,
|
||||
57, 65, 90, 97, 122, 45, 58, 63,
|
||||
95, 97, 48, 57, 65, 90, 98, 122,
|
||||
45, 58, 63, 95, 105, 48, 57, 65,
|
||||
90, 97, 122, 45, 58, 63, 95, 110,
|
||||
95, 111, 48, 57, 65, 90, 97, 122,
|
||||
45, 58, 63, 95, 110, 48, 57, 65,
|
||||
90, 97, 122, 45, 58, 63, 95, 116,
|
||||
48, 57, 65, 90, 97, 122, 45, 58,
|
||||
63, 95, 115, 48, 57, 65, 90, 97,
|
||||
122, 45, 58, 63, 95, 97, 111, 48,
|
||||
57, 65, 90, 98, 122, 45, 58, 63,
|
||||
95, 108, 48, 57, 65, 90, 97, 122,
|
||||
45, 58, 63, 95, 115, 48, 57, 65,
|
||||
90, 97, 122, 45, 58, 63, 95, 101,
|
||||
63, 95, 97, 48, 57, 65, 90, 98,
|
||||
122, 45, 58, 63, 95, 105, 48, 57,
|
||||
65, 90, 97, 122, 45, 58, 63, 95,
|
||||
110, 48, 57, 65, 90, 97, 122, 45,
|
||||
58, 63, 95, 115, 48, 57, 65, 90,
|
||||
97, 122, 45, 58, 63, 95, 97, 111,
|
||||
48, 57, 65, 90, 98, 122, 45, 58,
|
||||
63, 95, 108, 48, 57, 65, 90, 97,
|
||||
122, 45, 58, 63, 95, 115, 48, 57,
|
||||
65, 90, 97, 122, 45, 58, 63, 95,
|
||||
101, 48, 57, 65, 90, 97, 122, 45,
|
||||
58, 63, 95, 114, 48, 57, 65, 90,
|
||||
97, 122, 45, 58, 63, 95, 110, 48,
|
||||
57, 65, 90, 97, 122, 45, 58, 63,
|
||||
95, 105, 48, 57, 65, 90, 97, 122,
|
||||
45, 58, 63, 95, 108, 48, 57, 65,
|
||||
90, 97, 122, 45, 58, 63, 95, 114,
|
||||
48, 57, 65, 90, 97, 122, 45, 58,
|
||||
63, 95, 114, 48, 57, 65, 90, 97,
|
||||
122, 45, 58, 63, 95, 110, 48, 57,
|
||||
65, 90, 97, 122, 45, 58, 63, 95,
|
||||
105, 48, 57, 65, 90, 97, 122, 45,
|
||||
58, 63, 95, 108, 48, 57, 65, 90,
|
||||
97, 122, 45, 58, 63, 95, 114, 48,
|
||||
57, 65, 90, 97, 122, 45, 58, 63,
|
||||
95, 114, 48, 57, 65, 90, 97, 122,
|
||||
45, 58, 63, 95, 117, 48, 57, 65,
|
||||
90, 97, 122,
|
||||
122, 45, 58, 63, 95, 117, 48, 57,
|
||||
65, 90, 97, 122, 37,
|
||||
}
|
||||
|
||||
var _expression_single_lengths []byte = []byte{
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 0, 18, 1, 1, 1, 2,
|
||||
1, 1, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 1, 19, 1, 1, 1, 2,
|
||||
1, 1, 0, 1, 2, 3, 3, 1,
|
||||
1, 1, 4, 1, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 6, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5,
|
||||
1,
|
||||
}
|
||||
|
||||
var _expression_range_lengths []byte = []byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 4, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 4, 1, 0, 0, 0,
|
||||
0, 1, 1, 1, 3, 3, 3, 0,
|
||||
0, 0, 3, 0, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3,
|
||||
0,
|
||||
}
|
||||
|
||||
var _expression_index_offsets []int16 = []int16{
|
||||
0, 2, 4, 6, 8, 10, 12, 14,
|
||||
16, 18, 20, 22, 45, 48, 50, 52,
|
||||
55, 57, 60, 62, 65, 71, 78, 85,
|
||||
87, 89, 91, 99, 101, 110, 119, 128,
|
||||
137, 146, 155, 164, 173, 182, 192, 201,
|
||||
210, 219, 228, 237, 246, 255, 264, 273,
|
||||
16, 18, 20, 22, 24, 26, 28, 30,
|
||||
32, 34, 36, 38, 62, 65, 67, 69,
|
||||
72, 74, 77, 79, 82, 88, 95, 102,
|
||||
104, 106, 108, 116, 118, 127, 136, 145,
|
||||
154, 163, 172, 181, 190, 199, 209, 218,
|
||||
227, 236, 245, 254, 263, 272, 281, 290,
|
||||
299,
|
||||
}
|
||||
|
||||
var _expression_indicies []byte = []byte{
|
||||
2, 1, 3, 0, 4, 0, 5, 0,
|
||||
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, 30, 31, 32,
|
||||
14, 21, 25, 25, 13, 14, 14, 33,
|
||||
35, 34, 2, 1, 36, 37, 34, 2,
|
||||
11, 38, 21, 34, 12, 39, 12, 21,
|
||||
40, 41, 41, 42, 41, 41, 34, 41,
|
||||
44, 41, 41, 41, 41, 43, 41, 44,
|
||||
41, 42, 41, 41, 39, 45, 34, 46,
|
||||
34, 47, 34, 25, 49, 50, 25, 25,
|
||||
25, 25, 48, 49, 51, 25, 49, 50,
|
||||
25, 52, 25, 25, 25, 51, 25, 49,
|
||||
50, 25, 53, 25, 25, 25, 51, 25,
|
||||
49, 50, 25, 54, 25, 25, 25, 51,
|
||||
25, 49, 50, 25, 55, 25, 25, 25,
|
||||
51, 25, 49, 50, 25, 56, 25, 25,
|
||||
25, 51, 25, 49, 50, 25, 57, 25,
|
||||
25, 25, 51, 25, 49, 50, 25, 58,
|
||||
25, 25, 25, 51, 25, 49, 50, 25,
|
||||
59, 25, 25, 25, 51, 25, 49, 50,
|
||||
25, 60, 25, 25, 25, 51, 25, 49,
|
||||
50, 25, 61, 62, 25, 25, 25, 51,
|
||||
25, 49, 50, 25, 63, 25, 25, 25,
|
||||
51, 25, 49, 50, 25, 64, 25, 25,
|
||||
25, 51, 25, 49, 50, 25, 65, 25,
|
||||
25, 25, 51, 25, 49, 50, 25, 66,
|
||||
25, 25, 25, 51, 25, 49, 50, 25,
|
||||
67, 25, 25, 25, 51, 25, 49, 50,
|
||||
25, 68, 25, 25, 25, 51, 25, 49,
|
||||
50, 25, 69, 25, 25, 25, 51, 25,
|
||||
49, 50, 25, 70, 25, 25, 25, 51,
|
||||
25, 49, 50, 25, 71, 25, 25, 25,
|
||||
51, 25, 49, 50, 25, 64, 25, 25,
|
||||
25, 51,
|
||||
10, 0, 11, 0, 12, 0, 2, 13,
|
||||
14, 0, 15, 0, 16, 0, 17, 0,
|
||||
18, 0, 19, 0, 20, 0, 22, 23,
|
||||
24, 25, 26, 27, 28, 30, 31, 32,
|
||||
33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 22, 29, 33, 33, 21, 22, 22,
|
||||
42, 44, 43, 2, 1, 45, 46, 43,
|
||||
2, 13, 47, 29, 43, 14, 48, 14,
|
||||
29, 49, 50, 50, 51, 50, 50, 43,
|
||||
50, 53, 50, 50, 50, 50, 52, 50,
|
||||
53, 50, 51, 50, 50, 48, 54, 43,
|
||||
55, 43, 56, 43, 33, 58, 59, 33,
|
||||
33, 33, 33, 57, 58, 60, 33, 58,
|
||||
59, 33, 61, 33, 33, 33, 60, 33,
|
||||
58, 59, 33, 62, 33, 33, 33, 60,
|
||||
33, 58, 59, 33, 63, 33, 33, 33,
|
||||
60, 33, 58, 59, 33, 64, 33, 33,
|
||||
33, 60, 33, 58, 59, 33, 65, 33,
|
||||
33, 33, 60, 33, 58, 59, 33, 66,
|
||||
33, 33, 33, 60, 33, 58, 59, 33,
|
||||
67, 33, 33, 33, 60, 33, 58, 59,
|
||||
33, 68, 33, 33, 33, 60, 33, 58,
|
||||
59, 33, 69, 33, 33, 33, 60, 33,
|
||||
58, 59, 33, 70, 71, 33, 33, 33,
|
||||
60, 33, 58, 59, 33, 72, 33, 33,
|
||||
33, 60, 33, 58, 59, 33, 73, 33,
|
||||
33, 33, 60, 33, 58, 59, 33, 74,
|
||||
33, 33, 33, 60, 33, 58, 59, 33,
|
||||
75, 33, 33, 33, 60, 33, 58, 59,
|
||||
33, 76, 33, 33, 33, 60, 33, 58,
|
||||
59, 33, 77, 33, 33, 33, 60, 33,
|
||||
58, 59, 33, 78, 33, 33, 33, 60,
|
||||
33, 58, 59, 33, 79, 33, 33, 33,
|
||||
60, 33, 58, 59, 33, 80, 33, 33,
|
||||
33, 60, 33, 58, 59, 33, 73, 33,
|
||||
33, 33, 60, 81, 43,
|
||||
}
|
||||
|
||||
var _expression_trans_targs []byte = []byte{
|
||||
11, 0, 11, 2, 3, 4, 5, 11,
|
||||
7, 8, 11, 9, 18, 11, 12, 13,
|
||||
14, 15, 16, 17, 20, 19, 23, 24,
|
||||
25, 26, 28, 30, 37, 42, 43, 45,
|
||||
46, 11, 11, 11, 1, 6, 10, 11,
|
||||
11, 21, 22, 11, 11, 11, 11, 11,
|
||||
11, 11, 27, 11, 29, 26, 31, 32,
|
||||
33, 34, 35, 36, 26, 38, 41, 39,
|
||||
40, 26, 26, 26, 44, 26, 26, 47,
|
||||
19, 0, 19, 2, 3, 4, 5, 6,
|
||||
19, 8, 9, 10, 19, 11, 26, 14,
|
||||
15, 16, 17, 18, 19, 19, 20, 21,
|
||||
22, 23, 24, 25, 28, 27, 31, 32,
|
||||
33, 34, 36, 38, 45, 50, 51, 53,
|
||||
54, 56, 19, 19, 19, 1, 7, 12,
|
||||
19, 19, 29, 30, 19, 19, 19, 19,
|
||||
19, 19, 19, 35, 19, 37, 34, 39,
|
||||
40, 41, 42, 43, 44, 34, 46, 49,
|
||||
47, 48, 34, 34, 34, 52, 34, 34,
|
||||
55, 13,
|
||||
}
|
||||
|
||||
var _expression_trans_actions []byte = []byte{
|
||||
39, 0, 11, 0, 0, 0, 0, 7,
|
||||
0, 0, 9, 0, 0, 25, 0, 0,
|
||||
41, 0, 13, 0, 0, 0, 0, 0,
|
||||
7, 0, 0, 0, 11, 0, 0, 0,
|
||||
0, 0, 0, 0, 9, 27, 0, 0,
|
||||
5, 5, 5, 5, 0, 0, 0, 0,
|
||||
0, 64, 0, 0, 0, 0, 0, 0,
|
||||
0, 35, 37, 15, 0, 0, 0, 29,
|
||||
27, 0, 0, 33, 23, 19, 13, 17,
|
||||
41, 21, 0, 31, 0, 49, 0, 0,
|
||||
0, 0, 0, 0, 55, 0, 0, 0,
|
||||
0, 43, 58, 61, 0, 46, 52, 0,
|
||||
0, 66, 0, 0, 0, 0, 0, 0,
|
||||
0, 5, 37, 39, 17, 0, 0, 0,
|
||||
31, 29, 0, 0, 35, 25, 21, 15,
|
||||
19, 43, 23, 0, 33, 0, 51, 0,
|
||||
0, 0, 0, 0, 0, 57, 0, 0,
|
||||
0, 0, 45, 60, 63, 0, 48, 54,
|
||||
0, 0,
|
||||
}
|
||||
|
||||
var _expression_to_state_actions []byte = []byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 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, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
}
|
||||
|
||||
var _expression_from_state_actions []byte = []byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 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, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
}
|
||||
|
||||
var _expression_eof_trans []int16 = []int16{
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 0, 34, 35, 35, 35,
|
||||
35, 35, 40, 41, 35, 44, 40, 35,
|
||||
35, 35, 49, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 0, 43, 44, 44, 44,
|
||||
44, 44, 49, 50, 44, 53, 49, 44,
|
||||
44, 44, 58, 61, 61, 61, 61, 61,
|
||||
61, 61, 61, 61, 61, 61, 61, 61,
|
||||
61, 61, 61, 61, 61, 61, 61, 61,
|
||||
44,
|
||||
}
|
||||
|
||||
const expression_start int = 11
|
||||
const expression_first_final int = 11
|
||||
const expression_start int = 19
|
||||
const expression_first_final int = 19
|
||||
const expression_error int = -1
|
||||
|
||||
const expression_en_main int = 11
|
||||
const expression_en_main int = 19
|
||||
|
||||
//line scanner.rl:11
|
||||
|
||||
@ -210,7 +231,7 @@ func newLexer(data []byte) *lexer {
|
||||
pe: len(data),
|
||||
}
|
||||
|
||||
//line scanner.go:218
|
||||
//line scanner.go:239
|
||||
{
|
||||
lex.cs = expression_start
|
||||
lex.ts = 0
|
||||
@ -226,7 +247,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
eof := lex.pe
|
||||
tok := 0
|
||||
|
||||
//line scanner.go:235
|
||||
//line scanner.go:256
|
||||
{
|
||||
var _klen int
|
||||
var _trans int
|
||||
@ -247,7 +268,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
//line NONE:1
|
||||
lex.ts = (lex.p)
|
||||
|
||||
//line scanner.go:255
|
||||
//line scanner.go:276
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,28 +345,28 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
|
||||
case 3:
|
||||
//line scanner.rl:38
|
||||
lex.act = 6
|
||||
case 4:
|
||||
//line scanner.rl:88
|
||||
lex.act = 7
|
||||
case 4:
|
||||
//line scanner.rl:89
|
||||
lex.act = 8
|
||||
case 5:
|
||||
//line scanner.rl:93
|
||||
lex.act = 12
|
||||
case 6:
|
||||
//line scanner.rl:94
|
||||
lex.act = 13
|
||||
case 7:
|
||||
case 6:
|
||||
//line scanner.rl:95
|
||||
lex.act = 14
|
||||
case 8:
|
||||
case 7:
|
||||
//line scanner.rl:96
|
||||
lex.act = 15
|
||||
case 9:
|
||||
case 8:
|
||||
//line scanner.rl:97
|
||||
lex.act = 16
|
||||
case 9:
|
||||
//line scanner.rl:98
|
||||
lex.act = 17
|
||||
case 10:
|
||||
//line scanner.rl:43
|
||||
lex.act = 18
|
||||
lex.act = 19
|
||||
case 11:
|
||||
//line scanner.rl:82
|
||||
lex.te = (lex.p) + 1
|
||||
@ -358,11 +379,19 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
//line scanner.rl:83
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = LOOP
|
||||
tok = ARGLIST
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 13:
|
||||
//line scanner.rl:84
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = LOOP
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 14:
|
||||
//line scanner.rl:66
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
@ -373,19 +402,11 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
goto _out
|
||||
|
||||
}
|
||||
case 14:
|
||||
//line scanner.rl:89
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = EQ
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 15:
|
||||
//line scanner.rl:90
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = NEQ
|
||||
tok = EQ
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
@ -393,7 +414,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
//line scanner.rl:91
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = GE
|
||||
tok = NEQ
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
@ -401,12 +422,20 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
//line scanner.rl:92
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = LE
|
||||
tok = GE
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 18:
|
||||
//line scanner.rl:98
|
||||
//line scanner.rl:93
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = LE
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 19:
|
||||
//line scanner.rl:99
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = KEYWORD
|
||||
@ -414,8 +443,8 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 19:
|
||||
//line scanner.rl:100
|
||||
case 20:
|
||||
//line scanner.rl:101
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = PROPERTY
|
||||
@ -423,15 +452,15 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 20:
|
||||
//line scanner.rl:102
|
||||
case 21:
|
||||
//line scanner.rl:103
|
||||
lex.te = (lex.p) + 1
|
||||
{
|
||||
tok = int(lex.data[lex.ts])
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 21:
|
||||
case 22:
|
||||
//line scanner.rl:48
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
@ -446,7 +475,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
goto _out
|
||||
|
||||
}
|
||||
case 22:
|
||||
case 23:
|
||||
//line scanner.rl:57
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
@ -461,7 +490,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
goto _out
|
||||
|
||||
}
|
||||
case 23:
|
||||
case 24:
|
||||
//line scanner.rl:43
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
@ -472,8 +501,8 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
goto _out
|
||||
|
||||
}
|
||||
case 24:
|
||||
//line scanner.rl:100
|
||||
case 25:
|
||||
//line scanner.rl:101
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
{
|
||||
@ -482,32 +511,32 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 25:
|
||||
//line scanner.rl:101
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
|
||||
case 26:
|
||||
//line scanner.rl:102
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
{
|
||||
tok = int(lex.data[lex.ts])
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
|
||||
case 27:
|
||||
//line scanner.rl:102
|
||||
(lex.p) = (lex.te) - 1
|
||||
//line scanner.rl:103
|
||||
lex.te = (lex.p)
|
||||
(lex.p)--
|
||||
{
|
||||
tok = int(lex.data[lex.ts])
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 28:
|
||||
//line scanner.rl:103
|
||||
(lex.p) = (lex.te) - 1
|
||||
{
|
||||
tok = int(lex.data[lex.ts])
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 29:
|
||||
//line NONE:1
|
||||
switch lex.act {
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
|
||||
@ -517,7 +546,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
goto _out
|
||||
|
||||
}
|
||||
case 7:
|
||||
case 8:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
tok = LITERAL
|
||||
@ -525,42 +554,42 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 12:
|
||||
case 13:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
tok = AND
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 13:
|
||||
case 14:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
tok = OR
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
tok = CONTAINS
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 15:
|
||||
case 16:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
tok = FOR
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 16:
|
||||
case 17:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
tok = IN
|
||||
(lex.p)++
|
||||
goto _out
|
||||
}
|
||||
case 18:
|
||||
case 19:
|
||||
{
|
||||
(lex.p) = (lex.te) - 1
|
||||
|
||||
@ -572,7 +601,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
}
|
||||
}
|
||||
|
||||
//line scanner.go:513
|
||||
//line scanner.go:539
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,7 +616,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
//line NONE:1
|
||||
lex.ts = 0
|
||||
|
||||
//line scanner.go:527
|
||||
//line scanner.go:553
|
||||
}
|
||||
}
|
||||
|
||||
@ -610,7 +639,7 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
}
|
||||
}
|
||||
|
||||
//line scanner.rl:106
|
||||
//line scanner.rl:107
|
||||
|
||||
return tok
|
||||
}
|
||||
|
@ -79,8 +79,9 @@ func (lex *lexer) Lex(out *yySymType) int {
|
||||
string = '"' (any - '"')* '"' | "'" (any - "'")* "'" ; # TODO escapes
|
||||
|
||||
main := |*
|
||||
"%assign" => { tok = ASSIGN; fbreak; };
|
||||
"%loop" => { tok = LOOP; fbreak; };
|
||||
"%assign " => { tok = ASSIGN; fbreak; };
|
||||
"{%cycle " => { tok = ARGLIST; fbreak; };
|
||||
"%loop " => { tok = LOOP; fbreak; };
|
||||
int => Int;
|
||||
float => Float;
|
||||
string => String;
|
||||
|
@ -83,4 +83,7 @@ func TestLex(t *testing.T) {
|
||||
require.Equal(t, "ab_c", ts[1].typ.name)
|
||||
require.Equal(t, "ab-c", ts[2].typ.name)
|
||||
require.Equal(t, "abc?", ts[3].typ.name)
|
||||
|
||||
ts, _ = scanExpression(`{%cycle 'a', 'b'`)
|
||||
require.Len(t, ts, 4)
|
||||
}
|
||||
|
241
expression/y.go
241
expression/y.go
@ -21,6 +21,7 @@ type yySymType struct {
|
||||
name string
|
||||
val interface{}
|
||||
f func(Context) interface{}
|
||||
arglist []func(Context) interface{}
|
||||
loopmods loopModifiers
|
||||
filter_params []valueFn
|
||||
}
|
||||
@ -29,17 +30,18 @@ const LITERAL = 57346
|
||||
const IDENTIFIER = 57347
|
||||
const KEYWORD = 57348
|
||||
const PROPERTY = 57349
|
||||
const ASSIGN = 57350
|
||||
const LOOP = 57351
|
||||
const EQ = 57352
|
||||
const NEQ = 57353
|
||||
const GE = 57354
|
||||
const LE = 57355
|
||||
const FOR = 57356
|
||||
const IN = 57357
|
||||
const AND = 57358
|
||||
const OR = 57359
|
||||
const CONTAINS = 57360
|
||||
const ARGLIST = 57350
|
||||
const ASSIGN = 57351
|
||||
const LOOP = 57352
|
||||
const EQ = 57353
|
||||
const NEQ = 57354
|
||||
const GE = 57355
|
||||
const LE = 57356
|
||||
const FOR = 57357
|
||||
const IN = 57358
|
||||
const AND = 57359
|
||||
const OR = 57360
|
||||
const CONTAINS = 57361
|
||||
|
||||
var yyToknames = [...]string{
|
||||
"$end",
|
||||
@ -49,6 +51,7 @@ var yyToknames = [...]string{
|
||||
"IDENTIFIER",
|
||||
"KEYWORD",
|
||||
"PROPERTY",
|
||||
"ARGLIST",
|
||||
"ASSIGN",
|
||||
"LOOP",
|
||||
"EQ",
|
||||
@ -66,11 +69,11 @@ var yyToknames = [...]string{
|
||||
"'>'",
|
||||
"';'",
|
||||
"'='",
|
||||
"','",
|
||||
"'['",
|
||||
"']'",
|
||||
"'('",
|
||||
"')'",
|
||||
"','",
|
||||
}
|
||||
var yyStatenames = [...]string{}
|
||||
|
||||
@ -87,60 +90,67 @@ var yyExca = [...]int{
|
||||
|
||||
const yyPrivate = 57344
|
||||
|
||||
const yyLast = 67
|
||||
const yyLast = 77
|
||||
|
||||
var yyAct = [...]int{
|
||||
|
||||
7, 18, 51, 30, 20, 21, 24, 25, 6, 17,
|
||||
8, 9, 26, 8, 9, 23, 22, 3, 4, 19,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 18, 12,
|
||||
13, 44, 44, 10, 47, 18, 10, 53, 54, 43,
|
||||
45, 42, 12, 13, 31, 17, 19, 48, 49, 11,
|
||||
5, 2, 55, 19, 16, 52, 32, 33, 14, 56,
|
||||
1, 50, 27, 28, 29, 46, 15,
|
||||
8, 35, 21, 60, 7, 17, 23, 24, 27, 28,
|
||||
9, 10, 33, 37, 29, 9, 10, 26, 25, 4,
|
||||
3, 5, 22, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 13, 14, 21, 51, 11, 21, 52, 50, 51,
|
||||
11, 55, 21, 53, 49, 34, 20, 2, 13, 14,
|
||||
38, 6, 36, 22, 58, 12, 22, 56, 19, 30,
|
||||
20, 63, 22, 57, 15, 31, 32, 61, 62, 39,
|
||||
40, 64, 1, 16, 59, 54, 18,
|
||||
}
|
||||
var yyPact = [...]int{
|
||||
|
||||
9, -1000, 26, 53, 49, -1000, -11, -6, -1000, -1000,
|
||||
6, -1000, 6, 6, -21, -1000, 29, 51, -1000, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 13, -1000, -1000,
|
||||
6, 6, -1000, 6, 21, 28, 28, 28, 28, 28,
|
||||
28, 28, -1000, 25, 28, -11, -27, 28, -1000, -1000,
|
||||
32, 6, -1000, -1000, 55, 28, -1000,
|
||||
11, -1000, 31, 59, 6, 53, -1000, 25, -5, -1000,
|
||||
-1000, 6, -1000, 6, 6, -13, 21, 26, -11, 34,
|
||||
64, -1000, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
14, -1000, -1000, 6, -1000, -1000, 6, -1000, 6, -1000,
|
||||
6, 29, 35, 35, 35, 35, 35, 35, 35, -1000,
|
||||
39, 35, 26, 25, -23, 35, -1000, -1000, -1000, 62,
|
||||
6, -1000, 67, 35, -1000,
|
||||
}
|
||||
var yyPgo = [...]int{
|
||||
|
||||
0, 0, 50, 8, 51, 66, 65, 61, 60,
|
||||
0, 0, 51, 4, 47, 76, 75, 74, 73, 1,
|
||||
72,
|
||||
}
|
||||
var yyR1 = [...]int{
|
||||
|
||||
0, 8, 8, 8, 5, 7, 7, 7, 1, 1,
|
||||
1, 1, 1, 3, 3, 3, 6, 6, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 4, 4,
|
||||
0, 10, 10, 10, 10, 8, 9, 9, 5, 7,
|
||||
7, 7, 1, 1, 1, 1, 1, 3, 3, 3,
|
||||
6, 6, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
4, 4, 4,
|
||||
}
|
||||
var yyR2 = [...]int{
|
||||
|
||||
0, 2, 5, 2, 5, 0, 2, 3, 1, 1,
|
||||
2, 4, 3, 1, 3, 4, 1, 3, 1, 3,
|
||||
3, 3, 3, 3, 3, 3, 1, 3, 3,
|
||||
0, 2, 5, 3, 3, 2, 0, 3, 4, 0,
|
||||
2, 3, 1, 1, 2, 4, 3, 1, 3, 4,
|
||||
1, 3, 1, 3, 3, 3, 3, 3, 3, 3,
|
||||
1, 3, 3,
|
||||
}
|
||||
var yyChk = [...]int{
|
||||
|
||||
-1000, -8, -4, 8, 9, -2, -3, -1, 4, 5,
|
||||
27, 23, 16, 17, 5, -5, 5, 20, 7, 25,
|
||||
10, 11, 22, 21, 12, 13, 18, -4, -2, -2,
|
||||
24, 15, 5, 6, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 28, -3, -1, -3, -6, -1, 26, 23,
|
||||
-7, 29, 23, 5, 6, -1, 4,
|
||||
-1000, -10, -4, 9, 8, 10, -2, -3, -1, 4,
|
||||
5, 29, 24, 17, 18, 5, -8, -1, -5, 5,
|
||||
21, 7, 27, 11, 12, 23, 22, 13, 14, 19,
|
||||
-4, -2, -2, 25, 24, -9, 26, 24, 16, 5,
|
||||
6, -1, -1, -1, -1, -1, -1, -1, -1, 30,
|
||||
-3, -1, -1, -3, -6, -1, 28, 24, -9, -7,
|
||||
26, 5, 6, -1, 4,
|
||||
}
|
||||
var yyDef = [...]int{
|
||||
|
||||
0, -2, 0, 0, 0, 26, 18, 13, 8, 9,
|
||||
0, 1, 0, 0, 0, 3, 0, 0, 10, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 27, 28,
|
||||
0, 0, 14, 0, 0, 19, 20, 21, 22, 23,
|
||||
24, 25, 12, 0, 13, 5, 15, 16, 11, 2,
|
||||
0, 0, 4, 6, 0, 17, 7,
|
||||
0, -2, 0, 0, 0, 0, 30, 22, 17, 12,
|
||||
13, 0, 1, 0, 0, 0, 0, 6, 0, 0,
|
||||
0, 14, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 31, 32, 0, 3, 5, 0, 4, 0, 18,
|
||||
0, 0, 23, 24, 25, 26, 27, 28, 29, 16,
|
||||
0, 17, 6, 9, 19, 20, 15, 2, 7, 8,
|
||||
0, 10, 0, 21, 11,
|
||||
}
|
||||
var yyTok1 = [...]int{
|
||||
|
||||
@ -148,20 +158,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,
|
||||
27, 28, 3, 3, 29, 3, 19, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 23,
|
||||
21, 24, 22, 3, 3, 3, 3, 3, 3, 3,
|
||||
29, 30, 3, 3, 26, 3, 20, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 24,
|
||||
22, 25, 23, 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, 25, 3, 26, 3, 3, 3, 3, 3, 3,
|
||||
3, 27, 3, 28, 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, 20,
|
||||
3, 3, 3, 3, 21,
|
||||
}
|
||||
var yyTok2 = [...]int{
|
||||
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18,
|
||||
12, 13, 14, 15, 16, 17, 18, 19,
|
||||
}
|
||||
var yyTok3 = [...]int{
|
||||
0,
|
||||
@ -506,13 +516,13 @@ yydefault:
|
||||
|
||||
case 1:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line expressions.y:33
|
||||
//line expressions.y:35
|
||||
{
|
||||
yylex.(*lexer).val = yyDollar[1].f
|
||||
}
|
||||
case 2:
|
||||
yyDollar = yyS[yypt-5 : yypt+1]
|
||||
//line expressions.y:34
|
||||
//line expressions.y:36
|
||||
{
|
||||
name, expr := yyDollar[2].name, yyDollar[4].f
|
||||
yylex.(*lexer).val = func(ctx Context) interface{} {
|
||||
@ -521,29 +531,60 @@ yydefault:
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line expressions.y:41
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:43
|
||||
{
|
||||
args := yyDollar[2].arglist
|
||||
yylex.(*lexer).val = func(ctx Context) interface{} {
|
||||
result := make([]interface{}, len(args))
|
||||
for i, fn := range args {
|
||||
result[i] = fn(ctx)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:53
|
||||
{
|
||||
yylex.(*lexer).val = yyDollar[2].f
|
||||
}
|
||||
case 4:
|
||||
yyDollar = yyS[yypt-5 : yypt+1]
|
||||
//line expressions.y:44
|
||||
case 5:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line expressions.y:57
|
||||
{
|
||||
yyVAL.arglist = append([]func(Context) interface{}{yyDollar[1].f}, yyDollar[2].arglist...)
|
||||
}
|
||||
case 6:
|
||||
yyDollar = yyS[yypt-0 : yypt+1]
|
||||
//line expressions.y:59
|
||||
{
|
||||
yyVAL.arglist = []func(Context) interface{}{}
|
||||
}
|
||||
case 7:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:60
|
||||
{
|
||||
yyVAL.arglist = append([]func(Context) interface{}{yyDollar[2].f}, yyDollar[3].arglist...)
|
||||
}
|
||||
case 8:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:63
|
||||
{
|
||||
name, expr, mods := yyDollar[1].name, yyDollar[3].f, yyDollar[4].loopmods
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
return &Loop{name, expr(ctx), mods}
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
case 9:
|
||||
yyDollar = yyS[yypt-0 : yypt+1]
|
||||
//line expressions.y:52
|
||||
//line expressions.y:71
|
||||
{
|
||||
yyVAL.loopmods = loopModifiers{}
|
||||
}
|
||||
case 6:
|
||||
case 10:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line expressions.y:53
|
||||
//line expressions.y:72
|
||||
{
|
||||
switch yyDollar[2].name {
|
||||
case "reversed":
|
||||
@ -553,9 +594,9 @@ yydefault:
|
||||
}
|
||||
yyVAL.loopmods = yyDollar[1].loopmods
|
||||
}
|
||||
case 7:
|
||||
case 11:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:62
|
||||
//line expressions.y:81
|
||||
{ // TODO can this be a variable?
|
||||
switch yyDollar[2].name {
|
||||
case "limit":
|
||||
@ -575,65 +616,65 @@ yydefault:
|
||||
}
|
||||
yyVAL.loopmods = yyDollar[1].loopmods
|
||||
}
|
||||
case 8:
|
||||
case 12:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line expressions.y:84
|
||||
//line expressions.y:103
|
||||
{
|
||||
val := yyDollar[1].val
|
||||
yyVAL.f = func(_ Context) interface{} { return val }
|
||||
}
|
||||
case 9:
|
||||
case 13:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line expressions.y:85
|
||||
//line expressions.y:104
|
||||
{
|
||||
name := yyDollar[1].name
|
||||
yyVAL.f = func(ctx Context) interface{} { return ctx.Get(name) }
|
||||
}
|
||||
case 10:
|
||||
case 14:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line expressions.y:86
|
||||
//line expressions.y:105
|
||||
{
|
||||
yyVAL.f = makeObjectPropertyExpr(yyDollar[1].f, yyDollar[2].name)
|
||||
}
|
||||
case 11:
|
||||
case 15:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:87
|
||||
//line expressions.y:106
|
||||
{
|
||||
yyVAL.f = makeIndexExpr(yyDollar[1].f, yyDollar[3].f)
|
||||
}
|
||||
case 12:
|
||||
case 16:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:88
|
||||
//line expressions.y:107
|
||||
{
|
||||
yyVAL.f = yyDollar[2].f
|
||||
}
|
||||
case 14:
|
||||
case 18:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:93
|
||||
//line expressions.y:112
|
||||
{
|
||||
yyVAL.f = makeFilter(yyDollar[1].f, yyDollar[3].name, nil)
|
||||
}
|
||||
case 15:
|
||||
case 19:
|
||||
yyDollar = yyS[yypt-4 : yypt+1]
|
||||
//line expressions.y:94
|
||||
//line expressions.y:113
|
||||
{
|
||||
yyVAL.f = makeFilter(yyDollar[1].f, yyDollar[3].name, yyDollar[4].filter_params)
|
||||
}
|
||||
case 16:
|
||||
case 20:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line expressions.y:98
|
||||
//line expressions.y:117
|
||||
{
|
||||
yyVAL.filter_params = []valueFn{yyDollar[1].f}
|
||||
}
|
||||
case 17:
|
||||
case 21:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:100
|
||||
//line expressions.y:119
|
||||
{
|
||||
yyVAL.filter_params = append(yyDollar[1].filter_params, yyDollar[3].f)
|
||||
}
|
||||
case 19:
|
||||
case 23:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:104
|
||||
//line expressions.y:123
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -641,9 +682,9 @@ yydefault:
|
||||
return evaluator.Equal(a, b)
|
||||
}
|
||||
}
|
||||
case 20:
|
||||
case 24:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:111
|
||||
//line expressions.y:130
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -651,9 +692,9 @@ yydefault:
|
||||
return !evaluator.Equal(a, b)
|
||||
}
|
||||
}
|
||||
case 21:
|
||||
case 25:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:118
|
||||
//line expressions.y:137
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -661,9 +702,9 @@ yydefault:
|
||||
return evaluator.Less(b, a)
|
||||
}
|
||||
}
|
||||
case 22:
|
||||
case 26:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:125
|
||||
//line expressions.y:144
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -671,9 +712,9 @@ yydefault:
|
||||
return evaluator.Less(a, b)
|
||||
}
|
||||
}
|
||||
case 23:
|
||||
case 27:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:132
|
||||
//line expressions.y:151
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -681,9 +722,9 @@ yydefault:
|
||||
return evaluator.Less(b, a) || evaluator.Equal(a, b)
|
||||
}
|
||||
}
|
||||
case 24:
|
||||
case 28:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:139
|
||||
//line expressions.y:158
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
@ -691,24 +732,24 @@ yydefault:
|
||||
return evaluator.Less(a, b) || evaluator.Equal(a, b)
|
||||
}
|
||||
}
|
||||
case 25:
|
||||
case 29:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:146
|
||||
//line expressions.y:165
|
||||
{
|
||||
yyVAL.f = makeContainsExpr(yyDollar[1].f, yyDollar[3].f)
|
||||
}
|
||||
case 27:
|
||||
case 31:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:151
|
||||
//line expressions.y:170
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
return evaluator.IsTrue(fa(ctx)) && evaluator.IsTrue(fb(ctx))
|
||||
}
|
||||
}
|
||||
case 28:
|
||||
case 32:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line expressions.y:157
|
||||
//line expressions.y:176
|
||||
{
|
||||
fa, fb := yyDollar[1].f, yyDollar[3].f
|
||||
yyVAL.f = func(ctx Context) interface{} {
|
||||
|
@ -15,10 +15,10 @@ func addCompilerTestTags(s Config) {
|
||||
}
|
||||
|
||||
var compilerErrorTests = []struct{ in, expected string }{
|
||||
{"{% unknown_tag %}", "unknown tag"},
|
||||
{`{% unknown_tag %}`, "unknown tag"},
|
||||
{`{% block %}{% endblock %}`, "block compiler error"},
|
||||
// {`{% tag %}`, "tag compiler error"},
|
||||
// {"{%for syntax error%}{%endfor%}", "parse error"},
|
||||
// {`{%for syntax error%}{%endfor%}`, "parse error"},
|
||||
}
|
||||
|
||||
func TestCompileErrors(t *testing.T) {
|
||||
|
@ -9,21 +9,54 @@ import (
|
||||
"github.com/osteele/liquid/render"
|
||||
)
|
||||
|
||||
const forloopVarName = "forloop"
|
||||
|
||||
var errLoopContinueLoop = fmt.Errorf("continue outside a loop")
|
||||
var errLoopBreak = fmt.Errorf("break outside a loop")
|
||||
|
||||
func breakTag(parameters string) (func(io.Writer, render.Context) error, error) {
|
||||
func breakTag(string) (func(io.Writer, render.Context) error, error) {
|
||||
return func(_ io.Writer, ctx render.Context) error {
|
||||
return ctx.WrapError(errLoopBreak)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func continueTag(parameters string) (func(io.Writer, render.Context) error, error) {
|
||||
func continueTag(string) (func(io.Writer, render.Context) error, error) {
|
||||
return func(_ io.Writer, ctx render.Context) error {
|
||||
return ctx.WrapError(errLoopContinueLoop)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func cycleTag(args string) (func(io.Writer, render.Context) error, error) {
|
||||
return func(w io.Writer, ctx render.Context) error {
|
||||
expr, err := expression.Parse("{%cycle " + args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value, err := ctx.Evaluate(expr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
array := value.([]interface{})
|
||||
if len(array) == 0 {
|
||||
return nil
|
||||
}
|
||||
loopVar := ctx.Get(forloopVarName)
|
||||
if loopVar == nil {
|
||||
return ctx.Errorf("cycle must be within a forloop")
|
||||
}
|
||||
// the next few lines could panic if the user spoofs us by creating their own loop object
|
||||
// “C++ protects against accident, not against fraud.” – Bjarne Stroustrup
|
||||
loopRec := loopVar.(map[string]interface{})
|
||||
cycleMap := loopRec[".cycles"].(map[string]int)
|
||||
group := ""
|
||||
n := cycleMap[group]
|
||||
cycleMap[group] = n + 1
|
||||
fmt.Println(cycleMap)
|
||||
_, err = w.Write([]byte(fmt.Sprint(array[n%len(array)])))
|
||||
return err
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseLoopExpression(source string) (expression.Expression, error) {
|
||||
expr, err := expression.Parse("%loop " + source)
|
||||
if err != nil {
|
||||
@ -69,11 +102,11 @@ func loopTagParser(node render.BlockNode) (func(io.Writer, render.Context) error
|
||||
length = rt.Len()
|
||||
}
|
||||
}
|
||||
const forloopName = "forloop"
|
||||
defer func(index, forloop interface{}) {
|
||||
ctx.Set(forloopName, index)
|
||||
ctx.Set(forloopVarName, index)
|
||||
ctx.Set(loop.Variable, forloop)
|
||||
}(ctx.Get(forloopName), ctx.Get(loop.Variable))
|
||||
}(ctx.Get(forloopVarName), ctx.Get(loop.Variable))
|
||||
cycleMap := map[string]int{}
|
||||
loop:
|
||||
for i := 0; i < length; i++ {
|
||||
j := i
|
||||
@ -81,7 +114,7 @@ func loopTagParser(node render.BlockNode) (func(io.Writer, render.Context) error
|
||||
j = rt.Len() - 1 - i
|
||||
}
|
||||
ctx.Set(loop.Variable, rt.Index(j).Interface())
|
||||
ctx.Set(forloopName, map[string]interface{}{
|
||||
ctx.Set(forloopVarName, map[string]interface{}{
|
||||
"first": i == 0,
|
||||
"last": i == length-1,
|
||||
"index": i + 1,
|
||||
@ -89,6 +122,7 @@ func loopTagParser(node render.BlockNode) (func(io.Writer, render.Context) error
|
||||
"rindex": length - i,
|
||||
"rindex0": length - i - 1,
|
||||
"length": length,
|
||||
".cycles": cycleMap,
|
||||
})
|
||||
err := ctx.RenderChildren(w)
|
||||
switch {
|
||||
|
@ -55,7 +55,11 @@ var loopTests = []struct{ in, expected string }{
|
||||
{`{% for a in array %}{% if a == 'second' %}{% break %}{% endif %}{{ a }}{% endfor %}`, "first"},
|
||||
{`{% for a in array %}{% if a == 'second' %}{% continue %}{% endif %}{{ a }}.{% endfor %}`, "first.third."},
|
||||
|
||||
// hash
|
||||
{`{% for a in hash %}{{ a }}{% endfor %}`, "a"},
|
||||
|
||||
// cycle
|
||||
{`{% for a in array %}{% cycle 'even', 'odd' %}.{% endfor %}`, "even.odd.even."},
|
||||
}
|
||||
|
||||
var loopErrorTests = []struct{ in, expected string }{
|
||||
|
@ -19,6 +19,7 @@ func AddStandardTags(c render.Config) {
|
||||
// but it ignores any syntax specified here.
|
||||
c.AddTag("break", breakTag)
|
||||
c.AddTag("continue", continueTag)
|
||||
c.AddTag("cycle", cycleTag)
|
||||
c.AddBlock("capture").Compiler(captureTagParser)
|
||||
c.AddBlock("case").Clause("when").Clause("else").Compiler(caseTagParser)
|
||||
c.AddBlock("comment")
|
||||
|
Loading…
Reference in New Issue
Block a user