vendor/google.golang.org/protobuf/internal/encoding/text/decode_number.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
       
     1 // Copyright 2018 The Go Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style
       
     3 // license that can be found in the LICENSE file.
       
     4 
       
     5 package text
       
     6 
       
     7 // parseNumberValue parses a number from the input and returns a Token object.
       
     8 func (d *Decoder) parseNumberValue() (Token, bool) {
       
     9 	in := d.in
       
    10 	num := parseNumber(in)
       
    11 	if num.size == 0 {
       
    12 		return Token{}, false
       
    13 	}
       
    14 	numAttrs := num.kind
       
    15 	if num.neg {
       
    16 		numAttrs |= isNegative
       
    17 	}
       
    18 	strSize := num.size
       
    19 	last := num.size - 1
       
    20 	if num.kind == numFloat && (d.in[last] == 'f' || d.in[last] == 'F') {
       
    21 		strSize = last
       
    22 	}
       
    23 	tok := Token{
       
    24 		kind:     Scalar,
       
    25 		attrs:    numberValue,
       
    26 		pos:      len(d.orig) - len(d.in),
       
    27 		raw:      d.in[:num.size],
       
    28 		str:      string(d.in[:strSize]),
       
    29 		numAttrs: numAttrs,
       
    30 	}
       
    31 	d.consume(num.size)
       
    32 	return tok, true
       
    33 }
       
    34 
       
    35 const (
       
    36 	numDec uint8 = (1 << iota) / 2
       
    37 	numHex
       
    38 	numOct
       
    39 	numFloat
       
    40 )
       
    41 
       
    42 // number is the result of parsing out a valid number from parseNumber. It
       
    43 // contains data for doing float or integer conversion via the strconv package
       
    44 // in conjunction with the input bytes.
       
    45 type number struct {
       
    46 	kind uint8
       
    47 	neg  bool
       
    48 	size int
       
    49 }
       
    50 
       
    51 // parseNumber constructs a number object from given input. It allows for the
       
    52 // following patterns:
       
    53 //   integer: ^-?([1-9][0-9]*|0[xX][0-9a-fA-F]+|0[0-7]*)
       
    54 //   float: ^-?((0|[1-9][0-9]*)?([.][0-9]*)?([eE][+-]?[0-9]+)?[fF]?)
       
    55 // It also returns the number of parsed bytes for the given number, 0 if it is
       
    56 // not a number.
       
    57 func parseNumber(input []byte) number {
       
    58 	kind := numDec
       
    59 	var size int
       
    60 	var neg bool
       
    61 
       
    62 	s := input
       
    63 	if len(s) == 0 {
       
    64 		return number{}
       
    65 	}
       
    66 
       
    67 	// Optional -
       
    68 	if s[0] == '-' {
       
    69 		neg = true
       
    70 		s = s[1:]
       
    71 		size++
       
    72 		if len(s) == 0 {
       
    73 			return number{}
       
    74 		}
       
    75 	}
       
    76 
       
    77 	// C++ allows for whitespace and comments in between the negative sign and
       
    78 	// the rest of the number. This logic currently does not but is consistent
       
    79 	// with v1.
       
    80 
       
    81 	switch {
       
    82 	case s[0] == '0':
       
    83 		if len(s) > 1 {
       
    84 			switch {
       
    85 			case s[1] == 'x' || s[1] == 'X':
       
    86 				// Parse as hex number.
       
    87 				kind = numHex
       
    88 				n := 2
       
    89 				s = s[2:]
       
    90 				for len(s) > 0 && (('0' <= s[0] && s[0] <= '9') ||
       
    91 					('a' <= s[0] && s[0] <= 'f') ||
       
    92 					('A' <= s[0] && s[0] <= 'F')) {
       
    93 					s = s[1:]
       
    94 					n++
       
    95 				}
       
    96 				if n == 2 {
       
    97 					return number{}
       
    98 				}
       
    99 				size += n
       
   100 
       
   101 			case '0' <= s[1] && s[1] <= '7':
       
   102 				// Parse as octal number.
       
   103 				kind = numOct
       
   104 				n := 2
       
   105 				s = s[2:]
       
   106 				for len(s) > 0 && '0' <= s[0] && s[0] <= '7' {
       
   107 					s = s[1:]
       
   108 					n++
       
   109 				}
       
   110 				size += n
       
   111 			}
       
   112 
       
   113 			if kind&(numHex|numOct) > 0 {
       
   114 				if len(s) > 0 && !isDelim(s[0]) {
       
   115 					return number{}
       
   116 				}
       
   117 				return number{kind: kind, neg: neg, size: size}
       
   118 			}
       
   119 		}
       
   120 		s = s[1:]
       
   121 		size++
       
   122 
       
   123 	case '1' <= s[0] && s[0] <= '9':
       
   124 		n := 1
       
   125 		s = s[1:]
       
   126 		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
       
   127 			s = s[1:]
       
   128 			n++
       
   129 		}
       
   130 		size += n
       
   131 
       
   132 	case s[0] == '.':
       
   133 		// Set kind to numFloat to signify the intent to parse as float. And
       
   134 		// that it needs to have other digits after '.'.
       
   135 		kind = numFloat
       
   136 
       
   137 	default:
       
   138 		return number{}
       
   139 	}
       
   140 
       
   141 	// . followed by 0 or more digits.
       
   142 	if len(s) > 0 && s[0] == '.' {
       
   143 		n := 1
       
   144 		s = s[1:]
       
   145 		// If decimal point was before any digits, it should be followed by
       
   146 		// other digits.
       
   147 		if len(s) == 0 && kind == numFloat {
       
   148 			return number{}
       
   149 		}
       
   150 		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
       
   151 			s = s[1:]
       
   152 			n++
       
   153 		}
       
   154 		size += n
       
   155 		kind = numFloat
       
   156 	}
       
   157 
       
   158 	// e or E followed by an optional - or + and 1 or more digits.
       
   159 	if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
       
   160 		kind = numFloat
       
   161 		s = s[1:]
       
   162 		n := 1
       
   163 		if s[0] == '+' || s[0] == '-' {
       
   164 			s = s[1:]
       
   165 			n++
       
   166 			if len(s) == 0 {
       
   167 				return number{}
       
   168 			}
       
   169 		}
       
   170 		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
       
   171 			s = s[1:]
       
   172 			n++
       
   173 		}
       
   174 		size += n
       
   175 	}
       
   176 
       
   177 	// Optional suffix f or F for floats.
       
   178 	if len(s) > 0 && (s[0] == 'f' || s[0] == 'F') {
       
   179 		kind = numFloat
       
   180 		s = s[1:]
       
   181 		size++
       
   182 	}
       
   183 
       
   184 	// Check that next byte is a delimiter or it is at the end.
       
   185 	if len(s) > 0 && !isDelim(s[0]) {
       
   186 		return number{}
       
   187 	}
       
   188 
       
   189 	return number{kind: kind, neg: neg, size: size}
       
   190 }