Sfoglia il codice sorgente

Initial sketch for v3.

Gustavo Niemeyer 8 anni fa
parent
commit
e7ae84ed91
8 ha cambiato i file con 320 aggiunte e 170 eliminazioni
  1. 1 1
      apic.go
  2. 197 126
      decode.go
  3. 6 7
      decode_test.go
  4. 1 1
      emitterc.go
  5. 94 28
      encode.go
  6. 1 1
      resolve.go
  7. 14 0
      yaml.go
  8. 6 6
      yamlh.go

+ 1 - 1
apic.go

@@ -138,7 +138,7 @@ func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
 	emitter.canonical = canonical
 }
 
-//// Set the indentation increment.
+// Set the indentation increment.
 func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
 	if indent < 2 || indent > 9 {
 		indent = 2

+ 197 - 126
decode.go

@@ -8,27 +8,76 @@ import (
 	"math"
 	"reflect"
 	"strconv"
+	"strings"
 	"time"
 )
 
+type NodeKind uint32
+
+const (
+	DocumentNode NodeKind = 1 << iota
+	SequenceNode
+	MappingNode
+	ScalarNode
+	AliasNode
+)
+
+type Style uint32
+
 const (
-	documentNode = 1 << iota
-	mappingNode
-	sequenceNode
-	scalarNode
-	aliasNode
+	DoubleQuotedStyle Style = 1 << iota
+	SingleQuotedStyle
+	LiteralStyle
+	FoldedStyle
+	FlowStyle
 )
 
-type node struct {
-	kind         int
-	line, column int
-	tag          string
-	// For an alias node, alias holds the resolved alias.
-	alias    *node
-	value    string
-	implicit bool
-	children []*node
-	anchors  map[string]*node
+type Node struct {
+	Kind     NodeKind
+	Style    Style
+	Line     int
+	Column   int
+	Tag      string
+	Value    string
+	// TODO Alias should probably be the string, and then perhaps have a hidden cache?
+	Alias    *Node // Resolved alias for alias nodes.
+	Anchors  map[string]*Node
+	Children []*Node
+}
+
+func (n *Node) implicit() bool {
+	return n.Style&(SingleQuotedStyle|DoubleQuotedStyle) == 0 && (n.Tag == "" || n.Tag == "!")
+}
+
+func (n *Node) ShortTag() string {
+	tag := n.LongTag()
+	if strings.HasPrefix(tag, longTagPrefix) {
+		return "!!" + tag[len(longTagPrefix):]
+	}
+	return tag
+}
+
+func (n *Node) LongTag() string {
+	if n.Tag == "" || n.Tag == "!" {
+		if n.Style&(SingleQuotedStyle|DoubleQuotedStyle) != 0 {
+			return yaml_STR_TAG
+		}
+		tag, _ := resolve("", n.Value)
+		return tag
+	} else if strings.HasPrefix(n.Tag, "!!") {
+		return longTagPrefix + n.Tag[2:]
+	}
+	return n.Tag
+}
+
+func (n *Node) SetString(s string) {
+	n.Kind = ScalarNode
+	n.Value = s
+	if strings.Contains(s, "\n") {
+		n.Style = LiteralStyle
+	} else if n.LongTag() != "tag:yaml.org,2002:str" {
+		n.Style = DoubleQuotedStyle
+	}
 }
 
 // ----------------------------------------------------------------------------
@@ -37,7 +86,7 @@ type node struct {
 type parser struct {
 	parser   yaml_parser_t
 	event    yaml_event_t
-	doc      *node
+	doc      *Node
 	doneInit bool
 }
 
@@ -132,13 +181,13 @@ func (p *parser) fail() {
 	failf("%s%s", where, msg)
 }
 
-func (p *parser) anchor(n *node, anchor []byte) {
+func (p *parser) anchor(n *Node, anchor []byte) {
 	if anchor != nil {
-		p.doc.anchors[string(anchor)] = n
+		p.doc.Anchors[string(anchor)] = n
 	}
 }
 
-func (p *parser) parse() *node {
+func (p *parser) parse() *Node {
 	p.init()
 	switch p.peek() {
 	case yaml_SCALAR_EVENT:
@@ -159,62 +208,86 @@ func (p *parser) parse() *node {
 	}
 }
 
-func (p *parser) node(kind int) *node {
-	return &node{
-		kind:   kind,
-		line:   p.event.start_mark.line,
-		column: p.event.start_mark.column,
+func (p *parser) node(kind NodeKind) *Node {
+	return &Node{
+		Kind:   kind,
+		Line:   p.event.start_mark.line,
+		Column: p.event.start_mark.column,
 	}
 }
 
-func (p *parser) document() *node {
-	n := p.node(documentNode)
-	n.anchors = make(map[string]*node)
+func (p *parser) parseChild(parent *Node) {
+	child := p.parse()
+	parent.Children = append(parent.Children, child)
+}
+
+func (p *parser) document() *Node {
+	n := p.node(DocumentNode)
+	n.Anchors = make(map[string]*Node)
 	p.doc = n
 	p.expect(yaml_DOCUMENT_START_EVENT)
-	n.children = append(n.children, p.parse())
+	p.parseChild(n)
 	p.expect(yaml_DOCUMENT_END_EVENT)
 	return n
 }
 
-func (p *parser) alias() *node {
-	n := p.node(aliasNode)
-	n.value = string(p.event.anchor)
-	n.alias = p.doc.anchors[n.value]
-	if n.alias == nil {
-		failf("unknown anchor '%s' referenced", n.value)
+func (p *parser) alias() *Node {
+	n := p.node(AliasNode)
+	n.Value = string(p.event.anchor)
+	n.Alias = p.doc.Anchors[n.Value]
+	if n.Alias == nil {
+		failf("unknown anchor '%s' referenced", n.Value)
 	}
 	p.expect(yaml_ALIAS_EVENT)
 	return n
 }
 
-func (p *parser) scalar() *node {
-	n := p.node(scalarNode)
-	n.value = string(p.event.value)
-	n.tag = string(p.event.tag)
-	n.implicit = p.event.implicit
+func (p *parser) scalar() *Node {
+	n := p.node(ScalarNode)
+	n.Value = string(p.event.value)
+	n.Tag = string(p.event.tag)
+	style := p.event.scalar_style()
+	switch {
+	case style&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
+		n.Style = DoubleQuotedStyle
+	case style&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
+		n.Style = SingleQuotedStyle
+	case style&yaml_LITERAL_SCALAR_STYLE != 0:
+		n.Style = LiteralStyle
+	case style&yaml_FOLDED_SCALAR_STYLE != 0:
+		n.Style = FoldedStyle
+	}
 	p.anchor(n, p.event.anchor)
 	p.expect(yaml_SCALAR_EVENT)
 	return n
 }
 
-func (p *parser) sequence() *node {
-	n := p.node(sequenceNode)
+func (p *parser) sequence() *Node {
+	n := p.node(SequenceNode)
+	n.Tag = string(p.event.tag)
+	if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
+		n.Style = FlowStyle
+	}
 	p.anchor(n, p.event.anchor)
 	p.expect(yaml_SEQUENCE_START_EVENT)
 	for p.peek() != yaml_SEQUENCE_END_EVENT {
-		n.children = append(n.children, p.parse())
+		p.parseChild(n)
 	}
 	p.expect(yaml_SEQUENCE_END_EVENT)
 	return n
 }
 
-func (p *parser) mapping() *node {
-	n := p.node(mappingNode)
+func (p *parser) mapping() *Node {
+	n := p.node(MappingNode)
+	n.Tag = string(p.event.tag)
+	if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
+		n.Style |= FlowStyle
+	}
 	p.anchor(n, p.event.anchor)
 	p.expect(yaml_MAPPING_START_EVENT)
 	for p.peek() != yaml_MAPPING_END_EVENT {
-		n.children = append(n.children, p.parse(), p.parse())
+		p.parseChild(n)
+		p.parseChild(n)
 	}
 	p.expect(yaml_MAPPING_END_EVENT)
 	return n
@@ -224,14 +297,15 @@ func (p *parser) mapping() *node {
 // Decoder, unmarshals a node into a provided value.
 
 type decoder struct {
-	doc     *node
-	aliases map[*node]bool
+	doc     *Node
+	aliases map[*Node]bool
 	mapType reflect.Type
 	terrors []string
 	strict  bool
 }
 
 var (
+	nodeType       = reflect.TypeOf(Node{})
 	mapItemType    = reflect.TypeOf(MapItem{})
 	durationType   = reflect.TypeOf(time.Duration(0))
 	defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
@@ -242,15 +316,15 @@ var (
 
 func newDecoder(strict bool) *decoder {
 	d := &decoder{mapType: defaultMapType, strict: strict}
-	d.aliases = make(map[*node]bool)
+	d.aliases = make(map[*Node]bool)
 	return d
 }
 
-func (d *decoder) terror(n *node, tag string, out reflect.Value) {
-	if n.tag != "" {
-		tag = n.tag
+func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
+	if n.Tag != "" {
+		tag = n.Tag
 	}
-	value := n.value
+	value := n.Value
 	if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
 		if len(value) > 10 {
 			value = " `" + value[:7] + "...`"
@@ -258,10 +332,10 @@ func (d *decoder) terror(n *node, tag string, out reflect.Value) {
 			value = " `" + value + "`"
 		}
 	}
-	d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
+	d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line+1, shortTag(tag), value, out.Type()))
 }
 
-func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
+func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
 	terrlen := len(d.terrors)
 	err := u.UnmarshalYAML(func(v interface{}) (err error) {
 		defer handleErr(&err)
@@ -290,8 +364,8 @@ func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
 // its types unmarshalled appropriately.
 //
 // If n holds a null value, prepare returns before doing anything.
-func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
-	if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
+func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
+	if n.Tag == yaml_NULL_TAG || n.Kind == ScalarNode && n.Tag == "" && (n.Value == "null" || n.Value == "~" || n.Value == "" && n.implicit()) {
 		return out, false, false
 	}
 	again := true
@@ -314,46 +388,50 @@ func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unm
 	return out, false, false
 }
 
-func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
-	switch n.kind {
-	case documentNode:
+func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
+	if out.Type() == nodeType {
+		out.Set(reflect.ValueOf(n).Elem())
+		return true
+	}
+	switch n.Kind {
+	case DocumentNode:
 		return d.document(n, out)
-	case aliasNode:
+	case AliasNode:
 		return d.alias(n, out)
 	}
 	out, unmarshaled, good := d.prepare(n, out)
 	if unmarshaled {
 		return good
 	}
-	switch n.kind {
-	case scalarNode:
+	switch n.Kind {
+	case ScalarNode:
 		good = d.scalar(n, out)
-	case mappingNode:
+	case MappingNode:
 		good = d.mapping(n, out)
-	case sequenceNode:
+	case SequenceNode:
 		good = d.sequence(n, out)
 	default:
-		panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
+		panic("internal error: unknown node kind: " + strconv.Itoa(int(n.Kind)))
 	}
 	return good
 }
 
-func (d *decoder) document(n *node, out reflect.Value) (good bool) {
-	if len(n.children) == 1 {
+func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
+	if len(n.Children) == 1 {
 		d.doc = n
-		d.unmarshal(n.children[0], out)
+		d.unmarshal(n.Children[0], out)
 		return true
 	}
 	return false
 }
 
-func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
+func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
 	if d.aliases[n] {
 		// TODO this could actually be allowed in some circumstances.
-		failf("anchor '%s' value contains itself", n.value)
+		failf("anchor '%s' value contains itself", n.Value)
 	}
 	d.aliases[n] = true
-	good = d.unmarshal(n.alias, out)
+	good = d.unmarshal(n.Alias, out)
 	delete(d.aliases, n)
 	return good
 }
@@ -366,14 +444,14 @@ func resetMap(out reflect.Value) {
 	}
 }
 
-func (d *decoder) scalar(n *node, out reflect.Value) bool {
+func (d *decoder) scalar(n *Node, out reflect.Value) bool {
 	var tag string
 	var resolved interface{}
-	if n.tag == "" && !n.implicit {
+	if n.Tag == "" && !n.implicit() {
 		tag = yaml_STR_TAG
-		resolved = n.value
+		resolved = n.Value
 	} else {
-		tag, resolved = resolve(n.tag, n.value)
+		tag, resolved = resolve(n.Tag, n.Value)
 		if tag == yaml_BINARY_TAG {
 			data, err := base64.StdEncoding.DecodeString(resolved.(string))
 			if err != nil {
@@ -407,7 +485,7 @@ func (d *decoder) scalar(n *node, out reflect.Value) bool {
 				// We let any value be unmarshaled into TextUnmarshaler.
 				// That might be more lax than we'd like, but the
 				// TextUnmarshaler itself should bowl out any dubious values.
-				text = []byte(n.value)
+				text = []byte(n.Value)
 			}
 			err := u.UnmarshalText(text)
 			if err != nil {
@@ -423,19 +501,12 @@ func (d *decoder) scalar(n *node, out reflect.Value) bool {
 			return true
 		}
 		if resolved != nil {
-			out.SetString(n.value)
+			out.SetString(n.Value)
 			return true
 		}
 	case reflect.Interface:
 		if resolved == nil {
 			out.Set(reflect.Zero(out.Type()))
-		} else if tag == yaml_TIMESTAMP_TAG {
-			// It looks like a timestamp but for backward compatibility
-			// reasons we set it as a string, so that code that unmarshals
-			// timestamp-like values into interface{} will continue to
-			// see a string and not a time.Time.
-			// TODO(v3) Drop this.
-			out.Set(reflect.ValueOf(n.value))
 		} else {
 			out.Set(reflect.ValueOf(resolved))
 		}
@@ -540,8 +611,8 @@ func settableValueOf(i interface{}) reflect.Value {
 	return sv
 }
 
-func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
-	l := len(n.children)
+func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
+	l := len(n.Children)
 
 	var iface reflect.Value
 	switch out.Kind() {
@@ -564,7 +635,7 @@ func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
 	j := 0
 	for i := 0; i < l; i++ {
 		e := reflect.New(et).Elem()
-		if ok := d.unmarshal(n.children[i], e); ok {
+		if ok := d.unmarshal(n.Children[i], e); ok {
 			out.Index(j).Set(e)
 			j++
 		}
@@ -578,7 +649,7 @@ func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
 	return true
 }
 
-func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
+func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
 	switch out.Kind() {
 	case reflect.Struct:
 		return d.mappingStruct(n, out)
@@ -615,14 +686,14 @@ func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
 	if out.IsNil() {
 		out.Set(reflect.MakeMap(outt))
 	}
-	l := len(n.children)
+	l := len(n.Children)
 	for i := 0; i < l; i += 2 {
-		if isMerge(n.children[i]) {
-			d.merge(n.children[i+1], out)
+		if isMerge(n.Children[i]) {
+			d.merge(n.Children[i+1], out)
 			continue
 		}
 		k := reflect.New(kt).Elem()
-		if d.unmarshal(n.children[i], k) {
+		if d.unmarshal(n.Children[i], k) {
 			kkind := k.Kind()
 			if kkind == reflect.Interface {
 				kkind = k.Elem().Kind()
@@ -631,8 +702,8 @@ func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
 				failf("invalid map key: %#v", k.Interface())
 			}
 			e := reflect.New(et).Elem()
-			if d.unmarshal(n.children[i+1], e) {
-				d.setMapIndex(n.children[i+1], out, k, e)
+			if d.unmarshal(n.Children[i+1], e) {
+				d.setMapIndex(n.Children[i+1], out, k, e)
 			}
 		}
 	}
@@ -640,15 +711,15 @@ func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
 	return true
 }
 
-func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
+func (d *decoder) setMapIndex(n *Node, out, k, v reflect.Value) {
 	if d.strict && out.MapIndex(k) != zeroValue {
-		d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
+		d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.Line+1, k.Interface()))
 		return
 	}
 	out.SetMapIndex(k, v)
 }
 
-func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
+func (d *decoder) mappingSlice(n *Node, out reflect.Value) (good bool) {
 	outt := out.Type()
 	if outt.Elem() != mapItemType {
 		d.terror(n, yaml_MAP_TAG, out)
@@ -659,17 +730,17 @@ func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
 	d.mapType = outt
 
 	var slice []MapItem
-	var l = len(n.children)
+	var l = len(n.Children)
 	for i := 0; i < l; i += 2 {
-		if isMerge(n.children[i]) {
-			d.merge(n.children[i+1], out)
+		if isMerge(n.Children[i]) {
+			d.merge(n.Children[i+1], out)
 			continue
 		}
 		item := MapItem{}
 		k := reflect.ValueOf(&item.Key).Elem()
-		if d.unmarshal(n.children[i], k) {
+		if d.unmarshal(n.Children[i], k) {
 			v := reflect.ValueOf(&item.Value).Elem()
-			if d.unmarshal(n.children[i+1], v) {
+			if d.unmarshal(n.Children[i+1], v) {
 				slice = append(slice, item)
 			}
 		}
@@ -679,13 +750,13 @@ func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
 	return true
 }
 
-func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
+func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
 	sinfo, err := getStructInfo(out.Type())
 	if err != nil {
 		panic(err)
 	}
 	name := settableValueOf("")
-	l := len(n.children)
+	l := len(n.Children)
 
 	var inlineMap reflect.Value
 	var elemType reflect.Type
@@ -700,9 +771,9 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
 		doneFields = make([]bool, len(sinfo.FieldsList))
 	}
 	for i := 0; i < l; i += 2 {
-		ni := n.children[i]
+		ni := n.Children[i]
 		if isMerge(ni) {
-			d.merge(n.children[i+1], out)
+			d.merge(n.Children[i+1], out)
 			continue
 		}
 		if !d.unmarshal(ni, name) {
@@ -711,7 +782,7 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
 		if info, ok := sinfo.FieldsMap[name.String()]; ok {
 			if d.strict {
 				if doneFields[info.Id] {
-					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
+					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line+1, name.String(), out.Type()))
 					continue
 				}
 				doneFields[info.Id] = true
@@ -722,16 +793,16 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
 			} else {
 				field = out.FieldByIndex(info.Inline)
 			}
-			d.unmarshal(n.children[i+1], field)
+			d.unmarshal(n.Children[i+1], field)
 		} else if sinfo.InlineMap != -1 {
 			if inlineMap.IsNil() {
 				inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
 			}
 			value := reflect.New(elemType).Elem()
-			d.unmarshal(n.children[i+1], value)
-			d.setMapIndex(n.children[i+1], inlineMap, name, value)
+			d.unmarshal(n.Children[i+1], value)
+			d.setMapIndex(n.Children[i+1], inlineMap, name, value)
 		} else if d.strict {
-			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
+			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line+1, name.String(), out.Type()))
 		}
 	}
 	return true
@@ -741,26 +812,26 @@ func failWantMap() {
 	failf("map merge requires map or sequence of maps as the value")
 }
 
-func (d *decoder) merge(n *node, out reflect.Value) {
-	switch n.kind {
-	case mappingNode:
+func (d *decoder) merge(n *Node, out reflect.Value) {
+	switch n.Kind {
+	case MappingNode:
 		d.unmarshal(n, out)
-	case aliasNode:
-		an, ok := d.doc.anchors[n.value]
-		if ok && an.kind != mappingNode {
+	case AliasNode:
+		an, ok := d.doc.Anchors[n.Value]
+		if ok && an.Kind != MappingNode {
 			failWantMap()
 		}
 		d.unmarshal(n, out)
-	case sequenceNode:
+	case SequenceNode:
 		// Step backwards as earlier nodes take precedence.
-		for i := len(n.children) - 1; i >= 0; i-- {
-			ni := n.children[i]
-			if ni.kind == aliasNode {
-				an, ok := d.doc.anchors[ni.value]
-				if ok && an.kind != mappingNode {
+		for i := len(n.Children) - 1; i >= 0; i-- {
+			ni := n.Children[i]
+			if ni.Kind == AliasNode {
+				an, ok := d.doc.Anchors[ni.Value]
+				if ok && an.Kind != MappingNode {
 					failWantMap()
 				}
-			} else if ni.kind != mappingNode {
+			} else if ni.Kind != MappingNode {
 				failWantMap()
 			}
 			d.unmarshal(ni, out)
@@ -770,6 +841,6 @@ func (d *decoder) merge(n *node, out reflect.Value) {
 	}
 }
 
-func isMerge(n *node) bool {
-	return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
+func isMerge(n *Node) bool {
+	return n.Kind == ScalarNode && n.Value == "<<" && (n.implicit() || n.Tag == yaml_MERGE_TAG)
 }

+ 6 - 7
decode_test.go

@@ -655,12 +655,12 @@ var unmarshalTests = []struct {
 	{
 		// explicit timestamp tag into interface.
 		"a: !!timestamp \"2015-01-01\"",
-		map[string]interface{}{"a": "2015-01-01"},
+		map[string]interface{}{"a": time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)},
 	},
 	{
 		// implicit timestamp tag into interface.
 		"a: 2015-01-01",
-		map[string]interface{}{"a": "2015-01-01"},
+		map[string]interface{}{"a": time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)},
 	},
 
 	// Encode empty lists as zero-length slices.
@@ -703,10 +703,10 @@ var unmarshalTests = []struct {
 	{
 		"First occurrence: &anchor Foo\nSecond occurrence: *anchor\nOverride anchor: &anchor Bar\nReuse anchor: *anchor\n",
 		map[interface{}]interface{}{
-			"Reuse anchor":      "Bar",
 			"First occurrence":  "Foo",
 			"Second occurrence": "Foo",
 			"Override anchor":   "Bar",
+			"Reuse anchor":      "Bar",
 		},
 	},
 	// Single document with garbage following it.
@@ -740,16 +740,15 @@ func (s *S) TestUnmarshal(c *C) {
 	}
 }
 
-// TODO(v3): This test should also work when unmarshaling onto an interface{}.
 func (s *S) TestUnmarshalFullTimestamp(c *C) {
 	// Full timestamp in same format as encoded. This is confirmed to be
 	// properly decoded by Python as a timestamp as well.
 	var str = "2015-02-24T18:19:39.123456789-03:00"
-	var t time.Time
+	var t interface{}
 	err := yaml.Unmarshal([]byte(str), &t)
 	c.Assert(err, IsNil)
-	c.Assert(t, Equals, time.Date(2015, 2, 24, 18, 19, 39, 123456789, t.Location()))
-	c.Assert(t.In(time.UTC), Equals, time.Date(2015, 2, 24, 21, 19, 39, 123456789, time.UTC))
+	c.Assert(t, Equals, time.Date(2015, 2, 24, 18, 19, 39, 123456789, t.(time.Time).Location()))
+	c.Assert(t.(time.Time).In(time.UTC), Equals, time.Date(2015, 2, 24, 21, 19, 39, 123456789, time.UTC))
 }
 
 func (s *S) TestDecoderSingleDocument(c *C) {

+ 1 - 1
emitterc.go

@@ -392,7 +392,7 @@ func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event
 			if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
 				return false
 			}
-			if emitter.canonical {
+			if emitter.canonical || true {
 				if !yaml_emitter_write_indent(emitter) {
 					return false
 				}

+ 94 - 28
encode.go

@@ -88,14 +88,21 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
 		return
 	}
 	iface := in.Interface()
-	switch m := iface.(type) {
-	case time.Time, *time.Time:
-		// Although time.Time implements TextMarshaler,
-		// we don't want to treat it as a string for YAML
-		// purposes because YAML has special support for
-		// timestamps.
+	switch value := iface.(type) {
+	case *Node:
+		e.nodev(in)
+		return
+	case time.Time:
+		e.timev(tag, in)
+		return
+	case *time.Time:
+		e.timev(tag, in.Elem())
+		return
+	case time.Duration:
+		e.stringv(tag, reflect.ValueOf(value.String()))
+		return
 	case Marshaler:
-		v, err := m.MarshalYAML()
+		v, err := value.MarshalYAML()
 		if err != nil {
 			fail(err)
 		}
@@ -105,7 +112,7 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
 		}
 		in = reflect.ValueOf(v)
 	case encoding.TextMarshaler:
-		text, err := m.MarshalText()
+		text, err := value.MarshalText()
 		if err != nil {
 			fail(err)
 		}
@@ -120,31 +127,15 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
 	case reflect.Map:
 		e.mapv(tag, in)
 	case reflect.Ptr:
-		if in.Type() == ptrTimeType {
-			e.timev(tag, in.Elem())
-		} else {
-			e.marshal(tag, in.Elem())
-		}
+		e.marshal(tag, in.Elem())
 	case reflect.Struct:
-		if in.Type() == timeType {
-			e.timev(tag, in)
-		} else {
-			e.structv(tag, in)
-		}
+		e.structv(tag, in)
 	case reflect.Slice, reflect.Array:
-		if in.Type().Elem() == mapItemType {
-			e.itemsv(tag, in)
-		} else {
-			e.slicev(tag, in)
-		}
+		e.slicev(tag, in)
 	case reflect.String:
 		e.stringv(tag, in)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		if in.Type() == durationType {
-			e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String()))
-		} else {
-			e.intv(tag, in)
-		}
+		e.intv(tag, in)
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 		e.uintv(tag, in)
 	case reflect.Float32, reflect.Float64:
@@ -360,3 +351,78 @@ func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_
 	e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
 	e.emit()
 }
+
+func (e *encoder) nodev(in reflect.Value) {
+	e.node(in.Interface().(*Node))
+}
+
+func (e *encoder) node(node *Node) {
+	switch node.Kind {
+	case DocumentNode:
+		for _, node := range node.Children {
+			e.node(node)
+		}
+
+	case SequenceNode:
+		style := yaml_BLOCK_SEQUENCE_STYLE
+		if node.Style&FlowStyle != 0 {
+			style = yaml_FLOW_SEQUENCE_STYLE
+		}
+		e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(node.Tag), node.implicit(), style))
+		e.emit()
+		for _, node := range node.Children {
+			e.node(node)
+		}
+		e.must(yaml_sequence_end_event_initialize(&e.event))
+		e.emit()
+
+	case MappingNode:
+		style := yaml_BLOCK_MAPPING_STYLE
+		if node.Style&FlowStyle != 0 {
+			style = yaml_FLOW_MAPPING_STYLE
+		}
+		yaml_mapping_start_event_initialize(&e.event, nil, []byte(node.Tag), node.implicit(), style)
+		e.emit()
+
+		for i := 0; i+1 < len(node.Children); i += 2 {
+			e.node(node.Children[i])
+			e.node(node.Children[i+1])
+		}
+
+		yaml_mapping_end_event_initialize(&e.event)
+		e.emit()
+
+	case ScalarNode, AliasNode:
+		style := yaml_PLAIN_SCALAR_STYLE
+		switch {
+		case node.Style&DoubleQuotedStyle != 0:
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		case node.Style&SingleQuotedStyle != 0:
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		case node.Style&LiteralStyle != 0:
+			style = yaml_LITERAL_SCALAR_STYLE
+		case node.Style&FoldedStyle != 0:
+			style = yaml_FOLDED_SCALAR_STYLE
+		}
+
+		if style == yaml_PLAIN_SCALAR_STYLE && strings.Contains(node.Value, "\n") {
+			style = yaml_LITERAL_SCALAR_STYLE
+		}
+		e.emitScalar(node.Value, "", node.Tag, style)
+
+		// TODO Check if binaries are being decoded into node.Value or not.
+		//switch {
+		//if !utf8.ValidString(s) {
+		//	if tag == yaml_BINARY_TAG {
+		//		failf("explicitly tagged !!binary data must be base64-encoded")
+		//	}
+		//	if tag != "" {
+		//		failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
+		//	}
+		//	// It can't be encoded directly as YAML so use a binary tag
+		//	// and encode it as base64.
+		//	tag = yaml_BINARY_TAG
+		//	s = encodeBase64(s)
+		//}
+	}
+}

+ 1 - 1
resolve.go

@@ -190,7 +190,7 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
 				}
 			}
 		default:
-			panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
+			panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
 		}
 	}
 	return yaml_STR_TAG, in

+ 14 - 0
yaml.go

@@ -134,6 +134,20 @@ func (dec *Decoder) Decode(v interface{}) (err error) {
 	return nil
 }
 
+func (n *Node) Decode(v interface{}) (err error) {
+	d := newDecoder(false)
+	defer handleErr(&err)
+	out := reflect.ValueOf(v)
+	if out.Kind() == reflect.Ptr && !out.IsNil() {
+		out = out.Elem()
+	}
+	d.unmarshal(n, out)
+	if len(d.terrors) > 0 {
+		return &TypeError{d.terrors}
+	}
+	return nil
+}
+
 func unmarshal(in []byte, out interface{}, strict bool) (err error) {
 	defer handleErr(&err)
 	d := newDecoder(strict)

+ 6 - 6
yamlh.go

@@ -73,13 +73,13 @@ type yaml_scalar_style_t yaml_style_t
 // Scalar styles.
 const (
 	// Let the emitter choose the style.
-	yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota
+	yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
 
-	yaml_PLAIN_SCALAR_STYLE         // The plain scalar style.
-	yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
-	yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
-	yaml_LITERAL_SCALAR_STYLE       // The literal scalar style.
-	yaml_FOLDED_SCALAR_STYLE        // The folded scalar style.
+	yaml_PLAIN_SCALAR_STYLE         yaml_scalar_style_t = 1 << iota // The plain scalar style.
+	yaml_SINGLE_QUOTED_SCALAR_STYLE                                 // The single-quoted scalar style.
+	yaml_DOUBLE_QUOTED_SCALAR_STYLE                                 // The double-quoted scalar style.
+	yaml_LITERAL_SCALAR_STYLE                                       // The literal scalar style.
+	yaml_FOLDED_SCALAR_STYLE                                        // The folded scalar style.
 )
 
 type yaml_sequence_style_t yaml_style_t