Skip to content

Commit

Permalink
Merge pull request #278 from goccy/feature/fix-parse-multiline-value
Browse files Browse the repository at this point in the history
Fix indentState logic for multi-line value
  • Loading branch information
goccy authored Jan 11, 2022
2 parents ac4bc56 + f6e3a46 commit 5fdf77f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 34 deletions.
45 changes: 31 additions & 14 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,25 +547,42 @@ b: c
a: |+
value
b: c
`,
},
{
`
- key1: val
key2:
(
foo
+
bar
)
`,
`
- key1: val
key2: ( foo + bar )
`,
},
}

for _, test := range tests {
tokens := lexer.Tokenize(test.source)
f, err := parser.Parse(tokens, 0)
if err != nil {
t.Fatalf("%+v", err)
}
var v Visitor
for _, doc := range f.Docs {
ast.Walk(&v, doc.Body)
}
expect := fmt.Sprintf("\n%+v\n", f)
if test.expect != expect {
tokens.Dump()
t.Fatalf("unexpected output: [%s] != [%s]", test.expect, expect)
}
t.Run(test.source, func(t *testing.T) {
tokens := lexer.Tokenize(test.source)
f, err := parser.Parse(tokens, 0)
if err != nil {
t.Fatalf("%+v", err)
}
var v Visitor
for _, doc := range f.Docs {
ast.Walk(&v, doc.Body)
}
expect := fmt.Sprintf("\n%+v\n", f)
if test.expect != expect {
tokens.Dump()
t.Fatalf("unexpected output: [%s] != [%s]", test.expect, expect)
}
})
}
}

Expand Down
59 changes: 39 additions & 20 deletions scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,27 +128,16 @@ func (s *Scanner) newLineCount(src []rune) int {
return cnt
}

func (s *Scanner) updateIndent(ctx *Context, c rune) {
if s.isFirstCharAtLine && s.isNewLineChar(c) && ctx.isDocument() {
return
}
if s.isFirstCharAtLine && c == ' ' {
s.indentNum++
return
}
if !s.isFirstCharAtLine {
s.indentState = IndentStateKeep
return
}

func (s *Scanner) updateIndentState(ctx *Context) {
indentNumBasedIndentState := s.indentState
if s.prevIndentNum < s.indentNum {
s.indentLevel = s.prevIndentLevel + 1
s.indentState = IndentStateUp
indentNumBasedIndentState = IndentStateUp
} else if s.prevIndentNum == s.indentNum {
s.indentLevel = s.prevIndentLevel
s.indentState = IndentStateEqual
indentNumBasedIndentState = IndentStateEqual
} else {
s.indentState = IndentStateDown
indentNumBasedIndentState = IndentStateDown
if s.prevIndentLevel > 0 {
s.indentLevel = s.prevIndentLevel - 1
}
Expand All @@ -157,18 +146,48 @@ func (s *Scanner) updateIndent(ctx *Context, c rune) {
if s.prevIndentColumn > 0 {
if s.prevIndentColumn < s.column {
s.indentState = IndentStateUp
} else if s.prevIndentColumn == s.column {
s.indentState = IndentStateEqual
} else {
} else if s.prevIndentColumn != s.column || indentNumBasedIndentState != IndentStateEqual {
// The following case ( current position is 'd' ), some variables becomes like here
// - prevIndentColumn: 1 of 'a'
// - indentNumBasedIndentState: IndentStateDown because d's indentNum(1) is less than c's indentNum(3).
// Therefore, s.prevIndentColumn(1) == s.column(1) is true, but we want to treat this as IndentStateDown.
// So, we look also current indentState value by the above prevIndentNum based logic, and determins finally indentState.
// ---
// a:
// b
// c
// d: e
// ^
s.indentState = IndentStateDown
} else {
s.indentState = IndentStateEqual
}
} else {
s.indentState = indentNumBasedIndentState
}
}

func (s *Scanner) updateIndent(ctx *Context, c rune) {
if s.isFirstCharAtLine && s.isNewLineChar(c) && ctx.isDocument() {
return
}
if s.isFirstCharAtLine && c == ' ' {
s.indentNum++
return
}
if !s.isFirstCharAtLine {
s.indentState = IndentStateKeep
return
}
s.updateIndentState(ctx)
s.isFirstCharAtLine = false
if s.isNeededKeepPreviousIndentNum(ctx, c) {
return
}
if s.indentState != IndentStateUp {
s.prevIndentColumn = 0
}
s.prevIndentNum = s.indentNum
s.prevIndentColumn = 0
s.prevIndentLevel = s.indentLevel
}

Expand Down

0 comments on commit 5fdf77f

Please sign in to comment.