2005-06-27 Geoff Norton <gnorton@customerdna.com>
[mono-project.git] / mcs / bmcs / location.cs
blob0066b89256add2045e94b48d4da41ea0d4f60c96
1 //
2 // location.cs: Keeps track of the location of source code entity
3 //
4 // Author:
5 // Miguel de Icaza
6 //
7 // (C) 2001 Ximian, Inc.
8 //
10 using System;
11 using System.IO;
12 using System.Collections;
13 using Mono.CompilerServices.SymbolWriter;
15 namespace Mono.CSharp {
16 /// <summary>
17 /// This is one single source file.
18 /// </summary>
19 /// <remarks>
20 /// This is intentionally a class and not a struct since we need
21 /// to pass this by reference.
22 /// </remarks>
23 public sealed class SourceFile : ISourceFile {
24 public readonly string Name;
25 public readonly string Path;
26 public readonly int Index;
27 public SourceFileEntry SourceFileEntry;
28 public bool HasLineDirective;
30 public SourceFile (string name, string path, int index)
32 this.Index = index;
33 this.Name = name;
34 this.Path = path;
37 SourceFileEntry ISourceFile.Entry {
38 get { return SourceFileEntry; }
41 public override string ToString ()
43 return String.Format ("SourceFile ({0}:{1}:{2}:{3})",
44 Name, Path, Index, SourceFileEntry);
48 /// <summary>
49 /// Keeps track of the location in the program
50 /// </summary>
51 ///
52 /// <remarks>
53 /// This uses a compact representation and a couple of auxiliary
54 /// structures to keep track of tokens to (file,line) mappings.
55 ///
56 /// We could probably also keep track of columns by storing those
57 /// in 8 bits (and say, map anything after char 255 to be `255+').
58 /// </remarks>
59 public struct Location {
60 public int token;
62 static ArrayList source_list;
63 static Hashtable source_files;
64 static int source_bits;
65 static int source_mask;
66 static int source_count;
67 static int current_source;
69 public readonly static Location Null;
71 static Location ()
73 source_files = new Hashtable ();
74 source_list = new ArrayList ();
75 current_source = 0;
76 Null.token = 0;
79 // <summary>
80 // This must be called before parsing/tokenizing any files.
81 // </summary>
82 static public void AddFile (string name)
84 string path = Path.GetFullPath (name);
86 if (source_files.Contains (path)){
87 int id = (int) source_files [path];
88 string other_name = ((SourceFile) source_list [id - 1]).Name;
89 if (name.Equals (other_name))
90 Report.Warning (2002, "Source file '{0}' specified multiple times", name);
91 else
92 Report.Warning (2002, "Source filenames '{0}' and '{1}' both refer to the same file: {2}", name, other_name, path);
93 return;
96 source_files.Add (path, ++source_count);
97 source_list.Add (new SourceFile (name, path, source_count));
100 static public SourceFile[] SourceFiles {
101 get {
102 SourceFile[] retval = new SourceFile [source_list.Count];
103 source_list.CopyTo (retval, 0);
104 return retval;
108 static int log2 (int number)
110 int bits = 0;
111 while (number > 0) {
112 bits++;
113 number /= 2;
116 return bits;
119 // <summary>
120 // After adding all source files we want to compile with AddFile(), this method
121 // must be called to `reserve' an appropriate number of bits in the token for the
122 // source file. We reserve some extra space for files we encounter via #line
123 // directives while parsing.
124 // </summary>
125 static public void Initialize ()
127 source_bits = log2 (source_list.Count) + 2;
128 source_mask = (1 << source_bits) - 1;
131 // <remarks>
132 // This is used when we encounter a #line preprocessing directive.
133 // </remarks>
134 static public SourceFile LookupFile (string name)
136 string path = name == "" ? "" : Path.GetFullPath (name);
138 if (!source_files.Contains (path)) {
139 if (source_count >= (1 << source_bits))
140 return new SourceFile (name, path, 0);
142 source_files.Add (path, ++source_count);
143 SourceFile retval = new SourceFile (name, path, source_count);
144 source_list.Add (retval);
145 return retval;
148 int index = (int) source_files [path];
149 return (SourceFile) source_list [index - 1];
153 static public void Push (SourceFile file)
155 current_source = file.Index;
159 // <remarks>
160 // If we're compiling with debugging support, this is called between parsing
161 // and code generation to register all the source files with the
162 // symbol writer.
163 // </remarks>
164 static public void DefineSymbolDocuments (SymbolWriter symwriter)
166 foreach (SourceFile file in source_list) {
167 file.SourceFileEntry = symwriter.DefineDocument (file.Path);
171 public Location (int row)
173 if (row < 0)
174 token = 0;
175 else
176 token = current_source + (row << source_bits);
179 public override string ToString ()
181 return Name + ": (" + Row + ")";
184 /// <summary>
185 /// Whether the Location is Null
186 /// </summary>
187 static public bool IsNull (Location l)
189 return l.token == 0;
192 public string Name {
193 get {
194 int index = token & source_mask;
195 if ((token == 0) || (index == 0))
196 return "Internal";
198 SourceFile file = (SourceFile) source_list [index - 1];
199 return file.Name;
203 public int Row {
204 get {
205 if (token == 0)
206 return 1;
208 return token >> source_bits;
212 public int File {
213 get {
214 return token & source_mask;
218 // The ISymbolDocumentWriter interface is used by the symbol writer to
219 // describe a single source file - for each source file there's exactly
220 // one corresponding ISymbolDocumentWriter instance.
222 // This class has an internal hash table mapping source document names
223 // to such ISymbolDocumentWriter instances - so there's exactly one
224 // instance per document.
226 // This property returns the ISymbolDocumentWriter instance which belongs
227 // to the location's source file.
229 // If we don't have a symbol writer, this property is always null.
230 public SourceFile SourceFile {
231 get {
232 int index = token & source_mask;
233 if (index == 0)
234 return null;
235 return (SourceFile) source_list [index - 1];