forked from Archives/fx
179 lines
2.7 KiB
Go
179 lines
2.7 KiB
Go
package reducer
|
|
|
|
import (
|
|
"strconv"
|
|
"unicode"
|
|
)
|
|
|
|
type state int
|
|
|
|
const (
|
|
start state = iota
|
|
unknown
|
|
propOrIndex
|
|
prop
|
|
index
|
|
indexEnd
|
|
number
|
|
doubleQuote
|
|
doubleQuoteEscape
|
|
singleQuote
|
|
singleQuoteEscape
|
|
)
|
|
|
|
func split(args []string) ([]interface{}, bool) {
|
|
path := make([]interface{}, 0)
|
|
for _, arg := range args {
|
|
s := ""
|
|
state := start
|
|
for _, ch := range arg {
|
|
switch state {
|
|
|
|
case start:
|
|
switch {
|
|
case ch == 'x':
|
|
state = unknown
|
|
case ch == '.':
|
|
state = propOrIndex
|
|
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 == '$'
|
|
}
|