go-yaml/parser/context.go

186 lines
3.3 KiB
Go
Raw Normal View History

2019-11-05 17:02:55 +09:00
package parser
2021-09-07 17:31:17 +09:00
import (
"fmt"
"strings"
2021-09-07 17:31:17 +09:00
"github.com/goccy/go-yaml/token"
)
2019-11-05 17:02:55 +09:00
// context context at parsing
type context struct {
2021-09-07 17:31:17 +09:00
parent *context
2019-11-05 17:02:55 +09:00
idx int
size int
tokens token.Tokens
2021-09-07 17:31:17 +09:00
path string
}
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
}
2021-09-07 17:31:17 +09:00
func (c *context) withChild(path string) *context {
ctx := c.copy()
path = normalizePath(path)
2021-09-07 17:31:17 +09:00
ctx.path += fmt.Sprintf(".%s", path)
return ctx
}
func (c *context) withIndex(idx uint) *context {
ctx := c.copy()
ctx.path += fmt.Sprintf("[%d]", idx)
return ctx
}
func (c *context) copy() *context {
return &context{
parent: c,
idx: c.idx,
size: c.size,
tokens: append(token.Tokens{}, c.tokens...),
path: c.path,
}
2019-11-05 17:02:55 +09:00
}
func (c *context) next() bool {
return c.idx < c.size
}
func (c *context) previousToken() *token.Token {
if c.idx > 0 {
return c.tokens[c.idx-1]
}
return nil
}
func (c *context) insertToken(idx int, tk *token.Token) {
2021-09-07 17:31:17 +09:00
if c.parent != nil {
c.parent.insertToken(idx, tk)
}
if c.size < idx {
return
}
if c.size == idx {
curToken := c.tokens[c.size-1]
tk.Next = curToken
curToken.Prev = tk
c.tokens = append(c.tokens, tk)
c.size = len(c.tokens)
return
}
curToken := c.tokens[idx]
tk.Next = curToken
curToken.Prev = tk
c.tokens = append(c.tokens[:idx+1], c.tokens[idx:]...)
c.tokens[idx] = tk
c.size = len(c.tokens)
}
2019-11-05 17:02:55 +09:00
func (c *context) currentToken() *token.Token {
if c.idx >= c.size {
return nil
}
return c.tokens[c.idx]
}
func (c *context) nextToken() *token.Token {
2020-05-28 21:39:06 +09:00
if c.idx+1 >= c.size {
return nil
}
return c.tokens[c.idx+1]
}
2020-05-29 15:32:25 +09:00
func (c *context) nextNotCommentToken() *token.Token {
for i := c.idx + 1; i < c.size; i++ {
tk := c.tokens[i]
2020-05-28 21:39:06 +09:00
if tk.Type == token.CommentType {
continue
}
2020-05-29 16:10:24 +09:00
return tk
2019-11-05 17:02:55 +09:00
}
return nil
}
2020-05-29 15:32:25 +09:00
func (c *context) afterNextNotCommentToken() *token.Token {
notCommentTokenCount := 0
for i := c.idx + 1; i < c.size; i++ {
tk := c.tokens[i]
if tk.Type == token.CommentType {
continue
}
notCommentTokenCount++
if notCommentTokenCount == 2 {
return tk
}
}
return nil
}
func (c *context) isCurrentCommentToken() bool {
tk := c.currentToken()
if tk == nil {
return false
}
return tk.Type == token.CommentType
}
func (c *context) progressIgnoreComment(num int) {
2021-09-07 17:31:17 +09:00
if c.parent != nil {
c.parent.progressIgnoreComment(num)
}
2019-11-05 17:02:55 +09:00
if c.size <= c.idx+num {
c.idx = c.size
} else {
c.idx += num
}
}
2020-05-29 15:32:25 +09:00
func (c *context) progress(num int) {
if c.isCurrentCommentToken() {
return
}
c.progressIgnoreComment(num)
}
2019-11-05 17:02:55 +09:00
func newContext(tokens token.Tokens, mode Mode) *context {
filteredTokens := []*token.Token{}
2019-11-05 17:02:55 +09:00
if mode&ParseComments != 0 {
filteredTokens = tokens
} else {
for _, tk := range tokens {
if tk.Type == token.CommentType {
continue
}
// keep prev/next reference between tokens containing comments
// https://github.com/goccy/go-yaml/issues/254
filteredTokens = append(filteredTokens, tk)
2019-11-05 17:02:55 +09:00
}
}
return &context{
idx: 0,
size: len(filteredTokens),
tokens: token.Tokens(filteredTokens),
2021-09-07 17:31:17 +09:00
path: "$",
2019-11-05 17:02:55 +09:00
}
}