mirror of
https://github.com/go-gitea/gitea.git
synced 2024-08-25 05:37:29 +02:00
191 lines
3.9 KiB
Go
Vendored
191 lines
3.9 KiB
Go
Vendored
// 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 (d *Decoder) parseNumberValue() (Token, bool) {
|
|
in := d.in
|
|
num := parseNumber(in)
|
|
if num.size == 0 {
|
|
return Token{}, false
|
|
}
|
|
numAttrs := num.kind
|
|
if num.neg {
|
|
numAttrs |= isNegative
|
|
}
|
|
strSize := num.size
|
|
last := num.size - 1
|
|
if num.kind == numFloat && (d.in[last] == 'f' || d.in[last] == 'F') {
|
|
strSize = last
|
|
}
|
|
tok := Token{
|
|
kind: Scalar,
|
|
attrs: numberValue,
|
|
pos: len(d.orig) - len(d.in),
|
|
raw: d.in[:num.size],
|
|
str: string(d.in[:strSize]),
|
|
numAttrs: numAttrs,
|
|
}
|
|
d.consume(num.size)
|
|
return tok, 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 parseNumber(input []byte) number {
|
|
kind := numDec
|
|
var size int
|
|
var neg bool
|
|
|
|
s := input
|
|
if len(s) == 0 {
|
|
return number{}
|
|
}
|
|
|
|
// Optional -
|
|
if s[0] == '-' {
|
|
neg = true
|
|
s = s[1:]
|
|
size++
|
|
if len(s) == 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 s[0] == '0':
|
|
if len(s) > 1 {
|
|
switch {
|
|
case s[1] == 'x' || s[1] == 'X':
|
|
// Parse as hex number.
|
|
kind = numHex
|
|
n := 2
|
|
s = s[2:]
|
|
for len(s) > 0 && (('0' <= s[0] && s[0] <= '9') ||
|
|
('a' <= s[0] && s[0] <= 'f') ||
|
|
('A' <= s[0] && s[0] <= 'F')) {
|
|
s = s[1:]
|
|
n++
|
|
}
|
|
if n == 2 {
|
|
return number{}
|
|
}
|
|
size += n
|
|
|
|
case '0' <= s[1] && s[1] <= '7':
|
|
// Parse as octal number.
|
|
kind = numOct
|
|
n := 2
|
|
s = s[2:]
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '7' {
|
|
s = s[1:]
|
|
n++
|
|
}
|
|
size += n
|
|
}
|
|
|
|
if kind&(numHex|numOct) > 0 {
|
|
if len(s) > 0 && !isDelim(s[0]) {
|
|
return number{}
|
|
}
|
|
return number{kind: kind, neg: neg, size: size}
|
|
}
|
|
}
|
|
s = s[1:]
|
|
size++
|
|
|
|
case '1' <= s[0] && s[0] <= '9':
|
|
n := 1
|
|
s = s[1:]
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
|
s = s[1:]
|
|
n++
|
|
}
|
|
size += n
|
|
|
|
case s[0] == '.':
|
|
// Set kind to numFloat to signify the intent to parse as float. And
|
|
// that it needs to have other digits after '.'.
|
|
kind = numFloat
|
|
|
|
default:
|
|
return number{}
|
|
}
|
|
|
|
// . followed by 0 or more digits.
|
|
if len(s) > 0 && s[0] == '.' {
|
|
n := 1
|
|
s = s[1:]
|
|
// If decimal point was before any digits, it should be followed by
|
|
// other digits.
|
|
if len(s) == 0 && kind == numFloat {
|
|
return number{}
|
|
}
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
|
s = s[1:]
|
|
n++
|
|
}
|
|
size += n
|
|
kind = numFloat
|
|
}
|
|
|
|
// e or E followed by an optional - or + and 1 or more digits.
|
|
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
|
|
kind = numFloat
|
|
s = s[1:]
|
|
n := 1
|
|
if s[0] == '+' || s[0] == '-' {
|
|
s = s[1:]
|
|
n++
|
|
if len(s) == 0 {
|
|
return number{}
|
|
}
|
|
}
|
|
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
|
|
s = s[1:]
|
|
n++
|
|
}
|
|
size += n
|
|
}
|
|
|
|
// Optional suffix f or F for floats.
|
|
if len(s) > 0 && (s[0] == 'f' || s[0] == 'F') {
|
|
kind = numFloat
|
|
s = s[1:]
|
|
size++
|
|
}
|
|
|
|
// Check that next byte is a delimiter or it is at the end.
|
|
if len(s) > 0 && !isDelim(s[0]) {
|
|
return number{}
|
|
}
|
|
|
|
return number{kind: kind, neg: neg, size: size}
|
|
}
|