Skip to content

Commit

Permalink
Move tag compilation to compiler stage
Browse files Browse the repository at this point in the history
  • Loading branch information
osteele committed Jul 6, 2017
1 parent 803471c commit 54e840c
Show file tree
Hide file tree
Showing 8 changed files with 22 additions and 27 deletions.
16 changes: 6 additions & 10 deletions render/ast.go
@@ -1,32 +1,28 @@
package render

import (
"io"

"github.com/osteele/liquid/expression"
)

// ASTNode is a node of an AST.
type ASTNode interface {
}
type ASTNode interface{}

// ASTBlock represents a {% tag %}…{% endtag %}.
type ASTBlock struct {
Chunk
syntax BlockSyntax
Body []ASTNode
Branches []*ASTBlock
syntax BlockSyntax
Body []ASTNode // Body is the nodes before the first branch
Branches []*ASTBlock // E.g. else and elseif w/in an if
}

// ASTRaw holds the text between the start and end of a raw tag.
type ASTRaw struct {
slices []string
}

// ASTFunctional renders itself via a render function that is created during parsing.
type ASTFunctional struct {
// ASTTag is a tag.
type ASTTag struct {
Chunk
render func(io.Writer, Context) error
}

// ASTText is a text chunk, that is rendered verbatim.
Expand Down
2 changes: 1 addition & 1 deletion render/blocks.go
Expand Up @@ -71,7 +71,7 @@ func (c Config) AddBlock(name string) blockDefBuilder { // nolint: golint
}

// Branch tells the parser that the named tag can appear immediately between this tag and its end tag,
// so long as it is not nested within any other control tagc.
// so long as it is not nested within any other control tag.
func (b blockDefBuilder) Branch(name string) blockDefBuilder {
b.cfg.addBlockDef(&blockDef{name: name, isBranchTag: true, parent: b.tag})
return b
Expand Down
12 changes: 9 additions & 3 deletions render/compiler.go
Expand Up @@ -41,7 +41,6 @@ func (c Config) compileNode(n ASTNode) (Node, error) {
}
node := BlockNode{
Chunk: n.Chunk,
syntax: n.syntax,
Body: body,
Branches: branches,
}
Expand All @@ -53,8 +52,6 @@ func (c Config) compileNode(n ASTNode) (Node, error) {
node.renderer = r
}
return &node, nil
case *ASTFunctional:
return &FunctionalNode{n.Chunk, n.render}, nil
case *ASTRaw:
return &RawNode{n.slices}, nil
case *ASTSeq:
Expand All @@ -63,6 +60,15 @@ func (c Config) compileNode(n ASTNode) (Node, error) {
return nil, err
}
return &SeqNode{children}, nil
case *ASTTag:
if td, ok := c.FindTagDefinition(n.Name); ok {
f, err := td(n.Args)
if err != nil {
return nil, err
}
return &FunctionalNode{n.Chunk, f}, nil
}
return nil, parseErrorf("unknown tag: %s", n.Name)
case *ASTText:
return &TextNode{n.Chunk}, nil
case *ASTObject:
Expand Down
3 changes: 2 additions & 1 deletion render/compiler_test.go
Expand Up @@ -15,8 +15,9 @@ func addCompilerTestTags(s Config) {
}

var compilerErrorTests = []struct{ in, expected string }{
// {`{% tag %}`, "tag compiler error"},
{"{% unknown_tag %}", "unknown tag"},
{`{% block %}{% endblock %}`, "block compiler error"},
// {`{% tag %}`, "tag compiler error"},
// {"{%for syntax error%}{%endfor%}", "parse error"},
}

Expand Down
1 change: 0 additions & 1 deletion render/render_node.go → render/nodes.go
Expand Up @@ -14,7 +14,6 @@ type Node interface {
type BlockNode struct {
Chunk
renderer func(io.Writer, Context) error
syntax BlockSyntax
Body []Node
Branches []*BlockNode
}
Expand Down
10 changes: 2 additions & 8 deletions render/parser.go
Expand Up @@ -101,19 +101,13 @@ func (c Config) parseChunks(chunks []Chunk) (ASTNode, error) { // nolint: gocycl
default:
panic("unexpected block type")
}
} else if td, ok := c.FindTagDefinition(ch.Name); ok {
f, err := td(ch.Args)
if err != nil {
return nil, err
}
*ap = append(*ap, &ASTFunctional{ch, f})
} else {
return nil, parseErrorf("unknown tag: %s", ch.Name)
*ap = append(*ap, &ASTTag{ch})
}
}
}
if bn != nil {
return nil, parseErrorf("unterminated %s tag at %s", bn.Name, bn.SourceInfo)
return nil, parseErrorf("unterminated %s block at %s", bn.Name, bn.SourceInfo)
}
return root, nil
}
3 changes: 1 addition & 2 deletions render/parser_test.go
Expand Up @@ -17,8 +17,7 @@ func addParserTestTags(s Config) {
}

var parseErrorTests = []struct{ in, expected string }{
{"{% unknown_tag %}", "unknown tag"},
{"{% if test %}", "unterminated if tag"},
{"{% if test %}", "unterminated if block"},
{"{% if test %}{% endunless %}", "not inside unless"},
// TODO tag syntax could specify statement type to catch these in parser
// {"{{ syntax error }}", "parse error"},
Expand Down
2 changes: 1 addition & 1 deletion tags/tags_test.go
Expand Up @@ -11,7 +11,7 @@ import (

var parseErrorTests = []struct{ in, expected string }{
{"{%unknown_tag%}", "unknown tag"},
{"{%if syntax error%}", "unterminated if tag"},
{"{%if syntax error%}", "unterminated if block"},
// TODO once expression parsing is moved to template parse stage
// {"{%if syntax error%}{%endif%}", "parse error"},
// {"{%for a in ar unknown%}{{a}} {%endfor%}", "TODO"},
Expand Down

0 comments on commit 54e840c

Please sign in to comment.