// Copyright 2018 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 text

// parseNumberValue parses a number from the input and returns a Token object.
func ( *Decoder) () (Token, bool) {
	 := .in
	 := parseNumber()
	if .size == 0 {
		return Token{}, false
	}
	 := .kind
	if .neg {
		 |= isNegative
	}
	 := Token{
		kind:     Scalar,
		attrs:    numberValue,
		pos:      len(.orig) - len(.in),
		raw:      .in[:.size],
		str:      .string(.in),
		numAttrs: ,
	}
	.consume(.size)
	return , true
}

const (
	numDec uint8 = (1 << iota) / 2
	numHex
	numOct
	numFloat
)

// number is the result of parsing out a valid number from parseNumber. It
// contains data for doing float or integer conversion via the strconv package
// in conjunction with the input bytes.
type number struct {
	kind uint8
	neg  bool
	size int
	// if neg, this is the length of whitespace and comments between
	// the minus sign and the rest fo the number literal
	sep int
}

func ( number) ( []byte) string {
	 := .size
	 := .size - 1
	if .kind == numFloat && ([] == 'f' || [] == 'F') {
		 = 
	}
	if .neg && .sep > 0 {
		// strip whitespace/comments between negative sign and the rest
		 :=  - .sep
		 := make([]byte, )
		[0] = [0]
		copy([1:], [.sep+1:])
		return string()
	}
	return string([:])

}

// parseNumber constructs a number object from given input. It allows for the
// following patterns:
//
//	integer: ^-?([1-9][0-9]*|0[xX][0-9a-fA-F]+|0[0-7]*)
//	float: ^-?((0|[1-9][0-9]*)?([.][0-9]*)?([eE][+-]?[0-9]+)?[fF]?)
//
// It also returns the number of parsed bytes for the given number, 0 if it is
// not a number.
func ( []byte) number {
	 := numDec
	var  int
	var  bool

	 := 
	if len() == 0 {
		return number{}
	}

	// Optional -
	var  int
	if [0] == '-' {
		 = true
		 = [1:]
		++
		// Consume any whitespace or comments between the
		// negative sign and the rest of the number
		 := len()
		 = consume(, 0)
		 =  - len()
		 += 
		if len() == 0 {
			return number{}
		}
	}

	switch {
	case [0] == '0':
		if len() > 1 {
			switch {
			case [1] == 'x' || [1] == 'X':
				// Parse as hex number.
				 = numHex
				 := 2
				 = [2:]
				for len() > 0 && (('0' <= [0] && [0] <= '9') ||
					('a' <= [0] && [0] <= 'f') ||
					('A' <= [0] && [0] <= 'F')) {
					 = [1:]
					++
				}
				if  == 2 {
					return number{}
				}
				 += 

			case '0' <= [1] && [1] <= '7':
				// Parse as octal number.
				 = numOct
				 := 2
				 = [2:]
				for len() > 0 && '0' <= [0] && [0] <= '7' {
					 = [1:]
					++
				}
				 += 
			}

			if &(numHex|numOct) > 0 {
				if len() > 0 && !isDelim([0]) {
					return number{}
				}
				return number{kind: , neg: , size: , sep: }
			}
		}
		 = [1:]
		++

	case '1' <= [0] && [0] <= '9':
		 := 1
		 = [1:]
		for len() > 0 && '0' <= [0] && [0] <= '9' {
			 = [1:]
			++
		}
		 += 

	case [0] == '.':
		// Set kind to numFloat to signify the intent to parse as float. And
		// that it needs to have other digits after '.'.
		 = numFloat

	default:
		return number{}
	}

	// . followed by 0 or more digits.
	if len() > 0 && [0] == '.' {
		 := 1
		 = [1:]
		// If decimal point was before any digits, it should be followed by
		// other digits.
		if len() == 0 &&  == numFloat {
			return number{}
		}
		for len() > 0 && '0' <= [0] && [0] <= '9' {
			 = [1:]
			++
		}
		 += 
		 = numFloat
	}

	// e or E followed by an optional - or + and 1 or more digits.
	if len() >= 2 && ([0] == 'e' || [0] == 'E') {
		 = numFloat
		 = [1:]
		 := 1
		if [0] == '+' || [0] == '-' {
			 = [1:]
			++
			if len() == 0 {
				return number{}
			}
		}
		for len() > 0 && '0' <= [0] && [0] <= '9' {
			 = [1:]
			++
		}
		 += 
	}

	// Optional suffix f or F for floats.
	if len() > 0 && ([0] == 'f' || [0] == 'F') {
		 = numFloat
		 = [1:]
		++
	}

	// Check that next byte is a delimiter or it is at the end.
	if len() > 0 && !isDelim([0]) {
		return number{}
	}

	return number{kind: , neg: , size: , sep: }
}