Path: blob/main/vendor/go.yaml.in/yaml/v3/decode.go
2872 views
//1// Copyright (c) 2011-2019 Canonical Ltd2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.1415package yaml1617import (18"encoding"19"encoding/base64"20"fmt"21"io"22"math"23"reflect"24"strconv"25"time"26)2728// ----------------------------------------------------------------------------29// Parser, produces a node tree out of a libyaml event stream.3031type parser struct {32parser yaml_parser_t33event yaml_event_t34doc *Node35anchors map[string]*Node36doneInit bool37textless bool38}3940func newParser(b []byte) *parser {41p := parser{}42if !yaml_parser_initialize(&p.parser) {43panic("failed to initialize YAML emitter")44}45if len(b) == 0 {46b = []byte{'\n'}47}48yaml_parser_set_input_string(&p.parser, b)49return &p50}5152func newParserFromReader(r io.Reader) *parser {53p := parser{}54if !yaml_parser_initialize(&p.parser) {55panic("failed to initialize YAML emitter")56}57yaml_parser_set_input_reader(&p.parser, r)58return &p59}6061func (p *parser) init() {62if p.doneInit {63return64}65p.anchors = make(map[string]*Node)66p.expect(yaml_STREAM_START_EVENT)67p.doneInit = true68}6970func (p *parser) destroy() {71if p.event.typ != yaml_NO_EVENT {72yaml_event_delete(&p.event)73}74yaml_parser_delete(&p.parser)75}7677// expect consumes an event from the event stream and78// checks that it's of the expected type.79func (p *parser) expect(e yaml_event_type_t) {80if p.event.typ == yaml_NO_EVENT {81if !yaml_parser_parse(&p.parser, &p.event) {82p.fail()83}84}85if p.event.typ == yaml_STREAM_END_EVENT {86failf("attempted to go past the end of stream; corrupted value?")87}88if p.event.typ != e {89p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)90p.fail()91}92yaml_event_delete(&p.event)93p.event.typ = yaml_NO_EVENT94}9596// peek peeks at the next event in the event stream,97// puts the results into p.event and returns the event type.98func (p *parser) peek() yaml_event_type_t {99if p.event.typ != yaml_NO_EVENT {100return p.event.typ101}102// It's curious choice from the underlying API to generally return a103// positive result on success, but on this case return true in an error104// scenario. This was the source of bugs in the past (issue #666).105if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {106p.fail()107}108return p.event.typ109}110111func (p *parser) fail() {112var where string113var line int114if p.parser.context_mark.line != 0 {115line = p.parser.context_mark.line116// Scanner errors don't iterate line before returning error117if p.parser.error == yaml_SCANNER_ERROR {118line++119}120} else if p.parser.problem_mark.line != 0 {121line = p.parser.problem_mark.line122// Scanner errors don't iterate line before returning error123if p.parser.error == yaml_SCANNER_ERROR {124line++125}126}127if line != 0 {128where = "line " + strconv.Itoa(line) + ": "129}130var msg string131if len(p.parser.problem) > 0 {132msg = p.parser.problem133} else {134msg = "unknown problem parsing YAML content"135}136failf("%s%s", where, msg)137}138139func (p *parser) anchor(n *Node, anchor []byte) {140if anchor != nil {141n.Anchor = string(anchor)142p.anchors[n.Anchor] = n143}144}145146func (p *parser) parse() *Node {147p.init()148switch p.peek() {149case yaml_SCALAR_EVENT:150return p.scalar()151case yaml_ALIAS_EVENT:152return p.alias()153case yaml_MAPPING_START_EVENT:154return p.mapping()155case yaml_SEQUENCE_START_EVENT:156return p.sequence()157case yaml_DOCUMENT_START_EVENT:158return p.document()159case yaml_STREAM_END_EVENT:160// Happens when attempting to decode an empty buffer.161return nil162case yaml_TAIL_COMMENT_EVENT:163panic("internal error: unexpected tail comment event (please report)")164default:165panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())166}167}168169func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {170var style Style171if tag != "" && tag != "!" {172tag = shortTag(tag)173style = TaggedStyle174} else if defaultTag != "" {175tag = defaultTag176} else if kind == ScalarNode {177tag, _ = resolve("", value)178}179n := &Node{180Kind: kind,181Tag: tag,182Value: value,183Style: style,184}185if !p.textless {186n.Line = p.event.start_mark.line + 1187n.Column = p.event.start_mark.column + 1188n.HeadComment = string(p.event.head_comment)189n.LineComment = string(p.event.line_comment)190n.FootComment = string(p.event.foot_comment)191}192return n193}194195func (p *parser) parseChild(parent *Node) *Node {196child := p.parse()197parent.Content = append(parent.Content, child)198return child199}200201func (p *parser) document() *Node {202n := p.node(DocumentNode, "", "", "")203p.doc = n204p.expect(yaml_DOCUMENT_START_EVENT)205p.parseChild(n)206if p.peek() == yaml_DOCUMENT_END_EVENT {207n.FootComment = string(p.event.foot_comment)208}209p.expect(yaml_DOCUMENT_END_EVENT)210return n211}212213func (p *parser) alias() *Node {214n := p.node(AliasNode, "", "", string(p.event.anchor))215n.Alias = p.anchors[n.Value]216if n.Alias == nil {217failf("unknown anchor '%s' referenced", n.Value)218}219p.expect(yaml_ALIAS_EVENT)220return n221}222223func (p *parser) scalar() *Node {224var parsedStyle = p.event.scalar_style()225var nodeStyle Style226switch {227case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:228nodeStyle = DoubleQuotedStyle229case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:230nodeStyle = SingleQuotedStyle231case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:232nodeStyle = LiteralStyle233case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:234nodeStyle = FoldedStyle235}236var nodeValue = string(p.event.value)237var nodeTag = string(p.event.tag)238var defaultTag string239if nodeStyle == 0 {240if nodeValue == "<<" {241defaultTag = mergeTag242}243} else {244defaultTag = strTag245}246n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)247n.Style |= nodeStyle248p.anchor(n, p.event.anchor)249p.expect(yaml_SCALAR_EVENT)250return n251}252253func (p *parser) sequence() *Node {254n := p.node(SequenceNode, seqTag, string(p.event.tag), "")255if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {256n.Style |= FlowStyle257}258p.anchor(n, p.event.anchor)259p.expect(yaml_SEQUENCE_START_EVENT)260for p.peek() != yaml_SEQUENCE_END_EVENT {261p.parseChild(n)262}263n.LineComment = string(p.event.line_comment)264n.FootComment = string(p.event.foot_comment)265p.expect(yaml_SEQUENCE_END_EVENT)266return n267}268269func (p *parser) mapping() *Node {270n := p.node(MappingNode, mapTag, string(p.event.tag), "")271block := true272if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {273block = false274n.Style |= FlowStyle275}276p.anchor(n, p.event.anchor)277p.expect(yaml_MAPPING_START_EVENT)278for p.peek() != yaml_MAPPING_END_EVENT {279k := p.parseChild(n)280if block && k.FootComment != "" {281// Must be a foot comment for the prior value when being dedented.282if len(n.Content) > 2 {283n.Content[len(n.Content)-3].FootComment = k.FootComment284k.FootComment = ""285}286}287v := p.parseChild(n)288if k.FootComment == "" && v.FootComment != "" {289k.FootComment = v.FootComment290v.FootComment = ""291}292if p.peek() == yaml_TAIL_COMMENT_EVENT {293if k.FootComment == "" {294k.FootComment = string(p.event.foot_comment)295}296p.expect(yaml_TAIL_COMMENT_EVENT)297}298}299n.LineComment = string(p.event.line_comment)300n.FootComment = string(p.event.foot_comment)301if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {302n.Content[len(n.Content)-2].FootComment = n.FootComment303n.FootComment = ""304}305p.expect(yaml_MAPPING_END_EVENT)306return n307}308309// ----------------------------------------------------------------------------310// Decoder, unmarshals a node into a provided value.311312type decoder struct {313doc *Node314aliases map[*Node]bool315terrors []string316317stringMapType reflect.Type318generalMapType reflect.Type319320knownFields bool321uniqueKeys bool322decodeCount int323aliasCount int324aliasDepth int325326mergedFields map[interface{}]bool327}328329var (330nodeType = reflect.TypeOf(Node{})331durationType = reflect.TypeOf(time.Duration(0))332stringMapType = reflect.TypeOf(map[string]interface{}{})333generalMapType = reflect.TypeOf(map[interface{}]interface{}{})334ifaceType = generalMapType.Elem()335timeType = reflect.TypeOf(time.Time{})336ptrTimeType = reflect.TypeOf(&time.Time{})337)338339func newDecoder() *decoder {340d := &decoder{341stringMapType: stringMapType,342generalMapType: generalMapType,343uniqueKeys: true,344}345d.aliases = make(map[*Node]bool)346return d347}348349func (d *decoder) terror(n *Node, tag string, out reflect.Value) {350if n.Tag != "" {351tag = n.Tag352}353value := n.Value354if tag != seqTag && tag != mapTag {355if len(value) > 10 {356value = " `" + value[:7] + "...`"357} else {358value = " `" + value + "`"359}360}361d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))362}363364func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {365err := u.UnmarshalYAML(n)366if e, ok := err.(*TypeError); ok {367d.terrors = append(d.terrors, e.Errors...)368return false369}370if err != nil {371fail(err)372}373return true374}375376func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {377terrlen := len(d.terrors)378err := u.UnmarshalYAML(func(v interface{}) (err error) {379defer handleErr(&err)380d.unmarshal(n, reflect.ValueOf(v))381if len(d.terrors) > terrlen {382issues := d.terrors[terrlen:]383d.terrors = d.terrors[:terrlen]384return &TypeError{issues}385}386return nil387})388if e, ok := err.(*TypeError); ok {389d.terrors = append(d.terrors, e.Errors...)390return false391}392if err != nil {393fail(err)394}395return true396}397398// d.prepare initializes and dereferences pointers and calls UnmarshalYAML399// if a value is found to implement it.400// It returns the initialized and dereferenced out value, whether401// unmarshalling was already done by UnmarshalYAML, and if so whether402// its types unmarshalled appropriately.403//404// If n holds a null value, prepare returns before doing anything.405func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {406if n.ShortTag() == nullTag {407return out, false, false408}409again := true410for again {411again = false412if out.Kind() == reflect.Ptr {413if out.IsNil() {414out.Set(reflect.New(out.Type().Elem()))415}416out = out.Elem()417again = true418}419if out.CanAddr() {420outi := out.Addr().Interface()421if u, ok := outi.(Unmarshaler); ok {422good = d.callUnmarshaler(n, u)423return out, true, good424}425if u, ok := outi.(obsoleteUnmarshaler); ok {426good = d.callObsoleteUnmarshaler(n, u)427return out, true, good428}429}430}431return out, false, false432}433434func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {435if n.ShortTag() == nullTag {436return reflect.Value{}437}438for _, num := range index {439for {440if v.Kind() == reflect.Ptr {441if v.IsNil() {442v.Set(reflect.New(v.Type().Elem()))443}444v = v.Elem()445continue446}447break448}449v = v.Field(num)450}451return v452}453454const (455// 400,000 decode operations is ~500kb of dense object declarations, or456// ~5kb of dense object declarations with 10000% alias expansion457alias_ratio_range_low = 400000458459// 4,000,000 decode operations is ~5MB of dense object declarations, or460// ~4.5MB of dense object declarations with 10% alias expansion461alias_ratio_range_high = 4000000462463// alias_ratio_range is the range over which we scale allowed alias ratios464alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)465)466467func allowedAliasRatio(decodeCount int) float64 {468switch {469case decodeCount <= alias_ratio_range_low:470// allow 99% to come from alias expansion for small-to-medium documents471return 0.99472case decodeCount >= alias_ratio_range_high:473// allow 10% to come from alias expansion for very large documents474return 0.10475default:476// scale smoothly from 99% down to 10% over the range.477// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.478// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).479return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)480}481}482483func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {484d.decodeCount++485if d.aliasDepth > 0 {486d.aliasCount++487}488if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {489failf("document contains excessive aliasing")490}491if out.Type() == nodeType {492out.Set(reflect.ValueOf(n).Elem())493return true494}495switch n.Kind {496case DocumentNode:497return d.document(n, out)498case AliasNode:499return d.alias(n, out)500}501out, unmarshaled, good := d.prepare(n, out)502if unmarshaled {503return good504}505switch n.Kind {506case ScalarNode:507good = d.scalar(n, out)508case MappingNode:509good = d.mapping(n, out)510case SequenceNode:511good = d.sequence(n, out)512case 0:513if n.IsZero() {514return d.null(out)515}516fallthrough517default:518failf("cannot decode node with unknown kind %d", n.Kind)519}520return good521}522523func (d *decoder) document(n *Node, out reflect.Value) (good bool) {524if len(n.Content) == 1 {525d.doc = n526d.unmarshal(n.Content[0], out)527return true528}529return false530}531532func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {533if d.aliases[n] {534// TODO this could actually be allowed in some circumstances.535failf("anchor '%s' value contains itself", n.Value)536}537d.aliases[n] = true538d.aliasDepth++539good = d.unmarshal(n.Alias, out)540d.aliasDepth--541delete(d.aliases, n)542return good543}544545var zeroValue reflect.Value546547func resetMap(out reflect.Value) {548for _, k := range out.MapKeys() {549out.SetMapIndex(k, zeroValue)550}551}552553func (d *decoder) null(out reflect.Value) bool {554if out.CanAddr() {555switch out.Kind() {556case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:557out.Set(reflect.Zero(out.Type()))558return true559}560}561return false562}563564func (d *decoder) scalar(n *Node, out reflect.Value) bool {565var tag string566var resolved interface{}567if n.indicatedString() {568tag = strTag569resolved = n.Value570} else {571tag, resolved = resolve(n.Tag, n.Value)572if tag == binaryTag {573data, err := base64.StdEncoding.DecodeString(resolved.(string))574if err != nil {575failf("!!binary value contains invalid base64 data")576}577resolved = string(data)578}579}580if resolved == nil {581return d.null(out)582}583if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {584// We've resolved to exactly the type we want, so use that.585out.Set(resolvedv)586return true587}588// Perhaps we can use the value as a TextUnmarshaler to589// set its value.590if out.CanAddr() {591u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)592if ok {593var text []byte594if tag == binaryTag {595text = []byte(resolved.(string))596} else {597// We let any value be unmarshaled into TextUnmarshaler.598// That might be more lax than we'd like, but the599// TextUnmarshaler itself should bowl out any dubious values.600text = []byte(n.Value)601}602err := u.UnmarshalText(text)603if err != nil {604fail(err)605}606return true607}608}609switch out.Kind() {610case reflect.String:611if tag == binaryTag {612out.SetString(resolved.(string))613return true614}615out.SetString(n.Value)616return true617case reflect.Interface:618out.Set(reflect.ValueOf(resolved))619return true620case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:621// This used to work in v2, but it's very unfriendly.622isDuration := out.Type() == durationType623624switch resolved := resolved.(type) {625case int:626if !isDuration && !out.OverflowInt(int64(resolved)) {627out.SetInt(int64(resolved))628return true629}630case int64:631if !isDuration && !out.OverflowInt(resolved) {632out.SetInt(resolved)633return true634}635case uint64:636if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {637out.SetInt(int64(resolved))638return true639}640case float64:641if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {642out.SetInt(int64(resolved))643return true644}645case string:646if out.Type() == durationType {647d, err := time.ParseDuration(resolved)648if err == nil {649out.SetInt(int64(d))650return true651}652}653}654case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:655switch resolved := resolved.(type) {656case int:657if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {658out.SetUint(uint64(resolved))659return true660}661case int64:662if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {663out.SetUint(uint64(resolved))664return true665}666case uint64:667if !out.OverflowUint(uint64(resolved)) {668out.SetUint(uint64(resolved))669return true670}671case float64:672if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {673out.SetUint(uint64(resolved))674return true675}676}677case reflect.Bool:678switch resolved := resolved.(type) {679case bool:680out.SetBool(resolved)681return true682case string:683// This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).684// It only works if explicitly attempting to unmarshal into a typed bool value.685switch resolved {686case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":687out.SetBool(true)688return true689case "n", "N", "no", "No", "NO", "off", "Off", "OFF":690out.SetBool(false)691return true692}693}694case reflect.Float32, reflect.Float64:695switch resolved := resolved.(type) {696case int:697out.SetFloat(float64(resolved))698return true699case int64:700out.SetFloat(float64(resolved))701return true702case uint64:703out.SetFloat(float64(resolved))704return true705case float64:706out.SetFloat(resolved)707return true708}709case reflect.Struct:710if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {711out.Set(resolvedv)712return true713}714case reflect.Ptr:715panic("yaml internal error: please report the issue")716}717d.terror(n, tag, out)718return false719}720721func settableValueOf(i interface{}) reflect.Value {722v := reflect.ValueOf(i)723sv := reflect.New(v.Type()).Elem()724sv.Set(v)725return sv726}727728func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {729l := len(n.Content)730731var iface reflect.Value732switch out.Kind() {733case reflect.Slice:734out.Set(reflect.MakeSlice(out.Type(), l, l))735case reflect.Array:736if l != out.Len() {737failf("invalid array: want %d elements but got %d", out.Len(), l)738}739case reflect.Interface:740// No type hints. Will have to use a generic sequence.741iface = out742out = settableValueOf(make([]interface{}, l))743default:744d.terror(n, seqTag, out)745return false746}747et := out.Type().Elem()748749j := 0750for i := 0; i < l; i++ {751e := reflect.New(et).Elem()752if ok := d.unmarshal(n.Content[i], e); ok {753out.Index(j).Set(e)754j++755}756}757if out.Kind() != reflect.Array {758out.Set(out.Slice(0, j))759}760if iface.IsValid() {761iface.Set(out)762}763return true764}765766func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {767l := len(n.Content)768if d.uniqueKeys {769nerrs := len(d.terrors)770for i := 0; i < l; i += 2 {771ni := n.Content[i]772for j := i + 2; j < l; j += 2 {773nj := n.Content[j]774if ni.Kind == nj.Kind && ni.Value == nj.Value {775d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))776}777}778}779if len(d.terrors) > nerrs {780return false781}782}783switch out.Kind() {784case reflect.Struct:785return d.mappingStruct(n, out)786case reflect.Map:787// okay788case reflect.Interface:789iface := out790if isStringMap(n) {791out = reflect.MakeMap(d.stringMapType)792} else {793out = reflect.MakeMap(d.generalMapType)794}795iface.Set(out)796default:797d.terror(n, mapTag, out)798return false799}800801outt := out.Type()802kt := outt.Key()803et := outt.Elem()804805stringMapType := d.stringMapType806generalMapType := d.generalMapType807if outt.Elem() == ifaceType {808if outt.Key().Kind() == reflect.String {809d.stringMapType = outt810} else if outt.Key() == ifaceType {811d.generalMapType = outt812}813}814815mergedFields := d.mergedFields816d.mergedFields = nil817818var mergeNode *Node819820mapIsNew := false821if out.IsNil() {822out.Set(reflect.MakeMap(outt))823mapIsNew = true824}825for i := 0; i < l; i += 2 {826if isMerge(n.Content[i]) {827mergeNode = n.Content[i+1]828continue829}830k := reflect.New(kt).Elem()831if d.unmarshal(n.Content[i], k) {832if mergedFields != nil {833ki := k.Interface()834if d.getPossiblyUnhashableKey(mergedFields, ki) {835continue836}837d.setPossiblyUnhashableKey(mergedFields, ki, true)838}839kkind := k.Kind()840if kkind == reflect.Interface {841kkind = k.Elem().Kind()842}843if kkind == reflect.Map || kkind == reflect.Slice {844failf("invalid map key: %#v", k.Interface())845}846e := reflect.New(et).Elem()847if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {848out.SetMapIndex(k, e)849}850}851}852853d.mergedFields = mergedFields854if mergeNode != nil {855d.merge(n, mergeNode, out)856}857858d.stringMapType = stringMapType859d.generalMapType = generalMapType860return true861}862863func isStringMap(n *Node) bool {864if n.Kind != MappingNode {865return false866}867l := len(n.Content)868for i := 0; i < l; i += 2 {869shortTag := n.Content[i].ShortTag()870if shortTag != strTag && shortTag != mergeTag {871return false872}873}874return true875}876877func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {878sinfo, err := getStructInfo(out.Type())879if err != nil {880panic(err)881}882883var inlineMap reflect.Value884var elemType reflect.Type885if sinfo.InlineMap != -1 {886inlineMap = out.Field(sinfo.InlineMap)887elemType = inlineMap.Type().Elem()888}889890for _, index := range sinfo.InlineUnmarshalers {891field := d.fieldByIndex(n, out, index)892d.prepare(n, field)893}894895mergedFields := d.mergedFields896d.mergedFields = nil897var mergeNode *Node898var doneFields []bool899if d.uniqueKeys {900doneFields = make([]bool, len(sinfo.FieldsList))901}902name := settableValueOf("")903l := len(n.Content)904for i := 0; i < l; i += 2 {905ni := n.Content[i]906if isMerge(ni) {907mergeNode = n.Content[i+1]908continue909}910if !d.unmarshal(ni, name) {911continue912}913sname := name.String()914if mergedFields != nil {915if mergedFields[sname] {916continue917}918mergedFields[sname] = true919}920if info, ok := sinfo.FieldsMap[sname]; ok {921if d.uniqueKeys {922if doneFields[info.Id] {923d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))924continue925}926doneFields[info.Id] = true927}928var field reflect.Value929if info.Inline == nil {930field = out.Field(info.Num)931} else {932field = d.fieldByIndex(n, out, info.Inline)933}934d.unmarshal(n.Content[i+1], field)935} else if sinfo.InlineMap != -1 {936if inlineMap.IsNil() {937inlineMap.Set(reflect.MakeMap(inlineMap.Type()))938}939value := reflect.New(elemType).Elem()940d.unmarshal(n.Content[i+1], value)941inlineMap.SetMapIndex(name, value)942} else if d.knownFields {943d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))944}945}946947d.mergedFields = mergedFields948if mergeNode != nil {949d.merge(n, mergeNode, out)950}951return true952}953954func failWantMap() {955failf("map merge requires map or sequence of maps as the value")956}957958func (d *decoder) setPossiblyUnhashableKey(m map[interface{}]bool, key interface{}, value bool) {959defer func() {960if err := recover(); err != nil {961failf("%v", err)962}963}()964m[key] = value965}966967func (d *decoder) getPossiblyUnhashableKey(m map[interface{}]bool, key interface{}) bool {968defer func() {969if err := recover(); err != nil {970failf("%v", err)971}972}()973return m[key]974}975976func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {977mergedFields := d.mergedFields978if mergedFields == nil {979d.mergedFields = make(map[interface{}]bool)980for i := 0; i < len(parent.Content); i += 2 {981k := reflect.New(ifaceType).Elem()982if d.unmarshal(parent.Content[i], k) {983d.setPossiblyUnhashableKey(d.mergedFields, k.Interface(), true)984}985}986}987988switch merge.Kind {989case MappingNode:990d.unmarshal(merge, out)991case AliasNode:992if merge.Alias != nil && merge.Alias.Kind != MappingNode {993failWantMap()994}995d.unmarshal(merge, out)996case SequenceNode:997for i := 0; i < len(merge.Content); i++ {998ni := merge.Content[i]999if ni.Kind == AliasNode {1000if ni.Alias != nil && ni.Alias.Kind != MappingNode {1001failWantMap()1002}1003} else if ni.Kind != MappingNode {1004failWantMap()1005}1006d.unmarshal(ni, out)1007}1008default:1009failWantMap()1010}10111012d.mergedFields = mergedFields1013}10141015func isMerge(n *Node) bool {1016return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)1017}101810191020