Fix some panics related to nil values

This commit is contained in:
Elara 2024-02-10 13:31:27 -08:00
parent 4154ce5ce7
commit a042aaa430

View File

@ -404,7 +404,14 @@ func (t *Template) getIndex(i ast.Index, local map[string]any) (any, error) {
var out reflect.Value var out reflect.Value
rval := reflect.ValueOf(val) rval := reflect.ValueOf(val)
if !rval.IsValid() {
return nil, ast.PosError(i, "%s: cannot get index of nil value", valueToString(i))
}
rindex := reflect.ValueOf(index) rindex := reflect.ValueOf(index)
if !rval.IsValid() {
return nil, ast.PosError(i, "%s: cannot use nil value as an index", valueToString(i))
}
switch rval.Kind() { switch rval.Kind() {
case reflect.Slice, reflect.Array, reflect.String: case reflect.Slice, reflect.Array, reflect.String:
intType := reflect.TypeOf(0) intType := reflect.TypeOf(0)
@ -448,9 +455,15 @@ func (t *Template) getField(fa ast.FieldAccess, local map[string]any) (any, erro
return nil, err return nil, err
} }
rval := reflect.ValueOf(val) rval := reflect.ValueOf(val)
if !rval.IsValid() {
return nil, ast.PosError(fa, "%s: cannot get field of nil value", valueToString(fa))
}
for rval.Kind() == reflect.Pointer { for rval.Kind() == reflect.Pointer {
rval = rval.Elem() rval = rval.Elem()
} }
if rval.Kind() != reflect.Struct || rval.NumField() == 0 {
return nil, ast.PosError(fa, "%s: value has no fields", valueToString(fa))
}
field := rval.FieldByName(fa.Name.Value) field := rval.FieldByName(fa.Name.Value)
if !field.IsValid() { if !field.IsValid() {
return nil, ast.PosError(fa, "%s: no such field: %s", valueToString(fa), fa.Name.Value) return nil, ast.PosError(fa, "%s: no such field: %s", valueToString(fa), fa.Name.Value)
@ -468,6 +481,9 @@ func (t *Template) execMethodCall(mc ast.MethodCall, local map[string]any) (any,
return nil, err return nil, err
} }
rval := reflect.ValueOf(val) rval := reflect.ValueOf(val)
if !rval.IsValid() {
return nil, ast.PosError(mc, "%s: cannot call method on nil value", valueToString(mc))
}
for rval.Kind() == reflect.Pointer { for rval.Kind() == reflect.Pointer {
rval = rval.Elem() rval = rval.Elem()
} }
@ -487,6 +503,10 @@ func (t *Template) execMethodCall(mc ast.MethodCall, local map[string]any) (any,
// execFunc executes a function call // execFunc executes a function call
func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, local map[string]any) (any, error) { func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, local map[string]any) (any, error) {
if !fn.IsValid() {
return nil, ast.PosError(node, "%s: cannot call nil function", valueToString(node))
}
fnType := fn.Type() fnType := fn.Type()
lastIndex := fnType.NumIn() - 1 lastIndex := fnType.NumIn() - 1
isVariadic := fnType.IsVariadic() isVariadic := fnType.IsVariadic()
@ -525,12 +545,15 @@ func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, lo
} }
ret := fn.Call(params) ret := fn.Call(params)
for ret[0].Kind() == reflect.Pointer {
ret[0] = ret[0].Elem()
}
if len(ret) == 1 { if len(ret) == 1 {
retv := ret[0].Interface() retv := ret[0].Interface()
if err, ok := retv.(error); ok { if err, ok := retv.(error); ok {
return nil, ast.PosError(node, "%s: %w", valueToString(node), err) return nil, ast.PosError(node, "%s: %w", valueToString(node), err)
} }
return ret[0].Interface(), nil return retv, nil
} else { } else {
if ret[1].IsNil() { if ret[1].IsNil() {
return ret[0].Interface(), nil return ret[0].Interface(), nil