mirror of
https://github.com/johnkerl/miller.git
synced 2026-01-23 02:14:13 +00:00
185 lines
3.9 KiB
Go
185 lines
3.9 KiB
Go
package scan
|
|
|
|
import ()
|
|
|
|
// TODO: comment re context
|
|
|
|
// o grammar for numbers & case-through
|
|
// k len 0
|
|
// - len 1
|
|
// k has leading minus; strip & rest
|
|
// - 0x, 0b, 0[0-9]
|
|
// - decimal: leading minus; [0-9]+
|
|
// - octal: leading minus; 0[0-7]+
|
|
// - hex: leading minus; 0[xX][0-9a-fA-F]+
|
|
// - float: leadinug minus; [0-9] or '.'
|
|
//
|
|
// o float literals:
|
|
// 123 123. 123.4 .234
|
|
// 1e2 1e-2 1.2e3 1.e3 1.2e-3 1.e-3
|
|
// .2e3 .2e-3 1.e-3
|
|
//
|
|
// ?- [0-9]+
|
|
// ?- [0-9]+ '.' [0-9]*
|
|
// ?- [0-9]* '.' [0-9]+
|
|
// ?- [0-9]+ [eE] ?- [0-9]+
|
|
// ?- [0-9]+ '.' [0-9]* [eE] ?- [0-9]+
|
|
// ?- [0-9]* '.' [0-9]+ [eE] ?- [0-9]+
|
|
|
|
func FindScanType(sinput string) ScanType {
|
|
input := []byte(sinput)
|
|
|
|
if len(input) == 0 {
|
|
return scanTypeString
|
|
}
|
|
|
|
i0 := input[0]
|
|
if i0 == '-' {
|
|
return findScanTypePositiveNumberOrString(input[1:])
|
|
}
|
|
if i0 == '+' {
|
|
return findScanTypePositiveNumberOrString(input[1:])
|
|
}
|
|
if i0 >= '0' && i0 <= '9' {
|
|
return findScanTypePositiveNumberOrString(input)
|
|
}
|
|
if i0 == '.' {
|
|
if len(input) == 1 {
|
|
return scanTypeString
|
|
} else {
|
|
return findScanTypePositiveDecimalOrFloatOrString(input)
|
|
}
|
|
}
|
|
|
|
return scanTypeString
|
|
}
|
|
|
|
// Convenience function for unit test
|
|
func findScanTypeName(sinput string) string {
|
|
return TypeNames[FindScanType(sinput)]
|
|
}
|
|
|
|
func findScanTypePositiveNumberOrString(input []byte) ScanType {
|
|
if len(input) == 0 {
|
|
return scanTypeString
|
|
}
|
|
i0 := input[0]
|
|
|
|
if i0 == '.' {
|
|
return findScanTypePositiveFloatOrString(input)
|
|
}
|
|
|
|
if isDecimalDigit(i0) {
|
|
if len(input) == 1 {
|
|
return scanTypeDecimalInt
|
|
}
|
|
if i0 == '0' {
|
|
i1 := input[1]
|
|
if i1 == 'x' || i1 == 'X' {
|
|
if len(input) == 2 {
|
|
return scanTypeString
|
|
} else {
|
|
return findScanTypePositiveHexOrString(input[2:])
|
|
}
|
|
}
|
|
if i1 == 'o' || i1 == 'O' {
|
|
if len(input) == 2 {
|
|
return scanTypeString
|
|
} else {
|
|
return findScanTypePositiveOctalOrString(input[2:])
|
|
}
|
|
}
|
|
if i1 == 'b' || i1 == 'B' {
|
|
if len(input) == 2 {
|
|
return scanTypeString
|
|
} else {
|
|
return findScanTypePositiveBinaryOrString(input[2:])
|
|
}
|
|
}
|
|
|
|
allOctal := true
|
|
allDecimal := true
|
|
for _, c := range input[1:] {
|
|
if !isOctalDigit(c) {
|
|
allOctal = false
|
|
}
|
|
if !isDecimalDigit(c) {
|
|
allDecimal = false
|
|
break
|
|
}
|
|
}
|
|
if allOctal {
|
|
return scanTypeLeadingZeroOctalInt
|
|
}
|
|
if allDecimal {
|
|
return scanTypeLeadingZeroDecimalInt
|
|
}
|
|
// else fall through
|
|
}
|
|
|
|
return findScanTypePositiveDecimalOrFloatOrString(input)
|
|
}
|
|
|
|
return scanTypeString
|
|
}
|
|
|
|
func findScanTypePositiveFloatOrString(input []byte) ScanType {
|
|
for _, c := range []byte(input) {
|
|
if !isFloatDigit(c) {
|
|
return scanTypeString
|
|
}
|
|
}
|
|
return scanTypeMaybeFloat
|
|
}
|
|
|
|
func findScanTypePositiveDecimalOrFloatOrString(input []byte) ScanType {
|
|
maybeInt := true
|
|
for _, c := range []byte(input) {
|
|
// All float digits are decimal-int digits so if the current character
|
|
// is not a float digit, this can't be either a float or a decimal int.
|
|
// Example: "1x2"
|
|
if !isFloatDigit(c) {
|
|
return scanTypeString
|
|
}
|
|
|
|
// Examples: "1e2" or "1x2".
|
|
if !isDecimalDigit(c) {
|
|
maybeInt = false
|
|
}
|
|
}
|
|
if maybeInt {
|
|
return scanTypeDecimalInt
|
|
} else {
|
|
return scanTypeMaybeFloat
|
|
}
|
|
}
|
|
|
|
// Leading 0o has already been stripped
|
|
func findScanTypePositiveOctalOrString(input []byte) ScanType {
|
|
for _, c := range []byte(input) {
|
|
if !isOctalDigit(c) {
|
|
return scanTypeString
|
|
}
|
|
}
|
|
return scanTypeOctalInt
|
|
}
|
|
|
|
// Leading 0x has already been stripped
|
|
func findScanTypePositiveHexOrString(input []byte) ScanType {
|
|
for _, c := range []byte(input) {
|
|
if !isHexDigit(c) {
|
|
return scanTypeString
|
|
}
|
|
}
|
|
return scanTypeHexInt
|
|
}
|
|
|
|
// Leading 0b has already been stripped
|
|
func findScanTypePositiveBinaryOrString(input []byte) ScanType {
|
|
for _, c := range []byte(input) {
|
|
if c < '0' || c > '1' {
|
|
return scanTypeString
|
|
}
|
|
}
|
|
return scanTypeBinaryInt
|
|
}
|