mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
904 lines
23 KiB
904 lines
23 KiB
// |
|
// location.cs: Keeps track of the location of source code entity |
|
// |
|
// Author: |
|
// Miguel de Icaza |
|
// Atsushi Enomoto <atsushi@ximian.com> |
|
// Marek Safar (marek.safar@gmail.com) |
|
// |
|
// Copyright 2001 Ximian, Inc. |
|
// Copyright 2005 Novell, Inc. |
|
// |
|
|
|
using System; |
|
using System.IO; |
|
using System.Collections.Generic; |
|
using Mono.CompilerServices.SymbolWriter; |
|
using System.Diagnostics; |
|
using System.Linq; |
|
|
|
namespace Mono.CSharp { |
|
/// <summary> |
|
/// This is one single source file. |
|
/// </summary> |
|
/// <remarks> |
|
/// This is intentionally a class and not a struct since we need |
|
/// to pass this by reference. |
|
/// </remarks> |
|
public class SourceFile : ISourceFile { |
|
public readonly string Name; |
|
public readonly string Path; |
|
public readonly int Index; |
|
public bool AutoGenerated; |
|
public bool IsIncludeFile; |
|
|
|
SourceFileEntry file; |
|
byte[] guid, checksum; |
|
|
|
public SourceFile (string name, string path, int index, bool is_include) |
|
{ |
|
this.Index = index; |
|
this.Name = name; |
|
this.Path = path; |
|
this.IsIncludeFile = is_include; |
|
} |
|
|
|
public SourceFileEntry SourceFileEntry { |
|
get { return file; } |
|
} |
|
|
|
SourceFileEntry ISourceFile.Entry { |
|
get { return file; } |
|
} |
|
|
|
public void SetChecksum (byte[] guid, byte[] checksum) |
|
{ |
|
this.guid = guid; |
|
this.checksum = checksum; |
|
} |
|
|
|
public virtual void DefineSymbolInfo (MonoSymbolWriter symwriter) |
|
{ |
|
if (guid != null) |
|
file = symwriter.DefineDocument (Path, guid, checksum); |
|
else { |
|
file = symwriter.DefineDocument (Path); |
|
if (AutoGenerated) |
|
file.SetAutoGenerated (); |
|
} |
|
} |
|
|
|
public override string ToString () |
|
{ |
|
return String.Format ("SourceFile ({0}:{1}:{2}:{3})", |
|
Name, Path, Index, SourceFileEntry); |
|
} |
|
} |
|
|
|
public class CompilationUnit : SourceFile, ICompileUnit |
|
{ |
|
CompileUnitEntry comp_unit; |
|
Dictionary<string, SourceFile> include_files; |
|
Dictionary<string, bool> conditionals; |
|
|
|
public CompilationUnit (string name, string path, int index) |
|
: base (name, path, index, false) |
|
{ } |
|
|
|
public void AddFile (SourceFile file) |
|
{ |
|
if (file == this) |
|
return; |
|
|
|
if (include_files == null) |
|
include_files = new Dictionary<string, SourceFile> (); |
|
|
|
if (!include_files.ContainsKey (file.Path)) |
|
include_files.Add (file.Path, file); |
|
} |
|
|
|
public void AddDefine (string value) |
|
{ |
|
if (conditionals == null) |
|
conditionals = new Dictionary<string, bool> (2); |
|
|
|
conditionals [value] = true; |
|
} |
|
|
|
public void AddUndefine (string value) |
|
{ |
|
if (conditionals == null) |
|
conditionals = new Dictionary<string, bool> (2); |
|
|
|
conditionals [value] = false; |
|
} |
|
|
|
CompileUnitEntry ICompileUnit.Entry { |
|
get { return comp_unit; } |
|
} |
|
|
|
public CompileUnitEntry CompileUnitEntry { |
|
get { return comp_unit; } |
|
} |
|
|
|
public override void DefineSymbolInfo (MonoSymbolWriter symwriter) |
|
{ |
|
base.DefineSymbolInfo (symwriter); |
|
|
|
comp_unit = symwriter.DefineCompilationUnit (SourceFileEntry); |
|
|
|
if (include_files != null) { |
|
foreach (SourceFile include in include_files.Values) { |
|
include.DefineSymbolInfo (symwriter); |
|
comp_unit.AddFile (include.SourceFileEntry); |
|
} |
|
} |
|
} |
|
|
|
public bool IsConditionalDefined (string value) |
|
{ |
|
if (conditionals != null) { |
|
bool res; |
|
if (conditionals.TryGetValue (value, out res)) |
|
return res; |
|
|
|
// When conditional was undefined |
|
if (conditionals.ContainsKey (value)) |
|
return false; |
|
} |
|
|
|
return RootContext.IsConditionalDefined (value); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Keeps track of the location in the program |
|
/// </summary> |
|
/// |
|
/// <remarks> |
|
/// This uses a compact representation and a couple of auxiliary |
|
/// structures to keep track of tokens to (file,line and column) |
|
/// mappings. The usage of the bits is: |
|
/// |
|
/// - 16 bits for "checkpoint" which is a mixed concept of |
|
/// file and "line segment" |
|
/// - 8 bits for line delta (offset) from the line segment |
|
/// - 8 bits for column number. |
|
/// |
|
/// http://lists.ximian.com/pipermail/mono-devel-list/2004-December/009508.html |
|
/// </remarks> |
|
public struct Location : IEquatable<Location> |
|
{ |
|
int token; |
|
|
|
struct Checkpoint { |
|
public readonly int LineOffset; |
|
public readonly int CompilationUnit; |
|
public readonly int File; |
|
|
|
public Checkpoint (int compile_unit, int file, int line) |
|
{ |
|
File = file; |
|
CompilationUnit = compile_unit; |
|
LineOffset = line - (int) (line % (1 << line_delta_bits)); |
|
} |
|
} |
|
|
|
static List<SourceFile> source_list; |
|
static List<CompilationUnit> compile_units; |
|
static Dictionary<string, int> source_files; |
|
static int checkpoint_bits; |
|
static int source_count; |
|
static int current_source; |
|
static int current_compile_unit; |
|
static int line_delta_bits; |
|
static int line_delta_mask; |
|
static int column_bits; |
|
static int column_mask; |
|
static Checkpoint [] checkpoints; |
|
static int checkpoint_index; |
|
|
|
public readonly static Location Null = new Location (-1); |
|
public static bool InEmacs; |
|
|
|
static Location () |
|
{ |
|
Reset (); |
|
checkpoints = new Checkpoint [10]; |
|
} |
|
|
|
public static void Reset () |
|
{ |
|
source_files = new Dictionary<string, int> (); |
|
source_list = new List<SourceFile> (); |
|
compile_units = new List<CompilationUnit> (); |
|
current_source = 0; |
|
current_compile_unit = 0; |
|
source_count = 0; |
|
} |
|
|
|
// <summary> |
|
// This must be called before parsing/tokenizing any files. |
|
// </summary> |
|
static public void AddFile (Report r, string name) |
|
{ |
|
string path = Path.GetFullPath (name); |
|
int id; |
|
if (source_files.TryGetValue (path, out id)){ |
|
string other_name = source_list [id - 1].Name; |
|
if (name.Equals (other_name)) |
|
r.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name); |
|
else |
|
r.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", name, other_name, path); |
|
return; |
|
} |
|
|
|
source_files.Add (path, ++source_count); |
|
CompilationUnit unit = new CompilationUnit (name, path, source_count); |
|
source_list.Add (unit); |
|
compile_units.Add (unit); |
|
} |
|
|
|
public static IList<CompilationUnit> SourceFiles { |
|
get { |
|
return compile_units; |
|
} |
|
} |
|
|
|
// <summary> |
|
// After adding all source files we want to compile with AddFile(), this method |
|
// must be called to `reserve' an appropriate number of bits in the token for the |
|
// source file. We reserve some extra space for files we encounter via #line |
|
// directives while parsing. |
|
// </summary> |
|
static public void Initialize () |
|
{ |
|
checkpoints = new Checkpoint [source_list.Count * 2]; |
|
if (checkpoints.Length > 0) |
|
checkpoints [0] = new Checkpoint (0, 0, 0); |
|
|
|
column_bits = 8; |
|
column_mask = 0xFF; |
|
line_delta_bits = 8; |
|
line_delta_mask = 0xFF00; |
|
checkpoint_index = 0; |
|
checkpoint_bits = 16; |
|
} |
|
|
|
// <remarks> |
|
// This is used when we encounter a #line preprocessing directive. |
|
// </remarks> |
|
static public SourceFile LookupFile (CompilationUnit comp_unit, string name) |
|
{ |
|
string path; |
|
if (!Path.IsPathRooted (name)) { |
|
string root = Path.GetDirectoryName (comp_unit.Path); |
|
path = Path.Combine (root, name); |
|
} else |
|
path = name; |
|
|
|
if (!source_files.ContainsKey (path)) { |
|
if (source_count >= (1 << checkpoint_bits)) |
|
return new SourceFile (name, path, 0, true); |
|
|
|
source_files.Add (path, ++source_count); |
|
SourceFile retval = new SourceFile (name, path, source_count, true); |
|
source_list.Add (retval); |
|
return retval; |
|
} |
|
|
|
int index = (int) source_files [path]; |
|
return source_list [index - 1]; |
|
} |
|
|
|
static public void Push (CompilationUnit compile_unit, SourceFile file) |
|
{ |
|
current_source = file != null ? file.Index : -1; |
|
current_compile_unit = compile_unit != null ? compile_unit.Index : -1; |
|
// File is always pushed before being changed. |
|
} |
|
|
|
// <remarks> |
|
// If we're compiling with debugging support, this is called between parsing |
|
// and code generation to register all the source files with the |
|
// symbol writer. |
|
// </remarks> |
|
static public void DefineSymbolDocuments (MonoSymbolWriter symwriter) |
|
{ |
|
foreach (CompilationUnit unit in compile_units) |
|
unit.DefineSymbolInfo (symwriter); |
|
} |
|
|
|
public Location (int row) |
|
: this (row, 0) |
|
{ |
|
} |
|
|
|
public Location (int row, int column) |
|
{ |
|
if (row <= 0) |
|
token = 0; |
|
else { |
|
if (column > 254) |
|
column = 254; |
|
if (column < 0) |
|
column = 255; |
|
int target = -1; |
|
int delta = 0; |
|
int max = checkpoint_index < 10 ? |
|
checkpoint_index : 10; |
|
for (int i = 0; i < max; i++) { |
|
int offset = checkpoints [checkpoint_index - i].LineOffset; |
|
delta = row - offset; |
|
if (delta >= 0 && |
|
delta < (1 << line_delta_bits) && |
|
checkpoints [checkpoint_index - i].File == current_source) { |
|
target = checkpoint_index - i; |
|
break; |
|
} |
|
} |
|
if (target == -1) { |
|
AddCheckpoint (current_compile_unit, current_source, row); |
|
target = checkpoint_index; |
|
delta = row % (1 << line_delta_bits); |
|
} |
|
long l = column + |
|
(long) (delta << column_bits) + |
|
(long) (target << (line_delta_bits + column_bits)); |
|
token = l > 0xFFFFFFFF ? 0 : (int) l; |
|
} |
|
} |
|
|
|
public static Location operator - (Location loc, int columns) |
|
{ |
|
return new Location (loc.Row, loc.Column - columns); |
|
} |
|
|
|
static void AddCheckpoint (int compile_unit, int file, int row) |
|
{ |
|
if (checkpoints.Length == ++checkpoint_index) { |
|
Checkpoint [] tmp = new Checkpoint [checkpoint_index * 2]; |
|
Array.Copy (checkpoints, tmp, checkpoints.Length); |
|
checkpoints = tmp; |
|
} |
|
checkpoints [checkpoint_index] = new Checkpoint (compile_unit, file, row); |
|
} |
|
|
|
string FormatLocation (string fileName) |
|
{ |
|
if (column_bits == 0 || InEmacs) |
|
return fileName + "(" + Row.ToString () + "):"; |
|
|
|
return fileName + "(" + Row.ToString () + "," + Column.ToString () + |
|
(Column == column_mask ? "+):" : "):"); |
|
} |
|
|
|
public override string ToString () |
|
{ |
|
return FormatLocation (Name); |
|
} |
|
|
|
public string ToStringFullName () |
|
{ |
|
return FormatLocation (NameFullPath); |
|
} |
|
|
|
/// <summary> |
|
/// Whether the Location is Null |
|
/// </summary> |
|
public bool IsNull { |
|
get { return token == 0; } |
|
} |
|
|
|
public string Name { |
|
get { |
|
int index = File; |
|
if (token == 0 || index == 0) |
|
return "Internal"; |
|
if (source_list == null || index - 1 >= source_list.Count) |
|
return "unknown_file"; |
|
|
|
SourceFile file = source_list [index - 1]; |
|
return file.Name; |
|
} |
|
} |
|
|
|
public string NameFullPath { |
|
get { |
|
int index = File; |
|
if (token == 0 || index == 0) |
|
return "Internal"; |
|
|
|
return source_list [index - 1].Path; |
|
} |
|
} |
|
|
|
int CheckpointIndex { |
|
get { return (int) ((token & 0xFFFF0000) >> (line_delta_bits + column_bits)); } |
|
} |
|
|
|
public int Row { |
|
get { |
|
if (token == 0) |
|
return 1; |
|
return checkpoints [CheckpointIndex].LineOffset + ((token & line_delta_mask) >> column_bits); |
|
} |
|
} |
|
|
|
public int Column { |
|
get { |
|
if (token == 0) |
|
return 1; |
|
int col = (int) (token & column_mask); |
|
return col == 255 ? 1 : col; |
|
} |
|
} |
|
|
|
public bool Hidden { |
|
get { |
|
return (int) (token & column_mask) == 255; |
|
} |
|
} |
|
|
|
public int CompilationUnitIndex { |
|
get { |
|
if (token == 0) |
|
return 0; |
|
if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("Should not happen. Token is {0:X04}, checkpoints are {1}, index is {2}", token, checkpoints.Length, CheckpointIndex)); |
|
return checkpoints [CheckpointIndex].CompilationUnit; |
|
} |
|
} |
|
|
|
public int File { |
|
get { |
|
if (token == 0) |
|
return 0; |
|
if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("Should not happen. Token is {0:X04}, checkpoints are {1}, index is {2}", token, checkpoints.Length, CheckpointIndex)); |
|
return checkpoints [CheckpointIndex].File; |
|
} |
|
} |
|
|
|
// The ISymbolDocumentWriter interface is used by the symbol writer to |
|
// describe a single source file - for each source file there's exactly |
|
// one corresponding ISymbolDocumentWriter instance. |
|
// |
|
// This class has an internal hash table mapping source document names |
|
// to such ISymbolDocumentWriter instances - so there's exactly one |
|
// instance per document. |
|
// |
|
// This property returns the ISymbolDocumentWriter instance which belongs |
|
// to the location's source file. |
|
// |
|
// If we don't have a symbol writer, this property is always null. |
|
public SourceFile SourceFile { |
|
get { |
|
int index = File; |
|
if (index == 0) |
|
return null; |
|
return (SourceFile) source_list [index - 1]; |
|
} |
|
} |
|
|
|
public CompilationUnit CompilationUnit { |
|
get { |
|
int index = CompilationUnitIndex; |
|
if (index == 0) |
|
return null; |
|
return (CompilationUnit) source_list [index - 1]; |
|
} |
|
} |
|
|
|
#region IEquatable<Location> Members |
|
|
|
public bool Equals (Location other) |
|
{ |
|
return this.token == other.token; |
|
} |
|
|
|
#endregion |
|
} |
|
|
|
public class SpecialsBag |
|
{ |
|
public enum CommentType |
|
{ |
|
Single, |
|
Multi, |
|
Documentation |
|
} |
|
|
|
public class Comment |
|
{ |
|
public readonly CommentType CommentType; |
|
public readonly bool StartsLine; |
|
public readonly int Line; |
|
public readonly int Col; |
|
public readonly int EndLine; |
|
public readonly int EndCol; |
|
public readonly string Content; |
|
|
|
public Comment (CommentType commentType, bool startsLine, int line, int col, int endLine, int endCol, string content) |
|
{ |
|
this.CommentType = commentType; |
|
this.StartsLine = startsLine; |
|
this.Line = line; |
|
this.Col = col; |
|
this.EndLine = endLine; |
|
this.EndCol = endCol; |
|
this.Content = content; |
|
} |
|
|
|
public override string ToString () |
|
{ |
|
return string.Format ("[Comment: CommentType={0}, Line={1}, Col={2}, EndLine={3}, EndCol={4}, Content={5}]", CommentType, Line, Col, EndLine, EndCol, Content); |
|
} |
|
} |
|
|
|
public class PreProcessorDirective |
|
{ |
|
public readonly int Line; |
|
public readonly int Col; |
|
public readonly int EndLine; |
|
public readonly int EndCol; |
|
|
|
public readonly Tokenizer.PreprocessorDirective Cmd; |
|
public readonly string Arg; |
|
|
|
public PreProcessorDirective (int line, int col, int endLine, int endCol, Tokenizer.PreprocessorDirective cmd, string arg) |
|
{ |
|
this.Line = line; |
|
this.Col = col; |
|
this.EndLine = endLine; |
|
this.EndCol = endCol; |
|
this.Cmd = cmd; |
|
this.Arg = arg; |
|
} |
|
|
|
public override string ToString () |
|
{ |
|
return string.Format ("[PreProcessorDirective: Line={0}, Col={1}, EndLine={2}, EndCol={3}, Cmd={4}, Arg={5}]", Line, Col, EndLine, EndCol, Cmd, Arg); |
|
} |
|
} |
|
|
|
public readonly List<object> Specials = new List<object> (); |
|
|
|
CommentType curComment; |
|
bool startsLine; |
|
int startLine, startCol; |
|
System.Text.StringBuilder contentBuilder = new System.Text.StringBuilder (); |
|
|
|
[Conditional ("FULL_AST")] |
|
public void StartComment (CommentType type, bool startsLine, int startLine, int startCol) |
|
{ |
|
curComment = type; |
|
this.startsLine = startsLine; |
|
this.startLine = startLine; |
|
this.startCol = startCol; |
|
contentBuilder.Length = 0; |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void PushCommentChar (int ch) |
|
{ |
|
if (ch < 0) |
|
return; |
|
contentBuilder.Append ((char)ch); |
|
} |
|
[Conditional ("FULL_AST")] |
|
public void PushCommentString (string str) |
|
{ |
|
contentBuilder.Append (str); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void EndComment (int endLine, int endColumn) |
|
{ |
|
Specials.Add (new Comment (curComment, startsLine, startLine, startCol, endLine, endColumn, contentBuilder.ToString ())); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddPreProcessorDirective (int startLine, int startCol, int endLine, int endColumn, Tokenizer.PreprocessorDirective cmd, string arg) |
|
{ |
|
Specials.Add (new PreProcessorDirective (startLine, startCol, endLine, endColumn, cmd, arg)); |
|
} |
|
} |
|
|
|
// |
|
// A bag of additional locations to support full ast tree |
|
// |
|
public class LocationsBag |
|
{ |
|
public class MemberLocations |
|
{ |
|
public IList<Tuple<Modifiers, Location>> Modifiers { get; internal set; } |
|
List<Location> locations; |
|
|
|
public MemberLocations (IList<Tuple<Modifiers, Location>> mods, IEnumerable<Location> locs) |
|
{ |
|
Modifiers = mods; |
|
locations = locs != null ? new List<Location> (locs) : null; |
|
} |
|
|
|
#region Properties |
|
|
|
public Location this [int index] { |
|
get { |
|
return locations [index]; |
|
} |
|
} |
|
|
|
public int Count { |
|
get { |
|
return locations != null ? locations.Count : 0; |
|
} |
|
} |
|
|
|
#endregion |
|
|
|
public void AddLocations (params Location[] additional) |
|
|
|
{ |
|
|
|
AddLocations ((IEnumerable<Location>)additional); |
|
|
|
} |
|
public void AddLocations (IEnumerable<Location> additional) |
|
{ |
|
if (additional == null) |
|
return; |
|
if (locations == null) { |
|
locations = new List<Location>(additional); |
|
} else { |
|
locations.AddRange (additional); |
|
} |
|
} |
|
} |
|
|
|
public MemberCore LastMember { |
|
get; |
|
private set; |
|
} |
|
|
|
Dictionary<object, List<Location>> simple_locs = new Dictionary<object, List<Location>> (ReferenceEquality<object>.Default); |
|
Dictionary<MemberCore, MemberLocations> member_locs = new Dictionary<MemberCore, MemberLocations> (ReferenceEquality<MemberCore>.Default); |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddLocation (object element, params Location[] locations) |
|
{ |
|
AddLocation (element, (IEnumerable<Location>)locations); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddLocation (object element, IEnumerable<Location> locations) |
|
{ |
|
if (element == null || locations == null) |
|
return; |
|
simple_locs.Add (element, new List<Location> (locations)); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddStatement (object element, params Location[] locations) |
|
{ |
|
if (element == null) |
|
return; |
|
if (locations.Length == 0) |
|
throw new ArgumentException ("Statement is missing semicolon location"); |
|
simple_locs.Add (element, new List<Location>(locations)); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, params Location[] locations) |
|
{ |
|
LastMember = member; |
|
if (member == null) |
|
return; |
|
|
|
MemberLocations existing; |
|
if (member_locs.TryGetValue (member, out existing)) { |
|
existing.Modifiers = modLocations; |
|
existing.AddLocations (locations); |
|
return; |
|
} |
|
member_locs.Add (member, new MemberLocations (modLocations, locations)); |
|
} |
|
[Conditional ("FULL_AST")] |
|
public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, IEnumerable<Location> locations) |
|
{ |
|
LastMember = member; |
|
if (member == null) |
|
return; |
|
|
|
MemberLocations existing; |
|
if (member_locs.TryGetValue (member, out existing)) { |
|
existing.Modifiers = modLocations; |
|
existing.AddLocations (locations); |
|
return; |
|
} |
|
member_locs.Add (member, new MemberLocations (modLocations, locations)); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AppendTo (object existing, params Location[] locations) |
|
{ |
|
AppendTo (existing, (IEnumerable<Location>)locations); |
|
|
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AppendTo (object existing, IEnumerable<Location> locations) |
|
{ |
|
if (existing == null) |
|
return; |
|
List<Location> locs; |
|
if (simple_locs.TryGetValue (existing, out locs)) { |
|
simple_locs [existing].AddRange (locations); |
|
return; |
|
} |
|
AddLocation (existing, locations); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AppendToMember (MemberCore existing, params Location[] locations) |
|
{ |
|
AppendToMember (existing, (IEnumerable<Location>)locations); |
|
|
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AppendToMember (MemberCore existing, IEnumerable<Location> locations) |
|
{ |
|
if (existing == null) |
|
return; |
|
MemberLocations member; |
|
if (member_locs.TryGetValue (existing, out member)) { |
|
member.AddLocations (locations); |
|
return; |
|
} |
|
member_locs.Add (existing, new MemberLocations (null, locations)); |
|
} |
|
|
|
public List<Location> GetLocations (object element) |
|
{ |
|
List<Location> found; |
|
simple_locs.TryGetValue (element, out found); |
|
return found; |
|
} |
|
|
|
public MemberLocations GetMemberLocation (MemberCore element) |
|
{ |
|
MemberLocations found; |
|
member_locs.TryGetValue (element, out found); |
|
return found; |
|
} |
|
} |
|
|
|
public class UsingsBag |
|
{ |
|
public class Namespace { |
|
public Location NamespaceLocation { get; set; } |
|
public MemberName Name { get; set; } |
|
|
|
public Location OpenBrace { get; set; } |
|
public Location CloseBrace { get; set; } |
|
public Location OptSemicolon { get; set; } |
|
|
|
public List<object> usings = new List<object> (); |
|
public List<object> members = new List<object> (); |
|
|
|
|
|
public virtual void Accept (StructuralVisitor visitor) |
|
{ |
|
visitor.Visit (this); |
|
} |
|
} |
|
|
|
public class AliasUsing |
|
{ |
|
public readonly Location UsingLocation; |
|
public readonly Tokenizer.LocatedToken Identifier; |
|
public readonly Location AssignLocation; |
|
public readonly MemberName Nspace; |
|
public readonly Location SemicolonLocation; |
|
|
|
public AliasUsing (Location usingLocation, Tokenizer.LocatedToken identifier, Location assignLocation, MemberName nspace, Location semicolonLocation) |
|
{ |
|
this.UsingLocation = usingLocation; |
|
this.Identifier = identifier; |
|
this.AssignLocation = assignLocation; |
|
this.Nspace = nspace; |
|
this.SemicolonLocation = semicolonLocation; |
|
} |
|
|
|
public virtual void Accept (StructuralVisitor visitor) |
|
{ |
|
visitor.Visit (this); |
|
} |
|
} |
|
|
|
public class Using |
|
{ |
|
public readonly Location UsingLocation; |
|
public readonly MemberName NSpace; |
|
public readonly Location SemicolonLocation; |
|
|
|
public Using (Location usingLocation, MemberName nSpace, Location semicolonLocation) |
|
{ |
|
this.UsingLocation = usingLocation; |
|
this.NSpace = nSpace; |
|
this.SemicolonLocation = semicolonLocation; |
|
} |
|
public virtual void Accept (StructuralVisitor visitor) |
|
{ |
|
visitor.Visit (this); |
|
} |
|
} |
|
|
|
public Namespace Global { |
|
get; |
|
set; |
|
} |
|
Stack<Namespace> curNamespace = new Stack<Namespace> (); |
|
|
|
public UsingsBag () |
|
{ |
|
Global = new Namespace (); |
|
Global.OpenBrace = new Location (1, 1); |
|
Global.CloseBrace = new Location (int.MaxValue, int.MaxValue); |
|
curNamespace.Push (Global); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddUsingAlias (Location usingLocation, Tokenizer.LocatedToken identifier, Location assignLocation, MemberName nspace, Location semicolonLocation) |
|
{ |
|
curNamespace.Peek ().usings.Add (new AliasUsing (usingLocation, identifier, assignLocation, nspace, semicolonLocation)); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void AddUsing (Location usingLocation, MemberName nspace, Location semicolonLocation) |
|
{ |
|
curNamespace.Peek ().usings.Add (new Using (usingLocation, nspace, semicolonLocation)); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void DeclareNamespace (Location namespaceLocation, MemberName nspace) |
|
{ |
|
var newNamespace = new Namespace () { NamespaceLocation = namespaceLocation, Name = nspace }; |
|
curNamespace.Peek ().members.Add (newNamespace); |
|
curNamespace.Push (newNamespace); |
|
} |
|
|
|
int typeLevel = 0; |
|
[Conditional ("FULL_AST")] |
|
public void PushTypeDeclaration (object type) |
|
{ |
|
if (typeLevel == 0) |
|
curNamespace.Peek ().members.Add (type); |
|
typeLevel++; |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void PopTypeDeclaration () |
|
{ |
|
typeLevel--; |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void EndNamespace (Location optSemicolon) |
|
{ |
|
curNamespace.Peek ().OptSemicolon = optSemicolon; |
|
curNamespace.Pop (); |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void OpenNamespace (Location bracketLocation) |
|
{ |
|
curNamespace.Peek ().OpenBrace = bracketLocation; |
|
} |
|
|
|
[Conditional ("FULL_AST")] |
|
public void CloseNamespace (Location bracketLocation) |
|
{ |
|
curNamespace.Peek ().CloseBrace = bracketLocation; |
|
} |
|
} |
|
}
|
|
|