Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/location.cs @ 11700

Last change on this file since 11700 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 21.0 KB
Line 
1//
2// location.cs: Keeps track of the location of source code entity
3//
4// Author:
5//   Miguel de Icaza
6//   Atsushi Enomoto  <atsushi@ximian.com>
7//   Marek Safar (marek.safar@gmail.com)
8//
9// Copyright 2001 Ximian, Inc.
10// Copyright 2005 Novell, Inc.
11//
12
13using System;
14using System.Collections.Generic;
15using Mono.CompilerServices.SymbolWriter;
16using System.Diagnostics;
17using System.Linq;
18
19namespace Mono.CSharp
20{
21  //
22  //  This is one single source file.
23  //
24  public class SourceFile : IEquatable<SourceFile>
25  {
26    //
27    // Used by #line directive to track hidden sequence point
28    // regions
29    //
30    struct LocationRegion : IComparable<LocationRegion>
31    {
32      public readonly Location Start;
33      public readonly Location End;
34
35      public LocationRegion (Location start, Location end)
36      {
37        this.Start = start;
38        this.End = end;
39      }
40
41      public int CompareTo (LocationRegion other)
42      {
43        if (Start.Row == other.Start.Row)
44          return Start.Column.CompareTo (other.Start.Column);
45
46        return Start.Row.CompareTo (other.Start.Row);
47      }
48
49      public override string ToString ()
50      {
51        return Start.ToString () + " - " + End.ToString ();
52      }
53    }
54
55    static readonly byte[] MD5Algorith = { 96, 166, 110, 64, 207, 100, 130, 76, 182, 240, 66, 212, 129, 114, 167, 153 };
56
57    public readonly string Name;
58    public readonly string FullPathName;
59    public readonly int Index;
60    public bool AutoGenerated;
61
62    SourceFileEntry file;
63    byte[] algGuid, checksum;
64    List<LocationRegion> hidden_lines;
65
66    public SourceFile (string name, string path, int index)
67    {
68      this.Index = index;
69      this.Name = name;
70      this.FullPathName = path;
71    }
72
73    public byte[] Checksum {
74      get {
75        return checksum;
76      }
77    }
78
79    public bool HasChecksum {
80      get {
81        return checksum != null;
82      }
83    }
84
85    public SourceFileEntry SourceFileEntry {
86      get {
87        return file;
88      }
89    }
90
91    public void SetChecksum (byte[] checksum)
92    {
93      SetChecksum (MD5Algorith, checksum);
94    }
95
96    public void SetChecksum (byte[] algorithmGuid, byte[] checksum)
97    {
98      this.algGuid = algorithmGuid;
99      this.checksum = checksum;
100    }
101
102    public SourceFileEntry CreateSymbolInfo (MonoSymbolFile symwriter)
103    {
104      if (hidden_lines != null)
105        hidden_lines.Sort ();
106
107      file = new SourceFileEntry (symwriter, FullPathName, algGuid, checksum);
108      if (AutoGenerated)
109        file.SetAutoGenerated ();
110
111      return file;
112    }
113
114    public bool Equals (SourceFile other)
115    {
116      return FullPathName == other.FullPathName;
117    }
118
119    public bool IsHiddenLocation (Location loc)
120    {
121      if (hidden_lines == null)
122        return false;
123
124      int index = hidden_lines.BinarySearch (new LocationRegion (loc, loc));
125      index = ~index;
126      if (index > 0) {
127        var found = hidden_lines[index - 1];
128        if (loc.Row < found.End.Row)
129          return true;
130      }
131
132      return false;
133    }
134
135    public void RegisterHiddenScope (Location start, Location end)
136    {
137      if (hidden_lines == null)
138        hidden_lines = new List<LocationRegion> ();
139
140      hidden_lines.Add (new LocationRegion (start, end));
141    }
142
143    public override string ToString ()
144    {
145      return String.Format ("SourceFile ({0}:{1}:{2})", Name, FullPathName, Index);
146    }
147  }
148
149  /// <summary>
150  ///   Keeps track of the location in the program
151  /// </summary>
152  ///
153  /// <remarks>
154  ///   This uses a compact representation and a couple of auxiliary
155  ///   structures to keep track of tokens to (file,line and column)
156  ///   mappings. The usage of the bits is:
157  ///   
158  ///     - 16 bits for "checkpoint" which is a mixed concept of
159  ///       file and "line segment"
160  ///     - 8 bits for line delta (offset) from the line segment
161  ///     - 8 bits for column number.
162  ///
163  ///   http://lists.ximian.com/pipermail/mono-devel-list/2004-December/009508.html
164  /// </remarks>
165  public struct Location : IEquatable<Location>
166  {
167    struct Checkpoint {
168      public readonly int LineOffset;
169      public readonly int File;
170
171      public Checkpoint (int file, int line)
172      {
173        File = file;
174        LineOffset = line - (int) (line % (1 << line_delta_bits));
175      }
176    }
177
178#if FULL_AST
179    readonly long token;
180
181    const int column_bits = 24;
182    const int line_delta_bits = 24;
183#else
184    readonly int token;
185
186    const int column_bits = 8;
187    const int line_delta_bits = 8;
188#endif
189    const int checkpoint_bits = 16;
190
191    const int column_mask = (1 << column_bits) - 1;
192    const int max_column = column_mask;
193
194    static List<SourceFile> source_list;
195    static Checkpoint [] checkpoints;
196    static int checkpoint_index;
197   
198    public readonly static Location Null = new Location ();
199    public static bool InEmacs;
200   
201    static Location ()
202    {
203      Reset ();
204    }
205
206    public static void Reset ()
207    {
208      source_list = new List<SourceFile> ();
209      checkpoint_index = 0;
210    }
211
212    public static void AddFile (SourceFile file)
213    {
214      source_list.Add (file);
215    }
216
217    // <summary>
218    //   After adding all source files we want to compile with AddFile(), this method
219    //   must be called to `reserve' an appropriate number of bits in the token for the
220    //   source file.  We reserve some extra space for files we encounter via #line
221    //   directives while parsing.
222    // </summary>
223    static public void Initialize (List<SourceFile> files)
224    {
225#if NET_4_0 || MOBILE_DYNAMIC
226      source_list.AddRange (files);
227#else
228      source_list.AddRange (files.ToArray ());
229#endif
230
231      checkpoints = new Checkpoint [System.Math.Max (1, source_list.Count * 2)];
232      if (checkpoints.Length > 0)
233        checkpoints [0] = new Checkpoint (0, 0);
234    }
235
236    public Location (SourceFile file, int row, int column)
237    {
238      if (row <= 0)
239        token = 0;
240      else {
241        if (column > max_column)
242          column = max_column;
243
244        long target = -1;
245        long delta = 0;
246
247        // TODO: For eval only, need better handling of empty
248        int file_index = file == null ? 0 : file.Index;
249
250        // FIXME: This value is certainly wrong but what was the intension
251        int max = checkpoint_index < 10 ?
252          checkpoint_index : 10;
253        for (int i = 0; i < max; i++) {
254          int offset = checkpoints [checkpoint_index - i].LineOffset;
255          delta = row - offset;
256          if (delta >= 0 &&
257            delta < (1 << line_delta_bits) &&
258            checkpoints[checkpoint_index - i].File == file_index) {
259            target = checkpoint_index - i;
260            break;
261          }
262        }
263        if (target == -1) {
264          AddCheckpoint (file_index, row);
265          target = checkpoint_index;
266          delta = row % (1 << line_delta_bits);
267        }
268
269        long l = column +
270          (delta << column_bits) +
271          (target << (line_delta_bits + column_bits));
272#if FULL_AST
273        token = l;
274#else
275        token = l > 0xFFFFFFFF ? 0 : (int) l;
276#endif
277      }
278    }
279
280    public static Location operator - (Location loc, int columns)
281    {
282      return new Location (loc.SourceFile, loc.Row, loc.Column - columns);
283    }
284
285    static void AddCheckpoint (int file, int row)
286    {
287      if (checkpoints.Length == ++checkpoint_index) {
288        Array.Resize (ref checkpoints, checkpoint_index * 2);
289      }
290      checkpoints [checkpoint_index] = new Checkpoint (file, row);
291    }
292
293    string FormatLocation (string fileName)
294    {
295      if (column_bits == 0 || InEmacs)
296        return fileName + "(" + Row.ToString () + "):";
297
298      return fileName + "(" + Row.ToString () + "," + Column.ToString () +
299        (Column == max_column ? "+):" : "):");
300    }
301   
302    public override string ToString ()
303    {
304      return FormatLocation (Name);
305    }
306
307    public string ToStringFullName ()
308    {
309      return FormatLocation (NameFullPath);
310    }
311   
312    /// <summary>
313    ///   Whether the Location is Null
314    /// </summary>
315    public bool IsNull {
316      get { return token == 0; }
317    }
318
319    public string Name {
320      get {
321        int index = File;
322
323        if (token == 0 || index <= 0)
324          return null;
325
326        SourceFile file = source_list [index - 1];
327        return file.Name;
328      }
329    }
330
331    public string NameFullPath {
332      get {
333        int index = File;
334        if (token == 0 || index <= 0)
335          return null;
336
337        return source_list[index - 1].FullPathName;
338      }
339    }
340
341    int CheckpointIndex {
342      get {
343        const int checkpoint_mask = (1 << checkpoint_bits) - 1;
344        return ((int) (token >> (line_delta_bits + column_bits))) & checkpoint_mask;
345      }
346    }
347
348    public int Row {
349      get {
350        if (token == 0)
351          return 1;
352
353        int offset = checkpoints[CheckpointIndex].LineOffset;
354
355        const int line_delta_mask = (1 << column_bits) - 1;
356        return offset + (((int)(token >> column_bits)) & line_delta_mask);
357      }
358    }
359
360    public int Column {
361      get {
362        if (token == 0)
363          return 1;
364        return (int) (token & column_mask);
365      }
366    }
367
368    public int File {
369      get {
370        if (token == 0)
371          return 0;
372if (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));
373        return checkpoints [CheckpointIndex].File;
374      }
375    }
376
377    // The ISymbolDocumentWriter interface is used by the symbol writer to
378    // describe a single source file - for each source file there's exactly
379    // one corresponding ISymbolDocumentWriter instance.
380    //
381    // This class has an internal hash table mapping source document names
382    // to such ISymbolDocumentWriter instances - so there's exactly one
383    // instance per document.
384    //
385    // This property returns the ISymbolDocumentWriter instance which belongs
386    // to the location's source file.
387    //
388    // If we don't have a symbol writer, this property is always null.
389    public SourceFile SourceFile {
390      get {
391        int index = File;
392        if (index == 0)
393          return null;
394        return source_list [index - 1];
395      }
396    }
397
398    #region IEquatable<Location> Members
399
400    public bool Equals (Location other)
401    {
402      return this.token == other.token;
403    }
404
405    #endregion
406  }
407 
408  public class SpecialsBag
409  {
410    public enum CommentType
411    {
412      Single,
413      Multi,
414      Documentation,
415      InactiveCode
416    }
417
418    public bool Suppress {
419      get;
420      set;
421    }
422
423    public class SpecialVisitor
424    {
425      public virtual void Visit (Comment comment)
426      {
427      }
428      public virtual void Visit (NewLineToken newLineToken)
429      {
430      }
431      public virtual void Visit (PreProcessorDirective preProcessorDirective)
432      {
433      }
434    }
435    public abstract class SpecialBase
436    {
437      public abstract void Accept (SpecialVisitor visitor);
438    }
439   
440    public class Comment : SpecialBase
441    {
442      public readonly CommentType CommentType;
443      public readonly bool StartsLine;
444      public readonly int Line;
445      public readonly int Col;
446      public readonly int EndLine;
447      public readonly int EndCol;
448      public readonly string Content;
449     
450      public Comment (CommentType commentType, bool startsLine, int line, int col, int endLine, int endCol, string content)
451      {
452        this.CommentType = commentType;
453        this.StartsLine = startsLine;
454        this.Line = line;
455        this.Col = col;
456        this.EndLine = endLine;
457        this.EndCol = endCol;
458        this.Content = content;
459      }
460
461      public override string ToString ()
462      {
463        return string.Format ("[Comment: CommentType={0}, Line={1}, Col={2}, EndLine={3}, EndCol={4}, Content={5}]", CommentType, Line, Col, EndLine, EndCol, Content);
464      }
465
466      public override void Accept (SpecialVisitor visitor)
467      {
468        visitor.Visit (this);
469      }
470    }
471
472    public class NewLineToken : SpecialBase
473    {
474      public readonly int Line;
475      public readonly int Col;
476      public readonly NewLine NewLine;
477
478      public NewLineToken (int line, int col, NewLine newLine)
479      {
480        this.Line = line;
481        this.Col = col;
482        this.NewLine = newLine;
483      }
484
485      public override void Accept (SpecialVisitor visitor)
486      {
487        visitor.Visit (this);
488      }
489    }
490
491    public class PragmaPreProcessorDirective : PreProcessorDirective
492    {
493      public bool Disalbe { get; set; }
494
495      public int WarningColumn {
496        get;
497        set;
498      }
499
500      public int DisableRestoreColumn {
501        get;
502        set;
503      }
504
505      public List<Constant> Codes = new List<Constant> ();
506
507      public PragmaPreProcessorDirective (int line, int col, int endLine, int endCol, Tokenizer.PreprocessorDirective cmd, string arg) : base (line, col, endLine, endCol, cmd, arg)
508      {
509      }
510    }
511
512    public class LineProcessorDirective : PreProcessorDirective
513    {
514      public int LineNumber { get; set; }
515      public string FileName { get; set; }
516
517      public LineProcessorDirective (int line, int col, int endLine, int endCol, Tokenizer.PreprocessorDirective cmd, string arg) : base (line, col, endLine, endCol, cmd, arg)
518      {
519      }
520    }
521
522    public class PreProcessorDirective : SpecialBase
523    {
524      public readonly int Line;
525      public readonly int Col;
526      public readonly int EndLine;
527      public readonly int EndCol;
528
529      public readonly Tokenizer.PreprocessorDirective Cmd;
530      public readonly string Arg;
531     
532      public bool Take = true;
533     
534      public PreProcessorDirective (int line, int col, int endLine, int endCol, Tokenizer.PreprocessorDirective cmd, string arg)
535      {
536        this.Line = line;
537        this.Col = col;
538        this.EndLine = endLine;
539        this.EndCol = endCol;
540        this.Cmd = cmd;
541        this.Arg = arg;
542      }
543     
544      public override void Accept (SpecialVisitor visitor)
545      {
546        visitor.Visit (this);
547      }
548
549      public override string ToString ()
550      {
551        return string.Format ("[PreProcessorDirective: Line={0}, Col={1}, EndLine={2}, EndCol={3}, Cmd={4}, Arg={5}]", Line, Col, EndLine, EndCol, Cmd, Arg);
552      }
553    }
554   
555    public readonly List<SpecialBase> Specials = new List<SpecialBase> ();
556   
557    CommentType curComment;
558    bool startsLine;
559    int startLine, startCol;
560    System.Text.StringBuilder contentBuilder = new System.Text.StringBuilder ();
561   
562    [Conditional ("FULL_AST")]
563    public void StartComment (CommentType type, bool startsLine, int startLine, int startCol)
564    {
565      if (Suppress)
566        return;
567      inComment = true;
568      curComment = type;
569      this.startsLine = startsLine;
570      this.startLine = startLine;
571      this.startCol = startCol;
572      contentBuilder.Length = 0;
573    }
574   
575    [Conditional ("FULL_AST")]
576    public void PushCommentChar (int ch)
577    {
578      if (Suppress)
579        return;
580      if (ch < 0)
581        return;
582      contentBuilder.Append ((char)ch);
583    }
584    [Conditional ("FULL_AST")]
585    public void PushCommentString (string str)
586    {
587      if (Suppress)
588        return;
589      contentBuilder.Append (str);
590    }
591   
592    bool inComment;
593    [Conditional ("FULL_AST")]
594    public void EndComment (int endLine, int endColumn)
595    {
596      if (Suppress)
597        return;
598      if (!inComment)
599        return;
600      inComment = false;
601      // Ignore empty comments
602      if (startLine == endLine && startCol == endColumn)
603        return;
604      Specials.Add (new Comment (curComment, startsLine, startLine, startCol, endLine, endColumn, contentBuilder.ToString ()));
605    }
606   
607    [Conditional ("FULL_AST")]
608    public void AddPreProcessorDirective (int startLine, int startCol, int endLine, int endColumn, Tokenizer.PreprocessorDirective cmd, string arg)
609    {
610      if (Suppress)
611        return;
612      if (inComment)
613        EndComment (startLine, startCol);
614      switch (cmd) {
615      case Tokenizer.PreprocessorDirective.Pragma:
616        Specials.Add (new PragmaPreProcessorDirective (startLine, startCol, endLine, endColumn, cmd, arg));
617        break;
618      case Tokenizer.PreprocessorDirective.Line:
619        Specials.Add (new LineProcessorDirective (startLine, startCol, endLine, endColumn, cmd, arg));
620        break;
621      default:
622        Specials.Add (new PreProcessorDirective (startLine, startCol, endLine, endColumn, cmd, arg));
623        break;
624      }
625    }
626
627    #if FULL_AST
628    public PragmaPreProcessorDirective SetPragmaDisable(bool disable)
629    {
630      if (Suppress)
631        return null;
632      var pragmaDirective = Specials [Specials.Count - 1] as PragmaPreProcessorDirective;
633      if (pragmaDirective == null)
634        return null;
635      pragmaDirective.Disalbe = disable;
636      return pragmaDirective;
637    }
638    #endif
639
640    public PragmaPreProcessorDirective GetPragmaPreProcessorDirective()
641    {
642      if (Suppress)
643        return null;
644      return Specials [Specials.Count - 1] as PragmaPreProcessorDirective;
645    }
646
647
648    public LineProcessorDirective GetCurrentLineProcessorDirective()
649    {
650      if (Suppress)
651        return null;
652      return Specials [Specials.Count - 1] as LineProcessorDirective;
653    }
654
655    public enum NewLine { Unix, Windows }
656
657    int lastNewLine = -1;
658    int lastNewCol = -1;
659    [Conditional ("FULL_AST")]
660    public void AddNewLine (int line, int col, NewLine newLine)
661    {
662      if (Suppress)
663        return;
664      if (line == lastNewLine && col == lastNewCol)
665        return;
666      lastNewLine = line;
667      lastNewCol = col;
668      Specials.Add (new NewLineToken (line, col, newLine));
669    }
670
671    public void SkipIf ()
672    {
673      if (Specials.Count > 0) {
674        var directive = Specials[Specials.Count - 1] as PreProcessorDirective;
675        if (directive != null)
676          directive.Take = false;
677      }
678    }
679  }
680
681  //
682  // A bag of additional locations to support full ast tree
683  //
684  public class LocationsBag
685  {
686    public class MemberLocations
687    {
688      public IList<Tuple<Modifiers, Location>> Modifiers { get; internal set; }
689      List<Location> locations;
690     
691      public MemberLocations (IList<Tuple<Modifiers, Location>> mods, IEnumerable<Location> locs)
692      {
693        Modifiers = mods;
694        locations = locs != null ?  new List<Location> (locs) : null;
695/*
696      public readonly IList<Tuple<Modifiers, Location>> Modifiers;
697      List<Location> locations;
698
699      public MemberLocations (IList<Tuple<Modifiers, Location>> mods)
700      {
701        Modifiers = mods;
702      }
703
704      public MemberLocations (IList<Tuple<Modifiers, Location>> mods, Location loc)
705        : this (mods)
706      {
707        AddLocations (loc);
708      }
709
710      public MemberLocations (IList<Tuple<Modifiers, Location>> mods, Location[] locs)
711        : this (mods)
712      {
713        AddLocations (locs);
714      }
715
716      public MemberLocations (IList<Tuple<Modifiers, Location>> mods, List<Location> locs)
717        : this (mods)
718      {
719        locations = locs;*/
720      }
721
722      #region Properties
723
724      public Location this [int index] {
725        get {
726          return locations [index];
727        }
728      }
729     
730      public int Count {
731        get {
732          return locations != null ? locations.Count : 0;
733        }
734      }
735
736      #endregion
737
738      public void AddLocations (Location loc)
739      {
740        if (locations == null) {
741          locations = new List<Location> ();
742        }
743
744        locations.Add (loc);
745      }
746
747      public void AddLocations (params Location[] additional)
748
749      {
750
751        AddLocations ((IEnumerable<Location>)additional);
752
753      }
754      public void AddLocations (IEnumerable<Location> additional)
755      {
756        if (additional == null)
757          return;
758        if (locations == null) {
759          locations = new List<Location> (additional);
760        } else {
761          locations.AddRange (additional);
762        }
763      }
764    }
765   
766    public MemberCore LastMember {
767      get;
768      private set;
769    }
770
771    Dictionary<object, List<Location>> simple_locs = new Dictionary<object, List<Location>> (ReferenceEquality<object>.Default);
772    Dictionary<MemberCore, MemberLocations> member_locs = new Dictionary<MemberCore, MemberLocations> (ReferenceEquality<MemberCore>.Default);
773
774    [Conditional ("FULL_AST")]
775    public void AddLocation (object element, params Location[] locations)
776    {
777      AddLocation (element, (IEnumerable<Location>)locations);
778    }
779
780    [Conditional ("FULL_AST")]
781    public void AddLocation (object element, IEnumerable<Location> locations)
782    {
783      if (element == null || locations == null)
784        return;
785      List<Location> found;
786      if (!simple_locs.TryGetValue (element, out found)) {
787        simple_locs.Add (element, new List<Location> (locations));
788        return;
789      }
790      found.AddRange(locations);
791    }
792
793    [Conditional ("FULL_AST")]
794    public void InsertLocation (object element, int index, Location location)
795    {
796      List<Location> found;
797      if (!simple_locs.TryGetValue (element, out found)) {
798        found = new List<Location> ();
799        simple_locs.Add (element, found);
800      }
801
802      found.Insert (index, location);
803    }
804
805    [Conditional ("FULL_AST")]
806    public void AddStatement (object element, params Location[] locations)
807    {
808      if (element == null)
809        return;
810      if (locations.Length == 0)
811        throw new ArgumentException ("Statement is missing semicolon location");
812      simple_locs.Add (element, new List<Location>(locations));
813    }
814
815    [Conditional ("FULL_AST")]
816    public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, params Location[] locations)
817    {
818      LastMember = member;
819      if (member == null)
820        return;
821     
822      MemberLocations existing;
823      if (member_locs.TryGetValue (member, out existing)) {
824        existing.Modifiers = modLocations;
825        existing.AddLocations (locations);
826        return;
827      }
828      member_locs.Add (member, new MemberLocations (modLocations, locations));
829    }
830
831    [Conditional ("FULL_AST")]
832    public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, IEnumerable<Location> locations)
833    {
834      LastMember = member;
835      if (member == null)
836        return;
837     
838      MemberLocations existing;
839      if (member_locs.TryGetValue (member, out existing)) {
840        existing.Modifiers = modLocations;
841        existing.AddLocations (locations);
842        return;
843      }
844      member_locs.Add (member, new MemberLocations (modLocations, locations));
845    }
846
847    [Conditional ("FULL_AST")]
848    public void AppendToMember (MemberCore existing, params Location[] locations)
849    {
850      AppendToMember (existing, (IEnumerable<Location>)locations);
851
852    }
853   
854    [Conditional ("FULL_AST")]
855    public void AppendToMember (MemberCore existing, IEnumerable<Location> locations)
856    {
857      if (existing == null)
858        return;
859      MemberLocations member;
860      if (member_locs.TryGetValue (existing, out member)) {
861        member.AddLocations (locations);
862        return;
863      }
864      member_locs.Add (existing, new MemberLocations (null, locations));
865    }
866
867    public List<Location> GetLocations (object element)
868    {
869      if (element == null)
870        return null;
871      List<Location> found;
872      simple_locs.TryGetValue (element, out found);
873      return found;
874    }
875
876    public MemberLocations GetMemberLocation (MemberCore element)
877    {
878      MemberLocations found;
879      member_locs.TryGetValue (element, out found);
880      return found;
881    }
882  }
883}
Note: See TracBrowser for help on using the repository browser.