lang: types, core: Skip over invalid functions
It's not clear how best to support complex functions with struct fields in templates at the moment. Skip these for now.
This commit is contained in:
@@ -425,7 +425,11 @@ func (obj *TemplateFunc) run(templateText string, vars types.Value) (string, err
|
|||||||
// parameter types. Functions meant to apply to arguments of
|
// parameter types. Functions meant to apply to arguments of
|
||||||
// arbitrary type can use parameters of type interface{} or of
|
// arbitrary type can use parameters of type interface{} or of
|
||||||
// type reflect.Value.
|
// type reflect.Value.
|
||||||
f := wrap(name, fn) // wrap it so that it meets API expectations
|
f, err := wrap(name, fn) // wrap it so that it meets API expectations
|
||||||
|
if err != nil {
|
||||||
|
obj.init.Logf("warning, skipping function named: `%s`, err: %v", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
funcMap[name] = f // add it
|
funcMap[name] = f // add it
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,7 +585,14 @@ func safename(name string) string {
|
|||||||
// function API with what is expected from the reflection API. It returns a
|
// function API with what is expected from the reflection API. It returns a
|
||||||
// version that includes the optional second error return value so that our
|
// version that includes the optional second error return value so that our
|
||||||
// functions can return errors without causing a panic.
|
// functions can return errors without causing a panic.
|
||||||
func wrap(name string, fn *types.FuncValue) interface{} {
|
func wrap(name string, fn *types.FuncValue) (_ interface{}, reterr error) {
|
||||||
|
defer func() {
|
||||||
|
// catch unhandled panics
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
reterr = fmt.Errorf("panic in template wrap of `%s` function: %+v", name, r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if fn.T.Map == nil {
|
if fn.T.Map == nil {
|
||||||
panic("malformed func type")
|
panic("malformed func type")
|
||||||
}
|
}
|
||||||
@@ -600,7 +611,8 @@ func wrap(name string, fn *types.FuncValue) interface{} {
|
|||||||
|
|
||||||
in = append(in, t.Reflect())
|
in = append(in, t.Reflect())
|
||||||
}
|
}
|
||||||
out := []reflect.Type{fn.T.Out.Reflect(), errorType}
|
ret := fn.T.Out.Reflect() // this can panic!
|
||||||
|
out := []reflect.Type{ret, errorType}
|
||||||
var variadic = false // currently not supported in our function value
|
var variadic = false // currently not supported in our function value
|
||||||
typ := reflect.FuncOf(in, out, variadic)
|
typ := reflect.FuncOf(in, out, variadic)
|
||||||
|
|
||||||
@@ -640,5 +652,5 @@ func wrap(name string, fn *types.FuncValue) interface{} {
|
|||||||
return []reflect.Value{reflect.ValueOf(result.Value()), nilError}
|
return []reflect.Value{reflect.ValueOf(result.Value()), nilError}
|
||||||
}
|
}
|
||||||
val := reflect.MakeFunc(typ, f)
|
val := reflect.MakeFunc(typ, f)
|
||||||
return val.Interface()
|
return val.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -899,6 +899,11 @@ func (obj *Type) Reflect() reflect.Type {
|
|||||||
if t == nil {
|
if t == nil {
|
||||||
panic("malformed struct field")
|
panic("malformed struct field")
|
||||||
}
|
}
|
||||||
|
if strings.Title(k) != k { // is exported?
|
||||||
|
//k = strings.Title(k) // TODO: is this helpful?
|
||||||
|
// reflect.StructOf would panic on anything unexported
|
||||||
|
panic(fmt.Sprintf("struct has unexported field: %s", k))
|
||||||
|
}
|
||||||
|
|
||||||
fields = append(fields, reflect.StructField{
|
fields = append(fields, reflect.StructField{
|
||||||
Name: k, // struct field name
|
Name: k, // struct field name
|
||||||
|
|||||||
@@ -1502,3 +1502,25 @@ func TestTypeOf0(t *testing.T) {
|
|||||||
// TODO: implement testing of the TypeOf function
|
// TODO: implement testing of the TypeOf function
|
||||||
// TODO: implement testing TypeOf for struct field name mappings
|
// TODO: implement testing TypeOf for struct field name mappings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReflect0(t *testing.T) {
|
||||||
|
mustPanic := func() (reterr error) {
|
||||||
|
defer func() {
|
||||||
|
// catch unhandled panics
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
reterr = fmt.Errorf("panic: %+v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// It's unclear if we want this behaviour forever, but it is the
|
||||||
|
// current behaviour, and I'd at least like to know if it
|
||||||
|
// changes so we can understand where (if at all) it's required.
|
||||||
|
typ := NewType("struct{field1 str}")
|
||||||
|
_ = typ.Reflect()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mustPanic(); err == nil {
|
||||||
|
t.Errorf("expected panic, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user