diff --git a/Lexer.Tests/MLexerShould.cs b/Lexer.Tests/MLexerShould.cs index cae3b18..603241f 100644 --- a/Lexer.Tests/MLexerShould.cs +++ b/Lexer.Tests/MLexerShould.cs @@ -226,6 +226,16 @@ namespace Lexer.Tests Assert.AreEqual("just a 'string'", tokens[0].PureToken.Value); } + [Test] + public void ParseDoubleQuotedStringLiteralWithEscapedQuotes() + { + var sut = CreateLexer("\"just a \"\"string\"\"\""); + var tokens = sut.ParseAll(); + Assert.AreEqual(2, tokens.Count); + Assert.AreEqual(TokenKind.DoubleQuotedStringLiteral, tokens[0].Kind); + Assert.AreEqual("just a \"string\"", tokens[0].PureToken.Value); + } + [Test] public void ParseNumberStartingWithDot() { diff --git a/Lexer/MLexer.cs b/Lexer/MLexer.cs index 904d684..461d18f 100644 --- a/Lexer/MLexer.cs +++ b/Lexer/MLexer.cs @@ -406,14 +406,38 @@ namespace Lexer { Window.ConsumeChar(); var n = 0; - while (Window.PeekChar(n) != '"') + var pieces = new List(); + while (true) { + if (Window.PeekChar(n) == '"') + { + if (Window.PeekChar(n + 1) == '"') + { + var piece = Window.GetAndConsumeChars(n); + pieces.Add(piece); + Window.ConsumeChar(); + Window.ConsumeChar(); + pieces.Add("\""); + n = -1; + } + else + { + break; + } + } + if (IsEolOrEof(Window.PeekChar(n))) + { + throw new ParsingException("Unfinished double-quoted string literal."); + } + n++; } - var literal = Window.GetAndConsumeChars(n); + var lastPiece = Window.GetAndConsumeChars(n); + pieces.Add(lastPiece); + var total = string.Join("", pieces); Window.ConsumeChar(); - return PureTokenFactory.CreateDoubleQuotedStringLiteral(literal); + return PureTokenFactory.CreateDoubleQuotedStringLiteral(total); } private PureToken ContinueParsingUnquotedStringLiteral() diff --git a/Lexer/PureTokenFactory.cs b/Lexer/PureTokenFactory.cs index 73373b5..4fc0757 100644 --- a/Lexer/PureTokenFactory.cs +++ b/Lexer/PureTokenFactory.cs @@ -88,9 +88,14 @@ return new PureToken(TokenKind.StringLiteral, "'" + EscapeStringLiteral(s) + "'", s, Window.Position); } + private string EscapeDoubleQuotedStringLiteral(string s) + { + return s.Replace("\"", "\"\""); + } + public PureToken CreateDoubleQuotedStringLiteral(string s) { - return new PureToken(TokenKind.DoubleQuotedStringLiteral, "\"" + s + "\"", s, Window.Position); + return new PureToken(TokenKind.DoubleQuotedStringLiteral, "\"" + EscapeDoubleQuotedStringLiteral(s) + "\"", s, Window.Position); } public PureToken CreateUnquotedStringLiteral(string s)