add position to all decoder errors

Several of the esoteric syntax errors we encounter in Terraform have
bubbled up errors from the decoder. Since all these errors have a Node
in context, they can report their position which makes them _much_ more
helpful to the user, even if the error message itself is confusing.

I tried to move around PosError somewhere but got stuck finding a good
spot for it that doesn't have either a silly name or an import cycle, so
for now I'm just cross referencing into the parser package to reference
the error type.
This commit is contained in:
Paul Hinze 2015-12-18 10:54:32 -06:00
parent 5af5025c48
commit d1e666a42d

View File

@ -9,6 +9,7 @@ import (
"strings"
"github.com/hashicorp/hcl/hcl/ast"
"github.com/hashicorp/hcl/hcl/parser"
"github.com/hashicorp/hcl/hcl/token"
)
@ -95,11 +96,11 @@ func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error
case reflect.Struct:
return d.decodeStruct(name, node, result)
default:
return fmt.Errorf(
"%s: unknown kind to decode into: %s", name, k.Kind())
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()),
}
}
return nil
}
func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error {
@ -116,7 +117,10 @@ func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) e
}
}
return fmt.Errorf("%s: unknown type %T", name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: unknown type %T", name, node),
}
}
func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
@ -133,7 +137,10 @@ func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value)
}
}
return fmt.Errorf("%s: unknown type %T", name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: unknown type %T", name, node),
}
}
func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error {
@ -159,7 +166,10 @@ func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) er
}
}
return fmt.Errorf("%s: unknown type %T", name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: unknown type %T", name, node),
}
}
func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error {
@ -242,9 +252,10 @@ func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Val
case token.STRING, token.HEREDOC:
set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
default:
return fmt.Errorf(
"%s: cannot decode into interface: %T",
name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node),
}
}
default:
return fmt.Errorf(
@ -278,7 +289,10 @@ func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) er
n, ok := node.(*ast.ObjectList)
if !ok {
return fmt.Errorf("%s: not an object type for map (%T)", name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: not an object type for map (%T)", name, node),
}
}
// If we have an interface, then we can address the interface,
@ -292,8 +306,10 @@ func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) er
resultElemType := resultType.Elem()
resultKeyType := resultType.Key()
if resultKeyType.Kind() != reflect.String {
return fmt.Errorf(
"%s: map must have string keys", name)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: map must have string keys", name),
}
}
// Make a map if it is nil
@ -397,7 +413,10 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
case *ast.ListType:
items = n.List
default:
return fmt.Errorf("unknown slice type: %T", node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("unknown slice type: %T", node),
}
}
for i, item := range items {
@ -430,7 +449,10 @@ func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value)
}
}
return fmt.Errorf("%s: unknown type for string %T", name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: unknown type for string %T", name, node),
}
}
func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error {
@ -446,7 +468,10 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
list, ok := node.(*ast.ObjectList)
if !ok {
return fmt.Errorf("%s: not an object type for struct (%T)", name, node)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node),
}
}
// This slice will keep track of all the structs we'll be decoding.
@ -469,9 +494,11 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
if fieldType.Anonymous {
fieldKind := fieldType.Type.Kind()
if fieldKind != reflect.Struct {
return fmt.Errorf(
"%s: unsupported type to struct: %s",
fieldType.Name, fieldKind)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: unsupported type to struct: %s",
fieldType.Name, fieldKind),
}
}
// We have an embedded field. We "squash" the fields down
@ -524,9 +551,11 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
continue
case "key":
if item == nil {
return fmt.Errorf(
"%s: %s asked for 'key', impossible",
name, fieldName)
return &parser.PosError{
Pos: node.Pos(),
Err: fmt.Errorf("%s: %s asked for 'key', impossible",
name, fieldName),
}
}
field.SetString(item.Keys[0].Token.Value().(string))