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