using System; using System.Collections.Generic; using CodeStatistics.Handling.Languages.Java.Utils; using System.Linq; using CodeStatisticsCore.Handling.Utils; namespace CodeStatistics.Handling.Languages.Java{ public class JavaCodeBlockParser : CodeParser{ private static readonly string[] ParsedKeywords = { "if", "else", "for", "while", "do", "switch", "case", "default", "try", "catch", "finally", "return", "break", "continue" }; private static readonly HashSet<char> ParsedKeywordStarts = new HashSet<char>(ParsedKeywords.Select(str => str[0]).Distinct().ToList()); private static readonly Predicate<char> IsKeywordStart = ParsedKeywordStarts.Contains; private int prevCursor; public JavaCodeBlockParser(string code) : base(code){ IsWhiteSpace = JavaCharacters.IsWhiteSpace; IsIdentifierStart = JavaCharacters.IsIdentifierStart; IsIdentifierPart = JavaCharacters.IsIdentifierPart; IsValidIdentifier = str => str.Length > 0; } public override CodeParser Clone(string newCode = null){ return new JavaCodeBlockParser(newCode ?? string.Empty); } /// <summary> /// Goes back to the last cursor position before calling <see cref="ReadNextKeywordSkip"/>. Returns itself. /// </summary> public JavaCodeBlockParser RevertKeywordSkip(){ cursor = prevCursor; return this; } /// <summary> /// Skips until it hits a valid keyword surrounded by non-identifier characters. The cursor is placed right after the keyword. /// If no keyword is found, the cursor does not move and the method returns <see cref="string.Empty"/>, otherwise it returns the keyword. /// </summary> public string ReadNextKeywordSkip(){ prevCursor = cursor; while(!IsEOF){ if (IsKeywordStart(Char) && (cursor == 0 || !IsIdentifierPart(code[cursor-1]))){ string identifier = ReadIdentifier(); if (identifier.Length > 0 && ParsedKeywords.Contains(identifier))return identifier; } Skip(); } cursor = prevCursor; return string.Empty; } } }