PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/ABB.SrcML.Data/ParserContext.cs

https://github.com/nkcsgexi/SrcML.NET
C# | 162 lines | 75 code | 17 blank | 70 comment | 10 complexity | 5256357d482855ae9cc2b2fbc8a93c18 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Xml.Linq;
  7. namespace ABB.SrcML.Data {
  8. /// <summary>
  9. /// Parser context objects store the current state of the <see cref="AbstractCodeParser.ParseElement(XElement,ParserContext)"/> method.
  10. /// </summary>
  11. public class ParserContext {
  12. private XElement fileUnitBeingParsed;
  13. /// <summary>
  14. /// Creates a new parser context
  15. /// </summary>
  16. public ParserContext() : this(null) { }
  17. /// <summary>
  18. /// Creates a new parser context
  19. /// </summary>
  20. /// <param name="fileUnit">The file unit for this context</param>
  21. public ParserContext(XElement fileUnit) {
  22. this.FileUnit = fileUnit;
  23. ParentScopeStack = new Stack<Scope>();
  24. ScopeStack = new Stack<Scope>();
  25. }
  26. /// <summary>
  27. /// The aliases for this context. This should be set by a call to <see cref="AbstractCodeParser.ParseUnitElement"/>.
  28. /// </summary>
  29. public Collection<Alias> Aliases { get; set; }
  30. /// <summary>
  31. /// The file name from <see cref="FileUnit"/>
  32. /// </summary>
  33. public string FileName { get; private set; }
  34. /// <summary>
  35. /// The file unit for this context. This should be set by a call to <see cref="AbstractCodeParser.ParseUnitElement"/>.
  36. /// Alternatively, this can be set manually for calls to other Parse methods in <see cref="AbstractCodeParser"/>.
  37. /// </summary>
  38. public XElement FileUnit {
  39. get { return this.fileUnitBeingParsed; }
  40. set {
  41. if(null != value) {
  42. if(value.Name != SRC.Unit) throw new ArgumentException("must be a SRC.Unit", "value");
  43. this.FileName = SrcMLElement.GetFileNameForUnit(value);
  44. } else {
  45. this.FileName = string.Empty;
  46. }
  47. this.fileUnitBeingParsed = value;
  48. }
  49. }
  50. /// <summary>
  51. /// the parent scope stack stores the parent of the scope being parsed. This is only used in specific cases such as the following C# example:
  52. /// <code language="C#">
  53. /// namespace A.B.C { }
  54. /// </code>
  55. /// In this example, we want the tree to be <c>A->B->C</c>. What <see cref="AbstractCodeParser.ParseNamespaceElement(XElement,ParserContext)"/> does
  56. /// in this case is create three namespaces: <c>A</c>, <c>B</c>, and <c>C</c> and puts them all on <see cref="ScopeStack"/>. Because we have created
  57. /// three elements, we need a way to track how many need to be popped off. the <c>A</c> namespace will be put placed on <see cref="ParentScopeStack"/>.
  58. /// <see cref="AbstractCodeParser.ParseElement(XElement,ParserContext)"/> will see that ParentScopeStack and <see cref="ScopeStack"/> are not equal and
  59. /// it will <see cref="System.Collections.Stack.Pop()"/> elements off until they are.
  60. /// </summary>
  61. private Stack<Scope> ParentScopeStack { get; set; }
  62. /// <summary>
  63. /// The scope stack stores all of the scopes being parsed. When <see cref="AbstractCodeParser.ParseElement(XElement,ParserContext)"/>
  64. /// creates a scope it pushes it onto the stack. Once it has finished creating the scope (including calling
  65. /// <see cref="AbstractCodeParser.ParseElement(XElement,ParserContext)"/> on all of its children), it removes it from the stack.
  66. /// </summary>
  67. private Stack<Scope> ScopeStack { get; set; }
  68. /// <summary>
  69. /// The current scope on <see cref="ParentScopeStack"/>. If the stack is empty, it returns null.
  70. /// </summary>
  71. public Scope CurrentParentScope {
  72. get {
  73. if(ParentScopeStack.Count > 0)
  74. return ParentScopeStack.Peek();
  75. return null;
  76. }
  77. }
  78. /// <summary>
  79. /// The current scope on <see cref="ScopeStack"/>. If the stack is empty, it returns null.
  80. /// </summary>
  81. public Scope CurrentScope {
  82. get {
  83. if(ScopeStack.Count > 0)
  84. return ScopeStack.Peek();
  85. return null;
  86. }
  87. }
  88. /// <summary>
  89. /// Creates a location object for the given <paramref name="element"/>.
  90. /// </summary>
  91. /// <param name="element">The element to create a location for</param>
  92. /// <param name="isReference">whether or not this is a reference location</param>
  93. /// <returns>The new location object. The <see cref="SourceLocation.SourceFileName"/> will be set to <see cref="FileName"/></returns>
  94. public SrcMLLocation CreateLocation(XElement element, bool isReference) {
  95. var location = new SrcMLLocation(element, this.FileName, isReference);
  96. return location;
  97. }
  98. /// <summary>
  99. /// Creates a location object for the given <paramref name="element"/>.
  100. /// </summary>
  101. /// <param name="element">The element to create a location for</param>
  102. /// <returns>The new location object. The <see cref="SourceLocation.SourceFileName"/> will be set to <see cref="FileName"/></returns>
  103. public SrcMLLocation CreateLocation(XElement element) {
  104. var location = new SrcMLLocation(element, this.FileName);
  105. return location;
  106. }
  107. /// <summary>
  108. /// Removes the most recent scope from the scope stack and returns it. If intermediate scopes were inserted, it calls <see cref="RevertToNextParent()"/>.
  109. /// </summary>
  110. /// <returns>the most recent scope.</returns>
  111. public Scope Pop() {
  112. RevertToNextParent();
  113. ParentScopeStack.Pop();
  114. return ScopeStack.Pop();
  115. }
  116. /// <summary>
  117. /// adds <paramref name="scope"/> to this scope stack. This simply calls <see cref="Push(Scope,Scope)"/> with both arguments set to <paramref name="scope"/>
  118. /// </summary>
  119. /// <param name="scope">the scope to add.</param>
  120. public void Push(Scope scope) {
  121. Push(scope, scope);
  122. }
  123. /// <summary>
  124. /// Adds <paramref name="scope"/> and <paramref name="parent">it's parent</paramref>. If <see cref="CurrentParentScope"/> is equal to <paramref name="parent"/>
  125. /// then parent is not added.
  126. /// </summary>
  127. /// <param name="scope"></param>
  128. /// <param name="parent"></param>
  129. public void Push(Scope scope, Scope parent) {
  130. ScopeStack.Push(scope);
  131. if(parent != CurrentParentScope) {
  132. ParentScopeStack.Push(parent);
  133. }
  134. }
  135. /// <summary>
  136. /// Removes scopes until <c>CurrentScope == CurrentParentScope</c>. As each scope is removed, it is added as a child to its predecessor.
  137. /// </summary>
  138. public void RevertToNextParent() {
  139. while(CurrentScope != CurrentParentScope) {
  140. var scope = ScopeStack.Pop();
  141. CurrentScope.AddChildScope(scope);
  142. }
  143. }
  144. }
  145. }