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:
parent
61663ab11a
commit
5dddabeb78
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user