|
|
@@ -10,33 +10,9 @@ import (
|
|
|
// TODO: Support merge, timestamps, and base 60 floats.
|
|
|
|
|
|
|
|
|
-type stdTag int
|
|
|
-
|
|
|
-var StrTag = stdTag(1)
|
|
|
-var BoolTag = stdTag(2)
|
|
|
-var IntTag = stdTag(3)
|
|
|
-var FloatTag = stdTag(4)
|
|
|
-
|
|
|
-func (t stdTag) String() string {
|
|
|
- switch t {
|
|
|
- case StrTag:
|
|
|
- return "tag:yaml.org,2002:str"
|
|
|
- case BoolTag:
|
|
|
- return "tag:yaml.org,2002:bool"
|
|
|
- case IntTag:
|
|
|
- return "tag:yaml.org,2002:int"
|
|
|
- case FloatTag:
|
|
|
- return "tag:yaml.org,2002:float"
|
|
|
- default:
|
|
|
- panic("Internal error: missing tag case")
|
|
|
- }
|
|
|
- return ""
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
type resolveMapItem struct {
|
|
|
value interface{}
|
|
|
- tag stdTag
|
|
|
+ tag string
|
|
|
}
|
|
|
|
|
|
var resolveTable = make([]byte, 256)
|
|
|
@@ -50,23 +26,24 @@ func init() {
|
|
|
for _, c := range "0123456789" {
|
|
|
t[int(c)] = 'D' // Digit
|
|
|
}
|
|
|
- for _, c := range "yYnNtTfFoO" {
|
|
|
+ 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 stdTag; l []string} {
|
|
|
- {true, BoolTag, []string{"y", "Y", "yes", "Yes", "YES"}},
|
|
|
- {true, BoolTag, []string{"true", "True", "TRUE"}},
|
|
|
- {true, BoolTag, []string{"on", "On", "ON"}},
|
|
|
- {false, BoolTag, []string{"n", "N", "no", "No", "NO"}},
|
|
|
- {false, BoolTag, []string{"false", "False", "FALSE"}},
|
|
|
- {false, BoolTag, []string{"off", "Off", "OFF"}},
|
|
|
- {math.NaN, FloatTag, []string{".nan", ".NaN", ".NAN"}},
|
|
|
- {math.Inf(+1), FloatTag, []string{".inf", ".Inf", ".INF"}},
|
|
|
- {math.Inf(+1), FloatTag, []string{"+.inf", "+.Inf", "+.INF"}},
|
|
|
- {math.Inf(-1), FloatTag, []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
|
|
|
@@ -77,19 +54,48 @@ func init() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func resolve(in string) (out interface{}, tag stdTag) {
|
|
|
+const longTagPrefix = "tag:yaml.org,2002:"
|
|
|
+
|
|
|
+func shortTag(tag string) string {
|
|
|
+ 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
|
|
|
+}
|
|
|
+
|
|
|
+func resolve(tag string, in string) (rtag string, out interface{}) {
|
|
|
+ tag = shortTag(tag)
|
|
|
+ if !resolvableTag(tag) {
|
|
|
+ return tag, in
|
|
|
+ }
|
|
|
+
|
|
|
+ defer func() {
|
|
|
+ if tag != "" && tag != rtag {
|
|
|
+ panic("Can't decode " + rtag + " '" + in + "' as a " + tag)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
if in == "" {
|
|
|
- return in, tag
|
|
|
+ return "!!null", nil
|
|
|
}
|
|
|
+
|
|
|
c := resolveTable[in[0]]
|
|
|
if c == 0 {
|
|
|
// It's a string for sure. Nothing to do.
|
|
|
- return in, StrTag
|
|
|
+ return "!!str", in
|
|
|
}
|
|
|
|
|
|
// Handle things we can lookup in a map.
|
|
|
if item, ok := resolveMap[in]; ok {
|
|
|
- return item.value, item.tag
|
|
|
+ return item.tag, item.value
|
|
|
}
|
|
|
|
|
|
switch c {
|
|
|
@@ -100,9 +106,9 @@ func resolve(in string) (out interface{}, tag stdTag) {
|
|
|
// Not in the map, so maybe a normal float.
|
|
|
floatv, err := strconv.Atof(in)
|
|
|
if err == nil {
|
|
|
- return floatv, FloatTag
|
|
|
+ return "!!float", floatv
|
|
|
}
|
|
|
- // XXX Handle base 60 floats here.
|
|
|
+ // XXX Handle base 60 floats here (WTF!)
|
|
|
|
|
|
case 'D', 'S':
|
|
|
// Int, float, or timestamp.
|
|
|
@@ -115,14 +121,25 @@ func resolve(in string) (out interface{}, tag stdTag) {
|
|
|
intv, err := strconv.Btoi64(in, 0)
|
|
|
if err == nil {
|
|
|
if intv == int64(int(intv)) {
|
|
|
- return int(intv), IntTag
|
|
|
+ return "!!int", int(intv)
|
|
|
} else {
|
|
|
- return intv, IntTag
|
|
|
+ return "!!int", intv
|
|
|
}
|
|
|
}
|
|
|
floatv, err := strconv.Atof(in)
|
|
|
if err == nil {
|
|
|
- return floatv, FloatTag
|
|
|
+ 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.
|
|
|
|
|
|
@@ -133,5 +150,5 @@ func resolve(in string) (out interface{}, tag stdTag) {
|
|
|
panic("resolveTable item not yet handled: " +
|
|
|
string([]byte{c}) + " (with " + in +")")
|
|
|
}
|
|
|
- return in, StrTag
|
|
|
+ return "!!str", in
|
|
|
}
|