Skip to content

Commit

Permalink
Parse control tag forms at parse time
Browse files Browse the repository at this point in the history
  • Loading branch information
osteele committed Jun 29, 2017
1 parent 61663ab commit 5dddabe
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 7 deletions.
1 change: 1 addition & 0 deletions chunks/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions chunks/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
6 changes: 3 additions & 3 deletions chunks/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 }{
Expand All @@ -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)
Expand All @@ -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)
Expand Down
9 changes: 5 additions & 4 deletions chunks/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 5dddabe

Please sign in to comment.