mirror of
https://github.com/antonmedv/fx.git
synced 2024-09-11 18:27:10 +03:00
199 lines
2.9 KiB
Go
199 lines
2.9 KiB
Go
package path
|
|
|
|
import (
|
|
"regexp"
|
|
"strconv"
|
|
"unicode"
|
|
)
|
|
|
|
type state int
|
|
|
|
const (
|
|
start state = iota
|
|
unknown
|
|
propOrIndex
|
|
prop
|
|
index
|
|
indexEnd
|
|
number
|
|
doubleQuote
|
|
doubleQuoteEscape
|
|
singleQuote
|
|
singleQuoteEscape
|
|
)
|
|
|
|
func Split(p string) ([]any, bool) {
|
|
path := make([]any, 0)
|
|
s := ""
|
|
state := start
|
|
for _, ch := range p {
|
|
switch state {
|
|
|
|
case start:
|
|
switch {
|
|
case ch == 'x':
|
|
state = unknown
|
|
case ch == '.':
|
|
state = propOrIndex
|
|
case ch == '[':
|
|
state = index
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case unknown:
|
|
switch {
|
|
case ch == '.':
|
|
state = prop
|
|
s = ""
|
|
case ch == '[':
|
|
state = index
|
|
s = ""
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case propOrIndex:
|
|
switch {
|
|
case isProp(ch):
|
|
state = prop
|
|
s = string(ch)
|
|
case ch == '[':
|
|
state = index
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case prop:
|
|
switch {
|
|
case isProp(ch):
|
|
s += string(ch)
|
|
case ch == '.':
|
|
state = prop
|
|
path = append(path, s)
|
|
s = ""
|
|
case ch == '[':
|
|
state = index
|
|
path = append(path, s)
|
|
s = ""
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case index:
|
|
switch {
|
|
case unicode.IsDigit(ch):
|
|
state = number
|
|
s = string(ch)
|
|
case ch == '"':
|
|
state = doubleQuote
|
|
s = ""
|
|
case ch == '\'':
|
|
state = singleQuote
|
|
s = ""
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case indexEnd:
|
|
switch {
|
|
case ch == ']':
|
|
state = unknown
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case number:
|
|
switch {
|
|
case unicode.IsDigit(ch):
|
|
s += string(ch)
|
|
case ch == ']':
|
|
state = unknown
|
|
n, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return path, false
|
|
}
|
|
path = append(path, n)
|
|
s = ""
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case doubleQuote:
|
|
switch ch {
|
|
case '"':
|
|
state = indexEnd
|
|
path = append(path, s)
|
|
s = ""
|
|
case '\\':
|
|
state = doubleQuoteEscape
|
|
default:
|
|
s += string(ch)
|
|
}
|
|
|
|
case doubleQuoteEscape:
|
|
switch ch {
|
|
case '"':
|
|
state = doubleQuote
|
|
s += string(ch)
|
|
default:
|
|
return path, false
|
|
}
|
|
|
|
case singleQuote:
|
|
switch ch {
|
|
case '\'':
|
|
state = indexEnd
|
|
path = append(path, s)
|
|
s = ""
|
|
case '\\':
|
|
state = singleQuoteEscape
|
|
s += string(ch)
|
|
default:
|
|
s += string(ch)
|
|
}
|
|
|
|
case singleQuoteEscape:
|
|
switch ch {
|
|
case '\'':
|
|
state = singleQuote
|
|
s += string(ch)
|
|
default:
|
|
return path, false
|
|
}
|
|
}
|
|
}
|
|
if len(s) > 0 {
|
|
if state == prop {
|
|
path = append(path, s)
|
|
} else {
|
|
return path, false
|
|
}
|
|
|
|
}
|
|
return path, true
|
|
}
|
|
|
|
func isProp(ch rune) bool {
|
|
return unicode.IsLetter(ch) || unicode.IsDigit(ch) || ch == '_' || ch == '$'
|
|
}
|
|
|
|
var Identifier = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
|
|
|
func Join(path []any) string {
|
|
s := ""
|
|
for _, v := range path {
|
|
switch v := v.(type) {
|
|
case string:
|
|
if Identifier.MatchString(v) {
|
|
s += "." + v
|
|
} else {
|
|
s += "[" + strconv.Quote(v) + "]"
|
|
}
|
|
case int:
|
|
s += "[" + strconv.Itoa(v) + "]"
|
|
}
|
|
}
|
|
return s
|
|
}
|