// 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
	}
	 := .size
	 := .size - 1
	if .kind == numFloat && (.in[] == 'f' || .in[] == 'F') {
		 = 
	}
	 := 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
}

// 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 -
	if [0] == '-' {
		 = true
		 = [1:]
		++
		if len() == 0 {
			return number{}
		}
	}

	// C++ allows for whitespace and comments in between the negative sign and
	// the rest of the number. This logic currently does not but is consistent
	// with v1.

	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: }
			}
		}
		 = [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: }
}