module AST.Module where
import Data.Binary
import qualified Data.List as List
import qualified Data.Map as Map
import Control.Applicative ((<$>),(<*>))
import qualified AST.Expression.Canonical as Canonical
import qualified AST.Declaration as Decl
import qualified AST.Type as Type
import qualified AST.Variable as Var
import AST.PrettyPrint
import Text.PrettyPrint as P
import qualified Elm.Internal.Version as Version
data Module exs body = Module
{ names :: [String]
, path :: FilePath
, exports :: exs
, imports :: [(String, ImportMethod)]
, body :: body
}
getName :: Module exs body -> String
getName modul =
List.intercalate "." (names modul)
data CanonicalBody = CanonicalBody
{ program :: Canonical.Expr
, types :: Types
, fixities :: [(Decl.Assoc, Int, String)]
, aliases :: Aliases
, datatypes :: ADTs
, ports :: [String]
}
type SourceModule = Module (Var.Listing Var.Value) [Decl.SourceDecl]
type ValidModule = Module (Var.Listing Var.Value) [Decl.ValidDecl]
type CanonicalModule = Module [Var.Value] CanonicalBody
type Interfaces = Map.Map String Interface
type Types = Map.Map String Type.CanonicalType
type Aliases = Map.Map String ( [String], Type.CanonicalType )
type ADTs = Map.Map String (AdtInfo String)
type AdtInfo v = ( [String], [(v, [Type.CanonicalType])] )
type CanonicalAdt = (Var.Canonical, AdtInfo Var.Canonical)
data Interface = Interface
{ iVersion :: Version.Version
, iExports :: [Var.Value]
, iTypes :: Types
, iImports :: [(String, ImportMethod)]
, iAdts :: ADTs
, iAliases :: Aliases
, iFixities :: [(Decl.Assoc, Int, String)]
, iPorts :: [String]
}
toInterface :: CanonicalModule -> Interface
toInterface modul =
let body' = body modul in
Interface
{ iVersion = Version.elmVersion
, iExports = exports modul
, iTypes = types body'
, iImports = imports modul
, iAdts = datatypes body'
, iAliases = aliases body'
, iFixities = fixities body'
, iPorts = ports body'
}
instance Binary Interface where
get = Interface <$> get <*> get <*> get <*> get <*> get <*> get <*> get <*> get
put modul = do
put (iVersion modul)
put (iExports modul)
put (iTypes modul)
put (iImports modul)
put (iAdts modul)
put (iAliases modul)
put (iFixities modul)
put (iPorts modul)
data ImportMethod
= As !String
| Open !(Var.Listing Var.Value)
open :: ImportMethod
open = Open (Var.openListing)
importing :: [Var.Value] -> ImportMethod
importing xs = Open (Var.Listing xs False)
instance Binary ImportMethod where
put method =
case method of
As alias -> putWord8 0 >> put alias
Open listing -> putWord8 1 >> put listing
get = do tag <- getWord8
case tag of
0 -> As <$> get
1 -> Open <$> get
_ -> error "Error reading valid ImportMethod type from serialized string"
instance (Pretty exs, Pretty body) => Pretty (Module exs body) where
pretty (Module names _ exs ims body) =
P.vcat [modul, P.text "", prettyImports, P.text "", pretty body]
where
modul = P.text "module" <+> name <+> pretty exs <+> P.text "where"
name = P.text (List.intercalate "." names)
prettyImports = P.vcat $ map prettyMethod ims
prettyMethod :: (String, ImportMethod) -> Doc
prettyMethod (name, method) =
case method of
As alias
| name == alias -> P.empty
| otherwise -> P.text "as" <+> P.text alias
Open listing -> pretty listing