packages feed

cimple-0.0.21: src/Language/Cimple/Parser.y

{
{-# LANGUAGE CPP               #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}
module Language.Cimple.Parser
    ( parseExpr
    , parseStmt
    , parseTranslationUnit
    , source
    ) where

import qualified Data.ByteString             as BS
import           Data.FileEmbed              (embedFile)
import           Data.Fix                    (Fix (..))
import           Data.Text                   (Text)
import qualified Data.Text                   as Text
import           Language.Cimple.Ast         (AssignOp (..), BinaryOp (..),
                                              CommentStyle (..),
                                              LiteralType (..), Node,
                                              NodeF (..), Scope (..),
                                              UnaryOp (..))
import           Language.Cimple.DescribeAst (parseError)
import           Language.Cimple.Lexer       (Alex, AlexPosn (..), Lexeme (..),
                                              alexError, alexMonadScan)
import           Language.Cimple.Tokens      (LexemeClass (..))
}

-- Conflict between (static) FunctionDecl and (static) ConstDecl.
%expect 2

%name parseTranslationUnit TranslationUnit
%name parseExpr Expr
%name parseStmt Stmt

%error {parseError}
%errorhandlertype explist
%lexer {lexwrap} {L _ Eof _}
%monad {Alex}
%tokentype {Term}
%token
    ID_CONST			{ L _ IdConst			_ }
    ID_FUNC_TYPE		{ L _ IdFuncType		_ }
    ID_STD_TYPE			{ L _ IdStdType			_ }
    ID_SUE_TYPE			{ L _ IdSueType			_ }
    ID_VAR			{ L _ IdVar			_ }
    bitwise			{ L _ KwBitwise			_ }
    break			{ L _ KwBreak			_ }
    case			{ L _ KwCase			_ }
    const			{ L _ KwConst			_ }
    continue			{ L _ KwContinue		_ }
    default			{ L _ KwDefault			_ }
    do				{ L _ KwDo			_ }
    else			{ L _ KwElse			_ }
    enum			{ L _ KwEnum			_ }
    extern			{ L _ KwExtern			_ }
    for				{ L _ KwFor			_ }
    force			{ L _ KwForce			_ }
    GNU_PRINTF			{ L _ KwGnuPrintf		_ }
    goto			{ L _ KwGoto			_ }
    if				{ L _ KwIf			_ }
    non_null			{ L _ KwNonNull			_ }
    nullable			{ L _ KwNullable		_ }
    owner			{ L _ KwOwner			_ }
    return			{ L _ KwReturn			_ }
    sizeof			{ L _ KwSizeof			_ }
    static			{ L _ KwStatic			_ }
    static_assert		{ L _ KwStaticAssert		_ }
    struct			{ L _ KwStruct			_ }
    switch			{ L _ KwSwitch			_ }
    typedef			{ L _ KwTypedef			_ }
    union			{ L _ KwUnion			_ }
    VLA				{ L _ KwVla			_ }
    void			{ L _ KwVoid			_ }
    while			{ L _ KwWhile			_ }
    LIT_CHAR			{ L _ LitChar			_ }
    LIT_FALSE			{ L _ LitFalse			_ }
    LIT_TRUE			{ L _ LitTrue			_ }
    LIT_INTEGER			{ L _ LitInteger		_ }
    LIT_STRING			{ L _ LitString			_ }
    LIT_SYS_INCLUDE		{ L _ LitSysInclude		_ }
    '&'				{ L _ PctAmpersand		_ }
    '&&'			{ L _ PctAmpersandAmpersand	_ }
    '&='			{ L _ PctAmpersandEq		_ }
    '->'			{ L _ PctArrow			_ }
    '*'				{ L _ PctAsterisk		_ }
    '*='			{ L _ PctAsteriskEq		_ }
    '^'				{ L _ PctCaret			_ }
    '^='			{ L _ PctCaretEq		_ }
    ':'				{ L _ PctColon			_ }
    ','				{ L _ PctComma			_ }
    '!'				{ L _ PctEMark			_ }
    '!='			{ L _ PctEMarkEq		_ }
    '='				{ L _ PctEq			_ }
    '=='			{ L _ PctEqEq			_ }
    '>'				{ L _ PctGreater		_ }
    '>='			{ L _ PctGreaterEq		_ }
    '>>'			{ L _ PctGreaterGreater		_ }
    '>>='			{ L _ PctGreaterGreaterEq	_ }
    '{'				{ L _ PctLBrace			_ }
    '['				{ L _ PctLBrack			_ }
    '<'				{ L _ PctLess			_ }
    '<='			{ L _ PctLessEq			_ }
    '<<'			{ L _ PctLessLess		_ }
    '<<='			{ L _ PctLessLessEq		_ }
    '('				{ L _ PctLParen			_ }
    '-'				{ L _ PctMinus			_ }
    '-='			{ L _ PctMinusEq		_ }
    '--'			{ L _ PctMinusMinus		_ }
    '%'				{ L _ PctPercent		_ }
    '%='			{ L _ PctPercentEq		_ }
    '.'				{ L _ PctPeriod			_ }
    '...'			{ L _ PctEllipsis		_ }
    '|'				{ L _ PctPipe			_ }
    '|='			{ L _ PctPipeEq			_ }
    '||'			{ L _ PctPipePipe		_ }
    '+'				{ L _ PctPlus			_ }
    '+='			{ L _ PctPlusEq			_ }
    '++'			{ L _ PctPlusPlus		_ }
    '?'				{ L _ PctQMark			_ }
    '}'				{ L _ PctRBrace			_ }
    ']'				{ L _ PctRBrack			_ }
    ')'				{ L _ PctRParen			_ }
    ';'				{ L _ PctSemicolon		_ }
    '/'				{ L _ PctSlash			_ }
    '/='			{ L _ PctSlashEq		_ }
    '~'				{ L _ PctTilde			_ }
    'defined'			{ L _ PpDefined			_ }
    '#define'			{ L _ PpDefine			_ }
    '#elif'			{ L _ PpElif			_ }
    '#else'			{ L _ PpElse			_ }
    '#endif'			{ L _ PpEndif			_ }
    '#if'			{ L _ PpIf			_ }
    '#ifdef'			{ L _ PpIfdef			_ }
    '#ifndef'			{ L _ PpIfndef			_ }
    '#include'			{ L _ PpInclude			_ }
    '#undef'			{ L _ PpUndef			_ }
    '\n'			{ L _ PpNewline			_ }
    '/*'			{ L _ CmtStart			_ }
    '/*!'			{ L _ CmtStartCode		_ }
    '/**'			{ L _ CmtStartDoc		_ }
    '/** @{'			{ L _ CmtStartDocSection	_ }
    '/** @} */'			{ L _ CmtEndDocSection		_ }
    '/***'			{ L _ CmtStartBlock		_ }
    ' '				{ L _ CmtIndent			_ }
    '*/'			{ L _ CmtEnd			_ }
    'Copyright'			{ L _ CmtSpdxCopyright		_ }
    'License'			{ L _ CmtSpdxLicense		_ }
    CMT_ATTR			{ L _ CmtAttr			_ }
    CMT_CODE			{ L _ CmtCode			_ }
    CMT_COMMAND			{ L _ CmtCommand		_ }
    CMT_WORD			{ L _ CmtWord			_ }
    CMT_REF			{ L _ CmtRef			_ }
    IGN_START			{ L _ IgnStart			_ }
    IGN_BODY			{ L _ IgnBody			_ }
    IGN_END			{ L _ IgnEnd			_ }

%left ','
%right '=' '+=' '-=' '*=' '/=' '%=' '<<=' '>>=' '&=' '^=' '|='
%right '?' ':'
%left '||'
%left '&&'
%left '|'
%left '^'
%left '&'
%left '!=' '=='
%left '<' '<=' '>' '>='
%left '<<' '>>'
%left '+' '-'
%left '*' '/' '%'
%right CAST ADDRESS NEG DEREF sizeof '!' '~' '++' '--'
%left '->' '.' '(' '['

%%

TranslationUnit :: { [NonTerm] }
TranslationUnit
:	ToplevelDecls						{ reverse $1 }
|	LicenseDecl ToplevelDecls				{ $1 : reverse $2 }

LicenseDecl :: { NonTerm }
LicenseDecl
:	'/*' 'License' CMT_WORD '\n' CopyrightDecls '*/'	{ Fix $ LicenseDecl $3 (reverse $5) }

CopyrightDecls :: { [NonTerm] }
CopyrightDecls
:	CopyrightDecl						{ [$1] }
|	CopyrightDecls CopyrightDecl				{ $2 : $1 }

CopyrightDecl :: { NonTerm }
CopyrightDecl
:	' ' 'Copyright' CopyrightDates CopyrightOwner '\n'	{ Fix $ CopyrightDecl (fst $3) (snd $3) $4 }

CopyrightDates :: { (Term, Maybe Term) }
CopyrightDates
:	LIT_INTEGER						{ ($1, Nothing) }
|	LIT_INTEGER '-' LIT_INTEGER				{ ($1, Just $3) }

CopyrightOwner :: { [Term] }
CopyrightOwner
:	CMT_WORD CommentWords					{ $1 : reverse $2 }

ToplevelDecls :: { [NonTerm] }
ToplevelDecls
:	ToplevelDecl						{ [$1] }
|	ToplevelDecls ToplevelDecl				{ $2 : $1 }

ToplevelDecl :: { NonTerm }
ToplevelDecl
:	AggregateDecl						{ $1 }
|	Comment							{ $1 }
|	ConstDecl						{ $1 }
|	EnumDecl						{ $1 }
|	ExternC							{ $1 }
|	FunctionDecl						{ $1 }
|	PreprocDefine						{ $1 }
|	PreprocIfdef(ToplevelDecls)				{ $1 }
|	PreprocIf(ToplevelDecls)				{ $1 }
|	PreprocInclude						{ $1 }
|	PreprocUndef						{ $1 }
|	StaticAssert						{ $1 }
|	TypedefDecl						{ $1 }

StaticAssert :: { NonTerm }
StaticAssert
:	static_assert '(' ConstExpr ',' LIT_STRING ')' ';'	{ Fix $ StaticAssert $3 $5 }

Comment :: { NonTerm }
Comment
:	'/*' CommentTokens '*/'					{ Fix $ Comment Regular $1 (reverse $2) $3 }
|	'/**' CommentTokens '*/'				{ Fix $ Comment Doxygen $1 (reverse $2) $3 }
|	'/** @{' CommentTokens '*/'				{ Fix $ Comment Section $1 (reverse $2) $3 }
|	'/***' CommentTokens '*/'				{ Fix $ Comment Block $1 (reverse $2) $3 }
|	'/** @} */'						{ Fix $ CommentSectionEnd $1 }
|	Ignore							{ $1 }

CommentTokens :: { [Term] }
CommentTokens
:	CommentToken						{ [$1] }
|	CommentTokens CommentToken				{ $2 : $1 }

CommentToken :: { Term }
CommentToken
:	CommentWord						{ $1 }
|	'\n'							{ $1 }
|	' '							{ $1 }

CommentWords :: { [Term] }
CommentWords
:								{ [] }
|	CommentWords CommentWord				{ $2 : $1 }

CommentWord :: { Term }
CommentWord
:	CMT_WORD						{ $1 }
|	CMT_COMMAND						{ $1 }
|	CMT_ATTR						{ $1 }
|	CMT_REF							{ $1 }
|	CMT_CODE						{ $1 }
|	LIT_INTEGER						{ $1 }
|	LIT_STRING						{ $1 }
|	'.'							{ $1 }
|	'...'							{ $1 }
|	'?'							{ $1 }
|	'!'							{ $1 }
|	','							{ $1 }
|	';'							{ $1 }
|	':'							{ $1 }
|	'('							{ $1 }
|	')'							{ $1 }
|	'<'							{ $1 }
|	'>'							{ $1 }
|	'/'							{ $1 }
|	'+'							{ $1 }
|	'-'							{ $1 }
|	'='							{ $1 }
|	'=='							{ $1 }
|	'!='							{ $1 }
|	'>='							{ $1 }

Ignore :: { NonTerm }
Ignore
:	IGN_START IgnoreBody IGN_END				{ Fix $ Comment Ignore $1 (reverse $2) $3 }

IgnoreBody :: { [Term] }
IgnoreBody
:	IGN_BODY						{ [$1] }
|	IgnoreBody IGN_BODY					{ $2 : $1 }

PreprocIfdef(decls)
:	'#ifdef' ID_CONST decls PreprocElse(decls) Endif	{ Fix $ PreprocIfdef $2 (reverse $3) $4 }
|	'#ifndef' ID_CONST decls PreprocElse(decls) Endif	{ Fix $ PreprocIfndef $2 (reverse $3) $4 }

PreprocIf(decls)
:	'#if' PreprocConstExpr '\n' decls PreprocElif(decls) Endif	{ Fix $ PreprocIf $2 (reverse $4) $5 }

PreprocElif(decls)
:	PreprocElse(decls)					{ $1 }
|	'#elif' PreprocConstExpr '\n' decls PreprocElif(decls)	{ Fix $ PreprocElif $2 (reverse $4) $5 }

PreprocElse(decls)
:								{ Fix $ PreprocElse [] }
|	'#else' decls						{ Fix $ PreprocElse (reverse $2) }

Endif :: { [Term] }
Endif
:	'#endif' Comment					{ [$1] }

PreprocInclude :: { NonTerm }
PreprocInclude
:	'#include' LIT_STRING					{ Fix $ PreprocInclude $2 }
|	'#include' LIT_SYS_INCLUDE				{ Fix $ PreprocInclude $2 }

PreprocDefine :: { NonTerm }
PreprocDefine
:	'#define' ID_CONST '\n'					{ Fix $ PreprocDefine $2 }
|	'#define' ID_CONST PreprocSafeExpr(ConstExpr) '\n'	{ Fix $ PreprocDefineConst $2 $3 }
|	'#define' ID_CONST MacroParamList MacroBody '\n'	{ Fix $ PreprocDefineMacro $2 $3 $4 }

PreprocUndef :: { NonTerm }
PreprocUndef
:	'#undef' ID_CONST					{ Fix $ PreprocUndef $2 }

PreprocConstExpr :: { NonTerm }
PreprocConstExpr
:	PureExpr(PreprocConstExpr)				{ $1 }
|	'defined' '(' ID_CONST ')'				{ Fix $ PreprocDefined $3 }

MacroParamList :: { [NonTerm] }
MacroParamList
:	'(' ')'							{ [] }
|	'(' MacroParams ')'					{ reverse $2 }
|	'(' MacroParams ',' '...' ')'				{ reverse $ Fix Ellipsis : $2 }

MacroParams :: { [NonTerm] }
MacroParams
:	MacroParam						{ [$1] }
|	MacroParams ',' MacroParam				{ $3 : $1 }

MacroParam :: { NonTerm }
MacroParam
:	ID_VAR							{ Fix $ MacroParam $1 }

MacroBody :: { NonTerm }
MacroBody
:	do CompoundStmt while '(' LIT_INTEGER ')'		{% macroBodyStmt $2 $5 }
|	FunctionCall						{ Fix $ MacroBodyFunCall $1 }

ExternC :: { NonTerm }
ExternC
:	'#ifdef' ID_CONST
	extern LIT_STRING '{'
	'#endif'
	ToplevelDecls
	'#ifdef' ID_CONST
	'}' Comment
	'#endif'						{% externC $2 $4 (reverse $7) $9 }

Stmts :: { [NonTerm] }
Stmts
:	Stmt							{ [$1] }
|	Stmts Stmt						{ $2 : $1 }

Stmt :: { NonTerm }
Stmt
:	PreprocIfdef(Stmts)					{ $1 }
|	PreprocIf(Stmts)					{ $1 }
|	PreprocDefine Stmts PreprocUndef			{ Fix $ PreprocScopedDefine $1 (reverse $2) $3 }
|	DeclStmt						{ $1 }
|	CompoundStmt						{ $1 }
|	IfStmt(ReturnStmt)					{ $1 }
|	IfStmt(CompoundStmt)					{ $1 }
|	ForStmt							{ $1 }
|	WhileStmt						{ $1 }
|	DoWhileStmt						{ $1 }
|	StaticAssert						{ $1 }
|	AssignExpr ';'						{ Fix $ ExprStmt $1 }
|	ExprStmt ';'						{ Fix $ ExprStmt $1 }
|	FunctionCall ';'					{ Fix $ ExprStmt $1 }
|	break ';'						{ Fix $ Break }
|	goto ID_CONST ';'					{ Fix $ Goto $2 }
|	ID_CONST ':' Stmt					{ Fix $ Label $1 $3 }
|	continue ';'						{ Fix $ Continue }
|	switch '(' Expr ')' '{' SwitchCases '}'			{ Fix $ SwitchStmt $3 (reverse $6) }
|	ReturnStmt						{ $1 }
|	Comment							{ $1 }

ReturnStmt :: { NonTerm }
ReturnStmt
:	return ';'						{ Fix $ Return Nothing }
|	return Expr ';'						{ Fix $ Return (Just $2) }

IfStmt(x)
:	if '(' Expr ')' x					{ Fix $ IfStmt $3 $5 Nothing }
|	if '(' Expr ')' x else x				{ Fix $ IfStmt $3 $5 (Just $7) }
|	if '(' Expr ')' x else IfStmt(x)			{ Fix $ IfStmt $3 $5 (Just $7) }

ForStmt :: { NonTerm }
ForStmt
:	for '(' ForInit Expr ';' ForNext ')' CompoundStmt	{ Fix $ ForStmt $3 $4 $6 $8 }

ForInit :: { NonTerm }
ForInit
:	AssignExpr ';'						{ Fix $ ExprStmt $1 }
|	VarDeclStmt						{ $1 }

ForNext :: { NonTerm }
ForNext
:	ExprStmt						{ $1 }
|	AssignExpr						{ $1 }

WhileStmt :: { NonTerm }
WhileStmt
:	while '(' Expr ')' CompoundStmt				{ Fix $ WhileStmt $3 $5 }

DoWhileStmt :: { NonTerm }
DoWhileStmt
:	do CompoundStmt while '(' Expr ')' ';'			{ Fix $ DoWhileStmt $2 $5 }

SwitchCases :: { [NonTerm] }
SwitchCases
:	SwitchCase						{ [$1] }
|	SwitchCases SwitchCase					{ $2 : $1 }

SwitchCase :: { NonTerm }
SwitchCase
:	case Expr ':' SwitchCaseBody				{ Fix $ Case $2 $4 }
|	default ':' SwitchCaseBody				{ Fix $ Default $3 }

SwitchCaseBody :: { NonTerm }
SwitchCaseBody
:	CompoundStmt						{ $1 }
|	SwitchCase						{ $1 }
|	break ';'						{ Fix $ Break }
|	return Expr ';'						{ Fix $ Return (Just $2) }

DeclStmt :: { NonTerm }
DeclStmt
:	VarDeclStmt						{ $1 }
|	VLA '(' QualType ',' ID_VAR ',' Expr ')' ';'		{ Fix $ VLA $3 $5 $7 }

VarDeclStmt :: { NonTerm }
VarDeclStmt
:	VarDecl '=' InitialiserExpr ';'				{ Fix $ VarDeclStmt $1 (Just $3) }
|	VarDecl ';'						{ Fix $ VarDeclStmt $1 Nothing }

VarDecl :: { NonTerm }
VarDecl
:	QualType ID_VAR DeclSpecArrays				{ Fix $ VarDecl $1 $2 $3 }
|	ID_FUNC_TYPE '*' ID_VAR DeclSpecArrays			{ Fix $ VarDecl (Fix $ TyPointer $ Fix $ TyFunc $1) $3 $4 }

DeclSpecArrays :: { [NonTerm] }
DeclSpecArrays
:								{ [] }
|	DeclSpecArrays DeclSpecArray				{ $2 : $1 }

DeclSpecArray :: { NonTerm }
DeclSpecArray
:	'[' ']'							{ Fix $ DeclSpecArray Nothing }
|	'[' Expr ']'						{ Fix $ DeclSpecArray (Just $2) }
|	'[' '/*!' Expr '*/' ']'					{ Fix $ DeclSpecArray (Just $3) }

InitialiserExpr :: { NonTerm }
InitialiserExpr
:	InitialiserList						{ Fix $ InitialiserList $1 }
|	Expr							{ $1 }

InitialiserList :: { [NonTerm] }
InitialiserList
:	'{' Initialisers '}'					{ reverse $2 }
|	'{' Initialisers ',' '}'				{ reverse $2 }

Initialisers :: { [NonTerm] }
Initialisers
:	Initialiser						{ [$1] }
|	Initialisers ',' Initialiser				{ $3 : $1 }

Initialiser :: { NonTerm }
Initialiser
:	Expr							{ $1 }
|	InitialiserList						{ Fix $ InitialiserList $1 }

CompoundStmt :: { NonTerm }
CompoundStmt
:	'{' Stmts '}'						{ Fix $ CompoundStmt (reverse $2) }

-- Expressions that are safe for use as macro body without () around it..
PreprocSafeExpr(x)
:	LiteralExpr						{ $1 }
|	'(' x ')'						{ Fix $ ParenExpr $2 }
|	'(' QualType ')' x %prec CAST				{ Fix $ CastExpr $2 $4 }
|	sizeof '(' Expr ')'					{ Fix $ SizeofExpr $3 }
|	sizeof '(' QualType ')'					{ Fix $ SizeofType $3 }

ConstExpr :: { NonTerm }
ConstExpr
:	PureExpr(ConstExpr)					{ $1 }

PureExpr(x)
:	PreprocSafeExpr(x)					{ $1 }
|	x '!=' x						{ Fix $ BinaryExpr $1 BopNe $3 }
|	x '==' x						{ Fix $ BinaryExpr $1 BopEq $3 }
|	x '||' x						{ Fix $ BinaryExpr $1 BopOr $3 }
|	x '^' x							{ Fix $ BinaryExpr $1 BopBitXor $3 }
|	x '|' x							{ Fix $ BinaryExpr $1 BopBitOr $3 }
|	x '&&' x						{ Fix $ BinaryExpr $1 BopAnd $3 }
|	x '&' x							{ Fix $ BinaryExpr $1 BopBitAnd $3 }
|	x '/' x							{ Fix $ BinaryExpr $1 BopDiv $3 }
|	x '*' x							{ Fix $ BinaryExpr $1 BopMul $3 }
|	x '%' x							{ Fix $ BinaryExpr $1 BopMod $3 }
|	x '+' x							{ Fix $ BinaryExpr $1 BopPlus $3 }
|	x '-' x							{ Fix $ BinaryExpr $1 BopMinus $3 }
|	x '<' x							{ Fix $ BinaryExpr $1 BopLt $3 }
|	x '<=' x						{ Fix $ BinaryExpr $1 BopLe $3 }
|	x '<<' x						{ Fix $ BinaryExpr $1 BopLsh $3 }
|	x '>' x							{ Fix $ BinaryExpr $1 BopGt $3 }
|	x '>=' x						{ Fix $ BinaryExpr $1 BopGe $3 }
|	x '>>' x						{ Fix $ BinaryExpr $1 BopRsh $3 }
|	x '?' x ':' x						{ Fix $ TernaryExpr $1 $3 $5 }
|	'!' x							{ Fix $ UnaryExpr UopNot $2 }
|	'~' x							{ Fix $ UnaryExpr UopNeg $2 }
|	'-' x %prec NEG						{ Fix $ UnaryExpr UopMinus $2 }
|	'&' x %prec ADDRESS					{ Fix $ UnaryExpr UopAddress $2 }

LiteralExpr :: { NonTerm }
LiteralExpr
:	StringLiteralExpr					{ $1 }
|	LIT_CHAR						{ Fix $ LiteralExpr Char $1 }
|	LIT_INTEGER						{ Fix $ LiteralExpr Int $1 }
|	LIT_FALSE						{ Fix $ LiteralExpr Bool $1 }
|	LIT_TRUE						{ Fix $ LiteralExpr Bool $1 }
|	ID_CONST						{ Fix $ LiteralExpr ConstId $1 }

StringLiteralExpr :: { NonTerm }
StringLiteralExpr
:	LIT_STRING						{ Fix $ LiteralExpr String $1 }
|	StringLiteralExpr LIT_STRING				{ $1 }

LhsExpr :: { NonTerm }
LhsExpr
:	ID_VAR							{ Fix $ VarExpr $1 }
|	'*' LhsExpr %prec DEREF					{ Fix $ UnaryExpr UopDeref $2 }
|	LhsExpr '.' ID_VAR					{ Fix $ MemberAccess $1 $3 }
|	LhsExpr '->' ID_VAR					{ Fix $ PointerAccess $1 $3 }
|	LhsExpr '[' Expr ']'					{ Fix $ ArrayAccess $1 $3 }

Expr :: { NonTerm }
Expr
:	LhsExpr							{ $1 }
|	ExprStmt						{ $1 }
|	FunctionCall						{ $1 }
|	CompoundLiteral						{ $1 }
|	PureExpr(Expr)						{ $1 }

-- Allow `(Type){0}` to set struct values to all-zero.
CompoundLiteral :: { NonTerm }
CompoundLiteral
:	'(' QualType ')' '{' ZeroInitExpr '}'			{ Fix $ CompoundLiteral $2 $5 }

ZeroInitExpr :: { NonTerm }
ZeroInitExpr
:	ID_VAR							{ Fix $ VarExpr $1 }
|	LIT_CHAR						{ Fix $ LiteralExpr Char $1 }
|	LIT_INTEGER						{ Fix $ LiteralExpr Int $1 }
|	LIT_FALSE						{ Fix $ LiteralExpr Bool $1 }
|	ID_CONST						{ Fix $ LiteralExpr ConstId $1 }
|	'{' ZeroInitExpr '}'					{ Fix $ InitialiserList [$2] }

AssignExpr :: { NonTerm }
AssignExpr
:	LhsExpr AssignOperator Expr				{ Fix $ AssignExpr $1 $2 $3 }

AssignOperator :: { AssignOp }
AssignOperator
:	'='							{ AopEq      }
|	'*='							{ AopMul     }
|	'/='							{ AopDiv     }
|	'+='							{ AopPlus    }
|	'-='							{ AopMinus   }
|	'&='							{ AopBitAnd  }
|	'|='							{ AopBitOr   }
|	'^='							{ AopBitXor  }
|	'%='							{ AopMod     }
|	'<<='							{ AopLsh     }
|	'>>='							{ AopRsh     }

ExprStmt :: { NonTerm }
ExprStmt
:	'++' Expr						{ Fix $ UnaryExpr UopIncr $2 }
|	'--' Expr						{ Fix $ UnaryExpr UopDecr $2 }

FunctionCall :: { NonTerm }
FunctionCall
:	Expr ArgList						{ Fix $ FunctionCall $1 $2 }

ArgList :: { [NonTerm] }
ArgList
:	'(' ')'							{ [] }
|	'(' Args ')'						{ reverse $2 }

Args :: { [NonTerm] }
Args
:	Arg							{ [$1] }
|	Args ',' Arg						{ $3 : $1 }

Arg :: { NonTerm }
Arg
:	Expr							{ $1 }
|	Comment Expr						{ Fix $ CommentExpr $1 $2 }

EnumDecl :: { NonTerm }
EnumDecl
:	enum ID_SUE_TYPE EnumeratorList ';'			{ Fix $ EnumConsts (Just $2) $3 }
|	enum             EnumeratorList ';'			{ Fix $ EnumConsts Nothing $2 }
|	typedef enum ID_SUE_TYPE EnumeratorList ID_SUE_TYPE ';'	{ Fix $ EnumDecl $3 $4 $5 }

EnumeratorList :: { [NonTerm] }
EnumeratorList
:	'{' Enumerators '}'					{ reverse $2 }
|	'{' Enumerators ',' '}'					{ reverse $2 }
|	'{' Enumerators Comment '}'				{ reverse $2 }  -- TODO(iphydf): Don't throw away the comment.
|	'{' Enumerators ',' Comment '}'				{ reverse $2 }  -- TODO(iphydf): Don't throw away the comment.

Enumerators :: { [NonTerm] }
Enumerators
:	Enumerator						{ [$1] }
|	Enumerators ',' Enumerator				{ $3 : $1 }

Enumerator :: { NonTerm }
Enumerator
:	EnumeratorName						{ Fix $ Enumerator $1 Nothing }
|	EnumeratorName '=' ConstExpr				{ Fix $ Enumerator $1 (Just $3) }
|	Comment Enumerator					{ Fix $ Commented $1 $2 }

EnumeratorName :: { Term }
EnumeratorName
:	ID_CONST						{ $1 }
|	ID_SUE_TYPE						{ $1 }

AggregateDecl :: { NonTerm }
AggregateDecl
:	AggregateType ';'					{ Fix $ AggregateDecl $1 }
|	typedef AggregateType ID_SUE_TYPE ';'			{ Fix $ Typedef $2 $3 }

AggregateType :: { NonTerm }
AggregateType
:	struct ID_SUE_TYPE '{' MemberDeclList '}'		{ Fix $ Struct $2 $4 }
|	union ID_SUE_TYPE '{' MemberDeclList '}'		{ Fix $ Union $2 $4 }

MemberDeclList :: { [NonTerm] }
MemberDeclList
:	MemberDecls						{ reverse $1 }

MemberDecls :: { [NonTerm] }
MemberDecls
:	MemberDecl						{ [$1] }
|	MemberDecls MemberDecl					{ $2 : $1 }

MemberDecl :: { NonTerm }
MemberDecl
:	VarDecl ';'						{ Fix $ MemberDecl $1 Nothing }
|	VarDecl ':' LIT_INTEGER ';'				{ Fix $ MemberDecl $1 (Just $3) }
|	PreprocIfdef(MemberDeclList)				{ $1 }
|	Comment							{ $1 }

TypedefDecl :: { NonTerm }
TypedefDecl
:	typedef QualType ID_SUE_TYPE ';'			{ Fix $ Typedef $2 $3 }
|	typedef FunctionPrototype(ID_FUNC_TYPE) ';'		{ Fix $ TypedefFunction $2 }

QualType :: { NonTerm }
QualType
:	bitwise ID_STD_TYPE					{ Fix (TyBitwise (Fix (TyStd $2))) }
|	force LeafType						{ Fix (TyForce $2) }
|	LeafType						{                                        $1 }
|	LeafType '*'						{                              tyPointer $1 }
|	LeafType '*' '*'					{          tyPointer          (tyPointer $1) }
|	LeafType '*' '*' const					{ tyConst (tyPointer          (tyPointer $1)) }
|	LeafType '*' const					{                     tyConst (tyPointer $1) }
|	LeafType '*' const '*'					{          tyPointer (tyConst (tyPointer $1)) }
|	LeafType '*' const '*' const				{ tyConst (tyPointer (tyConst (tyPointer $1))) }
|	LeafType const						{                                         tyConst $1 }
|	LeafType const '*'					{                              tyPointer (tyConst $1) }
|	LeafType const '*' const				{                     tyConst (tyPointer (tyConst $1)) }
|	LeafType const '*' const '*'				{          tyPointer (tyConst (tyPointer (tyConst $1))) }
|	LeafType const '*' const '*' const			{ tyConst (tyPointer (tyConst (tyPointer (tyConst $1)))) }
|	const LeafType						{                                         tyConst $2 }
|	const LeafType '*'					{                              tyPointer (tyConst $2) }
|	const LeafType '*' const				{                     tyConst (tyPointer (tyConst $2)) }
|	const LeafType '*' const '*'				{          tyPointer (tyConst (tyPointer (tyConst $2))) }
|	const LeafType '*' const '*' const			{ tyConst (tyPointer (tyConst (tyPointer (tyConst $2)))) }
|	LeafType '*'       owner				{            tyOwner          (tyPointer $1) }
|	LeafType '*' const owner				{            tyOwner (tyConst (tyPointer $1)) }
|	LeafType '*' '*' owner					{ tyOwner (tyPointer          (tyPointer $1)) }
|	LeafType '*' owner '*'					{          tyPointer (tyOwner (tyPointer $1)) }
|	LeafType '*' owner '*' owner				{ tyOwner (tyPointer (tyOwner (tyPointer $1))) }

LeafType :: { NonTerm }
LeafType
:	struct ID_SUE_TYPE					{ Fix $ TyStruct $2 }
|	void							{ Fix $ TyStd $1 }
|	ID_STD_TYPE						{ Fix $ TyStd $1 }
|	ID_SUE_TYPE						{ Fix $ TyUserDefined $1 }

FunctionDecl :: { NonTerm }
FunctionDecl
:	FunctionDeclarator					{ $1 Global }
|	static FunctionDeclarator				{ $2 Static }
|	NonNull FunctionDeclarator				{ $1 $ $2 Global }
|	NonNull static FunctionDeclarator			{ $1 $ $3 Static }
|	NonNull Attrs FunctionDeclarator			{ $1 . $2 . $3 $ Global }

Attrs :: { NonTerm -> NonTerm }
Attrs
:	GNU_PRINTF '(' LIT_INTEGER ',' LIT_INTEGER ')'		{ Fix . AttrPrintf $3 $5 }

NonNull :: { NonTerm -> NonTerm }
NonNull
:	non_null '(' ')'					{ Fix . NonNull [] [] }
|	nullable '(' Ints ')'					{ Fix . NonNull [] $3 }
|	non_null '(' Ints ')' nullable '(' Ints ')'		{ Fix . NonNull $3 $7 }

Ints :: { [Term] }
Ints
:	IntList							{ reverse $1 }

IntList :: { [Term] }
IntList
:	LIT_INTEGER						{ [$1] }
|	IntList ',' LIT_INTEGER					{ $3 : $1 }

FunctionDeclarator :: { Scope -> NonTerm }
FunctionDeclarator
:	FunctionPrototype(ID_VAR) ';'				{ \s -> Fix $ FunctionDecl s $1 }
|	FunctionPrototype(ID_VAR) CompoundStmt			{ \s -> Fix $ FunctionDefn s $1 $2 }
|	CallbackDecl ';'					{ \s -> Fix $ FunctionDecl s $1 }

CallbackDecl :: { NonTerm }
CallbackDecl
:	ID_FUNC_TYPE ID_VAR					{ Fix $ CallbackDecl $1 $2 }

FunctionPrototype(id)
:	QualType id FunctionParamList				{ Fix $ FunctionPrototype $1 $2 $3 }
|	ID_FUNC_TYPE '*' id FunctionParamList			{ Fix $ FunctionPrototype (Fix $ TyPointer $ Fix $ TyFunc $1) $3 $4 }

FunctionParamList :: { [NonTerm] }
FunctionParamList
:	'(' ')'							{ [] }
|	'(' void ')'						{ [Fix $ TyStd $2] }
|	'(' FunctionParams ')'					{ reverse $2 }
|	'(' FunctionParams ',' '...' ')'			{ reverse $ Fix Ellipsis : $2 }

FunctionParams :: { [NonTerm] }
FunctionParams
:	FunctionParam						{ [$1] }
|	FunctionParams ',' FunctionParam			{ $3 : $1 }

FunctionParam :: { NonTerm }
FunctionParam
:	VarDecl							{ $1 }

ConstDecl :: { NonTerm }
ConstDecl
:	extern const LeafType ID_VAR ';'			{ Fix $ ConstDecl $3 $4 }
|	const LeafType ID_VAR '=' InitialiserExpr ';'		{ Fix $ ConstDefn Global $2 $3 $5 }
|	static const LeafType ID_VAR '=' InitialiserExpr ';'	{ Fix $ ConstDefn Static $3 $4 $6 }

{
type Term = Lexeme Text
type NonTerm = Node Term

tyPointer, tyConst, tyOwner :: NonTerm -> NonTerm
tyPointer = Fix . TyPointer
tyConst = Fix . TyConst
tyOwner = Fix . TyOwner

lexwrap :: (Lexeme Text -> Alex a) -> Alex a
lexwrap = (alexMonadScan >>=)

externC
    :: Term
    -> Term
    -> [NonTerm]
    -> Term
    -> Alex NonTerm
externC (L _ _ "__cplusplus") (L _ _ "\"C\"") decls (L _ _ "__cplusplus") =
    return $ Fix $ ExternC decls
externC _ lang _ _ =
    alexError $ show lang
        <> ": extern \"C\" declaration invalid (did you spell __cplusplus right?)"

macroBodyStmt
    :: NonTerm
    -> Term
    -> Alex NonTerm
macroBodyStmt decls (L _ _ "0") =
    return $ Fix $ MacroBodyStmt decls
macroBodyStmt _ cond =
    alexError $ show cond
        <> ": macro do-while body must end in 'while (0)'"

source :: Maybe BS.ByteString
#ifdef SOURCE
source = Just $(embedFile SOURCE)
#else
source = Nothing
#endif
}