Repository: BurntSushi/toml
Pull request #286 (2021-06-10 17:38:05)

Some better errors on EOF
This:

	unexpected EOF; expected key separator '='

Is rather nicer than:

	expected value but found '\x00' instead


Patch:
diff --git a/lex.go b/lex.go
index 246912b..47def13 100644
--- a/lex.go
+++ b/lex.go
@@ -388,6 +388,8 @@ func lexBareKey(lx *lexer) stateFn {
 		lx.backup()
 		lx.emit(itemText)
 		return lexKeyEnd
+	case r == eof:
+		return lx.errorf("unexpected EOF; expected key separator '='")
 	default:
 		return lx.errorf("bare keys cannot contain %q", r)
 	}
@@ -401,6 +403,8 @@ func lexKeyEnd(lx *lexer) stateFn {
 		return lexSkip(lx, lexValue)
 	case isWhitespace(r):
 		return lexSkip(lx, lexKeyEnd)
+	case r == eof:
+		return lx.errorf("unexpected EOF; expected key separator %q", keySep)
 	default:
 		return lx.errorf("expected key separator %q, but got %q instead",
 			keySep, r)
@@ -463,6 +467,9 @@ func lexValue(lx *lexer) stateFn {
 		lx.backup()
 		return lexBool
 	}
+	if r == eof {
+		return lx.errorf("unexpected EOF; expected value")
+	}
 	return lx.errorf("expected value but found %q instead", r)
 }
 
@@ -579,7 +586,7 @@ func lexString(lx *lexer) stateFn {
 	r := lx.next()
 	switch {
 	case r == eof:
-		return lx.errorf("unexpected EOF")
+		return lx.errorf(`unexpected EOF; expected '"'`)
 	case isNL(r):
 		return lx.errorf("strings cannot contain newlines")
 	case r == '\\':
@@ -600,7 +607,7 @@ func lexString(lx *lexer) stateFn {
 func lexMultilineString(lx *lexer) stateFn {
 	switch lx.next() {
 	case eof:
-		return lx.errorf("unexpected EOF")
+		return lx.errorf(`unexpected EOF; expected '"""'`)
 	case '\\':
 		return lexMultilineStringEscape
 	case stringEnd:
@@ -628,7 +635,7 @@ func lexRawString(lx *lexer) stateFn {
 	r := lx.next()
 	switch {
 	case r == eof:
-		return lx.errorf("unexpected EOF")
+		return lx.errorf(`unexpected EOF; expected "'"`)
 	case isNL(r):
 		return lx.errorf("strings cannot contain newlines")
 	case r == rawStringEnd:
@@ -647,7 +654,7 @@ func lexRawString(lx *lexer) stateFn {
 func lexMultilineRawString(lx *lexer) stateFn {
 	switch lx.next() {
 	case eof:
-		return lx.errorf("unexpected EOF")
+		return lx.errorf(`unexpected EOF; expected "'''"`)
 	case rawStringEnd:
 		if lx.accept(rawStringEnd) {
 			if lx.accept(rawStringEnd) {


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 7cecffd..d18bff4 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -989,17 +989,14 @@ func TestDecodeErrors(t *testing.T) {
 		wantErr string
 		lastKey bool
 	}{
-		{`x="`, "unexpected EOF", true},
-		{`x='`, "unexpected EOF", true},
-		{`x='''`, "unexpected EOF", true},
-
-		// TODO: Improve these
-		// {"x = ", "X", false},            // expected value but found '\x00' instead
-		// {"x = \n", "X", false},          // Near line 1 (last key parsed 'abc'): expected value but found '\n' instead
-		// {"x = \nzxc = 1\n", "X", false}, // Near line 1 (last key parsed 'abc'): expected value but found '\n' instead
-		// {`x  `, "X", false},             // expected key separator '=', but got '\x00' instead
-		// {`x`, "X", false},               // Near line 0 (last key parsed ''): bare keys cannot contain '\x00'
-		// {"x\n", "X", false},             // Near line 0 (last key parsed ''): bare keys cannot contain '\n'
+		{`x`, "unexpected EOF; expected key separator '='", false},
+		{`x  `, "unexpected EOF; expected key separator '='", true},
+		{`x="`, `unexpected EOF; expected '"'`, true},
+		{`x="""`, `unexpected EOF; expected '"""'`, true},
+		{`x='`, `unexpected EOF; expected "'"`, true},
+		{`x='''`, `unexpected EOF; expected "'''"`, true},
+		{"x = ", "unexpected EOF; expected value", true},
+		{"x = \n", "expected value but found '\\n' instead", true},
 
 		// Cases found by fuzzing in #155
 		{`""` + "\ufffd", "expected key separator", false}, // used to panic with index out of range