2 // location.cs: Keeps track of the location of source code entity
7 // (C) 2001 Ximian, Inc.
12 using System
.Collections
;
13 using Mono
.CompilerServices
.SymbolWriter
;
15 namespace Mono
.CSharp
{
17 /// This is one single source file.
20 /// This is intentionally a class and not a struct since we need
21 /// to pass this by reference.
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
)
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
);
49 /// Keeps track of the location in the program
53 /// This uses a compact representation and a couple of auxiliary
54 /// structures to keep track of tokens to (file,line) mappings.
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+').
59 public struct Location
{
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
;
73 source_files
= new Hashtable ();
74 source_list
= new ArrayList ();
80 // This must be called before parsing/tokenizing any files.
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
);
92 Report
.Warning (2002, "Source filenames '{0}' and '{1}' both refer to the same file: {2}", name
, other_name
, path
);
96 source_files
.Add (path
, ++source_count
);
97 source_list
.Add (new SourceFile (name
, path
, source_count
));
100 static public SourceFile
[] SourceFiles
{
102 SourceFile
[] retval
= new SourceFile
[source_list
.Count
];
103 source_list
.CopyTo (retval
, 0);
108 static int log2 (int number
)
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.
125 static public void Initialize ()
127 source_bits
= log2 (source_list
.Count
) + 2;
128 source_mask
= (1 << source_bits
) - 1;
132 // This is used when we encounter a #line preprocessing directive.
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
);
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;
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
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
)
176 token
= current_source
+ (row
<< source_bits
);
179 public override string ToString ()
181 return Name
+ ": (" + Row
+ ")";
185 /// Whether the Location is Null
187 static public bool IsNull (Location l
)
194 int index
= token
& source_mask
;
195 if ((token
== 0) || (index
== 0))
198 SourceFile file
= (SourceFile
) source_list
[index
- 1];
208 return token
>> source_bits
;
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
{
232 int index
= token
& source_mask
;
235 return (SourceFile
) source_list
[index
- 1];