Implemented encoding of values.
diff --git a/Makefile b/Makefile index 423c69b..4af8483 100644 --- a/Makefile +++ b/Makefile
@@ -11,15 +11,24 @@ CGOFILES=\ decode.go\ + encode.go\ CGO_LDFLAGS+=-lm -lpthread CGO_CFLAGS+=-I$(YAML)/include -CGO_OFILES+=_lib/*.o +#CGO_OFILES+=_lib/*.o +CGO_OFILES+=\ + helpers.o\ + _lib/api.o\ + _lib/scanner.o\ + _lib/reader.o\ + _lib/parser.o\ + _lib/writer.o\ + _lib/emitter.o\ all: package -$(CGO_OFILES): $(LIBYAML) +_lib/api.o: $(LIBYAML) @mkdir -p _lib cd _lib && ar x $(LIBYAML) @@ -29,5 +38,3 @@ CLEANFILES=_lib include $(GOROOT)/src/Make.pkg - -_cgo_defun.c: helpers.c
diff --git a/decode.go b/decode.go index 18233e9..475c017 100644 --- a/decode.go +++ b/decode.go
@@ -1,6 +1,6 @@ package goyaml -/* #include "helpers.c" */ +// #include "helpers.h" import "C" import ( @@ -11,24 +11,24 @@ type decoder struct { - parser *C.yaml_parser_t - event *C.yaml_event_t + parser C.yaml_parser_t + event C.yaml_event_t } func newDecoder(b []byte) *decoder { - if len(b) == 0 { - panic("Can't handle empty buffers yet") // XXX Fix this. + d := decoder{} + if C.yaml_parser_initialize(&d.parser) == 0 { + panic("Failed to initialize YAML emitter") } - d := decoder{} - d.event = &C.yaml_event_t{} - d.parser = &C.yaml_parser_t{} - C.yaml_parser_initialize(d.parser) + 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(d.parser, input, (C.size_t)(len(b))) + C.yaml_parser_set_input_string(&d.parser, input, (C.size_t)(len(b))) d.next() if d.event._type != C.YAML_STREAM_START_EVENT { @@ -41,9 +41,9 @@ func (d *decoder) destroy() { if d.event._type != C.YAML_NO_EVENT { - C.yaml_event_delete(d.event) + C.yaml_event_delete(&d.event) } - C.yaml_parser_delete(d.parser) + C.yaml_parser_delete(&d.parser) } func (d *decoder) next() { @@ -51,13 +51,34 @@ if d.event._type == C.YAML_STREAM_END_EVENT { panic("Attempted to go past the end of stream. Corrupted value?") } - C.yaml_event_delete(d.event) + C.yaml_event_delete(&d.event) } - if C.yaml_parser_parse(d.parser, d.event) == 0 { - panic("Parsing failed.") // XXX Need better error handling here. + if C.yaml_parser_parse(&d.parser, &d.event) == 0 { + d.fail("") } } +func (d *decoder) fail(msg string) { + var where string + var line int + if d.parser.problem_mark.line != 0 { + line = int(C.int(d.parser.problem_mark.line)) + } else if d.parser.context_mark.line != 0 { + line = int(C.int(d.parser.context_mark.line)) + } + if line != 0 { + where = "line " + strconv.Itoa(line) + ": " + } + if msg == "" { + if d.parser.problem != nil { + msg = C.GoString(d.parser.problem) + } else { + msg = "Unknown problem parsing YAML content" + } + } + panic(where + msg) +} + func (d *decoder) skip(_type C.yaml_event_type_t) { for d.event._type != _type { d.next() @@ -125,6 +146,8 @@ good = d.sequence(out) case C.YAML_DOCUMENT_START_EVENT: good = d.document(out) + case C.YAML_STREAM_END_EVENT: + // Happens when attempting to decode an empty buffer. default: panic("Attempted to unmarshal unexpected event: " + strconv.Itoa(int(d.event._type))) @@ -144,7 +167,7 @@ } func (d *decoder) scalar(out reflect.Value) (good bool) { - scalar := C.event_scalar(d.event) + scalar := C.event_scalar(&d.event) str := GoYString(scalar.value) tag := GoYString(scalar.tag) var resolved interface{}
diff --git a/decode_test.go b/decode_test.go index 27cf3ec..e78a70c 100644 --- a/decode_test.go +++ b/decode_test.go
@@ -9,25 +9,30 @@ ) -var unmarshalTests = []struct{data string; value interface{}}{ - // It will encode either value as a string if asked for. - {"hello: world", map[string]string{"hello": "world"}}, - {"hello: true", map[string]string{"hello": "true"}}, +var unmarshalIntTest = 123 - // And when given the option, will preserve the YAML type. - {"hello: world", map[string]interface{}{"hello": "world"}}, - {"hello: true", map[string]interface{}{"hello": true}}, - {"hello: 10", map[string]interface{}{"hello": 10}}, - {"hello: 0b10", map[string]interface{}{"hello": 2}}, - {"hello: 0xA", map[string]interface{}{"hello": 10}}, - {"hello: 4294967296", map[string]interface{}{"hello": int64(4294967296)}}, - {"hello: 4294967296", map[string]int64{"hello": int64(4294967296)}}, - {"hello: 0.1", map[string]interface{}{"hello": 0.1}}, - {"hello: .1", map[string]interface{}{"hello": 0.1}}, - {"hello: .Inf", map[string]interface{}{"hello": math.Inf(+1)}}, - {"hello: -.Inf", map[string]interface{}{"hello": math.Inf(-1)}}, - {"hello: -10", map[string]interface{}{"hello": -10}}, - {"hello: -.1", map[string]interface{}{"hello": -0.1}}, +var unmarshalTests = []struct{data string; value interface{}}{ + {"", &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}}, + + // Simple values. + {"123", &unmarshalIntTest}, // Floats from spec {"canonical: 6.8523e+5", map[string]interface{}{"canonical": 6.8523e+5}}, @@ -35,7 +40,7 @@ {"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}}, + {"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, {"fixed: 685_230.15", map[string]float{"fixed": 685230.15}}, // Bools from spec @@ -94,7 +99,7 @@ {"v: 128", map[string]int8{}}, // Quoted values. - {"'1': '2'", map[interface{}]interface{}{"1": "2"}}, + {"'1': '\"2\"'", map[interface{}]interface{}{"1": "\"2\""}}, // Explicit tags. {"v: !!float '1.1'", map[string]interface{}{"v": 1.1}}, @@ -123,7 +128,10 @@ } var unmarshalErrorTests = []struct{data, error string}{ - {"v: !!float 'error'", "Can't decode !!str 'error' as a !!float"}, + {"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"}, } func (s *S) TestUnmarshalErrors(c *C) {
diff --git a/encode.go b/encode.go new file mode 100644 index 0000000..8cad299 --- /dev/null +++ b/encode.go
@@ -0,0 +1,278 @@ +package goyaml + +// #include "helpers.h" +import "C" + +import ( + "reflect" + "unsafe" + "strconv" +) + + +type encoder struct { + emitter C.yaml_emitter_t + event C.yaml_event_t + out []byte + tmp []byte + tmph *reflect.SliceHeader +} + + +//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 +} + +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 +} + +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() +} + +func (e *encoder) destroy() { + 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") + } + } +} + +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) +} + +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()) + } +} + +func (e *encoder) mapv(tag string, in *reflect.MapValue) { + 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 + } + C.yaml_mapping_start_event_initialize(&e.event, nil, ctag, cimplicit, + C.YAML_BLOCK_MAPPING_STYLE) + e.emit() + for _, k := range in.Keys() { + e.marshal("", k) + e.marshal("", in.Elem(k)) + } + C.yaml_mapping_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) structv(tag string, in *reflect.StructValue) { + var ctag *C.yaml_char_t + var free func() + cimplicit := C.int(1) + if tag != "" { + ctag, free = ystr(tag) + defer free() + cimplicit = 0 + } + C.yaml_mapping_start_event_initialize(&e.event, nil, ctag, cimplicit, + C.YAML_BLOCK_MAPPING_STYLE) + e.emit() + fields, err := getStructFields(in.Type().(*reflect.StructType)) + if err != nil { + panic(err) + } + for i, info := range fields.List { + value := in.Field(i) + if info.Conditional && isZero(value) { + continue + } + e.marshal("", reflect.NewValue(info.Key)) + e.marshal("", value) + } + 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 + } + C.yaml_sequence_start_event_initialize(&e.event, nil, ctag, cimplicit, + C.YAML_BLOCK_SEQUENCE_STYLE) + 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) +} + +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) +} + +func (e *encoder) intv(tag string, in *reflect.IntValue) { + 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) +} + +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) +} + +func (e *encoder) nilv() { + 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() +} + +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 +}
diff --git a/encode_test.go b/encode_test.go new file mode 100644 index 0000000..6e0eb20 --- /dev/null +++ b/encode_test.go
@@ -0,0 +1,130 @@ +package goyaml_test + + +import ( + . "gocheck" + "goyaml" + "math" + //"reflect" +) + +var marshalIntTest = 123 + +var marshalTests = []struct{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"}}}, + + // 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}}, + + // 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}}, +} + + +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) + } +} + +//var unmarshalErrorTests = []struct{data, error string}{ +// {"v: !!float 'error'", "Can't decode !!str 'error' as a !!float"}, +//} +// +//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) +// } +//} + +var marshalTaggedIfaceTest interface{} = &struct{A string}{"B"} + +var getterTests = []struct{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}, +} + +type typeWithGetter struct { + tag string + value interface{} +} + +func (o typeWithGetter) GetYAML() (tag string, value interface{}) { + return o.tag, o.value +} + +type typeWithGetterField struct { + 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)) + } +} + +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") +}
diff --git a/goyaml.go b/goyaml.go index d3bff72..198f170 100644 --- a/goyaml.go +++ b/goyaml.go
@@ -13,7 +13,7 @@ if _, ok := r.(runtime.Error); ok { panic(r) } else if s, ok := r.(string); ok { - *err = os.ErrorString(s) + *err = os.ErrorString("YAML error: " + s) } else if e, ok := r.(os.Error); ok { *err = e } else { @@ -22,6 +22,13 @@ } } +type Setter interface { + SetYAML(tag string, value interface{}) bool +} + +type Getter interface { + GetYAML() (tag string, value interface{}) +} func Unmarshal(in []byte, out interface{}) (err os.Error) { defer handleErr(&err) @@ -31,12 +38,14 @@ return nil } -type Setter interface { - SetYAML(tag string, value interface{}) bool -} - -type Getter interface { - GetYAML() (tag string, value interface{}) +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 }
diff --git a/helpers.c b/helpers.c index 7ce0c1f..e63c67d 100644 --- a/helpers.c +++ b/helpers.c
@@ -1,8 +1,14 @@ -#include <yaml.h> +#include "_cgo_export.h" +#include "helpers.h" __typeof__(((yaml_event_t *)0)->data.scalar) * // Sadness. event_scalar(yaml_event_t *event) { - return &event->data.scalar; + return &event->data.scalar; +} + +void set_output_handler(yaml_emitter_t *e) +{ + yaml_emitter_set_output(e, outputHandler, (void *)e); }
diff --git a/helpers.h b/helpers.h new file mode 100644 index 0000000..d2cb15c --- /dev/null +++ b/helpers.h
@@ -0,0 +1,10 @@ +#ifndef helpers_h +#define helpers_h + +#include <yaml.h> + +__typeof__(((yaml_event_t *)0)->data.scalar) *event_scalar(yaml_event_t *event); + +void set_output_handler(yaml_emitter_t *e); + +#endif
diff --git a/resolve.go b/resolve.go index 296c585..9af47c9 100644 --- a/resolve.go +++ b/resolve.go
@@ -7,7 +7,7 @@ ) -// TODO: Support merge, timestamps, and base 60 floats. +// TODO: merge, timestamps, base 60 floats, omap. type resolveMapItem struct { @@ -40,7 +40,7 @@ {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.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"}},