modulo-1.5: src/Language/Modulo.hs
{-# LANGUAGE DisambiguateRecordFields, TypeFamilies,
StandaloneDeriving, DeriveFunctor, DeriveFoldable, GeneralizedNewtypeDeriving #-}
-------------------------------------------------------------------------------------
-- |
-- Copyright : (c) Hans Hoglund 2012
--
-- License : BSD-style
--
-- Maintainer : hans@hanshoglund.se
-- Stability : experimental
-- Portability : GHC
--
-- This Haskell module defines the Modulo description language. Typically, modules are created
-- by writing @.module@ files and using the parser defined in "Language.Modulo.Parser", or
-- the @modulo@ command-line tool. The abstract syntax tree is given below.
--
-- The module language is very simple. Each module consists of a name followed by
-- eventual import declarations, followed by all other declarations. Here is an example module:
--
-- > module Scl.List
-- > {
-- > opaque Elem;
-- > opaque List;
-- >
-- > nil : () -> List;
-- > cons : (Elem, List) -> List;
-- > head : (List) -> Elem;
-- > tail : (List) -> List;
-- >
-- > empty : (List) -> Bool;
-- > lenght : (List) -> Int;
-- >
-- > reverse : (List) -> List;
-- > sort : (List) -> List;
-- > }
--
-- Like C, the module language uses structural typing for pointers and functions, but
-- nominal typing for structures and unions. Thus in the following example values of type
-- @A@ and @B@ are interchangeable, but values of type @C@ and @D@ are not.
--
-- > type A = Ptr Int
-- > type B = Ptr Int
-- > type C = struct { x : Int, y : Int }
-- > type D = struct { x : Int, y : Int }
--
-- The pointer type constructor can be used with any type:
--
-- > type IntPtr = Int*
-- > type FloatPtr = Float*
--
-- The array type constructor need an explicit length:
--
-- > type IntVec = [Int x 10]
--
-- Functions are written as in Haskell, except for the parentheses enclosing the arguments.
-- Thus, higher-arity functions are easily distinguished.
--
-- > type NoCurry = (A, B) -> C
-- > type Curry = (A) -> (B) -> C
--
-- Compound types are written in a uniform manner:
--
-- > type IntCounter = struct { a : Int, b : Int -> Int }
-- > type NumValue = union { left : Int, right : Float }
-- > type Color = enum { Red, Green, Blue }
--
-- The following primitive types are provided:
--
-- > Void Size Ptrdiff Intptr UIntptr
-- > Char Short Int Long LongLong
-- > UChar UShort UInt ULong ULongLong
-- > Float Double LongDouble
-- > Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64
--
--
--
-------------------------------------------------------------------------------------
module Language.Modulo (
-- ** Modules
Module(..),
ModuleName(..),
toModuleName,
getModuleNameList,
-- ** Documentation
Doc(..),
-- ** Names
Name(..),
getName,
-- ** Declarations
Decl(..),
getDeclName,
Value(..),
-- ** Types
Type(..),
PrimType(..),
RefType(..),
FunType(..),
CompType(..),
) where
import Data.Ord
import Data.String
import Numeric.Natural
import Foreign.C.Types
import Data.List.NonEmpty ( NonEmpty(..) )
import qualified Data.List as List
import qualified Data.List.NonEmpty as NonEmpty
newtype Doc = Doc { getDoc :: String }
deriving (Eq, Ord, Show, IsString)
-- |
-- A module is a named container of imports and declarations.
--
-- Each module can depend on a set of other modules (translated as include directives).
-- Recursive dependencies are not allowed for now.
--
data Module
= Module
{
modDoc :: Doc,
modName :: ModuleName, -- ^ Name of module
modImports :: [(ModuleName, Maybe String)], -- ^ Imports with optional import conventions
modDecls :: [(Doc, Decl)] -- ^ List of declarations
}
deriving (Eq, Show)
instance Ord Module where
compare = comparing modName
-- |
-- A module name is a non-empty list of strings.
--
newtype ModuleName
= ModuleName
{
getModuleName :: (NonEmpty String)
}
deriving (Eq, Ord)
toModuleName :: [String] -> ModuleName
toModuleName = ModuleName . NonEmpty.fromList
getModuleNameList :: ModuleName -> [String]
getModuleNameList = NonEmpty.toList . getModuleName
instance Show ModuleName where
show (ModuleName (x :| xs)) = concat . List.intersperse "." $ x : xs
-- |
-- Name of a type, function or constant value.
--
-- Note that any Unicode string may be used as a name.
--
data Name
= Name String
| QName ModuleName String
deriving (Eq, Ord)
getName :: Name -> String
getName (Name n) = n
getName (QName m n) = show m ++ "." ++ n
instance Show Name where
show = getName
-- |
-- An declaration maps a name to type and optionally a value.
--
data Decl
= TypeDecl Name (Maybe Type) -- ^ Declares a type or opaque.
| FunctionDecl Name FunType -- ^ Declares a function.
| TagDecl Type -- ^ Declares a struct or enum tag.
| ConstDecl Name (Maybe Value) Type -- ^ Declares a constant value.
| GlobalDecl Name (Maybe Value) Type -- ^ Declares a global variable.
deriving (Eq, Show)
getDeclName :: Decl -> Maybe Name
getDeclName (TypeDecl n t) = Just n
getDeclName (FunctionDecl n t) = Just n
getDeclName (TagDecl t) = Nothing
getDeclName (ConstDecl n v t) = Just n
getDeclName (GlobalDecl n v t) = Just n
-- |
-- A value is anything that can be declared as a C constant.
data Value
= CInt Integer
| CFloat Double
| CStr String
| CWStr String
| CInitList [Value]
deriving (Eq, Show)
-- |
-- A type is either an alias, a primitive or a compound type.
data Type
= AliasType Name -- ^ An alias, introduced by a former type declaration.
| PrimType PrimType
| RefType RefType
| FunType FunType
| CompType CompType
deriving (Eq, Show)
-- | A primitive type.
data PrimType
= Void | Size | Ptrdiff | Intptr | UIntptr
| Char | Short | Int | Long | LongLong
| SChar
| Bool
| UChar | UShort | UInt | ULong | ULongLong
| Float | Double | LongDouble
| Int8 | Int16 | Int32 | Int64 | UInt8 | UInt16 | UInt32 | UInt64
deriving (Eq, Show)
-- StrUtf8
-- StrUcs16Be
-- StrUcs16Le
-- StrUtf16Be
-- StrUtf16Le
data RefType
= Pointer Type -- ^ The C pointer type @t*@.
| Array Type Natural -- ^ The C array type @t[n]@.
deriving (Eq, Show)
-- | A function type.
data FunType
= Function [Type] Type -- ^ The C function type @Tn(T1, ... Tn-1)@.
deriving (Eq, Show)
data CompType
= Enum (NonEmpty Name) -- ^ A C enum type.
| Struct (NonEmpty (Name, Type)) -- ^ A C struct type.
| Union (NonEmpty (Name, Type)) -- ^ A C union type.
| BitField (NonEmpty (Name, Type, Natural)) -- ^ A C bitfield type.
deriving (Eq, Show)
-- TODO Decl of struct/union tags
-- TODO use Foreign.C values for Value
-- TODO Decl order by sort and name?