/// <summary>
        /// Resolves the include statements in the given document.
        /// </summary>
        /// <param name="document"></param>
        /// <returns></returns>
        public static VirtualDocument Resolve( VirtualDocument document )
        {
            // We'll build a dictionary of replacement actions to perform them after initial enumeration
              Dictionary<VirtualDocument.Line, VirtualDocument> substitutions = new Dictionary<VirtualDocument.Line, VirtualDocument>();

              // Try to find lines that start with optional whitespace and then an #include statement
              foreach( VirtualDocument.Line line in document.Lines ) {
            if( line.VirtualLine.Trim().StartsWith( Keywords.PreProcessInclude ) ) {
              // Grab the file name from the statement
              string filename = ExtractFilename( line );
              if( !File.Exists( filename ) ) {
            throw new ParserException( string.Format( "Given include file '{0}' does not exist.", filename ), line );
              }
              Log.InfoFormat( "Including '{0}'.", filename );

              // Remember this substitution
              substitutions.Add( line, VirtualDocument.FromFile( filename ) );
            }
              }

              // Perform substitutions
              foreach( KeyValuePair<VirtualDocument.Line, VirtualDocument> substitution in substitutions ) {
            document.SubstituteLine( substitution.Key, substitution.Value );
              }
              document.UpdateVirtualLineCount();

              return document;
        }
        /// <summary>
        /// Construct a new virtual document from a subsection of another virtual document.
        /// Assumes begin &lt; end
        /// </summary>
        /// <param name="document"></param>
        /// <param name="begin">The character that marks the beginning of the new, virtual document.</param>
        /// <param name="end">The character that marks the end of the new, virtual document.</param>
        /// <returns></returns>
        public static VirtualDocument FromDocument( VirtualDocument document, Character begin, Character end )
        {
            // Store references to lines.
              Line first = begin.ParentLine;
              Line last  = end.ParentLine;

              VirtualDocument section = new VirtualDocument();

              // Find the index of the lines within the document.
              int firstLineIndex = document.Lines.FindIndex( l => l.Characters == first.Characters );
              int lastLineIndex = document.Lines.FindIndex( l => l.Characters == last.Characters );
              Debug.Assert( firstLineIndex != -1 && lastLineIndex != -1 );

              // Clone the lines into the new document
              foreach( Line line in document.Lines.GetRange( firstLineIndex, lastLineIndex - firstLineIndex + 1 ) ) {
            section.Lines.Add( (Line)line.Clone() );
              }
              // Now we can adjust the line numbers for this new virtual document.
              section.UpdateVirtualLineCount();

              // Trim start and end sections
              int startIndex = first.Characters.ToList().IndexOf( begin ) + first.VirtualWindowBegin;
              section.Lines.First().Trim( startIndex );

              int endIndex = last.Characters.ToList().IndexOf( end );
              section.Lines.Last().Trim( ( first != last ) ? 0 : startIndex, endIndex + first.VirtualWindowBegin + 1 );

              return section;
        }
        /// <summary>
        /// Construct a new virtual document from the given string.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="sourceFileName">The name of the file this text originated from.</param>
        /// <returns></returns>
        public static VirtualDocument FromText( string text, string sourceFileName = "<memory>" )
        {
            VirtualDocument document = new VirtualDocument();
              document.Lines = Regex.Split( text, "\r\n|\r|\n" ).Select( l => new Line( l, sourceFileName ) ).ToList();
              // Lay down the first
              document.ReIndexLines();
              document.UpdateVirtualLineCount();

              return document;
        }