Skip to content

Commit

Permalink
fix handling of invalid sequence (#492)
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy authored Oct 31, 2024
1 parent af5147b commit bbcd692
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 6 deletions.
36 changes: 31 additions & 5 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,36 @@ func (p *parser) parseSequence(ctx *context) (*ast.SequenceNode, error) {
node := ast.Sequence(ctx.currentToken(), true)
node.SetPath(ctx.path)
ctx.progress(1) // skip SequenceStart token

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

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

value, err := p.parseToken(ctx.withIndex(uint(len(node.Values))), tk)
value, err := p.parseToken(ctx.withIndex(uint(len(node.Values))), ctx.currentToken())
if err != nil {
return nil, err
}
node.Values = append(node.Values, value)
ctx.progress(1)
isFirst = false
}
if node.End == nil || node.End.Type != token.SequenceEndType {
return nil, errors.ErrSyntax("sequence end token ']' not found", node.Start)
}
return node, nil
}
Expand Down Expand Up @@ -227,7 +241,7 @@ func (p *parser) validateMapValue(ctx *context, key, value ast.Node) error {
}
ntk := ctx.nextToken()
if ntk == nil || (ntk.Type != token.MappingValueType && ntk.Type != token.SequenceEntryType) {
return errors.ErrSyntax("could not found expected ':' token", value.GetToken())
return errors.ErrSyntax("could not find expected ':' token", value.GetToken())
}
return nil
}
Expand Down Expand Up @@ -272,8 +286,16 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) {

ntk := ctx.nextNotCommentToken()
antk := ctx.afterNextNotCommentToken()
for antk != nil && antk.Type == token.MappingValueType &&
ntk.Position.Column == key.GetToken().Position.Column {
for ntk != nil && ntk.Position.Column == key.GetToken().Position.Column {
if ntk.Type == token.DocumentHeaderType || ntk.Type == token.DocumentEndType {
break
}
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)
}
ctx.progressIgnoreComment(1)
value, err := p.parseToken(ctx, ctx.currentToken())
if err != nil {
Expand Down Expand Up @@ -667,6 +689,10 @@ func (p *parser) createNodeFromToken(ctx *context, tk *token.Token) (ast.Node, e
return p.parseMapping(ctx)
case token.SequenceStartType:
return p.parseSequence(ctx)
case token.SequenceEndType:
// SequenceEndType is always validated in parseSequence.
// Therefore, if this is found in other cases, it is treated as a syntax error.
return nil, errors.ErrSyntax("could not find '[' character corresponding to ']'", tk)
case token.SequenceEntryType:
return p.parseSequenceEntry(ctx)
case token.AnchorType:
Expand Down
50 changes: 50 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,56 @@ a: |invalidopt
^
3 | foo`,
},
{
`
a: 1
b
`,
`
[3:1] required ':' and map value
2 | a: 1
> 3 | b
^
`,
},
{
`
a: 1
b
- c
`,
`
[4:1] required ':' and map value
2 | a: 1
3 | b
> 4 | - c
^
`,
},
{
`a: [`,
`
[1:4] sequence end token ']' not found
> 1 | a: [
^
`,
},
{
`a: ]`,
`
[1:4] could not find '[' character corresponding to ']'
> 1 | a: ]
^
`,
},
{
`a: [ [1] [2] [3] ]`,
`
[1:10] ',' or ']' must be specified
> 1 | a: [ [1] [2] [3] ]
^
`,
},
}
for _, test := range tests {
t.Run(test.source, func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ func (s *Scanner) scanFlowArrayStart(ctx *Context) bool {
}

func (s *Scanner) scanFlowArrayEnd(ctx *Context) bool {
if s.startedFlowSequenceNum <= 0 {
if ctx.existsBuffer() && s.startedFlowSequenceNum <= 0 {
return false
}

Expand Down

0 comments on commit bbcd692

Please sign in to comment.