Scan List and Array
This commit is contained in:
@ -37,7 +37,10 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
scanContinue = iota // uninteresting byte
|
scanContinue = iota // uninteresting byte
|
||||||
scanBeginCompound // begin compound (after left-brace )
|
scanBeginCompound // begin TAG_Compound (after left-brace )
|
||||||
|
scanBeginList // begin TAG_List (after left-brack)
|
||||||
|
scanListValue // just finished read list value
|
||||||
|
scanListType // just finished read list type (after "B;" or "L;")
|
||||||
scanCompoundTagName // just finished read tag name (before colon)
|
scanCompoundTagName // just finished read tag name (before colon)
|
||||||
scanCompoundValue // just finished read value (before comma or right-brace )
|
scanCompoundValue // just finished read value (before comma or right-brace )
|
||||||
scanSkipSpace // space byte; can skip; known to be last "continue" result
|
scanSkipSpace // space byte; can skip; known to be last "continue" result
|
||||||
@ -86,7 +89,7 @@ func (s *scanner) pushParseState(c byte, newParseState int, successState int) in
|
|||||||
// and updates s.step accordingly.
|
// and updates s.step accordingly.
|
||||||
func (s *scanner) popParseState() {
|
func (s *scanner) popParseState() {
|
||||||
n := len(s.parseState) - 1
|
n := len(s.parseState) - 1
|
||||||
s.parseState = s.parseState[0:n]
|
s.parseState = s.parseState[:n]
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
s.step = s.stateEndTop
|
s.step = s.stateEndTop
|
||||||
//s.endTop = true
|
//s.endTop = true
|
||||||
@ -108,6 +111,7 @@ func (s *scanner) stateEndTop(c byte) int {
|
|||||||
|
|
||||||
func (s *scanner) stateBeginValue(c byte) int {
|
func (s *scanner) stateBeginValue(c byte) int {
|
||||||
if isSpace(c) {
|
if isSpace(c) {
|
||||||
|
s.step = s.stateBeginValue
|
||||||
return scanSkipSpace
|
return scanSkipSpace
|
||||||
}
|
}
|
||||||
switch c {
|
switch c {
|
||||||
@ -115,17 +119,19 @@ func (s *scanner) stateBeginValue(c byte) int {
|
|||||||
s.step = s.stateCompoundOrEmpty
|
s.step = s.stateCompoundOrEmpty
|
||||||
return s.pushParseState(c, parseCompoundName, scanBeginCompound)
|
return s.pushParseState(c, parseCompoundName, scanBeginCompound)
|
||||||
case '[': // beginning of TAG_List
|
case '[': // beginning of TAG_List
|
||||||
s.step = s.stateList
|
s.step = s.stateListOrArray
|
||||||
|
return s.pushParseState(c, parseListValue, scanBeginList)
|
||||||
case '"', '\'': // beginning of TAG_String
|
case '"', '\'': // beginning of TAG_String
|
||||||
s.step = s.stateBeginString
|
return s.stateBeginString(c)
|
||||||
return scanContinue
|
|
||||||
case '-': // beginning of negative number
|
case '-': // beginning of negative number
|
||||||
s.step = s.stateNeg
|
s.step = s.stateNeg
|
||||||
return scanContinue
|
return scanContinue
|
||||||
default:
|
default:
|
||||||
if isNumber(c) {
|
if isNumber(c) {
|
||||||
s.step = s.stateNum1
|
return s.stateNum1(c)
|
||||||
return scanContinue
|
}
|
||||||
|
if isNumOrLetter(c) {
|
||||||
|
return s.stateBeginString(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.error(c, "looking for beginning of value")
|
return s.error(c, "looking for beginning of value")
|
||||||
@ -144,6 +150,9 @@ func (s *scanner) stateCompoundOrEmpty(c byte) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) stateBeginString(c byte) int {
|
func (s *scanner) stateBeginString(c byte) int {
|
||||||
|
if isSpace(c) {
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
switch c {
|
switch c {
|
||||||
case '\'':
|
case '\'':
|
||||||
s.step = s.stateInSqString
|
s.step = s.stateInSqString
|
||||||
@ -157,7 +166,7 @@ func (s *scanner) stateBeginString(c byte) int {
|
|||||||
return scanContinue
|
return scanContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.error(c, "looking for beginning of tag name string")
|
return s.error(c, "looking for beginning of string")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) stateInSqString(c byte) int {
|
func (s *scanner) stateInSqString(c byte) int {
|
||||||
@ -215,8 +224,27 @@ func (s *scanner) stateInPureString(c byte) int {
|
|||||||
return s.stateEndValue(c)
|
return s.stateEndValue(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) stateList(c byte) int {
|
func (s *scanner) stateListOrArray(c byte) int {
|
||||||
return s.error(c, "not implemented")
|
if isSpace(c) {
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case 'B', 'I', 'L':
|
||||||
|
s.step = s.stateListOrArrayT
|
||||||
|
return scanContinue
|
||||||
|
case ']':
|
||||||
|
return s.stateEndValue(c)
|
||||||
|
default:
|
||||||
|
return s.stateBeginValue(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *scanner) stateListOrArrayT(c byte) int {
|
||||||
|
if c == ';' {
|
||||||
|
s.step = s.stateBeginValue
|
||||||
|
return scanListType
|
||||||
|
}
|
||||||
|
return s.stateInPureString(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) stateNeg(c byte) int {
|
func (s *scanner) stateNeg(c byte) int {
|
||||||
@ -301,7 +329,6 @@ func (s *scanner) stateEndValue(c byte) int {
|
|||||||
return s.stateEndTop(c)
|
return s.stateEndTop(c)
|
||||||
}
|
}
|
||||||
if isSpace(c) {
|
if isSpace(c) {
|
||||||
s.step = s.stateEndValue
|
|
||||||
return scanSkipSpace
|
return scanSkipSpace
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,18 +340,30 @@ func (s *scanner) stateEndValue(c byte) int {
|
|||||||
s.step = s.stateBeginValue
|
s.step = s.stateBeginValue
|
||||||
return scanCompoundTagName
|
return scanCompoundTagName
|
||||||
}
|
}
|
||||||
return s.error(c, "after object key")
|
return s.error(c, "after compound tag name")
|
||||||
case parseCompoundValue:
|
case parseCompoundValue:
|
||||||
switch c {
|
switch c {
|
||||||
case ',':
|
case ',':
|
||||||
|
s.parseState[n-1] = parseCompoundName
|
||||||
s.step = s.stateBeginString
|
s.step = s.stateBeginString
|
||||||
return scanCompoundValue
|
return scanCompoundValue
|
||||||
case '}':
|
case '}':
|
||||||
s.popParseState()
|
s.popParseState()
|
||||||
return scanEndValue
|
return scanEndValue
|
||||||
}
|
}
|
||||||
|
return s.error(c, "after compound value")
|
||||||
|
case parseListValue:
|
||||||
|
switch c {
|
||||||
|
case ',':
|
||||||
|
s.step = s.stateBeginValue
|
||||||
|
return scanListValue
|
||||||
|
case ']':
|
||||||
|
s.popParseState()
|
||||||
|
return scanEndValue
|
||||||
|
}
|
||||||
|
return s.error(c, "after list element")
|
||||||
}
|
}
|
||||||
return s.error(c, "not implemented")
|
return s.error(c, "")
|
||||||
}
|
}
|
||||||
func (s *scanner) error(c byte, context string) int {
|
func (s *scanner) error(c byte, context string) int {
|
||||||
s.step = s.stateError
|
s.step = s.stateError
|
||||||
|
@ -39,7 +39,32 @@ func TestSNBT_number(t *testing.T) {
|
|||||||
func TestSNBT_compound(t *testing.T) {
|
func TestSNBT_compound(t *testing.T) {
|
||||||
goods := []string{
|
goods := []string{
|
||||||
`{}`, `{name:3.14f}`, `{ "name" : 12345 }`,
|
`{}`, `{name:3.14f}`, `{ "name" : 12345 }`,
|
||||||
`{ abc: {}}`,
|
`{ abc: { }}`, `{ "ab\"c": {}, def: 12345}`,
|
||||||
|
}
|
||||||
|
var s scanner
|
||||||
|
scan := func(str string) bool {
|
||||||
|
s.reset()
|
||||||
|
for _, c := range []byte(str) {
|
||||||
|
res := s.step(c)
|
||||||
|
if res == scanError {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, str := range goods {
|
||||||
|
if scan(str) == false {
|
||||||
|
t.Errorf("scan valid data %q error: %v", str, s.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSNBT_list(t *testing.T) {
|
||||||
|
goods := []string{
|
||||||
|
`[]`, `[a, 'b', "c", d]`, // List of string
|
||||||
|
`[{}, {}, {"a\"b":520}]`, // List of Compound
|
||||||
|
`[B,C,D]`, `[L, "abc"]`, // List of string (like array)
|
||||||
|
`[B; 01B, 02B, 3B, 10B, 127B]`, // Array
|
||||||
}
|
}
|
||||||
var s scanner
|
var s scanner
|
||||||
scan := func(str string) bool {
|
scan := func(str string) bool {
|
||||||
|
Reference in New Issue
Block a user