diff --git a/pkg/dsl/lexer/lexer.go b/pkg/dsl/lexer/lexer.go index 5a8b38fe4..055a9eed8 100644 --- a/pkg/dsl/lexer/lexer.go +++ b/pkg/dsl/lexer/lexer.go @@ -212,6 +212,11 @@ func (l *Lexer) lexString() string { if l.ch == '\\' { str += l.input[position:l.position] l.readChar() // Skip the backslash + if l.ch == 0 { + // Backslash at end of input (unterminated escape); stop before + // position runs past the input. + break + } switch l.ch { case 'n': str += "\n" diff --git a/pkg/dsl/lexer/lexer_test.go b/pkg/dsl/lexer/lexer_test.go index 969054738..8fc3ad6b6 100644 --- a/pkg/dsl/lexer/lexer_test.go +++ b/pkg/dsl/lexer/lexer_test.go @@ -1189,4 +1189,13 @@ rule test_rule(created_at time, started_at time) { Expect(hasBoolean).Should(BeTrue()) Expect(hasComparison).Should(BeTrue()) }) + + It("Unterminated string ending in a backslash does not panic", func() { + // A quote followed by a trailing backslash reaches EOF mid-escape. + l := NewLexer("\"\\") + + var tok token.Token + Expect(func() { tok = l.NextToken() }).ShouldNot(Panic()) + Expect(tok.Type).Should(BeEquivalentTo(token.STRING)) + }) })