123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- package yaml
- import (
- "encoding/base64"
- "fmt"
- "reflect"
- "strconv"
- "time"
- )
- const (
- documentNode = 1 << iota
- mappingNode
- sequenceNode
- scalarNode
- aliasNode
- )
- type node struct {
- kind int
- line, column int
- tag string
- value string
- implicit bool
- children []*node
- anchors map[string]*node
- }
- // ----------------------------------------------------------------------------
- // Parser, produces a node tree out of a libyaml event stream.
- type parser struct {
- parser yaml_parser_t
- event yaml_event_t
- doc *node
- transform transformString
- }
- func newParser(b []byte, t transformString) *parser {
- p := parser{transform: t}
- if !yaml_parser_initialize(&p.parser) {
- panic("Failed to initialize YAML emitter")
- }
- if len(b) == 0 {
- b = []byte{'\n'}
- }
- yaml_parser_set_input_string(&p.parser, b)
- p.skip()
- if p.event.typ != yaml_STREAM_START_EVENT {
- panic("Expected stream start event, got " + strconv.Itoa(int(p.event.typ)))
- }
- p.skip()
- return &p
- }
- func (p *parser) destroy() {
- if p.event.typ != yaml_NO_EVENT {
- yaml_event_delete(&p.event)
- }
- yaml_parser_delete(&p.parser)
- }
- func (p *parser) skip() {
- if p.event.typ != yaml_NO_EVENT {
- if p.event.typ == yaml_STREAM_END_EVENT {
- fail("Attempted to go past the end of stream. Corrupted value?")
- }
- yaml_event_delete(&p.event)
- }
- if !yaml_parser_parse(&p.parser, &p.event) {
- p.fail()
- }
- }
- func (p *parser) fail() {
- var where string
- var line int
- if p.parser.problem_mark.line != 0 {
- line = p.parser.problem_mark.line
- } else if p.parser.context_mark.line != 0 {
- line = p.parser.context_mark.line
- }
- if line != 0 {
- where = "line " + strconv.Itoa(line) + ": "
- }
- var msg string
- if len(p.parser.problem) > 0 {
- msg = p.parser.problem
- } else {
- msg = "Unknown problem parsing YAML content"
- }
- fail(where + msg)
- }
- func (p *parser) anchor(n *node, anchor []byte) {
- if anchor != nil {
- p.doc.anchors[string(anchor)] = n
- }
- }
- func (p *parser) parse() *node {
- switch p.event.typ {
- case yaml_SCALAR_EVENT:
- return p.scalar()
- case yaml_ALIAS_EVENT:
- return p.alias()
- case yaml_MAPPING_START_EVENT:
- return p.mapping()
- case yaml_SEQUENCE_START_EVENT:
- return p.sequence()
- case yaml_DOCUMENT_START_EVENT:
- return p.document()
- case yaml_STREAM_END_EVENT:
- // Happens when attempting to decode an empty buffer.
- return nil
- default:
- panic("Attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
- }
- panic("unreachable")
- }
- 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) document() *node {
- n := p.node(documentNode)
- n.anchors = make(map[string]*node)
- p.doc = n
- p.skip()
- n.children = append(n.children, p.parse())
- if p.event.typ != yaml_DOCUMENT_END_EVENT {
- panic("Expected end of document event but got " + strconv.Itoa(int(p.event.typ)))
- }
- p.skip()
- return n
- }
- func (p *parser) alias() *node {
- n := p.node(aliasNode)
- n.value = string(p.event.anchor)
- p.skip()
- 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
- p.anchor(n, p.event.anchor)
- p.skip()
- return n
- }
- func (p *parser) sequence() *node {
- n := p.node(sequenceNode)
- p.anchor(n, p.event.anchor)
- p.skip()
- for p.event.typ != yaml_SEQUENCE_END_EVENT {
- n.children = append(n.children, p.parse())
- }
- p.skip()
- return n
- }
- func (p *parser) mapping() *node {
- n := p.node(mappingNode)
- p.anchor(n, p.event.anchor)
- p.skip()
- for p.event.typ != yaml_MAPPING_END_EVENT {
- key := p.parse()
- key.value = p.transform(key.value)
- value := p.parse()
- n.children = append(n.children, key, value)
- }
- p.skip()
- return n
- }
- // ----------------------------------------------------------------------------
- // Decoder, unmarshals a node into a provided value.
- type decoder struct {
- doc *node
- aliases map[string]bool
- }
- func newDecoder() *decoder {
- d := &decoder{}
- d.aliases = make(map[string]bool)
- return d
- }
- // d.setter deals with setters and pointer dereferencing and initialization.
- //
- // It's a slightly convoluted case to handle properly:
- //
- // - nil pointers should be initialized, unless being set to nil
- // - we don't know at this point yet what's the value to SetYAML() with.
- // - we can't separate pointer deref/init and setter checking, because
- // a setter may be found while going down a pointer chain.
- //
- // Thus, here is how it takes care of it:
- //
- // - out is provided as a pointer, so that it can be replaced.
- // - when looking at a non-setter ptr, *out=ptr.Elem(), unless tag=!!null
- // - when a setter is found, *out=interface{}, and a set() function is
- // returned to call SetYAML() with the value of *out once it's defined.
- //
- func (d *decoder) setter(tag string, out *reflect.Value, good *bool) (set func()) {
- if (*out).Kind() != reflect.Ptr && (*out).CanAddr() {
- setter, _ := (*out).Addr().Interface().(Setter)
- if setter != nil {
- var arg interface{}
- *out = reflect.ValueOf(&arg).Elem()
- return func() {
- *good = setter.SetYAML(shortTag(tag), arg)
- }
- }
- }
- again := true
- for again {
- again = false
- setter, _ := (*out).Interface().(Setter)
- if tag != yaml_NULL_TAG || setter != nil {
- if pv := (*out); pv.Kind() == reflect.Ptr {
- if pv.IsNil() {
- *out = reflect.New(pv.Type().Elem()).Elem()
- pv.Set((*out).Addr())
- } else {
- *out = pv.Elem()
- }
- setter, _ = pv.Interface().(Setter)
- again = true
- }
- }
- if setter != nil {
- var arg interface{}
- *out = reflect.ValueOf(&arg).Elem()
- return func() {
- *good = setter.SetYAML(shortTag(tag), arg)
- }
- }
- }
- return nil
- }
- func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
- switch n.kind {
- case documentNode:
- good = d.document(n, out)
- case scalarNode:
- good = d.scalar(n, out)
- case aliasNode:
- good = d.alias(n, out)
- case mappingNode:
- good = d.mapping(n, out)
- case sequenceNode:
- good = d.sequence(n, out)
- default:
- panic("Internal error: unknown node kind: " + strconv.Itoa(n.kind))
- }
- return
- }
- 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)
- return true
- }
- return false
- }
- func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
- an, ok := d.doc.anchors[n.value]
- if !ok {
- fail("Unknown anchor '" + n.value + "' referenced")
- }
- if d.aliases[n.value] {
- fail("Anchor '" + n.value + "' value contains itself")
- }
- d.aliases[n.value] = true
- good = d.unmarshal(an, out)
- delete(d.aliases, n.value)
- return good
- }
- var zeroValue reflect.Value
- func resetMap(out reflect.Value) {
- for _, k := range out.MapKeys() {
- out.SetMapIndex(k, zeroValue)
- }
- }
- var durationType = reflect.TypeOf(time.Duration(0))
- func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
- var tag string
- var resolved interface{}
- if n.tag == "" && !n.implicit {
- tag = yaml_STR_TAG
- resolved = n.value
- } else {
- tag, resolved = resolve(n.tag, n.value)
- if tag == yaml_BINARY_TAG {
- data, err := base64.StdEncoding.DecodeString(resolved.(string))
- if err != nil {
- fail("!!binary value contains invalid base64 data")
- }
- resolved = string(data)
- }
- }
- if set := d.setter(tag, &out, &good); set != nil {
- defer set()
- }
- if resolved == nil {
- if out.Kind() == reflect.Map && !out.CanAddr() {
- resetMap(out)
- } else {
- out.Set(reflect.Zero(out.Type()))
- }
- good = true
- return
- }
- switch out.Kind() {
- case reflect.String:
- if tag == yaml_BINARY_TAG {
- out.SetString(resolved.(string))
- good = true
- } else if resolved != nil {
- out.SetString(n.value)
- good = true
- }
- case reflect.Interface:
- if resolved == nil {
- out.Set(reflect.Zero(out.Type()))
- } else {
- out.Set(reflect.ValueOf(resolved))
- }
- good = true
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- switch resolved := resolved.(type) {
- case int:
- if !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- good = true
- }
- case int64:
- if !out.OverflowInt(resolved) {
- out.SetInt(resolved)
- good = true
- }
- case float64:
- if resolved < 1<<63-1 && !out.OverflowInt(int64(resolved)) {
- out.SetInt(int64(resolved))
- good = true
- }
- case string:
- if out.Type() == durationType {
- d, err := time.ParseDuration(resolved)
- if err == nil {
- out.SetInt(int64(d))
- good = true
- }
- }
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- switch resolved := resolved.(type) {
- case int:
- if resolved >= 0 {
- out.SetUint(uint64(resolved))
- good = true
- }
- case int64:
- if resolved >= 0 {
- out.SetUint(uint64(resolved))
- good = true
- }
- case float64:
- if resolved < 1<<64-1 && !out.OverflowUint(uint64(resolved)) {
- out.SetUint(uint64(resolved))
- good = true
- }
- }
- case reflect.Bool:
- switch resolved := resolved.(type) {
- case bool:
- out.SetBool(resolved)
- good = true
- }
- case reflect.Float32, reflect.Float64:
- switch resolved := resolved.(type) {
- case int:
- out.SetFloat(float64(resolved))
- good = true
- case int64:
- out.SetFloat(float64(resolved))
- good = true
- case float64:
- out.SetFloat(resolved)
- good = true
- }
- case reflect.Ptr:
- if out.Type().Elem() == reflect.TypeOf(resolved) {
- elem := reflect.New(out.Type().Elem())
- elem.Elem().Set(reflect.ValueOf(resolved))
- out.Set(elem)
- good = true
- }
- }
- return good
- }
- func settableValueOf(i interface{}) reflect.Value {
- v := reflect.ValueOf(i)
- sv := reflect.New(v.Type()).Elem()
- sv.Set(v)
- return sv
- }
- func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
- if set := d.setter(yaml_SEQ_TAG, &out, &good); set != nil {
- defer set()
- }
- var iface reflect.Value
- if out.Kind() == reflect.Interface {
- // No type hints. Will have to use a generic sequence.
- iface = out
- out = settableValueOf(make([]interface{}, 0))
- }
- if out.Kind() != reflect.Slice {
- return false
- }
- et := out.Type().Elem()
- l := len(n.children)
- for i := 0; i < l; i++ {
- e := reflect.New(et).Elem()
- if ok := d.unmarshal(n.children[i], e); ok {
- out.Set(reflect.Append(out, e))
- }
- }
- if iface.IsValid() {
- iface.Set(out)
- }
- return true
- }
- func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
- if set := d.setter(yaml_MAP_TAG, &out, &good); set != nil {
- defer set()
- }
- if out.Kind() == reflect.Struct {
- return d.mappingStruct(n, out)
- }
- if out.Kind() == reflect.Interface {
- // No type hints. Will have to use a generic map.
- iface := out
- out = settableValueOf(make(map[interface{}]interface{}))
- iface.Set(out)
- }
- if out.Kind() != reflect.Map {
- return false
- }
- outt := out.Type()
- kt := outt.Key()
- et := outt.Elem()
- if out.IsNil() {
- out.Set(reflect.MakeMap(outt))
- }
- l := len(n.children)
- for i := 0; i < l; i += 2 {
- 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) {
- kkind := k.Kind()
- if kkind == reflect.Interface {
- kkind = k.Elem().Kind()
- }
- if kkind == reflect.Map || kkind == reflect.Slice {
- fail(fmt.Sprintf("invalid map key: %#v", k.Interface()))
- }
- e := reflect.New(et).Elem()
- if d.unmarshal(n.children[i+1], e) {
- out.SetMapIndex(k, e)
- }
- }
- }
- return true
- }
- 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)
- for i := 0; i < l; i += 2 {
- ni := n.children[i]
- if isMerge(ni) {
- d.merge(n.children[i+1], out)
- continue
- }
- if !d.unmarshal(ni, name) {
- continue
- }
- if info, ok := sinfo.FieldsMap[name.String()]; ok {
- var field reflect.Value
- if info.Inline == nil {
- field = out.Field(info.Num)
- } else {
- field = out.FieldByIndex(info.Inline)
- }
- d.unmarshal(n.children[i+1], field)
- }
- }
- return true
- }
- func (d *decoder) merge(n *node, out reflect.Value) {
- const wantMap = "map merge requires map or sequence of maps as the value"
- switch n.kind {
- case mappingNode:
- d.unmarshal(n, out)
- case aliasNode:
- an, ok := d.doc.anchors[n.value]
- if ok && an.kind != mappingNode {
- fail(wantMap)
- }
- d.unmarshal(n, out)
- 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 {
- fail(wantMap)
- }
- } else if ni.kind != mappingNode {
- fail(wantMap)
- }
- d.unmarshal(ni, out)
- }
- default:
- fail(wantMap)
- }
- }
- func isMerge(n *node) bool {
- return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
- }
|