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:
parent
5af5025c48
commit
d1e666a42d
73
decoder.go
73
decoder.go
@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/hcl/ast"
|
"github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
"github.com/hashicorp/hcl/hcl/parser"
|
||||||
"github.com/hashicorp/hcl/hcl/token"
|
"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:
|
case reflect.Struct:
|
||||||
return d.decodeStruct(name, node, result)
|
return d.decodeStruct(name, node, result)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return &parser.PosError{
|
||||||
"%s: unknown kind to decode into: %s", name, k.Kind())
|
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 {
|
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 {
|
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 {
|
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 {
|
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:
|
case token.STRING, token.HEREDOC:
|
||||||
set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
|
set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return &parser.PosError{
|
||||||
"%s: cannot decode into interface: %T",
|
Pos: node.Pos(),
|
||||||
name, node)
|
Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
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)
|
n, ok := node.(*ast.ObjectList)
|
||||||
if !ok {
|
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,
|
// 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()
|
resultElemType := resultType.Elem()
|
||||||
resultKeyType := resultType.Key()
|
resultKeyType := resultType.Key()
|
||||||
if resultKeyType.Kind() != reflect.String {
|
if resultKeyType.Kind() != reflect.String {
|
||||||
return fmt.Errorf(
|
return &parser.PosError{
|
||||||
"%s: map must have string keys", name)
|
Pos: node.Pos(),
|
||||||
|
Err: fmt.Errorf("%s: map must have string keys", name),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a map if it is nil
|
// 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:
|
case *ast.ListType:
|
||||||
items = n.List
|
items = n.List
|
||||||
default:
|
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 {
|
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 {
|
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)
|
list, ok := node.(*ast.ObjectList)
|
||||||
if !ok {
|
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.
|
// 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 {
|
if fieldType.Anonymous {
|
||||||
fieldKind := fieldType.Type.Kind()
|
fieldKind := fieldType.Type.Kind()
|
||||||
if fieldKind != reflect.Struct {
|
if fieldKind != reflect.Struct {
|
||||||
return fmt.Errorf(
|
return &parser.PosError{
|
||||||
"%s: unsupported type to struct: %s",
|
Pos: node.Pos(),
|
||||||
fieldType.Name, fieldKind)
|
Err: fmt.Errorf("%s: unsupported type to struct: %s",
|
||||||
|
fieldType.Name, fieldKind),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have an embedded field. We "squash" the fields down
|
// 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
|
continue
|
||||||
case "key":
|
case "key":
|
||||||
if item == nil {
|
if item == nil {
|
||||||
return fmt.Errorf(
|
return &parser.PosError{
|
||||||
"%s: %s asked for 'key', impossible",
|
Pos: node.Pos(),
|
||||||
name, fieldName)
|
Err: fmt.Errorf("%s: %s asked for 'key', impossible",
|
||||||
|
name, fieldName),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field.SetString(item.Keys[0].Token.Value().(string))
|
field.SetString(item.Keys[0].Token.Value().(string))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user