Repository: BurntSushi/toml
Pull request #303 (2021-06-24 05:59:50)

Multiline strings ending in 6 or more quotes should fail
For example:

	x = ''' too many quotes! ''''''
	x = """ too many quotes! """"""


Patch:
diff --git a/go.mod b/go.mod
index 4b6ff5d..7a6fd52 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,4 @@ module github.com/BurntSushi/toml
 
 go 1.13
 
-require github.com/BurntSushi/toml-test v0.1.1-0.20210621044449-d531a008d555
+require github.com/BurntSushi/toml-test v0.1.1-0.20210624055653-1f6389604dc6
diff --git a/go.sum b/go.sum
index aa93a9e..4af5daf 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,6 @@
 github.com/BurntSushi/toml v0.3.2-0.20210614224209-34d990aa228d/go.mod h1:2QZjSXA5e+XyFeCAxxtL8Z4StYUsTquL8ODGPR3C3MA=
 github.com/BurntSushi/toml v0.3.2-0.20210621044154-20a94d639b8e/go.mod h1:t4zg8TkHfP16Vb3x4WKIw7zVYMit5QFtPEO8lOWxzTg=
 github.com/BurntSushi/toml-test v0.1.1-0.20210620192437-de01089bbf76/go.mod h1:P/PrhmZ37t5llHfDuiouWXtFgqOoQ12SAh9j6EjrBR4=
-github.com/BurntSushi/toml-test v0.1.1-0.20210621044449-d531a008d555 h1:oNF2vOuH05dfefEw1E/x5wf6LRu98Wb9dzITyLYfrhc=
-github.com/BurntSushi/toml-test v0.1.1-0.20210621044449-d531a008d555/go.mod h1:UAIt+Eo8itMZAAgImXkPGDMYsT1SsJkVdB5TuONl86A=
+github.com/BurntSushi/toml-test v0.1.1-0.20210624055653-1f6389604dc6 h1:hRkQ1B9Jtdssyzo0Cr3EgS2WMwPscGNrCDNCeYshAQA=
+github.com/BurntSushi/toml-test v0.1.1-0.20210624055653-1f6389604dc6/go.mod h1:UAIt+Eo8itMZAAgImXkPGDMYsT1SsJkVdB5TuONl86A=
 zgo.at/zli v0.0.0-20210619044753-e7020a328e59/go.mod h1:HLAc12TjNGT+VRXr76JnsNE3pbooQtwKWhX+RlDjQ2Y=
diff --git a/lex.go b/lex.go
index ce1fae5..adc4eb5 100644
--- a/lex.go
+++ b/lex.go
@@ -174,7 +174,7 @@ func (lx *lexer) ignore() {
 	lx.start = lx.pos
 }
 
-// backup steps back one rune. Can be called only twice between calls to next.
+// backup steps back one rune. Can be called 4 times between calls to next.
 func (lx *lexer) backup() {
 	if lx.atEOF {
 		lx.atEOF = false
@@ -670,20 +670,28 @@ func lexMultilineString(lx *lexer) stateFn {
 	case '\\':
 		return lexMultilineStringEscape
 	case stringEnd:
+		/// Found " → try to read two more "".
 		if lx.accept(stringEnd) {
 			if lx.accept(stringEnd) {
-				// Can end in quote: """str""""
+				/// Peek ahead: the string can contain " and "", including at the
+				/// end: """str"""""
+				/// 6 or more at the end, however, is an error.
 				if lx.peek() == stringEnd {
+					/// Check if we already lexed 5 's; if so we have 6 now, and
+					/// that's just too many man!
+					if strings.HasSuffix(lx.current(), `"""""`) {
+						return lx.errorf(`unexpected '""""""'`)
+					}
 					lx.backup()
 					lx.backup()
 					return lexMultilineString
 				}
 
-				lx.backup()
+				lx.backup() /// backup: don't include the """ in the item.
 				lx.backup()
 				lx.backup()
 				lx.emit(itemMultilineString)
-				lx.next()
+				lx.next() /// Read over ''' again and discard it.
 				lx.next()
 				lx.next()
 				lx.ignore()
@@ -734,19 +742,28 @@ func lexMultilineRawString(lx *lexer) stateFn {
 		}
 		return lexMultilineRawString
 	case rawStringEnd:
+		/// Found ' → try to read two more ''.
 		if lx.accept(rawStringEnd) {
 			if lx.accept(rawStringEnd) {
-				// Can end in quote: '''str''''
+				/// Peek ahead: the string can contain ' and '', including at the
+				/// end: '''str'''''
+				/// 6 or more at the end, however, is an error.
 				if lx.peek() == rawStringEnd {
+					/// Check if we already lexed 5 's; if so we have 6 now, and
+					/// that's just too many man!
+					if strings.HasSuffix(lx.current(), "'''''") {
+						return lx.errorf(`unexpected "''''''"`)
+					}
 					lx.backup()
 					lx.backup()
 					return lexMultilineRawString
 				}
-				lx.backup()
+
+				lx.backup() /// backup: don't include the ''' in the item.
 				lx.backup()
 				lx.backup()
 				lx.emit(itemRawMultilineString)
-				lx.next()
+				lx.next() /// Read over ''' again and discard it.
 				lx.next()
 				lx.next()
 				lx.ignore()


Test patch:
diff --git a/toml_test.go b/toml_test.go
index 17dff47..ad7b4e6 100644
--- a/toml_test.go
+++ b/toml_test.go
@@ -57,8 +57,6 @@ func TestToml(t *testing.T) {
 				"valid/datetime-local",
 				"valid/array-mix-string-table",
 				"valid/inline-table-nest",
-
-				"invalid/string-literal-multiline-quotes",
 			},
 		}