2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00
sonic/ast/parser.go
2021-05-28 23:58:58 +08:00

304 lines
7.2 KiB
Go

/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ast
import (
`sync`
`unsafe`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/rt`
)
const _DEFAULT_NODE_CAP = 16
type Parser struct {
p int
s string
noLazy bool
}
var stackPool = sync.Pool{
New: func()interface{}{
return &native.StateMachine{}
},
}
/** Parser Private Methods **/
func (self *Parser) delim() native.ParsingError {
n := len(self.s)
p := self.lspace(self.p)
/* check for EOF */
if p >= n {
return native.ERR_EOF
}
/* check for the delimtier */
if self.s[p] != ':' {
return native.ERR_INVALID_CHAR
}
/* update the read pointer */
self.p = p + 1
return 0
}
func (self *Parser) object() native.ParsingError {
n := len(self.s)
p := self.lspace(self.p)
/* check for EOF */
if p >= n {
return native.ERR_EOF
}
/* check for the delimtier */
if self.s[p] != '{' {
return native.ERR_INVALID_CHAR
}
/* update the read pointer */
self.p = p + 1
return 0
}
func (self *Parser) array() native.ParsingError {
n := len(self.s)
p := self.lspace(self.p)
/* check for EOF */
if p >= n {
return native.ERR_EOF
}
/* check for the delimtier */
if self.s[p] != '[' {
return native.ERR_INVALID_CHAR
}
/* update the read pointer */
self.p = p + 1
return 0
}
func (self *Parser) lspace(sp int) int {
sv := (*rt.GoString)(unsafe.Pointer(&self.s))
return native.Lspace(sv.Ptr, sv.Len, sp)
}
func (self *Parser) decodeValue() (val native.JsonState) {
sv := (*rt.GoString)(unsafe.Pointer(&self.s))
self.p = native.Value(sv.Ptr, sv.Len, self.p, &val)
return
}
func (self *Parser) decodeArray(ret []Node) (Node, native.ParsingError) {
sp := self.p
ns := len(self.s)
/* check for EOF */
if self.p = self.lspace(sp); self.p >= ns {
return Node{}, native.ERR_EOF
}
/* check for empty array */
if self.s[self.p] == ']' {
self.p++
return emptyArrayNode, 0
}
/* allocate array space and parse every element */
for {
var val Node
var err native.ParsingError
/* decode the value */
if val, err = self.Parse(); err != 0 {
return Node{}, err
}
/* add the value to result */
ret = append(ret, val)
self.p = self.lspace(self.p)
/* check for EOF */
if self.p >= ns {
return Node{}, native.ERR_EOF
}
/* check for the next character */
switch self.s[self.p] {
case ',' : self.p++
case ']' : self.p++; return newArray(ret), 0
default:
if val.IsRaw() {
return newRawArray(self, ret), 0
}
return Node{}, native.ERR_INVALID_CHAR
}
}
}
func (self *Parser) decodeObject(ret []Pair) (Node, native.ParsingError) {
sp := self.p
ns := len(self.s)
/* check for EOF */
if self.p = self.lspace(sp); self.p >= ns {
return Node{}, native.ERR_EOF
}
/* check for empty object */
if self.s[self.p] == '}' {
self.p++
return emptyObjectNode, 0
}
/* decode each pair */
for {
var val Node
var njs native.JsonState
var err native.ParsingError
/* decode the key */
if njs = self.decodeValue(); njs.Vt != native.V_STRING {
return Node{}, native.ERR_INVALID_CHAR
}
/* extract the key */
idx := self.p - 1
key := self.s[njs.Iv:idx]
/* check for escape sequence */
if njs.Ep != -1 {
if key, err = UnquoteString(key); err != 0 {
return Node{}, err
}
}
/* expect a ':' delimiter */
if err = self.delim(); err != 0 {
return Node{}, err
}
/* decode the value */
if val, err = self.Parse(); err != 0 {
return Node{}, err
}
/* add the value to result */
ret = append(ret, Pair{Key: key, Value: val})
self.p = self.lspace(self.p)
/* check for EOF */
if self.p >= ns {
return Node{}, native.ERR_EOF
}
/* check for the next character */
switch self.s[self.p] {
case ',' : self.p++
case '}' : self.p++; return newObject(ret), 0
default:
if val.IsRaw() {
return newRawObject(self, ret), 0
}
return Node{}, native.ERR_INVALID_CHAR
}
}
}
func (self *Parser) decodeString(iv int64, ep int) (Node, native.ParsingError) {
p := self.p - 1
s := self.s[iv:p]
/* fast path: no escape sequence */
if ep == -1 {
return newString(s), 0
}
/* unquote the string */
buf := make([]byte, 0, len(s))
err := unquoteBytes(s, &buf)
/* check for errors */
if err != 0 {
return Node{}, err
} else {
return newBytes(buf), 0
}
}
/** Parser Interface **/
func (self *Parser) Pos() int {
return self.p
}
func (self *Parser) Parse() (Node, native.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case native.V_EOF : return Node{}, native.ERR_EOF
case native.V_NULL : return nullNode, 0
case native.V_TRUE : return trueNode, 0
case native.V_FALSE : return falseNode, 0
case native.V_ARRAY:
if self.noLazy {
return self.decodeArray(make([]Node, 0, _DEFAULT_NODE_CAP))
}
return newRawArray(self, make([]Node, 0, _DEFAULT_NODE_CAP)), 0
case native.V_OBJECT:
if self.noLazy {
return self.decodeObject(make([]Pair, 0, _DEFAULT_NODE_CAP))
}
return newRawObject(self, make([]Pair, 0, _DEFAULT_NODE_CAP)), 0
case native.V_STRING : return self.decodeString(val.Iv, val.Ep)
case native.V_DOUBLE : return newFloat64(val.Dv), 0
case native.V_INTEGER : return newInt64(val.Iv), 0
default : return Node{}, native.ParsingError(-val.Vt)
}
}
func (self *Parser) skip() (int, native.ParsingError) {
fsm := stackPool.Get().(*native.StateMachine)
start := native.SkipOne(&self.s, &self.p, fsm)
stackPool.Put(fsm)
if start < 0 {
return self.p, native.ParsingError(-start)
}
return start, 0
}
/** Parser Factory **/
func Loads(src string) (int, interface{}, native.ParsingError) {
ps := &Parser{s: src}
np, err := ps.Parse()
/* check for errors */
if err != 0 {
return 0, nil, err
} else {
return ps.Pos(), np.Interface(), 0
}
}
func NewParser(src string) *Parser {
return &Parser{s: src}
}