namespace Ink { /// <summary> /// Pre-pass before main ink parser runs. It actually performs two main tasks: /// - comment elimination to simplify the parse rules in the main parser /// - Conversion of Windows line endings (\r\n) to the simpler Unix style (\n), so /// we don't have to worry about them later. /// </summary> public class CommentEliminator : StringParser { public CommentEliminator (string input) : base(input) { } public string Process() { // Make both comments and non-comments optional to handle trivial empty file case (or *only* comments) var stringList = Interleave<string>(Optional (CommentsAndNewlines), Optional(MainInk)); if (stringList != null) { return string.Join("", stringList.ToArray()); } else { return null; } } string MainInk() { return ParseUntil (CommentsAndNewlines, _commentOrNewlineStartCharacter, null); } string CommentsAndNewlines() { var newlines = Interleave<string> (Optional (ParseNewline), Optional (ParseSingleComment)); if (newlines != null) { return string.Join ("", newlines.ToArray()); } else { return null; } } // Valid comments always return either an empty string or pure newlines, // which we want to keep so that line numbers stay the same string ParseSingleComment() { return (string) OneOf (EndOfLineComment, BlockComment); } string EndOfLineComment() { if (ParseString ("//") == null) { return null; } ParseUntilCharactersFromCharSet (_newlineCharacters); return ""; } string BlockComment() { if (ParseString ("/*") == null) { return null; } int startLineIndex = lineIndex; var commentResult = ParseUntil (String("*/"), _commentBlockEndCharacter, null); if (!endOfInput) { ParseString ("*/"); } // Count the number of lines that were inside the block, and replicate them as newlines // so that the line indexing still works from the original source if (commentResult != null) { return new string ('\n', lineIndex - startLineIndex); } // No comment at all else { return null; } } CharacterSet _commentOrNewlineStartCharacter = new CharacterSet ("/\r\n"); CharacterSet _commentBlockEndCharacter = new CharacterSet("*"); CharacterSet _newlineCharacters = new CharacterSet ("\n\r"); } }