2015-05-04 16 views
10

Sto scrivendo un parser di codice Delphi usando Parsec, i miei attuali strutture di dati AST simile a questa:Come posso gestire i commenti nel mio AST?

module Text.DelphiParser.Ast where 

data TypeName = TypeName String [String] deriving (Show) 
type UnitName = String 
data ArgumentKind = Const | Var | Out | Normal deriving (Show) 
data Argument = Argument ArgumentKind String TypeName deriving (Show) 
data MethodFlag = Overload | Override | Reintroduce | Static | StdCall deriving (Show) 
data ClassMember = 
     ConstField String TypeName 
    | VarField String TypeName 
    | Property String TypeName String (Maybe String) 
    | ConstructorMethod String [Argument] [MethodFlag] 
    | DestructorMethod String [Argument] [MethodFlag] 
    | ProcMethod String [Argument] [MethodFlag] 
    | FunMethod String [Argument] TypeName [MethodFlag] 
    | ClassProcMethod String [Argument] [MethodFlag] 
    | ClassFunMethod String [Argument] TypeName [MethodFlag] 
    deriving (Show) 
data Visibility = Private | Protected | Public | Published deriving (Show) 
data ClassSection = ClassSection Visibility [ClassMember] deriving (Show) 
data Class = Class String [ClassSection] deriving (Show) 
data Type = ClassType Class deriving (Show) 
data Interface = Interface [UnitName] [Type] deriving (Show) 
data Implementation = Implementation [UnitName] deriving (Show) 
data Unit = Unit String Interface Implementation deriving (Show) 

voglio conservare i commenti nei miei strutture dati AST e attualmente sto cercando di capire come fare Questo.

Il mio parser è diviso in un lexer e un parser (entrambi scritti con Parsec) e ho già implementato il lexing dei token dei commenti.

unit SomeUnit; 

interface 

uses 
    OtherUnit1, OtherUnit2; 

type 
    // This is my class that does blabla 
    TMyClass = class 
    var 
    FMyAttribute: Integer; 
    public 
    procedure SomeProcedure; 
    { The constructor takes an argument ... } 
    constructor Create(const Arg1: Integer); 
    end; 

implementation 

end. 

Il flusso di token si presenta così:

[..., Type, LineComment " This is my class that does blabla", Identifier "TMyClass", Equals, Class, ...] 

Il parser questo si traduce in:

Class "TMyClass" ... 

Il tipo di dati Class non ha alcun modo di allegare commenti e poiché i commenti (in particolare i commenti dei blocchi) potrebbero apparire quasi ovunque nel flusso di token. Dovrei aggiungere un commento facoltativo a tutti i tipi di dati nell'AST?

Come posso gestire i commenti nel mio AST?

+0

vedere anche http://stackoverflow.com/questions/9392546/pretty-print-haskell-source-code-with-comments e verificare come sono definiti questi AST. Ad esempio, http://hackage.haskell.org/package/haskell-src-exts-1.16.0.1/docs/Language-Haskell-Exts-Annotated-Syntax.html è polimorfico nell'annotazione. – d8d0d65b3f7cf42

risposta

11

Un approccio ragionevole per la gestione dei dati annotati su un AST è il threading di un parametro di tipo extra tramite che può contenere qualsiasi metadata desiderato. Oltre ad essere in grado di includere o ignorare in modo selettivo i commenti, questo ti permetterà anche di includere altri tipi di informazioni con il tuo albero.

In primo luogo, si dovrebbe riscrivere tutti i tipi di AST con un parametro aggiuntivo:

data TypeName a = TypeName a String [String] 
{- ... -} 
data ClassSection a = ClassSection a Visibility [ClassMember a] 
{- ... -} 

Sarebbe utile aggiungere deriving Functor a tutti loro pure, rendendo più semplice per trasformare le annotazioni su un dato AST .

Ora un AST con i commenti rimanenti avrebbe il tipo Class Comment o qualcosa del genere. Si potrebbe anche riutilizzare questo per ulteriori informazioni come l'analisi dell'ambito, dove si dovrebbe includere l'ambito corrente con la parte pertinente dell'AST.

Se si desideravano più annotazioni contemporaneamente, la soluzione più semplice sarebbe quella di utilizzare un record, anche se questo è un po 'imbarazzante perché (almeno per ora¹) non è facile scrivere codice polimorfico su campi di record. (Vale a dire che non si può facilmente scrivere il tipo di "qualsiasi record con un campo comments :: Comment".)

Una ulteriore cosa semplice si può fare è utilizzare PatternSynonyms (disponibile da GHC 7.8) per avere una suite di modelli che funzionano proprio come il tuo attuale AST non annotato, che ti consente di riutilizzare le tue dichiarazioni caso esistenti. (Per fare questo, dovrete anche per rinominare i costruttori per i tipi annotati in modo che non si sovrappongano.)

pattern TypeName a as <- TypeName' _ a as 

Note

¹ Speriamo parte 2 la revived overloaded record fields proposal aiuterà in questo riguardo quando viene effettivamente aggiunto alla lingua.

Problemi correlati