...

Source file src/github.com/noirbizarre/gonja/builtins/statements/block.go

Documentation: github.com/noirbizarre/gonja/builtins/statements

     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  	// root, block := r.Root.GetBlock(stmt.Name)
    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