Skip to content

Commit

Permalink
Control tag parsers can return an error
Browse files Browse the repository at this point in the history
  • Loading branch information
osteele committed Jun 29, 2017
1 parent e9c35a3 commit 61663ab
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 28 deletions.
12 changes: 6 additions & 6 deletions chunks/control_tags.go
Expand Up @@ -8,16 +8,16 @@ import (
// controlTagDefinitions is a map of tag names to control tag definitions.
var controlTagDefinitions = map[string]*controlTagDefinition{}

// ControlTagAction runs the interpreter.
type ControlTagAction func(ASTControlTag) func(io.Writer, Context) error
// ControlTagParser runs the interpreter.
type ControlTagParser func(ASTControlTag) (func(io.Writer, Context) error, error)

// controlTagDefinition tells the parser how to parse control tags.
type controlTagDefinition struct {
name string
isBranchTag, isEndTag bool
syntaxModel *controlTagDefinition
parent *controlTagDefinition
action ControlTagAction
parser ControlTagParser
}

func (c *controlTagDefinition) compatibleParent(p *controlTagDefinition) bool {
Expand Down Expand Up @@ -79,7 +79,7 @@ func (b tagBuilder) SameSyntaxAs(name string) tagBuilder {
return b
}

// Action sets the action for a control tag definition.
func (b tagBuilder) Action(fn ControlTagAction) {
b.tag.action = fn
// Parser sets the parser for a control tag definition.
func (b tagBuilder) Parser(fn ControlTagParser) {
b.tag.parser = fn
}
7 changes: 5 additions & 2 deletions chunks/render.go
Expand Up @@ -53,10 +53,13 @@ func (n *ASTRaw) Render(w io.Writer, _ Context) error {
// Render evaluates an AST node and writes the result to an io.Writer.
func (n *ASTControlTag) Render(w io.Writer, ctx Context) error {
cd, ok := findControlTagDefinition(n.Tag)
if !ok || cd.action == nil {
if !ok || cd.parser == nil {
return fmt.Errorf("unimplemented tag: %s", n.Tag)
}
f := cd.action(*n)
f, err := cd.parser(*n)
if err != nil {
return err
}
return f(w, ctx)
}

Expand Down
6 changes: 3 additions & 3 deletions tags/loop.go
Expand Up @@ -16,10 +16,10 @@ func parseLoop(source string) (expressions.Expression, error) {
return expr, nil
}

func loopTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
func loopTagParser(node chunks.ASTControlTag) (func(io.Writer, chunks.Context) error, error) {
expr, err := parseLoop(node.Args)
if err != nil {
return func(io.Writer, chunks.Context) error { return err }
return nil, err
}
return func(w io.Writer, ctx chunks.Context) error {
val, err := ctx.Evaluate(expr)
Expand Down Expand Up @@ -73,5 +73,5 @@ func loopTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
}
}
return nil
}
}, nil
}
32 changes: 15 additions & 17 deletions tags/tags.go
Expand Up @@ -14,17 +14,17 @@ func DefineStandardTags() {
// The parser only recognize the comment and raw tags if they've been defined,
// but it ignores any syntax specified here.
loopTags := []string{"break", "continue", "cycle"}
chunks.DefineControlTag("capture").Action(captureTag)
chunks.DefineControlTag("case").Branch("when").Action(caseTag)
chunks.DefineControlTag("capture").Parser(captureTagParser)
chunks.DefineControlTag("case").Branch("when").Parser(caseTagParser)
chunks.DefineControlTag("comment")
chunks.DefineControlTag("for").Governs(loopTags).Action(loopTag)
chunks.DefineControlTag("if").Branch("else").Branch("elsif").Action(ifTag(true))
chunks.DefineControlTag("for").Governs(loopTags).Parser(loopTagParser)
chunks.DefineControlTag("if").Branch("else").Branch("elsif").Parser(ifTagParser(true))
chunks.DefineControlTag("raw")
chunks.DefineControlTag("tablerow").Governs(loopTags)
chunks.DefineControlTag("unless").SameSyntaxAs("if").Action(ifTag(false))
chunks.DefineControlTag("unless").SameSyntaxAs("if").Parser(ifTagParser(false))
}

func captureTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
func captureTagParser(node chunks.ASTControlTag) (func(io.Writer, chunks.Context) error, error) {
// TODO verify syntax
varname := node.Args
return func(w io.Writer, ctx chunks.Context) error {
Expand All @@ -34,16 +34,15 @@ func captureTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error
}
ctx.Set(varname, buf.String())
return nil
}
}, nil
}

func caseTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
func caseTagParser(node chunks.ASTControlTag) (func(io.Writer, chunks.Context) error, error) {
// TODO parse error on non-empty node.Body
// TODO case can include an else
expr, err := chunks.MakeExpressionValueFn(node.Args)
// TODO change the API to let this return the error directly
if err != nil {
return func(io.Writer, chunks.Context) error { return err }
return nil, err
}
type branchRec struct {
fn func(chunks.Context) (interface{}, error)
Expand All @@ -53,7 +52,7 @@ func caseTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
for _, branch := range node.Branches {
bfn, err := chunks.MakeExpressionValueFn(branch.Args)
if err != nil {
return func(io.Writer, chunks.Context) error { return err }
return nil, err
}
cases = append(cases, branchRec{bfn, branch})
}
Expand All @@ -72,17 +71,16 @@ func caseTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
}
}
return nil
}
}, nil
}

func ifTag(polarity bool) func(chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
func ifTagParser(polarity bool) func(chunks.ASTControlTag) (func(io.Writer, chunks.Context) error, error) {
// TODO parse error if the order of branches is other than ifelse*else?
// TODO parse the tests into a table evaluator -> []AST
return func(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
return func(node chunks.ASTControlTag) (func(io.Writer, chunks.Context) error, error) {
expr, err := chunks.MakeExpressionValueFn(node.Args)
if err != nil {
// TODO allow these to return the error directly
return func(io.Writer, chunks.Context) error { return err }
return nil, err
}
return func(w io.Writer, ctx chunks.Context) error {
val, err := expr(ctx)
Expand Down Expand Up @@ -112,6 +110,6 @@ func ifTag(polarity bool) func(chunks.ASTControlTag) func(io.Writer, chunks.Cont
}
}
return nil
}
}, nil
}
}

0 comments on commit 61663ab

Please sign in to comment.