//// Copyright (c) 2011-2019 Canonical Ltd//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.package yamlimport ()type resolveMapItem struct { value interface{} tag string}var resolveTable = make([]byte, 256)var resolveMap = make(map[string]resolveMapItem)func init() { := resolveTable [int('+')] = 'S'// Sign [int('-')] = 'S'for , := range"0123456789" { [int()] = 'D'// Digit }for , := range"yYnNtTfFoO~" { [int()] = 'M'// In map } [int('.')] = '.'// Float (potentially in map)var = []struct {interface{}string []string }{ {true, boolTag, []string{"true", "True", "TRUE"}}, {false, boolTag, []string{"false", "False", "FALSE"}}, {nil, nullTag, []string{"", "~", "null", "Null", "NULL"}}, {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"}}, {"<<", mergeTag, []string{"<<"}}, } := resolveMapfor , := range {for , := range . { [] = resolveMapItem{., .} } }}const ( nullTag = "!!null" boolTag = "!!bool" strTag = "!!str" intTag = "!!int" floatTag = "!!float" timestampTag = "!!timestamp" seqTag = "!!seq" mapTag = "!!map" binaryTag = "!!binary" mergeTag = "!!merge")var longTags = make(map[string]string)var shortTags = make(map[string]string)func init() {for , := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} { := longTag()longTags[] = shortTags[] = }}const longTagPrefix = "tag:yaml.org,2002:"func shortTag( string) string {ifstrings.HasPrefix(, longTagPrefix) {if , := shortTags[]; {return }return"!!" + [len(longTagPrefix):] }return}func longTag( string) string {ifstrings.HasPrefix(, "!!") {if , := longTags[]; {return }returnlongTagPrefix + [2:] }return}func resolvableTag( string) bool {switch {case"", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:returntrue }returnfalse}var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)func resolve( string, string) ( string, interface{}) { = shortTag()if !resolvableTag() {return , }deferfunc() {switch {case"", , strTag, binaryTag:returncasefloatTag:if == intTag {switch v := .(type) {caseint64: = floatTag = float64()returncaseint: = floatTag = float64()return } } }failf("cannot decode %s `%s` as a %s", shortTag(), , shortTag()) }()// Any data is accepted as a !!str or !!binary. // Otherwise, the prefix is enough of a hint about what it might be. := byte('N')if != "" { = resolveTable[[0]] }if != 0 && != strTag && != binaryTag {// Handle things we can lookup in a map.if , := resolveMap[]; {return .tag, .value }// Base 60 floats are a bad idea, were dropped in YAML 1.2, and // are purposefully unsupported here. They're still quoted on // the way out for compatibility with other parser, though.switch {case'M':// We've already checked the map above.case'.':// Not in the map, so maybe a normal float. , := strconv.ParseFloat(, 64)if == nil {returnfloatTag, }case'D', 'S':// Int, float, or timestamp. // Only try values as a timestamp if the value is unquoted or there's an explicit // !!timestamp tag.if == "" || == timestampTag { , := parseTimestamp()if {returntimestampTag, } } := strings.Replace(, "_", "", -1) , := strconv.ParseInt(, 0, 64)if == nil {if == int64(int()) {returnintTag, int() } else {returnintTag, } } , := strconv.ParseUint(, 0, 64)if == nil {returnintTag, }ifyamlStyleFloat.MatchString() { , := strconv.ParseFloat(, 64)if == nil {returnfloatTag, } }ifstrings.HasPrefix(, "0b") { , := strconv.ParseInt([2:], 2, 64)if == nil {if == int64(int()) {returnintTag, int() } else {returnintTag, } } , := strconv.ParseUint([2:], 2, 64)if == nil {returnintTag, } } elseifstrings.HasPrefix(, "-0b") { , := strconv.ParseInt("-"+[3:], 2, 64)if == nil {iftrue || == int64(int()) {returnintTag, int() } else {returnintTag, } } }// Octals as introduced in version 1.2 of the spec. // Octals from the 1.1 spec, spelled as 0777, are still // decoded by default in v3 as well for compatibility. // May be dropped in v4 depending on how usage evolves.ifstrings.HasPrefix(, "0o") { , := strconv.ParseInt([2:], 8, 64)if == nil {if == int64(int()) {returnintTag, int() } else {returnintTag, } } , := strconv.ParseUint([2:], 8, 64)if == nil {returnintTag, } } elseifstrings.HasPrefix(, "-0o") { , := strconv.ParseInt("-"+[3:], 8, 64)if == nil {iftrue || == int64(int()) {returnintTag, int() } else {returnintTag, } } }default:panic("internal error: missing handler for resolver table: " + string(rune()) + " (with " + + ")") } }returnstrTag, }// encodeBase64 encodes s as base64 that is broken up into multiple lines// as appropriate for the resulting length.func encodeBase64( string) string {const = 70 := base64.StdEncoding.EncodedLen(len()) := / + 1 := make([]byte, *2+) := [0:] := [:]base64.StdEncoding.Encode(, []byte()) := 0for := 0; < len(); += { := + if > len() { = len() } += copy([:], [:])if > 1 { [] = '\n' ++ } }returnstring([:])}// This is a subset of the formats allowed by the regular expression// defined at http://yaml.org/type/timestamp.html.var allowedTimestampFormats = []string{"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields."2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t"."2006-1-2 15:4:5.999999999", // space separated with no time zone"2006-1-2", // date only// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" // from the set of examples.}// parseTimestamp parses s as a timestamp string and// returns the timestamp and reports whether it succeeded.// Timestamp formats are defined at http://yaml.org/type/timestamp.htmlfunc parseTimestamp( string) (time.Time, bool) {// TODO write code to check all the formats supported by // http://yaml.org/type/timestamp.html instead of using time.Parse.// Quick check: all date formats start with YYYY-. := 0for ; < len(); ++ {if := []; < '0' || > '9' {break } }if != 4 || == len() || [] != '-' {returntime.Time{}, false }for , := rangeallowedTimestampFormats {if , := time.Parse(, ); == nil {return , true } }returntime.Time{}, false}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.