Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
TDocumentation dotNet - Parsing.vb

Parsing.vb

Caricato da: Totem
Scarica il programma completo

  1. Imports System.Text.RegularExpressions
  2.  
  3. Namespace Parsing
  4.     Public Enum EntityType
  5.         [Namespace]
  6.         [Class]
  7.         [Structure]
  8.         [Enumerator]
  9.         [Interface]
  10.         [Delegate]
  11.         [Sub]
  12.         [Function]
  13.         [Property]
  14.         [Operator]
  15.         Field
  16.         [Event]
  17.         [Const]
  18.         None
  19.     End Enum
  20.  
  21.     Public Enum EntityCommentType
  22.         Generic
  23.         Method
  24.         [Property]
  25.     End Enum
  26.  
  27.     Public Class Entity
  28.         Private _Id, _Name As String
  29.         Private _Type As EntityType
  30.         Private _Declaration As String
  31.         Private _Documentation As Comments.DocumentationComment
  32.         Private _Parent As Entity
  33.         Private _Children As New List(Of Entity)
  34.  
  35.         Private Shared NormalTag As New Regex("\<(?<CommentType>(summary|remarks|see|seealso|returns|value))\>(?<Content>[\w\W]+?)\<\/\k<CommentType>\>", RegexOptions.Multiline)
  36.         Private Shared ParamTag As New Regex("\<(?<CommentType>(param|typeparam|exception))\s*(name|cref)\s*\=\s*""(?<ParamName>.+)""\s*\>(?<Content>[\w\W]+?)\<\/\k<CommentType>\>", RegexOptions.Multiline)
  37.  
  38.         Public Property Id() As String
  39.             Get
  40.                 Return _Id
  41.             End Get
  42.             Set(ByVal value As String)
  43.                 _Id = value
  44.             End Set
  45.         End Property
  46.  
  47.         Public Property Name() As String
  48.             Get
  49.                 Return _Name
  50.             End Get
  51.             Set(ByVal value As String)
  52.                 _Name = value
  53.             End Set
  54.         End Property
  55.  
  56.         Public Property Type() As EntityType
  57.             Get
  58.                 Return _Type
  59.             End Get
  60.             Set(ByVal Value As EntityType)
  61.                 _Type = Value
  62.             End Set
  63.         End Property
  64.  
  65.         Public Property Declaration() As String
  66.             Get
  67.                 Return _Declaration
  68.             End Get
  69.             Set(ByVal Value As String)
  70.                 _Declaration = Value
  71.             End Set
  72.         End Property
  73.  
  74.         Public Property Documentation() As Comments.DocumentationComment
  75.             Get
  76.                 Return _Documentation
  77.             End Get
  78.             Set(ByVal Value As Comments.DocumentationComment)
  79.                 _Documentation = Value
  80.             End Set
  81.         End Property
  82.  
  83.         Public Property Parent() As Entity
  84.             Get
  85.                 Return _Parent
  86.             End Get
  87.             Set(ByVal value As Entity)
  88.                 _Parent = value
  89.             End Set
  90.         End Property
  91.  
  92.         Public Property Children() As List(Of Entity)
  93.             Get
  94.                 Return _Children
  95.             End Get
  96.             Set(ByVal value As List(Of Entity))
  97.                 _Children = value
  98.             End Set
  99.         End Property
  100.  
  101.  
  102.         Friend Function GetComment() As Comments.DocumentationComment
  103.             If Me.Type = EntityType.Property Then
  104.                 Return New Comments.PropertyComment
  105.             End If
  106.  
  107.             If Me.Type = EntityType.Function Or Me.Type = EntityType.Sub Or _
  108.                Me.Type = EntityType.Delegate Or Me.Type = EntityType.Operator Then
  109.                 Return New Comments.MethodComment
  110.             End If
  111.  
  112.             Return New Comments.GenericComment
  113.         End Function
  114.  
  115.         Friend Function GetCommentType() As EntityCommentType
  116.             If Me.Type = EntityType.Property Then
  117.                 Return EntityCommentType.Property
  118.             End If
  119.  
  120.             If Me.Type = EntityType.Function Or Me.Type = EntityType.Sub Or _
  121.                Me.Type = EntityType.Delegate Or Me.Type = EntityType.Operator Then
  122.                 Return EntityCommentType.Method
  123.             End If
  124.  
  125.             Return EntityCommentType.Generic
  126.         End Function
  127.  
  128.         Friend Function IsContainer() As Boolean
  129.             Return IsTypeContainer(Me.Type)
  130.         End Function
  131.  
  132.         Friend Function IsMemberContainer() As Boolean
  133.             Return IsTypeMemberContainer(Me.Type)
  134.         End Function
  135.  
  136.         Friend Function IsOneLine() As Boolean
  137.             Return IsTypeOneLine(Me.Type)
  138.         End Function
  139.  
  140.         Friend Shared Function IsTypeContainer(ByVal Type As EntityType) As Boolean
  141.             If Type = EntityType.Class Or Type = EntityType.Namespace Or _
  142.                Type = EntityType.Enumerator Or Type = EntityType.Interface Or _
  143.                Type = EntityType.Structure Then
  144.                 Return True
  145.             Else
  146.                 Return False
  147.             End If
  148.         End Function
  149.  
  150.         Friend Shared Function IsTypeMemberContainer(ByVal Type As EntityType) As Boolean
  151.             If Type = EntityType.Function Or Type = EntityType.Property Or _
  152.                Type = EntityType.Sub Or Type = EntityType.Operator Then
  153.                 Return True
  154.             Else
  155.                 Return False
  156.             End If
  157.         End Function
  158.  
  159.         Friend Shared Function IsTypeOneLine(ByVal Type As EntityType)
  160.             If Type = EntityType.Const Or Type = EntityType.Delegate Or Type = EntityType.Event Or Type = EntityType.Field Then
  161.                 Return True
  162.             Else
  163.                 Return False
  164.             End If
  165.         End Function
  166.  
  167.         Friend Shared Function CreateFromDeclaration(ByVal Declaration As String) As Entity
  168.             Dim Result As New Entity
  169.             Dim Id As String = CodeParser.GetNameFromDeclaration(Declaration)
  170.  
  171.             Result.Id = Id
  172.             Result.Name = Id
  173.             Result.Type = CodeParser.GetTypeFromDeclaration(Declaration)
  174.             Result.Declaration = Declaration.Trim
  175.             Result.Documentation = Result.GetComment()
  176.             Result.Documentation.Summary = "Documentazione assente."
  177.  
  178.             Return Result
  179.         End Function
  180.  
  181.         Private Function NormalizeComment(ByVal Content As String) As String
  182.             Content = Content.Replace("'''", "")
  183.             Content = Content.Replace(vbCrLf, " ")
  184.             Content = Content.Replace("  ", " ")
  185.             Content = Content.Replace("<example>", "<br><br><i>Esempio:</i><br>")
  186.             Content = Content.Replace("</example>", "")
  187.             Content = Content.Replace("<list>", "<ul>")
  188.             Content = Content.Replace("</list>", "</ul>")
  189.             Content = Content.Replace("<item>", "<li>")
  190.             Content = Content.Replace("</item>", "</li>")
  191.             Content = Content.Replace("<para>", "<p>")
  192.             Content = Content.Replace("</para>", "</p>")
  193.             Return Content.Trim
  194.         End Function
  195.  
  196.  
  197.         Friend Sub ParseDocumentation(ByVal XmlComments As String)
  198.             If String.IsNullOrEmpty(XmlComments) Then
  199.                 Exit Sub
  200.             End If
  201.  
  202.             Dim NormalComments As MatchCollection = NormalTag.Matches(XmlComments)
  203.             Dim Doc As Comments.DocumentationComment = Me.GetComment()
  204.             Dim C As EntityCommentType = Me.GetCommentType()
  205.  
  206.             For Each NC As Match In NormalComments
  207.                 Dim CommentType As String = NC.Groups("CommentType").Value
  208.                 Dim Content As String = NC.Groups("Content").Value
  209.  
  210.                 Select Case CommentType
  211.                     Case "summary"
  212.                         Doc.Summary = NormalizeComment(Content)
  213.                     Case "remarks"
  214.                         Doc.Remarks = NormalizeComment(Content)
  215.                     Case "see"
  216.                         Doc.See = NormalizeComment(Content)
  217.                     Case "seealso"
  218.                         Doc.SeeAlso = NormalizeComment(Content)
  219.                     Case "returns"
  220.                         If Me.Type = EntityType.Function Or Me.Type = EntityType.Property Then
  221.                             DirectCast(Doc, Comments.MethodComment).Returns = NormalizeComment(Content)
  222.                         End If
  223.                     Case "value"
  224.                         If Me.Type = EntityType.Property Then
  225.                             DirectCast(Doc, Comments.PropertyComment).Value = NormalizeComment(Content)
  226.                         End If
  227.                 End Select
  228.             Next
  229.  
  230.             If C = EntityCommentType.Generic Then
  231.                 Me.Documentation = Doc
  232.                 Exit Sub
  233.             End If
  234.  
  235.             Dim ParamComments As MatchCollection = ParamTag.Matches(XmlComments)
  236.             Dim DetailedDoc As Comments.MethodComment = CType(Doc, Comments.MethodComment)
  237.  
  238.             For Each PC As Match In ParamComments
  239.                 Dim CommentType As String = PC.Groups("CommentType").Value
  240.                 Dim Content As String = PC.Groups("Content").Value
  241.                 Dim ParamName As String = PC.Groups("ParamName").Value
  242.  
  243.                 Select Case CommentType
  244.                     Case "param"
  245.                         DetailedDoc.Params.Add(ParamName, NormalizeComment(Content))
  246.                     Case "typeparam"
  247.                         DetailedDoc.TypeParams.Add(ParamName, NormalizeComment(Content))
  248.                     Case "exception"
  249.                         DetailedDoc.Exceptions.Add(ParamName, NormalizeComment(Content))
  250.                 End Select
  251.             Next
  252.  
  253.             Me.Documentation = DetailedDoc
  254.         End Sub
  255.  
  256.         Public Overrides Function ToString() As String
  257.             Return Me.Declaration
  258.         End Function
  259.     End Class
  260.  
  261.     Public Class ParserResult
  262.         Inherits List(Of Entity)
  263.     End Class
  264.  
  265.     Public Class CodeParser
  266.         Private _Code As String
  267.  
  268.         Private Shared Keywords() As String = New String() _
  269.         {"<summary>", "<remarks>", "<see>", "<seealso>", "<returns>", "<value>", _
  270.         "<param", "<typeparam", "<exception"}
  271.  
  272.         Private Shared NamespaceRegex As New Regex("Namespace\s+(?<Id>([\w_][\w\d_]*))")
  273.         Private Shared ClassRegex As New Regex("(Class|Module)\s+(?<Id>([\w_][\w\d_]*))")
  274.         Private Shared EnumRegex As New Regex("Enum\s+(?<Id>([\w_][\w\d_\(\)]*))")
  275.         Private Shared StructureRegex As New Regex("Structure\s+(?<Id>([\w_][\w\d_]*))")
  276.         Private Shared InterfaceRegex As New Regex("Interface\s+(?<Id>([\w_][\w\d_]*))")
  277.         Private Shared DelegateRegex As New Regex("Delegate\s+(Sub|Function)\s+(?<Id>([\w_][\w\d_]*))")
  278.         Private Shared SubRegex As New Regex("Sub\s+(?<Id>([\w_][\w\d_]*))\(")
  279.         Private Shared FunctionRegex As New Regex("Function\s+(?<Id>([\w_][\w\d_]*))\(")
  280.         Private Shared PropertyRegex As New Regex("Property\s+(?<Id>([\w_][\w\d_]*))\(")
  281.         Private Shared ConstRegex As New Regex("Const\s+(?<Id>([\w_][\w\d_]*))")
  282.         Private Shared FieldRegex As New Regex("(Dim|Private|Public|Friend|Protected|Protected Friend|Static)\s*(Shared)?\s*(ReadOnly|WriteOnly)?\s*(?<Id>([\w_][\w\d_]*))")
  283.         Private Shared EventRegex As New Regex("Event\s+(?<Id>([\w_][\w\d_]*))")
  284.         Private Shared OperatorRegex As New Regex("Operator\s+(?<Id>(\<|\>|\=|\<\>|\+|\-|\*|\/|\\|\^|\&|\<\<|\>\>|\<\=|\>\=|And|Or|Xor|Not|IsTrue|IsFalse|Like|Mod|CType))\(")
  285.  
  286.         Public Property Code() As String
  287.             Get
  288.                 Return _Code
  289.             End Get
  290.             Set(ByVal value As String)
  291.                 _Code = value
  292.             End Set
  293.         End Property
  294.  
  295.         Sub New(ByVal FileName As String)
  296.             Me.Code = IO.File.ReadAllText(FileName)
  297.         End Sub
  298.  
  299.         Sub New()
  300.  
  301.         End Sub
  302.  
  303.         Public Sub Load(ByVal FileName As String)
  304.             Dim B As New IO.BinaryReader(New IO.FileStream(FileName, IO.FileMode.Open))
  305.             Dim Buffer As New System.Text.StringBuilder
  306.  
  307.             Do While B.BaseStream.Position < B.BaseStream.Length
  308.                 Dim O As Byte = B.ReadByte
  309.                 Select Case O
  310.                     Case 224
  311.                         Buffer.Append("à")
  312.                     Case 232
  313.                         Buffer.Append("è")
  314.                     Case 236
  315.                         Buffer.Append("ì")
  316.                     Case 242
  317.                         Buffer.Append("ò")
  318.                     Case 249
  319.                         Buffer.Append("ù")
  320.                     Case 233
  321.                         Buffer.Append("é")
  322.                     Case Else
  323.                         Buffer.Append(Chr(O))
  324.                 End Select
  325.             Loop
  326.  
  327.             Me.Code = Buffer.ToString
  328.         End Sub
  329.  
  330.         Friend Shared Function GetTypeFromDeclaration(ByVal Declaration As String) As EntityType
  331.             If NamespaceRegex.IsMatch(Declaration) Then
  332.                 Return EntityType.Namespace
  333.             End If
  334.             If ClassRegex.IsMatch(Declaration) Then
  335.                 Return EntityType.Class
  336.             End If
  337.             If EnumRegex.IsMatch(Declaration) Then
  338.                 Return EntityType.Enumerator
  339.             End If
  340.             If StructureRegex.IsMatch(Declaration) Then
  341.                 Return EntityType.Structure
  342.             End If
  343.             If InterfaceRegex.IsMatch(Declaration) Then
  344.                 Return EntityType.Interface
  345.             End If
  346.             If DelegateRegex.IsMatch(Declaration) Then
  347.                 Return EntityType.Delegate
  348.             End If
  349.             If SubRegex.IsMatch(Declaration) Then
  350.                 Return EntityType.Sub
  351.             End If
  352.             If FunctionRegex.IsMatch(Declaration) Then
  353.                 Return EntityType.Function
  354.             End If
  355.             If PropertyRegex.IsMatch(Declaration) Then
  356.                 Return EntityType.Property
  357.             End If
  358.             If EventRegex.IsMatch(Declaration) Then
  359.                 Return EntityType.Event
  360.             End If
  361.             If ConstRegex.IsMatch(Declaration) Then
  362.                 Return EntityType.Const
  363.             End If
  364.             If OperatorRegex.IsMatch(Declaration) Then
  365.                 Return EntityType.Operator
  366.             End If
  367.             If FieldRegex.IsMatch(Declaration) Then
  368.                 Return EntityType.Field
  369.             End If
  370.             Return EntityType.None
  371.         End Function
  372.  
  373.         Friend Shared Function GetNameFromDeclaration(ByVal Declaration As String) As String
  374.             Dim Regexes() As Regex = New Regex() _
  375.                 {NamespaceRegex, ClassRegex, EnumRegex, StructureRegex, InterfaceRegex, _
  376.                 DelegateRegex, SubRegex, FunctionRegex, PropertyRegex, EventRegex, ConstRegex, _
  377.                 OperatorRegex, FieldRegex}
  378.             Dim M As Match
  379.  
  380.             For Each R As Regex In Regexes
  381.                 M = R.Match(Declaration)
  382.                 If M.Success Then
  383.                     Return M.Groups("Id").Value
  384.                 End If
  385.             Next
  386.  
  387.             Return ""
  388.         End Function
  389.  
  390.         Friend Shared Function GetNameFromType(ByVal Type As EntityType)
  391.             Select Case Type
  392.                 Case EntityType.Class
  393.                     Return "Classe"
  394.                 Case EntityType.Delegate
  395.                     Return "Delegato"
  396.                 Case EntityType.Enumerator
  397.                     Return "Enumeratore"
  398.                 Case EntityType.Field
  399.                     Return "Campo"
  400.                 Case EntityType.Function
  401.                     Return "Funzione"
  402.                 Case EntityType.Interface
  403.                     Return "Interfaccia"
  404.                 Case EntityType.Namespace
  405.                     Return "Spazio dei nomi"
  406.                 Case EntityType.Property
  407.                     Return "Proprietà"
  408.                 Case EntityType.Structure
  409.                     Return "Struttura"
  410.                 Case EntityType.Sub
  411.                     Return "Procedura"
  412.                 Case EntityType.Event
  413.                     Return "Evento"
  414.                 Case EntityType.Const
  415.                     Return "Costante"
  416.                 Case EntityType.Operator
  417.                     Return "Operatore"
  418.                 Case EntityType.None
  419.                     Return ""
  420.             End Select
  421.             Return ""
  422.         End Function
  423.  
  424.         Public Function ParseCode() As ParserResult
  425.             Dim Result As New ParserResult
  426.             Dim Reader As New IO.StringReader(Me.Code)
  427.             Dim XmlStarted As Boolean = False
  428.             Dim Line As String
  429.             Dim TempXml As New System.Text.StringBuilder()
  430.             Dim CurrentEntity As Entity = Nothing
  431.             Dim CurrentBlock As EntityType = EntityType.None
  432.  
  433.             Do While Reader.Peek >= 0
  434.                 Line = Reader.ReadLine
  435.  
  436.                 If (Not XmlStarted) And (Line.Contains("'''")) Then
  437.                     'Inzia un commento xml
  438.                     For Each Keyword As String In Keywords
  439.                         If Line.Contains(Keyword) Then
  440.                             XmlStarted = True
  441.                             Exit For
  442.                         End If
  443.                     Next
  444.                 End If
  445.  
  446.                 If (Not XmlStarted) Then
  447.                     'Inizia un contenitore (classe/namespace/struttura/enumeratore/interfaccia)
  448.                     '(Not Line.Contains("Private")) And (Not Line.Contains("Protected")) And _
  449.                     If GetTypeFromDeclaration(Line) <> EntityType.None Then
  450.                         Dim El As Entity = Entity.CreateFromDeclaration(Line)
  451.  
  452.                         If (Not Entity.IsTypeContainer(CurrentBlock)) And _
  453.                            (El.Type = EntityType.Field Or El.Type = EntityType.Const Or El.Type = EntityType.Event) Then
  454.                             'Variabili e costanti locali non vengono contate
  455.                         Else
  456.                             If Not El.IsOneLine Then
  457.                                 'Nelle interfacce, i membri non hanno corpo, e i
  458.                                 'i membri MustOverride nemmeno
  459.                                 If Not (CurrentBlock = EntityType.Interface Or El.Declaration.Contains("MustOverride")) Then
  460.                                     CurrentBlock = El.Type
  461.                                 End If
  462.                             End If
  463.                             If CurrentEntity Is Nothing Then
  464.                                 CurrentEntity = El
  465.                                 Result.Add(El)
  466.                             Else
  467.                                 El.Parent = CurrentEntity
  468.                                 CurrentEntity.Children.Add(El)
  469.                                 If El.IsContainer Then
  470.                                     CurrentEntity = El
  471.                                 End If
  472.                             End If
  473.                             End If
  474.                     End If
  475.                 End If
  476.  
  477.                 If (XmlStarted) And (Not Line.Contains("'''")) Then
  478.                     'Attributo custom
  479.                     If (Line.Contains("<") Or Line.Contains(">")) And (Not Line.Contains("Shared Operator")) Then
  480.                         Continue Do
  481.                     End If
  482.  
  483.                     'Finisce il commento xml, inizia una dichiarazione
  484.                     '(Not Line.Contains("Private")) And (Not Line.Contains("Protected")) And _
  485.                     If GetTypeFromDeclaration(Line) <> EntityType.None Then
  486.                         Dim El As Entity = Entity.CreateFromDeclaration(Line)
  487.                         'I "_" continuano la dichiarazione
  488.                         Do While Line.EndsWith("_")
  489.                             Line = Reader.ReadLine
  490.                             El.Declaration &= Line
  491.                         Loop
  492.                         El.ParseDocumentation(TempXml.ToString)
  493.  
  494.                         If (Not Entity.IsTypeContainer(CurrentBlock)) And _
  495.                            (El.Type = EntityType.Field Or El.Type = EntityType.Const Or El.Type = EntityType.Event) Then
  496.                             'Variabili e costanti locali non vengono contate
  497.                         Else
  498.                             If Not El.IsOneLine Then
  499.                                 'Nelle interfacce, i membri non hanno corpo, e i
  500.                                 'i membri MustOverride nemmeno
  501.                                 If Not (CurrentBlock = EntityType.Interface Or El.Declaration.Contains("MustOverride")) Then
  502.                                     CurrentBlock = El.Type
  503.                                 End If
  504.                             End If
  505.                             If CurrentEntity Is Nothing Then
  506.                                 CurrentEntity = El
  507.                                 Result.Add(El)
  508.                             Else
  509.                                 El.Parent = CurrentEntity
  510.                                 CurrentEntity.Children.Add(El)
  511.                                 If El.IsContainer Then
  512.                                     CurrentEntity = El
  513.                                 End If
  514.                             End If
  515.                             End If
  516.                     End If
  517.  
  518.                     XmlStarted = False
  519.                     TempXml.Remove(0, TempXml.Length)
  520.                 End If
  521.  
  522.                 If Line.Contains("End Class") Or Line.Contains("End Namespace") Or _
  523.                    Line.Contains("End Interface") Or Line.Contains("End Enum") Or _
  524.                    Line.Contains("End Structure") Then
  525.                     'Finisce un contenitore
  526.                     CurrentEntity = CurrentEntity.Parent
  527.                     If CurrentEntity IsNot Nothing Then
  528.                         CurrentBlock = CurrentEntity.Type
  529.                     Else
  530.                         CurrentBlock = EntityType.None
  531.                     End If
  532.                 End If
  533.  
  534.                 If Line.Contains("End Sub") Or Line.Contains("End Function") Or _
  535.                    Line.Contains("End Event") Or Line.Contains("End Property") Or Line.Contains("End Operator") Then
  536.                     CurrentBlock = CurrentEntity.Type
  537.                 End If
  538.  
  539.  
  540.                 If XmlStarted Then
  541.                     'Continue il commento xml
  542.                     TempXml.AppendLine(Line)
  543.                 End If
  544.             Loop
  545.             Reader.Close()
  546.  
  547.             Return Result
  548.         End Function
  549.     End Class
  550. End Namespace