Use launchpad.net/gocheck and gofmt.
diff --git a/Makefile b/Makefile index ff7b1a4..507f607 100644 --- a/Makefile +++ b/Makefile
@@ -22,7 +22,7 @@ writer.o\ emitter.o\ -GOFMT=gofmt -spaces=true -tabwidth=4 -tabindent=false +GOFMT=gofmt BADFMT:=$(shell $(GOFMT) -l $(GOFILES) $(CGOFILES) $(wildcard *_test.go))
diff --git a/decode.go b/decode.go index e8da5dd..9db4102 100644 --- a/decode.go +++ b/decode.go
@@ -7,31 +7,31 @@ import "C" import ( - "unsafe" - "reflect" - "strconv" + "unsafe" + "reflect" + "strconv" ) const ( - documentNode = 1 << iota - mappingNode - sequenceNode - scalarNode - aliasNode + 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 + kind int + line, column int + tag string + value string + implicit bool + children []*node + anchors map[string]*node } func stry(s *C.yaml_char_t) string { - return C.GoString((*C.char)(unsafe.Pointer(s))) + return C.GoString((*C.char)(unsafe.Pointer(s))) } @@ -39,161 +39,161 @@ // Parser, produces a node tree out of a libyaml event stream. type parser struct { - parser C.yaml_parser_t - event C.yaml_event_t - doc *node + parser C.yaml_parser_t + event C.yaml_event_t + doc *node } func newParser(b []byte) *parser { - p := parser{} - if C.yaml_parser_initialize(&p.parser) == 0 { - panic("Failed to initialize YAML emitter") - } + p := parser{} + if C.yaml_parser_initialize(&p.parser) == 0 { + panic("Failed to initialize YAML emitter") + } - if len(b) == 0 { - b = []byte{'\n'} - } + if len(b) == 0 { + b = []byte{'\n'} + } - // How unsafe is this really? Will this break if the GC becomes compacting? - // Probably not, otherwise that would likely break &parse below as well. - input := (*C.uchar)(unsafe.Pointer(&b[0])) - C.yaml_parser_set_input_string(&p.parser, input, (C.size_t)(len(b))) + // How unsafe is this really? Will this break if the GC becomes compacting? + // Probably not, otherwise that would likely break &parse below as well. + input := (*C.uchar)(unsafe.Pointer(&b[0])) + C.yaml_parser_set_input_string(&p.parser, input, (C.size_t)(len(b))) - p.skip() - if p.event._type != C.YAML_STREAM_START_EVENT { - panic("Expected stream start event, got " + - strconv.Itoa(int(p.event._type))) - } - p.skip() - return &p + p.skip() + if p.event._type != C.YAML_STREAM_START_EVENT { + panic("Expected stream start event, got " + + strconv.Itoa(int(p.event._type))) + } + p.skip() + return &p } func (p *parser) destroy() { - if p.event._type != C.YAML_NO_EVENT { - C.yaml_event_delete(&p.event) - } - C.yaml_parser_delete(&p.parser) + if p.event._type != C.YAML_NO_EVENT { + C.yaml_event_delete(&p.event) + } + C.yaml_parser_delete(&p.parser) } func (p *parser) skip() { - if p.event._type != C.YAML_NO_EVENT { - if p.event._type == C.YAML_STREAM_END_EVENT { - panic("Attempted to go past the end of stream. Corrupted value?") - } - C.yaml_event_delete(&p.event) - } - if C.yaml_parser_parse(&p.parser, &p.event) == 0 { - p.fail() - } + if p.event._type != C.YAML_NO_EVENT { + if p.event._type == C.YAML_STREAM_END_EVENT { + panic("Attempted to go past the end of stream. Corrupted value?") + } + C.yaml_event_delete(&p.event) + } + if C.yaml_parser_parse(&p.parser, &p.event) == 0 { + p.fail() + } } func (p *parser) fail() { - var where string - var line int - if p.parser.problem_mark.line != 0 { - line = int(C.int(p.parser.problem_mark.line)) - } else if p.parser.context_mark.line != 0 { - line = int(C.int(p.parser.context_mark.line)) - } - if line != 0 { - where = "line " + strconv.Itoa(line) + ": " - } - var msg string - if p.parser.problem != nil { - msg = C.GoString(p.parser.problem) - } else { - msg = "Unknown problem parsing YAML content" - } - panic(where + msg) + var where string + var line int + if p.parser.problem_mark.line != 0 { + line = int(C.int(p.parser.problem_mark.line)) + } else if p.parser.context_mark.line != 0 { + line = int(C.int(p.parser.context_mark.line)) + } + if line != 0 { + where = "line " + strconv.Itoa(line) + ": " + } + var msg string + if p.parser.problem != nil { + msg = C.GoString(p.parser.problem) + } else { + msg = "Unknown problem parsing YAML content" + } + panic(where + msg) } func (p *parser) anchor(n *node, anchor *C.yaml_char_t) { - if anchor != nil { - p.doc.anchors[stry(anchor)] = n - } + if anchor != nil { + p.doc.anchors[stry(anchor)] = n + } } func (p *parser) parse() *node { - switch p.event._type { - case C.YAML_SCALAR_EVENT: - return p.scalar() - case C.YAML_ALIAS_EVENT: - return p.alias() - case C.YAML_MAPPING_START_EVENT: - return p.mapping() - case C.YAML_SEQUENCE_START_EVENT: - return p.sequence() - case C.YAML_DOCUMENT_START_EVENT: - return p.document() - case C.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._type))) - } - panic("Unreachable") + switch p.event._type { + case C.YAML_SCALAR_EVENT: + return p.scalar() + case C.YAML_ALIAS_EVENT: + return p.alias() + case C.YAML_MAPPING_START_EVENT: + return p.mapping() + case C.YAML_SEQUENCE_START_EVENT: + return p.sequence() + case C.YAML_DOCUMENT_START_EVENT: + return p.document() + case C.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._type))) + } + panic("Unreachable") } func (p *parser) node(kind int) *node { - return &node{kind: kind, - line: int(C.int(p.event.start_mark.line)), - column: int(C.int(p.event.start_mark.column))} + return &node{kind: kind, + line: int(C.int(p.event.start_mark.line)), + column: int(C.int(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._type != C.YAML_DOCUMENT_END_EVENT { - panic("Expected end of document event but got " + - strconv.Itoa(int(p.event._type))) - } - p.skip() - return n + 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._type != C.YAML_DOCUMENT_END_EVENT { + panic("Expected end of document event but got " + + strconv.Itoa(int(p.event._type))) + } + p.skip() + return n } func (p *parser) alias() *node { - alias := C.event_alias(&p.event) - n := p.node(aliasNode) - n.value = stry(alias.anchor) - p.skip() - return n + alias := C.event_alias(&p.event) + n := p.node(aliasNode) + n.value = stry(alias.anchor) + p.skip() + return n } func (p *parser) scalar() *node { - scalar := C.event_scalar(&p.event) - n := p.node(scalarNode) - n.value = stry(scalar.value) - n.tag = stry(scalar.tag) - n.implicit = (scalar.plain_implicit != 0) - p.anchor(n, scalar.anchor) - p.skip() - return n + scalar := C.event_scalar(&p.event) + n := p.node(scalarNode) + n.value = stry(scalar.value) + n.tag = stry(scalar.tag) + n.implicit = (scalar.plain_implicit != 0) + p.anchor(n, scalar.anchor) + p.skip() + return n } func (p *parser) sequence() *node { - n := p.node(sequenceNode) - p.anchor(n, C.event_sequence_start(&p.event).anchor) - p.skip() - for p.event._type != C.YAML_SEQUENCE_END_EVENT { - n.children = append(n.children, p.parse()) - } - p.skip() - return n + n := p.node(sequenceNode) + p.anchor(n, C.event_sequence_start(&p.event).anchor) + p.skip() + for p.event._type != C.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, C.event_mapping_start(&p.event).anchor) - p.skip() - for p.event._type != C.YAML_MAPPING_END_EVENT { - n.children = append(n.children, p.parse(), p.parse()) - } - p.skip() - return n + n := p.node(mappingNode) + p.anchor(n, C.event_mapping_start(&p.event).anchor) + p.skip() + for p.event._type != C.YAML_MAPPING_END_EVENT { + n.children = append(n.children, p.parse(), p.parse()) + } + p.skip() + return n } @@ -201,14 +201,14 @@ // Decoder, unmarshals a node into a provided value. type decoder struct { - doc *node - aliases map[string]bool + doc *node + aliases map[string]bool } func newDecoder() *decoder { - d := &decoder{} - d.aliases = make(map[string]bool) - return d + d := &decoder{} + d.aliases = make(map[string]bool) + return d } // d.setter deals with setters and pointer dereferencing and initialization. @@ -228,219 +228,219 @@ // 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()) { - again := true - for again { - again = false - setter, _ := (*out).Interface().(Setter) - if tag != "!!null" || setter != nil { - if pv, ok := (*out).(*reflect.PtrValue); ok { - if pv.IsNil() { - *out = reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()) - pv.PointTo(*out) - } else { - *out = pv.Elem() - } - setter, _ = pv.Interface().(Setter) - again = true - } - } - if setter != nil { - var arg interface{} - *out = reflect.NewValue(&arg).(*reflect.PtrValue).Elem() - return func() { - *good = setter.SetYAML(tag, arg) - } - } - } - return nil + again := true + for again { + again = false + setter, _ := (*out).Interface().(Setter) + if tag != "!!null" || setter != nil { + if pv, ok := (*out).(*reflect.PtrValue); ok { + if pv.IsNil() { + *out = reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()) + pv.PointTo(*out) + } else { + *out = pv.Elem() + } + setter, _ = pv.Interface().(Setter) + again = true + } + } + if setter != nil { + var arg interface{} + *out = reflect.NewValue(&arg).(*reflect.PtrValue).Elem() + return func() { + *good = setter.SetYAML(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 + 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 + 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 { - panic("Unknown anchor '" + n.value + "' referenced") - } - if d.aliases[n.value] { - panic("Anchor '" + n.value + "' value contains itself") - } - d.aliases[n.value] = true - good = d.unmarshal(an, out) - d.aliases[n.value] = false, false - return good + an, ok := d.doc.anchors[n.value] + if !ok { + panic("Unknown anchor '" + n.value + "' referenced") + } + if d.aliases[n.value] { + panic("Anchor '" + n.value + "' value contains itself") + } + d.aliases[n.value] = true + good = d.unmarshal(an, out) + d.aliases[n.value] = false, false + return good } func (d *decoder) scalar(n *node, out reflect.Value) (good bool) { - var tag string - var resolved interface{} - if n.tag == "" && !n.implicit { - resolved = n.value - } else { - tag, resolved = resolve(n.tag, n.value) - if set := d.setter(tag, &out, &good); set != nil { - defer set() - } - } - switch out := out.(type) { - case *reflect.StringValue: - out.Set(n.value) - good = true - case *reflect.InterfaceValue: - out.Set(reflect.NewValue(resolved)) - good = true - case *reflect.IntValue: - switch resolved := resolved.(type) { - case int: - if !out.Overflow(int64(resolved)) { - out.Set(int64(resolved)) - good = true - } - case int64: - if !out.Overflow(resolved) { - out.Set(resolved) - good = true - } - } - case *reflect.UintValue: - switch resolved := resolved.(type) { - case int: - if resolved >= 0 { - out.Set(uint64(resolved)) - good = true - } - case int64: - if resolved >= 0 { - out.Set(uint64(resolved)) - good = true - } - } - case *reflect.BoolValue: - switch resolved := resolved.(type) { - case bool: - out.Set(resolved) - good = true - } - case *reflect.FloatValue: - switch resolved := resolved.(type) { - case float64: - out.Set(resolved) - good = true - } - case *reflect.PtrValue: - switch resolved := resolved.(type) { - case nil: - out.PointTo(nil) - good = true - } - default: - panic("Can't handle type yet: " + out.Type().String()) - } - return good + var tag string + var resolved interface{} + if n.tag == "" && !n.implicit { + resolved = n.value + } else { + tag, resolved = resolve(n.tag, n.value) + if set := d.setter(tag, &out, &good); set != nil { + defer set() + } + } + switch out := out.(type) { + case *reflect.StringValue: + out.Set(n.value) + good = true + case *reflect.InterfaceValue: + out.Set(reflect.NewValue(resolved)) + good = true + case *reflect.IntValue: + switch resolved := resolved.(type) { + case int: + if !out.Overflow(int64(resolved)) { + out.Set(int64(resolved)) + good = true + } + case int64: + if !out.Overflow(resolved) { + out.Set(resolved) + good = true + } + } + case *reflect.UintValue: + switch resolved := resolved.(type) { + case int: + if resolved >= 0 { + out.Set(uint64(resolved)) + good = true + } + case int64: + if resolved >= 0 { + out.Set(uint64(resolved)) + good = true + } + } + case *reflect.BoolValue: + switch resolved := resolved.(type) { + case bool: + out.Set(resolved) + good = true + } + case *reflect.FloatValue: + switch resolved := resolved.(type) { + case float64: + out.Set(resolved) + good = true + } + case *reflect.PtrValue: + switch resolved := resolved.(type) { + case nil: + out.PointTo(nil) + good = true + } + default: + panic("Can't handle type yet: " + out.Type().String()) + } + return good } func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { - if set := d.setter("!!seq", &out, &good); set != nil { - defer set() - } - if iface, ok := out.(*reflect.InterfaceValue); ok { - // No type hints. Will have to use a generic sequence. - out = reflect.NewValue(make([]interface{}, 0)) - iface.SetValue(out) - } + if set := d.setter("!!seq", &out, &good); set != nil { + defer set() + } + if iface, ok := out.(*reflect.InterfaceValue); ok { + // No type hints. Will have to use a generic sequence. + out = reflect.NewValue(make([]interface{}, 0)) + iface.SetValue(out) + } - sv, ok := out.(*reflect.SliceValue) - if !ok { - return false - } - st := sv.Type().(*reflect.SliceType) - et := st.Elem() + sv, ok := out.(*reflect.SliceValue) + if !ok { + return false + } + st := sv.Type().(*reflect.SliceType) + et := st.Elem() - l := len(n.children) - for i := 0; i < l; i++ { - e := reflect.MakeZero(et) - if ok := d.unmarshal(n.children[i], e); ok { - sv.SetValue(reflect.Append(sv, e)) - } - } - return true + l := len(n.children) + for i := 0; i < l; i++ { + e := reflect.MakeZero(et) + if ok := d.unmarshal(n.children[i], e); ok { + sv.SetValue(reflect.Append(sv, e)) + } + } + return true } func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { - if set := d.setter("!!map", &out, &good); set != nil { - defer set() - } - if s, ok := out.(*reflect.StructValue); ok { - return d.mappingStruct(n, s) - } + if set := d.setter("!!map", &out, &good); set != nil { + defer set() + } + if s, ok := out.(*reflect.StructValue); ok { + return d.mappingStruct(n, s) + } - if iface, ok := out.(*reflect.InterfaceValue); ok { - // No type hints. Will have to use a generic map. - out = reflect.NewValue(make(map[interface{}]interface{})) - iface.SetValue(out) - } + if iface, ok := out.(*reflect.InterfaceValue); ok { + // No type hints. Will have to use a generic map. + out = reflect.NewValue(make(map[interface{}]interface{})) + iface.SetValue(out) + } - mv, ok := out.(*reflect.MapValue) - if !ok { - return false - } - mt := mv.Type().(*reflect.MapType) - kt := mt.Key() - et := mt.Elem() + mv, ok := out.(*reflect.MapValue) + if !ok { + return false + } + mt := mv.Type().(*reflect.MapType) + kt := mt.Key() + et := mt.Elem() - l := len(n.children) - for i := 0; i < l; i += 2 { - k := reflect.MakeZero(kt) - if d.unmarshal(n.children[i], k) { - e := reflect.MakeZero(et) - if d.unmarshal(n.children[i+1], e) { - mv.SetElem(k, e) - } - } - } - return true + l := len(n.children) + for i := 0; i < l; i += 2 { + k := reflect.MakeZero(kt) + if d.unmarshal(n.children[i], k) { + e := reflect.MakeZero(et) + if d.unmarshal(n.children[i+1], e) { + mv.SetElem(k, e) + } + } + } + return true } func (d *decoder) mappingStruct(n *node, out *reflect.StructValue) (good bool) { - fields, err := getStructFields(out.Type().(*reflect.StructType)) - if err != nil { - panic(err) - } - name := reflect.NewValue("").(*reflect.StringValue) - fieldsMap := fields.Map - l := len(n.children) - for i := 0; i < l; i += 2 { - if !d.unmarshal(n.children[i], name) { - continue - } - if info, ok := fieldsMap[name.Get()]; ok { - d.unmarshal(n.children[i+1], out.Field(info.Num)) - } - } - return true + fields, err := getStructFields(out.Type().(*reflect.StructType)) + if err != nil { + panic(err) + } + name := reflect.NewValue("").(*reflect.StringValue) + fieldsMap := fields.Map + l := len(n.children) + for i := 0; i < l; i += 2 { + if !d.unmarshal(n.children[i], name) { + continue + } + if info, ok := fieldsMap[name.Get()]; ok { + d.unmarshal(n.children[i+1], out.Field(info.Num)) + } + } + return true }
diff --git a/decode_test.go b/decode_test.go index aca12ca..5fdf2b4 100644 --- a/decode_test.go +++ b/decode_test.go
@@ -2,245 +2,245 @@ import ( - . "gocheck" - "goyaml" - "reflect" - "math" + . "launchpad.net/gocheck" + "goyaml" + "reflect" + "math" ) var unmarshalIntTest = 123 var unmarshalTests = []struct { - data string - value interface{} + data string + value interface{} }{ - {"", &struct{}{}}, - {"{}", &struct{}{}}, + {"", &struct{}{}}, + {"{}", &struct{}{}}, - {"v: hi", map[string]string{"v": "hi"}}, - {"v: hi", map[string]interface{}{"v": "hi"}}, - {"v: true", map[string]string{"v": "true"}}, - {"v: true", map[string]interface{}{"v": true}}, - {"v: 10", map[string]interface{}{"v": 10}}, - {"v: 0b10", map[string]interface{}{"v": 2}}, - {"v: 0xA", map[string]interface{}{"v": 10}}, - {"v: 4294967296", map[string]interface{}{"v": int64(4294967296)}}, - {"v: 4294967296", map[string]int64{"v": int64(4294967296)}}, - {"v: 0.1", map[string]interface{}{"v": 0.1}}, - {"v: .1", map[string]interface{}{"v": 0.1}}, - {"v: .Inf", map[string]interface{}{"v": math.Inf(+1)}}, - {"v: -.Inf", map[string]interface{}{"v": math.Inf(-1)}}, - {"v: -10", map[string]interface{}{"v": -10}}, - {"v: -.1", map[string]interface{}{"v": -0.1}}, + {"v: hi", map[string]string{"v": "hi"}}, + {"v: hi", map[string]interface{}{"v": "hi"}}, + {"v: true", map[string]string{"v": "true"}}, + {"v: true", map[string]interface{}{"v": true}}, + {"v: 10", map[string]interface{}{"v": 10}}, + {"v: 0b10", map[string]interface{}{"v": 2}}, + {"v: 0xA", map[string]interface{}{"v": 10}}, + {"v: 4294967296", map[string]interface{}{"v": int64(4294967296)}}, + {"v: 4294967296", map[string]int64{"v": int64(4294967296)}}, + {"v: 0.1", map[string]interface{}{"v": 0.1}}, + {"v: .1", map[string]interface{}{"v": 0.1}}, + {"v: .Inf", map[string]interface{}{"v": math.Inf(+1)}}, + {"v: -.Inf", map[string]interface{}{"v": math.Inf(-1)}}, + {"v: -10", map[string]interface{}{"v": -10}}, + {"v: -.1", map[string]interface{}{"v": -0.1}}, - // Simple values. - {"123", &unmarshalIntTest}, + // Simple values. + {"123", &unmarshalIntTest}, - // Floats from spec - {"canonical: 6.8523e+5", map[string]interface{}{"canonical": 6.8523e+5}}, - {"expo: 685.230_15e+03", map[string]interface{}{"expo": 685.23015e+03}}, - {"fixed: 685_230.15", map[string]interface{}{"fixed": 685230.15}}, - //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported - {"neginf: -.inf", map[string]interface{}{"neginf": math.Inf(-1)}}, - {"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, - {"fixed: 685_230.15", map[string]float64{"fixed": 685230.15}}, + // Floats from spec + {"canonical: 6.8523e+5", map[string]interface{}{"canonical": 6.8523e+5}}, + {"expo: 685.230_15e+03", map[string]interface{}{"expo": 685.23015e+03}}, + {"fixed: 685_230.15", map[string]interface{}{"fixed": 685230.15}}, + //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported + {"neginf: -.inf", map[string]interface{}{"neginf": math.Inf(-1)}}, + {"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, + {"fixed: 685_230.15", map[string]float64{"fixed": 685230.15}}, - // Bools from spec - {"canonical: y", map[string]interface{}{"canonical": true}}, - {"answer: NO", map[string]interface{}{"answer": false}}, - {"logical: True", map[string]interface{}{"logical": true}}, - {"option: on", map[string]interface{}{"option": true}}, - {"option: on", map[string]bool{"option": true}}, + // Bools from spec + {"canonical: y", map[string]interface{}{"canonical": true}}, + {"answer: NO", map[string]interface{}{"answer": false}}, + {"logical: True", map[string]interface{}{"logical": true}}, + {"option: on", map[string]interface{}{"option": true}}, + {"option: on", map[string]bool{"option": true}}, - // Ints from spec - {"canonical: 685230", map[string]interface{}{"canonical": 685230}}, - {"decimal: +685_230", map[string]interface{}{"decimal": 685230}}, - {"octal: 02472256", map[string]interface{}{"octal": 685230}}, - {"hexa: 0x_0A_74_AE", map[string]interface{}{"hexa": 685230}}, - {"bin: 0b1010_0111_0100_1010_1110", map[string]interface{}{"bin": 685230}}, - {"bin: -0b101010", map[string]interface{}{"bin": -42}}, - //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported - {"decimal: +685_230", map[string]int{"decimal": 685230}}, + // Ints from spec + {"canonical: 685230", map[string]interface{}{"canonical": 685230}}, + {"decimal: +685_230", map[string]interface{}{"decimal": 685230}}, + {"octal: 02472256", map[string]interface{}{"octal": 685230}}, + {"hexa: 0x_0A_74_AE", map[string]interface{}{"hexa": 685230}}, + {"bin: 0b1010_0111_0100_1010_1110", map[string]interface{}{"bin": 685230}}, + {"bin: -0b101010", map[string]interface{}{"bin": -42}}, + //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported + {"decimal: +685_230", map[string]int{"decimal": 685230}}, - // Nulls from spec - {"empty:", map[string]interface{}{"empty": nil}}, - {"canonical: ~", map[string]interface{}{"canonical": nil}}, - {"english: null", map[string]interface{}{"english": nil}}, - {"~: null key", map[interface{}]string{nil: "null key"}}, - {"empty:", map[string]*bool{"empty": nil}}, + // Nulls from spec + {"empty:", map[string]interface{}{"empty": nil}}, + {"canonical: ~", map[string]interface{}{"canonical": nil}}, + {"english: null", map[string]interface{}{"english": nil}}, + {"~: null key", map[interface{}]string{nil: "null key"}}, + {"empty:", map[string]*bool{"empty": nil}}, - // Sequence - {"seq: [A,B]", map[string]interface{}{"seq": []interface{}{"A", "B"}}}, - {"seq: [A,B,C]", map[string][]string{"seq": []string{"A", "B", "C"}}}, - {"seq: [A,1,C]", map[string][]string{"seq": []string{"A", "1", "C"}}}, - {"seq: [A,1,C]", map[string][]int{"seq": []int{1}}}, - {"seq: [A,1,C]", map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}}, + // Sequence + {"seq: [A,B]", map[string]interface{}{"seq": []interface{}{"A", "B"}}}, + {"seq: [A,B,C]", map[string][]string{"seq": []string{"A", "B", "C"}}}, + {"seq: [A,1,C]", map[string][]string{"seq": []string{"A", "1", "C"}}}, + {"seq: [A,1,C]", map[string][]int{"seq": []int{1}}}, + {"seq: [A,1,C]", map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}}, - // Map inside interface with no type hints. - {"a: {b: c}", - map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}}, + // Map inside interface with no type hints. + {"a: {b: c}", + map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}}, - // Structs and type conversions. - {"hello: world", &struct{ Hello string }{"world"}}, - {"a: {b: c}", &struct { - A struct { - B string - } - }{struct{ B string }{"c"}}}, - {"a: {b: c}", &struct { - A *struct { - B string - } - }{&struct{ B string }{"c"}}}, - {"a: 1", &struct{ A int }{1}}, - {"a: [1, 2]", &struct{ A []int }{[]int{1, 2}}}, - {"a: 1", &struct{ B int }{0}}, - {"a: 1", &struct { - B int "a" - }{1}}, - {"a: y", &struct{ A bool }{true}}, + // Structs and type conversions. + {"hello: world", &struct{ Hello string }{"world"}}, + {"a: {b: c}", &struct { + A struct { + B string + } + }{struct{ B string }{"c"}}}, + {"a: {b: c}", &struct { + A *struct { + B string + } + }{&struct{ B string }{"c"}}}, + {"a: 1", &struct{ A int }{1}}, + {"a: [1, 2]", &struct{ A []int }{[]int{1, 2}}}, + {"a: 1", &struct{ B int }{0}}, + {"a: 1", &struct { + B int "a" + }{1}}, + {"a: y", &struct{ A bool }{true}}, - // Some cross type conversions - {"v: 42", map[string]uint{"v": 42}}, - {"v: -42", map[string]uint{}}, - {"v: 4294967296", map[string]uint64{"v": 4294967296}}, - {"v: -4294967296", map[string]uint64{}}, + // Some cross type conversions + {"v: 42", map[string]uint{"v": 42}}, + {"v: -42", map[string]uint{}}, + {"v: 4294967296", map[string]uint64{"v": 4294967296}}, + {"v: -4294967296", map[string]uint64{}}, - // Overflow cases. - {"v: 4294967297", map[string]int32{}}, - {"v: 128", map[string]int8{}}, + // Overflow cases. + {"v: 4294967297", map[string]int32{}}, + {"v: 128", map[string]int8{}}, - // Quoted values. - {"'1': '\"2\"'", map[interface{}]interface{}{"1": "\"2\""}}, + // Quoted values. + {"'1': '\"2\"'", map[interface{}]interface{}{"1": "\"2\""}}, - // Explicit tags. - {"v: !!float '1.1'", map[string]interface{}{"v": 1.1}}, - {"v: !!null ''", map[string]interface{}{"v": nil}}, - {"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'", - map[string]interface{}{"v": 1}}, + // Explicit tags. + {"v: !!float '1.1'", map[string]interface{}{"v": 1.1}}, + {"v: !!null ''", map[string]interface{}{"v": nil}}, + {"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'", + map[string]interface{}{"v": 1}}, - // Anchors and aliases. - {"a: &x 1\nb: &y 2\nc: *x\nd: *y\n", &struct{ A, B, C, D int }{1, 2, 1, 2}}, - {"a: &a {c: 1}\nb: *a", - &struct { - A, B struct { - C int - } - }{struct{ C int }{1}, struct{ C int }{1}}}, - {"a: &a [1, 2]\nb: *a", &struct{ B []int }{[]int{1, 2}}}, + // Anchors and aliases. + {"a: &x 1\nb: &y 2\nc: *x\nd: *y\n", &struct{ A, B, C, D int }{1, 2, 1, 2}}, + {"a: &a {c: 1}\nb: *a", + &struct { + A, B struct { + C int + } + }{struct{ C int }{1}, struct{ C int }{1}}}, + {"a: &a [1, 2]\nb: *a", &struct{ B []int }{[]int{1, 2}}}, } func (s *S) TestUnmarshal(c *C) { - for _, item := range unmarshalTests { - t := reflect.NewValue(item.value).Type() - var value interface{} - if t, ok := t.(*reflect.MapType); ok { - value = reflect.MakeMap(t).Interface() - } else { - pt := reflect.NewValue(item.value).Type().(*reflect.PtrType) - pv := reflect.MakeZero(pt).(*reflect.PtrValue) - pv.PointTo(reflect.MakeZero(pt.Elem())) - value = pv.Interface() - } - err := goyaml.Unmarshal([]byte(item.data), value) - c.Assert(err, IsNil) - c.Assert(value, Equals, item.value) - } + for _, item := range unmarshalTests { + t := reflect.NewValue(item.value).Type() + var value interface{} + if t, ok := t.(*reflect.MapType); ok { + value = reflect.MakeMap(t).Interface() + } else { + pt := reflect.NewValue(item.value).Type().(*reflect.PtrType) + pv := reflect.MakeZero(pt).(*reflect.PtrValue) + pv.PointTo(reflect.MakeZero(pt.Elem())) + value = pv.Interface() + } + err := goyaml.Unmarshal([]byte(item.data), value) + c.Assert(err, IsNil) + c.Assert(value, Equals, item.value) + } } var unmarshalErrorTests = []struct { - data, error string + data, error string }{ - {"v: !!float 'error'", - "YAML error: Can't decode !!str 'error' as a !!float"}, - {"v: [A,", "YAML error: line 1: did not find expected node content"}, - {"v:\n- [A,", "YAML error: line 2: did not find expected node content"}, - {"a: *b\n", "YAML error: Unknown anchor 'b' referenced"}, - {"a: &a\n b: *a\n", "YAML error: Anchor 'a' value contains itself"}, + {"v: !!float 'error'", + "YAML error: Can't decode !!str 'error' as a !!float"}, + {"v: [A,", "YAML error: line 1: did not find expected node content"}, + {"v:\n- [A,", "YAML error: line 2: did not find expected node content"}, + {"a: *b\n", "YAML error: Unknown anchor 'b' referenced"}, + {"a: &a\n b: *a\n", "YAML error: Anchor 'a' value contains itself"}, } func (s *S) TestUnmarshalErrors(c *C) { - for _, item := range unmarshalErrorTests { - var value interface{} - err := goyaml.Unmarshal([]byte(item.data), &value) - c.Assert(err, Matches, item.error, Bug("Partial unmarshal: %#v", value)) - } + for _, item := range unmarshalErrorTests { + var value interface{} + err := goyaml.Unmarshal([]byte(item.data), &value) + c.Assert(err, Matches, item.error, Bug("Partial unmarshal: %#v", value)) + } } var setterTests = []struct { - data, tag string - value interface{} + data, tag string + value interface{} }{ - {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}}, - {"_: [1,A]", "!!seq", []interface{}{1, "A"}}, - {"_: 10", "!!int", 10}, - {"_: null", "!!null", nil}, - {"_: !!foo 'BAR!'", "!!foo", "BAR!"}, + {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}}, + {"_: [1,A]", "!!seq", []interface{}{1, "A"}}, + {"_: 10", "!!int", 10}, + {"_: null", "!!null", nil}, + {"_: !!foo 'BAR!'", "!!foo", "BAR!"}, } var setterResult = map[int]bool{} type typeWithSetter struct { - tag string - value interface{} + tag string + value interface{} } func (o *typeWithSetter) SetYAML(tag string, value interface{}) (ok bool) { - o.tag = tag - o.value = value - if i, ok := value.(int); ok { - if result, ok := setterResult[i]; ok { - return result - } - } - return true + o.tag = tag + o.value = value + if i, ok := value.(int); ok { + if result, ok := setterResult[i]; ok { + return result + } + } + return true } type typeWithSetterField struct { - Field *typeWithSetter "_" + Field *typeWithSetter "_" } func (s *S) TestUnmarshalWithSetter(c *C) { - for _, item := range setterTests { - obj := &typeWithSetterField{} - err := goyaml.Unmarshal([]byte(item.data), obj) - c.Assert(err, IsNil) - c.Assert(obj.Field, NotNil, - Bug("Pointer not initialized (%#v)", item.value)) - c.Assert(obj.Field.tag, Equals, item.tag) - c.Assert(obj.Field.value, Equals, item.value) - } + for _, item := range setterTests { + obj := &typeWithSetterField{} + err := goyaml.Unmarshal([]byte(item.data), obj) + c.Assert(err, IsNil) + c.Assert(obj.Field, NotNil, + Bug("Pointer not initialized (%#v)", item.value)) + c.Assert(obj.Field.tag, Equals, item.tag) + c.Assert(obj.Field.value, Equals, item.value) + } } func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) { - obj := &typeWithSetter{} - err := goyaml.Unmarshal([]byte(setterTests[0].data), obj) - c.Assert(err, IsNil) - c.Assert(obj.tag, Equals, setterTests[0].tag) - value, ok := obj.value.(map[interface{}]interface{}) - c.Assert(ok, Equals, true) - c.Assert(value["_"], Equals, setterTests[0].value) + obj := &typeWithSetter{} + err := goyaml.Unmarshal([]byte(setterTests[0].data), obj) + c.Assert(err, IsNil) + c.Assert(obj.tag, Equals, setterTests[0].tag) + value, ok := obj.value.(map[interface{}]interface{}) + c.Assert(ok, Equals, true) + c.Assert(value["_"], Equals, setterTests[0].value) } func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) { - setterResult[2] = false - setterResult[4] = false - defer func() { - setterResult[2] = false, false - setterResult[4] = false, false - }() + setterResult[2] = false + setterResult[4] = false + defer func() { + setterResult[2] = false, false + setterResult[4] = false, false + }() - m := map[string]*typeWithSetter{} - data := "{abc: 1, def: 2, ghi: 3, jkl: 4}" - err := goyaml.Unmarshal([]byte(data), m) - c.Assert(err, IsNil) - c.Assert(m["abc"], NotNil) - c.Assert(m["def"], IsNil) - c.Assert(m["ghi"], NotNil) - c.Assert(m["jkl"], IsNil) + m := map[string]*typeWithSetter{} + data := "{abc: 1, def: 2, ghi: 3, jkl: 4}" + err := goyaml.Unmarshal([]byte(data), m) + c.Assert(err, IsNil) + c.Assert(m["abc"], NotNil) + c.Assert(m["def"], IsNil) + c.Assert(m["ghi"], NotNil) + c.Assert(m["jkl"], IsNil) - c.Assert(m["abc"].value, Equals, 1) - c.Assert(m["ghi"].value, Equals, 3) + c.Assert(m["abc"].value, Equals, 1) + c.Assert(m["ghi"].value, Equals, 3) }
diff --git a/encode.go b/encode.go index 8233eb7..2eba6a5 100644 --- a/encode.go +++ b/encode.go
@@ -4,284 +4,284 @@ import "C" import ( - "reflect" - "unsafe" - "strconv" + "reflect" + "unsafe" + "strconv" ) type encoder struct { - emitter C.yaml_emitter_t - event C.yaml_event_t - out []byte - tmp []byte - tmph *reflect.SliceHeader - flow bool + emitter C.yaml_emitter_t + event C.yaml_event_t + out []byte + tmp []byte + tmph *reflect.SliceHeader + flow bool } //export outputHandler func outputHandler(data unsafe.Pointer, buffer *C.uchar, size C.size_t) C.int { - e := (*encoder)(data) - e.tmph.Data = uintptr(unsafe.Pointer(buffer)) - e.tmph.Len = int(size) - e.tmph.Cap = int(size) - e.out = append(e.out, e.tmp...) - return 1 + e := (*encoder)(data) + e.tmph.Data = uintptr(unsafe.Pointer(buffer)) + e.tmph.Len = int(size) + e.tmph.Cap = int(size) + e.out = append(e.out, e.tmp...) + return 1 } func newEncoder() (e *encoder) { - e = &encoder{} - e.tmph = (*reflect.SliceHeader)(unsafe.Pointer(&e.tmp)) - if C.yaml_emitter_initialize(&e.emitter) == 0 { - panic("Failed to initialize YAML emitter") - } - C.set_output_handler(&e.emitter) - C.yaml_stream_start_event_initialize(&e.event, C.YAML_UTF8_ENCODING) - e.emit() - C.yaml_document_start_event_initialize(&e.event, nil, nil, nil, 1) - e.emit() - return e + e = &encoder{} + e.tmph = (*reflect.SliceHeader)(unsafe.Pointer(&e.tmp)) + if C.yaml_emitter_initialize(&e.emitter) == 0 { + panic("Failed to initialize YAML emitter") + } + C.set_output_handler(&e.emitter) + C.yaml_stream_start_event_initialize(&e.event, C.YAML_UTF8_ENCODING) + e.emit() + C.yaml_document_start_event_initialize(&e.event, nil, nil, nil, 1) + e.emit() + return e } func (e *encoder) finish() { - C.yaml_document_end_event_initialize(&e.event, 1) - e.emit() - e.emitter.open_ended = 0 - C.yaml_stream_end_event_initialize(&e.event) - e.emit() + C.yaml_document_end_event_initialize(&e.event, 1) + e.emit() + e.emitter.open_ended = 0 + C.yaml_stream_end_event_initialize(&e.event) + e.emit() } func (e *encoder) destroy() { - C.yaml_emitter_delete(&e.emitter) + C.yaml_emitter_delete(&e.emitter) } func (e *encoder) emit() { - // This will internally delete the e.event value. - if C.yaml_emitter_emit(&e.emitter, &e.event) == 0 && - e.event._type != C.YAML_DOCUMENT_END_EVENT && - e.event._type != C.YAML_STREAM_END_EVENT { - if e.emitter.error == C.YAML_EMITTER_ERROR { - // XXX TESTME - panic("YAML emitter error: " + C.GoString(e.emitter.problem)) - } else { - // XXX TESTME - panic("Unknown YAML emitter error") - } - } + // This will internally delete the e.event value. + if C.yaml_emitter_emit(&e.emitter, &e.event) == 0 && + e.event._type != C.YAML_DOCUMENT_END_EVENT && + e.event._type != C.YAML_STREAM_END_EVENT { + if e.emitter.error == C.YAML_EMITTER_ERROR { + // XXX TESTME + panic("YAML emitter error: " + C.GoString(e.emitter.problem)) + } else { + // XXX TESTME + panic("Unknown YAML emitter error") + } + } } func (e *encoder) fail(msg string) { - if msg == "" { - if e.emitter.problem != nil { - msg = C.GoString(e.emitter.problem) - } else { - msg = "Unknown problem generating YAML content" - } - } - panic(msg) + if msg == "" { + if e.emitter.problem != nil { + msg = C.GoString(e.emitter.problem) + } else { + msg = "Unknown problem generating YAML content" + } + } + panic(msg) } func (e *encoder) marshal(tag string, in reflect.Value) { - var value interface{} - if getter, ok := in.Interface().(Getter); ok { - tag, value = getter.GetYAML() - if value == nil { - e.nilv() - return - } - in = reflect.NewValue(value) - } - switch in := in.(type) { - case *reflect.InterfaceValue: - if in.IsNil() { - e.nilv() - } else { - e.marshal(tag, in.Elem()) - } - case *reflect.MapValue: - e.mapv(tag, in) - case *reflect.PtrValue: - if in.IsNil() { - e.nilv() - } else { - e.marshal(tag, in.Elem()) - } - case *reflect.StructValue: - e.structv(tag, in) - case *reflect.SliceValue: - e.slicev(tag, in) - case *reflect.StringValue: - e.stringv(tag, in) - case *reflect.IntValue: - e.intv(tag, in) - case *reflect.UintValue: - e.uintv(tag, in) - case *reflect.FloatValue: - e.floatv(tag, in) - case *reflect.BoolValue: - e.boolv(tag, in) - default: - panic("Can't marshal type yet: " + in.Type().String()) - } + var value interface{} + if getter, ok := in.Interface().(Getter); ok { + tag, value = getter.GetYAML() + if value == nil { + e.nilv() + return + } + in = reflect.NewValue(value) + } + switch in := in.(type) { + case *reflect.InterfaceValue: + if in.IsNil() { + e.nilv() + } else { + e.marshal(tag, in.Elem()) + } + case *reflect.MapValue: + e.mapv(tag, in) + case *reflect.PtrValue: + if in.IsNil() { + e.nilv() + } else { + e.marshal(tag, in.Elem()) + } + case *reflect.StructValue: + e.structv(tag, in) + case *reflect.SliceValue: + e.slicev(tag, in) + case *reflect.StringValue: + e.stringv(tag, in) + case *reflect.IntValue: + e.intv(tag, in) + case *reflect.UintValue: + e.uintv(tag, in) + case *reflect.FloatValue: + e.floatv(tag, in) + case *reflect.BoolValue: + e.boolv(tag, in) + default: + panic("Can't marshal type yet: " + in.Type().String()) + } } func (e *encoder) mapv(tag string, in *reflect.MapValue) { - e.mappingv(tag, func() { - for _, k := range in.Keys() { - e.marshal("", k) - e.marshal("", in.Elem(k)) - } - }) + e.mappingv(tag, func() { + for _, k := range in.Keys() { + e.marshal("", k) + e.marshal("", in.Elem(k)) + } + }) } func (e *encoder) structv(tag string, in *reflect.StructValue) { - fields, err := getStructFields(in.Type().(*reflect.StructType)) - if err != nil { - panic(err) - } - e.mappingv(tag, func() { - for i, info := range fields.List { - value := in.Field(i) - if info.Conditional && isZero(value) { - continue - } - e.marshal("", reflect.NewValue(info.Key)) - e.flow = info.Flow - e.marshal("", value) - } - }) + fields, err := getStructFields(in.Type().(*reflect.StructType)) + if err != nil { + panic(err) + } + e.mappingv(tag, func() { + for i, info := range fields.List { + value := in.Field(i) + if info.Conditional && isZero(value) { + continue + } + e.marshal("", reflect.NewValue(info.Key)) + e.flow = info.Flow + e.marshal("", value) + } + }) } func (e *encoder) mappingv(tag string, f func()) { - var ctag *C.yaml_char_t - var free func() - cimplicit := C.int(1) - if tag != "" { - ctag, free = ystr(tag) - defer free() - cimplicit = 0 - } - cstyle := C.yaml_mapping_style_t(C.YAML_BLOCK_MAPPING_STYLE) - if e.flow { - e.flow = false - cstyle = C.YAML_FLOW_MAPPING_STYLE - } - C.yaml_mapping_start_event_initialize(&e.event, nil, ctag, cimplicit, - cstyle) - e.emit() - f() - C.yaml_mapping_end_event_initialize(&e.event) - e.emit() + var ctag *C.yaml_char_t + var free func() + cimplicit := C.int(1) + if tag != "" { + ctag, free = ystr(tag) + defer free() + cimplicit = 0 + } + cstyle := C.yaml_mapping_style_t(C.YAML_BLOCK_MAPPING_STYLE) + if e.flow { + e.flow = false + cstyle = C.YAML_FLOW_MAPPING_STYLE + } + C.yaml_mapping_start_event_initialize(&e.event, nil, ctag, cimplicit, + cstyle) + e.emit() + f() + C.yaml_mapping_end_event_initialize(&e.event) + e.emit() } func (e *encoder) slicev(tag string, in *reflect.SliceValue) { - var ctag *C.yaml_char_t - var free func() - var cimplicit C.int - if tag != "" { - ctag, free = ystr(tag) - defer free() - cimplicit = 0 - } else { - cimplicit = 1 - } + var ctag *C.yaml_char_t + var free func() + var cimplicit C.int + if tag != "" { + ctag, free = ystr(tag) + defer free() + cimplicit = 0 + } else { + cimplicit = 1 + } - cstyle := C.yaml_sequence_style_t(C.YAML_BLOCK_SEQUENCE_STYLE) - if e.flow { - e.flow = false - cstyle = C.YAML_FLOW_SEQUENCE_STYLE - } - C.yaml_sequence_start_event_initialize(&e.event, nil, ctag, cimplicit, - cstyle) - e.emit() - n := in.Len() - for i := 0; i < n; i++ { - e.marshal("", in.Elem(i)) - } - C.yaml_sequence_end_event_initialize(&e.event) - e.emit() + cstyle := C.yaml_sequence_style_t(C.YAML_BLOCK_SEQUENCE_STYLE) + if e.flow { + e.flow = false + cstyle = C.YAML_FLOW_SEQUENCE_STYLE + } + C.yaml_sequence_start_event_initialize(&e.event, nil, ctag, cimplicit, + cstyle) + e.emit() + n := in.Len() + for i := 0; i < n; i++ { + e.marshal("", in.Elem(i)) + } + C.yaml_sequence_end_event_initialize(&e.event) + e.emit() } func (e *encoder) stringv(tag string, in *reflect.StringValue) { - var style C.yaml_scalar_style_t - s := in.Get() - if rtag, _ := resolve("", s); rtag != "!!str" { - style = C.YAML_DOUBLE_QUOTED_SCALAR_STYLE - } else { - style = C.YAML_PLAIN_SCALAR_STYLE - } - e.emitScalar(s, "", tag, style) + var style C.yaml_scalar_style_t + s := in.Get() + if rtag, _ := resolve("", s); rtag != "!!str" { + style = C.YAML_DOUBLE_QUOTED_SCALAR_STYLE + } else { + style = C.YAML_PLAIN_SCALAR_STYLE + } + e.emitScalar(s, "", tag, style) } func (e *encoder) boolv(tag string, in *reflect.BoolValue) { - var s string - if in.Get() { - s = "true" - } else { - s = "false" - } - e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) + var s string + if in.Get() { + s = "true" + } else { + s = "false" + } + e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) } func (e *encoder) intv(tag string, in *reflect.IntValue) { - s := strconv.Itoa64(in.Get()) - e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) + s := strconv.Itoa64(in.Get()) + e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) } func (e *encoder) uintv(tag string, in *reflect.UintValue) { - s := strconv.Uitoa64(in.Get()) - e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) + s := strconv.Uitoa64(in.Get()) + e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) } func (e *encoder) floatv(tag string, in *reflect.FloatValue) { - // FIXME: Handle 64 bits here. - s := strconv.Ftoa32(float32(in.Get()), 'g', -1) - switch s { - case "+Inf": - s = ".inf" - case "-Inf": - s = "-.inf" - case "NaN": - s = ".nan" - } - e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) + // FIXME: Handle 64 bits here. + s := strconv.Ftoa32(float32(in.Get()), 'g', -1) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE) } func (e *encoder) nilv() { - e.emitScalar("null", "", "", C.YAML_PLAIN_SCALAR_STYLE) + e.emitScalar("null", "", "", C.YAML_PLAIN_SCALAR_STYLE) } func (e *encoder) emitScalar(value, anchor, tag string, style C.yaml_scalar_style_t) { - var canchor, ctag, cvalue *C.yaml_char_t - var cimplicit C.int - var free func() - if anchor != "" { - canchor, free = ystr(anchor) - defer free() - } - if tag != "" { - ctag, free = ystr(tag) - defer free() - cimplicit = 0 - style = C.YAML_PLAIN_SCALAR_STYLE - } else { - cimplicit = 1 - } - cvalue, free = ystr(value) - defer free() - size := C.int(len(value)) - if C.yaml_scalar_event_initialize(&e.event, canchor, ctag, cvalue, size, - cimplicit, cimplicit, style) == 0 { - e.fail("") - } - e.emit() + var canchor, ctag, cvalue *C.yaml_char_t + var cimplicit C.int + var free func() + if anchor != "" { + canchor, free = ystr(anchor) + defer free() + } + if tag != "" { + ctag, free = ystr(tag) + defer free() + cimplicit = 0 + style = C.YAML_PLAIN_SCALAR_STYLE + } else { + cimplicit = 1 + } + cvalue, free = ystr(value) + defer free() + size := C.int(len(value)) + if C.yaml_scalar_event_initialize(&e.event, canchor, ctag, cvalue, size, + cimplicit, cimplicit, style) == 0 { + e.fail("") + } + e.emit() } func ystr(s string) (ys *C.yaml_char_t, free func()) { - up := unsafe.Pointer(C.CString(s)) - ys = (*C.yaml_char_t)(up) - free = func() { C.free(up) } - return ys, free + up := unsafe.Pointer(C.CString(s)) + ys = (*C.yaml_char_t)(up) + free = func() { C.free(up) } + return ys, free }
diff --git a/encode_test.go b/encode_test.go index 2a8ceb1..5753cfc 100644 --- a/encode_test.go +++ b/encode_test.go
@@ -2,105 +2,105 @@ import ( - . "gocheck" - "goyaml" - "math" - //"reflect" + . "launchpad.net/gocheck" + "goyaml" + "math" + //"reflect" ) var marshalIntTest = 123 var marshalTests = []struct { - data string - value interface{} + data string + value interface{} }{ - {"{}\n", &struct{}{}}, - {"v: hi\n", map[string]string{"v": "hi"}}, - {"v: hi\n", map[string]interface{}{"v": "hi"}}, - {"v: \"true\"\n", map[string]string{"v": "true"}}, - {"v: \"false\"\n", map[string]string{"v": "false"}}, - {"v: true\n", map[string]interface{}{"v": true}}, - {"v: false\n", map[string]interface{}{"v": false}}, - {"v: 10\n", map[string]interface{}{"v": 10}}, - {"v: -10\n", map[string]interface{}{"v": -10}}, - {"v: 42\n", map[string]uint{"v": 42}}, - {"v: 4294967296\n", map[string]interface{}{"v": int64(4294967296)}}, - {"v: 4294967296\n", map[string]int64{"v": int64(4294967296)}}, - {"v: 4294967296\n", map[string]uint64{"v": 4294967296}}, - {"v: \"10\"\n", map[string]interface{}{"v": "10"}}, - {"v: 0.1\n", map[string]interface{}{"v": 0.1}}, - {"v: 0.1\n", map[string]interface{}{"v": float64(0.1)}}, - {"v: -0.1\n", map[string]interface{}{"v": -0.1}}, - {"v: .inf\n", map[string]interface{}{"v": math.Inf(+1)}}, - {"v: -.inf\n", map[string]interface{}{"v": math.Inf(-1)}}, - {"v: .nan\n", map[string]interface{}{"v": math.NaN()}}, - {"v: null\n", map[string]interface{}{"v": nil}}, - {"v: \"\"\n", map[string]interface{}{"v": ""}}, - {"v:\n- A\n- B\n", map[string][]string{"v": []string{"A", "B"}}}, - {"v:\n- A\n- 1\n", map[string][]interface{}{"v": []interface{}{"A", 1}}}, - {"a:\n b: c\n", - map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}}, + {"{}\n", &struct{}{}}, + {"v: hi\n", map[string]string{"v": "hi"}}, + {"v: hi\n", map[string]interface{}{"v": "hi"}}, + {"v: \"true\"\n", map[string]string{"v": "true"}}, + {"v: \"false\"\n", map[string]string{"v": "false"}}, + {"v: true\n", map[string]interface{}{"v": true}}, + {"v: false\n", map[string]interface{}{"v": false}}, + {"v: 10\n", map[string]interface{}{"v": 10}}, + {"v: -10\n", map[string]interface{}{"v": -10}}, + {"v: 42\n", map[string]uint{"v": 42}}, + {"v: 4294967296\n", map[string]interface{}{"v": int64(4294967296)}}, + {"v: 4294967296\n", map[string]int64{"v": int64(4294967296)}}, + {"v: 4294967296\n", map[string]uint64{"v": 4294967296}}, + {"v: \"10\"\n", map[string]interface{}{"v": "10"}}, + {"v: 0.1\n", map[string]interface{}{"v": 0.1}}, + {"v: 0.1\n", map[string]interface{}{"v": float64(0.1)}}, + {"v: -0.1\n", map[string]interface{}{"v": -0.1}}, + {"v: .inf\n", map[string]interface{}{"v": math.Inf(+1)}}, + {"v: -.inf\n", map[string]interface{}{"v": math.Inf(-1)}}, + {"v: .nan\n", map[string]interface{}{"v": math.NaN()}}, + {"v: null\n", map[string]interface{}{"v": nil}}, + {"v: \"\"\n", map[string]interface{}{"v": ""}}, + {"v:\n- A\n- B\n", map[string][]string{"v": []string{"A", "B"}}}, + {"v:\n- A\n- 1\n", map[string][]interface{}{"v": []interface{}{"A", 1}}}, + {"a:\n b: c\n", + map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}}, - // Simple values. - {"123\n", &marshalIntTest}, + // Simple values. + {"123\n", &marshalIntTest}, - // Structures - {"hello: world\n", &struct{ Hello string }{"world"}}, - {"a:\n b: c\n", &struct { - A struct { - B string - } - }{struct{ B string }{"c"}}}, - {"a:\n b: c\n", &struct { - A *struct { - B string - } - }{&struct{ B string }{"c"}}}, - {"a: null\n", &struct { - A *struct { - B string - } - }{}}, - {"a: 1\n", &struct{ A int }{1}}, - {"a:\n- 1\n- 2\n", &struct{ A []int }{[]int{1, 2}}}, - {"a: 1\n", &struct { - B int "a" - }{1}}, - {"a: true\n", &struct{ A bool }{true}}, + // Structures + {"hello: world\n", &struct{ Hello string }{"world"}}, + {"a:\n b: c\n", &struct { + A struct { + B string + } + }{struct{ B string }{"c"}}}, + {"a:\n b: c\n", &struct { + A *struct { + B string + } + }{&struct{ B string }{"c"}}}, + {"a: null\n", &struct { + A *struct { + B string + } + }{}}, + {"a: 1\n", &struct{ A int }{1}}, + {"a:\n- 1\n- 2\n", &struct{ A []int }{[]int{1, 2}}}, + {"a: 1\n", &struct { + B int "a" + }{1}}, + {"a: true\n", &struct{ A bool }{true}}, - // Conditional flag - {"a: 1\n", &struct { - A int "a/c" - B int "b/c" - }{1, 0}}, - {"{}\n", &struct { - A int "a/c" - B int "b/c" - }{0, 0}}, + // Conditional flag + {"a: 1\n", &struct { + A int "a/c" + B int "b/c" + }{1, 0}}, + {"{}\n", &struct { + A int "a/c" + B int "b/c" + }{0, 0}}, - // Flow flag - {"a: [1, 2]\n", &struct { - A []int "a/f" - }{[]int{1, 2}}}, - {"a: {b: c}\n", - &struct { - A map[string]string "a/f" - }{map[string]string{"b": "c"}}}, - {"a: {b: c}\n", - &struct { - A struct { - B string - } "a/f" - }{struct{ B string }{"c"}}}, + // Flow flag + {"a: [1, 2]\n", &struct { + A []int "a/f" + }{[]int{1, 2}}}, + {"a: {b: c}\n", + &struct { + A map[string]string "a/f" + }{map[string]string{"b": "c"}}}, + {"a: {b: c}\n", + &struct { + A struct { + B string + } "a/f" + }{struct{ B string }{"c"}}}, } func (s *S) TestMarshal(c *C) { - for _, item := range marshalTests { - data, err := goyaml.Marshal(item.value) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, item.data) - } + for _, item := range marshalTests { + data, err := goyaml.Marshal(item.value) + c.Assert(err, IsNil) + c.Assert(string(data), Equals, item.data) + } } //var unmarshalErrorTests = []struct{data, error string}{ @@ -118,54 +118,54 @@ var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"} var getterTests = []struct { - data, tag string - value interface{} + data, tag string + value interface{} }{ - {"_:\n hi: there\n", "", map[interface{}]interface{}{"hi": "there"}}, - {"_:\n- 1\n- A\n", "", []interface{}{1, "A"}}, - {"_: 10\n", "", 10}, - {"_: null\n", "", nil}, - {"_: !foo BAR!\n", "!foo", "BAR!"}, - {"_: !foo 1\n", "!foo", "1"}, - {"_: !foo '\"1\"'\n", "!foo", "\"1\""}, - {"_: !foo 1.1\n", "!foo", 1.1}, - {"_: !foo 1\n", "!foo", 1}, - {"_: !foo 1\n", "!foo", uint(1)}, - {"_: !foo true\n", "!foo", true}, - {"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}}, - {"_: !foo\n A: B\n", "!foo", map[string]string{"A": "B"}}, - {"_: !foo\n a: B\n", "!foo", &marshalTaggedIfaceTest}, + {"_:\n hi: there\n", "", map[interface{}]interface{}{"hi": "there"}}, + {"_:\n- 1\n- A\n", "", []interface{}{1, "A"}}, + {"_: 10\n", "", 10}, + {"_: null\n", "", nil}, + {"_: !foo BAR!\n", "!foo", "BAR!"}, + {"_: !foo 1\n", "!foo", "1"}, + {"_: !foo '\"1\"'\n", "!foo", "\"1\""}, + {"_: !foo 1.1\n", "!foo", 1.1}, + {"_: !foo 1\n", "!foo", 1}, + {"_: !foo 1\n", "!foo", uint(1)}, + {"_: !foo true\n", "!foo", true}, + {"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}}, + {"_: !foo\n A: B\n", "!foo", map[string]string{"A": "B"}}, + {"_: !foo\n a: B\n", "!foo", &marshalTaggedIfaceTest}, } type typeWithGetter struct { - tag string - value interface{} + tag string + value interface{} } func (o typeWithGetter) GetYAML() (tag string, value interface{}) { - return o.tag, o.value + return o.tag, o.value } type typeWithGetterField struct { - Field typeWithGetter "_" + Field typeWithGetter "_" } func (s *S) TestMashalWithGetter(c *C) { - for _, item := range getterTests { - obj := &typeWithGetterField{} - obj.Field.tag = item.tag - obj.Field.value = item.value - data, err := goyaml.Marshal(obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, string(item.data)) - } + for _, item := range getterTests { + obj := &typeWithGetterField{} + obj.Field.tag = item.tag + obj.Field.value = item.value + data, err := goyaml.Marshal(obj) + c.Assert(err, IsNil) + c.Assert(string(data), Equals, string(item.data)) + } } func (s *S) TestUnmarshalWholeDocumentWithGetter(c *C) { - obj := &typeWithGetter{} - obj.tag = "" - obj.value = map[string]string{"hello": "world!"} - data, err := goyaml.Marshal(obj) - c.Assert(err, IsNil) - c.Assert(string(data), Equals, "hello: world!\n") + obj := &typeWithGetter{} + obj.tag = "" + obj.value = map[string]string{"hello": "world!"} + data, err := goyaml.Marshal(obj) + c.Assert(err, IsNil) + c.Assert(string(data), Equals, "hello: world!\n") }
diff --git a/goyaml.go b/goyaml.go index 60d578e..58a9a05 100644 --- a/goyaml.go +++ b/goyaml.go
@@ -10,25 +10,25 @@ package goyaml import ( - "reflect" - "runtime" - "strings" - "sync" - "os" + "reflect" + "runtime" + "strings" + "sync" + "os" ) func handleErr(err *os.Error) { - if r := recover(); r != nil { - if _, ok := r.(runtime.Error); ok { - panic(r) - } else if s, ok := r.(string); ok { - *err = os.ErrorString("YAML error: " + s) - } else if e, ok := r.(os.Error); ok { - *err = e - } else { - panic(r) - } - } + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } else if s, ok := r.(string); ok { + *err = os.ErrorString("YAML error: " + s) + } else if e, ok := r.(os.Error); ok { + *err = e + } else { + panic(r) + } + } } // Objects implementing the goyaml.Setter interface will receive the YAML @@ -37,14 +37,14 @@ // works, the method should return true. If it returns false, the given // value will be omitted from maps and slices. type Setter interface { - SetYAML(tag string, value interface{}) bool + SetYAML(tag string, value interface{}) bool } // Objects implementing the goyaml.Getter interface will get the GetYAML() // method called when goyaml is requested to marshal the given value, and // the result of this method will be marshaled in place of the actual object. type Getter interface { - GetYAML() (tag string, value interface{}) + GetYAML() (tag string, value interface{}) } // Unmarshal decodes the first document found within the in byte slice @@ -80,15 +80,15 @@ // goyaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // func Unmarshal(in []byte, out interface{}) (err os.Error) { - defer handleErr(&err) - d := newDecoder() - p := newParser(in) - defer p.destroy() - node := p.parse() - if node != nil { - d.unmarshal(node, reflect.NewValue(out)) - } - return nil + defer handleErr(&err) + d := newDecoder() + p := newParser(in) + defer p.destroy() + node := p.parse() + if node != nil { + d.unmarshal(node, reflect.NewValue(out)) + } + return nil } // Marshal writes the object provided into a YAML document. The structure @@ -114,13 +114,13 @@ // goyaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" // func Marshal(in interface{}) (out []byte, err os.Error) { - defer handleErr(&err) - e := newEncoder() - defer e.destroy() - e.marshal("", reflect.NewValue(in)) - e.finish() - out = e.out - return + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshal("", reflect.NewValue(in)) + e.finish() + out = e.out + return } @@ -130,99 +130,99 @@ // The code in this section was copied from gobson. type structFields struct { - Map map[string]fieldInfo - List []fieldInfo + Map map[string]fieldInfo + List []fieldInfo } type fieldInfo struct { - Key string - Num int - Conditional bool - Flow bool + Key string + Num int + Conditional bool + Flow bool } var fieldMap = make(map[string]*structFields) var fieldMapMutex sync.RWMutex func getStructFields(st *reflect.StructType) (*structFields, os.Error) { - path := st.PkgPath() - name := st.Name() + path := st.PkgPath() + name := st.Name() - fullName := path + "." + name - fieldMapMutex.RLock() - fields, found := fieldMap[fullName] - fieldMapMutex.RUnlock() - if found { - return fields, nil - } + fullName := path + "." + name + fieldMapMutex.RLock() + fields, found := fieldMap[fullName] + fieldMapMutex.RUnlock() + if found { + return fields, nil + } - n := st.NumField() - fieldsMap := make(map[string]fieldInfo) - fieldsList := make([]fieldInfo, n) - for i := 0; i != n; i++ { - field := st.Field(i) - if field.PkgPath != "" { - continue // Private field - } + n := st.NumField() + fieldsMap := make(map[string]fieldInfo) + fieldsList := make([]fieldInfo, n) + for i := 0; i != n; i++ { + field := st.Field(i) + if field.PkgPath != "" { + continue // Private field + } - info := fieldInfo{Num: i} + info := fieldInfo{Num: i} - if s := strings.LastIndex(field.Tag, "/"); s != -1 { - for _, c := range field.Tag[s+1:] { - switch c { - case int('c'): - info.Conditional = true - case int('f'): - info.Flow = true - default: - panic("Unsupported field flag: " + string([]int{c})) - } - } - field.Tag = field.Tag[:s] - } + if s := strings.LastIndex(field.Tag, "/"); s != -1 { + for _, c := range field.Tag[s+1:] { + switch c { + case int('c'): + info.Conditional = true + case int('f'): + info.Flow = true + default: + panic("Unsupported field flag: " + string([]int{c})) + } + } + field.Tag = field.Tag[:s] + } - if field.Tag != "" { - info.Key = field.Tag - } else { - info.Key = strings.ToLower(field.Name) - } + if field.Tag != "" { + info.Key = field.Tag + } else { + info.Key = strings.ToLower(field.Name) + } - if _, found = fieldsMap[info.Key]; found { - msg := "Duplicated key '" + info.Key + "' in struct " + st.String() - return nil, os.NewError(msg) - } + if _, found = fieldsMap[info.Key]; found { + msg := "Duplicated key '" + info.Key + "' in struct " + st.String() + return nil, os.NewError(msg) + } - fieldsList[len(fieldsMap)] = info - fieldsMap[info.Key] = info - } + fieldsList[len(fieldsMap)] = info + fieldsMap[info.Key] = info + } - fields = &structFields{fieldsMap, fieldsList[:len(fieldsMap)]} + fields = &structFields{fieldsMap, fieldsList[:len(fieldsMap)]} - if fullName != "." { - fieldMapMutex.Lock() - fieldMap[fullName] = fields - fieldMapMutex.Unlock() - } + if fullName != "." { + fieldMapMutex.Lock() + fieldMap[fullName] = fields + fieldMapMutex.Unlock() + } - return fields, nil + return fields, nil } func isZero(v reflect.Value) bool { - switch v := v.(type) { - case *reflect.StringValue: - return len(v.Get()) == 0 - case *reflect.InterfaceValue: - return v.IsNil() - case *reflect.SliceValue: - return v.Len() == 0 - case *reflect.MapValue: - return v.Len() == 0 - case *reflect.IntValue: - return v.Get() == 0 - case *reflect.UintValue: - return v.Get() == 0 - case *reflect.BoolValue: - return !v.Get() - } - return false + switch v := v.(type) { + case *reflect.StringValue: + return len(v.Get()) == 0 + case *reflect.InterfaceValue: + return v.IsNil() + case *reflect.SliceValue: + return v.Len() == 0 + case *reflect.MapValue: + return v.Len() == 0 + case *reflect.IntValue: + return v.Get() == 0 + case *reflect.UintValue: + return v.Get() == 0 + case *reflect.BoolValue: + return !v.Get() + } + return false }
diff --git a/resolve.go b/resolve.go index 45e6955..36f43ff 100644 --- a/resolve.go +++ b/resolve.go
@@ -1,9 +1,9 @@ package goyaml import ( - "strconv" - "strings" - "math" + "strconv" + "strings" + "math" ) @@ -11,8 +11,8 @@ type resolveMapItem struct { - value interface{} - tag string + value interface{} + tag string } var resolveTable = make([]byte, 256) @@ -20,139 +20,139 @@ func init() { - t := resolveTable - t[int('+')] = 'S' // Sign - t[int('-')] = 'S' - for _, c := range "0123456789" { - t[int(c)] = 'D' // Digit - } - for _, c := range "yYnNtTfFoO~" { - t[int(c)] = 'M' // In map - } - t[int('.')] = '.' // Float (potentially in map) - t[int('<')] = '<' // Merge + t := resolveTable + t[int('+')] = 'S' // Sign + t[int('-')] = 'S' + for _, c := range "0123456789" { + t[int(c)] = 'D' // Digit + } + for _, c := range "yYnNtTfFoO~" { + t[int(c)] = 'M' // In map + } + t[int('.')] = '.' // Float (potentially in map) + t[int('<')] = '<' // Merge - var resolveMapList = []struct { - v interface{} - tag string - l []string - }{ - {true, "!!bool", []string{"y", "Y", "yes", "Yes", "YES"}}, - {true, "!!bool", []string{"true", "True", "TRUE"}}, - {true, "!!bool", []string{"on", "On", "ON"}}, - {false, "!!bool", []string{"n", "N", "no", "No", "NO"}}, - {false, "!!bool", []string{"false", "False", "FALSE"}}, - {false, "!!bool", []string{"off", "Off", "OFF"}}, - {nil, "!!null", []string{"~", "null", "Null", "NULL"}}, - {math.NaN(), "!!float", []string{".nan", ".NaN", ".NAN"}}, - {math.Inf(+1), "!!float", []string{".inf", ".Inf", ".INF"}}, - {math.Inf(+1), "!!float", []string{"+.inf", "+.Inf", "+.INF"}}, - {math.Inf(-1), "!!float", []string{"-.inf", "-.Inf", "-.INF"}}, - } + var resolveMapList = []struct { + v interface{} + tag string + l []string + }{ + {true, "!!bool", []string{"y", "Y", "yes", "Yes", "YES"}}, + {true, "!!bool", []string{"true", "True", "TRUE"}}, + {true, "!!bool", []string{"on", "On", "ON"}}, + {false, "!!bool", []string{"n", "N", "no", "No", "NO"}}, + {false, "!!bool", []string{"false", "False", "FALSE"}}, + {false, "!!bool", []string{"off", "Off", "OFF"}}, + {nil, "!!null", []string{"~", "null", "Null", "NULL"}}, + {math.NaN(), "!!float", []string{".nan", ".NaN", ".NAN"}}, + {math.Inf(+1), "!!float", []string{".inf", ".Inf", ".INF"}}, + {math.Inf(+1), "!!float", []string{"+.inf", "+.Inf", "+.INF"}}, + {math.Inf(-1), "!!float", []string{"-.inf", "-.Inf", "-.INF"}}, + } - m := resolveMap - for _, item := range resolveMapList { - for _, s := range item.l { - m[s] = resolveMapItem{item.v, item.tag} - } - } + m := resolveMap + for _, item := range resolveMapList { + for _, s := range item.l { + m[s] = resolveMapItem{item.v, item.tag} + } + } } const longTagPrefix = "tag:yaml.org,2002:" func shortTag(tag string) string { - if strings.HasPrefix(tag, longTagPrefix) { - return "!!" + tag[len(longTagPrefix):] - } - return tag + if strings.HasPrefix(tag, longTagPrefix) { + return "!!" + tag[len(longTagPrefix):] + } + return tag } func resolvableTag(tag string) bool { - switch tag { - case "", "!!str", "!!bool", "!!int", "!!float", "!!null": - return true - } - return false + switch tag { + case "", "!!str", "!!bool", "!!int", "!!float", "!!null": + return true + } + return false } func resolve(tag string, in string) (rtag string, out interface{}) { - tag = shortTag(tag) - if !resolvableTag(tag) { - return tag, in - } + tag = shortTag(tag) + if !resolvableTag(tag) { + return tag, in + } - defer func() { - if tag != "" && tag != rtag { - panic("Can't decode " + rtag + " '" + in + "' as a " + tag) - } - }() + defer func() { + if tag != "" && tag != rtag { + panic("Can't decode " + rtag + " '" + in + "' as a " + tag) + } + }() - if in == "" { - return "!!null", nil - } + if in == "" { + return "!!null", nil + } - c := resolveTable[in[0]] - if c == 0 { - // It's a string for sure. Nothing to do. - return "!!str", in - } + c := resolveTable[in[0]] + if c == 0 { + // It's a string for sure. Nothing to do. + return "!!str", in + } - // Handle things we can lookup in a map. - if item, ok := resolveMap[in]; ok { - return item.tag, item.value - } + // Handle things we can lookup in a map. + if item, ok := resolveMap[in]; ok { + return item.tag, item.value + } - switch c { - case 'M': - // We've already checked the map above. + switch c { + case 'M': + // We've already checked the map above. - case '.': - // Not in the map, so maybe a normal float. - floatv, err := strconv.Atof64(in) - if err == nil { - return "!!float", floatv - } - // XXX Handle base 60 floats here (WTF!) + case '.': + // Not in the map, so maybe a normal float. + floatv, err := strconv.Atof64(in) + if err == nil { + return "!!float", floatv + } + // XXX Handle base 60 floats here (WTF!) - case 'D', 'S': - // Int, float, or timestamp. - for i := 0; i != len(in); i++ { - if in[i] == '_' { - in = strings.Replace(in, "_", "", -1) - break - } - } - intv, err := strconv.Btoi64(in, 0) - if err == nil { - if intv == int64(int(intv)) { - return "!!int", int(intv) - } else { - return "!!int", intv - } - } - floatv, err := strconv.Atof64(in) - if err == nil { - return "!!float", floatv - } - if strings.HasPrefix(in, "0b") { - intv, err := strconv.Btoi64(in[2:], 2) - if err == nil { - return "!!int", int(intv) - } - } else if strings.HasPrefix(in, "-0b") { - intv, err := strconv.Btoi64(in[3:], 2) - if err == nil { - return "!!int", -int(intv) - } - } - // XXX Handle timestamps here. + case 'D', 'S': + // Int, float, or timestamp. + for i := 0; i != len(in); i++ { + if in[i] == '_' { + in = strings.Replace(in, "_", "", -1) + break + } + } + intv, err := strconv.Btoi64(in, 0) + if err == nil { + if intv == int64(int(intv)) { + return "!!int", int(intv) + } else { + return "!!int", intv + } + } + floatv, err := strconv.Atof64(in) + if err == nil { + return "!!float", floatv + } + if strings.HasPrefix(in, "0b") { + intv, err := strconv.Btoi64(in[2:], 2) + if err == nil { + return "!!int", int(intv) + } + } else if strings.HasPrefix(in, "-0b") { + intv, err := strconv.Btoi64(in[3:], 2) + if err == nil { + return "!!int", -int(intv) + } + } + // XXX Handle timestamps here. - case '<': - // XXX Handle merge (<<) here. + case '<': + // XXX Handle merge (<<) here. - default: - panic("resolveTable item not yet handled: " + - string([]byte{c}) + " (with " + in + ")") - } - return "!!str", in + default: + panic("resolveTable item not yet handled: " + + string([]byte{c}) + " (with " + in + ")") + } + return "!!str", in }
diff --git a/suite_test.go b/suite_test.go index be26fc2..03359cd 100644 --- a/suite_test.go +++ b/suite_test.go
@@ -2,8 +2,8 @@ import ( - . "gocheck" - "testing" + . "launchpad.net/gocheck" + "testing" ) func Test(t *testing.T) { TestingT(t) }