cimple-0.0.4: src/Language/Cimple/TreeParser.y
{
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Language.Cimple.TreeParser
( TreeParser
, parseTranslationUnit
, toEither
) where
import Data.Text (Text)
import Language.Cimple.AST (CommentStyle (..), Node (..))
import Language.Cimple.Lexer (Lexeme)
}
%name parseTranslationUnit TranslationUnit
%name parseDecls Decls
%name parseHeaderBody HeaderBody
%error {parseError}
%errorhandlertype explist
%monad {TreeParser}
%tokentype {TextNode}
%token
ifndefDefine { PreprocIfndef _ body (PreprocElse []) | isDefine body }
ifdefDefine { PreprocIfdef _ body (PreprocElse []) | isDefine body }
ifDefine { PreprocIf _ body (PreprocElse []) | isDefine body }
ifndefInclude { PreprocIfndef{} | isPreproc tk && hasInclude tk }
ifdefInclude { PreprocIfdef{} | isPreproc tk && hasInclude tk }
ifInclude { PreprocIf{} | isPreproc tk && hasInclude tk }
docComment { Comment Doxygen _ _ _ }
-- Preprocessor
preprocInclude { PreprocInclude{} }
preprocDefine { PreprocDefine{} }
preprocDefineConst { PreprocDefineConst{} }
preprocDefineMacro { PreprocDefineMacro{} }
preprocIf { PreprocIf{} }
preprocIfdef { PreprocIfdef{} }
preprocIfndef { PreprocIfndef{} }
preprocElse { PreprocElse{} }
preprocElif { PreprocElif{} }
preprocUndef { PreprocUndef{} }
preprocDefined { PreprocDefined{} }
preprocScopedDefine { PreprocScopedDefine{} }
macroBodyStmt { MacroBodyStmt{} }
macroBodyFunCall { MacroBodyFunCall{} }
macroParam { MacroParam{} }
staticAssert { StaticAssert{} }
-- Comments
licenseDecl { LicenseDecl{} }
copyrightDecl { CopyrightDecl{} }
comment { Comment{} }
commentBlock { CommentBlock{} }
commentWord { CommentWord{} }
commented { Commented{} }
-- Namespace-like blocks
externC { ExternC{} }
class { Class{} }
namespace { Namespace{} }
-- Statements
compoundStmt { CompoundStmt{} }
break { Break }
goto { Goto{} }
continue { Continue }
return { Return{} }
switchStmt { SwitchStmt{} }
ifStmt { IfStmt{} }
forStmt { ForStmt{} }
whileStmt { WhileStmt{} }
doWhileStmt { DoWhileStmt{} }
case { Case{} }
default { Default{} }
label { Label{} }
-- Variable declarations
vLA { VLA{} }
varDecl { VarDecl{} }
declarator { Declarator{} }
declSpecVar { DeclSpecVar{} }
declSpecArray { DeclSpecArray{} }
-- Expressions
initialiserList { InitialiserList{} }
unaryExpr { UnaryExpr{} }
binaryExpr { BinaryExpr{} }
ternaryExpr { TernaryExpr{} }
assignExpr { AssignExpr{} }
parenExpr { ParenExpr{} }
castExpr { CastExpr{} }
compoundExpr { CompoundExpr{} }
sizeofExpr { SizeofExpr{} }
sizeofType { SizeofType{} }
literalExpr { LiteralExpr{} }
varExpr { VarExpr{} }
memberAccess { MemberAccess{} }
pointerAccess { PointerAccess{} }
arrayAccess { ArrayAccess{} }
functionCall { FunctionCall{} }
commentExpr { CommentExpr{} }
-- Type definitions
enumClass { EnumClass{} }
enumConsts { EnumConsts{} }
enumDecl { EnumDecl{} }
enumerator { Enumerator{} }
classForward { ClassForward{} }
typedef { Typedef{} }
typedefFunction { TypedefFunction{} }
struct { Struct{} }
union { Union{} }
memberDecl { MemberDecl{} }
tyConst { TyConst{} }
tyPointer { TyPointer{} }
tyStruct { TyStruct{} }
tyFunc { TyFunc{} }
tyStd { TyStd{} }
tyVar { TyVar{} }
tyUserDefined { TyUserDefined{} }
-- Functions
functionDecl { FunctionDecl{} }
functionDefn { FunctionDefn{} }
functionPrototype { FunctionPrototype{} }
functionParam { FunctionParam{} }
event { Event{} }
eventParams { EventParams{} }
property { Property{} }
accessor { Accessor{} }
errorDecl { ErrorDecl{} }
errorList { ErrorList{} }
errorFor { ErrorFor{} }
ellipsis { Ellipsis }
-- Constants
constDecl { ConstDecl{} }
constDefn { ConstDefn{} }
%%
TranslationUnit :: { [TextNode] }
TranslationUnit
: licenseDecl FileComment Header { [$1, $2, $3] }
| licenseDecl FileComment Source { $1 : $2 : $3 }
| licenseDecl Header { [$1, $2] }
| licenseDecl Source { $1 : $2 }
FileComment :: { TextNode }
FileComment
: comment { $1 }
| docComment { $1 }
Header :: { TextNode }
Header
: preprocIfndef {% recurse parseHeaderBody $1 }
HeaderBody :: { [TextNode] }
HeaderBody
: preprocDefine Includes Decls { $1 : reverse $2 ++ reverse $3 }
Source :: { [TextNode] }
Source
: Features preprocInclude Includes Decls { $1 ++ [$2] ++ reverse $3 ++ reverse $4 }
Features :: { [TextNode] }
Features
: { [] }
| Features IfDefine { $2 : $1 }
IfDefine :: { TextNode }
IfDefine
: ifndefDefine { $1 }
| ifdefDefine { $1 }
| ifDefine { $1 }
Includes :: { [TextNode] }
Includes
: { [] }
| Includes Include { $2 : $1 }
Include :: { TextNode }
Include
: preprocInclude { $1 }
| ifndefInclude { $1 }
| ifdefInclude { $1 }
| ifInclude { $1 }
Decls :: { [TextNode] }
Decls
: { [] }
| Decls Decl { $2 : $1 }
Decl :: { TextNode }
Decl
: comment { $1 }
| CommentableDecl { $1 }
| docComment CommentableDecl { Commented $1 $2 }
CommentableDecl :: { TextNode }
CommentableDecl
: functionDecl { $1 }
| functionDefn { $1 }
| struct { $1 }
| typedef { $1 }
| constDecl { $1 }
| constDefn { $1 }
| enumConsts { $1 }
| enumDecl { $1 }
| externC {% recurse parseDecls $1 }
| preprocDefine { $1 }
| preprocDefineConst { $1 }
| preprocDefineMacro { $1 }
| preprocIf {% recurse parseDecls $1 }
| preprocIfdef {% recurse parseDecls $1 }
| preprocIfndef {% recurse parseDecls $1 }
| staticAssert { $1 }
| typedefFunction { $1 }
| IfDefine { $1 }
{
type TextLexeme = Lexeme Text
type TextNode = Node () TextLexeme
newtype TreeParser a = TreeParser { toEither :: Either String a }
deriving (Functor, Applicative, Monad)
instance MonadFail TreeParser where
fail = TreeParser . Left
isDefine :: [TextNode] -> Bool
isDefine (PreprocUndef{}:d) = isDefine d
isDefine [PreprocDefine{}] = True
isDefine [PreprocDefineConst{}] = True
isDefine _ = False
isPreproc :: TextNode -> Bool
isPreproc PreprocInclude{} = True
isPreproc PreprocUndef{} = True
isPreproc PreprocDefine{} = True
isPreproc PreprocDefineConst{} = True
isPreproc (PreprocIf _ td ed) = all isPreproc td && isPreproc ed
isPreproc (PreprocIfdef _ td ed) = all isPreproc td && isPreproc ed
isPreproc (PreprocIfndef _ td ed) = all isPreproc td && isPreproc ed
isPreproc (PreprocElse ed) = all isPreproc ed
isPreproc _ = False
hasInclude :: TextNode -> Bool
hasInclude PreprocInclude{} = True
hasInclude (PreprocIf _ td ed) = any hasInclude td || hasInclude ed
hasInclude (PreprocIfdef _ td ed) = any hasInclude td || hasInclude ed
hasInclude (PreprocIfndef _ td ed) = any hasInclude td || hasInclude ed
hasInclude (PreprocElse ed) = any hasInclude ed
hasInclude _ = False
recurse :: ([TextNode] -> TreeParser [TextNode]) -> TextNode -> TreeParser TextNode
recurse f (ExternC ds) = ExternC <$> f ds
recurse f (PreprocIf c t e) = PreprocIf c <$> f t <*> recurse f e
recurse f (PreprocIfdef c t e) = PreprocIfdef c <$> f t <*> recurse f e
recurse f (PreprocIfndef c t e) = PreprocIfndef c <$> f t <*> recurse f e
recurse f (PreprocIfndef c t e) = PreprocIfndef c <$> f t <*> recurse f e
recurse f (PreprocElif c t e) = PreprocElif c <$> f t <*> recurse f e
recurse f (PreprocElse []) = return $ PreprocElse []
recurse f (PreprocElse e) = PreprocElse <$> f e
recurse _ ns = fail $ show ns
parseError :: ([TextNode], [String]) -> TreeParser a
parseError ([], options) = fail $ "end of file; expected one of " <> show options
parseError (n:_, []) = fail $ show n <> "; expected end of file"
parseError (n:_, options) = fail $ show n <> "; expected one of " <> show options
}