/// <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 < 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; }