Skip to content

Commit

Permalink
fix parsing of flow mapping (#505)
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy authored Nov 5, 2024
1 parent 2e63415 commit 97070fb
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 8 deletions.
9 changes: 8 additions & 1 deletion parser/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (

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

var pathSpecialChars = []string{
Expand Down Expand Up @@ -42,6 +43,12 @@ func (c *context) withIndex(idx uint) *context {
return &ctx
}

func (c *context) withFlow(isFlow bool) *context {
ctx := *c
ctx.isFlow = isFlow
return &ctx
}

func newContext() *context {
return &context{
path: "$",
Expand Down
65 changes: 59 additions & 6 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,27 @@ func (p *parser) parseMapping(ctx *context) (*ast.MappingNode, error) {
node := ast.Mapping(mapTk, true)
node.SetPath(ctx.path)
p.progress(1) // skip MappingStart token

isFirst := true
for p.next() {
tk := p.currentToken()
if tk.Type == token.MappingEndType {
node.End = tk
return node, nil
break
} else if tk.Type == token.CollectEntryType {
p.progress(1)
continue
} else if !isFirst {
return nil, errors.ErrSyntax("',' or '}' must be specified", tk)
}

if tk := p.currentToken(); tk != nil && tk.Type == token.MappingEndType {
// this case is here: "{ elem, }".
// In this case, ignore the last element and break mapping parsing.
node.End = tk
break
}

value, err := p.parseMappingValue(ctx)
value, err := p.parseMappingValue(ctx.withFlow(true))
if err != nil {
return nil, err
}
Expand All @@ -160,8 +170,12 @@ func (p *parser) parseMapping(ctx *context) (*ast.MappingNode, error) {
}
node.Values = append(node.Values, mvnode)
p.progress(1)
isFirst = false
}
if node.End == nil || node.End.Type != token.MappingEndType {
return nil, errors.ErrSyntax("could not find flow mapping end token '}'", node.Start)
}
return nil, errors.ErrSyntax("unterminated flow mapping", node.GetToken())
return node, nil
}

func (p *parser) parseSequence(ctx *context) (*ast.SequenceNode, error) {
Expand Down Expand Up @@ -382,12 +396,32 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) {
if err := p.validateMapKey(key.GetToken()); err != nil {
return nil, err
}
p.progress(1) // progress to mapping value token
tk := p.currentToken() // get mapping value token
p.progress(1) // progress to mapping value token
if ctx.isFlow {
// if "{key}" or "{key," style, returns MappingValueNode.
node, err := p.parseFlowMapNullValue(ctx, key)
if err != nil {
return nil, err
}
if node != nil {
return node, nil
}
}
tk := p.currentToken() // get mapping value (':') token.
if tk == nil {
return nil, errors.ErrSyntax("unexpected map", key.GetToken())
}
p.progress(1) // progress to value token
if ctx.isFlow {
// if "{key:}" or "{key:," style, returns MappingValueNode.
node, err := p.parseFlowMapNullValue(ctx, key)
if err != nil {
return nil, err
}
if node != nil {
return node, nil
}
}
if err := p.setSameLineCommentIfExists(ctx.withChild(keyText), key); err != nil {
return nil, err
}
Expand Down Expand Up @@ -474,6 +508,25 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) {
return node, nil
}

func (p *parser) parseFlowMapNullValue(ctx *context, key ast.MapKeyNode) (*ast.MappingValueNode, error) {
tk := p.currentToken()
if tk == nil {
return nil, errors.ErrSyntax("unexpected map", key.GetToken())
}
if tk.Type != token.MappingEndType && tk.Type != token.CollectEntryType {
return nil, nil
}
nullTk := p.createNullToken(tk)
p.insertToken(p.idx, nullTk)
value, err := p.parseToken(ctx, nullTk)
if err != nil {
return nil, err
}
node := ast.MappingValue(tk, key, value)
node.SetPath(ctx.withChild(key.GetToken().Value).path)
return node, nil
}

func (p *parser) parseSequenceEntry(ctx *context) (*ast.SequenceNode, error) {
tk := p.currentToken()
sequenceNode := ast.Sequence(tk, false)
Expand Down
4 changes: 3 additions & 1 deletion parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ func TestParser(t *testing.T) {
"value: >\nother:",
"value: >\n\nother:",
"a:\n-",
"a: {foo}",
"a: {foo,bar}",
}
for _, src := range sources {
if _, err := parser.Parse(lexer.Tokenize(src), 0); err != nil {
Expand Down Expand Up @@ -968,7 +970,7 @@ a
{
`{ "key": "value" `,
`
[1:1] unterminated flow mapping
[1:1] could not find flow mapping end token '}'
> 1 | { "key": "value"
^
`,
Expand Down

0 comments on commit 97070fb

Please sign in to comment.