diff options
Diffstat (limited to 'tpl/internal/go_templates/texttemplate/exec.go')
-rw-r--r-- | tpl/internal/go_templates/texttemplate/exec.go | 39 |
1 files changed, 23 insertions, 16 deletions
diff --git a/tpl/internal/go_templates/texttemplate/exec.go b/tpl/internal/go_templates/texttemplate/exec.go index 73153c764..bd8c82bd7 100644 --- a/tpl/internal/go_templates/texttemplate/exec.go +++ b/tpl/internal/go_templates/texttemplate/exec.go @@ -7,13 +7,12 @@ package template import ( "errors" "fmt" + "github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort" + "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse" "io" "reflect" "runtime" "strings" - - "github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort" - "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse" ) // maxExecDepth specifies the maximum stack depth of templates within @@ -95,7 +94,7 @@ type missingValType struct{} var missingVal = reflect.ValueOf(missingValType{}) -var missingValReflectType = reflect.TypeOf(missingValType{}) +var missingValReflectType = reflect.TypeFor[missingValType]() func isMissing(v reflect.Value) bool { return v.IsValid() && v.Type() == missingValReflectType @@ -202,8 +201,8 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { // A template may be executed safely in parallel, although if parallel // executions share a Writer the output may be interleaved. // -// If data is a reflect.Value, the template applies to the concrete -// value that the reflect.Value holds, as in fmt.Print. +// If data is a [reflect.Value], the template applies to the concrete +// value that the reflect.Value holds, as in [fmt.Print]. func (t *Template) Execute(wr io.Writer, data any) error { return t.execute(wr, data) } @@ -229,7 +228,7 @@ func (t *Template) execute(wr io.Writer, data any) (err error) { // DefinedTemplates returns a string listing the defined templates, // prefixed by the string "; defined templates are: ". If there are none, // it returns the empty string. For generating an error message here -// and in html/template. +// and in [html/template]. func (t *Template) DefinedTemplates() string { if t.common == nil { return "" @@ -409,8 +408,8 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { break } om := fmtsort.Sort(val) - for i, key := range om.Key { - oneIteration(key, om.Value[i]) + for _, m := range om { + oneIteration(m.Key, m.Value) } return case reflect.Chan: @@ -480,7 +479,7 @@ func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value ref value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. // If the object has type interface{}, dig down one level to the thing inside. if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { - value = reflect.ValueOf(value.Interface()) // lovely! + value = value.Elem() } } for _, variable := range pipe.Decl { @@ -709,9 +708,9 @@ func (s *state) evalFieldOld(dot reflect.Value, fieldName string, node parse.Nod } var ( - errorType = reflect.TypeOf((*error)(nil)).Elem() - fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() - reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem() + errorType = reflect.TypeFor[error]() + fmtStringerType = reflect.TypeFor[fmt.Stringer]() + reflectValueType = reflect.TypeFor[reflect.Value]() ) // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so @@ -735,9 +734,8 @@ func (s *state) evalCallOld(dot, fun reflect.Value, isBuiltin bool, node parse.N } else if numIn != typ.NumIn() { s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn) } - if !goodFunc(typ) { - // TODO: This could still be a confusing error; maybe goodFunc should provide info. - s.errorf("can't call method/function %q with %d results", name, typ.NumOut()) + if err := goodFunc(name, typ); err != nil { + s.errorf("%v", err) } unwrap := func(v reflect.Value) reflect.Value { @@ -801,6 +799,15 @@ func (s *state) evalCallOld(dot, fun reflect.Value, isBuiltin bool, node parse.N } argv[i] = s.validateType(final, t) } + + // Special case for the "call" builtin. + // Insert the name of the callee function as the first argument. + if isBuiltin && name == "call" { + calleeName := args[0].String() + argv = append([]reflect.Value{reflect.ValueOf(calleeName)}, argv...) + fun = reflect.ValueOf(call) + } + v, err := safeCall(fun, argv) // If we have an error that is not nil, stop execution and return that // error to the caller. |