language-qux-0.2.0.0: src/Language/Qux/Annotated/Syntax.hs
{-|
Module : Language.Qux.Annotated.Syntax
Description : Abstract syntax tree nodes with annotations.
Copyright : (c) Henry J. Wylde, 2015
License : BSD3
Maintainer : public@hjwylde.com
Abstract syntax tree nodes with annotations.
The annotation style was inspired by haskell-src-exts.
Instances of 'Simplifiable' are provided for simplifying a node down to it's unannotated form and of
'Pretty' for pretty printing.
-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Language.Qux.Annotated.Syntax (
-- * Type classes
Annotated(..),
Simplifiable(..),
-- * Annotated nodes
Id(..), Program(..), Decl(..), Stmt(..), Expr(..), Type(..),
-- * Regular nodes
BinaryOp(..), UnaryOp(..), Value(..)
) where
import Language.Qux.Syntax (BinaryOp(..), UnaryOp(..), Value(..))
import qualified Language.Qux.Syntax as S
import Text.PrettyPrint.HughesPJClass
-- | An annotated class.
-- Annotations are used for attaching data to a node, such as a 'Text.Parsec.SourcePos'.
class Annotated n where
ann :: n a -> a
-- | A simplifiable class.
-- Simplifiable is used to simplify a node to a a simpler form.
-- See "Language.Qux.Syntax" for simpler forms of the nodes defined here.
class Simplifiable n r | n -> r where
simp :: n -> r
-- | An identifier. Identifiers should match '[a-z_][a-zA-Z0-9_']*'.
data Id a = Id a String
deriving (Eq, Functor, Show)
instance Annotated Id where
ann (Id a _) = a
instance Simplifiable (Id a) [Char] where
simp (Id _ id_) = id_
instance Pretty (Id a) where
pPrint = text . simp
-- | A program is a module identifier (list of 'Id''s) and a list of declarations.
data Program a = Program a [Id a] [Decl a]
deriving (Eq, Functor, Show)
instance Annotated Program where
ann (Program a _ _) = a
instance Simplifiable (Program a) S.Program where
simp (Program _ module_ decls) = S.Program (map simp module_) (map simp decls)
instance Pretty (Program a) where
pPrint = pPrint . simp
-- | A declaration.
data Decl a = FunctionDecl a (Id a) [(Type a, Id a)] [Stmt a] -- ^ A name, list of ('Type', 'Id') parameters and statements.
-- The return type is treated as a parameter with id '@'.
deriving (Eq, Functor, Show)
instance Annotated Decl where
ann (FunctionDecl a _ _ _) = a
instance Simplifiable (Decl a) S.Decl where
simp (FunctionDecl _ name parameters stmts) = S.FunctionDecl (simp name) (map (tmap simp simp) parameters) (map simp stmts)
instance Pretty (Decl a) where
pPrint = pPrint . simp
-- | A statement.
data Stmt a = IfStmt a (Expr a) [Stmt a] [Stmt a] -- ^ A condition, true block and false block of statements.
| ReturnStmt a (Expr a) -- ^ An expression.
| WhileStmt a (Expr a) [Stmt a] -- ^ A condition and block of statements.
deriving (Eq, Functor, Show)
instance Annotated Stmt where
ann (IfStmt a _ _ _) = a
ann (ReturnStmt a _) = a
ann (WhileStmt a _ _) = a
instance Simplifiable (Stmt a) S.Stmt where
simp (IfStmt _ condition trueStmts falseStmts) = S.IfStmt (simp condition) (map simp trueStmts) (map simp falseStmts)
simp (ReturnStmt _ expr) = S.ReturnStmt (simp expr)
simp (WhileStmt _ condition stmts) = S.WhileStmt (simp condition) (map simp stmts)
instance Pretty (Stmt a) where
pPrint = pPrint . simp
-- | A complex expression.
data Expr a = ApplicationExpr a (Id a) [Expr a] -- ^ A function name to call and the arguments to pass as parameters.
| BinaryExpr a BinaryOp (Expr a) (Expr a) -- ^ A binary operation.
| ListExpr a [Expr a] -- ^ A list expression.
| TypedExpr a S.Type (Expr a) -- ^ A typed expression.
-- See "Language.Qux.Annotated.TypeResolver".
| UnaryExpr a UnaryOp (Expr a) -- ^ A unary operation.
| ValueExpr a Value -- ^ A raw value.
deriving (Eq, Functor, Show)
instance Annotated Expr where
ann (ApplicationExpr a _ _) = a
ann (BinaryExpr a _ _ _) = a
ann (ListExpr a _) = a
ann (TypedExpr a _ _) = a
ann (UnaryExpr a _ _) = a
ann (ValueExpr a _) = a
instance Simplifiable (Expr a) S.Expr where
simp (ApplicationExpr _ id arguments) = S.ApplicationExpr (simp id) (map simp arguments)
simp (BinaryExpr _ op lhs rhs) = S.BinaryExpr op (simp lhs) (simp rhs)
simp (ListExpr _ elements) = S.ListExpr (map simp elements)
simp (TypedExpr _ type_ expr) = S.TypedExpr type_ (simp expr)
simp (UnaryExpr _ op expr) = S.UnaryExpr op (simp expr)
simp (ValueExpr _ value) = S.ValueExpr value
instance Pretty (Expr a) where
pPrint = pPrint . simp
-- | A type.
data Type a = BoolType a
| IntType a
| ListType a (Type a) -- ^ A list type with an inner type.
| NilType a
deriving (Eq, Functor, Show)
instance Annotated Type where
ann (BoolType a) = a
ann (IntType a) = a
ann (ListType a _) = a
ann (NilType a) = a
instance Simplifiable (Type a) S.Type where
simp (BoolType _) = S.BoolType
simp (IntType _) = S.IntType
simp (ListType _ inner) = S.ListType $ simp inner
simp (NilType _) = S.NilType
instance Pretty (Type a) where
pPrint = pPrint . simp
-- Helper methods
tmap :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)
tmap f g (a, c) = (f a, g c)