新增: @use 同文件片段复用
支持 @use("name") 引用同一文件内 @tpl 定义的块,
消除 _list/_count 模板中 WHERE 条件重复问题。
This commit is contained in:
@@ -15,6 +15,7 @@ type Executor struct {
|
||||
style PlaceholderStyle
|
||||
rawPolicy rawValidator
|
||||
strict bool
|
||||
blocks map[string][]Node
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
@@ -22,11 +23,12 @@ type Result struct {
|
||||
Args []any
|
||||
}
|
||||
|
||||
func NewExecutor(style PlaceholderStyle, rawPolicy rawValidator, strict bool) *Executor {
|
||||
func NewExecutor(style PlaceholderStyle, rawPolicy rawValidator, strict bool, blocks map[string][]Node) *Executor {
|
||||
return &Executor{
|
||||
style: style,
|
||||
rawPolicy: rawPolicy,
|
||||
strict: strict,
|
||||
blocks: blocks,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +101,17 @@ func (e *Executor) walk(ctx *Context, ph *Placeholder, sql *strings.Builder, arg
|
||||
|
||||
case *BlockNode, *NamespaceNode, *IncludeNode, *CommentNode:
|
||||
// skip
|
||||
case *UseNode:
|
||||
if e.blocks == nil {
|
||||
return fmt.Errorf("line %d, col %d: @use(\"%s\") no blocks available", n.Pos.Line, n.Pos.Col, n.Name)
|
||||
}
|
||||
blockNodes, ok := e.blocks[n.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("line %d, col %d: @use(\"%s\") block not found", n.Pos.Line, n.Pos.Col, n.Name)
|
||||
}
|
||||
if err := e.walk(ctx, ph, sql, args, blockNodes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -16,6 +16,7 @@ const (
|
||||
TokTplStart
|
||||
TokIncludeStart
|
||||
TokNamespaceStart
|
||||
TokUseStart
|
||||
TokElse
|
||||
TokComment
|
||||
TokEOF
|
||||
@@ -173,6 +174,7 @@ func (l *Lexer) tryDirective() (Token, bool) {
|
||||
{[]rune("@tpl(\""), TokTplStart, 5},
|
||||
{[]rune("@include(\""), TokIncludeStart, 10},
|
||||
{[]rune("@namespace(\""), TokNamespaceStart, 12},
|
||||
{[]rune("@use(\""), TokUseStart, 6},
|
||||
}
|
||||
|
||||
for _, d := range directives {
|
||||
|
||||
@@ -85,6 +85,13 @@ type CommentNode struct {
|
||||
|
||||
func (n *CommentNode) nodeType() string { return "Comment" }
|
||||
|
||||
type UseNode struct {
|
||||
Pos Pos
|
||||
Name string
|
||||
}
|
||||
|
||||
func (n *UseNode) nodeType() string { return "Use" }
|
||||
|
||||
type ExprType int
|
||||
|
||||
const (
|
||||
|
||||
@@ -96,6 +96,13 @@ func (p *Parser) Parse() ([]Node, error) {
|
||||
}
|
||||
nodes = append(nodes, node)
|
||||
|
||||
case TokUseStart:
|
||||
node, err := p.parseUse(tok)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodes = append(nodes, node)
|
||||
|
||||
case TokElse:
|
||||
return nil, fmt.Errorf("line %d, col %d: unexpected else", tok.Pos.Line, tok.Pos.Col)
|
||||
|
||||
@@ -521,6 +528,26 @@ func (p *Parser) expandInclude(tok Token) ([]Node, error) {
|
||||
return subParser.Parse()
|
||||
}
|
||||
|
||||
func (p *Parser) parseUse(tok Token) (*UseNode, error) {
|
||||
runePos := p.runePosFromToken(tok)
|
||||
name, quotePos, err := p.readUntilQuote(runePos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("line %d, col %d: unterminated @use name", tok.Pos.Line, tok.Pos.Col)
|
||||
}
|
||||
name = strings.TrimSpace(name)
|
||||
|
||||
endPos := quotePos + 1
|
||||
if endPos < len(p.input) && p.input[endPos] == ')' {
|
||||
endPos++
|
||||
}
|
||||
p.consumeTokensForRuneRange(runePos, endPos)
|
||||
|
||||
return &UseNode{
|
||||
Pos: tok.Pos,
|
||||
Name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseNamespace(tok Token, nodeCount int) (*NamespaceNode, error) {
|
||||
if nodeCount > 0 {
|
||||
return nil, fmt.Errorf("line %d, col %d: @namespace must be at the top of the file", tok.Pos.Line, tok.Pos.Col)
|
||||
@@ -695,6 +722,12 @@ func (p *Parser) parseBlockBodyWithElse(blockType string) ([]Node, []Node, []*El
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
body = append(body, subNodes...)
|
||||
case TokUseStart:
|
||||
node, err := p.parseUse(tok)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
body = append(body, node)
|
||||
case TokNamespaceStart:
|
||||
return nil, nil, nil, fmt.Errorf("line %d, col %d: @namespace must be at file top level", tok.Pos.Line, tok.Pos.Col)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user