miller/pkg/scan/find.go
John Kerl 268a96d002
Export library code in pkg/ (#1391)
* Export library code in `pkg/`

* new doc page
2023-09-10 17:15:13 -04:00

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
}