2019-05-01 09:23:05 +00:00
|
|
|
package builtin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
|
2019-05-01 09:28:55 +00:00
|
|
|
"git.xdrm.io/go/aicra/typecheck"
|
2019-05-01 09:23:05 +00:00
|
|
|
)
|
|
|
|
|
2019-05-01 13:14:49 +00:00
|
|
|
var fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`)
|
2019-05-01 09:23:05 +00:00
|
|
|
var variableLengthRegex = regexp.MustCompile(`^string\((\d+), ?(\d+)\)$`)
|
|
|
|
|
|
|
|
// String checks if a value is a string
|
|
|
|
type String struct{}
|
|
|
|
|
|
|
|
// NewString returns a bare string type checker
|
|
|
|
func NewString() *String {
|
|
|
|
return &String{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checker returns the checker function. Availables type names are : `string`, `string(length)` and `string(minLength, maxLength)`.
|
2019-05-02 20:15:03 +00:00
|
|
|
func (s String) Checker(typeName string) typecheck.CheckerFunc {
|
2019-05-01 09:23:05 +00:00
|
|
|
isSimpleString := typeName == "string"
|
|
|
|
fixedLengthMatches := fixedLengthRegex.FindStringSubmatch(typeName)
|
|
|
|
variableLengthMatches := variableLengthRegex.FindStringSubmatch(typeName)
|
|
|
|
|
|
|
|
// nothing if type not handled
|
|
|
|
if !isSimpleString && fixedLengthMatches == nil && variableLengthMatches == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-05-03 18:09:04 +00:00
|
|
|
var (
|
|
|
|
mustFail bool
|
|
|
|
min, max int
|
|
|
|
)
|
|
|
|
|
|
|
|
// extract fixed length
|
|
|
|
if fixedLengthMatches != nil {
|
|
|
|
exLen, ok := s.getFixedLength(fixedLengthMatches)
|
|
|
|
if !ok {
|
|
|
|
mustFail = true
|
|
|
|
}
|
|
|
|
min = exLen
|
|
|
|
max = exLen
|
|
|
|
|
|
|
|
// extract variable length
|
|
|
|
} else if variableLengthMatches != nil {
|
|
|
|
exMin, exMax, ok := s.getVariableLength(variableLengthMatches)
|
|
|
|
if !ok {
|
|
|
|
mustFail = true
|
|
|
|
}
|
|
|
|
min = exMin
|
|
|
|
max = exMax
|
|
|
|
}
|
|
|
|
|
2019-05-01 09:23:05 +00:00
|
|
|
return func(value interface{}) bool {
|
2019-05-03 18:09:04 +00:00
|
|
|
// preprocessing error
|
|
|
|
if mustFail {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-05-01 09:23:05 +00:00
|
|
|
// check type
|
|
|
|
strValue, isString := value.(string)
|
2019-11-18 15:17:02 +00:00
|
|
|
byteSliceValue, isByteSlice := value.([]byte)
|
|
|
|
if !isString && isByteSlice {
|
|
|
|
strValue = string(byteSliceValue)
|
|
|
|
isString = true
|
|
|
|
}
|
|
|
|
|
2019-05-01 09:23:05 +00:00
|
|
|
if !isString {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-05-03 18:09:04 +00:00
|
|
|
if isSimpleString {
|
|
|
|
return true
|
2019-05-01 09:23:05 +00:00
|
|
|
}
|
|
|
|
|
2019-05-03 18:09:04 +00:00
|
|
|
// check length against previously extracted length
|
|
|
|
l := len(strValue)
|
|
|
|
return l >= min && l <= max
|
2019-05-01 09:23:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// getFixedLength returns the fixed length from regex matches and a success state.
|
|
|
|
func (String) getFixedLength(regexMatches []string) (int, bool) {
|
|
|
|
// incoherence error
|
|
|
|
if regexMatches == nil || len(regexMatches) < 2 {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract length
|
2019-05-03 18:09:04 +00:00
|
|
|
fixedLength, err := strconv.ParseInt(regexMatches[1], 10, 64)
|
|
|
|
if err != nil || fixedLength < 0 {
|
2019-05-01 09:23:05 +00:00
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(fixedLength), true
|
|
|
|
}
|
|
|
|
|
|
|
|
// getVariableLength returns the length min and max from regex matches and a success state.
|
|
|
|
func (String) getVariableLength(regexMatches []string) (int, int, bool) {
|
|
|
|
// incoherence error
|
|
|
|
if regexMatches == nil || len(regexMatches) < 3 {
|
|
|
|
return 0, 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract minimum length
|
2019-05-03 18:09:04 +00:00
|
|
|
minLen, err := strconv.ParseInt(regexMatches[1], 10, 64)
|
|
|
|
if err != nil || minLen < 0 {
|
2019-05-01 09:23:05 +00:00
|
|
|
return 0, 0, false
|
|
|
|
}
|
|
|
|
// extract maximum length
|
2019-05-03 18:09:04 +00:00
|
|
|
maxLen, err := strconv.ParseInt(regexMatches[2], 10, 64)
|
|
|
|
if err != nil || maxLen < 0 {
|
2019-05-01 09:23:05 +00:00
|
|
|
return 0, 0, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(minLen), int(maxLen), true
|
|
|
|
}
|