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