vendor/github.com/pelletier/go-toml/v2/decode.go
changeset 265 05c40b36d3b2
parent 260 445e01aede7e
equal deleted inserted replaced
264:8f478162d991 265:05c40b36d3b2
     3 import (
     3 import (
     4 	"fmt"
     4 	"fmt"
     5 	"math"
     5 	"math"
     6 	"strconv"
     6 	"strconv"
     7 	"time"
     7 	"time"
       
     8 
       
     9 	"github.com/pelletier/go-toml/v2/unstable"
     8 )
    10 )
     9 
    11 
    10 func parseInteger(b []byte) (int64, error) {
    12 func parseInteger(b []byte) (int64, error) {
    11 	if len(b) > 2 && b[0] == '0' {
    13 	if len(b) > 2 && b[0] == '0' {
    12 		switch b[1] {
    14 		switch b[1] {
    30 	// date-month     = 2DIGIT  ; 01-12
    32 	// date-month     = 2DIGIT  ; 01-12
    31 	// date-mday      = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
    33 	// date-mday      = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
    32 	var date LocalDate
    34 	var date LocalDate
    33 
    35 
    34 	if len(b) != 10 || b[4] != '-' || b[7] != '-' {
    36 	if len(b) != 10 || b[4] != '-' || b[7] != '-' {
    35 		return date, newDecodeError(b, "dates are expected to have the format YYYY-MM-DD")
    37 		return date, unstable.NewParserError(b, "dates are expected to have the format YYYY-MM-DD")
    36 	}
    38 	}
    37 
    39 
    38 	var err error
    40 	var err error
    39 
    41 
    40 	date.Year, err = parseDecimalDigits(b[0:4])
    42 	date.Year, err = parseDecimalDigits(b[0:4])
    51 	if err != nil {
    53 	if err != nil {
    52 		return LocalDate{}, err
    54 		return LocalDate{}, err
    53 	}
    55 	}
    54 
    56 
    55 	if !isValidDate(date.Year, date.Month, date.Day) {
    57 	if !isValidDate(date.Year, date.Month, date.Day) {
    56 		return LocalDate{}, newDecodeError(b, "impossible date")
    58 		return LocalDate{}, unstable.NewParserError(b, "impossible date")
    57 	}
    59 	}
    58 
    60 
    59 	return date, nil
    61 	return date, nil
    60 }
    62 }
    61 
    63 
    62 func parseDecimalDigits(b []byte) (int, error) {
    64 func parseDecimalDigits(b []byte) (int, error) {
    63 	v := 0
    65 	v := 0
    64 
    66 
    65 	for i, c := range b {
    67 	for i, c := range b {
    66 		if c < '0' || c > '9' {
    68 		if c < '0' || c > '9' {
    67 			return 0, newDecodeError(b[i:i+1], "expected digit (0-9)")
    69 			return 0, unstable.NewParserError(b[i:i+1], "expected digit (0-9)")
    68 		}
    70 		}
    69 		v *= 10
    71 		v *= 10
    70 		v += int(c - '0')
    72 		v += int(c - '0')
    71 	}
    73 	}
    72 
    74 
    95 		b = b[1:]
    97 		b = b[1:]
    96 		zone = time.UTC
    98 		zone = time.UTC
    97 	} else {
    99 	} else {
    98 		const dateTimeByteLen = 6
   100 		const dateTimeByteLen = 6
    99 		if len(b) != dateTimeByteLen {
   101 		if len(b) != dateTimeByteLen {
   100 			return time.Time{}, newDecodeError(b, "invalid date-time timezone")
   102 			return time.Time{}, unstable.NewParserError(b, "invalid date-time timezone")
   101 		}
   103 		}
   102 		var direction int
   104 		var direction int
   103 		switch b[0] {
   105 		switch b[0] {
   104 		case '-':
   106 		case '-':
   105 			direction = -1
   107 			direction = -1
   106 		case '+':
   108 		case '+':
   107 			direction = +1
   109 			direction = +1
   108 		default:
   110 		default:
   109 			return time.Time{}, newDecodeError(b[:1], "invalid timezone offset character")
   111 			return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset character")
   110 		}
   112 		}
   111 
   113 
   112 		if b[3] != ':' {
   114 		if b[3] != ':' {
   113 			return time.Time{}, newDecodeError(b[3:4], "expected a : separator")
   115 			return time.Time{}, unstable.NewParserError(b[3:4], "expected a : separator")
   114 		}
   116 		}
   115 
   117 
   116 		hours, err := parseDecimalDigits(b[1:3])
   118 		hours, err := parseDecimalDigits(b[1:3])
   117 		if err != nil {
   119 		if err != nil {
   118 			return time.Time{}, err
   120 			return time.Time{}, err
   119 		}
   121 		}
   120 		if hours > 23 {
   122 		if hours > 23 {
   121 			return time.Time{}, newDecodeError(b[:1], "invalid timezone offset hours")
   123 			return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset hours")
   122 		}
   124 		}
   123 
   125 
   124 		minutes, err := parseDecimalDigits(b[4:6])
   126 		minutes, err := parseDecimalDigits(b[4:6])
   125 		if err != nil {
   127 		if err != nil {
   126 			return time.Time{}, err
   128 			return time.Time{}, err
   127 		}
   129 		}
   128 		if minutes > 59 {
   130 		if minutes > 59 {
   129 			return time.Time{}, newDecodeError(b[:1], "invalid timezone offset minutes")
   131 			return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset minutes")
   130 		}
   132 		}
   131 
   133 
   132 		seconds := direction * (hours*3600 + minutes*60)
   134 		seconds := direction * (hours*3600 + minutes*60)
   133 		if seconds == 0 {
   135 		if seconds == 0 {
   134 			zone = time.UTC
   136 			zone = time.UTC
   137 		}
   139 		}
   138 		b = b[dateTimeByteLen:]
   140 		b = b[dateTimeByteLen:]
   139 	}
   141 	}
   140 
   142 
   141 	if len(b) > 0 {
   143 	if len(b) > 0 {
   142 		return time.Time{}, newDecodeError(b, "extra bytes at the end of the timezone")
   144 		return time.Time{}, unstable.NewParserError(b, "extra bytes at the end of the timezone")
   143 	}
   145 	}
   144 
   146 
   145 	t := time.Date(
   147 	t := time.Date(
   146 		dt.Year,
   148 		dt.Year,
   147 		time.Month(dt.Month),
   149 		time.Month(dt.Month),
   158 func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
   160 func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
   159 	var dt LocalDateTime
   161 	var dt LocalDateTime
   160 
   162 
   161 	const localDateTimeByteMinLen = 11
   163 	const localDateTimeByteMinLen = 11
   162 	if len(b) < localDateTimeByteMinLen {
   164 	if len(b) < localDateTimeByteMinLen {
   163 		return dt, nil, newDecodeError(b, "local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNNNNN]")
   165 		return dt, nil, unstable.NewParserError(b, "local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNNNNN]")
   164 	}
   166 	}
   165 
   167 
   166 	date, err := parseLocalDate(b[:10])
   168 	date, err := parseLocalDate(b[:10])
   167 	if err != nil {
   169 	if err != nil {
   168 		return dt, nil, err
   170 		return dt, nil, err
   169 	}
   171 	}
   170 	dt.LocalDate = date
   172 	dt.LocalDate = date
   171 
   173 
   172 	sep := b[10]
   174 	sep := b[10]
   173 	if sep != 'T' && sep != ' ' && sep != 't' {
   175 	if sep != 'T' && sep != ' ' && sep != 't' {
   174 		return dt, nil, newDecodeError(b[10:11], "datetime separator is expected to be T or a space")
   176 		return dt, nil, unstable.NewParserError(b[10:11], "datetime separator is expected to be T or a space")
   175 	}
   177 	}
   176 
   178 
   177 	t, rest, err := parseLocalTime(b[11:])
   179 	t, rest, err := parseLocalTime(b[11:])
   178 	if err != nil {
   180 	if err != nil {
   179 		return dt, nil, err
   181 		return dt, nil, err
   193 	)
   195 	)
   194 
   196 
   195 	// check if b matches to have expected format HH:MM:SS[.NNNNNN]
   197 	// check if b matches to have expected format HH:MM:SS[.NNNNNN]
   196 	const localTimeByteLen = 8
   198 	const localTimeByteLen = 8
   197 	if len(b) < localTimeByteLen {
   199 	if len(b) < localTimeByteLen {
   198 		return t, nil, newDecodeError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]")
   200 		return t, nil, unstable.NewParserError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]")
   199 	}
   201 	}
   200 
   202 
   201 	var err error
   203 	var err error
   202 
   204 
   203 	t.Hour, err = parseDecimalDigits(b[0:2])
   205 	t.Hour, err = parseDecimalDigits(b[0:2])
   204 	if err != nil {
   206 	if err != nil {
   205 		return t, nil, err
   207 		return t, nil, err
   206 	}
   208 	}
   207 
   209 
   208 	if t.Hour > 23 {
   210 	if t.Hour > 23 {
   209 		return t, nil, newDecodeError(b[0:2], "hour cannot be greater 23")
   211 		return t, nil, unstable.NewParserError(b[0:2], "hour cannot be greater 23")
   210 	}
   212 	}
   211 	if b[2] != ':' {
   213 	if b[2] != ':' {
   212 		return t, nil, newDecodeError(b[2:3], "expecting colon between hours and minutes")
   214 		return t, nil, unstable.NewParserError(b[2:3], "expecting colon between hours and minutes")
   213 	}
   215 	}
   214 
   216 
   215 	t.Minute, err = parseDecimalDigits(b[3:5])
   217 	t.Minute, err = parseDecimalDigits(b[3:5])
   216 	if err != nil {
   218 	if err != nil {
   217 		return t, nil, err
   219 		return t, nil, err
   218 	}
   220 	}
   219 	if t.Minute > 59 {
   221 	if t.Minute > 59 {
   220 		return t, nil, newDecodeError(b[3:5], "minutes cannot be greater 59")
   222 		return t, nil, unstable.NewParserError(b[3:5], "minutes cannot be greater 59")
   221 	}
   223 	}
   222 	if b[5] != ':' {
   224 	if b[5] != ':' {
   223 		return t, nil, newDecodeError(b[5:6], "expecting colon between minutes and seconds")
   225 		return t, nil, unstable.NewParserError(b[5:6], "expecting colon between minutes and seconds")
   224 	}
   226 	}
   225 
   227 
   226 	t.Second, err = parseDecimalDigits(b[6:8])
   228 	t.Second, err = parseDecimalDigits(b[6:8])
   227 	if err != nil {
   229 	if err != nil {
   228 		return t, nil, err
   230 		return t, nil, err
   229 	}
   231 	}
   230 
   232 
   231 	if t.Second > 60 {
   233 	if t.Second > 60 {
   232 		return t, nil, newDecodeError(b[6:8], "seconds cannot be greater 60")
   234 		return t, nil, unstable.NewParserError(b[6:8], "seconds cannot be greater 60")
   233 	}
   235 	}
   234 
   236 
   235 	b = b[8:]
   237 	b = b[8:]
   236 
   238 
   237 	if len(b) >= 1 && b[0] == '.' {
   239 	if len(b) >= 1 && b[0] == '.' {
   240 		digits := 0
   242 		digits := 0
   241 
   243 
   242 		for i, c := range b[1:] {
   244 		for i, c := range b[1:] {
   243 			if !isDigit(c) {
   245 			if !isDigit(c) {
   244 				if i == 0 {
   246 				if i == 0 {
   245 					return t, nil, newDecodeError(b[0:1], "need at least one digit after fraction point")
   247 					return t, nil, unstable.NewParserError(b[0:1], "need at least one digit after fraction point")
   246 				}
   248 				}
   247 				break
   249 				break
   248 			}
   250 			}
   249 			digits++
   251 			digits++
   250 
   252 
   264 			frac += int(c - '0')
   266 			frac += int(c - '0')
   265 			precision++
   267 			precision++
   266 		}
   268 		}
   267 
   269 
   268 		if precision == 0 {
   270 		if precision == 0 {
   269 			return t, nil, newDecodeError(b[:1], "nanoseconds need at least one digit")
   271 			return t, nil, unstable.NewParserError(b[:1], "nanoseconds need at least one digit")
   270 		}
   272 		}
   271 
   273 
   272 		t.Nanosecond = frac * nspow[precision]
   274 		t.Nanosecond = frac * nspow[precision]
   273 		t.Precision = precision
   275 		t.Precision = precision
   274 
   276 
   287 	if err != nil {
   289 	if err != nil {
   288 		return 0, err
   290 		return 0, err
   289 	}
   291 	}
   290 
   292 
   291 	if cleaned[0] == '.' {
   293 	if cleaned[0] == '.' {
   292 		return 0, newDecodeError(b, "float cannot start with a dot")
   294 		return 0, unstable.NewParserError(b, "float cannot start with a dot")
   293 	}
   295 	}
   294 
   296 
   295 	if cleaned[len(cleaned)-1] == '.' {
   297 	if cleaned[len(cleaned)-1] == '.' {
   296 		return 0, newDecodeError(b, "float cannot end with a dot")
   298 		return 0, unstable.NewParserError(b, "float cannot end with a dot")
   297 	}
   299 	}
   298 
   300 
   299 	dotAlreadySeen := false
   301 	dotAlreadySeen := false
   300 	for i, c := range cleaned {
   302 	for i, c := range cleaned {
   301 		if c == '.' {
   303 		if c == '.' {
   302 			if dotAlreadySeen {
   304 			if dotAlreadySeen {
   303 				return 0, newDecodeError(b[i:i+1], "float can have at most one decimal point")
   305 				return 0, unstable.NewParserError(b[i:i+1], "float can have at most one decimal point")
   304 			}
   306 			}
   305 			if !isDigit(cleaned[i-1]) {
   307 			if !isDigit(cleaned[i-1]) {
   306 				return 0, newDecodeError(b[i-1:i+1], "float decimal point must be preceded by a digit")
   308 				return 0, unstable.NewParserError(b[i-1:i+1], "float decimal point must be preceded by a digit")
   307 			}
   309 			}
   308 			if !isDigit(cleaned[i+1]) {
   310 			if !isDigit(cleaned[i+1]) {
   309 				return 0, newDecodeError(b[i:i+2], "float decimal point must be followed by a digit")
   311 				return 0, unstable.NewParserError(b[i:i+2], "float decimal point must be followed by a digit")
   310 			}
   312 			}
   311 			dotAlreadySeen = true
   313 			dotAlreadySeen = true
   312 		}
   314 		}
   313 	}
   315 	}
   314 
   316 
   315 	start := 0
   317 	start := 0
   316 	if cleaned[0] == '+' || cleaned[0] == '-' {
   318 	if cleaned[0] == '+' || cleaned[0] == '-' {
   317 		start = 1
   319 		start = 1
   318 	}
   320 	}
   319 	if cleaned[start] == '0' && isDigit(cleaned[start+1]) {
   321 	if cleaned[start] == '0' && isDigit(cleaned[start+1]) {
   320 		return 0, newDecodeError(b, "float integer part cannot have leading zeroes")
   322 		return 0, unstable.NewParserError(b, "float integer part cannot have leading zeroes")
   321 	}
   323 	}
   322 
   324 
   323 	f, err := strconv.ParseFloat(string(cleaned), 64)
   325 	f, err := strconv.ParseFloat(string(cleaned), 64)
   324 	if err != nil {
   326 	if err != nil {
   325 		return 0, newDecodeError(b, "unable to parse float: %w", err)
   327 		return 0, unstable.NewParserError(b, "unable to parse float: %w", err)
   326 	}
   328 	}
   327 
   329 
   328 	return f, nil
   330 	return f, nil
   329 }
   331 }
   330 
   332 
   334 		return 0, err
   336 		return 0, err
   335 	}
   337 	}
   336 
   338 
   337 	i, err := strconv.ParseInt(string(cleaned), 16, 64)
   339 	i, err := strconv.ParseInt(string(cleaned), 16, 64)
   338 	if err != nil {
   340 	if err != nil {
   339 		return 0, newDecodeError(b, "couldn't parse hexadecimal number: %w", err)
   341 		return 0, unstable.NewParserError(b, "couldn't parse hexadecimal number: %w", err)
   340 	}
   342 	}
   341 
   343 
   342 	return i, nil
   344 	return i, nil
   343 }
   345 }
   344 
   346 
   348 		return 0, err
   350 		return 0, err
   349 	}
   351 	}
   350 
   352 
   351 	i, err := strconv.ParseInt(string(cleaned), 8, 64)
   353 	i, err := strconv.ParseInt(string(cleaned), 8, 64)
   352 	if err != nil {
   354 	if err != nil {
   353 		return 0, newDecodeError(b, "couldn't parse octal number: %w", err)
   355 		return 0, unstable.NewParserError(b, "couldn't parse octal number: %w", err)
   354 	}
   356 	}
   355 
   357 
   356 	return i, nil
   358 	return i, nil
   357 }
   359 }
   358 
   360 
   362 		return 0, err
   364 		return 0, err
   363 	}
   365 	}
   364 
   366 
   365 	i, err := strconv.ParseInt(string(cleaned), 2, 64)
   367 	i, err := strconv.ParseInt(string(cleaned), 2, 64)
   366 	if err != nil {
   368 	if err != nil {
   367 		return 0, newDecodeError(b, "couldn't parse binary number: %w", err)
   369 		return 0, unstable.NewParserError(b, "couldn't parse binary number: %w", err)
   368 	}
   370 	}
   369 
   371 
   370 	return i, nil
   372 	return i, nil
   371 }
   373 }
   372 
   374 
   385 	if isSign(cleaned[0]) {
   387 	if isSign(cleaned[0]) {
   386 		startIdx++
   388 		startIdx++
   387 	}
   389 	}
   388 
   390 
   389 	if len(cleaned) > startIdx+1 && cleaned[startIdx] == '0' {
   391 	if len(cleaned) > startIdx+1 && cleaned[startIdx] == '0' {
   390 		return 0, newDecodeError(b, "leading zero not allowed on decimal number")
   392 		return 0, unstable.NewParserError(b, "leading zero not allowed on decimal number")
   391 	}
   393 	}
   392 
   394 
   393 	i, err := strconv.ParseInt(string(cleaned), 10, 64)
   395 	i, err := strconv.ParseInt(string(cleaned), 10, 64)
   394 	if err != nil {
   396 	if err != nil {
   395 		return 0, newDecodeError(b, "couldn't parse decimal number: %w", err)
   397 		return 0, unstable.NewParserError(b, "couldn't parse decimal number: %w", err)
   396 	}
   398 	}
   397 
   399 
   398 	return i, nil
   400 	return i, nil
   399 }
   401 }
   400 
   402 
   407 	if len(b) == start {
   409 	if len(b) == start {
   408 		return b, nil
   410 		return b, nil
   409 	}
   411 	}
   410 
   412 
   411 	if b[start] == '_' {
   413 	if b[start] == '_' {
   412 		return nil, newDecodeError(b[start:start+1], "number cannot start with underscore")
   414 		return nil, unstable.NewParserError(b[start:start+1], "number cannot start with underscore")
   413 	}
   415 	}
   414 
   416 
   415 	if b[len(b)-1] == '_' {
   417 	if b[len(b)-1] == '_' {
   416 		return nil, newDecodeError(b[len(b)-1:], "number cannot end with underscore")
   418 		return nil, unstable.NewParserError(b[len(b)-1:], "number cannot end with underscore")
   417 	}
   419 	}
   418 
   420 
   419 	// fast path
   421 	// fast path
   420 	i := 0
   422 	i := 0
   421 	for ; i < len(b); i++ {
   423 	for ; i < len(b); i++ {
   433 
   435 
   434 	for i++; i < len(b); i++ {
   436 	for i++; i < len(b); i++ {
   435 		c := b[i]
   437 		c := b[i]
   436 		if c == '_' {
   438 		if c == '_' {
   437 			if !before {
   439 			if !before {
   438 				return nil, newDecodeError(b[i-1:i+1], "number must have at least one digit between underscores")
   440 				return nil, unstable.NewParserError(b[i-1:i+1], "number must have at least one digit between underscores")
   439 			}
   441 			}
   440 			before = false
   442 			before = false
   441 		} else {
   443 		} else {
   442 			before = true
   444 			before = true
   443 			cleaned = append(cleaned, c)
   445 			cleaned = append(cleaned, c)
   447 	return cleaned, nil
   449 	return cleaned, nil
   448 }
   450 }
   449 
   451 
   450 func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
   452 func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
   451 	if b[0] == '_' {
   453 	if b[0] == '_' {
   452 		return nil, newDecodeError(b[0:1], "number cannot start with underscore")
   454 		return nil, unstable.NewParserError(b[0:1], "number cannot start with underscore")
   453 	}
   455 	}
   454 
   456 
   455 	if b[len(b)-1] == '_' {
   457 	if b[len(b)-1] == '_' {
   456 		return nil, newDecodeError(b[len(b)-1:], "number cannot end with underscore")
   458 		return nil, unstable.NewParserError(b[len(b)-1:], "number cannot end with underscore")
   457 	}
   459 	}
   458 
   460 
   459 	// fast path
   461 	// fast path
   460 	i := 0
   462 	i := 0
   461 	for ; i < len(b); i++ {
   463 	for ; i < len(b); i++ {
   474 		c := b[i]
   476 		c := b[i]
   475 
   477 
   476 		switch c {
   478 		switch c {
   477 		case '_':
   479 		case '_':
   478 			if !before {
   480 			if !before {
   479 				return nil, newDecodeError(b[i-1:i+1], "number must have at least one digit between underscores")
   481 				return nil, unstable.NewParserError(b[i-1:i+1], "number must have at least one digit between underscores")
   480 			}
   482 			}
   481 			if i < len(b)-1 && (b[i+1] == 'e' || b[i+1] == 'E') {
   483 			if i < len(b)-1 && (b[i+1] == 'e' || b[i+1] == 'E') {
   482 				return nil, newDecodeError(b[i+1:i+2], "cannot have underscore before exponent")
   484 				return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore before exponent")
   483 			}
   485 			}
   484 			before = false
   486 			before = false
   485 		case '+', '-':
   487 		case '+', '-':
   486 			// signed exponents
   488 			// signed exponents
   487 			cleaned = append(cleaned, c)
   489 			cleaned = append(cleaned, c)
   488 			before = false
   490 			before = false
   489 		case 'e', 'E':
   491 		case 'e', 'E':
   490 			if i < len(b)-1 && b[i+1] == '_' {
   492 			if i < len(b)-1 && b[i+1] == '_' {
   491 				return nil, newDecodeError(b[i+1:i+2], "cannot have underscore after exponent")
   493 				return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore after exponent")
   492 			}
   494 			}
   493 			cleaned = append(cleaned, c)
   495 			cleaned = append(cleaned, c)
   494 		case '.':
   496 		case '.':
   495 			if i < len(b)-1 && b[i+1] == '_' {
   497 			if i < len(b)-1 && b[i+1] == '_' {
   496 				return nil, newDecodeError(b[i+1:i+2], "cannot have underscore after decimal point")
   498 				return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore after decimal point")
   497 			}
   499 			}
   498 			if i > 0 && b[i-1] == '_' {
   500 			if i > 0 && b[i-1] == '_' {
   499 				return nil, newDecodeError(b[i-1:i], "cannot have underscore before decimal point")
   501 				return nil, unstable.NewParserError(b[i-1:i], "cannot have underscore before decimal point")
   500 			}
   502 			}
   501 			cleaned = append(cleaned, c)
   503 			cleaned = append(cleaned, c)
   502 		default:
   504 		default:
   503 			before = true
   505 			before = true
   504 			cleaned = append(cleaned, c)
   506 			cleaned = append(cleaned, c)
   540 }
   542 }
   541 
   543 
   542 func isLeap(year int) bool {
   544 func isLeap(year int) bool {
   543 	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
   545 	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
   544 }
   546 }
       
   547 
       
   548 func isDigit(r byte) bool {
       
   549 	return r >= '0' && r <= '9'
       
   550 }