Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package strconv

import 
lower(c) is a lower-case letter if and only if c is either that lower-case letter or the equivalent upper-case letter. Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. Note that lower of non-letters can produce other non-letters.
func ( byte) byte {
	return  | ('x' - 'X')
}
ErrRange indicates that a value is out of range for the target type.
var ErrRange = errors.New("value out of range")
ErrSyntax indicates that a value does not have the right syntax for the target type.
var ErrSyntax = errors.New("invalid syntax")
A NumError records a failed conversion.
type NumError struct {
	Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex)
	Num  string // the input
	Err  error  // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
}

func ( *NumError) () string {
	return "strconv." + .Func + ": " + "parsing " + Quote(.Num) + ": " + .Err.Error()
}

func ( *NumError) () error { return .Err }

func (,  string) *NumError {
	return &NumError{, , ErrSyntax}
}

func (,  string) *NumError {
	return &NumError{, , ErrRange}
}

func (,  string,  int) *NumError {
	return &NumError{, , errors.New("invalid base " + Itoa())}
}

func (,  string,  int) *NumError {
	return &NumError{, , errors.New("invalid bit size " + Itoa())}
}

const intSize = 32 << (^uint(0) >> 63)
IntSize is the size in bits of an int or uint value.
const IntSize = intSize

const maxUint64 = 1<<64 - 1
ParseUint is like ParseInt but for unsigned numbers.
func ( string,  int,  int) (uint64, error) {
	const  = "ParseUint"

	if  == "" {
		return 0, syntaxError(, )
	}

	 :=  == 0

	 := 
	switch {
valid base; nothing to do

Look for octal, hex prefix.
		 = 10
		if [0] == '0' {
			switch {
			case len() >= 3 && lower([1]) == 'b':
				 = 2
				 = [2:]
			case len() >= 3 && lower([1]) == 'o':
				 = 8
				 = [2:]
			case len() >= 3 && lower([1]) == 'x':
				 = 16
				 = [2:]
			default:
				 = 8
				 = [1:]
			}
		}

	default:
		return 0, baseError(, , )
	}

	if  == 0 {
		 = IntSize
	} else if  < 0 ||  > 64 {
		return 0, bitSizeError(, , )
	}
Cutoff is the smallest number such that cutoff*base > maxUint64. Use compile-time constants for common cases.
	var  uint64
	switch  {
	case 10:
		 = maxUint64/10 + 1
	case 16:
		 = maxUint64/16 + 1
	default:
		 = maxUint64/uint64() + 1
	}

	 := uint64(1)<<uint() - 1

	 := false
	var  uint64
	for ,  := range []byte() {
		var  byte
		switch {
		case  == '_' && :
			 = true
			continue
		case '0' <=  &&  <= '9':
			 =  - '0'
		case 'a' <= lower() && lower() <= 'z':
			 = lower() - 'a' + 10
		default:
			return 0, syntaxError(, )
		}

		if  >= byte() {
			return 0, syntaxError(, )
		}

n*base overflows
			return , rangeError(, )
		}
		 *= uint64()

		 :=  + uint64()
n+v overflows
			return , rangeError(, )
		}
		 = 
	}

	if  && !underscoreOK() {
		return 0, syntaxError(, )
	}

	return , nil
}
ParseInt interprets a string s in the given base (0, 2 to 36) and bit size (0 to 64) and returns the corresponding value i. If the base argument is 0, the true base is implied by the string's prefix: 2 for "0b", 8 for "0" or "0o", 16 for "0x", and 10 otherwise. Also, for argument base 0 only, underscore characters are permitted as defined by the Go syntax for integer literals. The bitSize argument specifies the integer type that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 correspond to int, int8, int16, int32, and int64. If bitSize is below 0 or above 64, an error is returned. The errors that ParseInt returns have concrete type *NumError and include err.Num = s. If s is empty or contains invalid digits, err.Err = ErrSyntax and the returned value is 0; if the value corresponding to s cannot be represented by a signed integer of the given size, err.Err = ErrRange and the returned value is the maximum magnitude integer of the appropriate bitSize and sign.
func ( string,  int,  int) ( int64,  error) {
	const  = "ParseInt"

	if  == "" {
		return 0, syntaxError(, )
	}
Pick off leading sign.
	 := 
	 := false
	if [0] == '+' {
		 = [1:]
	} else if [0] == '-' {
		 = true
		 = [1:]
	}
Convert unsigned and check range.
	var  uint64
	,  = ParseUint(, , )
	if  != nil && .(*NumError).Err != ErrRange {
		.(*NumError).Func = 
		.(*NumError).Num = 
		return 0, 
	}

	if  == 0 {
		 = IntSize
	}

	 := uint64(1 << uint(-1))
	if ! &&  >=  {
		return int64( - 1), rangeError(, )
	}
	if  &&  >  {
		return -int64(), rangeError(, )
	}
	 := int64()
	if  {
		 = -
	}
	return , nil
}
Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
func ( string) (int, error) {
	const  = "Atoi"

	 := len()
	if intSize == 32 && (0 <  &&  < 10) ||
Fast path for small integers that fit int type.
		 := 
		if [0] == '-' || [0] == '+' {
			 = [1:]
			if len() < 1 {
				return 0, &NumError{, , ErrSyntax}
			}
		}

		 := 0
		for ,  := range []byte() {
			 -= '0'
			if  > 9 {
				return 0, &NumError{, , ErrSyntax}
			}
			 = *10 + int()
		}
		if [0] == '-' {
			 = -
		}
		return , nil
	}
Slow path for invalid, big, or underscored integers.
	,  := ParseInt(, 10, 0)
	if ,  := .(*NumError);  {
		.Func = 
	}
	return int(), 
}
underscoreOK reports whether the underscores in s are allowed. Checking them in this one function lets all the parsers skip over them simply. Underscore must appear only between digits or between a base prefix and a digit.
saw tracks the last character (class) we saw: ^ for beginning of number, 0 for a digit or base prefix, _ for an underscore, ! for none of the above.
	 := '^'
	 := 0
Optional sign.
	if len() >= 1 && ([0] == '-' || [0] == '+') {
		 = [1:]
	}
Optional base prefix.
	 := false
	if len() >= 2 && [0] == '0' && (lower([1]) == 'b' || lower([1]) == 'o' || lower([1]) == 'x') {
		 = 2
		 = '0' // base prefix counts as a digit for "underscore as digit separator"
		 = lower([1]) == 'x'
	}
Number proper.
Digits are always okay.
		if '0' <= [] && [] <= '9' ||  && 'a' <= lower([]) && lower([]) <= 'f' {
			 = '0'
			continue
Underscore must follow digit.
		if [] == '_' {
			if  != '0' {
				return false
			}
			 = '_'
			continue
Underscore must also be followed by digit.
		if  == '_' {
			return false
Saw non-digit, non-underscore.
		 = '!'
	}
	return  != '_'