mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	Viper dependency + viper godeps
licences
This commit is contained in:
		
							
								
								
									
										659
									
								
								vendor/github.com/hashicorp/hcl/decoder.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										659
									
								
								vendor/github.com/hashicorp/hcl/decoder.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,659 @@ | ||||
| package hcl | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/hashicorp/hcl/hcl/ast" | ||||
| 	"github.com/hashicorp/hcl/hcl/parser" | ||||
| 	"github.com/hashicorp/hcl/hcl/token" | ||||
| ) | ||||
|  | ||||
| // This is the tag to use with structures to have settings for HCL | ||||
| const tagName = "hcl" | ||||
|  | ||||
| var ( | ||||
| 	// nodeType holds a reference to the type of ast.Node | ||||
| 	nodeType reflect.Type = findNodeType() | ||||
| ) | ||||
|  | ||||
| // Unmarshal accepts a byte slice as input and writes the | ||||
| // data to the value pointed to by v. | ||||
| func Unmarshal(bs []byte, v interface{}) error { | ||||
| 	root, err := parse(bs) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return DecodeObject(v, root) | ||||
| } | ||||
|  | ||||
| // Decode reads the given input and decodes it into the structure | ||||
| // given by `out`. | ||||
| func Decode(out interface{}, in string) error { | ||||
| 	obj, err := Parse(in) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return DecodeObject(out, obj) | ||||
| } | ||||
|  | ||||
| // DecodeObject is a lower-level version of Decode. It decodes a | ||||
| // raw Object into the given output. | ||||
| func DecodeObject(out interface{}, n ast.Node) error { | ||||
| 	val := reflect.ValueOf(out) | ||||
| 	if val.Kind() != reflect.Ptr { | ||||
| 		return errors.New("result must be a pointer") | ||||
| 	} | ||||
|  | ||||
| 	// If we have the file, we really decode the root node | ||||
| 	if f, ok := n.(*ast.File); ok { | ||||
| 		n = f.Node | ||||
| 	} | ||||
|  | ||||
| 	var d decoder | ||||
| 	return d.decode("root", n, val.Elem()) | ||||
| } | ||||
|  | ||||
| type decoder struct { | ||||
| 	stack []reflect.Kind | ||||
| } | ||||
|  | ||||
| func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { | ||||
| 	k := result | ||||
|  | ||||
| 	// If we have an interface with a valid value, we use that | ||||
| 	// for the check. | ||||
| 	if result.Kind() == reflect.Interface { | ||||
| 		elem := result.Elem() | ||||
| 		if elem.IsValid() { | ||||
| 			k = elem | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Push current onto stack unless it is an interface. | ||||
| 	if k.Kind() != reflect.Interface { | ||||
| 		d.stack = append(d.stack, k.Kind()) | ||||
|  | ||||
| 		// Schedule a pop | ||||
| 		defer func() { | ||||
| 			d.stack = d.stack[:len(d.stack)-1] | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	switch k.Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		return d.decodeBool(name, node, result) | ||||
| 	case reflect.Float64: | ||||
| 		return d.decodeFloat(name, node, result) | ||||
| 	case reflect.Int: | ||||
| 		return d.decodeInt(name, node, result) | ||||
| 	case reflect.Interface: | ||||
| 		// When we see an interface, we make our own thing | ||||
| 		return d.decodeInterface(name, node, result) | ||||
| 	case reflect.Map: | ||||
| 		return d.decodeMap(name, node, result) | ||||
| 	case reflect.Ptr: | ||||
| 		return d.decodePtr(name, node, result) | ||||
| 	case reflect.Slice: | ||||
| 		return d.decodeSlice(name, node, result) | ||||
| 	case reflect.String: | ||||
| 		return d.decodeString(name, node, result) | ||||
| 	case reflect.Struct: | ||||
| 		return d.decodeStruct(name, node, result) | ||||
| 	default: | ||||
| 		return &parser.PosError{ | ||||
| 			Pos: node.Pos(), | ||||
| 			Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { | ||||
| 	switch n := node.(type) { | ||||
| 	case *ast.LiteralType: | ||||
| 		if n.Token.Type == token.BOOL { | ||||
| 			v, err := strconv.ParseBool(n.Token.Text) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			result.Set(reflect.ValueOf(v)) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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 { | ||||
| 	switch n := node.(type) { | ||||
| 	case *ast.LiteralType: | ||||
| 		if n.Token.Type == token.FLOAT { | ||||
| 			v, err := strconv.ParseFloat(n.Token.Text, 64) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			result.Set(reflect.ValueOf(v)) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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 { | ||||
| 	switch n := node.(type) { | ||||
| 	case *ast.LiteralType: | ||||
| 		switch n.Token.Type { | ||||
| 		case token.NUMBER: | ||||
| 			v, err := strconv.ParseInt(n.Token.Text, 0, 0) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			result.Set(reflect.ValueOf(int(v))) | ||||
| 			return nil | ||||
| 		case token.STRING: | ||||
| 			v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			result.Set(reflect.ValueOf(int(v))) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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 { | ||||
| 	// When we see an ast.Node, we retain the value to enable deferred decoding. | ||||
| 	// Very useful in situations where we want to preserve ast.Node information | ||||
| 	// like Pos | ||||
| 	if result.Type() == nodeType && result.CanSet() { | ||||
| 		result.Set(reflect.ValueOf(node)) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	var set reflect.Value | ||||
| 	redecode := true | ||||
|  | ||||
| 	// For testing types, ObjectType should just be treated as a list. We | ||||
| 	// set this to a temporary var because we want to pass in the real node. | ||||
| 	testNode := node | ||||
| 	if ot, ok := node.(*ast.ObjectType); ok { | ||||
| 		testNode = ot.List | ||||
| 	} | ||||
|  | ||||
| 	switch n := testNode.(type) { | ||||
| 	case *ast.ObjectList: | ||||
| 		// If we're at the root or we're directly within a slice, then we | ||||
| 		// decode objects into map[string]interface{}, otherwise we decode | ||||
| 		// them into lists. | ||||
| 		if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { | ||||
| 			var temp map[string]interface{} | ||||
| 			tempVal := reflect.ValueOf(temp) | ||||
| 			result := reflect.MakeMap( | ||||
| 				reflect.MapOf( | ||||
| 					reflect.TypeOf(""), | ||||
| 					tempVal.Type().Elem())) | ||||
|  | ||||
| 			set = result | ||||
| 		} else { | ||||
| 			var temp []map[string]interface{} | ||||
| 			tempVal := reflect.ValueOf(temp) | ||||
| 			result := reflect.MakeSlice( | ||||
| 				reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) | ||||
| 			set = result | ||||
| 		} | ||||
| 	case *ast.ObjectType: | ||||
| 		// If we're at the root or we're directly within a slice, then we | ||||
| 		// decode objects into map[string]interface{}, otherwise we decode | ||||
| 		// them into lists. | ||||
| 		if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { | ||||
| 			var temp map[string]interface{} | ||||
| 			tempVal := reflect.ValueOf(temp) | ||||
| 			result := reflect.MakeMap( | ||||
| 				reflect.MapOf( | ||||
| 					reflect.TypeOf(""), | ||||
| 					tempVal.Type().Elem())) | ||||
|  | ||||
| 			set = result | ||||
| 		} else { | ||||
| 			var temp []map[string]interface{} | ||||
| 			tempVal := reflect.ValueOf(temp) | ||||
| 			result := reflect.MakeSlice( | ||||
| 				reflect.SliceOf(tempVal.Type().Elem()), 0, 1) | ||||
| 			set = result | ||||
| 		} | ||||
| 	case *ast.ListType: | ||||
| 		var temp []interface{} | ||||
| 		tempVal := reflect.ValueOf(temp) | ||||
| 		result := reflect.MakeSlice( | ||||
| 			reflect.SliceOf(tempVal.Type().Elem()), 0, 0) | ||||
| 		set = result | ||||
| 	case *ast.LiteralType: | ||||
| 		switch n.Token.Type { | ||||
| 		case token.BOOL: | ||||
| 			var result bool | ||||
| 			set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) | ||||
| 		case token.FLOAT: | ||||
| 			var result float64 | ||||
| 			set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) | ||||
| 		case token.NUMBER: | ||||
| 			var result int | ||||
| 			set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) | ||||
| 		case token.STRING, token.HEREDOC: | ||||
| 			set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) | ||||
| 		default: | ||||
| 			return &parser.PosError{ | ||||
| 				Pos: node.Pos(), | ||||
| 				Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		return fmt.Errorf( | ||||
| 			"%s: cannot decode into interface: %T", | ||||
| 			name, node) | ||||
| 	} | ||||
|  | ||||
| 	// Set the result to what its supposed to be, then reset | ||||
| 	// result so we don't reflect into this method anymore. | ||||
| 	result.Set(set) | ||||
|  | ||||
| 	if redecode { | ||||
| 		// Revisit the node so that we can use the newly instantiated | ||||
| 		// thing and populate it. | ||||
| 		if err := d.decode(name, node, result); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { | ||||
| 	if item, ok := node.(*ast.ObjectItem); ok { | ||||
| 		node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} | ||||
| 	} | ||||
|  | ||||
| 	if ot, ok := node.(*ast.ObjectType); ok { | ||||
| 		node = ot.List | ||||
| 	} | ||||
|  | ||||
| 	n, ok := node.(*ast.ObjectList) | ||||
| 	if !ok { | ||||
| 		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, | ||||
| 	// but not the slice itself, so get the element but set the interface | ||||
| 	set := result | ||||
| 	if result.Kind() == reflect.Interface { | ||||
| 		result = result.Elem() | ||||
| 	} | ||||
|  | ||||
| 	resultType := result.Type() | ||||
| 	resultElemType := resultType.Elem() | ||||
| 	resultKeyType := resultType.Key() | ||||
| 	if resultKeyType.Kind() != reflect.String { | ||||
| 		return &parser.PosError{ | ||||
| 			Pos: node.Pos(), | ||||
| 			Err: fmt.Errorf("%s: map must have string keys", name), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Make a map if it is nil | ||||
| 	resultMap := result | ||||
| 	if result.IsNil() { | ||||
| 		resultMap = reflect.MakeMap( | ||||
| 			reflect.MapOf(resultKeyType, resultElemType)) | ||||
| 	} | ||||
|  | ||||
| 	// Go through each element and decode it. | ||||
| 	done := make(map[string]struct{}) | ||||
| 	for _, item := range n.Items { | ||||
| 		if item.Val == nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// github.com/hashicorp/terraform/issue/5740 | ||||
| 		if len(item.Keys) == 0 { | ||||
| 			return &parser.PosError{ | ||||
| 				Pos: node.Pos(), | ||||
| 				Err: fmt.Errorf("%s: map must have string keys", name), | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Get the key we're dealing with, which is the first item | ||||
| 		keyStr := item.Keys[0].Token.Value().(string) | ||||
|  | ||||
| 		// If we've already processed this key, then ignore it | ||||
| 		if _, ok := done[keyStr]; ok { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Determine the value. If we have more than one key, then we | ||||
| 		// get the objectlist of only these keys. | ||||
| 		itemVal := item.Val | ||||
| 		if len(item.Keys) > 1 { | ||||
| 			itemVal = n.Filter(keyStr) | ||||
| 			done[keyStr] = struct{}{} | ||||
| 		} | ||||
|  | ||||
| 		// Make the field name | ||||
| 		fieldName := fmt.Sprintf("%s.%s", name, keyStr) | ||||
|  | ||||
| 		// Get the key/value as reflection values | ||||
| 		key := reflect.ValueOf(keyStr) | ||||
| 		val := reflect.Indirect(reflect.New(resultElemType)) | ||||
|  | ||||
| 		// If we have a pre-existing value in the map, use that | ||||
| 		oldVal := resultMap.MapIndex(key) | ||||
| 		if oldVal.IsValid() { | ||||
| 			val.Set(oldVal) | ||||
| 		} | ||||
|  | ||||
| 		// Decode! | ||||
| 		if err := d.decode(fieldName, itemVal, val); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		// Set the value on the map | ||||
| 		resultMap.SetMapIndex(key, val) | ||||
| 	} | ||||
|  | ||||
| 	// Set the final map if we can | ||||
| 	set.Set(resultMap) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { | ||||
| 	// Create an element of the concrete (non pointer) type and decode | ||||
| 	// into that. Then set the value of the pointer to this type. | ||||
| 	resultType := result.Type() | ||||
| 	resultElemType := resultType.Elem() | ||||
| 	val := reflect.New(resultElemType) | ||||
| 	if err := d.decode(name, node, reflect.Indirect(val)); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result.Set(val) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { | ||||
| 	// If we have an interface, then we can address the interface, | ||||
| 	// but not the slice itself, so get the element but set the interface | ||||
| 	set := result | ||||
| 	if result.Kind() == reflect.Interface { | ||||
| 		result = result.Elem() | ||||
| 	} | ||||
|  | ||||
| 	// Create the slice if it isn't nil | ||||
| 	resultType := result.Type() | ||||
| 	resultElemType := resultType.Elem() | ||||
| 	if result.IsNil() { | ||||
| 		resultSliceType := reflect.SliceOf(resultElemType) | ||||
| 		result = reflect.MakeSlice( | ||||
| 			resultSliceType, 0, 0) | ||||
| 	} | ||||
|  | ||||
| 	// Figure out the items we'll be copying into the slice | ||||
| 	var items []ast.Node | ||||
| 	switch n := node.(type) { | ||||
| 	case *ast.ObjectList: | ||||
| 		items = make([]ast.Node, len(n.Items)) | ||||
| 		for i, item := range n.Items { | ||||
| 			items[i] = item | ||||
| 		} | ||||
| 	case *ast.ObjectType: | ||||
| 		items = []ast.Node{n} | ||||
| 	case *ast.ListType: | ||||
| 		items = n.List | ||||
| 	default: | ||||
| 		return &parser.PosError{ | ||||
| 			Pos: node.Pos(), | ||||
| 			Err: fmt.Errorf("unknown slice type: %T", node), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for i, item := range items { | ||||
| 		fieldName := fmt.Sprintf("%s[%d]", name, i) | ||||
|  | ||||
| 		// Decode | ||||
| 		val := reflect.Indirect(reflect.New(resultElemType)) | ||||
| 		if err := d.decode(fieldName, item, val); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		// Append it onto the slice | ||||
| 		result = reflect.Append(result, val) | ||||
| 	} | ||||
|  | ||||
| 	set.Set(result) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { | ||||
| 	switch n := node.(type) { | ||||
| 	case *ast.LiteralType: | ||||
| 		switch n.Token.Type { | ||||
| 		case token.NUMBER: | ||||
| 			result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) | ||||
| 			return nil | ||||
| 		case token.STRING, token.HEREDOC: | ||||
| 			result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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 { | ||||
| 	var item *ast.ObjectItem | ||||
| 	if it, ok := node.(*ast.ObjectItem); ok { | ||||
| 		item = it | ||||
| 		node = it.Val | ||||
| 	} | ||||
|  | ||||
| 	if ot, ok := node.(*ast.ObjectType); ok { | ||||
| 		node = ot.List | ||||
| 	} | ||||
|  | ||||
| 	// Handle the special case where the object itself is a literal. Previously | ||||
| 	// the yacc parser would always ensure top-level elements were arrays. The new | ||||
| 	// parser does not make the same guarantees, thus we need to convert any | ||||
| 	// top-level literal elements into a list. | ||||
| 	if _, ok := node.(*ast.LiteralType); ok { | ||||
| 		node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} | ||||
| 	} | ||||
|  | ||||
| 	list, ok := node.(*ast.ObjectList) | ||||
| 	if !ok { | ||||
| 		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. | ||||
| 	// There can be more than one struct if there are embedded structs | ||||
| 	// that are squashed. | ||||
| 	structs := make([]reflect.Value, 1, 5) | ||||
| 	structs[0] = result | ||||
|  | ||||
| 	// Compile the list of all the fields that we're going to be decoding | ||||
| 	// from all the structs. | ||||
| 	fields := make(map[*reflect.StructField]reflect.Value) | ||||
| 	for len(structs) > 0 { | ||||
| 		structVal := structs[0] | ||||
| 		structs = structs[1:] | ||||
|  | ||||
| 		structType := structVal.Type() | ||||
| 		for i := 0; i < structType.NumField(); i++ { | ||||
| 			fieldType := structType.Field(i) | ||||
| 			tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") | ||||
|  | ||||
| 			// Ignore fields with tag name "-" | ||||
| 			if tagParts[0] == "-" { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			if fieldType.Anonymous { | ||||
| 				fieldKind := fieldType.Type.Kind() | ||||
| 				if fieldKind != reflect.Struct { | ||||
| 					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 | ||||
| 				// if specified in the tag. | ||||
| 				squash := false | ||||
| 				for _, tag := range tagParts[1:] { | ||||
| 					if tag == "squash" { | ||||
| 						squash = true | ||||
| 						break | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				if squash { | ||||
| 					structs = append( | ||||
| 						structs, result.FieldByName(fieldType.Name)) | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Normal struct field, store it away | ||||
| 			fields[&fieldType] = structVal.Field(i) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	usedKeys := make(map[string]struct{}) | ||||
| 	decodedFields := make([]string, 0, len(fields)) | ||||
| 	decodedFieldsVal := make([]reflect.Value, 0) | ||||
| 	unusedKeysVal := make([]reflect.Value, 0) | ||||
| 	for fieldType, field := range fields { | ||||
| 		if !field.IsValid() { | ||||
| 			// This should never happen | ||||
| 			panic("field is not valid") | ||||
| 		} | ||||
|  | ||||
| 		// If we can't set the field, then it is unexported or something, | ||||
| 		// and we just continue onwards. | ||||
| 		if !field.CanSet() { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		fieldName := fieldType.Name | ||||
|  | ||||
| 		tagValue := fieldType.Tag.Get(tagName) | ||||
| 		tagParts := strings.SplitN(tagValue, ",", 2) | ||||
| 		if len(tagParts) >= 2 { | ||||
| 			switch tagParts[1] { | ||||
| 			case "decodedFields": | ||||
| 				decodedFieldsVal = append(decodedFieldsVal, field) | ||||
| 				continue | ||||
| 			case "key": | ||||
| 				if item == nil { | ||||
| 					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)) | ||||
| 				continue | ||||
| 			case "unusedKeys": | ||||
| 				unusedKeysVal = append(unusedKeysVal, field) | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if tagParts[0] != "" { | ||||
| 			fieldName = tagParts[0] | ||||
| 		} | ||||
|  | ||||
| 		// Determine the element we'll use to decode. If it is a single | ||||
| 		// match (only object with the field), then we decode it exactly. | ||||
| 		// If it is a prefix match, then we decode the matches. | ||||
| 		filter := list.Filter(fieldName) | ||||
| 		prefixMatches := filter.Children() | ||||
| 		matches := filter.Elem() | ||||
| 		if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Track the used key | ||||
| 		usedKeys[fieldName] = struct{}{} | ||||
|  | ||||
| 		// Create the field name and decode. We range over the elements | ||||
| 		// because we actually want the value. | ||||
| 		fieldName = fmt.Sprintf("%s.%s", name, fieldName) | ||||
| 		if len(prefixMatches.Items) > 0 { | ||||
| 			if err := d.decode(fieldName, prefixMatches, field); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		for _, match := range matches.Items { | ||||
| 			var decodeNode ast.Node = match.Val | ||||
| 			if ot, ok := decodeNode.(*ast.ObjectType); ok { | ||||
| 				decodeNode = &ast.ObjectList{Items: ot.List.Items} | ||||
| 			} | ||||
|  | ||||
| 			if err := d.decode(fieldName, decodeNode, field); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		decodedFields = append(decodedFields, fieldType.Name) | ||||
| 	} | ||||
|  | ||||
| 	if len(decodedFieldsVal) > 0 { | ||||
| 		// Sort it so that it is deterministic | ||||
| 		sort.Strings(decodedFields) | ||||
|  | ||||
| 		for _, v := range decodedFieldsVal { | ||||
| 			v.Set(reflect.ValueOf(decodedFields)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // findNodeType returns the type of ast.Node | ||||
| func findNodeType() reflect.Type { | ||||
| 	var nodeContainer struct { | ||||
| 		Node ast.Node | ||||
| 	} | ||||
| 	value := reflect.ValueOf(nodeContainer).FieldByName("Node") | ||||
| 	return value.Type() | ||||
| } | ||||
		Reference in New Issue
	
	Block a user