Skip to content

Commit

Permalink
fixed parsing unquoted strings inside the arrays, fixes #33
Browse files Browse the repository at this point in the history
  • Loading branch information
gurkankaymak committed Dec 19, 2022
1 parent d921461 commit b8644ed
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 9 deletions.
2 changes: 1 addition & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ type Int int
// Type Number
func (i Int) Type() Type { return NumberType }
func (i Int) String() string { return strconv.Itoa(int(i)) }
func (i Int) isConcatenable() bool { return false }
func (i Int) isConcatenable() bool { return true }

// Float32 represents a Float32 value
type Float32 float32
Expand Down
47 changes: 45 additions & 2 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,25 @@ func (p *parser) checkAndConcatenate(object Object, key string) (bool, error) {
return false, nil
}

func (p *parser) checkConcatenation(lastValue Value) (Value, error) {
if lastValue.isConcatenable() && p.isTokenConcatenable(p.scanner.TokenText(), p.scanner.Peek()) {
lastConsumedWhitespaces := p.lastConsumedWhitespaces

value, err := p.extractValue()
if err != nil {
return nil, err
}

if lastValue.Type() == ConcatenationType {
return append(lastValue.(concatenation), String(lastConsumedWhitespaces), value), nil
} else {
return concatenation{lastValue, String(lastConsumedWhitespaces), value}, nil
}
}

return nil, nil
}

func (p *parser) extractArray() (Array, error) {
if firstToken := p.scanner.TokenText(); firstToken != arrayStartToken {
return nil, invalidArrayError(fmt.Sprintf("%q is not an array start token", firstToken), p.scanner.Line, p.scanner.Column)
Expand Down Expand Up @@ -563,11 +582,35 @@ func (p *parser) extractArray() (Array, error) {
return nil, err
}

array = append(array, value)
//array = append(array, value)
token = p.scanner.TokenText()

if p.scanner.Line == lastRow && token != commaToken && token != arrayEndToken {
return nil, missingCommaError(p.scanner.Line, p.scanner.Column)
if isUnquotedString(token) {
concatenatedValue, err := p.checkConcatenation(value)
if err != nil {
return nil, err
}
lastValue := concatenatedValue
token = p.scanner.TokenText()
for concatenatedValue != nil && isUnquotedString(token) && token != commaToken && token != arrayEndToken {
concatenatedValue, err = p.checkConcatenation(lastValue)
if err != nil {
return nil, err
}
if concatenatedValue != nil {
lastValue = concatenatedValue
} else {
break
}
token = p.scanner.TokenText()
}
array = append(array, lastValue)
} else {
return nil, missingCommaError(p.scanner.Line, p.scanner.Column)
}
} else {
array = append(array, value)
}

if p.scanner.TokenText() == commaToken {
Expand Down
58 changes: 52 additions & 6 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ func TestExtractObject(t *testing.T) {
t.Run("return missingCommaError if there is no comma or ASCII newline between the object elements", func(t *testing.T) {
parser := newParser(strings.NewReader("{a:1 b:2}"))
parser.advance()
expectedError := missingCommaError(1, 6)
expectedError := missingCommaError(1, 7)
got, err := parser.extractObject()
assertError(t, err, expectedError)
assertNil(t, got)
Expand Down Expand Up @@ -1054,6 +1054,14 @@ func TestExtractArray(t *testing.T) {
assertNil(t, got)
})

t.Run("extract the array successfully if it contains an unquoted string value", func(t *testing.T) {
parser := newParser(strings.NewReader("[example.com]"))
parser.advance()
got, err := parser.extractArray()
assertNoError(t, err)
assertDeepEqual(t, got, Array{concatenation{String("example"), String(""), String("."), String(""), String("com")}})
})

t.Run("return invalidArrayError if the closing parenthesis is missing", func(t *testing.T) {
parser := newParser(strings.NewReader("[1"))
parser.advance()
Expand All @@ -1063,10 +1071,10 @@ func TestExtractArray(t *testing.T) {
assertNil(t, got)
})

t.Run("return missingCommaError if there is no comma or ASCII newline between the array elements", func(t *testing.T) {
parser := newParser(strings.NewReader("[1 2]"))
t.Run("return missingCommaError if there is no comma or ASCII newline between the array elements and elements separated with a forbidden character", func(t *testing.T) {
parser := newParser(strings.NewReader("[1@2]"))
parser.advance()
expectedError := missingCommaError(1, 4)
expectedError := missingCommaError(1, 3)
got, err := parser.extractArray()
assertError(t, err, expectedError)
assertNil(t, got)
Expand Down Expand Up @@ -1489,9 +1497,9 @@ func TestCheckAndConcatenate(t *testing.T) {
})

t.Run("return false if the value with the given is not concatenable", func(t *testing.T) {
parser := newParser(strings.NewReader("a:1 bb"))
parser := newParser(strings.NewReader("a:1s bb"))
advanceScanner(t, parser, "bb")
got, err := parser.checkAndConcatenate(Object{"a": Int(1)}, "a")
got, err := parser.checkAndConcatenate(Object{"a": Duration(1)}, "a")
assertNoError(t, err)
assertEquals(t, got, false)
})
Expand Down Expand Up @@ -1536,3 +1544,41 @@ func TestCheckAndConcatenate(t *testing.T) {
assertEquals(t, object.String(), expected.String())
})
}

func TestCheckConcatenation(t *testing.T) {
t.Run("return nil if the value with the given is not concatenable", func(t *testing.T) {
parser := newParser(strings.NewReader("[1s bb]"))
advanceScanner(t, parser, "bb")
got, err := parser.checkConcatenation(Array{Duration(1)})
assertNoError(t, err)
assertNil(t, got)
})

t.Run("return nil if the current token is not concatenable", func(t *testing.T) {
parser := newParser(strings.NewReader("[abc 1s]"))
advanceScanner(t, parser, "1")
got, err := parser.checkConcatenation(Array{String("abc")})
assertNoError(t, err)
assertNil(t, got)
})

t.Run("concatenate the value to the previous value if the previous one is a concatenation", func(t *testing.T) {
parser := newParser(strings.NewReader("[aa bb cc]"))
advanceScanner(t, parser, "cc")
whitespace := parser.lastConsumedWhitespaces
a := concatenation{String("aa"), String(whitespace), String("bb")}
got, err := parser.checkConcatenation(a)
assertNoError(t, err)
expected := concatenation{String("aa"), String(whitespace), String("bb"), String(whitespace), String("cc")}
assertDeepEqual(t, got, expected)
})

t.Run("create a concatenation with the value and the previous value if the previous one is not a concatenation", func(t *testing.T) {
parser := newParser(strings.NewReader("[aa bb]"))
advanceScanner(t, parser, "bb")
got, err := parser.checkConcatenation(String("aa"))
assertNoError(t, err)
expected := concatenation{String("aa"), String(" "), String("bb")}
assertEquals(t, got.String(), expected.String())
})
}

0 comments on commit b8644ed

Please sign in to comment.