Scan List and Array

This commit is contained in:
Tnze
2021-05-25 14:25:08 +08:00
parent 0c0459d69d
commit 5320722ed0
2 changed files with 78 additions and 14 deletions

View File

@ -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

View File

@ -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 {