You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Les commentaires formalisés ont pour but de permettre au développeur de renseigner des métas donnés concernant les Nodes suivants :
Fonctions/Procédures
Types
Programmes
On récupère ces informations pour générer une documentation en y ajoutant des informations des Nodes eux même comme le nom, le Namespace ou encore la visibilité.
Scanner
Les TokenTypes et leur TokenFamilly sont présents dans TypeCobol/Compiler/Scanner/TokenType.cs.
Tout d’abord les balises ouvrantes et fermantes (des commentaires formalisés et multilignes) ne sont pas prises comme des commentaires standards pour qu’ils passent dans le scanner.
Les balises ouvrantes sont traitées dans le switch principale :
Le premier caractère visible par le scanner est le ‘<’ car le ‘*’ se trouve en colonne 7 et le scanner regarde a partir de la colonne 8. On teste quand même la présence du ‘*’ à la position n-1.
On détecte aussi les balises ouvrantes hors colonne 7 pour mettre un warning et quand même créer les Tokens pour ne pas gêner le parsing.
Quand on ajoute un Token de balise ouvrante ou fermante, on modifie le ScanState (MultilineScanState.cs) pour indiquer que l’on se trouve dans le contexte d’un commentaire formalisée.
Pour ne pas générer des Token propres à TypeCobol qui n’ont pas de sens dans le contexte des commentaires formalisées ou des commentaires multilignes, le reste du scan se fait dans un switch séparé du switch principal.
Ainsi, comme le scanner ne passe que dans le switch dédié aux commentaires formalisés si une balise ouvrante est trouvée, la détection de la balise fermante ne se fait que dans ce switch.
Les mots clés sont reconnus si le dernier token significatif est un ‘@’ via ScanCharacterString(startIndex) qui évalue le mot démarrant à startIndex. Si nous sommes dans le contexte d’un commentaire formalisé, on évalue le mot pour savoir à quel mot clé il correspond.
TokenType.UserDefinedWord est utilisé pour une clé de Params.
Pour autoriser les mots clés dans le nommage des paramètres, on vérifie que si on trouve un mot clé, que nous sommes juste après un ‘-‘ et que le précédent mot clé trouvé est le mot clé ‘@parameters’. Si c’est le cas, on corrige le Type de Token en TokenType.UserDefinedWord.
Enfin, si ce n’est ni un mot clé, ni une clé de ‘@parameters’, c’est une valeur. Les valeurs ne pouvant pas précéder d’autres Token sur une ligne, on regroupe tout le reste de la ligne dans un même Token TokenType.FormComsValue grâce à ScanUntilDelimiter(startIndex, tokenType, delimiter)
Cette méthode scanne le reste de la ligne et renvoie un Token du type spécifié allant jusqu’à la fin de la ligne ou jusqu’au délimiteur spécifié.
Le délimiteur ici est "*>>>", malgré le fait que ce soit pour l’instant impossible de le rencontrer, comme la balise fermante ne peux se trouver qu’en colonne 7. Cela permettra dans le futur d’avoir une syntaxe comme celle-ci :
*<<< Ici mon commentaire formalisé sur une seule ligne *>>>
Grammaire
La grammaire des commentaires formalisée se décompose comme suit :
Elle est composé de : une balise ouvrante, n lignes et une balise fermante.
Il existe trois types de lignes :
Les lignes de niveau « extérieur » qui commencent par ‘’@’’ sont composé d’un mot clé + ‘’ : ’’ (optionnel, le ‘’ : ‘’ n’a qu’un but de clarté du code) et une valeur (optionnel)
Les lignes de niveau « intérieur » servant à lister des valeurs se composent de ‘’-‘’ + une valeur dans le cas d’un listing simple (pour Todo et Needs) ou de ‘’-‘’ + clé (UserDefinedWord) + ‘’ : ’’ (optionnel, toujours un but de clarté) et une valeur. Un listItem de type clé-valeur ne s’applique que à ‘@params’.
Les lignes simplement composé d’une valeur qui sera rattaché à l’instruction précédente.
Cette grammaire s’intègre au début de celle d’une Fonction, d’une définition de type et d’une Procedure Division ainsi les tokens du commentaire formalisé sont inclue dans le CodeElements suivant et il n’y a donc pas de CodeElements dédiés aux commentaires formalisés
CodeElement
Commentaires formalisées
On implémente l’interface IFormalizedCommentable aux CodeElements applicables. Cette interface force ces CodeElements à avoir une propriété FormalizedCommentDocumentation de type FormalizedCommentDocumentation qui contiendra les données du commentaire formalisé.
La propriété privée _lastParameterRegistered enregistre la dernière clé ajouté à la propriété Parameters pour y rattacher les valeurs seules sur leur ligne (le cas d’une continuation de ligne). En effet, comme c’est un Dictionnaire, la propriété n’est pas ordonnée et n’a donc pas de « dernier » élément comme les listes Needs et ToDo
Les autres Propriétés sont les données renseignables dans un commentaire formalisé.
Il y a deux méthodes Add qui servent à ajouter une valeur à la propriété associée à un mot clé.
Pour les valeurs simples (tout sauf @params). isContinuation sert, dans le cas des listes, à spécifier si c’est la continuité d’une valeur ou une nouvelle valeur, donc de savoir s’il faut créer un nouvelle élément ou concaténer la valeur au dernier élément.
Le constructeur s’occupe de décortiquer le contexte retourné par Antlr et ajouter les bonnes valeurs aux bonnes propriétés.
Ces Propriétés sont créées au CodeElementBuilders directement après le parsing d’Antlr.
Commentaires multilignes
Il faut injecter les tokens des commentaires multilignes dans les CodeElements correspondant à leurs lignes pour pouvoir les repérer et les commenter dans la phase de génération de Code.
Ceci est effectué dans CodeElementsParserStep :
CrossCheck
Fonctions
Pour les fonctions, on vérifie si il y a des paramètres dans ‘@params’ qui ne correspondent pas à des paramètres présents dans la signature de la Fonction, pour y placer un Warning.
De la même manière, on vérifie si des paramètres présents dans la signature de la Fonction ne le sont pas dans la section ‘@params’ des commentaires formalisés pour y placer un Warning.
On vérifie enfin s’il y a un mot clé qui est déclaré deux fois pour y placer un Warning. Cette action est factorisée dans une méthode statique car elle est utilisée pour chaque structure acceptant un commentaire formalisé.
Type Définition
Pour les types on vérifie si il y le champ ‘@params’ déclaré pour y placer un Warning.
Enfin on vérifie s’il y a un mot clé qui est déclaré deux fois pour y placer un Warning.
Programmes
Pour les fonctions, on vérifie si il y a des paramètres dans‘@params’ qui ne correspondent pas à des paramètres présents dans la section using de la Procedure Division pour y placer un Warning.
De la même manière, on vérifie si des paramètres présents dans la section using de la Procedure Division ne le sont pas dans la section ‘@params’ des commentaires formalisées pour y placer un Warning.
On vérifie enfin s’il y a un mot clé qui est déclaré deux fois pour y placer un Warning.
Procédure Division
On vérifie si la Procédure Division à laquelle est rattachée le commentaire formalisé est bien la Procédure Division d’un Programme et pas d’une déclaration de fonction.
Génération de la documentation
La Génération de la documentation se fait en mettant l’argument du CLI OutputFormat à Documentation (-f 4 OU -f Documentation). Le générateur s’occupant de la documentation utilise un Visiteur dédié qui crée un DTO pour chaque TypeDefinition, FunctionDeclaration et Program et les stocke dans une liste de documentation.
Les DTOs :
A noter que les DTOs possèdent tous un constructeur par défaut vide qui est nécessaire à la sérialisation.
Documentation
Documentation est la classe de base qui implémente les propriétés et la logique commune aux trois types de commentaires formalisés. Elle contient tous les champs des commentaires formalisés sauf ‘@params’ qui ne sont utilisés que pour les fonctions et les procédures. Elle contient aussi des informations qui ne se trouvent pas dans les commentaires formalisés comme le nom, la visibilité et le namespace.
Elle initialise ses propriétés avec son constructeur :
A noter que Deprecated ne s’initialise pas comme les autres propriétés car il peut représenter un booléen à true si il contient un string vide, il ne faut donc pas utiliser IsNullOrEmpty().
Documentation possède aussi la méthode CreateAppropriateDocumentation() qui permet de créer un documentation sans savoir si le node est de type Program, FunctionDeclaration ou TypeDefinition. C’est la méthode qui est toujours utilisée pour créer une documentation.
C’est aussi Documentation qui implémente les méthodes de sérialisation. Pour l’instant en XML ou JSON, mais si un autre format est nécessaire, il suffit d'implémenter la nouvelle méthode à Documentation.
DocumentationDataType
DocumentationDataType définie les données communes aux variables présentes dans la documentation comme le type lui-même, ses éventuelles enfants, les paramètres de fonctions et les paramètres de programmes.
Elle est composée de deux constructeurs : DocumentationDataType(DataDefinition dataDef)
Qui prend en paramètre un DataDefinition, un node qui définit une donnée mais n’est pas serialisable directement. Ce constructeur en extrait la majeure partie de ses données directement et récupère la valeur par défaut de la variable avec son codeElement.
N’est jamais utilisé pour l’instant mais peut être utile si on doit créer un dataType sans avoir de DataDefinition.
DocumentationTypeChildren
DocumentationTypeChildren regroupe les données des enfants du type si ce dernier est un groupe. En plus du DocumentationDataType, il comporte des propriétés que l’on ne peut retrouver que chez les enfants d’un Type tel que les conditions des niveaux 88, IsBlankWhenZero, Justified etc.
IsSubGroup indique que cet enfant a lui-même des enfants.
Il est composé d’un constructeur prenant en paramètre un DataDefinition qui permet d’instancier toute les propriétés de l’objet.
DocumentationForType
Représente la documentation propre aux définitions de types. En plus des propriétés héritées de Documentation, elle contient les propriétés définissant son type de donnée DocDataType de type DocumentationDataType, IsBlankWhenZero et Justified qui sont des options utilisables pour un Type et ses enfants mais pas pour des paramètres de fonction/programmes, donc ne figurent pas dans DocumentationDataType. Elle comprend aussi la liste d’enfants du type pour y enregistrer leur DocumentationTypeChildren. À l’instar des Nodes, la liste de childrens ne possède que la DocumentationTypeChildren des enfants directs du type, les sous enfants se trouvent dans la liste de childrens de leurs parents directs.
Le constructeur de DocumentationForType prend le node documentable TypeDefinition pour en tirer, avec son codeElement, un maximum d’informations.
DocumentationParameter
DocumentationParameter regroupe les données des paramètres des fonctions et des programmes. En plus du DocumentationDataType, il comporte des propriétés que l’on ne peut retrouver que chez les paramètres tel que les informations renseignées dans les commentaires formalisés (@params), le passing type (input, output, inout) et son nom.
Le premier constructeur prend en paramètre un ParameterDescription contenant les informations liées au dataType et un string qui contient la description du commentaire formalisé si elle existe. Le passing type est contenu dans le ParameterDescription. Ce constructeur est utilisé par les Fonctions.
Le second constructeur prend en paramètre une DataDefinition contenant les informations liées au dataType, un string qui contient la description du commentaire formalisé si elle existe et un booléen qui indique si on doit déterminer le PassingTypes avec la description du commentaire formalisé ou non. Ce constructeur est utilisé par les Programmes car DataDefinition ne supporte pas le PassingTypes. Il faut donc le déterminer si possible.
La reconnaissance du PassingTypes se fait par la méthode suivante
Elle prend en paramètre la description du commentaire formalisé et en extrait le premier mot. Si ce dernier est ‘INPUT’, ‘OUTPUT’, ‘INOUT’ (case insensitive) alors on enregistre le passing type adéquat et on tronque l’info jusqu’au premier caractère alphabétique et on renvoie un Tuple<PassingTypes, string> du passing type trouvé et de la description tronquée. Ainsi, une description du type :
‘Input – Description de mon paramètre’
Donne le Tuple {PassingTypes.Input, ‘Description de mon paramètre’}
Et pas le Tuple {PassingTypes.Input, ‘ - Description de mon paramètre’}
DocumentationForFunction
En plus des propriétés héritées de Documentation, DocumentationForFunction n’a qu’une liste de DocumentationParameter.
Elle possède un seul constructeur qui construit la liste des paramètres :
DocumentationForProgram
Comme DocumentationForFunction, DocumentationForProgram n’ajoute qu’une liste de DocumentationParameter aux propriétés héritées de Documentation.
Elle possède un seul constructeur qui construit la liste des paramètres à partir des paramètres spécifiés dans la clause USING de la Procédure Division. À la différence de DocumentationForFunction, le passing type est déterminé à partir du commentaire formalisé et non pas dans la définition du paramètre.
DocumentationGenerator & DocumentationBuilder
Le passage du paramètre CLI OutputFormat à 4 (Documentation) permet d’utiliser le générateur dédié à la documentation DocumentationGenerator au lieu du générateur par défaut.
Il utilise un visiteur, DocumentationBuilder, qui contient une liste de DTOs. Il parcoure les Nodes en créant le DTO approprié selon le node trouvé (Program – Function – TypeDefinition), si ces derniers sont Publics.
Enfin, DocumentationGenerator récupère cette liste et, pour chacun d’eux, les sérialise et les concatène dans this.Destination.
La fonction Generate de DocumentationGenerator :
Le Visiteur DocumentationBuilder :
CodeGen
Commentaires formalisés
La génération du code est assez simple en théorie puisque nous n’avons qu’à commenter les lignes du commentaire formalisé. En pratique, il n’est pas possible de procéder comme pour les autre Nodes que nous devons commenter, car les commentaires formalisées ne constituent pas de Nodes propres. Ils font parties de codeElements existants et nous ne pouvons que commenter l’intégralité d’un Node.
Les Nodes de Function et de TypeDefinition sont déjà commentées dans le CodeGen. Il ne reste donc que les Nodes de Procedure Division directement enfants des Programs.
Ce Node se génère de deux manières, s’il contient une fonction déclaré en public ou non:
Avec une fonction public, C’est la propriété IEnumerable<TypeCobol.Compiler.Text.ITextLine> Lines du Node ProcedureDivision qui génère le code via son getter.
On parcoure les ConsumedTokens du Node : s’ils sont compris dans un commentaire formalisé, on commente la TokensLine (les autres ConsumedTokens de la TokensLine sont ignorés).
Sans fonction public. C’est la méthode CommentSpecificParts dans LinearNodeSourceCodeMapper qui commente ces lignes.
Cette méthode est appelée pour chaque Node et s’occupe de commenter les commentaires formalisés des ProcedureDivision appartenant au Program et les Commentaires Multilignes pouvant apparaitre n’importe où.
Dans les deux cas, la méthode
est appelée. Cette méthode commente toutes les lignes se trouvant entre les deux tokens passés en paramètre en injectant un ‘*’ dans leur buffer.
Un problème se pose cependant, Razor utilise le caractère ‘@’ comme mot clé. Cela pose donc problème pour les champs des commentaires formalisés. Il faut donc les échapper dans RazorEngine :
Enfin il ne reste que le cas de la génération des signatures à commenter dans SignaturesGenerator.
Pour se faire, à la création de chaque ligne à inscrire dans le fichier de sortie, si elle est dans un commentaire formalisé (entre les deux balises), on ajoute la ligne commentée. Sinon, on ajoute la ligne sans y toucher.
Commentaires Multilignes
Pour les commentaires multilignes, on distingue deux cas de figures :
Les commentaires multilignes appartenant à un Node (avec le commentaire entre deux lignes d’un même node par exemple)
Les commentaires multilignes libre donc sans Nodes (comme les commentaires classiques)
Les premiers sont commentés dans LinearNodeSourceCodeMapper avec la méthode CommentSpecificParts. Comme pour les commentaires formalisés, on parcoure chaque Nodes et on commente tout ce qui se trouve entre les balises.
Le second cas est géré dans DefaultGenerator. Pour chaque ligne n’appartenant à aucun Node, si elles sont entre les balises d’un commentaire multilignes, on les commente.
Ajout d’éléments
Nouveau mot clé
Pour ajouter un nouveau mot clé au commentaire formalisé, il faut suivre les étapes suivantes :
L’ajouter au Tokens et à la TokenFamily.
Dans TokenUtils, modifier la méthode
TokenType GetFormalComTokenTypeFromTokenString(string tokenString)
pour que le scanner reconnaisse le nouveau mot clé.
Inclure le nouveau dans CobolWords.g4 et dans la grammaire dans la liste des formalizedCommentParam.
Ajouter sa propriété à FormalizedCommentDocumentation, choisir le type selon les valeurs qu’on peut y mettre :
string pour une valeur simple et un flag
List pour une série de valeurs
Dictionary<string, string> pour une série de couples clé – valeurs
Extraire sa valeur dans le constructeur de FormalizedCommentDocumentation et l’ajouter à la propriété créée précédemment
Ajouter sa propriété à Documentation, DocumentationForType, DocumentationForFunction ou DocumentationForProgram selon ce à quoi s’applique le mot clé et y assigner la valeur extraite et transformée si besoin du commentaire formalisé.
Nouveau Node commentable
Pour ajouter un nouveau Node pouvant contenir un commentaire formalisé, il faut suivre les étapes suivantes :
Créer le Node désiré implémentant l’interface IDocumentable.
Créer un nouveau CodeElement implémentant IFormalizedCommentable ou si c’est un CodeElement existant qui sera utilisé, lui faire implémenter IFormalizedCommentable.
Modifier ou créer la grammaire de ce CodeElement en y ajoutant formalisedComment à l’emplacement souhaité.
Dans CodeElementBuilder, modifier la méthode liée à ce Node pour y mettre l’instanciation de FormalizedCommentDocumentation si le contexte Antlr contiens formalizedComment(), donc si Antlr a repéré un commentaire formalisé pour ce Node. Il faut passer au constructeur de FormalizedCommentDocumentation les formalizedCommentLine du contexte Antlr.
Vérifier si besoin dans CrossCheck que les champs du commentaire formalisé sont correctement remplis.
Il faut ensuite créer son DTO dans Documentation.cs héritant de la classe Documentation. Si la documentation du Node doit avoir des propriétés autre que celles communes dans documentation, alors il faut les ajouter à ce DTO et les instancier dans son constructeur.
Enfin, pour que la documentation se fasse correctement, dans DocumentationGenerator, au visiteur DocumentationBuilder, il faut ajouter une méthode Visit prenant en paramètre ce Node, y construire son DTO et l’ajouter à la liste de DTOs du visiteur.
En cas de modification des commentaires formalisés il est bon de créer des tests unitaires ou de mettre à jour les tests unitaires dédiés.
Commentaires Formalisées et Documentation
Principe de base
Les commentaires formalisés ont pour but de permettre au développeur de renseigner des métas donnés concernant les Nodes suivants :
On récupère ces informations pour générer une documentation en y ajoutant des informations des Nodes eux même comme le nom, le Namespace ou encore la visibilité.
Scanner
Les TokenTypes et leur TokenFamilly sont présents dans TypeCobol/Compiler/Scanner/TokenType.cs.
Tout d’abord les balises ouvrantes et fermantes (des commentaires formalisés et multilignes) ne sont pas prises comme des commentaires standards pour qu’ils passent dans le scanner.
Les balises ouvrantes sont traitées dans le switch principale :
Le premier caractère visible par le scanner est le ‘<’ car le ‘*’ se trouve en colonne 7 et le scanner regarde a partir de la colonne 8. On teste quand même la présence du ‘*’ à la position n-1.
On détecte aussi les balises ouvrantes hors colonne 7 pour mettre un warning et quand même créer les Tokens pour ne pas gêner le parsing.
Quand on ajoute un Token de balise ouvrante ou fermante, on modifie le ScanState (MultilineScanState.cs) pour indiquer que l’on se trouve dans le contexte d’un commentaire formalisée.
Pour ne pas générer des Token propres à TypeCobol qui n’ont pas de sens dans le contexte des commentaires formalisées ou des commentaires multilignes, le reste du scan se fait dans un switch séparé du switch principal.
Ainsi, comme le scanner ne passe que dans le switch dédié aux commentaires formalisés si une balise ouvrante est trouvée, la détection de la balise fermante ne se fait que dans ce switch.
Les mots clés sont reconnus si le dernier token significatif est un ‘@’ via ScanCharacterString(startIndex) qui évalue le mot démarrant à startIndex. Si nous sommes dans le contexte d’un commentaire formalisé, on évalue le mot pour savoir à quel mot clé il correspond.
TokenType.UserDefinedWord est utilisé pour une clé de Params.
Pour autoriser les mots clés dans le nommage des paramètres, on vérifie que si on trouve un mot clé, que nous sommes juste après un ‘-‘ et que le précédent mot clé trouvé est le mot clé ‘@parameters’. Si c’est le cas, on corrige le Type de Token en TokenType.UserDefinedWord.
Enfin, si ce n’est ni un mot clé, ni une clé de ‘@parameters’, c’est une valeur. Les valeurs ne pouvant pas précéder d’autres Token sur une ligne, on regroupe tout le reste de la ligne dans un même Token TokenType.FormComsValue grâce à ScanUntilDelimiter(startIndex, tokenType, delimiter)
Cette méthode scanne le reste de la ligne et renvoie un Token du type spécifié allant jusqu’à la fin de la ligne ou jusqu’au délimiteur spécifié.
Le délimiteur ici est "*>>>", malgré le fait que ce soit pour l’instant impossible de le rencontrer, comme la balise fermante ne peux se trouver qu’en colonne 7. Cela permettra dans le futur d’avoir une syntaxe comme celle-ci :
Grammaire
La grammaire des commentaires formalisée se décompose comme suit :
Elle est composé de : une balise ouvrante, n lignes et une balise fermante.
Il existe trois types de lignes :
Cette grammaire s’intègre au début de celle d’une Fonction, d’une définition de type et d’une Procedure Division ainsi les tokens du commentaire formalisé sont inclue dans le CodeElements suivant et il n’y a donc pas de CodeElements dédiés aux commentaires formalisés
CodeElement
Commentaires formalisées
On implémente l’interface IFormalizedCommentable aux CodeElements applicables. Cette interface force ces CodeElements à avoir une propriété FormalizedCommentDocumentation de type FormalizedCommentDocumentation qui contiendra les données du commentaire formalisé.
La propriété privée _lastParameterRegistered enregistre la dernière clé ajouté à la propriété Parameters pour y rattacher les valeurs seules sur leur ligne (le cas d’une continuation de ligne). En effet, comme c’est un Dictionnaire, la propriété n’est pas ordonnée et n’a donc pas de « dernier » élément comme les listes Needs et ToDo
Les autres Propriétés sont les données renseignables dans un commentaire formalisé.
Il y a deux méthodes Add qui servent à ajouter une valeur à la propriété associée à un mot clé.
Pour les valeurs simples (tout sauf @params). isContinuation sert, dans le cas des listes, à spécifier si c’est la continuité d’une valeur ou une nouvelle valeur, donc de savoir s’il faut créer un nouvelle élément ou concaténer la valeur au dernier élément.
Pour les couples clé-valeur (@params)
Le constructeur s’occupe de décortiquer le contexte retourné par Antlr et ajouter les bonnes valeurs aux bonnes propriétés.
Ces Propriétés sont créées au CodeElementBuilders directement après le parsing d’Antlr.
Commentaires multilignes
Il faut injecter les tokens des commentaires multilignes dans les CodeElements correspondant à leurs lignes pour pouvoir les repérer et les commenter dans la phase de génération de Code.
Ceci est effectué dans CodeElementsParserStep :
CrossCheck
Fonctions
Pour les fonctions, on vérifie si il y a des paramètres dans ‘@params’ qui ne correspondent pas à des paramètres présents dans la signature de la Fonction, pour y placer un Warning.
De la même manière, on vérifie si des paramètres présents dans la signature de la Fonction ne le sont pas dans la section ‘@params’ des commentaires formalisés pour y placer un Warning.
On vérifie enfin s’il y a un mot clé qui est déclaré deux fois pour y placer un Warning. Cette action est factorisée dans une méthode statique car elle est utilisée pour chaque structure acceptant un commentaire formalisé.
Type Définition
Pour les types on vérifie si il y le champ ‘@params’ déclaré pour y placer un Warning.
Enfin on vérifie s’il y a un mot clé qui est déclaré deux fois pour y placer un Warning.
Programmes
Pour les fonctions, on vérifie si il y a des paramètres dans‘@params’ qui ne correspondent pas à des paramètres présents dans la section using de la Procedure Division pour y placer un Warning.
De la même manière, on vérifie si des paramètres présents dans la section using de la Procedure Division ne le sont pas dans la section ‘@params’ des commentaires formalisées pour y placer un Warning.
On vérifie enfin s’il y a un mot clé qui est déclaré deux fois pour y placer un Warning.
Procédure Division
On vérifie si la Procédure Division à laquelle est rattachée le commentaire formalisé est bien la Procédure Division d’un Programme et pas d’une déclaration de fonction.
Génération de la documentation
La Génération de la documentation se fait en mettant l’argument du CLI OutputFormat à Documentation (-f 4 OU -f Documentation). Le générateur s’occupant de la documentation utilise un Visiteur dédié qui crée un DTO pour chaque TypeDefinition, FunctionDeclaration et Program et les stocke dans une liste de documentation.
Les DTOs :
A noter que les DTOs possèdent tous un constructeur par défaut vide qui est nécessaire à la sérialisation.
Documentation
Documentation est la classe de base qui implémente les propriétés et la logique commune aux trois types de commentaires formalisés. Elle contient tous les champs des commentaires formalisés sauf ‘@params’ qui ne sont utilisés que pour les fonctions et les procédures. Elle contient aussi des informations qui ne se trouvent pas dans les commentaires formalisés comme le nom, la visibilité et le namespace.
Elle initialise ses propriétés avec son constructeur :
A noter que Deprecated ne s’initialise pas comme les autres propriétés car il peut représenter un booléen à true si il contient un string vide, il ne faut donc pas utiliser IsNullOrEmpty().
Documentation possède aussi la méthode CreateAppropriateDocumentation() qui permet de créer un documentation sans savoir si le node est de type Program, FunctionDeclaration ou TypeDefinition. C’est la méthode qui est toujours utilisée pour créer une documentation.
C’est aussi Documentation qui implémente les méthodes de sérialisation. Pour l’instant en XML ou JSON, mais si un autre format est nécessaire, il suffit d'implémenter la nouvelle méthode à Documentation.
DocumentationDataType
DocumentationDataType définie les données communes aux variables présentes dans la documentation comme le type lui-même, ses éventuelles enfants, les paramètres de fonctions et les paramètres de programmes.
Elle est composée de deux constructeurs :
DocumentationDataType(DataDefinition dataDef)
Qui prend en paramètre un DataDefinition, un node qui définit une donnée mais n’est pas serialisable directement. Ce constructeur en extrait la majeure partie de ses données directement et récupère la valeur par défaut de la variable avec son codeElement.
Le second constructeur :
N’est jamais utilisé pour l’instant mais peut être utile si on doit créer un dataType sans avoir de DataDefinition.
DocumentationTypeChildren
DocumentationTypeChildren regroupe les données des enfants du type si ce dernier est un groupe. En plus du DocumentationDataType, il comporte des propriétés que l’on ne peut retrouver que chez les enfants d’un Type tel que les conditions des niveaux 88, IsBlankWhenZero, Justified etc.
IsSubGroup indique que cet enfant a lui-même des enfants.
Il est composé d’un constructeur prenant en paramètre un DataDefinition qui permet d’instancier toute les propriétés de l’objet.
DocumentationForType
Représente la documentation propre aux définitions de types. En plus des propriétés héritées de Documentation, elle contient les propriétés définissant son type de donnée DocDataType de type DocumentationDataType, IsBlankWhenZero et Justified qui sont des options utilisables pour un Type et ses enfants mais pas pour des paramètres de fonction/programmes, donc ne figurent pas dans DocumentationDataType. Elle comprend aussi la liste d’enfants du type pour y enregistrer leur DocumentationTypeChildren. À l’instar des Nodes, la liste de childrens ne possède que la DocumentationTypeChildren des enfants directs du type, les sous enfants se trouvent dans la liste de childrens de leurs parents directs.
Le constructeur de DocumentationForType prend le node documentable TypeDefinition pour en tirer, avec son codeElement, un maximum d’informations.
DocumentationParameter
DocumentationParameter regroupe les données des paramètres des fonctions et des programmes. En plus du DocumentationDataType, il comporte des propriétés que l’on ne peut retrouver que chez les paramètres tel que les informations renseignées dans les commentaires formalisés (@params), le passing type (input, output, inout) et son nom.
Il est composé de deux constructeurs :
Le premier constructeur prend en paramètre un ParameterDescription contenant les informations liées au dataType et un string qui contient la description du commentaire formalisé si elle existe. Le passing type est contenu dans le ParameterDescription. Ce constructeur est utilisé par les Fonctions.
Le second constructeur prend en paramètre une DataDefinition contenant les informations liées au dataType, un string qui contient la description du commentaire formalisé si elle existe et un booléen qui indique si on doit déterminer le PassingTypes avec la description du commentaire formalisé ou non. Ce constructeur est utilisé par les Programmes car DataDefinition ne supporte pas le PassingTypes. Il faut donc le déterminer si possible.
La reconnaissance du PassingTypes se fait par la méthode suivante
Elle prend en paramètre la description du commentaire formalisé et en extrait le premier mot. Si ce dernier est ‘INPUT’, ‘OUTPUT’, ‘INOUT’ (case insensitive) alors on enregistre le passing type adéquat et on tronque l’info jusqu’au premier caractère alphabétique et on renvoie un Tuple<PassingTypes, string> du passing type trouvé et de la description tronquée. Ainsi, une description du type :
‘Input – Description de mon paramètre’
Donne le Tuple {PassingTypes.Input, ‘Description de mon paramètre’}
Et pas le Tuple {PassingTypes.Input, ‘ - Description de mon paramètre’}
DocumentationForFunction
En plus des propriétés héritées de Documentation, DocumentationForFunction n’a qu’une liste de DocumentationParameter.
Elle possède un seul constructeur qui construit la liste des paramètres :
DocumentationForProgram
Comme DocumentationForFunction, DocumentationForProgram n’ajoute qu’une liste de DocumentationParameter aux propriétés héritées de Documentation.
Elle possède un seul constructeur qui construit la liste des paramètres à partir des paramètres spécifiés dans la clause USING de la Procédure Division. À la différence de DocumentationForFunction, le passing type est déterminé à partir du commentaire formalisé et non pas dans la définition du paramètre.
DocumentationGenerator & DocumentationBuilder
Le passage du paramètre CLI OutputFormat à 4 (Documentation) permet d’utiliser le générateur dédié à la documentation DocumentationGenerator au lieu du générateur par défaut.
Il utilise un visiteur, DocumentationBuilder, qui contient une liste de DTOs. Il parcoure les Nodes en créant le DTO approprié selon le node trouvé (Program – Function – TypeDefinition), si ces derniers sont Publics.
Enfin, DocumentationGenerator récupère cette liste et, pour chacun d’eux, les sérialise et les concatène dans this.Destination.
La fonction Generate de DocumentationGenerator :
Le Visiteur DocumentationBuilder :
CodeGen
Commentaires formalisés
La génération du code est assez simple en théorie puisque nous n’avons qu’à commenter les lignes du commentaire formalisé. En pratique, il n’est pas possible de procéder comme pour les autre Nodes que nous devons commenter, car les commentaires formalisées ne constituent pas de Nodes propres. Ils font parties de codeElements existants et nous ne pouvons que commenter l’intégralité d’un Node.
Les Nodes de Function et de TypeDefinition sont déjà commentées dans le CodeGen. Il ne reste donc que les Nodes de Procedure Division directement enfants des Programs.
Ce Node se génère de deux manières, s’il contient une fonction déclaré en public ou non:
Avec une fonction public, C’est la propriété IEnumerable<TypeCobol.Compiler.Text.ITextLine> Lines du Node ProcedureDivision qui génère le code via son getter.
On parcoure les ConsumedTokens du Node : s’ils sont compris dans un commentaire formalisé, on commente la TokensLine (les autres ConsumedTokens de la TokensLine sont ignorés).
Sans fonction public. C’est la méthode CommentSpecificParts dans LinearNodeSourceCodeMapper qui commente ces lignes.
Cette méthode est appelée pour chaque Node et s’occupe de commenter les commentaires formalisés des ProcedureDivision appartenant au Program et les Commentaires Multilignes pouvant apparaitre n’importe où.
Dans les deux cas, la méthode
est appelée. Cette méthode commente toutes les lignes se trouvant entre les deux tokens passés en paramètre en injectant un ‘*’ dans leur buffer.
Un problème se pose cependant, Razor utilise le caractère ‘@’ comme mot clé. Cela pose donc problème pour les champs des commentaires formalisés. Il faut donc les échapper dans RazorEngine :
Enfin il ne reste que le cas de la génération des signatures à commenter dans SignaturesGenerator.
Pour se faire, à la création de chaque ligne à inscrire dans le fichier de sortie, si elle est dans un commentaire formalisé (entre les deux balises), on ajoute la ligne commentée. Sinon, on ajoute la ligne sans y toucher.
Commentaires Multilignes
Pour les commentaires multilignes, on distingue deux cas de figures :
Les premiers sont commentés dans LinearNodeSourceCodeMapper avec la méthode CommentSpecificParts. Comme pour les commentaires formalisés, on parcoure chaque Nodes et on commente tout ce qui se trouve entre les balises.
Le second cas est géré dans DefaultGenerator. Pour chaque ligne n’appartenant à aucun Node, si elles sont entre les balises d’un commentaire multilignes, on les commente.
Ajout d’éléments
Nouveau mot clé
Pour ajouter un nouveau mot clé au commentaire formalisé, il faut suivre les étapes suivantes :
TokenType GetFormalComTokenTypeFromTokenString(string tokenString)
pour que le scanner reconnaisse le nouveau mot clé.
Nouveau Node commentable
Pour ajouter un nouveau Node pouvant contenir un commentaire formalisé, il faut suivre les étapes suivantes :
En cas de modification des commentaires formalisés il est bon de créer des tests unitaires ou de mettre à jour les tests unitaires dédiés.
Test du processus complet :
Test du CodeGen :
Test de sérialisation et CodeElement :
The text was updated successfully, but these errors were encountered: