/// <summary> /// Returns the Position after the last character in the file (including comments). /// Throws an ArgumentException is file does not have any content. /// </summary> public static Position End(this FileContentManager file) { if (file.NrLines() == 0) { throw new ArgumentException("file is empty", nameof(file)); } return(Position.Create(file.NrLines() - 1, file.GetLine(file.NrLines() - 1).Text.Length)); }
/// <summary> /// Computes excess bracket errors for the given range of lines in file based on the corresponding CodeLine. /// Throws an ArgumentOutOfRangeException if the range [start, start + count) is not within file. /// </summary> private static IEnumerable <Diagnostic> ComputeScopeDiagnostics(this FileContentManager file, int start, int count) { foreach (var line in file.GetLines(start, count)) { foreach (var pos in line.ExcessBracketPositions) { yield return(Errors.ExcessBracketError(file.FileName, Position.Create(start, pos))); } ++start; } }
/// <summary> /// Returns the Position right after where the last relevant (i.e. non-comment) code in the file ends, /// or the position (0,0) if no such line exists. /// Throws an ArgumentException if file does not contain any lines. /// </summary> private static Position LastInFile(FileContentManager file) { if (file.NrLines() == 0) { throw new ArgumentException("file is null or missing content", nameof(file)); } var endIndex = file.NrLines(); while (endIndex-- > 0 && file.GetLine(endIndex).WithoutEnding.Trim().Length == 0) { } return(endIndex < 0 ? Position.Zero : Position.Create(endIndex, file.GetLine(endIndex).WithoutEnding.Length)); }
/// <summary> /// Computes excess bracket errors for the given range of lines in file based on the corresponding CodeLine. /// </summary> /// <exception cref="ArgumentOutOfRangeException">The range [<paramref name="start"/>, <paramref name="start"/> + <paramref name="count"/>) is not within <paramref name="file"/>.</exception> private static IEnumerable <Diagnostic> ComputeScopeDiagnostics(this FileContentManager file, int start, int count) { foreach (var line in file.GetLines(start, count)) { foreach (var pos in line.ExcessBracketPositions) { yield return(Errors.ExcessBracketError(file.FileName, Position.Create(start, pos))); } foreach (var pos in line.ErrorDelimiterPositions) { yield return(Errors.InvalidCharacterInInterpolatedArgument(file.FileName, Position.Create(start, pos), file.GetLine(start).Text[pos])); } ++start; } }
// routines used to compute scope diagnostics updates /// <summary> /// Given the total number of excess closings in the file /// checks for both an unclosed scope and a missing string ending on lastLine, and adds the corresponding error(s) to updatedScopeErrors. /// Throws an ArgumentException if the number of lines in the file is zero. /// </summary> private static IEnumerable <Diagnostic> CheckForMissingClosings(this FileContentManager file) { if (file.NrLines() == 0) { throw new ArgumentException("the number of lines in a file can never be zero"); } var lastLine = file.GetLine(file.NrLines() - 1); if (lastLine.FinalIndentation() > 0) { yield return(Errors.MissingClosingBracketError(file.FileName, Position.Create(file.NrLines() - 1, lastLine.Text.Length))); } if (ContinueString(lastLine)) { yield return(Errors.MissingStringDelimiterError(file.FileName, Position.Create(file.NrLines() - 1, lastLine.Text.Length))); } }
static int MoveNextLine(ref Position position) { position = Position.Create(position.Line + 1, position.Column); return(position.Line); }