Skip to content

Commit

Permalink
refactor parser
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy committed Nov 25, 2024
1 parent ff5d41f commit 6a4fdd3
Show file tree
Hide file tree
Showing 10 changed files with 1,710 additions and 856 deletions.
8 changes: 8 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,14 @@ type TagNode struct {
Value Node
}

func (n *TagNode) GetValue() any {
scalar, ok := n.Value.(ScalarNode)
if !ok {
return nil
}
return scalar.GetValue()
}

func (n *TagNode) stringWithoutComment() string {
return n.Value.String()
}
Expand Down
20 changes: 17 additions & 3 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ func (d *Decoder) addHeadOrLineCommentToMap(node ast.Node) {
}
commentPath := node.GetPath()
if minCommentLine < targetLine {
switch n := node.(type) {
case *ast.MappingNode:
if len(n.Values) != 0 {
commentPath = n.Values[0].Key.GetPath()
}
case *ast.MappingValueNode:
commentPath = n.Key.GetPath()
}
d.addCommentToMap(commentPath, HeadComment(texts...))
} else {
d.addCommentToMap(commentPath, LineComment(texts[0]))
Expand Down Expand Up @@ -255,14 +263,20 @@ func (d *Decoder) addFootCommentToMap(node ast.Node) {
)
switch n := node.(type) {
case *ast.SequenceNode:
if len(n.Values) != 0 {
footCommentPath = n.Values[len(n.Values)-1].GetPath()
}
footComment = n.FootComment
if n.FootComment != nil {
footCommentPath = n.FootComment.GetPath()
}
case *ast.MappingNode:
footComment = n.FootComment
if n.FootComment != nil {
footCommentPath = n.FootComment.GetPath()
}
case *ast.MappingValueNode:
footComment = n.FootComment
if n.FootComment != nil {
footCommentPath = n.FootComment.GetPath()
}
}
if footComment == nil {
return
Expand Down
28 changes: 28 additions & 0 deletions parser/color.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package parser

import "fmt"

const (
colorFgHiBlack int = iota + 90
colorFgHiRed
colorFgHiGreen
colorFgHiYellow
colorFgHiBlue
colorFgHiMagenta
colorFgHiCyan
)

var colorTable = []int{
colorFgHiRed,
colorFgHiGreen,
colorFgHiYellow,
colorFgHiBlue,
colorFgHiMagenta,
colorFgHiCyan,
}

func colorize(idx int, content string) string {
colorIdx := idx % len(colorTable)
color := colorTable[colorIdx]
return fmt.Sprintf("\x1b[1;%dm", color) + content + "\x1b[22;0m"
}
91 changes: 84 additions & 7 deletions parser/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ package parser
import (
"fmt"
"strings"

"github.com/goccy/go-yaml/token"
)

// context context at parsing
type context struct {
tokenRef *tokenRef
path string
isFlow bool
isMapKey bool
}

type tokenRef struct {
tokens []*Token
size int
idx int
}

var pathSpecialChars = []string{
Expand All @@ -32,6 +40,44 @@ func normalizePath(path string) string {
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) 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)
Expand All @@ -50,14 +96,45 @@ func (c *context) withFlow(isFlow bool) *context {
return &ctx
}

func (c *context) withMapKey() *context {
ctx := *c
ctx.isMapKey = true
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) insertToken(tk *Token) {
idx := c.tokenRef.idx
if c.tokenRef.size < idx {
return
}
if c.tokenRef.size == idx {
curToken := c.tokenRef.tokens[c.tokenRef.size-1]
tk.RawToken().Next = curToken.RawToken()
curToken.RawToken().Prev = tk.RawToken()

c.tokenRef.tokens = append(c.tokenRef.tokens, tk)
c.tokenRef.size = len(c.tokenRef.tokens)
return
}

curToken := c.tokenRef.tokens[idx]
tk.RawToken().Next = curToken.RawToken()
curToken.RawToken().Prev = tk.RawToken()

c.tokenRef.tokens = append(c.tokenRef.tokens[:idx+1], c.tokenRef.tokens[idx:]...)
c.tokenRef.tokens[idx] = tk
c.tokenRef.size = len(c.tokenRef.tokens)
}
193 changes: 193 additions & 0 deletions parser/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package parser

import (
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/token"
)

func newMappingNode(ctx *context, tk *Token, isFlow bool, values ...*ast.MappingValueNode) (*ast.MappingNode, error) {
node := ast.Mapping(tk.RawToken(), isFlow, values...)
node.SetPath(ctx.path)
return node, nil
}

func newMappingValueNode(ctx *context, tk *Token, key ast.MapKeyNode, value ast.Node) (*ast.MappingValueNode, error) {
node := ast.MappingValue(tk.RawToken(), key, value)
node.SetPath(ctx.path)
if key.GetToken().Position.Line == value.GetToken().Position.Line {
// originally key was commented, but now that null value has been added, value must be commented.
if err := setLineComment(ctx, value, tk); err != nil {
return nil, err
}
} else {
if err := setLineComment(ctx, key, tk); err != nil {
return nil, err
}
}
return node, nil
}

func newMappingKeyNode(ctx *context, tk *Token) (*ast.MappingKeyNode, error) {
node := ast.MappingKey(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newAnchorNode(ctx *context, tk *Token) (*ast.AnchorNode, error) {
node := ast.Anchor(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newAliasNode(ctx *context, tk *Token) (*ast.AliasNode, error) {
node := ast.Alias(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newDirectiveNode(ctx *context, tk *Token) (*ast.DirectiveNode, error) {
node := ast.Directive(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newMergeKeyNode(ctx *context, tk *Token) (*ast.MergeKeyNode, error) {
node := ast.MergeKey(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newNullNode(ctx *context, tk *Token) (*ast.NullNode, error) {
node := ast.Null(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newBoolNode(ctx *context, tk *Token) (*ast.BoolNode, error) {
node := ast.Bool(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newIntegerNode(ctx *context, tk *Token) (*ast.IntegerNode, error) {
node := ast.Integer(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newFloatNode(ctx *context, tk *Token) (*ast.FloatNode, error) {
node := ast.Float(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newInfinityNode(ctx *context, tk *Token) (*ast.InfinityNode, error) {
node := ast.Infinity(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newNanNode(ctx *context, tk *Token) (*ast.NanNode, error) {
node := ast.Nan(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newStringNode(ctx *context, tk *Token) (*ast.StringNode, error) {
node := ast.String(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newLiteralNode(ctx *context, tk *Token) (*ast.LiteralNode, error) {
node := ast.Literal(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newTagNode(ctx *context, tk *Token) (*ast.TagNode, error) {
node := ast.Tag(tk.RawToken())
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func newSequenceNode(ctx *context, tk *Token, isFlow bool) (*ast.SequenceNode, error) {
node := ast.Sequence(tk.RawToken(), isFlow)
node.SetPath(ctx.path)
if err := setLineComment(ctx, node, tk); err != nil {
return nil, err
}
return node, nil
}

func setLineComment(ctx *context, node ast.Node, tk *Token) error {
if tk.LineComment == nil {
return nil
}
comment := ast.CommentGroup([]*token.Token{tk.LineComment})
comment.SetPath(ctx.path)
if err := node.SetComment(comment); err != nil {
return err
}
return nil
}

func setHeadComment(cm *ast.CommentGroupNode, value ast.Node) error {
if cm == nil {
return nil
}
switch n := value.(type) {
case *ast.MappingNode:
if len(n.Values) != 0 && value.GetComment() == nil {
cm.SetPath(n.Values[0].GetPath())
return n.Values[0].SetComment(cm)
}
case *ast.MappingValueNode:
cm.SetPath(n.GetPath())
return n.SetComment(cm)
}
cm.SetPath(value.GetPath())
return value.SetComment(cm)
}
Loading

0 comments on commit 6a4fdd3

Please sign in to comment.