/// <summary> /// Returns true if the given <paramref name="node"/> does not ends with a semicolon. /// </summary> public static bool IsSemicolonMissingAfter(INode node, TextSource text, out int position) { position = -1; if (!s_syntaxKindsToAnalyzer.Contains(node.Kind)) { return(false); } var charPosition = node.End - 1; var charCodeAtPosition = text.CharCodeAt(charPosition); if (charCodeAtPosition != CharacterCodes.Semicolon) { // When files are parsed while preserving whitespace, the semicolon might be followed by whitespace characters which is ok. // We therefore have to walk back until the first non-whitespace character. while (true) { if (!Scanner.IsLineBreak(charCodeAtPosition) && !Scanner.IsWhiteSpace(charCodeAtPosition)) { break; } charPosition--; if (charPosition == 0) { break; } charCodeAtPosition = text.CharCodeAt(charPosition); if (charCodeAtPosition == CharacterCodes.Semicolon) { // This node is fine return(false); } } position = charPosition; return(true); } return(false); }
/// <summary> /// Computes a map with line breaks. /// </summary> /// <remarks> /// This is heavyweight computation and the result of it definitely should be cached to avoid perf impact. /// </remarks> public static int[] ComputeLineStarts(TextSource text) { List <int> result = new List <int>(); var pos = 0; var lineStart = 0; while (pos < text.Length) { var ch = text.CharCodeAt(pos++); switch (ch) { case CharacterCodes.CarriageReturn: if (text.CharCodeAt(pos) == CharacterCodes.LineFeed) { pos++; } goto case CharacterCodes.LineFeed; case CharacterCodes.LineFeed: result.Add(lineStart); lineStart = pos; break; default: if (ch > CharacterCodes.MaxAsciiCharacter && Scanner.IsLineBreak(ch)) { result.Add(lineStart); lineStart = pos; } break; } } result.Add(lineStart); return(result.ToArray()); }