Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parser by using yaml-test-suite #542

Merged
merged 14 commits into from
Nov 17, 2024
21 changes: 21 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,7 @@ type MappingValueNode struct {
Start *token.Token
Key MapKeyNode
Value Node
Anchor *AnchorNode
FootComment *CommentGroupNode
}

Expand Down Expand Up @@ -1597,6 +1598,10 @@ type AnchorNode struct {
Value Node
}

func (n *AnchorNode) stringWithoutComment() string {
return n.Value.String()
}

func (n *AnchorNode) SetName(name string) error {
if n.Name == nil {
return ErrInvalidAnchorName
Expand All @@ -1622,6 +1627,10 @@ func (n *AnchorNode) GetToken() *token.Token {
return n.Start
}

func (n *AnchorNode) GetValue() any {
return n.Value.GetToken().Value
}

// AddColumn add column number to child nodes recursively
func (n *AnchorNode) AddColumn(col int) {
n.Start.AddColumn(col)
Expand Down Expand Up @@ -1658,6 +1667,10 @@ type AliasNode struct {
Value Node
}

func (n *AliasNode) stringWithoutComment() string {
return n.Value.String()
}

func (n *AliasNode) SetName(name string) error {
if n.Value == nil {
return ErrInvalidAliasName
Expand All @@ -1683,6 +1696,10 @@ func (n *AliasNode) GetToken() *token.Token {
return n.Start
}

func (n *AliasNode) GetValue() any {
return n.Value.GetToken().Value
}

// AddColumn add column number to child nodes recursively
func (n *AliasNode) AddColumn(col int) {
n.Start.AddColumn(col)
Expand Down Expand Up @@ -1745,6 +1762,10 @@ type TagNode struct {
Value Node
}

func (n *TagNode) stringWithoutComment() string {
return n.Value.String()
}

// Read implements (io.Reader).Read
func (n *TagNode) Read(p []byte) (int, error) {
return readNode(p, n)
Expand Down
11 changes: 9 additions & 2 deletions parser/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (

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

var pathSpecialChars = []string{
Expand Down Expand Up @@ -49,6 +50,12 @@ 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: "$",
Expand Down
150 changes: 104 additions & 46 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func (p *parser) parseTag(ctx *context) (*ast.TagNode, error) {
if typ == token.LiteralType || typ == token.FoldedType {
value, err = p.parseLiteral(ctx)
} else {
value = p.parseScalarValue(p.currentToken())
value, err = p.parseScalarValueWithComment(ctx, p.currentToken())
}
case token.SequenceTag,
token.SetTag:
Expand Down Expand Up @@ -429,7 +429,7 @@ func (p *parser) mapKeyText(n ast.Node) string {
}

func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) {
key, err := p.parseMapKey(ctx)
key, err := p.parseMapKey(ctx.withMapKey())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -497,30 +497,55 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) {
if antk == nil {
return nil, errors.ErrSyntax("required ':' and map value", ntk)
}
if antk.Type != token.MappingValueType {
return nil, errors.ErrSyntax("required ':' and map value", antk)
}
p.progressIgnoreComment(1)
value, err := p.parseToken(ctx, p.currentToken())
var comment *ast.CommentGroupNode
if tk := p.currentToken(); tk.Type == token.CommentType {
comment = p.parseCommentOnly(ctx)
}
value, err := p.parseMappingValue(ctx)
if err != nil {
return nil, err
}
switch value.Type() {
case ast.MappingType:
c, _ := value.(*ast.MappingNode)
comment := c.GetComment()
for idx, v := range c.Values {
if comment != nil {
comment.SetPath(value.GetPath())
if err := value.SetComment(comment); err != nil {
return nil, err
}
}
switch v := value.(type) {
case *ast.MappingNode:
comment := v.GetComment()
for idx, val := range v.Values {
if idx == 0 && comment != nil {
if err := v.SetComment(comment); err != nil {
if err := val.SetComment(comment); err != nil {
return nil, err
}
}
node.Values = append(node.Values, v)
node.Values = append(node.Values, val)
}
case *ast.MappingValueNode:
node.Values = append(node.Values, v)
case *ast.AnchorNode:
switch anchorV := v.Value.(type) {
case *ast.MappingNode:
comment := anchorV.GetComment()
for idx, val := range anchorV.Values {
if idx == 0 && comment != nil {
if err := val.SetComment(comment); err != nil {
return nil, err
}
}
val.Anchor = v
node.Values = append(node.Values, val)
}
case *ast.MappingValueNode:
anchorV.Anchor = v
node.Values = append(node.Values, anchorV)
default:
return nil, fmt.Errorf("failed to parse mapping value node. anchor node is %s", anchorV.Type())
}
case ast.MappingValueType:
node.Values = append(node.Values, value.(*ast.MappingValueNode))
default:
return nil, fmt.Errorf("failed to parse mapping value node node is %s", value.Type())
return nil, fmt.Errorf("failed to parse mapping value node. node is %s", value.Type())
}
ntk = p.nextNotCommentToken()
antk = p.afterNextNotCommentToken()
Expand Down Expand Up @@ -657,11 +682,15 @@ func (p *parser) parseAnchor(ctx *context) (*ast.AnchorNode, error) {
return nil, errors.ErrSyntax("unexpected anchor. anchor name is undefined", tk)
}
p.progress(1) // skip anchor token
name, err := p.parseToken(ctx, p.currentToken())
anchorNameTk := p.currentToken()
anchorNameNode, err := p.parseScalarValueWithComment(ctx, anchorNameTk)
if err != nil {
return nil, err
}
anchor.Name = name
if anchorNameNode == nil {
return nil, errors.ErrSyntax("unexpected anchor. anchor name is not scalar value", anchorNameTk)
}
anchor.Name = anchorNameNode
ntk = p.nextToken()
if ntk == nil {
return nil, errors.ErrSyntax("unexpected anchor. anchor value is undefined", p.currentToken())
Expand All @@ -684,40 +713,39 @@ func (p *parser) parseAlias(ctx *context) (*ast.AliasNode, error) {
return nil, errors.ErrSyntax("unexpected alias. alias name is undefined", tk)
}
p.progress(1) // skip alias token
name, err := p.parseToken(ctx, p.currentToken())
aliasNameTk := p.currentToken()
aliasNameNode, err := p.parseScalarValueWithComment(ctx, aliasNameTk)
if err != nil {
return nil, err
}
alias.Value = name
if aliasNameNode == nil {
return nil, errors.ErrSyntax("unexpected alias. alias name is not scalar value", aliasNameTk)
}
alias.Value = aliasNameNode
return alias, nil
}

func (p *parser) parseMapKey(ctx *context) (ast.MapKeyNode, error) {
tk := p.currentToken()
if value := p.parseScalarValue(tk); value != nil {
if value, _ := p.parseScalarValueWithComment(ctx, tk); value != nil {
return value, nil
}
switch tk.Type {
case token.MergeKeyType:
return ast.MergeKey(tk), nil
case token.MappingKeyType:
return p.parseMappingKey(ctx)
case token.TagType:
return p.parseTag(ctx)
}
return nil, errors.ErrSyntax("unexpected mapping key", tk)
}

func (p *parser) parseStringValue(tk *token.Token) *ast.StringNode {
switch tk.Type {
case token.StringType,
token.SingleQuoteType,
token.DoubleQuoteType:
return ast.String(tk)
}
return nil
}

func (p *parser) parseScalarValueWithComment(ctx *context, tk *token.Token) (ast.ScalarNode, error) {
node := p.parseScalarValue(tk)
node, err := p.parseScalarValue(ctx, tk)
if err != nil {
return nil, err
}
if node == nil {
return nil, nil
}
Expand All @@ -731,28 +759,32 @@ func (p *parser) parseScalarValueWithComment(ctx *context, tk *token.Token) (ast
return node, nil
}

func (p *parser) parseScalarValue(tk *token.Token) ast.ScalarNode {
if node := p.parseStringValue(tk); node != nil {
return node
}
func (p *parser) parseScalarValue(ctx *context, tk *token.Token) (ast.ScalarNode, error) {
switch tk.Type {
case token.NullType:
return ast.Null(tk)
return ast.Null(tk), nil
case token.BoolType:
return ast.Bool(tk)
return ast.Bool(tk), nil
case token.IntegerType,
token.BinaryIntegerType,
token.OctetIntegerType,
token.HexIntegerType:
return ast.Integer(tk)
return ast.Integer(tk), nil
case token.FloatType:
return ast.Float(tk)
return ast.Float(tk), nil
case token.InfinityType:
return ast.Infinity(tk)
return ast.Infinity(tk), nil
case token.NanType:
return ast.Nan(tk)
return ast.Nan(tk), nil
case token.StringType, token.SingleQuoteType,
token.DoubleQuoteType:
return ast.String(tk), nil
case token.AnchorType:
return p.parseAnchor(ctx)
case token.AliasType:
return p.parseAlias(ctx)
}
return nil
return nil, nil
}

func (p *parser) parseDirective(ctx *context) (*ast.DirectiveNode, error) {
Expand Down Expand Up @@ -925,9 +957,14 @@ func (p *parser) createNodeFromToken(ctx *context, tk *token.Token) (ast.Node, e
if tk == nil {
return nil, nil
}
if tk.NextType() == token.MappingValueType {
node, err := p.parseMappingValue(ctx)
return node, err
if !ctx.isMapKey && tk.NextType() == token.MappingValueType {
return p.parseMappingValue(ctx)
}
if tk.Type == token.AliasType {
aliasValueTk := p.nextToken()
if aliasValueTk != nil && aliasValueTk.NextType() == token.MappingValueType {
return p.parseMappingValue(ctx)
}
}
node, err := p.parseScalarValueWithComment(ctx, tk)
if err != nil {
Expand Down Expand Up @@ -982,13 +1019,34 @@ func (p *parser) parse(ctx *context) (*ast.File, error) {
}
if doc, ok := node.(*ast.DocumentNode); ok {
file.Docs = append(file.Docs, doc)
} else if len(file.Docs) == 0 {
file.Docs = append(file.Docs, ast.Document(nil, node))
} else {
lastNode := p.comparableColumnNode(file.Docs[len(file.Docs)-1])
curNode := p.comparableColumnNode(node)
if lastNode.GetToken().Position.Column != curNode.GetToken().Position.Column {
return nil, errors.ErrSyntax("value is not allowed in this context", curNode.GetToken())
}
file.Docs = append(file.Docs, ast.Document(nil, node))
}
}
return file, nil
}

func (p *parser) comparableColumnNode(n ast.Node) ast.Node {
switch nn := n.(type) {
case *ast.MappingNode:
if len(nn.Values) != 0 {
return nn.Values[0].Key
}
case *ast.MappingValueNode:
return nn.Key
case *ast.DocumentNode:
return p.comparableColumnNode(nn.Body)
}
return n
}

type Mode uint

const (
Expand Down
7 changes: 3 additions & 4 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1110,12 +1110,11 @@ b
- c
`,
`
[4:1] required ':' and map value
[3:1] unexpected key name
2 | a: 1
3 | b
> 4 | - c
> 3 | b
^
`,
4 | - c`,
},
{
`a: [`,
Expand Down
Loading
Loading