217 lines
5.5 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
module Windows12.Ast where
import Data.Text (Text)
import Data.Text.Prettyprint.Doc
data BinOp
= Add
| Sub
| Mul
| Div
| Mod
| Eq
| Ne
| Lt
| Gt
| Le
| Ge
| And
| Or
| BitAnd
| BitOr
| BitXor
| ShiftL
| ShiftR
deriving (Show, Eq)
data UnOp
= Neg
| Not
| BitNot
| Deref
| AddrOf
deriving (Show, Eq)
data AssignOp
= BaseAssign
| AddAssign
| SubAssign
| MulAssign
| DivAssign
| ModAssign
| BitAndAssign
| BitOrAssign
| BitXorAssign
| ShiftLAssign
| ShiftRAssign
deriving (Show, Eq)
data Expr
= Id Text
| IntLit Int
| UIntLit Word
| FloatLit Double
| StrLit Text
| BoolLit Bool
| CharLit Char
| BinOp BinOp Expr Expr
| UnOp UnOp Expr
| Call Expr [Expr]
| Index Expr Expr
| Member Expr Expr
| Cast Type Expr
| Sizeof Type
| StructInit Text [(Text, Expr)]
deriving (Show, Eq)
data Stmt
= Expr Expr
| Return Expr
| If Expr [Stmt] (Maybe [Stmt])
| While Expr [Stmt]
| Assign AssignOp Expr Expr
| Block [Stmt]
| Var Text (Maybe Type) (Maybe Expr)
deriving (Show, Eq)
data Type
= IntType
| UIntType
| FloatType
| StrType
| BoolType
| CharType
| PtrType Type
| ArrayType Type
| StructType Text
| EnumType Text
| VoidType
deriving (Show, Eq)
data Bind = Bind {bindName :: Text, bindType :: Type}
deriving (Show, Eq)
data TLStruct = Struct {structName :: Text, structFields :: [Bind]}
deriving (Show, Eq)
data TLEnum = Enum {enumName :: Text, enumFields :: [Text]}
deriving (Show, Eq)
data TLFunc = Func {funcName :: Text, funcArgs :: [Bind], funcRetType :: Type, funcBody :: [Stmt]}
deriving (Show, Eq)
data TL = TLStruct TLStruct | TLEnum TLEnum | TLFunc TLFunc
deriving (Show, Eq)
data Program = Program [TLStruct] [TLEnum] [TLFunc]
deriving (Show, Eq)
-- Pretty printing
instance Pretty BinOp where
pretty Add = "+"
pretty Sub = "-"
pretty Mul = "*"
pretty Div = "/"
pretty Mod = "%"
pretty Eq = "=="
pretty Ne = "!="
pretty Lt = "<"
pretty Gt = ">"
pretty Le = "<="
pretty Ge = ">="
pretty And = "&&"
pretty Or = "||"
pretty BitAnd = "&"
pretty BitOr = "|"
pretty BitXor = "^"
pretty ShiftL = "<<"
pretty ShiftR = ">>"
instance Pretty UnOp where
pretty Neg = "-"
pretty Not = "!"
pretty BitNot = "~"
pretty Deref = "*"
pretty AddrOf = "&"
instance Pretty AssignOp where
pretty BaseAssign = "="
pretty AddAssign = "+="
pretty SubAssign = "-="
pretty MulAssign = "*="
pretty DivAssign = "/="
pretty ModAssign = "%="
pretty BitAndAssign = "&="
pretty BitOrAssign = "|="
pretty BitXorAssign = "^="
pretty ShiftLAssign = "<<="
pretty ShiftRAssign = ">>="
instance Pretty Expr where
pretty (Id x) = pretty x
pretty (IntLit x) = pretty x
pretty (UIntLit x) = pretty x
pretty (FloatLit x) = pretty x
pretty (StrLit x) = dquotes (pretty x)
pretty (BoolLit x) = pretty x
pretty (CharLit x) = squotes (pretty x)
pretty (BinOp op l r) = parens (pretty l <+> pretty op <+> pretty r)
pretty (UnOp op e) = pretty op <> parens (pretty e)
pretty (Call f args) = parens (pretty f) <> parens (hsep (punctuate comma (map pretty args)))
pretty (Index arr idx) = parens (pretty arr) <> brackets (pretty idx)
pretty (Member e m) = pretty e <> "." <> pretty m
pretty (Cast t e) = parens (pretty t) <> parens (pretty e)
pretty (Sizeof t) = "sizeof" <> parens (pretty t)
pretty (StructInit s fields) = pretty s <+> lbrace <> line <> indent 4 (vsep (punctuate comma (map (\(n, e) -> pretty n <+> "=" <+> pretty e) fields))) <> line <> rbrace
instance Pretty Stmt where
pretty (Expr e) = pretty e <> semi
pretty (Return e) = "return" <+> pretty e <> semi
pretty (If cond t f) = "if" <+> pretty cond <+> prettyBlock t <+> maybe "" (\f' -> "else" <+> prettyBlock f') f
pretty (While cond body) = "while" <+> pretty cond <+> prettyBlock body
pretty (Assign op l r) = pretty l <+> pretty op <+> pretty r <> semi
pretty (Block stmts) = braces (vsep (map pretty stmts))
pretty (Var n t e) = pretty n <+> maybe "" (\t' -> ":" <+> pretty t') t <+> maybe "" (\e' -> "=" <+> pretty e') e <> semi
instance Pretty Type where
pretty IntType = "int"
pretty UIntType = "uint"
pretty FloatType = "float"
pretty StrType = "str"
pretty BoolType = "bool"
pretty CharType = "char"
pretty (PtrType t) = pretty t <> "*"
pretty (ArrayType t) = pretty t <> "[]"
pretty (StructType s) = pretty s
pretty (EnumType e) = pretty e
pretty VoidType = "void"
instance Pretty Bind where
pretty (Bind n t) = pretty n <+> ":" <+> pretty t
instance Pretty TLStruct where
pretty (Struct n fields) = "struct" <+> pretty n <+> prettyFields fields
instance Pretty TLEnum where
pretty (Enum n fields) = "enum" <+> pretty n <+> prettyFields fields
instance Pretty TLFunc where
pretty (Func n args ret body) =
"fn " <> pretty n <> parens (hsep (punctuate comma (map pretty args))) <+> "->" <+> pretty ret <+> prettyBlock body
instance Pretty TL where
pretty (TLStruct s) = pretty s
pretty (TLEnum e) = pretty e
pretty (TLFunc f) = pretty f
instance Pretty Program where
pretty (Program structs enums funcs) = vsep (map pretty structs) <> line <> vsep (map pretty enums) <> line <> vsep (map pretty funcs)
prettyFields :: (Pretty a) => [a] -> Doc ann
prettyFields fields = lbrace <> line <> indent 4 (vsep (punctuate comma (map pretty fields))) <> line <> rbrace
prettyBlock :: (Pretty a) => [a] -> Doc ann
prettyBlock stmts = lbrace <> line <> indent 4 (vsep (map pretty stmts)) <> line <> rbrace