1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-27 03:14:39 +01:00

Parse control tag forms at parse time

This commit is contained in:
Oliver Steele 2017-06-28 21:45:24 -04:00
parent 61663ab11a
commit 5dddabeb78
4 changed files with 50 additions and 7 deletions

View File

@ -47,6 +47,7 @@ type ASTObject struct {
// ASTControlTag is a control tag.
type ASTControlTag struct {
Chunk
renderer func(io.Writer, Context) error
cd *controlTagDefinition
Body []ASTNode
Branches []*ASTControlTag

View File

@ -68,6 +68,13 @@ func Parse(chunks []Chunk) (ASTNode, error) {
ccn.Branches = append(ccn.Branches, n)
ap = &n.Body
case cd.isEndTag:
// if ccn != nil && cd.parser != nil {
// renderer, err := cd.parser(*ccn)
// if err != nil {
// return nil, err
// }
// ccn.renderer = renderer
// }
f := stack[len(stack)-1]
stack = stack[:len(stack)-1]
ccd, ccn, ap = f.cd, f.cn, f.ap
@ -96,8 +103,42 @@ func Parse(chunks []Chunk) (ASTNode, error) {
if ccd != nil {
return nil, fmt.Errorf("unterminated %s tag", ccd.name)
}
if err := evaluateBuilders(root); err != nil {
return nil, err
}
if len(root.Children) == 1 {
return root.Children[0], nil
}
return root, nil
}
func evaluateBuilders(n ASTNode) error {
switch n := n.(type) {
case *ASTControlTag:
for _, child := range n.Body {
if err := evaluateBuilders(child); err != nil {
return err
}
}
for _, branch := range n.Branches {
if err := evaluateBuilders(branch); err != nil {
return err
}
}
cd, ok := findControlTagDefinition(n.Tag)
if ok && cd.parser != nil {
renderer, err := cd.parser(*n)
if err != nil {
return err
}
n.renderer = renderer
}
case *ASTSeq:
for _, child := range n.Children {
if error := evaluateBuilders(child); error != nil {
return error
}
}
}
return nil
}

View File

@ -18,7 +18,7 @@ func init() {
var parseErrorTests = []struct{ in, expected string }{
{"{%unknown_tag%}", "unknown tag"},
{"{%if test%}", "unterminated if tag"},
// {"{%if syntax error%}{%endif%}", "parse error"},
// {"{%for syntax error%}{%endfor%}", "parse error"},
}
var parserTests = []struct{ in string }{
@ -30,7 +30,7 @@ var parserTests = []struct{ in string }{
func TestParseErrors(t *testing.T) {
for i, test := range parseErrorTests {
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
tokens := Scan(test.in, "")
ast, err := Parse(tokens)
require.Nilf(t, ast, test.in)
@ -42,7 +42,7 @@ func TestParseErrors(t *testing.T) {
func TestParser(t *testing.T) {
for i, test := range parserTests {
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
tokens := Scan(test.in, "")
_, err := Parse(tokens)
require.NoError(t, err, test.in)

View File

@ -56,11 +56,12 @@ func (n *ASTControlTag) Render(w io.Writer, ctx Context) error {
if !ok || cd.parser == nil {
return fmt.Errorf("unimplemented tag: %s", n.Tag)
}
f, err := cd.parser(*n)
if err != nil {
return err
renderer := n.renderer
if renderer == nil {
panic(fmt.Errorf("unset renderer for %v", n))
return nil
}
return f(w, ctx)
return renderer(w, ctx)
}
// Render evaluates an AST node and writes the result to an io.Writer.