Add support for unquoted config strings that start with number

Signed-off-by: Waldemar Quevedo <wally@synadia.com>
This commit is contained in:
Waldemar Quevedo
2019-01-31 16:40:06 -08:00
parent 457c442198
commit 47055eddef
2 changed files with 97 additions and 11 deletions

View File

@@ -547,7 +547,7 @@ func lexValue(lx *lexer) stateFn {
return lexBlock
case unicode.IsDigit(r):
lx.backup() // avoid an extra state and use the same as above
return lexNumberOrDateOrIPStart
return lexNumberOrDateOrStringOrIPStart
case r == '.': // special error case, be kind to users
return lx.errorf("Floats must start with a digit")
case isNL(r):
@@ -948,9 +948,11 @@ func lexStringBinary(lx *lexer) stateFn {
return lx.stringStateFn
}
// lexNumberOrDateStart consumes either a (positive) integer, a float, a datetime, or IP.
// It assumes that NO negative sign has been consumed, that is triggered above.
func lexNumberOrDateOrIPStart(lx *lexer) stateFn {
// lexNumberOrDateOrStringOrIPStart consumes either a (positive)
// integer, a float, a datetime, or IP, or String that started with a
// number. It assumes that NO negative sign has been consumed, that
// is triggered above.
func lexNumberOrDateOrStringOrIPStart(lx *lexer) stateFn {
r := lx.next()
if !unicode.IsDigit(r) {
if r == '.' {
@@ -958,11 +960,13 @@ func lexNumberOrDateOrIPStart(lx *lexer) stateFn {
}
return lx.errorf("Expected a digit but got '%v'.", r)
}
return lexNumberOrDateOrIP
return lexNumberOrDateOrStringOrIP
}
// lexNumberOrDateOrIP consumes either a (positive) integer, float, datetime or IP.
func lexNumberOrDateOrIP(lx *lexer) stateFn {
// lexNumberOrDateOrStringOrIP consumes either a (positive) integer,
// float, datetime, IP or string without quotes that starts with a
// number.
func lexNumberOrDateOrStringOrIP(lx *lexer) stateFn {
r := lx.next()
switch {
case r == '-':
@@ -971,13 +975,17 @@ func lexNumberOrDateOrIP(lx *lexer) stateFn {
}
return lexDateAfterYear
case unicode.IsDigit(r):
return lexNumberOrDateOrIP
return lexNumberOrDateOrStringOrIP
case r == '.':
return lexFloatStart // Assume float at first, but could be IP
// Assume float at first, but could be IP
return lexFloatStart
case isNumberSuffix(r):
return lexConvenientNumber
case !(isNL(r) || r == eof || r == mapEnd || r == optValTerm || r == mapValTerm || isWhitespace(r) || unicode.IsDigit(r)):
// Treat it as a string value once we get a rune that
// is not a number.
return lexString
}
lx.backup()
lx.emit(itemInteger)
return lx.pop()

View File

@@ -87,6 +87,84 @@ func TestComplexStringValues(t *testing.T) {
expect(t, lx, expectedItems)
}
func TestStringStartingWithNumber(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "3xyz", 1, 6},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = 3xyz`)
expect(t, lx, expectedItems)
lx = lex(`foo = 3xyz,`)
expect(t, lx, expectedItems)
lx = lex(`foo = 3xyz;`)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 2, 9},
{itemString, "3xyz", 2, 15},
{itemEOF, "", 2, 0},
}
content := `
foo = 3xyz
`
lx = lex(content)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "map", 2, 9},
{itemMapStart, "", 2, 14},
{itemKey, "foo", 3, 11},
{itemString, "3xyz", 3, 17},
{itemMapEnd, "", 3, 22},
{itemEOF, "", 2, 0},
}
content = `
map {
foo = 3xyz}
`
lx = lex(content)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "map", 2, 9},
{itemMapStart, "", 2, 14},
{itemKey, "foo", 3, 11},
{itemString, "3xyz", 3, 17},
{itemMapEnd, "", 4, 10},
{itemEOF, "", 2, 0},
}
content = `
map {
foo = 3xyz;
}
`
lx = lex(content)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "map", 2, 9},
{itemMapStart, "", 2, 14},
{itemKey, "foo", 3, 11},
{itemString, "3xyz", 3, 17},
{itemKey, "bar", 4, 11},
{itemString, "4wqs", 4, 17},
{itemMapEnd, "", 5, 10},
{itemEOF, "", 2, 0},
}
content = `
map {
foo = 3xyz,
bar = 4wqs
}
`
lx = lex(content)
expect(t, lx, expectedItems)
}
func TestBinaryString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
@@ -380,7 +458,7 @@ func TestRawString(t *testing.T) {
}
lx := lex("foo = bar")
expect(t, lx, expectedItems)
lx = lex(`foo = bar' `) //'single-quote for emacs TODO: Remove me
lx = lex(`foo = bar' `)
expect(t, lx, expectedItems)
}