mirror of
https://github.com/goccy/go-yaml.git
synced 2025-10-19 15:53:16 +00:00
187 lines
3.5 KiB
Go
187 lines
3.5 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/goccy/go-yaml/token"
|
|
)
|
|
|
|
// context context at parsing
|
|
type context struct {
|
|
tokenRef *tokenRef
|
|
path string
|
|
isFlow bool
|
|
}
|
|
|
|
type tokenRef struct {
|
|
tokens []*Token
|
|
size int
|
|
idx int
|
|
}
|
|
|
|
var pathSpecialChars = []string{
|
|
"$", "*", ".", "[", "]",
|
|
}
|
|
|
|
func containsPathSpecialChar(path string) bool {
|
|
for _, char := range pathSpecialChars {
|
|
if strings.Contains(path, char) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func normalizePath(path string) string {
|
|
if containsPathSpecialChar(path) {
|
|
return fmt.Sprintf("'%s'", path)
|
|
}
|
|
return path
|
|
}
|
|
|
|
func (c *context) currentToken() *Token {
|
|
if c.tokenRef.idx >= c.tokenRef.size {
|
|
return nil
|
|
}
|
|
return c.tokenRef.tokens[c.tokenRef.idx]
|
|
}
|
|
|
|
func (c *context) isComment() bool {
|
|
return c.currentToken().Type() == token.CommentType
|
|
}
|
|
|
|
func (c *context) nextToken() *Token {
|
|
if c.tokenRef.idx+1 >= c.tokenRef.size {
|
|
return nil
|
|
}
|
|
return c.tokenRef.tokens[c.tokenRef.idx+1]
|
|
}
|
|
|
|
func (c *context) nextNotCommentToken() *Token {
|
|
for i := c.tokenRef.idx + 1; i < c.tokenRef.size; i++ {
|
|
tk := c.tokenRef.tokens[i]
|
|
if tk.Type() == token.CommentType {
|
|
continue
|
|
}
|
|
return tk
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *context) isTokenNotFound() bool {
|
|
return c.currentToken() == nil
|
|
}
|
|
|
|
func (c *context) withGroup(g *TokenGroup) *context {
|
|
ctx := *c
|
|
ctx.tokenRef = &tokenRef{
|
|
tokens: g.Tokens,
|
|
size: len(g.Tokens),
|
|
}
|
|
return &ctx
|
|
}
|
|
|
|
func (c *context) withChild(path string) *context {
|
|
ctx := *c
|
|
ctx.path = c.path + "." + normalizePath(path)
|
|
return &ctx
|
|
}
|
|
|
|
func (c *context) withIndex(idx uint) *context {
|
|
ctx := *c
|
|
ctx.path = c.path + "[" + fmt.Sprint(idx) + "]"
|
|
return &ctx
|
|
}
|
|
|
|
func (c *context) withFlow(isFlow bool) *context {
|
|
ctx := *c
|
|
ctx.isFlow = isFlow
|
|
return &ctx
|
|
}
|
|
|
|
func newContext() *context {
|
|
return &context{
|
|
path: "$",
|
|
}
|
|
}
|
|
|
|
func (c *context) goNext() {
|
|
ref := c.tokenRef
|
|
if ref.size <= ref.idx+1 {
|
|
ref.idx = ref.size
|
|
} else {
|
|
ref.idx++
|
|
}
|
|
}
|
|
|
|
func (c *context) next() bool {
|
|
return c.tokenRef.idx < c.tokenRef.size
|
|
}
|
|
|
|
func (c *context) insertNullToken(tk *Token) *Token {
|
|
nullToken := c.createImplicitNullToken(tk)
|
|
c.insertToken(nullToken)
|
|
c.goNext()
|
|
|
|
return nullToken
|
|
}
|
|
|
|
func (c *context) addNullValueToken(tk *Token) *Token {
|
|
nullToken := c.createImplicitNullToken(tk)
|
|
rawTk := nullToken.RawToken()
|
|
|
|
// add space for map or sequence value.
|
|
rawTk.Position.Column++
|
|
|
|
c.addToken(nullToken)
|
|
c.goNext()
|
|
|
|
return nullToken
|
|
}
|
|
|
|
func (c *context) createImplicitNullToken(base *Token) *Token {
|
|
pos := *(base.RawToken().Position)
|
|
pos.Column++
|
|
tk := token.New("null", " null", &pos)
|
|
tk.Type = token.ImplicitNullType
|
|
return &Token{Token: tk}
|
|
}
|
|
|
|
func (c *context) insertToken(tk *Token) {
|
|
ref := c.tokenRef
|
|
idx := ref.idx
|
|
if ref.size < idx {
|
|
return
|
|
}
|
|
if ref.size == idx {
|
|
curToken := ref.tokens[ref.size-1]
|
|
tk.RawToken().Next = curToken.RawToken()
|
|
curToken.RawToken().Prev = tk.RawToken()
|
|
|
|
ref.tokens = append(ref.tokens, tk)
|
|
ref.size = len(ref.tokens)
|
|
return
|
|
}
|
|
|
|
curToken := ref.tokens[idx]
|
|
tk.RawToken().Next = curToken.RawToken()
|
|
curToken.RawToken().Prev = tk.RawToken()
|
|
|
|
ref.tokens = append(ref.tokens[:idx+1], ref.tokens[idx:]...)
|
|
ref.tokens[idx] = tk
|
|
ref.size = len(ref.tokens)
|
|
}
|
|
|
|
func (c *context) addToken(tk *Token) {
|
|
ref := c.tokenRef
|
|
lastTk := ref.tokens[ref.size-1]
|
|
if lastTk.Group != nil {
|
|
lastTk = lastTk.Group.Last()
|
|
}
|
|
lastTk.RawToken().Next = tk.RawToken()
|
|
tk.RawToken().Prev = lastTk.RawToken()
|
|
|
|
ref.tokens = append(ref.tokens, tk)
|
|
ref.size = len(ref.tokens)
|
|
}
|