...
1 package statements
2
3 import (
4 "fmt"
5 "strings"
6
7 "github.com/pkg/errors"
8
9 "github.com/noirbizarre/gonja/exec"
10 "github.com/noirbizarre/gonja/nodes"
11 "github.com/noirbizarre/gonja/parser"
12 "github.com/noirbizarre/gonja/tokens"
13 )
14
15 type BlockStmt struct {
16 Location *tokens.Token
17 Name string
18 }
19
20 func (stmt *BlockStmt) Position() *tokens.Token { return stmt.Location }
21 func (stmt *BlockStmt) String() string {
22 t := stmt.Position()
23 return fmt.Sprintf("BlockStmt(Line=%d Col=%d)", t.Line, t.Col)
24 }
25
26 func (stmt *BlockStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
27
28 blocks := r.Root.GetBlocks(stmt.Name)
29 block, blocks := blocks[0], blocks[1:]
30
31 if block == nil {
32 return errors.Errorf(`Unable to find block "%s"`, stmt.Name)
33 }
34
35 sub := r.Inherit()
36 infos := &BlockInfos{Block: stmt, Renderer: sub, Blocks: blocks}
37
38 sub.Ctx.Set("super", infos.super)
39 sub.Ctx.Set("self", exec.Self(sub))
40
41 err := sub.ExecuteWrapper(block)
42 if err != nil {
43 return err
44 }
45
46 return nil
47 }
48
49 type BlockInfos struct {
50 Block *BlockStmt
51 Renderer *exec.Renderer
52 Blocks []*nodes.Wrapper
53 Root *nodes.Template
54 }
55
56 func (bi *BlockInfos) super() string {
57 if len(bi.Blocks) <= 0 {
58 return ""
59 }
60 r := bi.Renderer
61 block, blocks := bi.Blocks[0], bi.Blocks[1:]
62 sub := r.Inherit()
63 var out strings.Builder
64 sub.Out = &out
65 infos := &BlockInfos{
66 Block: bi.Block,
67 Renderer: sub,
68 Blocks: blocks,
69 }
70 sub.Ctx.Set("self", exec.Self(sub))
71 sub.Ctx.Set("super", infos.super)
72 sub.ExecuteWrapper(block)
73 return out.String()
74 }
75
76 func blockParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
77 block := &BlockStmt{
78 Location: p.Current(),
79 }
80 if args.End() {
81 return nil, errors.New("Tag 'block' requires an identifier.")
82 }
83
84 name := args.Match(tokens.Name)
85 if name == nil {
86 return nil, errors.New("First argument for tag 'block' must be an identifier.")
87 }
88
89 if !args.End() {
90 return nil, errors.New("Tag 'block' takes exactly 1 argument (an identifier).")
91 }
92
93 wrapper, endargs, err := p.WrapUntil("endblock")
94 if err != nil {
95 return nil, err
96 }
97 if !endargs.End() {
98 endName := endargs.Match(tokens.Name)
99 if endName != nil {
100 if endName.Val != endName.Val {
101 return nil, errors.Errorf(`Name for 'endblock' must equal to 'block'-tag's name ('%s' != '%s').`,
102 name.Val, endName.Val)
103 }
104 }
105
106 if endName == nil || !endargs.End() {
107 return nil, errors.New("Either no or only one argument (identifier) allowed for 'endblock'.")
108 }
109 }
110
111 if !p.Template.Blocks.Exists(name.Val) {
112 p.Template.Blocks.Register(name.Val, wrapper)
113 } else {
114 return nil, args.Error(fmt.Sprintf("Block named '%s' already defined", name.Val), nil)
115 }
116
117 block.Name = name.Val
118 return block, nil
119 }
120
121 func init() {
122 All.Register("block", blockParser)
123 }
124
View as plain text