cimple-0.0.16: src/Language/Cimple/CommentParser.y
{
{-# LANGUAGE OverloadedStrings #-}
module Language.Cimple.CommentParser
( parseComment
) where
import Data.Fix (Fix (..))
import Data.Text (Text)
import qualified Data.Text as Text
import Language.Cimple.Ast (AssignOp (..), BinaryOp (..),
Comment, CommentF (..))
import Language.Cimple.DescribeAst (describeLexeme, sloc)
import Language.Cimple.Lexer (Lexeme (..))
import Language.Cimple.ParseResult (ParseResult)
import Language.Cimple.Tokens (LexemeClass (..))
}
%name parseComment Comment
%expect 0
%error {parseError}
%errorhandlertype explist
%monad {ParseResult}
%tokentype {Term}
%token
'@attention' { L _ CmtCommand "@attention" }
'@brief' { L _ CmtCommand "@brief" }
'@deprecated' { L _ CmtCommand "@deprecated" }
'@extends' { L _ CmtCommand "@extends" }
'@implements' { L _ CmtCommand "@implements" }
'@param' { L _ CmtCommand "@param" }
'@private' { L _ CmtCommand "@private" }
'@ref' { L _ CmtCommand "@ref" }
'@p' { L _ CmtCommand "@p" }
'@return' { L _ CmtCommand "@return" }
'@retval' { L _ CmtCommand "@retval" }
'@see' { L _ CmtCommand "@see" }
' ' { L _ CmtIndent " " }
'INDENT1' { L _ CmtIndent " " }
'INDENT2' { L _ CmtIndent " " }
'INDENT3' { L _ CmtIndent " " }
'(' { L _ PctLParen _ }
')' { L _ PctRParen _ }
',' { L _ PctComma _ }
':' { L _ PctColon _ }
'/' { L _ PctSlash _ }
'=' { L _ PctEq _ }
'==' { L _ PctEqEq _ }
'!=' { L _ PctEMarkEq _ }
'>=' { L _ PctGreaterEq _ }
';' { L _ PctSemicolon _ }
'.' { L _ PctPeriod _ }
'...' { L _ PctEllipsis _ }
'?' { L _ PctQMark _ }
'!' { L _ PctEMark _ }
'-' { L _ PctMinus _ }
'+' { L _ PctPlus _ }
'\n' { L _ PpNewline _ }
'/**' { L _ CmtStartDoc _ }
'*/' { L _ CmtEnd _ }
LIT_INTEGER { L _ LitInteger _ }
LIT_STRING { L _ LitString _ }
CMT_ATTR { L _ CmtAttr _ }
CMT_CODE { L _ CmtCode _ }
CMT_WORD { L _ CmtWord _ }
CMT_REF { L _ CmtRef _ }
%right '='
%left '.' '?' ',' ';' '!'
%left '!=' '=='
%left '>='
%left '-' '+'
%left '/'
%left '(' ')'
%%
Comment :: { NonTerm }
Comment
: '/**' '\n' Blocks '*/' { Fix $ DocComment $3 }
| '/**' DocLine '*/' { Fix $ DocComment $2 }
| '/**' Command(DocLine) '*/' { Fix $ DocComment [$2] }
| '/**' Command(IndentedSentence) Blocks '*/' { Fix $ DocComment ($2 : $3) }
Blocks :: { [NonTerm] }
Blocks
: BlockList { reverse $1 }
BlockList :: { [NonTerm] }
BlockList
: Block { [$1] }
| BlockList Block { $2 : $1 }
Block :: { NonTerm }
Block
: '\n' { Fix DocNewline }
| ' ' Command(IndentedSentence) { $2 }
| ' ' Paragraph { Fix $ DocParagraph $2 }
| ' ' NumberedListItem { Fix $ DocList [$2] }
| ' ' BulletListItem { Fix $ DocList [$2] }
Paragraph :: { [NonTerm] }
Paragraph
: Word(NonInt) Punctuation MaybeWords { Fix (DocSentence [$1] $2) : $3 }
| Word(NonInt) MaybeWords { prepend $1 $2 }
Punctuation :: { Term }
Punctuation
: '.' { $1 }
| ',' { $1 }
| ';' { $1 }
| '?' { $1 }
MaybeWords :: { [NonTerm] }
MaybeWords
: { [] }
| IndentedSentence { $1 }
IndentedSentence :: { [NonTerm] }
IndentedSentence
: DocLine '\n' { $1 }
| DocLine '\n' 'INDENT1' IndentedSentence { $1 ++ $4 }
DocLine :: { [NonTerm] }
DocLine
: Words { [Fix $ DocLine $1] }
Command(x)
: '@attention' x { Fix $ DocAttention $2 }
| '@brief' x { Fix $ DocBrief $2 }
| '@param' CMT_WORD x { Fix $ DocParam Nothing $2 $3 }
| '@param' CMT_ATTR CMT_WORD x { Fix $ DocParam (Just $2) $3 $4 }
| '@retval' Atom x { Fix $ DocRetval $2 $3 }
| '@return' x { Fix $ DocReturn $2 }
| '@return' '\n' BulletListItemII { Fix $ DocReturn (Fix (DocLine []) : $3) }
| '@see' CMT_WORD x { Fix $ DocSee $2 $3 }
| '@deprecated' x { Fix $ DocDeprecated $2 }
| '@implements' CMT_WORD { Fix $ DocImplements $2 }
| '@extends' CMT_WORD { Fix $ DocExtends $2 }
| '@private' { Fix DocPrivate }
BulletListItem :: { NonTerm }
BulletListItem
: '-' Words '\n' BulletICont { Fix $ DocULItem $2 $4 }
BulletICont :: { [NonTerm] }
BulletICont
: { [] }
| 'INDENT1' DocLine '\n' BulletICont { $2 ++ $4 }
| BulletListItemII { $1 }
BulletListItemII :: { [NonTerm] }
BulletListItemII
: 'INDENT1' '-' Words '\n' BulletIICont { Fix (DocULItem ($3 ++ snd $5) []) : fst $5 }
BulletIICont :: { ([NonTerm], [NonTerm]) }
BulletIICont
: { ([], []) }
| BulletListItemII { ($1, []) }
| 'INDENT3' DocLine '\n' BulletIICont { ([], $2) <> $4 }
NumberedListItem :: { NonTerm }
NumberedListItem
: LIT_INTEGER '.' IndentedSentenceII { Fix (DocOLItem $1 $3) }
IndentedSentenceII :: { [NonTerm] }
IndentedSentenceII
: DocLine '\n' { $1 }
| DocLine '\n' 'INDENT2' IndentedSentenceII { $1 ++ $4 }
Words :: { [NonTerm] }
Words
: SentenceList(WordList) { $1 }
WordList :: { [NonTerm] }
WordList
: Word(Atom) { [$1] }
| WordList Word(Atom) { $2 : $1 }
SentenceList(x)
: x { reverse $1 }
| SentenceList(x) ';' { [Fix (DocSentence $1 $2)] }
| SentenceList(x) ',' { [Fix (DocSentence $1 $2)] }
| SentenceList(x) '.' { [Fix (DocSentence $1 $2)] }
| SentenceList(x) '?' { [Fix (DocSentence $1 $2)] }
| SentenceList(x) '!' { [Fix (DocSentence $1 $2)] }
| SentenceList(x) ';' SentenceList(x) { Fix (DocSentence $1 $2) : $3 }
| SentenceList(x) ',' SentenceList(x) { Fix (DocSentence $1 $2) : $3 }
| SentenceList(x) '.' SentenceList(x) { Fix (DocSentence $1 $2) : $3 }
| SentenceList(x) '?' SentenceList(x) { Fix (DocSentence $1 $2) : $3 }
| SentenceList(x) '!' SentenceList(x) { Fix (DocSentence $1 $2) : $3 }
Word(x)
: x { Fix $ DocWord $1 }
| x ':' { Fix $ DocColon $1 }
| Word(x) '=' Word(Atom) { Fix $ DocAssignOp AopEq $1 $3 }
| Word(x) '+' Word(Atom) { Fix $ DocBinaryOp BopPlus $1 $3 }
| Word(x) '-' Word(Atom) { Fix $ DocBinaryOp BopMinus $1 $3 }
| Word(x) '/' Word(Atom) { Fix $ DocBinaryOp BopDiv $1 $3 }
| Word(x) '!=' Word(Atom) { Fix $ DocBinaryOp BopNe $1 $3 }
| Word(x) '>=' Word(Atom) { Fix $ DocBinaryOp BopGe $1 $3 }
| Word(x) '==' Word(Atom) { Fix $ DocBinaryOp BopEq $1 $3 }
| '@ref' Atom { Fix $ DocRef $2 }
| '@p' Atom { Fix $ DocP $2 }
| '(' Word(Atom) { Fix $ DocLParen $2 }
| Word(x) ')' { Fix $ DocRParen $1 }
Atom :: { Term }
Atom
: NonInt { $1 }
| LIT_INTEGER { $1 }
NonInt :: { Term }
NonInt
: CMT_WORD { $1 }
| CMT_CODE { $1 }
| LIT_STRING { $1 }
| '...' { $1 }
{
type Term = Lexeme Text
type NonTerm = Comment Term
prepend :: NonTerm -> [NonTerm] -> [NonTerm]
prepend x [] = [x]
prepend x (Fix (DocLine xs):rest) = Fix (DocLine (x:xs)) : rest
failAt :: Lexeme Text -> String -> ParseResult a
failAt n msg =
fail $ Text.unpack (sloc "" n) <> ": unexpected " <> describeLexeme n <> msg
parseError :: ([Lexeme Text], [String]) -> ParseResult a
parseError ([], options) = fail $ " end of comment; expected one of " <> show options
parseError (n:_, []) = failAt n "; expected end of comment"
parseError (n:_, options) = failAt n $ "; expected one of " <> show options
}