Skip to content

Commit

Permalink
rework macro imports
Browse files Browse the repository at this point in the history
  • Loading branch information
jjkavalam committed Feb 12, 2023
1 parent 2533a77 commit 15b9d6b
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 37 deletions.
18 changes: 11 additions & 7 deletions tags_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ type tagImportNode struct {
position *Token
filename string
macros map[string]*tagMacroNode // alias/name -> macro instance
template *Template
}

func (node *tagImportNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
for name, macro := range node.macros {
func(name string, macro *tagMacroNode) {
ctx.Private[name] = func(args ...*Value) (*Value, error) {
return macro.call(ctx, args...)
}
}(name, macro)
}
// for name, macro := range node.macros {
// func(name string, macro *tagMacroNode) {
// ctx.Private[name] = func(args ...*Value) (*Value, error) {
// return macro.call(ctx, args...)
// }
// }(name, macro)
// }
return nil
}

Expand Down Expand Up @@ -76,6 +77,9 @@ func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
}
}

doc.template.macroImportNodes = append(doc.template.macroImportNodes, importNode)
importNode.template = tpl

return importNode, nil
}

Expand Down
27 changes: 14 additions & 13 deletions tags_macro.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@ type tagMacroNode struct {
}

func (node *tagMacroNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
ctx.Private[node.name] = func(args ...*Value) (*Value, error) {
ctx.macroDepth++
defer func() {
ctx.macroDepth--
}()

if ctx.macroDepth > maxMacroDepth {
return nil, ctx.Error(fmt.Sprintf("maximum recursive macro call depth reached (max is %v)", maxMacroDepth), node.position)
}

return node.call(ctx, args...)
}

// ctx.Private[node.name] = func(args ...*Value) (*Value, error) {
// ctx.macroDepth++
// defer func() {
// ctx.macroDepth--
// }()

// if ctx.macroDepth > maxMacroDepth {
// return nil, ctx.Error(fmt.Sprintf("maximum recursive macro call depth reached (max is %v)", maxMacroDepth), node.position)
// }

// return node.call(ctx, args...)
// }
return nil
}

Expand Down Expand Up @@ -151,6 +150,8 @@ func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
doc.template.exportedMacros[macroNode.name] = macroNode
}

doc.template.ownMacroNodes = append(doc.template.ownMacroNodes, macroNode)

return macroNode, nil
}

Expand Down
30 changes: 17 additions & 13 deletions template.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ type Template struct {
parser *Parser

// first come, first serve (it's important to not override existing entries in here)
level int
parent *Template
child *Template
blocks map[string]*NodeWrapper
exportedMacros map[string]*tagMacroNode
level int
parent *Template
child *Template
blocks map[string]*NodeWrapper
exportedMacros map[string]*tagMacroNode
ownMacroNodes []*tagMacroNode
macroImportNodes []*tagImportNode

// Output
root *nodeDocument
Expand All @@ -61,14 +63,16 @@ func newTemplate(set *TemplateSet, name string, isTplString bool, tpl []byte) (*

// Create the template
t := &Template{
set: set,
isTplString: isTplString,
name: name,
tpl: strTpl,
size: len(strTpl),
blocks: make(map[string]*NodeWrapper),
exportedMacros: make(map[string]*tagMacroNode),
Options: newOptions(),
set: set,
isTplString: isTplString,
name: name,
tpl: strTpl,
size: len(strTpl),
blocks: make(map[string]*NodeWrapper),
exportedMacros: make(map[string]*tagMacroNode),
ownMacroNodes: make([]*tagMacroNode, 0),
macroImportNodes: make([]*tagImportNode, 0),
Options: newOptions(),
}
// Copy all settings from another Options.
t.Options.Update(set.Options)
Expand Down
4 changes: 2 additions & 2 deletions template_tests/macro.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ issue #39 (deactivate auto-escape of macros)
{{ html_test("Max") }}

Importing macros
{% import "macro.helper" imported_macro, imported_macro as renamed_macro, imported_macro as html_test %}
{% import "macro.helper" imported_macro, imported_macro as renamed_macro, imported_macro as html_test2 %}
{{ imported_macro("User1") }}
{{ renamed_macro("User2") }}
{{ html_test("Max") }}
{{ html_test2("Max") }}

Chaining macros{% import "macro2.helper" greeter_macro %}
{{ greeter_macro() }}
Expand Down
2 changes: 2 additions & 0 deletions template_tests/macro_transitive.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% import "macro_transitive/b.tpl" b -%}
a{{ b() }}
1 change: 1 addition & 0 deletions template_tests/macro_transitive.tpl.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abc
2 changes: 2 additions & 0 deletions template_tests/macro_transitive/b.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% import "c.tpl" c %}
{% macro b() export %}b{{ c() }}{% endmacro %}
1 change: 1 addition & 0 deletions template_tests/macro_transitive/c.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% macro c() export %}c{% endmacro %}
56 changes: 54 additions & 2 deletions variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,33 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
// First we're having a look in our private
// context (e. g. information provided by tags, like the forloop)
val, inPrivate := ctx.Private[vr.parts[0].s]
valPublic, inPublic := ctx.Public[vr.parts[0].s]

if !inPrivate {
// Nothing found? Then have a final lookup in the public context
val = ctx.Public[vr.parts[0].s]
if inPublic {
// Nothing found? Then have a final lookup in the public context
val = valPublic
} else {
// could be a macro
macroNode, template := lookupMacro(ctx.template, vr.parts[0].s)
if macroNode != nil {
val = func(args ...*Value) (*Value, error) {
ctx.macroDepth++
thisTemplate := ctx.template
defer func() {
ctx.macroDepth--
ctx.template = thisTemplate
}()
ctx.template = template

if ctx.macroDepth > maxMacroDepth {
return nil, ctx.Error(fmt.Sprintf("maximum recursive macro call depth reached (max is %v)", maxMacroDepth), macroNode.position)
}

return macroNode.call(ctx, args...)
}
}
}
}
current = reflect.ValueOf(val) // Get the initial value
} else {
Expand Down Expand Up @@ -505,6 +529,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
current = rv.Interface().(*Value).val
isSafe = rv.Interface().(*Value).safe
}

}

if !current.IsValid() {
Expand All @@ -516,6 +541,33 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
return &Value{val: current, safe: isSafe}, nil
}

// lookupMacro searches for the macro in the current template including imports
// and returns the macro's call function along with the template it is registered in
func lookupMacro(template *Template, name string) (*tagMacroNode, *Template) {
var macro *tagMacroNode
for _, m := range template.ownMacroNodes {
if m.name == name {
macro = m
break
}
}
if macro != nil {
return macro, template
}
for _, importNode := range template.macroImportNodes {
for n, m := range importNode.macros {
if n == name {
macro = m
break
}
}
if macro != nil {
return macro, importNode.template
}
}
return nil, nil
}

func (vr *variableResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
value, err := vr.resolve(ctx)
if err != nil {
Expand Down

0 comments on commit 15b9d6b

Please sign in to comment.