From 30a4181ceebb5bcee13e62a6539d8253af8a536e Mon Sep 17 00:00:00 2001 From: tacosontitan Date: Mon, 25 Nov 2024 22:32:00 -0600 Subject: [PATCH] Add support for capturing comments in JSON. --- src/Pasper.Json/Parsing/JsonLexer.cs | 33 +++++++++++++++++++ .../Parsing/JsonLexer/TryGetNextToken.cs | 13 ++++++++ 2 files changed, 46 insertions(+) diff --git a/src/Pasper.Json/Parsing/JsonLexer.cs b/src/Pasper.Json/Parsing/JsonLexer.cs index cda82c6..7f5c74a 100644 --- a/src/Pasper.Json/Parsing/JsonLexer.cs +++ b/src/Pasper.Json/Parsing/JsonLexer.cs @@ -71,6 +71,9 @@ private bool TryGetNextToken([NotNullWhen(true)] out IToken? token) if (TryGetStringToken(out token)) return true; + if (TryGetSingleLineCommentToken(out token)) + return true; + throw new UnexpectedTokenException(_lineNumber, _columnNumber, currentCharacter.ToString()); } @@ -129,4 +132,34 @@ private bool TryGetStringToken([NotNullWhen(true)] out IToken? token) _currentIndex = endIndex + 1; return true; } + + private bool TryGetSingleLineCommentToken([NotNullWhen(true)] out IToken? token) + { + if (json[_currentIndex] != '/') + { + token = null; + return false; + } + + var nextToken = json[_currentIndex + 1]; + if (nextToken is not '/') + { + token = null; + return false; + } + + // Single line comments can technically be placed on the final line of the specified + // input. The lexer accounts for this by assuming that if no line breaks are detected + // after the start of a comment, that the comment goes to the end of the input. + var startIndex = _currentIndex + 2; + var endIndex = json.IndexOf('\n', startIndex); + if (endIndex == -1) + endIndex = json.Length; + + var value = json.Substring(startIndex, endIndex - startIndex); + token = new CommentToken(value.Trim()); + _currentIndex = endIndex + 1; + _columnNumber += value.Length + 2; + return true; + } } \ No newline at end of file diff --git a/test/Pasper.Json.Tests/Parsing/JsonLexer/TryGetNextToken.cs b/test/Pasper.Json.Tests/Parsing/JsonLexer/TryGetNextToken.cs index 3d417b9..0f45dfe 100644 --- a/test/Pasper.Json.Tests/Parsing/JsonLexer/TryGetNextToken.cs +++ b/test/Pasper.Json.Tests/Parsing/JsonLexer/TryGetNextToken.cs @@ -44,4 +44,17 @@ public void TryGetNextToken_EndObjectDetected_ReturnsTrue() Assert.NotNull(lexer.Current); Assert.IsType(lexer.Current); } + + [Fact] + public void TryGetNextToken_CommentDetected_ReturnsTrue() + { + const string comment = "this is a comment"; + const string testJson = $"// {comment}"; + var lexer = new JsonLexer(testJson); + var tokenAvailable = lexer.MoveNext(); + Assert.True(tokenAvailable); + Assert.NotNull(lexer.Current); + Assert.IsType(lexer.Current); + Assert.Equal(comment, lexer.Current.Value); + } } \ No newline at end of file