6adee744b43b11529fa865f63d483b871c37e4c7
[mono.git] / mcs / mcs / location.cs
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 //
9
10 using System;
11 using System.IO;
12 using System.Collections;
13 using System.Diagnostics.SymbolStore;
14
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 {
24                 public readonly string Name;
25                 public readonly string Path;
26                 public readonly int Index;
27                 public ISymbolDocumentWriter SymbolDocument;
28
29                 public SourceFile (string name, string path, int index)
30                 {
31                         this.Index = index;
32                         this.Name = name;
33                         this.Path = path;
34                 }
35         }
36
37         /// <summary>
38         ///   Keeps track of the location in the program
39         /// </summary>
40         ///
41         /// <remarks>
42         ///   This uses a compact representation and a couple of auxiliary
43         ///   structures to keep track of tokens to (file,line) mappings.
44         ///
45         ///   We could probably also keep track of columns by storing those
46         ///   in 8 bits (and say, map anything after char 255 to be `255+').
47         /// </remarks>
48         public struct Location {
49                 public int token; 
50
51                 static ArrayList source_list;
52                 static Hashtable source_files;
53                 static int source_bits;
54                 static int source_mask;
55                 static int source_count;
56                 static int module_base;
57                 static int current_source;
58
59                 public readonly static Location Null;
60                 
61                 static Location ()
62                 {
63                         source_files = new Hashtable ();
64                         source_list = new ArrayList ();
65                         current_source = 0;
66                         module_base = 0;
67                         Null.token = 0;
68                 }
69
70                 // <summary>
71                 //   This must be called before parsing/tokenizing any files.
72                 // </summary>
73                 static public void AddFile (string name)
74                 {
75                         string path = Path.GetFullPath (name);
76
77                         if (source_files.Contains (path)){
78                                 Report.Error (
79                                         1516,
80                                         "Source file `" + name + "' specified multiple times");
81                                 Environment.Exit (1);
82                         }
83
84                         source_files.Add (path, ++source_count);
85                         source_list.Add (new SourceFile (name, path, source_count));
86                 }
87
88                 static public SourceFile[] SourceFiles {
89                         get {
90                                 SourceFile[] retval = new SourceFile [source_list.Count];
91                                 source_list.CopyTo (retval, 0);
92                                 return retval;
93                         }
94                 }
95
96                 static int log2 (int number)
97                 {
98                         int bits = 0;
99                         while (number > 0) {
100                                 bits++;
101                                 number /= 2;
102                         }
103
104                         return bits;
105                 }
106
107                 // <summary>
108                 //   After adding all source files we want to compile with AddFile(), this method
109                 //   must be called to `reserve' an appropriate number of bits in the token for the
110                 //   source file.  We reserve some extra space for files we encounter via #line
111                 //   directives while parsing.
112                 // </summary>
113                 static public void Initialize ()
114                 {
115                         source_bits = log2 (source_list.Count) + 2;
116                         source_mask = (1 << source_bits) - 1;
117                 }
118
119                 // <remarks>
120                 //   This is used when we encounter a #line preprocessing directive.
121                 // </remarks>
122                 static public SourceFile LookupFile (string name)
123                 {
124                         string path = Path.GetFullPath (name);
125
126                         if (!source_files.Contains (path)) {
127                                 if (source_count >= source_bits * 8)
128                                         return new SourceFile (name, path, 0);
129
130                                 source_files.Add (path, ++source_count);
131                                 SourceFile retval = new SourceFile (name, path, source_count);
132                                 source_list.Add (retval);
133                                 return retval;
134                         }
135
136                         int index = (int) source_files [path];
137                         return (SourceFile) source_list [index - 1];
138                 }
139
140                 static public void Push (SourceFile file)
141                 {
142                         current_source = file.Index;
143                         module_base = current_source << source_bits;
144                 }
145
146                 // <remarks>
147                 //   If we're compiling with debugging support, this is called between parsing and
148                 //   code generation to register all the source files with the symbol writer.           //
149                 // </remarks>
150                 static public void DefineSymbolDocuments (SymbolWriter symwriter)
151                 {
152                         foreach (SourceFile file in source_list)
153                                 file.SymbolDocument = symwriter.DefineDocument (file.Path);
154                 }
155                 
156                 public Location (int row)
157                 {
158                         if (row < 0)
159                                 token = 0;
160                         else
161                                 token = current_source + (row << source_bits);
162                 }
163
164                 public override string ToString ()
165                 {
166                         return Name + ": (" + Row + ")";
167                 }
168                 
169                 /// <summary>
170                 ///   Whether the Location is Null
171                 /// </summary>
172                 static public bool IsNull (Location l)
173                 {
174                         return l.token == 0;
175                 }
176
177                 public string Name {
178                         get {
179                                 int index = token & source_mask;
180                                 if ((token == 0) || (index == 0))
181                                         return "Internal";
182
183                                 SourceFile file = (SourceFile) source_list [index - 1];
184                                 return file.Name;
185                         }
186                 }
187
188                 public int Row {
189                         get {
190                                 if (token == 0)
191                                         return 1;
192
193                                 return token >> source_bits;
194                         }
195                 }
196
197                 // The ISymbolDocumentWriter interface is used by the symbol writer to
198                 // describe a single source file - for each source file there's exactly
199                 // one corresponding ISymbolDocumentWriter instance.
200                 //
201                 // This class has an internal hash table mapping source document names
202                 // to such ISymbolDocumentWriter instances - so there's exactly one
203                 // instance per document.
204                 //
205                 // This property returns the ISymbolDocumentWriter instance which belongs
206                 // to the location's source file.
207                 //
208                 // If we don't have a symbol writer, this property is always null.
209                 public ISymbolDocumentWriter SymbolDocument {
210                         get {
211                                 int index = token & source_mask;
212                                 if (index == 0)
213                                         return null;
214                                 SourceFile file = (SourceFile) source_list [index - 1];
215                                 return file.SymbolDocument;
216                         }
217                 }
218         }
219 }