1
0
mirror of https://github.com/danog/liquid.git synced 2025-01-23 02:01:11 +01:00

Functional is constructed within parser, not scanner

This commit is contained in:
Oliver Steele 2017-06-25 20:47:31 -04:00
parent 6af4fca71b
commit c02fbd57ac
6 changed files with 57 additions and 40 deletions

View File

@ -33,8 +33,8 @@ type ASTControlTag struct {
branches []*ASTControlTag branches []*ASTControlTag
} }
func (n ASTSeq) String() string { func MustYAML(val interface{}) string {
b, err := yaml.Marshal(n) b, err := yaml.Marshal(val)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"fmt"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -13,16 +14,18 @@ func TestChunkParser(t *testing.T) {
}, },
} }
for _, test := range chunkTests { for i, test := range chunkTests {
tokens := ScanChunks(test.in, "") t.Run(fmt.Sprint(i), func(t *testing.T) {
// fmt.Println(tokens) tokens := ScanChunks(test.in, "")
ast, err := Parse(tokens) // fmt.Println(tokens)
require.NoError(t, err, test.in) ast, err := Parse(tokens)
// fmt.Println("%#v", ast) require.NoErrorf(t, err, test.in)
buf := new(bytes.Buffer) // fmt.Println(MustYAML(ast))
err = ast.Render(buf, ctx) buf := new(bytes.Buffer)
require.NoError(t, err, test.in) err = ast.Render(buf, ctx)
require.Equal(t, test.expected, buf.String(), test.in) require.NoErrorf(t, err, test.in)
require.Equalf(t, test.expected, buf.String(), test.in)
})
} }
} }

View File

@ -6,12 +6,15 @@ import (
%} %}
%union { %union {
name string name string
val func(Context) interface{} val interface{}
f func(Context) interface{}
} }
%type <val> expr %type <f> expr
%token <val> LITERAL IDENTIFIER %token <val> LITERAL
%token <name> RELATION %token <name> IDENTIFIER RELATION
%% %%
top: expr { yylex.(*lexer).val = $1 }; top: expr { yylex.(*lexer).val = $1 };
expr: LITERAL | IDENTIFIER; expr:
LITERAL { $$ = func(_ Context) interface{} { return $1 } }
| IDENTIFIER { $$ = func(ctx Context) interface{} { return ctx.Variables[$1] } }

View File

@ -263,18 +263,18 @@ _eof_trans:
//line scanner.rl:36 //line scanner.rl:36
lex.act = 2; lex.act = 2;
case 4: case 4:
//line scanner.rl:56 //line scanner.rl:55
lex.act = 4; lex.act = 4;
case 5: case 5:
//line scanner.rl:41 //line scanner.rl:41
lex.act = 5; lex.act = 5;
case 6: case 6:
//line scanner.rl:56 //line scanner.rl:55
lex.te = ( lex.p)+1 lex.te = ( lex.p)+1
{ tok = RELATION; out.name = string(lex.data[lex.ts:lex.te]); ( lex.p)++; goto _out { tok = RELATION; out.name = string(lex.data[lex.ts:lex.te]); ( lex.p)++; goto _out
} }
case 7: case 7:
//line scanner.rl:47 //line scanner.rl:46
lex.te = ( lex.p) lex.te = ( lex.p)
( lex.p)-- ( lex.p)--
{ {
@ -283,12 +283,12 @@ _eof_trans:
if err != nil { if err != nil {
panic(err) panic(err)
} }
out.val = func(_ Context) interface{} { return n } out.val = n
( lex.p)++; goto _out ( lex.p)++; goto _out
} }
case 8: case 8:
//line scanner.rl:56 //line scanner.rl:55
lex.te = ( lex.p) lex.te = ( lex.p)
( lex.p)-- ( lex.p)--
{ tok = RELATION; out.name = string(lex.data[lex.ts:lex.te]); ( lex.p)++; goto _out { tok = RELATION; out.name = string(lex.data[lex.ts:lex.te]); ( lex.p)++; goto _out
@ -299,13 +299,12 @@ _eof_trans:
( lex.p)-- ( lex.p)--
{ {
tok = IDENTIFIER tok = IDENTIFIER
name := string(lex.data[lex.ts:lex.te]) out.name = string(lex.data[lex.ts:lex.te])
out.val = func(ctx Context) interface{} { return ctx.Variables[name] }
( lex.p)++; goto _out ( lex.p)++; goto _out
} }
case 10: case 10:
//line scanner.rl:67 //line scanner.rl:66
lex.te = ( lex.p) lex.te = ( lex.p)
( lex.p)-- ( lex.p)--
@ -316,8 +315,9 @@ _eof_trans:
{( lex.p) = ( lex.te) - 1 {( lex.p) = ( lex.te) - 1
tok = LITERAL tok = LITERAL
val := string(lex.data[lex.ts:lex.te]) == "true" out.val = string(lex.data[lex.ts:lex.te]) == "true"
out.val = func(_ Context) interface{} { return val } ( lex.p)++; goto _out
} }
case 4: case 4:
{( lex.p) = ( lex.te) - 1 {( lex.p) = ( lex.te) - 1
@ -327,14 +327,13 @@ _eof_trans:
{( lex.p) = ( lex.te) - 1 {( lex.p) = ( lex.te) - 1
tok = IDENTIFIER tok = IDENTIFIER
name := string(lex.data[lex.ts:lex.te]) out.name = string(lex.data[lex.ts:lex.te])
out.val = func(ctx Context) interface{} { return ctx.Variables[name] }
( lex.p)++; goto _out ( lex.p)++; goto _out
} }
} }
//line scanner.go:338 //line scanner.go:337
} }
} }
@ -348,7 +347,7 @@ _again:
//line NONE:1 //line NONE:1
lex.ts = 0 lex.ts = 0
//line scanner.go:352 //line scanner.go:351
} }
} }
@ -370,7 +369,7 @@ _again:
_out: {} _out: {}
} }
//line scanner.rl:71 //line scanner.rl:70
return tok return tok

View File

@ -35,13 +35,12 @@ func (lex *lexer) Lex(out *yySymType) int {
%%{ %%{
action Bool { action Bool {
tok = LITERAL tok = LITERAL
val := string(lex.data[lex.ts:lex.te]) == "true" out.val = string(lex.data[lex.ts:lex.te]) == "true"
out.val = func(_ Context) interface{} { return val } fbreak;
} }
action Ident { action Ident {
tok = IDENTIFIER tok = IDENTIFIER
name := string(lex.data[lex.ts:lex.te]) out.name = string(lex.data[lex.ts:lex.te])
out.val = func(ctx Context) interface{} { return ctx.Variables[name] }
fbreak; fbreak;
} }
action Number { action Number {
@ -50,7 +49,7 @@ func (lex *lexer) Lex(out *yySymType) int {
if err != nil { if err != nil {
panic(err) panic(err)
} }
out.val = func(_ Context) interface{} { return n } out.val = n
fbreak; fbreak;
} }
action Relation { tok = RELATION; out.name = string(lex.data[lex.ts:lex.te]); fbreak; } action Relation { tok = RELATION; out.name = string(lex.data[lex.ts:lex.te]); fbreak; }

19
y.go
View File

@ -12,7 +12,8 @@ import (
type yySymType struct { type yySymType struct {
yys int yys int
name string name string
val func(Context) interface{} val interface{}
f func(Context) interface{}
} }
const LITERAL = 57346 const LITERAL = 57346
@ -423,9 +424,21 @@ yydefault:
case 1: case 1:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line expression_parser.y:15 //line expression_parser.y:16
{ {
yylex.(*lexer).val = yyDollar[1].val yylex.(*lexer).val = yyDollar[1].f
}
case 2:
yyDollar = yyS[yypt-1 : yypt+1]
//line expression_parser.y:19
{
yyVAL.f = func(_ Context) interface{} { return yyDollar[1].val }
}
case 3:
yyDollar = yyS[yypt-1 : yypt+1]
//line expression_parser.y:20
{
yyVAL.f = func(ctx Context) interface{} { return ctx.Variables[yyDollar[1].name] }
} }
} }
goto yystack /* stack new state and value */ goto yystack /* stack new state and value */