package docopt import ( "regexp" "strings" "unicode" ) type tokenList struct { tokens []string errorFunc func(string, ...interface{}) error err errorType } type token string func newTokenList(source []string, err errorType) *tokenList { errorFunc := newError if err == errorUser { errorFunc = newUserError } else if err == errorLanguage { errorFunc = newLanguageError } return &tokenList{source, errorFunc, err} } func tokenListFromString(source string) *tokenList { return newTokenList(strings.Fields(source), errorUser) } func tokenListFromPattern(source string) *tokenList { p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`) source = p.ReplaceAllString(source, ` $1 `) p = regexp.MustCompile(`\s+|(\S*<.*?>)`) split := p.Split(source, -1) match := p.FindAllStringSubmatch(source, -1) var result []string l := len(split) for i := 0; i < l; i++ { if len(split[i]) > 0 { result = append(result, split[i]) } if i < l-1 && len(match[i][1]) > 0 { result = append(result, match[i][1]) } } return newTokenList(result, errorLanguage) } func (t *token) eq(s string) bool { if t == nil { return false } return string(*t) == s } func (t *token) match(matchNil bool, tokenStrings ...string) bool { if t == nil && matchNil { return true } else if t == nil && !matchNil { return false } for _, tok := range tokenStrings { if tok == string(*t) { return true } } return false } func (t *token) hasPrefix(prefix string) bool { if t == nil { return false } return strings.HasPrefix(string(*t), prefix) } func (t *token) hasSuffix(suffix string) bool { if t == nil { return false } return strings.HasSuffix(string(*t), suffix) } func (t *token) isUpper() bool { if t == nil { return false } return isStringUppercase(string(*t)) } func (t *token) String() string { if t == nil { return "" } return string(*t) } func (tl *tokenList) current() *token { if len(tl.tokens) > 0 { return (*token)(&(tl.tokens[0])) } return nil } func (tl *tokenList) length() int { return len(tl.tokens) } func (tl *tokenList) move() *token { if len(tl.tokens) > 0 { t := tl.tokens[0] tl.tokens = tl.tokens[1:] return (*token)(&t) } return nil } // returns true if all cased characters in the string are uppercase // and there are there is at least one cased charcter func isStringUppercase(s string) bool { if strings.ToUpper(s) != s { return false } for _, c := range []rune(s) { if unicode.IsUpper(c) { return true } } return false }