packages feed

curry-frontend 0.2.12 → 1.0.1

raw patch · 131 files changed

+23279/−19823 lines, 131 filesdep +Cabaldep +curry-frontenddep +directorydep −old-timedep −sybdep ~basedep ~curry-basenew-component:exe:curry-frontendnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: Cabal, curry-frontend, directory, extra, network, network-uri, process, set-extra, transformers

Dependencies removed: old-time, syb

Dependency ranges changed: base, curry-base

API changes (from Hackage documentation)

- Curry.Files.CymakePath: cymakeVersion :: String
- Curry.Files.CymakePath: getCymake :: IO String
+ Base.AnnotExpr: class QualAnnotExpr e
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Alt
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.CondExpr
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Decl
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Equation
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Expression
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.InfixOp
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Lhs
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Pattern
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Rhs
+ Base.AnnotExpr: instance Base.AnnotExpr.QualAnnotExpr Curry.Syntax.Type.Statement
+ Base.AnnotExpr: qafv :: QualAnnotExpr e => ModuleIdent -> e Type -> [(Type, Ident)]
+ Base.CurryKinds: fromKind :: Kind -> KindExpr
+ Base.CurryKinds: fromKind' :: Kind -> Int -> Maybe KindExpr
+ Base.CurryKinds: ppKind :: Kind -> Doc
+ Base.CurryKinds: toKind :: KindExpr -> Kind
+ Base.CurryKinds: toKind' :: Maybe KindExpr -> Int -> Kind
+ Base.CurryTypes: fromPred :: [Ident] -> Pred -> Constraint
+ Base.CurryTypes: fromPredSet :: [Ident] -> PredSet -> Context
+ Base.CurryTypes: fromPredType :: [Ident] -> PredType -> QualTypeExpr
+ Base.CurryTypes: fromQualPred :: ModuleIdent -> [Ident] -> Pred -> Constraint
+ Base.CurryTypes: fromQualPredSet :: ModuleIdent -> [Ident] -> PredSet -> Context
+ Base.CurryTypes: fromQualPredType :: ModuleIdent -> [Ident] -> PredType -> QualTypeExpr
+ Base.CurryTypes: fromQualType :: ModuleIdent -> [Ident] -> Type -> TypeExpr
+ Base.CurryTypes: fromType :: [Ident] -> Type -> TypeExpr
+ Base.CurryTypes: ppPred :: ModuleIdent -> Pred -> Doc
+ Base.CurryTypes: ppPredType :: ModuleIdent -> PredType -> Doc
+ Base.CurryTypes: ppType :: ModuleIdent -> Type -> Doc
+ Base.CurryTypes: ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc
+ Base.CurryTypes: toConstrType :: QualIdent -> [Ident] -> Context -> [TypeExpr] -> PredType
+ Base.CurryTypes: toMethodType :: QualIdent -> Ident -> QualTypeExpr -> PredType
+ Base.CurryTypes: toPred :: [Ident] -> Constraint -> Pred
+ Base.CurryTypes: toPredSet :: [Ident] -> Context -> PredSet
+ Base.CurryTypes: toPredType :: [Ident] -> QualTypeExpr -> PredType
+ Base.CurryTypes: toQualPred :: ModuleIdent -> [Ident] -> Constraint -> Pred
+ Base.CurryTypes: toQualPredSet :: ModuleIdent -> [Ident] -> Context -> PredSet
+ Base.CurryTypes: toQualPredType :: ModuleIdent -> [Ident] -> QualTypeExpr -> PredType
+ Base.CurryTypes: toQualType :: ModuleIdent -> [Ident] -> TypeExpr -> Type
+ Base.CurryTypes: toQualTypes :: ModuleIdent -> [Ident] -> [TypeExpr] -> [Type]
+ Base.CurryTypes: toType :: [Ident] -> TypeExpr -> Type
+ Base.CurryTypes: toTypes :: [Ident] -> [TypeExpr] -> [Type]
+ Base.Expr: bv :: QuantExpr e => e -> [Ident]
+ Base.Expr: class Expr e
+ Base.Expr: class QualExpr e
+ Base.Expr: class QuantExpr e
+ Base.Expr: fv :: Expr e => e -> [Ident]
+ Base.Expr: instance Base.Expr.Expr Curry.Syntax.Type.Constraint
+ Base.Expr: instance Base.Expr.Expr Curry.Syntax.Type.QualTypeExpr
+ Base.Expr: instance Base.Expr.Expr Curry.Syntax.Type.TypeExpr
+ Base.Expr: instance Base.Expr.Expr e => Base.Expr.Expr [e]
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Alt a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.CondExpr a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Decl a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Equation a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Expression a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.InfixOp a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Lhs a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Pattern a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Rhs a)
+ Base.Expr: instance Base.Expr.QualExpr (Curry.Syntax.Type.Statement a)
+ Base.Expr: instance Base.Expr.QualExpr a => Base.Expr.QualExpr (Curry.Syntax.Type.Field a)
+ Base.Expr: instance Base.Expr.QualExpr e => Base.Expr.QualExpr [e]
+ Base.Expr: instance Base.Expr.QuantExpr (Curry.Syntax.Type.Decl a)
+ Base.Expr: instance Base.Expr.QuantExpr (Curry.Syntax.Type.Lhs a)
+ Base.Expr: instance Base.Expr.QuantExpr (Curry.Syntax.Type.Pattern a)
+ Base.Expr: instance Base.Expr.QuantExpr (Curry.Syntax.Type.Statement a)
+ Base.Expr: instance Base.Expr.QuantExpr (Curry.Syntax.Type.Var a)
+ Base.Expr: instance Base.Expr.QuantExpr Curry.Syntax.Type.Constraint
+ Base.Expr: instance Base.Expr.QuantExpr Curry.Syntax.Type.QualTypeExpr
+ Base.Expr: instance Base.Expr.QuantExpr Curry.Syntax.Type.TypeExpr
+ Base.Expr: instance Base.Expr.QuantExpr a => Base.Expr.QuantExpr (Curry.Syntax.Type.Field a)
+ Base.Expr: instance Base.Expr.QuantExpr e => Base.Expr.QuantExpr [e]
+ Base.Expr: qfv :: QualExpr e => ModuleIdent -> e -> [Ident]
+ Base.KindSubst: bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e
+ Base.KindSubst: bindVar :: Int -> Kind -> KindSubst -> KindSubst
+ Base.KindSubst: class SubstKind a
+ Base.KindSubst: compose :: Ord v => Subst v e -> Subst v e -> Subst v e
+ Base.KindSubst: idSubst :: Subst a b
+ Base.KindSubst: instance Base.KindSubst.SubstKind Base.Kinds.Kind
+ Base.KindSubst: instance Base.KindSubst.SubstKind Env.TypeConstructor.TypeInfo
+ Base.KindSubst: instance Base.KindSubst.SubstKind a => Base.KindSubst.SubstKind (Base.TopEnv.TopEnv a)
+ Base.KindSubst: singleSubst :: Ord v => v -> e -> Subst v e
+ Base.KindSubst: subst :: SubstKind a => KindSubst -> a -> a
+ Base.KindSubst: substVar :: KindSubst -> Int -> Kind
+ Base.KindSubst: type KindSubst = Subst Int Kind
+ Base.Kinds: KindArrow :: Kind -> Kind -> Kind
+ Base.Kinds: KindStar :: Kind
+ Base.Kinds: KindVariable :: Int -> Kind
+ Base.Kinds: data Kind
+ Base.Kinds: defaultKind :: Kind -> Kind
+ Base.Kinds: instance GHC.Classes.Eq Base.Kinds.Kind
+ Base.Kinds: instance GHC.Show.Show Base.Kinds.Kind
+ Base.Kinds: isSimpleKind :: Kind -> Bool
+ Base.Kinds: kindArity :: Kind -> Int
+ Base.Kinds: kindVars :: Kind -> [Int]
+ Base.Kinds: simpleKind :: Int -> Kind
+ Base.Messages: abortWith :: [String] -> IO a
+ Base.Messages: abortWithMessage :: Message -> IO a
+ Base.Messages: abortWithMessages :: [Message] -> IO a
+ Base.Messages: class Monad m => MonadIO (m :: * -> *)
+ Base.Messages: data Message :: *
+ Base.Messages: internalError :: String -> a
+ Base.Messages: liftIO :: MonadIO m => IO a -> m a
+ Base.Messages: message :: Doc -> Message
+ Base.Messages: posMessage :: HasPosition p => p -> Doc -> Message
+ Base.Messages: putErrLn :: MonadIO m => String -> m ()
+ Base.Messages: putErrsLn :: MonadIO m => [String] -> m ()
+ Base.Messages: putMsg :: MonadIO m => String -> m ()
+ Base.Messages: status :: MonadIO m => Options -> String -> m ()
+ Base.Messages: warnOrAbort :: WarnOpts -> [Message] -> IO ()
+ Base.NestEnv: bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a
+ Base.NestEnv: data NestEnv a
+ Base.NestEnv: elemNestEnv :: Ident -> NestEnv a -> Bool
+ Base.NestEnv: emptyEnv :: NestEnv a
+ Base.NestEnv: globalEnv :: TopEnv a -> NestEnv a
+ Base.NestEnv: instance GHC.Base.Functor Base.NestEnv.NestEnv
+ Base.NestEnv: instance GHC.Show.Show a => GHC.Show.Show (Base.NestEnv.NestEnv a)
+ Base.NestEnv: localNestEnv :: NestEnv a -> [(Ident, a)]
+ Base.NestEnv: lookupNestEnv :: Ident -> NestEnv a -> [a]
+ Base.NestEnv: modifyNestEnv :: (a -> a) -> Ident -> NestEnv a -> NestEnv a
+ Base.NestEnv: nestEnv :: NestEnv a -> NestEnv a
+ Base.NestEnv: qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a
+ Base.NestEnv: qualInLocalNestEnv :: QualIdent -> NestEnv a -> Bool
+ Base.NestEnv: qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]
+ Base.NestEnv: qualModifyNestEnv :: (a -> a) -> QualIdent -> NestEnv a -> NestEnv a
+ Base.NestEnv: qualRebindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a
+ Base.NestEnv: rebindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a
+ Base.NestEnv: toplevelEnv :: NestEnv a -> TopEnv a
+ Base.NestEnv: unnestEnv :: NestEnv a -> NestEnv a
+ Base.PrettyKinds: instance Curry.Base.Pretty.Pretty Base.Kinds.Kind
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.ClassMethod
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.DataConstr
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.ExistTypeScheme
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.Pred
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.PredType
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.Type
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty Base.Types.TypeScheme
+ Base.PrettyTypes: instance Curry.Base.Pretty.Pretty a => Curry.Base.Pretty.Pretty (Data.Set.Internal.Set a)
+ Base.SCC: instance GHC.Classes.Eq (Base.SCC.Node a b)
+ Base.SCC: instance GHC.Classes.Ord (Base.SCC.Node b a)
+ Base.SCC: scc :: Eq b => (a -> [b]) -> (a -> [b]) -> [a] -> [[a]]
+ Base.Subst: Subst :: Bool -> (Map a b) -> Subst a b
+ Base.Subst: bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e
+ Base.Subst: class IntSubst e
+ Base.Subst: compose :: Ord v => Subst v e -> Subst v e -> Subst v e
+ Base.Subst: data Subst a b
+ Base.Subst: idSubst :: Subst a b
+ Base.Subst: instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Base.Subst.Subst a b)
+ Base.Subst: isubst :: IntSubst e => Subst Int e -> e -> e
+ Base.Subst: isubstVar :: IntSubst e => Subst Int e -> Int -> e
+ Base.Subst: ivar :: IntSubst e => Int -> e
+ Base.Subst: restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e
+ Base.Subst: singleSubst :: Ord v => v -> e -> Subst v e
+ Base.Subst: substToList :: Subst v e -> [(v, e)]
+ Base.Subst: substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e) -> Subst v e -> v -> e
+ Base.Subst: unbindSubst :: Ord v => v -> Subst v e -> Subst v e
+ Base.TopEnv: TopEnv :: Map QualIdent [(Source, a)] -> TopEnv a
+ Base.TopEnv: [topEnvMap] :: TopEnv a -> Map QualIdent [(Source, a)]
+ Base.TopEnv: allBindings :: TopEnv a -> [(QualIdent, a)]
+ Base.TopEnv: allEntities :: TopEnv a -> [a]
+ Base.TopEnv: allImports :: TopEnv a -> [(QualIdent, a)]
+ Base.TopEnv: allLocalBindings :: TopEnv a -> [(QualIdent, a)]
+ Base.TopEnv: bindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: class Entity a
+ Base.TopEnv: emptyTopEnv :: TopEnv a
+ Base.TopEnv: importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: instance GHC.Base.Functor Base.TopEnv.TopEnv
+ Base.TopEnv: instance GHC.Classes.Eq Base.TopEnv.Source
+ Base.TopEnv: instance GHC.Show.Show Base.TopEnv.Source
+ Base.TopEnv: instance GHC.Show.Show a => GHC.Show.Show (Base.TopEnv.TopEnv a)
+ Base.TopEnv: localBindings :: TopEnv a -> [(Ident, a)]
+ Base.TopEnv: lookupTopEnv :: Ident -> TopEnv a -> [a]
+ Base.TopEnv: merge :: Entity a => a -> a -> Maybe a
+ Base.TopEnv: moduleImports :: ModuleIdent -> TopEnv a -> [(Ident, a)]
+ Base.TopEnv: newtype TopEnv a
+ Base.TopEnv: origName :: Entity a => a -> QualIdent
+ Base.TopEnv: predefTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: qualBindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: qualElemTopEnv :: QualIdent -> TopEnv a -> Bool
+ Base.TopEnv: qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]
+ Base.TopEnv: qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: qualUnbindTopEnv :: QualIdent -> TopEnv a -> TopEnv a
+ Base.TopEnv: rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a
+ Base.TopEnv: unbindTopEnv :: Ident -> TopEnv a -> TopEnv a
+ Base.TypeExpansion: expandConstrType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> [Ident] -> Context -> [TypeExpr] -> PredType
+ Base.TypeExpansion: expandMethodType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> Ident -> QualTypeExpr -> PredType
+ Base.TypeExpansion: expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type
+ Base.TypeExpansion: expandPolyType :: ModuleIdent -> TCEnv -> ClassEnv -> QualTypeExpr -> PredType
+ Base.TypeExpansion: expandPred :: ModuleIdent -> TCEnv -> Pred -> Pred
+ Base.TypeExpansion: expandPredSet :: ModuleIdent -> TCEnv -> ClassEnv -> PredSet -> PredSet
+ Base.TypeExpansion: expandPredType :: ModuleIdent -> TCEnv -> ClassEnv -> PredType -> PredType
+ Base.TypeExpansion: expandType :: ModuleIdent -> TCEnv -> Type -> Type
+ Base.TypeExpansion: expandType' :: ModuleIdent -> TCEnv -> Type -> [Type] -> Type
+ Base.TypeSubst: bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e
+ Base.TypeSubst: bindVar :: Int -> Type -> TypeSubst -> TypeSubst
+ Base.TypeSubst: class ExpandAliasType a
+ Base.TypeSubst: class SubstType a
+ Base.TypeSubst: compose :: Ord v => Subst v e -> Subst v e -> Subst v e
+ Base.TypeSubst: expandAliasType :: ExpandAliasType a => [Type] -> a -> a
+ Base.TypeSubst: expandAliasType' :: [Type] -> Type -> [Type] -> Type
+ Base.TypeSubst: idSubst :: Subst a b
+ Base.TypeSubst: instance (GHC.Classes.Ord a, Base.TypeSubst.ExpandAliasType a) => Base.TypeSubst.ExpandAliasType (Data.Set.Internal.Set a)
+ Base.TypeSubst: instance (GHC.Classes.Ord a, Base.TypeSubst.SubstType a) => Base.TypeSubst.SubstType (Data.Set.Internal.Set a)
+ Base.TypeSubst: instance Base.TypeSubst.ExpandAliasType Base.Types.Pred
+ Base.TypeSubst: instance Base.TypeSubst.ExpandAliasType Base.Types.PredType
+ Base.TypeSubst: instance Base.TypeSubst.ExpandAliasType Base.Types.Type
+ Base.TypeSubst: instance Base.TypeSubst.ExpandAliasType a => Base.TypeSubst.ExpandAliasType [a]
+ Base.TypeSubst: instance Base.TypeSubst.SubstType Base.Types.ExistTypeScheme
+ Base.TypeSubst: instance Base.TypeSubst.SubstType Base.Types.Pred
+ Base.TypeSubst: instance Base.TypeSubst.SubstType Base.Types.PredType
+ Base.TypeSubst: instance Base.TypeSubst.SubstType Base.Types.Type
+ Base.TypeSubst: instance Base.TypeSubst.SubstType Base.Types.TypeScheme
+ Base.TypeSubst: instance Base.TypeSubst.SubstType Env.Value.ValueInfo
+ Base.TypeSubst: instance Base.TypeSubst.SubstType a => Base.TypeSubst.SubstType (Base.TopEnv.TopEnv a)
+ Base.TypeSubst: instance Base.TypeSubst.SubstType a => Base.TypeSubst.SubstType [a]
+ Base.TypeSubst: instanceType :: ExpandAliasType a => Type -> a -> a
+ Base.TypeSubst: normalize :: Int -> PredType -> PredType
+ Base.TypeSubst: singleSubst :: Ord v => v -> e -> Subst v e
+ Base.TypeSubst: subst :: SubstType a => TypeSubst -> a -> a
+ Base.TypeSubst: subst' :: TypeSubst -> Type -> [Type] -> Type
+ Base.TypeSubst: substVar :: TypeSubst -> Int -> Type
+ Base.TypeSubst: type TypeSubst = Subst Int Type
+ Base.Types: ClassMethod :: Ident -> (Maybe Int) -> PredType -> ClassMethod
+ Base.Types: DataConstr :: Ident -> Int -> PredSet -> [Type] -> DataConstr
+ Base.Types: ForAll :: Int -> PredType -> TypeScheme
+ Base.Types: ForAllExist :: Int -> Int -> PredType -> ExistTypeScheme
+ Base.Types: Pred :: QualIdent -> Type -> Pred
+ Base.Types: PredType :: PredSet -> Type -> PredType
+ Base.Types: RecordConstr :: Ident -> Int -> PredSet -> [Ident] -> [Type] -> DataConstr
+ Base.Types: TypeApply :: Type -> Type -> Type
+ Base.Types: TypeArrow :: Type -> Type -> Type
+ Base.Types: TypeConstrained :: [Type] -> Int -> Type
+ Base.Types: TypeConstructor :: QualIdent -> Type
+ Base.Types: TypeForall :: [Int] -> Type -> Type
+ Base.Types: TypeSkolem :: Int -> Type
+ Base.Types: TypeVariable :: Int -> Type
+ Base.Types: applyType :: Type -> [Type] -> Type
+ Base.Types: arrowArgs :: Type -> [Type]
+ Base.Types: arrowArity :: Type -> Int
+ Base.Types: arrowBase :: Type -> Type
+ Base.Types: arrowType :: Type -> Type -> Type
+ Base.Types: arrowUnapply :: Type -> ([Type], Type)
+ Base.Types: boolType :: Type
+ Base.Types: charType :: Type
+ Base.Types: class IsType t
+ Base.Types: consType :: Type -> Type
+ Base.Types: constrIdent :: DataConstr -> Ident
+ Base.Types: constrTypes :: DataConstr -> [Type]
+ Base.Types: data ClassMethod
+ Base.Types: data DataConstr
+ Base.Types: data ExistTypeScheme
+ Base.Types: data Pred
+ Base.Types: data PredType
+ Base.Types: data Type
+ Base.Types: data TypeScheme
+ Base.Types: emptyPredSet :: PredSet
+ Base.Types: floatType :: Type
+ Base.Types: fractionalTypes :: [Type]
+ Base.Types: instance (Base.Types.IsType a, GHC.Classes.Ord a) => Base.Types.IsType (Data.Set.Internal.Set a)
+ Base.Types: instance Base.Types.IsType Base.Types.ExistTypeScheme
+ Base.Types: instance Base.Types.IsType Base.Types.Pred
+ Base.Types: instance Base.Types.IsType Base.Types.PredType
+ Base.Types: instance Base.Types.IsType Base.Types.Type
+ Base.Types: instance Base.Types.IsType Base.Types.TypeScheme
+ Base.Types: instance GHC.Classes.Eq Base.Types.ClassMethod
+ Base.Types: instance GHC.Classes.Eq Base.Types.DataConstr
+ Base.Types: instance GHC.Classes.Eq Base.Types.ExistTypeScheme
+ Base.Types: instance GHC.Classes.Eq Base.Types.Pred
+ Base.Types: instance GHC.Classes.Eq Base.Types.PredType
+ Base.Types: instance GHC.Classes.Eq Base.Types.Type
+ Base.Types: instance GHC.Classes.Eq Base.Types.TypeScheme
+ Base.Types: instance GHC.Classes.Ord Base.Types.Pred
+ Base.Types: instance GHC.Classes.Ord Base.Types.Type
+ Base.Types: instance GHC.Show.Show Base.Types.ClassMethod
+ Base.Types: instance GHC.Show.Show Base.Types.DataConstr
+ Base.Types: instance GHC.Show.Show Base.Types.ExistTypeScheme
+ Base.Types: instance GHC.Show.Show Base.Types.Pred
+ Base.Types: instance GHC.Show.Show Base.Types.PredType
+ Base.Types: instance GHC.Show.Show Base.Types.Type
+ Base.Types: instance GHC.Show.Show Base.Types.TypeScheme
+ Base.Types: intType :: Type
+ Base.Types: ioType :: Type -> Type
+ Base.Types: isArrowType :: Type -> Bool
+ Base.Types: listType :: Type -> Type
+ Base.Types: maxPredSet :: ClassEnv -> PredSet -> PredSet
+ Base.Types: methodArity :: ClassMethod -> Maybe Int
+ Base.Types: methodName :: ClassMethod -> Ident
+ Base.Types: methodType :: ClassMethod -> PredType
+ Base.Types: minPredSet :: ClassEnv -> PredSet -> PredSet
+ Base.Types: monoType :: Type -> TypeScheme
+ Base.Types: numTypes :: [Type]
+ Base.Types: partitionPredSet :: PredSet -> (PredSet, PredSet)
+ Base.Types: polyType :: Type -> TypeScheme
+ Base.Types: predBoolType :: PredType
+ Base.Types: predFloatType :: PredType
+ Base.Types: predIntType :: PredType
+ Base.Types: predStringType :: PredType
+ Base.Types: predType :: Type -> PredType
+ Base.Types: predUnitType :: PredType
+ Base.Types: predefTypes :: [(Type, [DataConstr])]
+ Base.Types: qualifyPred :: ModuleIdent -> Pred -> Pred
+ Base.Types: qualifyPredSet :: ModuleIdent -> PredSet -> PredSet
+ Base.Types: qualifyPredType :: ModuleIdent -> PredType -> PredType
+ Base.Types: qualifyTC :: ModuleIdent -> QualIdent -> QualIdent
+ Base.Types: qualifyType :: ModuleIdent -> Type -> Type
+ Base.Types: rawType :: TypeScheme -> Type
+ Base.Types: recLabelTypes :: DataConstr -> [Type]
+ Base.Types: recLabels :: DataConstr -> [Ident]
+ Base.Types: rootOfType :: Type -> QualIdent
+ Base.Types: stringType :: Type
+ Base.Types: tupleData :: [DataConstr]
+ Base.Types: tupleType :: [Type] -> Type
+ Base.Types: type PredSet = Set Pred
+ Base.Types: typeConstrs :: Type -> [QualIdent]
+ Base.Types: typeScheme :: PredType -> TypeScheme
+ Base.Types: typeSkolems :: IsType t => t -> [Int]
+ Base.Types: typeVars :: IsType t => t -> [Int]
+ Base.Types: unapplyType :: Bool -> Type -> (Type, [Type])
+ Base.Types: unitType :: Type
+ Base.Types: unpredType :: PredType -> Type
+ Base.Types: unqualifyPred :: ModuleIdent -> Pred -> Pred
+ Base.Types: unqualifyPredSet :: ModuleIdent -> PredSet -> PredSet
+ Base.Types: unqualifyPredType :: ModuleIdent -> PredType -> PredType
+ Base.Types: unqualifyType :: ModuleIdent -> Type -> Type
+ Base.Typing: bindDecl :: (Eq t, Typeable t, ValueType t) => Decl t -> ValueEnv -> ValueEnv
+ Base.Typing: bindDecls :: (Eq t, Typeable t, ValueType t) => [Decl t] -> ValueEnv -> ValueEnv
+ Base.Typing: bindPattern :: (Eq t, Typeable t, ValueType t) => Pattern t -> ValueEnv -> ValueEnv
+ Base.Typing: bindPatterns :: (Eq t, Typeable t, ValueType t) => [Pattern t] -> ValueEnv -> ValueEnv
+ Base.Typing: class Typeable a
+ Base.Typing: declVars :: (Eq t, Typeable t, ValueType t) => Decl t -> [(Ident, Int, t)]
+ Base.Typing: instance Base.Typing.Typeable Base.Types.PredType
+ Base.Typing: instance Base.Typing.Typeable Base.Types.Type
+ Base.Typing: instance Base.Typing.Typeable a => Base.Typing.Typeable (Curry.Syntax.Type.Alt a)
+ Base.Typing: instance Base.Typing.Typeable a => Base.Typing.Typeable (Curry.Syntax.Type.Expression a)
+ Base.Typing: instance Base.Typing.Typeable a => Base.Typing.Typeable (Curry.Syntax.Type.Pattern a)
+ Base.Typing: instance Base.Typing.Typeable a => Base.Typing.Typeable (Curry.Syntax.Type.Rhs a)
+ Base.Typing: matchType :: Type -> Type -> TypeSubst -> TypeSubst
+ Base.Typing: patternVars :: (Eq t, Typeable t, ValueType t) => Pattern t -> [(Ident, Int, t)]
+ Base.Typing: typeOf :: Typeable a => a -> Type
+ Base.Typing: withType :: (Functor f, Typeable (f Type)) => Type -> f Type -> f Type
+ Base.Utils: (++!) :: [a] -> [a] -> [a]
+ Base.Utils: curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d
+ Base.Utils: findDouble :: Eq a => [a] -> Maybe a
+ Base.Utils: findMultiples :: Eq a => [a] -> [[a]]
+ Base.Utils: foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c
+ Base.Utils: fst3 :: (a, b, c) -> a
+ Base.Utils: infixr 5 ++!
+ Base.Utils: mapAccumM :: (Monad m, MonadPlus p) => (acc -> x -> m (acc, y)) -> acc -> [x] -> m (acc, p y)
+ Base.Utils: snd3 :: (a, b, c) -> b
+ Base.Utils: thd3 :: (a, b, c) -> c
+ Base.Utils: uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
+ Checks: deriveCheck :: Monad m => Check m (Module a)
+ Checks: expandExports :: Monad m => Options -> CompEnv (Module a) -> m (CompEnv (Module a))
+ Checks: exportCheck :: Monad m => Check m (Module a)
+ Checks: extensionCheck :: Monad m => Check m (Module a)
+ Checks: importCheck :: Monad m => Interface -> Maybe ImportSpec -> CYT m (Maybe ImportSpec)
+ Checks: instanceCheck :: Monad m => Check m (Module a)
+ Checks: interfaceCheck :: Monad m => Check m Interface
+ Checks: kindCheck :: Monad m => Check m (Module a)
+ Checks: precCheck :: Monad m => Check m (Module a)
+ Checks: syntaxCheck :: Monad m => Check m (Module ())
+ Checks: type Check m a = Options -> CompEnv a -> CYT m (CompEnv a)
+ Checks: typeCheck :: Monad m => Options -> CompEnv (Module a) -> CYT m (CompEnv (Module PredType))
+ Checks: typeSyntaxCheck :: Monad m => Check m (Module a)
+ Checks: warnCheck :: Options -> CompilerEnv -> Module a -> [Message]
+ Checks.DeriveCheck: deriveCheck :: TCEnv -> Module a -> [Message]
+ Checks.ExportCheck: expandExports :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec -> ExportSpec
+ Checks.ExportCheck: exportCheck :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec -> [Message]
+ Checks.ExtensionCheck: extensionCheck :: Options -> Module a -> ([KnownExtension], [Message])
+ Checks.ImportSyntaxCheck: importCheck :: Interface -> Maybe ImportSpec -> (Maybe ImportSpec, [Message])
+ Checks.ImportSyntaxCheck: instance Base.TopEnv.Entity Checks.ImportSyntaxCheck.ITypeInfo
+ Checks.ImportSyntaxCheck: instance Base.TopEnv.Entity Checks.ImportSyntaxCheck.IValueInfo
+ Checks.ImportSyntaxCheck: instance GHC.Show.Show Checks.ImportSyntaxCheck.ITypeInfo
+ Checks.ImportSyntaxCheck: instance GHC.Show.Show Checks.ImportSyntaxCheck.IValueInfo
+ Checks.InstanceCheck: instance GHC.Classes.Eq Checks.InstanceCheck.InstSource
+ Checks.InstanceCheck: instanceCheck :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Decl a] -> (InstEnv, [Message])
+ Checks.InterfaceCheck: interfaceCheck :: OpPrecEnv -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv -> Interface -> [Message]
+ Checks.InterfaceSyntaxCheck: intfSyntaxCheck :: Interface -> (Interface, [Message])
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.Alt a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.CondExpr a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.Decl a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.Equation a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.Expression a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.Rhs a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType (Curry.Syntax.Type.Statement a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Base.Ident.QualIdent
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Syntax.Type.ConstrDecl
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Syntax.Type.Constraint
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Syntax.Type.FieldDecl
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Syntax.Type.NewConstrDecl
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Syntax.Type.QualTypeExpr
+ Checks.KindCheck: instance Checks.KindCheck.HasType Curry.Syntax.Type.TypeExpr
+ Checks.KindCheck: instance Checks.KindCheck.HasType a => Checks.KindCheck.HasType (Curry.Syntax.Type.Field a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType a => Checks.KindCheck.HasType (GHC.Base.Maybe a)
+ Checks.KindCheck: instance Checks.KindCheck.HasType a => Checks.KindCheck.HasType [a]
+ Checks.KindCheck: kindCheck :: TCEnv -> ClassEnv -> Module a -> ((TCEnv, ClassEnv), [Message])
+ Checks.PrecCheck: precCheck :: ModuleIdent -> OpPrecEnv -> [Decl a] -> ([Decl a], OpPrecEnv, [Message])
+ Checks.SyntaxCheck: instance GHC.Classes.Eq Checks.SyntaxCheck.RenameInfo
+ Checks.SyntaxCheck: instance GHC.Show.Show Checks.SyntaxCheck.RenameInfo
+ Checks.SyntaxCheck: syntaxCheck :: [KnownExtension] -> TCEnv -> ValueEnv -> Module () -> ((Module (), [KnownExtension]), [Message])
+ Checks.TypeCheck: instance Checks.TypeCheck.Binding (Curry.Syntax.Type.Decl a)
+ Checks.TypeCheck: instance Checks.TypeCheck.Binding (Curry.Syntax.Type.Expression a)
+ Checks.TypeCheck: instance Checks.TypeCheck.Binding (Curry.Syntax.Type.Rhs a)
+ Checks.TypeCheck: instance Checks.TypeCheck.Binding a => Checks.TypeCheck.Binding (Curry.Syntax.Type.Field a)
+ Checks.TypeCheck: instance Checks.TypeCheck.Binding a => Checks.TypeCheck.Binding [a]
+ Checks.TypeCheck: typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> ClassEnv -> InstEnv -> [Decl a] -> ([Decl PredType], ValueEnv, [Message])
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Alt a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.CondExpr a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Decl a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Equation a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Expression a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Rhs a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Statement a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Base.Ident.Ident
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Syntax.Type.ConstrDecl
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Syntax.Type.Constraint
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Syntax.Type.FieldDecl
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Syntax.Type.NewConstrDecl
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Syntax.Type.QualTypeExpr
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename Curry.Syntax.Type.TypeExpr
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename a => Checks.TypeSyntaxCheck.Rename (Curry.Syntax.Type.Field a)
+ Checks.TypeSyntaxCheck: instance Checks.TypeSyntaxCheck.Rename a => Checks.TypeSyntaxCheck.Rename [a]
+ Checks.TypeSyntaxCheck: typeSyntaxCheck :: [KnownExtension] -> TCEnv -> Module a -> ((Module a, [KnownExtension]), [Message])
+ Checks.WarnCheck: instance GHC.Show.Show Checks.WarnCheck.IdInfo
+ Checks.WarnCheck: warnCheck :: WarnOpts -> CaseMode -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv -> Module a -> [Message]
+ CompilerEnv: CompilerEnv :: ModuleIdent -> FilePath -> [KnownExtension] -> [(Span, Token)] -> InterfaceEnv -> AliasEnv -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv -> OpPrecEnv -> CompilerEnv
+ CompilerEnv: [aliasEnv] :: CompilerEnv -> AliasEnv
+ CompilerEnv: [classEnv] :: CompilerEnv -> ClassEnv
+ CompilerEnv: [extensions] :: CompilerEnv -> [KnownExtension]
+ CompilerEnv: [filePath] :: CompilerEnv -> FilePath
+ CompilerEnv: [instEnv] :: CompilerEnv -> InstEnv
+ CompilerEnv: [interfaceEnv] :: CompilerEnv -> InterfaceEnv
+ CompilerEnv: [moduleIdent] :: CompilerEnv -> ModuleIdent
+ CompilerEnv: [opPrecEnv] :: CompilerEnv -> OpPrecEnv
+ CompilerEnv: [tokens] :: CompilerEnv -> [(Span, Token)]
+ CompilerEnv: [tyConsEnv] :: CompilerEnv -> TCEnv
+ CompilerEnv: [valueEnv] :: CompilerEnv -> ValueEnv
+ CompilerEnv: data CompilerEnv
+ CompilerEnv: initCompilerEnv :: ModuleIdent -> CompilerEnv
+ CompilerEnv: ppAL :: (Show a, Pretty a, Show b, Pretty b) => Bool -> [(a, b)] -> Doc
+ CompilerEnv: ppALPretty :: (Pretty a, Pretty b) => [(a, b)] -> Doc
+ CompilerEnv: ppALShow :: (Show a, Show b) => [(a, b)] -> Doc
+ CompilerEnv: ppMap :: (Show a, Pretty a, Show b, Pretty b) => Bool -> Map a b -> Doc
+ CompilerEnv: ppMapPretty :: (Pretty a, Pretty b) => Map a b -> Doc
+ CompilerEnv: ppMapShow :: (Show a, Show b) => Map a b -> Doc
+ CompilerEnv: showCompilerEnv :: CompilerEnv -> Bool -> Bool -> String
+ CompilerEnv: type CompEnv a = (CompilerEnv, a)
+ CompilerOpts: AbstractCurry :: TargetType
+ CompilerOpts: AnonFreeVars :: KnownExtension
+ CompilerOpts: CPP :: KnownExtension
+ CompilerOpts: CaseModeFree :: CaseMode
+ CompilerOpts: CaseModeGoedel :: CaseMode
+ CompilerOpts: CaseModeHaskell :: CaseMode
+ CompilerOpts: CaseModeProlog :: CaseMode
+ CompilerOpts: CppOpts :: Bool -> Map String Int -> CppOpts
+ CompilerOpts: DebugOpts :: [DumpLevel] -> Bool -> Bool -> Bool -> Bool -> DebugOpts
+ CompilerOpts: DumpCaseCompleted :: DumpLevel
+ CompilerOpts: DumpCondCompiled :: DumpLevel
+ CompilerOpts: DumpDeriveChecked :: DumpLevel
+ CompilerOpts: DumpDerived :: DumpLevel
+ CompilerOpts: DumpDesugared :: DumpLevel
+ CompilerOpts: DumpDictionaries :: DumpLevel
+ CompilerOpts: DumpExportChecked :: DumpLevel
+ CompilerOpts: DumpExtensionChecked :: DumpLevel
+ CompilerOpts: DumpFlatCurry :: DumpLevel
+ CompilerOpts: DumpInstanceChecked :: DumpLevel
+ CompilerOpts: DumpKindChecked :: DumpLevel
+ CompilerOpts: DumpLifted :: DumpLevel
+ CompilerOpts: DumpNewtypes :: DumpLevel
+ CompilerOpts: DumpParsed :: DumpLevel
+ CompilerOpts: DumpPrecChecked :: DumpLevel
+ CompilerOpts: DumpQualified :: DumpLevel
+ CompilerOpts: DumpSimplified :: DumpLevel
+ CompilerOpts: DumpSyntaxChecked :: DumpLevel
+ CompilerOpts: DumpTranslated :: DumpLevel
+ CompilerOpts: DumpTypeChecked :: DumpLevel
+ CompilerOpts: DumpTypeSyntaxChecked :: DumpLevel
+ CompilerOpts: DumpTypedFlatCurry :: DumpLevel
+ CompilerOpts: ExistentialQuantification :: KnownExtension
+ CompilerOpts: FlatCurry :: TargetType
+ CompilerOpts: FunctionalPatterns :: KnownExtension
+ CompilerOpts: Html :: TargetType
+ CompilerOpts: ModeHelp :: CymakeMode
+ CompilerOpts: ModeMake :: CymakeMode
+ CompilerOpts: ModeNumericVersion :: CymakeMode
+ CompilerOpts: ModeVersion :: CymakeMode
+ CompilerOpts: NegativeLiterals :: KnownExtension
+ CompilerOpts: NoImplicitPrelude :: KnownExtension
+ CompilerOpts: Options :: CymakeMode -> Verbosity -> Bool -> [FilePath] -> [FilePath] -> Maybe FilePath -> Bool -> Bool -> PrepOpts -> WarnOpts -> [TargetType] -> [KnownExtension] -> DebugOpts -> CaseMode -> CppOpts -> Options
+ CompilerOpts: Parsed :: TargetType
+ CompilerOpts: PrepOpts :: Bool -> String -> [String] -> PrepOpts
+ CompilerOpts: Tokens :: TargetType
+ CompilerOpts: TypedFlatCurry :: TargetType
+ CompilerOpts: UntypedAbstractCurry :: TargetType
+ CompilerOpts: VerbQuiet :: Verbosity
+ CompilerOpts: VerbStatus :: Verbosity
+ CompilerOpts: WarnDisjoinedRules :: WarnFlag
+ CompilerOpts: WarnIncompletePatterns :: WarnFlag
+ CompilerOpts: WarnIrregularCaseMode :: WarnFlag
+ CompilerOpts: WarnMissingMethods :: WarnFlag
+ CompilerOpts: WarnMissingSignatures :: WarnFlag
+ CompilerOpts: WarnMultipleImports :: WarnFlag
+ CompilerOpts: WarnNameShadowing :: WarnFlag
+ CompilerOpts: WarnOpts :: Bool -> [WarnFlag] -> Bool -> WarnOpts
+ CompilerOpts: WarnOrphanInstances :: WarnFlag
+ CompilerOpts: WarnOverlapping :: WarnFlag
+ CompilerOpts: WarnUnusedBindings :: WarnFlag
+ CompilerOpts: WarnUnusedGlobalBindings :: WarnFlag
+ CompilerOpts: [cppDefinitions] :: CppOpts -> Map String Int
+ CompilerOpts: [cppRun] :: CppOpts -> Bool
+ CompilerOpts: [dbDumpAllBindings] :: DebugOpts -> Bool
+ CompilerOpts: [dbDumpEnv] :: DebugOpts -> Bool
+ CompilerOpts: [dbDumpLevels] :: DebugOpts -> [DumpLevel]
+ CompilerOpts: [dbDumpRaw] :: DebugOpts -> Bool
+ CompilerOpts: [dbDumpSimple] :: DebugOpts -> Bool
+ CompilerOpts: [optCaseMode] :: Options -> CaseMode
+ CompilerOpts: [optCppOpts] :: Options -> CppOpts
+ CompilerOpts: [optDebugOpts] :: Options -> DebugOpts
+ CompilerOpts: [optExtensions] :: Options -> [KnownExtension]
+ CompilerOpts: [optForce] :: Options -> Bool
+ CompilerOpts: [optHtmlDir] :: Options -> Maybe FilePath
+ CompilerOpts: [optImportPaths] :: Options -> [FilePath]
+ CompilerOpts: [optInterface] :: Options -> Bool
+ CompilerOpts: [optLibraryPaths] :: Options -> [FilePath]
+ CompilerOpts: [optMode] :: Options -> CymakeMode
+ CompilerOpts: [optPrepOpts] :: Options -> PrepOpts
+ CompilerOpts: [optTargetTypes] :: Options -> [TargetType]
+ CompilerOpts: [optUseSubdir] :: Options -> Bool
+ CompilerOpts: [optVerbosity] :: Options -> Verbosity
+ CompilerOpts: [optWarnOpts] :: Options -> WarnOpts
+ CompilerOpts: [ppCmd] :: PrepOpts -> String
+ CompilerOpts: [ppOpts] :: PrepOpts -> [String]
+ CompilerOpts: [ppPreprocess] :: PrepOpts -> Bool
+ CompilerOpts: [wnWarnAsError] :: WarnOpts -> Bool
+ CompilerOpts: [wnWarnFlags] :: WarnOpts -> [WarnFlag]
+ CompilerOpts: [wnWarn] :: WarnOpts -> Bool
+ CompilerOpts: data CaseMode
+ CompilerOpts: data CppOpts
+ CompilerOpts: data CymakeMode
+ CompilerOpts: data DebugOpts
+ CompilerOpts: data DumpLevel
+ CompilerOpts: data KnownExtension :: *
+ CompilerOpts: data Options
+ CompilerOpts: data PrepOpts
+ CompilerOpts: data TargetType
+ CompilerOpts: data Verbosity
+ CompilerOpts: data WarnFlag
+ CompilerOpts: data WarnOpts
+ CompilerOpts: defaultDebugOpts :: DebugOpts
+ CompilerOpts: defaultOptions :: Options
+ CompilerOpts: defaultPrepOpts :: PrepOpts
+ CompilerOpts: defaultWarnOpts :: WarnOpts
+ CompilerOpts: dumpLevel :: [(DumpLevel, String, String)]
+ CompilerOpts: getCompilerOpts :: IO (String, Options, [String], [String])
+ CompilerOpts: instance GHC.Classes.Eq CompilerOpts.CaseMode
+ CompilerOpts: instance GHC.Classes.Eq CompilerOpts.CymakeMode
+ CompilerOpts: instance GHC.Classes.Eq CompilerOpts.DumpLevel
+ CompilerOpts: instance GHC.Classes.Eq CompilerOpts.TargetType
+ CompilerOpts: instance GHC.Classes.Eq CompilerOpts.Verbosity
+ CompilerOpts: instance GHC.Classes.Eq CompilerOpts.WarnFlag
+ CompilerOpts: instance GHC.Classes.Ord CompilerOpts.Verbosity
+ CompilerOpts: instance GHC.Enum.Bounded CompilerOpts.DumpLevel
+ CompilerOpts: instance GHC.Enum.Bounded CompilerOpts.WarnFlag
+ CompilerOpts: instance GHC.Enum.Enum CompilerOpts.DumpLevel
+ CompilerOpts: instance GHC.Enum.Enum CompilerOpts.WarnFlag
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.CaseMode
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.CppOpts
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.CymakeMode
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.DebugOpts
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.DumpLevel
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.Options
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.PrepOpts
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.TargetType
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.Verbosity
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.WarnFlag
+ CompilerOpts: instance GHC.Show.Show CompilerOpts.WarnOpts
+ CompilerOpts: updateOpts :: Options -> [String] -> (Options, [String], [String])
+ CompilerOpts: usage :: String -> String
+ CondCompile: condCompile :: CppOpts -> FilePath -> String -> CYIO String
+ CurryBuilder: buildCurry :: Options -> String -> CYIO ()
+ CurryBuilder: findCurry :: Options -> String -> CYIO FilePath
+ CurryDeps: Interface :: FilePath -> Source
+ CurryDeps: Source :: FilePath -> [ModulePragma] -> [ModuleIdent] -> Source
+ CurryDeps: Unknown :: Source
+ CurryDeps: data Source
+ CurryDeps: deps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv
+ CurryDeps: flatDeps :: Options -> FilePath -> CYIO [(ModuleIdent, Source)]
+ CurryDeps: flattenDeps :: SourceEnv -> ([(ModuleIdent, Source)], [Message])
+ CurryDeps: instance GHC.Classes.Eq CurryDeps.Source
+ CurryDeps: instance GHC.Show.Show CurryDeps.Source
+ CurryDeps: moduleDeps :: Options -> SourceEnv -> FilePath -> Module a -> CYIO SourceEnv
+ CurryDeps: sourceDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv
+ Env.Class: allSuperClasses :: QualIdent -> ClassEnv -> [QualIdent]
+ Env.Class: bindClassInfo :: QualIdent -> ClassInfo -> ClassEnv -> ClassEnv
+ Env.Class: classMethods :: QualIdent -> ClassEnv -> [Ident]
+ Env.Class: hasDefaultImpl :: QualIdent -> Ident -> ClassEnv -> Bool
+ Env.Class: initClassEnv :: ClassEnv
+ Env.Class: lookupClassInfo :: QualIdent -> ClassEnv -> Maybe ClassInfo
+ Env.Class: mergeClassInfo :: ClassInfo -> ClassInfo -> ClassInfo
+ Env.Class: superClasses :: QualIdent -> ClassEnv -> [QualIdent]
+ Env.Class: type ClassEnv = Map QualIdent ClassInfo
+ Env.Class: type ClassInfo = ([QualIdent], [(Ident, Bool)])
+ Env.Instance: bindInstInfo :: InstIdent -> InstInfo -> InstEnv -> InstEnv
+ Env.Instance: initInstEnv :: InstEnv
+ Env.Instance: lookupInstInfo :: InstIdent -> InstEnv -> Maybe InstInfo
+ Env.Instance: ppInstIdent :: InstIdent -> Doc
+ Env.Instance: type InstEnv = Map InstIdent InstInfo
+ Env.Instance: type InstIdent = (QualIdent, QualIdent)
+ Env.Instance: type InstInfo = (ModuleIdent, PredSet, [(Ident, Int)])
+ Env.Interface: initInterfaceEnv :: InterfaceEnv
+ Env.Interface: lookupInterface :: ModuleIdent -> InterfaceEnv -> Maybe Interface
+ Env.Interface: type InterfaceEnv = Map ModuleIdent Interface
+ Env.ModuleAlias: importAliases :: [ImportDecl] -> AliasEnv
+ Env.ModuleAlias: initAliasEnv :: AliasEnv
+ Env.ModuleAlias: type AliasEnv = Map ModuleIdent ModuleIdent
+ Env.OpPrec: OpPrec :: Infix -> Precedence -> OpPrec
+ Env.OpPrec: PrecInfo :: QualIdent -> OpPrec -> PrecInfo
+ Env.OpPrec: bindP :: ModuleIdent -> Ident -> OpPrec -> OpPrecEnv -> OpPrecEnv
+ Env.OpPrec: data OpPrec
+ Env.OpPrec: data PrecInfo
+ Env.OpPrec: defaultAssoc :: Infix
+ Env.OpPrec: defaultP :: OpPrec
+ Env.OpPrec: defaultPrecedence :: Precedence
+ Env.OpPrec: initOpPrecEnv :: OpPrecEnv
+ Env.OpPrec: instance Base.TopEnv.Entity Env.OpPrec.PrecInfo
+ Env.OpPrec: instance Curry.Base.Pretty.Pretty Env.OpPrec.OpPrec
+ Env.OpPrec: instance Curry.Base.Pretty.Pretty Env.OpPrec.PrecInfo
+ Env.OpPrec: instance GHC.Classes.Eq Env.OpPrec.OpPrec
+ Env.OpPrec: instance GHC.Classes.Eq Env.OpPrec.PrecInfo
+ Env.OpPrec: instance GHC.Show.Show Env.OpPrec.OpPrec
+ Env.OpPrec: instance GHC.Show.Show Env.OpPrec.PrecInfo
+ Env.OpPrec: lookupP :: Ident -> OpPrecEnv -> [PrecInfo]
+ Env.OpPrec: mkPrec :: Maybe Precedence -> Precedence
+ Env.OpPrec: qualLookupP :: QualIdent -> OpPrecEnv -> [PrecInfo]
+ Env.OpPrec: type OpPrecEnv = TopEnv PrecInfo
+ Env.Type: Alias :: QualIdent -> TypeKind
+ Env.Type: Class :: QualIdent -> [Ident] -> TypeKind
+ Env.Type: Data :: QualIdent -> [Ident] -> TypeKind
+ Env.Type: bindTypeKind :: ModuleIdent -> Ident -> TypeKind -> TypeEnv -> TypeEnv
+ Env.Type: data TypeKind
+ Env.Type: instance Base.TopEnv.Entity Env.Type.TypeKind
+ Env.Type: instance GHC.Classes.Eq Env.Type.TypeKind
+ Env.Type: instance GHC.Show.Show Env.Type.TypeKind
+ Env.Type: lookupTypeKind :: Ident -> TypeEnv -> [TypeKind]
+ Env.Type: qualLookupTypeKind :: QualIdent -> TypeEnv -> [TypeKind]
+ Env.Type: toTypeKind :: TypeInfo -> TypeKind
+ Env.Type: type TypeEnv = TopEnv TypeKind
+ Env.TypeConstructor: AliasType :: QualIdent -> Kind -> Int -> Type -> TypeInfo
+ Env.TypeConstructor: DataType :: QualIdent -> Kind -> [DataConstr] -> TypeInfo
+ Env.TypeConstructor: RenamingType :: QualIdent -> Kind -> DataConstr -> TypeInfo
+ Env.TypeConstructor: TypeClass :: QualIdent -> Kind -> [ClassMethod] -> TypeInfo
+ Env.TypeConstructor: TypeVar :: Kind -> TypeInfo
+ Env.TypeConstructor: bindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv
+ Env.TypeConstructor: clsKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind
+ Env.TypeConstructor: clsMethods :: ModuleIdent -> QualIdent -> TCEnv -> [Ident]
+ Env.TypeConstructor: data TypeInfo
+ Env.TypeConstructor: getOrigName :: ModuleIdent -> QualIdent -> TCEnv -> QualIdent
+ Env.TypeConstructor: initTCEnv :: TCEnv
+ Env.TypeConstructor: instance Base.TopEnv.Entity Env.TypeConstructor.TypeInfo
+ Env.TypeConstructor: instance Curry.Base.Pretty.Pretty Env.TypeConstructor.TypeInfo
+ Env.TypeConstructor: instance GHC.Show.Show Env.TypeConstructor.TypeInfo
+ Env.TypeConstructor: lookupTypeInfo :: Ident -> TCEnv -> [TypeInfo]
+ Env.TypeConstructor: qualLookupTypeInfo :: QualIdent -> TCEnv -> [TypeInfo]
+ Env.TypeConstructor: qualLookupTypeInfoUnique :: ModuleIdent -> QualIdent -> TCEnv -> [TypeInfo]
+ Env.TypeConstructor: rebindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv
+ Env.TypeConstructor: reverseLookupByOrigName :: QualIdent -> TCEnv -> [QualIdent]
+ Env.TypeConstructor: tcKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind
+ Env.TypeConstructor: type TCEnv = TopEnv TypeInfo
+ Env.TypeConstructor: varKind :: Ident -> TCEnv -> Kind
+ Env.Value: DataConstructor :: QualIdent -> Int -> [Ident] -> ExistTypeScheme -> ValueInfo
+ Env.Value: Label :: QualIdent -> [QualIdent] -> TypeScheme -> ValueInfo
+ Env.Value: NewtypeConstructor :: QualIdent -> Ident -> ExistTypeScheme -> ValueInfo
+ Env.Value: Value :: QualIdent -> Bool -> Int -> TypeScheme -> ValueInfo
+ Env.Value: bindFun :: ModuleIdent -> Ident -> Bool -> Int -> TypeScheme -> ValueEnv -> ValueEnv
+ Env.Value: bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a -> ValueEnv -> ValueEnv
+ Env.Value: bindLocalVar :: ValueType t => (Ident, Int, t) -> ValueEnv -> ValueEnv
+ Env.Value: bindLocalVars :: ValueType t => [(Ident, Int, t)] -> ValueEnv -> ValueEnv
+ Env.Value: class ValueType t
+ Env.Value: data ValueInfo
+ Env.Value: fromValueType :: ValueType t => t -> PredType
+ Env.Value: initDCEnv :: ValueEnv
+ Env.Value: instance Base.TopEnv.Entity Env.Value.ValueInfo
+ Env.Value: instance Curry.Base.Pretty.Pretty Env.Value.ValueInfo
+ Env.Value: instance Env.Value.ValueType Base.Types.PredType
+ Env.Value: instance Env.Value.ValueType Base.Types.Type
+ Env.Value: instance GHC.Show.Show Env.Value.ValueInfo
+ Env.Value: lookupValue :: Ident -> ValueEnv -> [ValueInfo]
+ Env.Value: qualBindFun :: ModuleIdent -> Ident -> Bool -> Int -> TypeScheme -> ValueEnv -> ValueEnv
+ Env.Value: qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]
+ Env.Value: qualLookupValueUnique :: ModuleIdent -> QualIdent -> ValueEnv -> [ValueInfo]
+ Env.Value: rebindFun :: ModuleIdent -> Ident -> Bool -> Int -> TypeScheme -> ValueEnv -> ValueEnv
+ Env.Value: toValueType :: ValueType t => Type -> t
+ Env.Value: type ValueEnv = TopEnv ValueInfo
+ Env.Value: unbindFun :: Ident -> ValueEnv -> ValueEnv
+ Exports: exportInterface :: CompilerEnv -> Module a -> Interface
+ Exports: instance Exports.HasModule Curry.Base.Ident.ModuleIdent
+ Exports: instance Exports.HasModule Curry.Base.Ident.QualIdent
+ Exports: instance Exports.HasModule Curry.Syntax.Type.ConstrDecl
+ Exports: instance Exports.HasModule Curry.Syntax.Type.Constraint
+ Exports: instance Exports.HasModule Curry.Syntax.Type.FieldDecl
+ Exports: instance Exports.HasModule Curry.Syntax.Type.IDecl
+ Exports: instance Exports.HasModule Curry.Syntax.Type.IMethodDecl
+ Exports: instance Exports.HasModule Curry.Syntax.Type.NewConstrDecl
+ Exports: instance Exports.HasModule Curry.Syntax.Type.QualTypeExpr
+ Exports: instance Exports.HasModule Curry.Syntax.Type.TypeExpr
+ Exports: instance Exports.HasModule a => Exports.HasModule (GHC.Base.Maybe a)
+ Exports: instance Exports.HasModule a => Exports.HasModule [a]
+ Exports: instance Exports.HasType Curry.Syntax.Type.ConstrDecl
+ Exports: instance Exports.HasType Curry.Syntax.Type.Constraint
+ Exports: instance Exports.HasType Curry.Syntax.Type.FieldDecl
+ Exports: instance Exports.HasType Curry.Syntax.Type.IDecl
+ Exports: instance Exports.HasType Curry.Syntax.Type.IMethodDecl
+ Exports: instance Exports.HasType Curry.Syntax.Type.NewConstrDecl
+ Exports: instance Exports.HasType Curry.Syntax.Type.QualTypeExpr
+ Exports: instance Exports.HasType Curry.Syntax.Type.TypeExpr
+ Exports: instance Exports.HasType a => Exports.HasType (GHC.Base.Maybe a)
+ Exports: instance Exports.HasType a => Exports.HasType [a]
+ Exports: instance GHC.Classes.Eq Exports.IInfo
+ Exports: instance GHC.Classes.Ord Exports.IInfo
+ Files.CymakePath: cymakeGreeting :: String
+ Files.CymakePath: cymakeVersion :: String
+ Files.CymakePath: getCymake :: IO String
+ Generators: genFlatCurry :: AProg a -> Prog
+ Generators: genFlatInterface :: Prog -> Prog
+ Generators: genTypedAbstractCurry :: CompilerEnv -> Module PredType -> CurryProg
+ Generators: genTypedFlatCurry :: CompilerEnv -> Module Type -> Module -> AProg TypeExpr
+ Generators: genUntypedAbstractCurry :: CompilerEnv -> Module PredType -> CurryProg
+ Generators.GenAbstractCurry: genAbstractCurry :: Bool -> CompilerEnv -> Module PredType -> CurryProg
+ Generators.GenAbstractCurry: instance GHC.Show.Show Generators.GenAbstractCurry.AbstractEnv
+ Generators.GenFlatCurry: genFlatCurry :: AProg a -> Prog
+ Generators.GenFlatCurry: genFlatInterface :: Prog -> Prog
+ Generators.GenTypedFlatCurry: genTypedFlatCurry :: CompilerEnv -> Module Type -> Module -> AProg TypeExpr
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize Curry.FlatCurry.Type.TypeExpr
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize GHC.Types.Int
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize a => Generators.GenTypedFlatCurry.Normalize (Curry.FlatCurry.Annotated.Type.ABranchExpr a)
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize a => Generators.GenTypedFlatCurry.Normalize (Curry.FlatCurry.Annotated.Type.AExpr a)
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize a => Generators.GenTypedFlatCurry.Normalize (Curry.FlatCurry.Annotated.Type.AFuncDecl a)
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize a => Generators.GenTypedFlatCurry.Normalize (Curry.FlatCurry.Annotated.Type.APattern a)
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize a => Generators.GenTypedFlatCurry.Normalize (Curry.FlatCurry.Annotated.Type.ARule a)
+ Generators.GenTypedFlatCurry: instance Generators.GenTypedFlatCurry.Normalize b => Generators.GenTypedFlatCurry.Normalize (a, b)
+ Html.CurryHtml: source2html :: Options -> ModuleIdent -> [(Position, Token)] -> Module a -> CYIO ()
+ Html.SyntaxColoring: CharCode :: String -> Code
+ Html.SyntaxColoring: Commentary :: String -> Code
+ Html.SyntaxColoring: ConsCall :: ConsUsage
+ Html.SyntaxColoring: ConsDeclare :: ConsUsage
+ Html.SyntaxColoring: ConsExport :: ConsUsage
+ Html.SyntaxColoring: ConsImport :: ConsUsage
+ Html.SyntaxColoring: ConsInfix :: ConsUsage
+ Html.SyntaxColoring: ConsPattern :: ConsUsage
+ Html.SyntaxColoring: DataCons :: ConsUsage -> Bool -> QualIdent -> Code
+ Html.SyntaxColoring: FuncCall :: FuncUsage
+ Html.SyntaxColoring: FuncDeclare :: FuncUsage
+ Html.SyntaxColoring: FuncExport :: FuncUsage
+ Html.SyntaxColoring: FuncImport :: FuncUsage
+ Html.SyntaxColoring: FuncInfix :: FuncUsage
+ Html.SyntaxColoring: FuncTypeSig :: FuncUsage
+ Html.SyntaxColoring: Function :: FuncUsage -> Bool -> QualIdent -> Code
+ Html.SyntaxColoring: IdDeclare :: IdentUsage
+ Html.SyntaxColoring: IdRefer :: IdentUsage
+ Html.SyntaxColoring: IdUnknown :: IdentUsage
+ Html.SyntaxColoring: Identifier :: IdentUsage -> Bool -> QualIdent -> Code
+ Html.SyntaxColoring: Keyword :: String -> Code
+ Html.SyntaxColoring: ModuleName :: ModuleIdent -> Code
+ Html.SyntaxColoring: NewLine :: Code
+ Html.SyntaxColoring: NumberCode :: String -> Code
+ Html.SyntaxColoring: Pragma :: String -> Code
+ Html.SyntaxColoring: Space :: Int -> Code
+ Html.SyntaxColoring: StringCode :: String -> Code
+ Html.SyntaxColoring: Symbol :: String -> Code
+ Html.SyntaxColoring: TypeCons :: TypeUsage -> Bool -> QualIdent -> Code
+ Html.SyntaxColoring: TypeDeclare :: TypeUsage
+ Html.SyntaxColoring: TypeExport :: TypeUsage
+ Html.SyntaxColoring: TypeImport :: TypeUsage
+ Html.SyntaxColoring: TypeRefer :: TypeUsage
+ Html.SyntaxColoring: code2string :: Code -> String
+ Html.SyntaxColoring: data Code
+ Html.SyntaxColoring: data ConsUsage
+ Html.SyntaxColoring: data FuncUsage
+ Html.SyntaxColoring: data IdentUsage
+ Html.SyntaxColoring: data TypeUsage
+ Html.SyntaxColoring: genProgram :: Module a -> [(Position, Token)] -> [Code]
+ Html.SyntaxColoring: getQualIdent :: Code -> Maybe QualIdent
+ Html.SyntaxColoring: instance GHC.Show.Show Html.SyntaxColoring.Code
+ Html.SyntaxColoring: instance GHC.Show.Show Html.SyntaxColoring.ConsUsage
+ Html.SyntaxColoring: instance GHC.Show.Show Html.SyntaxColoring.FuncUsage
+ Html.SyntaxColoring: instance GHC.Show.Show Html.SyntaxColoring.IdentUsage
+ Html.SyntaxColoring: instance GHC.Show.Show Html.SyntaxColoring.TypeUsage
+ IL: ppModule :: Module -> Doc
+ IL: showModule :: Module -> String
+ IL.Pretty: ppModule :: Module -> Doc
+ IL.ShowModule: showModule :: Module -> String
+ IL.Type: Alt :: ConstrTerm -> Expression -> Alt
+ IL.Type: Apply :: Expression -> Expression -> Expression
+ IL.Type: Binding :: Ident -> Expression -> Binding
+ IL.Type: Case :: Eval -> Expression -> [Alt] -> Expression
+ IL.Type: Char :: Char -> Literal
+ IL.Type: ConstrDecl :: QualIdent -> [Type] -> ConstrDecl
+ IL.Type: Constructor :: Type -> QualIdent -> Int -> Expression
+ IL.Type: ConstructorPattern :: Type -> QualIdent -> [(Type, Ident)] -> ConstrTerm
+ IL.Type: DataDecl :: QualIdent -> Int -> [ConstrDecl] -> Decl
+ IL.Type: Exist :: Ident -> Expression -> Expression
+ IL.Type: ExternalDataDecl :: QualIdent -> Int -> Decl
+ IL.Type: ExternalDecl :: QualIdent -> Type -> Decl
+ IL.Type: Flex :: Eval
+ IL.Type: Float :: Double -> Literal
+ IL.Type: Function :: Type -> QualIdent -> Int -> Expression
+ IL.Type: FunctionDecl :: QualIdent -> [(Type, Ident)] -> Type -> Expression -> Decl
+ IL.Type: Int :: Integer -> Literal
+ IL.Type: Let :: Binding -> Expression -> Expression
+ IL.Type: Letrec :: [Binding] -> Expression -> Expression
+ IL.Type: Literal :: Type -> Literal -> Expression
+ IL.Type: LiteralPattern :: Type -> Literal -> ConstrTerm
+ IL.Type: Module :: ModuleIdent -> [ModuleIdent] -> [Decl] -> Module
+ IL.Type: Or :: Expression -> Expression -> Expression
+ IL.Type: Rigid :: Eval
+ IL.Type: TypeArrow :: Type -> Type -> Type
+ IL.Type: TypeConstructor :: QualIdent -> [Type] -> Type
+ IL.Type: TypeForall :: [Int] -> Type -> Type
+ IL.Type: TypeVariable :: Int -> Type
+ IL.Type: Typed :: Expression -> Type -> Expression
+ IL.Type: Variable :: Type -> Ident -> Expression
+ IL.Type: VariablePattern :: Type -> Ident -> ConstrTerm
+ IL.Type: data Alt
+ IL.Type: data Binding
+ IL.Type: data ConstrDecl
+ IL.Type: data ConstrTerm
+ IL.Type: data Decl
+ IL.Type: data Eval
+ IL.Type: data Expression
+ IL.Type: data Literal
+ IL.Type: data Module
+ IL.Type: data Type
+ IL.Type: instance Base.Expr.Expr IL.Type.Alt
+ IL.Type: instance Base.Expr.Expr IL.Type.Expression
+ IL.Type: instance GHC.Classes.Eq IL.Type.Alt
+ IL.Type: instance GHC.Classes.Eq IL.Type.Binding
+ IL.Type: instance GHC.Classes.Eq IL.Type.ConstrDecl
+ IL.Type: instance GHC.Classes.Eq IL.Type.ConstrTerm
+ IL.Type: instance GHC.Classes.Eq IL.Type.Decl
+ IL.Type: instance GHC.Classes.Eq IL.Type.Eval
+ IL.Type: instance GHC.Classes.Eq IL.Type.Expression
+ IL.Type: instance GHC.Classes.Eq IL.Type.Literal
+ IL.Type: instance GHC.Classes.Eq IL.Type.Module
+ IL.Type: instance GHC.Classes.Eq IL.Type.Type
+ IL.Type: instance GHC.Show.Show IL.Type.Alt
+ IL.Type: instance GHC.Show.Show IL.Type.Binding
+ IL.Type: instance GHC.Show.Show IL.Type.ConstrDecl
+ IL.Type: instance GHC.Show.Show IL.Type.ConstrTerm
+ IL.Type: instance GHC.Show.Show IL.Type.Decl
+ IL.Type: instance GHC.Show.Show IL.Type.Eval
+ IL.Type: instance GHC.Show.Show IL.Type.Expression
+ IL.Type: instance GHC.Show.Show IL.Type.Literal
+ IL.Type: instance GHC.Show.Show IL.Type.Module
+ IL.Type: instance GHC.Show.Show IL.Type.Type
+ IL.Typing: class Typeable a
+ IL.Typing: instance IL.Typing.Typeable IL.Type.Alt
+ IL.Typing: instance IL.Typing.Typeable IL.Type.ConstrTerm
+ IL.Typing: instance IL.Typing.Typeable IL.Type.Expression
+ IL.Typing: typeOf :: Typeable a => a -> Type
+ Imports: importInterfaces :: Interface -> InterfaceEnv -> CompilerEnv
+ Imports: importModules :: Monad m => Module a -> InterfaceEnv -> [ImportDecl] -> CYT m CompilerEnv
+ Imports: qualifyEnv :: CompilerEnv -> CompilerEnv
+ Interfaces: loadInterfaces :: [FilePath] -> Module a -> CYIO InterfaceEnv
+ Modules: checkModule :: Options -> CompEnv (Module ()) -> CYIO (CompEnv (Module PredType))
+ Modules: checkModuleHeader :: Monad m => Options -> ModuleIdent -> FilePath -> Module () -> CYT m (Module ())
+ Modules: compileModule :: Options -> ModuleIdent -> FilePath -> CYIO ()
+ Modules: loadAndCheckModule :: Options -> ModuleIdent -> FilePath -> CYIO (CompEnv (Module PredType))
+ Modules: loadModule :: Options -> ModuleIdent -> FilePath -> CYIO (CompEnv (Module ()))
+ Modules: parseModule :: Options -> ModuleIdent -> FilePath -> CYIO ([(Span, Token)], Module ())
+ TokenStream: showTokenStream :: [(Span, Token)] -> String
+ Transformations: completeCase :: CompEnv Module -> CompEnv Module
+ Transformations: derive :: CompEnv (Module PredType) -> CompEnv (Module PredType)
+ Transformations: desugar :: CompEnv (Module PredType) -> CompEnv (Module PredType)
+ Transformations: ilTrans :: CompEnv (Module Type) -> CompEnv Module
+ Transformations: insertDicts :: CompEnv (Module PredType) -> CompEnv (Module Type)
+ Transformations: lift :: CompEnv (Module Type) -> CompEnv (Module Type)
+ Transformations: qual :: CompEnv (Module a) -> CompEnv (Module a)
+ Transformations: removeNewtypes :: CompEnv (Module Type) -> CompEnv (Module Type)
+ Transformations: simplify :: CompEnv (Module Type) -> CompEnv (Module Type)
+ Transformations: transType :: Type -> Type
+ Transformations.CaseCompletion: completeCase :: InterfaceEnv -> Module -> Module
+ Transformations.CaseCompletion: instance Transformations.CaseCompletion.SubstType IL.Type.Type
+ Transformations.CaseCompletion: instance Transformations.CaseCompletion.SubstType a => Transformations.CaseCompletion.SubstType [a]
+ Transformations.CurryToIL: ilTrans :: ValueEnv -> Module Type -> Module
+ Transformations.CurryToIL: instance GHC.Show.Show Transformations.CurryToIL.NestedTerm
+ Transformations.CurryToIL: transType :: Type -> Type
+ Transformations.Derive: derive :: TCEnv -> ValueEnv -> InstEnv -> OpPrecEnv -> Module PredType -> Module PredType
+ Transformations.Desugar: desugar :: [KnownExtension] -> ValueEnv -> TCEnv -> Module PredType -> (Module PredType, ValueEnv)
+ Transformations.Dictionary: defaultMethodId :: QualIdent -> Ident -> Ident
+ Transformations.Dictionary: dictConstrId :: QualIdent -> Ident
+ Transformations.Dictionary: dictTypeId :: QualIdent -> Ident
+ Transformations.Dictionary: implMethodId :: QualIdent -> Type -> Ident -> Ident
+ Transformations.Dictionary: insertDicts :: InterfaceEnv -> TCEnv -> ValueEnv -> ClassEnv -> InstEnv -> OpPrecEnv -> Module PredType -> (Module Type, InterfaceEnv, TCEnv, ValueEnv, OpPrecEnv)
+ Transformations.Dictionary: instFunId :: QualIdent -> Type -> Ident
+ Transformations.Dictionary: instance Transformations.Dictionary.Augment Curry.Syntax.Type.Alt
+ Transformations.Dictionary: instance Transformations.Dictionary.Augment Curry.Syntax.Type.Expression
+ Transformations.Dictionary: instance Transformations.Dictionary.Augment Curry.Syntax.Type.Module
+ Transformations.Dictionary: instance Transformations.Dictionary.Augment Curry.Syntax.Type.Rhs
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Alt
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Decl
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Equation
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Expression
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Module
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Pattern
+ Transformations.Dictionary: instance Transformations.Dictionary.DictTrans Curry.Syntax.Type.Rhs
+ Transformations.Dictionary: instance Transformations.Dictionary.Specialize Curry.Syntax.Type.Alt
+ Transformations.Dictionary: instance Transformations.Dictionary.Specialize Curry.Syntax.Type.Decl
+ Transformations.Dictionary: instance Transformations.Dictionary.Specialize Curry.Syntax.Type.Equation
+ Transformations.Dictionary: instance Transformations.Dictionary.Specialize Curry.Syntax.Type.Expression
+ Transformations.Dictionary: instance Transformations.Dictionary.Specialize Curry.Syntax.Type.Module
+ Transformations.Dictionary: instance Transformations.Dictionary.Specialize Curry.Syntax.Type.Rhs
+ Transformations.Dictionary: qDefaultMethodId :: QualIdent -> Ident -> QualIdent
+ Transformations.Dictionary: qDictConstrId :: QualIdent -> QualIdent
+ Transformations.Dictionary: qDictTypeId :: QualIdent -> QualIdent
+ Transformations.Dictionary: qImplMethodId :: ModuleIdent -> QualIdent -> Type -> Ident -> QualIdent
+ Transformations.Dictionary: qInstFunId :: ModuleIdent -> QualIdent -> Type -> QualIdent
+ Transformations.Dictionary: qSuperDictStubId :: QualIdent -> QualIdent -> QualIdent
+ Transformations.Dictionary: superDictStubId :: QualIdent -> QualIdent -> Ident
+ Transformations.Lift: lift :: ValueEnv -> Module Type -> (Module Type, ValueEnv)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Alt a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Decl a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Equation a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Expression a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Lhs a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Module a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Pattern a)
+ Transformations.Newtypes: instance GHC.Show.Show a => Transformations.Newtypes.Newtypes (Curry.Syntax.Type.Rhs a)
+ Transformations.Newtypes: instance Transformations.Newtypes.Newtypes a => Transformations.Newtypes.Newtypes [a]
+ Transformations.Newtypes: removeNewtypes :: ValueEnv -> Module Type -> Module Type
+ Transformations.Qual: qual :: ModuleIdent -> TCEnv -> ValueEnv -> Module a -> Module a
+ Transformations.Simplify: simplify :: ValueEnv -> Module Type -> (Module Type, ValueEnv)

Files

+ CHANGELOG.md view
@@ -0,0 +1,296 @@+Change log for curry-frontend+=============================++Under development (1.0.1)+=============++  * Fixed bug with wrong order of super classes in selector functions+    generated by the dictionary transformation.+  * Changed desugaring of numeric literals. It now generates calls to the+    functions `Prelude.fromInt` and `Prelude.fromFloat`.+  * Fixed bug with wrong original names of imported record labels+  * Fixed bug when compiling type constructor classes with super classes+  * Adjusted warning message for potentially unreachable pattern matches++Version 1.0.0+=============++  * Added support for typeclasses as known from Haskell++Version 0.4.2+=============++  * Improved readability of environment information in dumps+    (option dump-simple)+  * Added option to dump all bindings instead of just local ones+    (dump-all-bindings)+  * Introduced annotated FlatCurry as a new output format+    (annotated-flat)++Version 0.4.1+=============++  * Added a simple cabal test suite+  * Split import of interfaces/modules and expansion and checking of+    import specifications into two modules.+  * Improved error messages generated by export check (fixes #1253)+  * Split checking and expansion of export specification into two+    subsequent steps (by Yannik Potdevin, fixes #1335)+  * Consider parenthesized type expressions in the Curry AST (by Katharina Rahf)+  * Added syntax extension `ExistentialQuantification` that allows the use+    of existentially quantified types in data and newtype constructors+  * Fixed bug that type declarations weren't syntax checked++Version 0.4.0+=============++  * Refactored AbstractCurry generation++  * Complete refactoring of FlatCurry generation++  * Removed support for Curry's record syntax and introduced Haskell's record+    syntax instead++  * During desugaring record updates are translated to fcase-expressions instead+    of introducing explicit update functions++  * HTML generation now places HTML files for hierarchical modules into+    files named `<Module>_curry.html`, i.e., no sub-folders reflecting+    the the module name hierarchy are generated. In addition, if the option+    `--html-dir` is not given, the current directory is used as the output+    directory.++  * Removed record type extensions++  * Enabled declaration of (mutually) recursive record types++  * Removed expansion of record types in type error messages++  * Replaced `MessageM` monad with `CYT` monads and moved `CYT` monads+    to package `curry-base`++  * Implemented warnings for overlapping module aliases - fixes #14++  * The check for overlapping rules has been completely refactored and+    improved to now also handle rigid case expressions.++  * The check for missing pattern matching alternatives now correctly handles+    String literals - fixes #1048.++  * Added warnings for top-level functions without type signatures - fixes #769++  * Moved pretty-printing of types from Checks.TypeCheck to Base.CurryTypes++  * Type synonyms in typed expressions are now desugared - fixes #921++  * Declaration of operator precedence is now optional in infix operator+    declarations++  * Moved module `InterfaceEquivalence` to curry-base+    (`Curry.Syntax.InterfaceEquivalence`)++  * Converted literate Haskell files into simple Haskell files++  * Removed support for FlatCurry XML files.++  * Added syntax extension `NegativeLiterals` to translate negated literals+    into negative literals instead of a call to `Prelude.negate` and+    `Prelude.negateFloat`, respectively.++  * The frontend now considers options pragmas of the following form:++    ~~~ {.curry}+    {-# OPTIONS_CYMAKE opt1 ... optn #-}+    ~~~++    The string following `OPTIONS_CYMAKE` will be split at white spaces+    and treated like an ordinary command line argument string.++    If one wishes to provide options containing spaces, e.g., directory+    paths or alike, this can be achieved by quoting the respective argument+    using either `'single quotes'` or `'double quotes'` (may bot be mixed).++    Note that *following options are excluded*:++      * A change of the current mode+        (e.g., change from compilation to HTML generation)+      * A change of the import  paths+      * A change of the library paths+      * A change of the compilation targets+        (e.g., change from FlatCurry to AbstractCurry)++    These options can only be set via the command line.++  * Refactored the source code HTML generation.+    The generation now supports full Curry with all supported extensions,+    i.e., it supports pragmas, record types and functional patterns.+    Furthermore, the created HTML has been simplified, and updated towards+    HTML 5.++  * The HTML generation now accepts an option `--htmldir=dir` to specify+    the output directory of the generated HTML files.++Version 0.3.10+==============++  * Various improvements of the internal structure.++  * Improved status messages. The compilation status message are now of the form++        [m of n] Compiling/Skipping <Module> (<source file>, <target file>)++  * Implemented support for custom preprocessors. It is now possible to run+    a custom preprocessor command via the following options:++    * `-F` enables support for a preprocessor+    * `-pgmF <cmd>` set the preprocessor command to `<cmd>`+    * `-optF <arg>` adds an additional argument to the preprocessor command+      (can be repeated to add multiple arguments)++    The preprocessor is applied to all source files which are (re)compiled+    after unliterating *and after determining the import list*.+    Consequently, adding modules via the preprocessor will results in+    compilation errors due to missing imports.+    On the other hand, the frontend will automatically determine changed+    files which are then handed to the preprocessor.++    The command is called with at least three arguments:++     #. The (normalised) file name of the source file currently processed.+        **This name is intended only for reference.**+     #. The name of the file containing the (potentially unliterated)+        contents of the original file.+        **This is the file the preprocessor should read from.**+     #. The name of the file where the preprocessed source code should go to.+        **This is the file the preprocessor should write to.**+     #. Optionally, any additional arguments specified using `-optF`.++Version 0.3.9+=============++  * Simplified verbosity options by merging options "-v1" and "-v2".+    Now only "-v0" and "-v1" are supported.++  * Fixed bug in non-exhaustive pattern matching check which occured+    when retrieving the siblings of a constructor imported using an alias.++  * Fixed bug when using functional patterns in `case`-expressions.+    Functional patterns are only allowed in the patterns of a function+    definition and forbidden elsewhere, i.e., in `case`-expressions,+    `do`-sequences, list comprehensions or lambda expressions.++  * Implementation of module pragmas added. Module pragmas of the following+    types are now parsed and represented in the abstract syntax tree:++    ~~~ {.curry}+    {-# LANGUAGE LANG_EXT+ #-}+    {-# OPTIONS "string" #-}+    {-# OPTIONS_TOOL "string" #-}+    module Main where+    ~~~++    where++      - `LANGEXT+` is a non-empty, comma-separated list of the following+        language extensions: `AnonFreeVars`, `FunctionalPatterns`,+        `NoImplicitPrelude`, `Records`+      - `TOOL` is either `KICS2`, `PAKCS`, or some other tool, represented+        as `Unknown String`.++    While the distinct language pragmas enable the respective language+    extensions, the OPTIONS pragma is ignored.++    All other texts given in the pragma braces is ignored and treated as+    a nested comment.++  * Error message for different arities of function equations now also+    report the corresponding source code positions.++Version 0.3.8+=============++  * Implemented warnings for non-exhaustive pattern matchings+    both in function declarations and `case`-expressions - fixes #349.++  * Extended options to enable/disable certain types of warnings.++  * Fixed problem when defining an operator directly after an import statement+    without import restrictions - fixes #494.++  * Fixed bug w.r.t. polymorphically typed local variables - fixes #480.++  * Fixed missing polymorphism in record labels - fixes #445.++  * Dumping of intermediate structures improved.++  * Fixed bug in type checking w.r.t. recursive type synonyms - fixes 489.++  * Reactivation of Curry interface files.+    During adaption of the MCC frontend to FlatCurry the Curry interface+    files have been deactivated and replaced by FlatCurry's interface+    files. To allow the later addition of type classes to Curry,+    they have now been reactivated.++  * Implemented missing semantics of functional patterns in combination+    with non-linear left-hand-sides and as-patterns.++  * Various improvements.++Version 0.3.7+=============++  * Support for typed FlatCurry expressions added. Now additional type+    information given by the programmer as in++    ~~~ {.curry}+    null (unknown :: [()])+    ~~~++    is represented in FlatCurry and cann therefore be processed by other+    programs like PAKCS or KICS2.++Version 0.3.6+=============++  * Error messages are now sorted according to their source code position.++Version 0.3.5+=============++  * Improved reporting of mutiple type signatures.++Version 0.3.4+=============++  * Bug in renaming phase fixed.++Version 0.3.3+=============++  * Corrected translation of `fcase`-expressions.++Version 0.3.2+=============++  * Non-linear left-hand-sides now work with guarded expressions - fixes #328.++  * Implemented precedence check - fixes #327.++  * Case completion refactored and corrected - fixes #323.++  * Various improvements and refactorings.++Version 0.3.1+=============++  * Corrected renaming of anonymous free variables - fixes #288.++Version 0.3.0+=============++  * Massive refactoring of the previous version.++  * All compiler warnings removed.++  * Fixed various implementation bugs (#9, #16, #19, #29, #289).+
LICENSE view
@@ -1,4 +1,5 @@ Copyright (c) 1998-2004, Wolfgang Lux+Copyright (c) 2005-2016, Michael Hanus All rights reserved.  Redistribution and use in source and binary forms, with or without
curry-frontend.cabal view
@@ -1,71 +1,165 @@ Name:          curry-frontend-Version:       0.2.12-Cabal-Version: >= 1.6+Version:       1.0.1+Cabal-Version: >= 1.10 Synopsis:      Compile the functional logic language Curry to several                intermediate formats-Description:   The Curry Frontend consists of the executable program "cymake".+Description:   The Curry front end consists of the executable program+               "curry-frontend".                It is used by various backends to compile Curry programs to-               an internal representation.+               an intermediate representation.                The code is a stripped-down version of an early version of                the Muenster Curry Compiler-               (<http://danae.uni-muenster.de/~lux/curry/>)+               (<http://danae.uni-muenster.de/curry/>)+               which has been extended to produce different intermediate+               representations.+               For further information, please check+               <http://curry-language.org> Category:      Language-License:       OtherLicense+License:       BSD3 License-File:  LICENSE-Author:        Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel-Maintainer:    Björn Peemöller-Bug-Reports:   http://www-ps.informatik.uni-kiel.de/redmine/projects/curry-frontend-Homepage:      http://www.curry-language.org+Author:        Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel,+               Bjoern Peemoeller, Finn Teegen+Maintainer:    fte@informatik.uni-kiel.de+Homepage:      http://curry-language.org Build-Type:    Simple Stability:     experimental -Extra-Source-Files: LIESMICH-Data-Files:         src/currydoc.css+Extra-Source-Files: LIESMICH CHANGELOG.md -Flag split-syb-  Description: Has the syb functionality been split into the package syb?-  Default:     True+Data-Dir:   data+Data-Files: currysource.css -Executable cymake-  hs-source-dirs: src-  Main-is:        cymake.hs-  if flag(split-syb)-    Build-Depends: base == 4.*, syb-  else-    Build-Depends: base == 3.*-  Build-Depends:-    curry-base >= 0.2.9 && < 0.3-    , mtl, old-time, containers, pretty-  ghc-options: -Wall-  Other-Modules:    Curry.Syntax.Lexer, Curry.Syntax.LexComb-                    Curry.Syntax.Parser, Curry.Syntax.LLParseComb-                    Curry.Syntax.ShowModule, Curry.Syntax.Pretty-                    Curry.Syntax, Curry.Syntax.Type-                    Curry.Syntax.Unlit,-                    Curry.Syntax.Utils,-                    Curry.Syntax.Frontend,-                    CurryBuilder, IL.Type-                    CurryCompilerOpts, Modules, Subst, Arity-                    CurryDeps, Eval, IL.Pretty, NestEnv, SyntaxCheck, Base-                    Exports, IL.Scope, SyntaxColoring, CurryEnv-                    IL.CurryToIL, OldScopeEnv, CurryHtml-                    IL.XML, PatchPrelude, TopEnv, CaseCompletion-                    Imports,-                    TypeCheck,-                    InterfaceCheck,-                    Types, PrecCheck-                    TypeSubst, GenAbstractCurry-                    Typing-                    GenFlatCurry, KindCheck, Qual-                    SCC, Utils-                    Lift, ScopeEnv, WarnCheck-                    Desugar,-                    Simplify+source-repository head+  type:     git+  location: https://git.ps.informatik.uni-kiel.de/curry/curry-frontend.git +Flag network-uri+   description: Get Network.URI from the network-uri package+   default: True+ Library-  hs-source-dirs:  src-  Build-Depends:   filepath+  hs-source-dirs:   src+  default-language:  Haskell2010+  Build-Depends:+      base == 4.*+    , containers+    , curry-base == 1.0.0+    , directory+    , extra >= 1.4.6+    , filepath+    , mtl+    , pretty+    , process+    , set-extra+    , transformers+  if flag(network-uri)+    build-depends: network-uri >= 2.6+  else+    build-depends: network < 2.6   Exposed-Modules:-    Curry.Files.CymakePath+      Base.AnnotExpr+    , Base.CurryKinds+    , Base.CurryTypes+    , Base.Expr+    , Base.KindSubst+    , Base.Kinds+    , Base.Messages+    , Base.NestEnv+    , Base.PrettyKinds+    , Base.PrettyTypes+    , Base.SCC+    , Base.Subst+    , Base.TopEnv+    , Base.TypeExpansion+    , Base.TypeSubst+    , Base.Types+    , Base.Typing+    , Base.Utils+    , Checks+    , Checks.DeriveCheck+    , Checks.ExportCheck+    , Checks.ExtensionCheck+    , Checks.ImportSyntaxCheck+    , Checks.InstanceCheck+    , Checks.InterfaceCheck+    , Checks.InterfaceSyntaxCheck+    , Checks.KindCheck+    , Checks.PrecCheck+    , Checks.SyntaxCheck+    , Checks.TypeCheck+    , Checks.TypeSyntaxCheck+    , Checks.WarnCheck+    , CompilerEnv+    , CompilerOpts+    , CondCompile+    , CurryBuilder+    , CurryDeps+    , Env.Class+    , Env.Instance+    , Env.Interface+    , Env.ModuleAlias+    , Env.OpPrec+    , Env.Type+    , Env.TypeConstructor+    , Env.Value+    , Exports+    , Files.CymakePath+    , Generators+    , Generators.GenAbstractCurry+    , Generators.GenFlatCurry+    , Generators.GenTypedFlatCurry+    , Html.CurryHtml+    , Html.SyntaxColoring+    , IL+    , IL.Pretty+    , IL.ShowModule+    , IL.Type+    , IL.Typing+    , Imports+    , Interfaces+    , Modules+    , TokenStream+    , Transformations+    , Transformations.CaseCompletion+    , Transformations.CurryToIL+    , Transformations.Derive+    , Transformations.Desugar+    , Transformations.Dictionary+    , Transformations.Lift+    , Transformations.Newtypes+    , Transformations.Qual+    , Transformations.Simplify   Other-Modules:     Paths_curry_frontend+  ghc-options:       -Wall -fno-warn-orphans++Executable curry-frontend+  hs-source-dirs: src+  Main-is:        cymake.hs+  default-language:  Haskell2010+  Build-Depends:+      base == 4.*+    , containers+    , curry-base == 1.0.0+    , curry-frontend+    , directory+    , extra >= 1.4.6+    , filepath+    , mtl+    , pretty+    , process+    , set-extra+    , transformers+  if flag(network-uri)+    build-depends: network-uri >= 2.6+  else+    build-depends: network < 2.6+  ghc-options: -Wall -fno-warn-orphans++Test-Suite test-frontend+  type:           detailed-0.9+  hs-source-dirs: test+  default-language:  Haskell2010+  test-module:    TestFrontend+  build-depends:  base == 4.*, Cabal >= 1.20, curry-base == 1.0.0+    , curry-frontend, filepath
+ data/currysource.css view
@@ -0,0 +1,41 @@+/* Use always white background */+body {+  background : white;+  color      : black;+  font-family: monospace;+}++/* Show hyperlinks without text decoration, but in light yellow */+a:visited, a:link, a:active {+  text-decoration: none;+  background     : lightyellow;+}++/* Line numbers */+.linenumbers {+  width        : 40px;+  text-align   : right;+  color        : grey;+  padding-right: 10px;+  border-right : 1px solid grey;+}++/* Source code */+.sourcecode  {+  padding-left: 10px;+}++/* Code highlighting */+.pragma  { color : green     }+.comment { color : green     }+.keyword { color : blue      }+.symbol  { color : red       }+.type    { color : orange    }+.cons    { color : magenta   }+.label   { color : darkgreen }+.func    { color : purple    }+.ident   { color : black     }+.module  { color : brown     }+.number  { color : teal      }+.string  { color : maroon    }+.char    { color : maroon    }
− src/Arity.hs
@@ -1,133 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Arity - provides functions for expanding the arity environment 'ArityEnv'---         (see Module "Base")------ September 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module Arity (bindArities) where--import Curry.Base.Ident-import Curry.Syntax--import Base(ArityEnv, bindArity)-------------------------------------------------------------------------------------- Expands the arity envorinment with (global / local) function arities and--- constructor arities-bindArities :: ArityEnv -> Module -> ArityEnv-bindArities aEnv (Module mid _ decls)-   = foldl (visitDecl mid) aEnv decls------------------------------------------------------------------------------------visitDecl :: ModuleIdent -> ArityEnv -> Decl -> ArityEnv-visitDecl mid aEnv (DataDecl _ _ _ cdecls)-   = foldl (visitConstrDecl mid) aEnv cdecls-visitDecl mid aEnv (ExternalDecl _ _ _ id texpr)-   = bindArity mid id (typeArity texpr) aEnv-visitDecl mid aEnv (FunctionDecl _ id equs)-   = let (Equation _ lhs rhs) = head equs-     in  visitRhs mid (visitLhs mid id aEnv lhs) rhs-visitDecl _ aEnv _ = aEnv---visitConstrDecl :: ModuleIdent -> ArityEnv -> ConstrDecl -> ArityEnv-visitConstrDecl mid aEnv (ConstrDecl _ _ id texprs)-   = bindArity mid id (length texprs) aEnv-visitConstrDecl mid aEnv (ConOpDecl _ _ _ id _)-   = bindArity mid id 2 aEnv---visitLhs :: ModuleIdent -> Ident -> ArityEnv -> Lhs -> ArityEnv-visitLhs mid _ aEnv (FunLhs id params)-   = bindArity mid id (length params) aEnv-visitLhs mid id aEnv (OpLhs _ _ _)-   = bindArity mid id 2 aEnv-visitLhs _ _ aEnv _ = aEnv---visitRhs :: ModuleIdent -> ArityEnv -> Rhs -> ArityEnv-visitRhs mid aEnv (SimpleRhs _ expr decls)-   = foldl (visitDecl mid) (visitExpression mid aEnv expr) decls-visitRhs mid aEnv (GuardedRhs cexprs decls)-   = foldl (visitDecl mid) (foldl (visitCondExpr mid) aEnv cexprs) decls---visitCondExpr :: ModuleIdent -> ArityEnv -> CondExpr -> ArityEnv-visitCondExpr mid aEnv (CondExpr _ cond expr)-   = visitExpression mid (visitExpression mid aEnv expr) cond---visitExpression :: ModuleIdent -> ArityEnv -> Expression -> ArityEnv-visitExpression mid aEnv (Paren expr)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (Typed expr _)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (Tuple _ exprs)-   = foldl (visitExpression mid) aEnv exprs-visitExpression mid aEnv (List _ exprs)-   = foldl (visitExpression mid) aEnv exprs-visitExpression mid aEnv (ListCompr _ expr stmts)-   = foldl (visitStatement mid) (visitExpression mid aEnv expr) stmts-visitExpression mid aEnv (EnumFrom expr)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (EnumFromThen expr1 expr2)-   = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (EnumFromTo expr1 expr2)-   = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (EnumFromThenTo expr1 expr2 expr3)-   = foldl (visitExpression mid) aEnv [expr1,expr2,expr3]-visitExpression mid aEnv (UnaryMinus _ expr)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (Apply expr1 expr2)-   = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (InfixApply expr1 _ expr2)-   = foldl (visitExpression mid) aEnv [expr1,expr2]-visitExpression mid aEnv (LeftSection expr _)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (RightSection _ expr)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (Lambda _ _ expr)-   = visitExpression mid aEnv expr-visitExpression mid aEnv (Let decls expr)-   = foldl (visitDecl mid) (visitExpression mid aEnv expr) decls-visitExpression mid aEnv (Do stmts expr)-   = foldl (visitStatement mid) (visitExpression mid aEnv expr) stmts-visitExpression mid aEnv (IfThenElse _ expr1 expr2 expr3)-   = foldl (visitExpression mid) aEnv [expr1,expr2,expr3]-visitExpression mid aEnv (Case _ expr alts)-   = visitExpression mid (foldl (visitAlt mid) aEnv alts) expr-visitExpression _ aEnv _ = aEnv---visitStatement :: ModuleIdent -> ArityEnv -> Statement -> ArityEnv-visitStatement mid aEnv (StmtExpr _ expr)-   = visitExpression mid aEnv expr-visitStatement mid aEnv (StmtDecl decls)-   = foldl (visitDecl mid) aEnv decls-visitStatement mid aEnv (StmtBind _ _ expr)-   = visitExpression mid aEnv expr---visitAlt :: ModuleIdent -> ArityEnv -> Alt -> ArityEnv-visitAlt mid aEnv (Alt _ _ rhs)-   = visitRhs mid aEnv rhs--------------------------------------------------------------------------------------- Computes the function arity using a type expression-typeArity :: TypeExpr -> Int-typeArity (ArrowType _ t2) = 1 + typeArity t2-typeArity _                = 0------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/Base.lhs
@@ -1,557 +0,0 @@-% $Id: Base.lhs,v 1.77 2004/02/15 22:10:25 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Base.lhs}-\section{Common Definitions for the Compiler}--The module Base implements the anti-pattern 'God-object'.-By providing definitions for various unrelated phases of the-compiler, it irrevocably turns the module structure into spaghetti.-(hsi, 2009)--\begin{verbatim}--> module Base where--> import Data.List-> import Control.Monad-> import Data.Maybe-> import qualified Data.Map as Map--> import Curry.Base.Ident -> import Curry.Base.Position-> import Types-> import qualified Curry.Syntax as CS-> import Curry.Syntax.Utils-> import TopEnv-> import Utils----\end{verbatim}-\paragraph{Types}-The functions \texttt{toType}, \texttt{toTypes}, and \texttt{fromType}-convert Curry type expressions into types and vice versa. The-functions \texttt{qualifyType} and \texttt{unqualifyType} add and-remove module qualifiers in a type, respectively.--When Curry type expression are converted with \texttt{toType} or-\texttt{toTypes}, type variables are assigned ascending indices in the-order of their occurrence. It is possible to pass a list of additional-type variables to both functions which are assigned indices before-those variables occurring in the type. This allows preserving the-order of type variables in the left hand side of a type declaration.-\begin{verbatim}--> toQualType :: ModuleIdent -> [Ident] -> CS.TypeExpr -> Type-> toQualType m tvs = qualifyType m . toType tvs--> toQualTypes :: ModuleIdent -> [Ident] -> [CS.TypeExpr] -> [Type]-> toQualTypes m tvs = map (qualifyType m) . toTypes tvs--> toType :: [Ident] -> CS.TypeExpr -> Type-> toType tvs ty = toType' (Map.fromList (zip (tvs ++ tvs') [0..])) ty->   where tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs]--> toTypes :: [Ident] -> [CS.TypeExpr] -> [Type]-> toTypes tvs tys = map (toType' (Map.fromList (zip (tvs ++ tvs') [0..]))) tys->   where tvs' = [tv | tv <- nub (concatMap fv tys), tv `notElem` tvs]--> toType' :: Map.Map Ident Int -> CS.TypeExpr -> Type-> toType' tvs (CS.ConstructorType tc tys) =->   TypeConstructor tc (map (toType' tvs) tys)-> toType' tvs (CS.VariableType tv) =->   maybe (internalError ("toType " ++ show tv)) TypeVariable (Map.lookup tv tvs)-> toType' tvs (CS.TupleType tys)->   | null tys = TypeConstructor (qualify unitId) []->   | otherwise = TypeConstructor (qualify (tupleId (length tys'))) tys'->   where tys' = map (toType' tvs) tys-> toType' tvs (CS.ListType ty) = TypeConstructor (qualify listId) [toType' tvs ty]-> toType' tvs (CS.ArrowType ty1 ty2) =->   TypeArrow (toType' tvs ty1) (toType' tvs ty2)-> toType' tvs (CS.RecordType fs rty) =->   TypeRecord (concatMap (\ (ls,ty) -> map (\l -> (l, toType' tvs ty)) ls) fs)->              (maybe Nothing ->	              (\ty -> case toType' tvs ty of->	                        TypeVariable tv -> Just tv ->	                        _ -> internalError ("toType " ++ show ty))->	              rty)--> fromQualType :: ModuleIdent -> Type -> CS.TypeExpr-> fromQualType m = fromType . unqualifyType m--> fromType :: Type -> CS.TypeExpr-> fromType (TypeConstructor tc tys)->   | isTupleId c = CS.TupleType tys'->   | c == listId && length tys == 1 = CS.ListType (head tys')->   | c == unitId && null tys = CS.TupleType []->   | otherwise = CS.ConstructorType tc tys'->   where c = unqualify tc->         tys' = map fromType tys-> fromType (TypeVariable tv) =->   CS.VariableType (if tv >= 0 then nameSupply !! tv->                            else mkIdent ('_' : show (-tv)))-> fromType (TypeConstrained tys _) = fromType (head tys)-> fromType (TypeArrow ty1 ty2) = CS.ArrowType (fromType ty1) (fromType ty2)-> fromType (TypeSkolem k) = CS.VariableType (mkIdent ("_?" ++ show k))-> fromType (TypeRecord fs rty) = ->   CS.RecordType (map (\ (l,ty) -> ([l], fromType ty)) fs)->              (maybe Nothing (Just . fromType . TypeVariable) rty)----\end{verbatim}-\paragraph{Interfaces}-The compiler maintains a global environment holding all (directly or-indirectly) imported interfaces.--The function \texttt{bindFlatInterface} transforms FlatInterface-information (type \texttt{FlatCurry.Prog} to MCC interface declarations-(type \texttt{CurrySyntax.IDecl}. This is necessary to process-FlatInterfaces instead of ".icurry" files when using MCC as frontend-for PAKCS.-\begin{verbatim}--> type ModuleEnv = Map.Map ModuleIdent [CS.IDecl]--> lookupModule :: ModuleIdent -> ModuleEnv -> Maybe [CS.IDecl]-> lookupModule = Map.lookup---\end{verbatim}-\paragraph{Type constructors}-For all defined types the compiler must maintain kind information. At-present, Curry does not support type classes. Therefore its type-language is first order and the only information that must be recorded-is the arity of each type. For algebraic data types and renaming types-the compiler also records all data constructors belonging to that-type, for alias types the type expression to be expanded is saved. In-order to manage the import and export of types, the names of the-original definitions are also recorded. On import two types are-considered equal if their original names match.--The information for a data constructor comprises the number of-existentially quantified type variables and the list of the argument-types. Note that renaming type constructors have only one type-argument.--Importing and exporting algebraic data types and renaming types is-complicated by the fact that the constructors of the type may be-(partially) hidden in the interface. This facilitates the definition-of abstract data types. An abstract type is always represented as a-data type without constructors in the interface regardless of whether-it is defined as a data type or as a renaming type. When only some-constructors of a data type are hidden, those constructors are-replaced by underscores in the interface. Furthermore, if the-right-most constructors of a data type are hidden, they are not-exported at all in order to make the interface more stable against-changes which are private to the module.-\begin{verbatim}--> data TypeInfo = DataType QualIdent Int [Maybe (Data [Type])]->               | RenamingType QualIdent Int (Data Type)->               | AliasType QualIdent Int Type->               deriving Show--> data Data a = Data Ident Int a deriving Show--> instance Entity TypeInfo where->   origName (DataType tc _ _) = tc->   origName (RenamingType tc _ _) = tc->   origName (AliasType tc _ _) = tc->   merge (DataType tc n cs) (DataType tc' _ cs')->     | tc == tc' = Just (DataType tc n (mergeData cs cs'))->     where mergeData ds [] = ds->           mergeData [] ds = ds->           mergeData (d:ds) (d':ds') = d `mplus` d' : mergeData ds ds'->   merge (DataType tc n _) (RenamingType tc' _ nc)->     | tc == tc' = Just (RenamingType tc n nc)->   merge (RenamingType tc n nc) (DataType tc' _ _)->     | tc == tc' = Just (RenamingType tc n nc)->   merge (RenamingType tc n nc) (RenamingType tc' _ _)->     | tc == tc' = Just (RenamingType tc n nc)->   merge (AliasType tc n ty) (AliasType tc' _ _)->     | tc == tc' = Just (AliasType tc n ty)->   merge _ _ = Nothing--> tcArity :: TypeInfo -> Int-> tcArity (DataType _ n _) = n-> tcArity (RenamingType _ n _) = n-> tcArity (AliasType _ n _) = n--\end{verbatim}-Types can only be defined on the top-level; no nested environments are-needed for them. Tuple types must be handled as a special case because-there is an infinite number of potential tuple types making it-impossible to insert them into the environment in advance.-\begin{verbatim}--> type TCEnv = TopEnv TypeInfo--> bindTypeInfo :: (QualIdent -> Int -> a -> TypeInfo) -> ModuleIdent->              -> Ident -> [Ident] -> a -> TCEnv -> TCEnv-> bindTypeInfo f m tc tvs x ->   = bindTopEnv "Base.bindTypeInfo" tc t ->     . qualBindTopEnv "Base.bindTypeInfo" tc' t->   where tc' = qualifyWith m tc->         t = f tc' (length tvs) x--> lookupTC :: Ident -> TCEnv -> [TypeInfo]-> lookupTC tc tcEnv = lookupTopEnv tc tcEnv ++! lookupTupleTC tc--> qualLookupTC :: QualIdent -> TCEnv -> [TypeInfo]-> qualLookupTC tc tcEnv =->   qualLookupTopEnv tc tcEnv ++! lookupTupleTC (unqualify tc)--> lookupTupleTC :: Ident -> [TypeInfo]-> lookupTupleTC tc->   | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]->   | otherwise = []--> tupleTCs :: [TypeInfo]-> tupleTCs = map typeInfo tupleData->   where typeInfo (Data c _ tys) =->           DataType (qualifyWith preludeMIdent c) (length tys)->                    [Just (Data c 0 tys)]--> tupleData :: [Data [Type]]-> tupleData = [Data (tupleId n) 0 (take n tvs) | n <- [2..]]->   where tvs = map typeVar [0..]--\end{verbatim}-\paragraph{Function and constructor types}-In order to test the type correctness of a module, the compiler needs-to determine the type of every data constructor, function,-variable, record and label in the module. -For the purpose of type checking there is no-need for distinguishing between variables and functions. For all objects-their original names and their types are saved. Functions also-contain arity information. Labels currently contain the name of their-defining record. On import two values-are considered equal if their original names match.-\begin{verbatim}--> data ValueInfo = DataConstructor QualIdent ExistTypeScheme->                | NewtypeConstructor QualIdent ExistTypeScheme->                | Value QualIdent TypeScheme->	         | Label QualIdent QualIdent TypeScheme->	           -- Label <label> <record name> <type>->                deriving Show--> instance Entity ValueInfo where->   origName (DataConstructor origName _) = origName->   origName (NewtypeConstructor origName _) = origName->   origName (Value origName _) = origName->   origName (Label origName _ _) = origName->   ->   merge (Label l r ty) (Label l' r' ty')->     | l == l' && r == r' = Just (Label l r ty)->     | otherwise = Nothing->   merge x y->     | origName x == origName y = Just x->     | otherwise = Nothing---\end{verbatim}-Even though value declarations may be nested, the compiler uses only-flat environments for saving type information. This is possible-because all identifiers are renamed by the compiler. Here we need-special cases for handling tuple constructors.--\em{Note:} the function \texttt{qualLookupValue} has been extended to-allow the usage of the qualified list constructor \texttt{(Prelude.:)}.-\begin{verbatim}--> type ValueEnv = TopEnv ValueInfo--> bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a->                -> ValueEnv -> ValueEnv-> bindGlobalInfo f m c ty ->   = bindTopEnv "Base.bindGlobalInfo" c v ->     . qualBindTopEnv "Base.bindGlobalInfo" c' v->   where c' = qualifyWith m c->         v = f c' ty--> bindFun :: ModuleIdent -> Ident -> TypeScheme -> ValueEnv -> ValueEnv-> bindFun m f ty tyEnv->   | uniqueId f == 0 ->     = bindTopEnv "Base.bindFun" f v (qualBindTopEnv "Base.bindFun" f' v tyEnv)->   | otherwise = bindTopEnv "Base.bindFun" f v tyEnv->   where f' = qualifyWith m f->         v = Value f' ty--> rebindFun :: ModuleIdent -> Ident -> TypeScheme -> ValueEnv -> ValueEnv-> rebindFun m f ty->   | uniqueId f == 0 = rebindTopEnv f v . qualRebindTopEnv f' v->   | otherwise = rebindTopEnv f v->   where f' = qualifyWith m f->         v = Value f' ty--> bindLabel :: Ident -> QualIdent -> TypeScheme -> ValueEnv -> ValueEnv-> bindLabel l r ty tyEnv = bindTopEnv "Base.bindLabel" l v tyEnv->   where v  = Label (qualify l) r ty--> lookupValue :: Ident -> ValueEnv -> [ValueInfo]-> lookupValue x tyEnv = lookupTopEnv x tyEnv ++! lookupTuple x--> qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]-> qualLookupValue x tyEnv =->   qualLookupTopEnv x tyEnv ->   ++! qualLookupCons x tyEnv->   ++! lookupTuple (unqualify x)--> qualLookupCons :: QualIdent -> ValueEnv -> [ValueInfo]-> qualLookupCons x tyEnv->    | maybe False ((==) preludeMIdent) mmid && id == consId->       = qualLookupTopEnv (qualify id) tyEnv->    | otherwise = []->  where (mmid, id) = (qualidMod x, qualidId x)--> lookupTuple :: Ident -> [ValueInfo]-> lookupTuple c->   | isTupleId c = [tupleDCs !! (tupleArity c - 2)]->   | otherwise = []--> tupleDCs :: [ValueInfo]-> tupleDCs = map dataInfo tupleTCs->   where dataInfo (DataType tc tvs [Just (Data c _ tys)]) =->           DataConstructor (qualUnqualify preludeMIdent tc)->                           (ForAllExist (length tys) 0->                                        (foldr TypeArrow (tupleType tys) tys))--\end{verbatim}-\paragraph{Arity}-In order to generate correct FlatCurry application it is necessary-to define the number of arguments as the arity value (instead of-using the arity computed from the type). For this reason the compiler-needs a table containing the information for all known functions-and constructors. -\begin{verbatim}--> type ArityEnv = TopEnv ArityInfo--> data ArityInfo = ArityInfo QualIdent Int deriving Show--> instance Entity ArityInfo where->   origName (ArityInfo origName _) = origName--> bindArity :: ModuleIdent -> Ident -> Int -> ArityEnv -> ArityEnv-> bindArity mid id arity aEnv->    | uniqueId id == 0 ->      = bindTopEnv "Base.bindArity" id arityInfo ->                   (qualBindTopEnv "Base.bindArity" qid arityInfo aEnv)->    | otherwise        ->      = bindTopEnv "Base.bindArity" id arityInfo aEnv->  where->  qid = qualifyWith mid id->  arityInfo = ArityInfo qid arity--> lookupArity :: Ident -> ArityEnv -> [ArityInfo]-> lookupArity id aEnv = lookupTopEnv id aEnv ++! lookupTupleArity id--> qualLookupArity :: QualIdent -> ArityEnv -> [ArityInfo]-> qualLookupArity qid aEnv = qualLookupTopEnv qid aEnv->		             ++! qualLookupConsArity qid aEnv->			     ++! lookupTupleArity (unqualify qid)--> qualLookupConsArity :: QualIdent -> ArityEnv -> [ArityInfo]-> qualLookupConsArity qid aEnv->    | maybe False ((==) preludeMIdent) mmid && id == consId->      = qualLookupTopEnv (qualify id) aEnv->    | otherwise->      = []->  where (mmid, id) = (qualidMod qid, qualidId qid)--> lookupTupleArity :: Ident -> [ArityInfo]-> lookupTupleArity id ->    | isTupleId id ->      = [ArityInfo (qualifyWith preludeMIdent id) (tupleArity id)]->    | otherwise->      = []--\end{verbatim}-\paragraph{Module alias}-\begin{verbatim}--> type ImportEnv = Map.Map ModuleIdent ModuleIdent--> bindAlias :: CS.Decl -> ImportEnv -> ImportEnv-> bindAlias (CS.ImportDecl _ mid _ mmid _)->    = Map.insert mid (fromMaybe mid mmid)--> lookupAlias :: ModuleIdent -> ImportEnv -> Maybe ModuleIdent-> lookupAlias = Map.lookup--> sureLookupAlias :: ModuleIdent -> ImportEnv -> ModuleIdent-> sureLookupAlias m = fromMaybe m . lookupAlias m---\end{verbatim}-\paragraph{Operator precedences}-In order to parse infix expressions correctly, the compiler must know-the precedence and fixity of each operator. Operator precedences are-associated with entities and will be checked after renaming was-applied. Nevertheless, we need to save precedences for ambiguous names-in order to handle them correctly while computing the exported-interface of a module.--If no fixity is assigned to an operator, it will be given the default-precedence 9 and assumed to be a left-associative operator.--\em{Note:} this modified version uses Haskell type \texttt{Integer}-for representing the precedence. This change had to be done due to the-introduction of unlimited integer constants in the parser / lexer.-\begin{verbatim}--> data OpPrec = OpPrec CS.Infix Integer deriving Eq--> instance Show OpPrec where->   showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p->     where assoc CS.InfixL = "left "->           assoc CS.InfixR = "right "->           assoc CS.Infix  = "non-assoc "--> defaultP :: OpPrec-> defaultP = OpPrec CS.InfixL 9--\end{verbatim}-The lookup functions for the environment which maintains the operator-precedences are simpler than for the type and value environments-because they do not need to handle tuple constructors.-\begin{verbatim}--> data PrecInfo = PrecInfo QualIdent OpPrec deriving (Eq,Show)--> instance Entity PrecInfo where->   origName (PrecInfo op _) = op--> type PEnv = TopEnv PrecInfo--> bindP :: ModuleIdent -> Ident -> OpPrec -> PEnv -> PEnv-> bindP m op p->   | uniqueId op == 0 ->     = bindTopEnv "Base.bindP" op info . qualBindTopEnv "Base.bindP" op' info->   | otherwise = bindTopEnv "Base.bindP" op info->   where op' = qualifyWith m op->         info = PrecInfo op' p--> lookupP :: Ident -> PEnv -> [PrecInfo]-> lookupP = lookupTopEnv--> qualLookupP :: QualIdent -> PEnv -> [PrecInfo]-> qualLookupP = qualLookupTopEnv--\end{verbatim}-\paragraph{Evaluation modes}-The compiler has to collect the evaluation annotations for a program-in an environment. As these annotations affect only local declarations,-a flat environment mapping unqualified names onto annotations is-sufficient.-\begin{verbatim}--> type EvalEnv = Map.Map Ident CS.EvalAnnotation---\end{verbatim}-\paragraph{Predefined types}-The list and unit data types must be predefined because their-definitions-\begin{verbatim}-data () = ()-data [] a = [] | a : [a]-\end{verbatim}-are not allowed by Curry's syntax. The corresponding types-are available in the environments \texttt{initTCEnv} and-\texttt{initDCEnv}. In addition, the precedence of the (infix) list-constructor is available in the environment \texttt{initPEnv}.--Note that only the unqualified names are predefined. This is correct,-because neither \texttt{Prelude.()} nor \texttt{Prelude.[]} are valid-identifiers.-\begin{verbatim}--> initPEnv :: PEnv-> initPEnv =->   predefTopEnv qConsId (PrecInfo qConsId (OpPrec CS.InfixR 5)) emptyTopEnv--> initTCEnv :: TCEnv-> initTCEnv = foldr (uncurry predefTC) emptyTopEnv predefTypes->   where predefTC (TypeConstructor tc tys) =->           predefTopEnv (qualify (unqualify tc)) .->             DataType tc (length tys) . map Just--> initDCEnv :: ValueEnv-> initDCEnv =->   foldr (uncurry predefDC) emptyTopEnv->         [(c,constrType (polyType ty) n' tys)->         | (ty,cs) <- predefTypes, Data c n' tys <- cs]->   where predefDC c ty = predefTopEnv c' (DataConstructor c' ty)->           where c' = qualify c->         constrType (ForAll n ty) n' = ForAllExist n n' . foldr TypeArrow ty--> initAEnv :: ArityEnv-> initAEnv->    = foldr bindPredefArity emptyTopEnv (concatMap snd predefTypes)->  where->  bindPredefArity (Data id _ ts)->     = bindArity preludeMIdent id (length ts)--> initIEnv :: ImportEnv-> initIEnv = Map.empty--> predefTypes :: [(Type,[Data [Type]])]-> predefTypes =->   let a = typeVar 0 in [->     (unitType,   [Data unitId 0 []]),->     (listType a, [Data nilId 0 [],Data consId 0 [a,listType a]])->   ]---\end{verbatim}--\paragraph{Miscellany}-Error handling-\begin{verbatim}--> errorAt :: Position -> String -> a-> errorAt p msg = error ("\n" ++ show p ++ ": " ++ msg)--> errorAt' :: (Position,String) -> a-> errorAt' = uncurry errorAt--> internalError :: String -> a-> internalError what = error ("internal error: " ++ what)--\end{verbatim}-Name supply for the generation of (type) variable names.-\begin{verbatim}--> nameSupply :: [Ident]-> nameSupply = map mkIdent [c:showNum i | i <- [0..], c <- ['a'..'z']]->   where showNum 0 = ""->         showNum n = show n--\end{verbatim}-\ToDo{The \texttt{nameSupply} should respect the current case mode, -i.e., use upper case for variables in Prolog mode.}--\end{verbatim}-The function \texttt{findDouble} checks whether a list of entities is-linear, i.e., if every entity in the list occurs only once. If it is-non-linear, the first offending object is returned.-\begin{verbatim}--> findDouble :: Eq a => [a] -> Maybe a-> findDouble (x:xs)->   | x `elem` xs = Just x->   | otherwise = findDouble xs-> findDouble [] = Nothing--\end{verbatim}---
+ src/Base/AnnotExpr.hs view
@@ -0,0 +1,123 @@+{- |+    Module      :  $Header$+    Description :  Extraction of free qualified annotated variables+    Copyright   :  (c) 2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    TODO+-}+module Base.AnnotExpr (QualAnnotExpr (..)) where++import qualified Data.Set  as Set (fromList, notMember)++import Curry.Base.Ident+import Curry.Syntax++import Base.Expr+import Base.Types+import Base.Typing++class QualAnnotExpr e where+  -- |Free qualified annotated variables in an 'Expr'+  qafv :: ModuleIdent -> e Type -> [(Type, Ident)]++-- The 'Decl' instance of 'QualAnnotExpr' returns all free+-- variables on the right hand side, regardless of whether they are bound+-- on the left hand side. This is more convenient as declarations are+-- usually processed in a declaration group where the set of free+-- variables cannot be computed independently for each declaration.++instance QualAnnotExpr Decl where+  qafv m (FunctionDecl  _ _ _ eqs) = concatMap (qafv m) eqs+  qafv m (PatternDecl     _ _ rhs) = qafv m rhs+  qafv m (ClassDecl    _ _ _ _ ds) = concatMap (qafv m) ds+  qafv m (InstanceDecl _ _ _ _ ds) = concatMap (qafv m) ds+  qafv _ _                         = []++instance QualAnnotExpr Equation where+  qafv m (Equation _ lhs rhs) = filterBv lhs $ qafv m lhs ++ qafv m rhs++instance QualAnnotExpr Lhs where+  qafv m = concatMap (qafv m) . snd . flatLhs++instance QualAnnotExpr Rhs where+  qafv m (SimpleRhs _ e ds) = filterBv ds $ qafv m e ++ concatMap (qafv m) ds+  qafv m (GuardedRhs es ds) =+    filterBv ds $ concatMap (qafv m) es ++ concatMap (qafv m) ds++instance QualAnnotExpr CondExpr where+  qafv m (CondExpr _ g e) = qafv m g ++ qafv m e++instance QualAnnotExpr Expression where+  qafv _ (Literal             _ _) = []+  qafv m (Variable           ty v) =+    maybe [] (return . (\v' -> (ty, v'))) $ localIdent m v+  qafv _ (Constructor         _ _) = []+  qafv m (Paren                 e) = qafv m e+  qafv m (Typed               e _) = qafv m e+  qafv m (Record           _ _ fs) = concatMap (qafvField m) fs+  qafv m (RecordUpdate       e fs) = qafv m e ++ concatMap (qafvField m) fs+  qafv m (Tuple                es) = concatMap (qafv m) es+  qafv m (List               _ es) = concatMap (qafv m) es+  qafv m (ListCompr          e qs) = foldr (qafvStmt m) (qafv m e) qs+  qafv m (EnumFrom              e) = qafv m e+  qafv m (EnumFromThen      e1 e2) = qafv m e1 ++ qafv m e2+  qafv m (EnumFromTo        e1 e2) = qafv m e1 ++ qafv m e2+  qafv m (EnumFromThenTo e1 e2 e3) = qafv m e1 ++ qafv m e2 ++ qafv m e3+  qafv m (UnaryMinus            e) = qafv m e+  qafv m (Apply             e1 e2) = qafv m e1 ++ qafv m e2+  qafv m (InfixApply     e1 op e2) = qafv m op ++ qafv m e1 ++ qafv m e2+  qafv m (LeftSection        e op) = qafv m op ++ qafv m e+  qafv m (RightSection       op e) = qafv m op ++ qafv m e+  qafv m (Lambda             ts e) = filterBv ts $ qafv m e+  qafv m (Let                ds e) =+    filterBv ds $ concatMap (qafv m) ds ++ qafv m e+  qafv m (Do                sts e) = foldr (qafvStmt m) (qafv m e) sts+  qafv m (IfThenElse     e1 e2 e3) = qafv m e1 ++ qafv m e2 ++ qafv m e3+  qafv m (Case           _ e alts) = qafv m e ++ concatMap (qafv m) alts++qafvField :: QualAnnotExpr e => ModuleIdent -> Field (e Type) -> [(Type, Ident)]+qafvField m (Field _ _ t) = qafv m t++qafvStmt :: ModuleIdent -> Statement Type -> [(Type, Ident)] -> [(Type, Ident)]+qafvStmt m st fvs = qafv m st ++ filterBv st fvs++instance QualAnnotExpr Statement where+  qafv m (StmtExpr   e) = qafv m e+  qafv m (StmtDecl  ds) = filterBv ds $ concatMap (qafv m) ds+  qafv m (StmtBind _ e) = qafv m e++instance QualAnnotExpr Alt where+  qafv m (Alt _ t rhs) = filterBv t $ qafv m rhs++instance QualAnnotExpr InfixOp where+  qafv m (InfixOp    ty op) = qafv m $ Variable ty op+  qafv _ (InfixConstr _ _ ) = []++instance QualAnnotExpr Pattern where+  qafv _ (LiteralPattern           _ _) = []+  qafv _ (NegativePattern          _ _) = []+  qafv _ (VariablePattern          _ _) = []+  qafv m (ConstructorPattern    _ _ ts) = concatMap (qafv m) ts+  qafv m (InfixPattern       _ t1 _ t2) = qafv m t1 ++ qafv m t2+  qafv m (ParenPattern               t) = qafv m t+  qafv m (RecordPattern         _ _ fs) = concatMap (qafvField m) fs+  qafv m (TuplePattern              ts) = concatMap (qafv m) ts+  qafv m (ListPattern             _ ts) = concatMap (qafv m) ts+  qafv m (AsPattern                _ t) = qafv m t+  qafv m (LazyPattern                t) = qafv m t+  qafv m (FunctionPattern      ty f ts) =+    maybe [] (return . (\f' -> (ty', f'))) (localIdent m f) +++      concatMap (qafv m) ts+    where ty' = foldr TypeArrow ty $ map typeOf ts+  qafv m (InfixFuncPattern ty t1 op t2) =+    maybe [] (return . (\op' -> (ty', op'))) (localIdent m op) +++      concatMap (qafv m) [t1, t2]+    where ty' = foldr TypeArrow ty $ map typeOf [t1, t2]++filterBv :: QuantExpr e => e -> [(Type, Ident)] -> [(Type, Ident)]+filterBv e = filter ((`Set.notMember` Set.fromList (bv e)) . snd)
+ src/Base/CurryKinds.hs view
@@ -0,0 +1,45 @@+{- |+    Module      :  $Header$+    Description :  Conversion of kind representation+    Copyright   :  (c) 2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The functions 'tokind' and 'fromKind' convert Curry kind expressions into+   kinds and vice versa.++   When Curry kinds are converted with 'fromKind', kind variables are+   instantiated with the kind *.+-}++module Base.CurryKinds+  ( toKind, toKind', fromKind, fromKind', ppKind+  ) where++import Curry.Base.Pretty (Doc)+import Curry.Syntax.Pretty (ppKindExpr)+import Curry.Syntax.Type (KindExpr (..))++import Base.Kinds++toKind :: KindExpr -> Kind+toKind Star              = KindStar+toKind (ArrowKind k1 k2) = KindArrow (toKind k1) (toKind k2)++toKind' :: Maybe KindExpr -> Int -> Kind+toKind' k n = maybe (simpleKind n) toKind k++fromKind :: Kind -> KindExpr+fromKind KindStar          = Star+fromKind (KindVariable  _) = Star+fromKind (KindArrow k1 k2) = ArrowKind (fromKind k1) (fromKind k2)++fromKind' :: Kind -> Int -> Maybe KindExpr+fromKind' k n | k == simpleKind n = Nothing+              | otherwise         = Just (fromKind k)++ppKind :: Kind -> Doc+ppKind = ppKindExpr 0 . fromKind
+ src/Base/CurryTypes.hs view
@@ -0,0 +1,215 @@+{- |+    Module      :  $Header$+    Description :  Conversion of type representation+    Copyright   :  (c)         Wolfgang Lux+                   2011 - 2012 Björn Peemöller+                   2015        Jan Tikovsky+                   2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The functions 'toType', 'toTypes', and 'fromType' convert Curry type+   expressions into types and vice versa. The functions 'qualifyType' and+   'unqualifyType' add and remove module qualifiers in a type, respectively.++   When Curry type expression are converted with 'toType' or 'toTypes',+   type variables are assigned ascending indices in the order of their+   occurrence. It is possible to pass a list of additional type variables+   to both functions which are assigned indices before those variables+   occurring in the type. This allows preserving the order of type variables+   in the left hand side of a type declaration.+-}++module Base.CurryTypes+  ( toType, toTypes, toQualType, toQualTypes+  , toPred, toQualPred, toPredSet, toQualPredSet, toPredType, toQualPredType+  , toConstrType, toMethodType+  , fromType, fromQualType+  , fromPred, fromQualPred, fromPredSet, fromQualPredSet, fromPredType+  , fromQualPredType+  , ppType, ppPred, ppPredType, ppTypeScheme+  ) where++import Data.List (nub)+import qualified Data.Map as Map (Map, fromList, lookup)+import qualified Data.Set as Set++import Curry.Base.Ident+import Curry.Base.Pretty (Doc)+import qualified Curry.Syntax as CS+import Curry.Syntax.Pretty (ppConstraint, ppTypeExpr, ppQualTypeExpr)++import Base.Expr+import Base.Messages (internalError)+import Base.Types++enumTypeVars :: (Expr a, QuantExpr a) => [Ident] -> a -> Map.Map Ident Int+enumTypeVars tvs ty = Map.fromList $ zip (tvs ++ tvs') [0..]+  where+    tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs] +++             [tv | tv <- nub (bv ty), tv `notElem` tvs]++toType :: [Ident] -> CS.TypeExpr -> Type+toType tvs ty = toType' (enumTypeVars tvs ty) ty []++toTypes :: [Ident] -> [CS.TypeExpr] -> [Type]+toTypes tvs tys = map ((flip (toType' (enumTypeVars tvs tys))) []) tys++toType' :: Map.Map Ident Int -> CS.TypeExpr -> [Type] -> Type+toType' _   (CS.ConstructorType tc) tys = applyType (TypeConstructor tc) tys+toType' tvs (CS.ApplyType  ty1 ty2) tys =+  toType' tvs ty1 (toType' tvs ty2 [] : tys)+toType' tvs (CS.VariableType    tv) tys =+  applyType (TypeVariable (toVar tvs tv)) tys+toType' tvs (CS.TupleType      tys) tys'+  | null tys  = internalError "Base.CurryTypes.toType': zero-element tuple"+  | null tys' = tupleType $ map ((flip $ toType' tvs) []) tys+  | otherwise = internalError "Base.CurryTypes.toType': tuple type application"+toType' tvs (CS.ListType        ty) tys+  | null tys  = listType $ toType' tvs ty []+  | otherwise = internalError "Base.CurryTypes.toType': list type application"+toType' tvs (CS.ArrowType  ty1 ty2) tys+  | null tys = TypeArrow (toType' tvs ty1 []) (toType' tvs ty2 [])+  | otherwise = internalError "Base.CurryTypes.toType': arrow type application"+toType' tvs (CS.ParenType       ty) tys = toType' tvs ty tys+toType' tvs (CS.ForallType tvs' ty) tys+  | null tvs' = toType' tvs ty tys+  | otherwise = applyType (TypeForall (map (toVar tvs) tvs') (toType' tvs ty []))+                          tys++toVar :: Map.Map Ident Int -> Ident -> Int+toVar tvs tv = case Map.lookup tv tvs of+  Just tv' -> tv'+  Nothing  -> internalError "Base.CurryTypes.toVar: unknown type variable"++toQualType :: ModuleIdent -> [Ident] -> CS.TypeExpr -> Type+toQualType m tvs = qualifyType m . toType tvs++toQualTypes :: ModuleIdent -> [Ident] -> [CS.TypeExpr] -> [Type]+toQualTypes m tvs = map (qualifyType m) . toTypes tvs++toPred :: [Ident] -> CS.Constraint -> Pred+toPred tvs c = toPred' (enumTypeVars tvs c) c++toPred' :: Map.Map Ident Int -> CS.Constraint -> Pred+toPred' tvs (CS.Constraint qcls ty) = Pred qcls (toType' tvs ty [])++toQualPred :: ModuleIdent -> [Ident] -> CS.Constraint -> Pred+toQualPred m tvs = qualifyPred m . toPred tvs++toPredSet :: [Ident] -> CS.Context -> PredSet+toPredSet tvs cx = toPredSet' (enumTypeVars tvs cx) cx++toPredSet' :: Map.Map Ident Int -> CS.Context -> PredSet+toPredSet' tvs = Set.fromList . map (toPred' tvs)++toQualPredSet :: ModuleIdent -> [Ident] -> CS.Context -> PredSet+toQualPredSet m tvs = qualifyPredSet m . toPredSet tvs++toPredType :: [Ident] -> CS.QualTypeExpr -> PredType+toPredType tvs qty = toPredType' (enumTypeVars tvs qty) qty++toPredType' :: Map.Map Ident Int -> CS.QualTypeExpr -> PredType+toPredType' tvs (CS.QualTypeExpr cx ty) =+  PredType (toPredSet' tvs cx) (toType' tvs ty [])++toQualPredType :: ModuleIdent -> [Ident] -> CS.QualTypeExpr -> PredType+toQualPredType m tvs = qualifyPredType m . toPredType tvs++-- The function 'toConstrType' returns the type of a data or newtype+-- constructor. Hereby, it restricts the context to those type variables+-- which are free in the argument types.++toConstrType :: QualIdent -> [Ident] -> CS.Context -> [CS.TypeExpr] -> PredType+toConstrType tc tvs cx tys = toPredType tvs $ CS.QualTypeExpr cx' ty'+  where tvs' = nub (fv tys)+        cx'  = restrictContext tvs' cx+        ty'  = foldr CS.ArrowType ty0 tys+        ty0  = foldl CS.ApplyType+                     (CS.ConstructorType tc)+                     (map CS.VariableType tvs)++restrictContext :: [Ident] -> CS.Context -> CS.Context+restrictContext tvs cx =+  [CS.Constraint cls ty | CS.Constraint cls ty <- cx, classVar ty `elem` tvs]+  where classVar (CS.VariableType tv) = tv+        classVar (CS.ApplyType  ty _) = classVar ty+        classVar _ = internalError "Base.CurryTypes.restrictContext.classVar"++-- The function 'toMethodType' returns the type of a type class method.+-- It adds the implicit type class constraint to the method's type signature+-- and ensures that the class' type variable is always assigned index 0.++toMethodType :: QualIdent -> Ident -> CS.QualTypeExpr -> PredType+toMethodType qcls clsvar (CS.QualTypeExpr cx ty) =+  toPredType [clsvar] (CS.QualTypeExpr cx' ty)+  where cx' = CS.Constraint qcls (CS.VariableType clsvar) : cx++fromType :: [Ident] -> Type -> CS.TypeExpr+fromType tvs ty = fromType' tvs ty []++fromType' :: [Ident] -> Type -> [CS.TypeExpr] -> CS.TypeExpr+fromType' _   (TypeConstructor    tc) tys+  | isQTupleId tc && qTupleArity tc == length tys = CS.TupleType tys+  | tc == qListId && length tys == 1              = CS.ListType (head tys)+  | otherwise+  = foldl CS.ApplyType (CS.ConstructorType tc) tys+fromType' tvs (TypeApply     ty1 ty2) tys =+  fromType' tvs ty1 (fromType tvs ty2 : tys)+fromType' tvs (TypeVariable       tv) tys =+  foldl CS.ApplyType (CS.VariableType (fromVar tvs tv)) tys+fromType' tvs (TypeArrow     ty1 ty2) tys =+  foldl CS.ApplyType (CS.ArrowType (fromType tvs ty1) (fromType tvs ty2)) tys+fromType' tvs (TypeConstrained tys _) tys' = fromType' tvs (head tys) tys'+fromType' _   (TypeSkolem          k) tys =+  foldl CS.ApplyType (CS.VariableType $ mkIdent $ "_?" ++ show k) tys+fromType' tvs (TypeForall    tvs' ty) tys+  | null tvs' = fromType' tvs ty tys+  | otherwise = foldl CS.ApplyType+                      (CS.ForallType (map (fromVar tvs) tvs') (fromType tvs ty))+                      tys++fromVar :: [Ident] -> Int -> Ident+fromVar tvs tv = if tv >= 0 then tvs !! tv else mkIdent ('_' : show (-tv))++fromQualType :: ModuleIdent -> [Ident] -> Type -> CS.TypeExpr+fromQualType m tvs = fromType tvs . unqualifyType m++fromPred :: [Ident] -> Pred -> CS.Constraint+fromPred tvs (Pred qcls ty) = CS.Constraint qcls (fromType tvs ty)++fromQualPred :: ModuleIdent -> [Ident] -> Pred -> CS.Constraint+fromQualPred m tvs = fromPred tvs .  unqualifyPred m++-- Due to the sorting of the predicate set, the list of constraints is sorted+-- as well.++fromPredSet :: [Ident] -> PredSet -> CS.Context+fromPredSet tvs = map (fromPred tvs) . Set.toAscList++fromQualPredSet :: ModuleIdent -> [Ident] -> PredSet -> CS.Context+fromQualPredSet m tvs = fromPredSet tvs . unqualifyPredSet m++fromPredType :: [Ident] -> PredType -> CS.QualTypeExpr+fromPredType tvs (PredType ps ty) =+  CS.QualTypeExpr (fromPredSet tvs ps) (fromType tvs ty)++fromQualPredType :: ModuleIdent -> [Ident] -> PredType -> CS.QualTypeExpr+fromQualPredType m tvs = fromPredType tvs . unqualifyPredType m++-- The following functions implement pretty-printing for types.++ppType :: ModuleIdent -> Type -> Doc+ppType m = ppTypeExpr 0 . fromQualType m identSupply++ppPred :: ModuleIdent -> Pred -> Doc+ppPred m = ppConstraint . fromQualPred m identSupply++ppPredType :: ModuleIdent -> PredType -> Doc+ppPredType m = ppQualTypeExpr . fromQualPredType m identSupply++ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc+ppTypeScheme m (ForAll _ pty) = ppPredType m pty
+ src/Base/Expr.hs view
@@ -0,0 +1,211 @@+{- |+    Module      :  $Header$+    Description :  Extraction of free and bound variables+    Copyright   :  (c)             Wolfgang Lux+                       2011 - 2015 Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    The compiler needs to compute the lists of free and bound variables for+    various different entities. We will devote three type classes to that+    purpose. The 'QualExpr' class is expected to take into account+    that it is possible to use a qualified name to refer to a function+    defined in the current module and therefore @M.x@ and @x@, where+    @M@ is the current module name, should be considered the same name.+    However, note that this is correct only after renaming all local+    definitions as @M.x@ always denotes an entity defined at the+    top-level.+-}+module Base.Expr (Expr (..), QualExpr (..), QuantExpr (..)) where++import           Data.List        (nub)+import qualified Data.Set  as Set (fromList, notMember)++import Curry.Base.Ident+import Curry.Syntax++class Expr e where+  -- |Free variables in an 'Expr'+  fv :: e -> [Ident]++class QualExpr e where+  -- |Free qualified variables in an 'Expr'+  qfv :: ModuleIdent -> e -> [Ident]++class QuantExpr e where+  -- |Bounded variables in an 'Expr'+  bv :: e -> [Ident]++instance Expr e => Expr [e] where+  fv = concatMap fv++instance QualExpr e => QualExpr [e] where+  qfv m = concatMap (qfv m)++instance QuantExpr e => QuantExpr [e] where+  bv = concatMap bv++-- The 'Decl' instance of 'QualExpr' returns all free+-- variables on the right hand side, regardless of whether they are bound+-- on the left hand side. This is more convenient as declarations are+-- usually processed in a declaration group where the set of free+-- variables cannot be computed independently for each declaration.++instance QualExpr (Decl a) where+  qfv m (FunctionDecl  _ _ _ eqs) = qfv m eqs+  qfv m (PatternDecl     _ _ rhs) = qfv m rhs+  qfv m (ClassDecl    _ _ _ _ ds) = qfv m ds+  qfv m (InstanceDecl _ _ _ _ ds) = qfv m ds+  qfv _ _                         = []++instance QuantExpr (Decl a) where+  bv (TypeSig          _ vs _) = vs+  bv (FunctionDecl    _ _ f _) = [f]+  bv (ExternalDecl       _ vs) = bv vs+  bv (PatternDecl       _ t _) = bv t+  bv (FreeDecl           _ vs) = bv vs+  bv (ClassDecl    _ _ _ _ ds) = concatMap methods ds+  bv _                         = []++instance QualExpr (Equation a) where+  qfv m (Equation _ lhs rhs) = filterBv lhs $ qfv m lhs ++ qfv m rhs++instance QuantExpr (Lhs a) where+  bv = bv . snd . flatLhs++instance QualExpr (Lhs a) where+  qfv m lhs = qfv m $ snd $ flatLhs lhs++instance QualExpr (Rhs a) where+  qfv m (SimpleRhs _ e ds) = filterBv ds $ qfv m e  ++ qfv m ds+  qfv m (GuardedRhs es ds) = filterBv ds $ qfv m es ++ qfv m ds++instance QualExpr (CondExpr a) where+  qfv m (CondExpr _ g e) = qfv m g ++ qfv m e++instance QualExpr (Expression a) where+  qfv _ (Literal             _ _) = []+  qfv m (Variable            _ v) = maybe [] return $ localIdent m v+  qfv _ (Constructor         _ _) = []+  qfv m (Paren                 e) = qfv m e+  qfv m (Typed               e _) = qfv m e+  qfv m (Record           _ _ fs) = qfv m fs+  qfv m (RecordUpdate       e fs) = qfv m e ++ qfv m fs+  qfv m (Tuple                es) = qfv m es+  qfv m (List               _ es) = qfv m es+  qfv m (ListCompr          e qs) = foldr (qfvStmt m) (qfv m e) qs+  qfv m (EnumFrom              e) = qfv m e+  qfv m (EnumFromThen      e1 e2) = qfv m e1 ++ qfv m e2+  qfv m (EnumFromTo        e1 e2) = qfv m e1 ++ qfv m e2+  qfv m (EnumFromThenTo e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3+  qfv m (UnaryMinus            e) = qfv m e+  qfv m (Apply             e1 e2) = qfv m e1 ++ qfv m e2+  qfv m (InfixApply     e1 op e2) = qfv m op ++ qfv m e1 ++ qfv m e2+  qfv m (LeftSection        e op) = qfv m op ++ qfv m e+  qfv m (RightSection       op e) = qfv m op ++ qfv m e+  qfv m (Lambda             ts e) = filterBv ts $ qfv m e+  qfv m (Let                ds e) = filterBv ds $ qfv m ds ++ qfv m e+  qfv m (Do                sts e) = foldr (qfvStmt m) (qfv m e) sts+  qfv m (IfThenElse     e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3+  qfv m (Case           _ e alts) = qfv m e ++ qfv m alts++qfvStmt :: ModuleIdent -> (Statement a) -> [Ident] -> [Ident]+qfvStmt m st fvs = qfv m st ++ filterBv st fvs++instance QualExpr (Statement a) where+  qfv m (StmtExpr   e) = qfv m e+  qfv m (StmtDecl  ds) = filterBv ds $ qfv m ds+  qfv m (StmtBind _ e) = qfv m e++instance QualExpr (Alt a) where+  qfv m (Alt _ t rhs) = filterBv t $ qfv m rhs++instance QuantExpr (Var a) where+  bv (Var _ v) = [v]++instance QuantExpr a => QuantExpr (Field a) where+  bv (Field _ _ t) = bv t++instance QualExpr a => QualExpr (Field a) where+  qfv m (Field _ _ t) = qfv m t++instance QuantExpr (Statement a) where+  bv (StmtExpr   _) = []+  bv (StmtBind t _) = bv t+  bv (StmtDecl  ds) = bv ds++instance QualExpr (InfixOp a) where+  qfv m (InfixOp     a op) = qfv m $ Variable a op+  qfv _ (InfixConstr _ _ ) = []++instance QuantExpr (Pattern a) where+  bv (LiteralPattern         _ _) = []+  bv (NegativePattern        _ _) = []+  bv (VariablePattern        _ v) = [v]+  bv (ConstructorPattern  _ _ ts) = bv ts+  bv (InfixPattern     _ t1 _ t2) = bv t1 ++ bv t2+  bv (ParenPattern             t) = bv t+  bv (RecordPattern       _ _ fs) = bv fs+  bv (TuplePattern            ts) = bv ts+  bv (ListPattern           _ ts) = bv ts+  bv (AsPattern              v t) = v : bv t+  bv (LazyPattern              t) = bv t+  bv (FunctionPattern     _ _ ts) = nub $ bv ts+  bv (InfixFuncPattern _ t1 _ t2) = nub $ bv t1 ++ bv t2++instance QualExpr (Pattern a) where+  qfv _ (LiteralPattern          _ _) = []+  qfv _ (NegativePattern         _ _) = []+  qfv _ (VariablePattern         _ _) = []+  qfv m (ConstructorPattern   _ _ ts) = qfv m ts+  qfv m (InfixPattern      _ t1 _ t2) = qfv m [t1, t2]+  qfv m (ParenPattern              t) = qfv m t+  qfv m (RecordPattern        _ _ fs) = qfv m fs+  qfv m (TuplePattern             ts) = qfv m ts+  qfv m (ListPattern            _ ts) = qfv m ts+  qfv m (AsPattern              _ ts) = qfv m ts+  qfv m (LazyPattern               t) = qfv m t+  qfv m (FunctionPattern      _ f ts)+    = maybe [] return (localIdent m f) ++ qfv m ts+  qfv m (InfixFuncPattern _ t1 op t2)+    = maybe [] return (localIdent m op) ++ qfv m [t1, t2]++instance Expr Constraint where+  fv (Constraint _ ty) = fv ty++instance QuantExpr Constraint where+  bv _ = []++instance Expr QualTypeExpr where+  fv (QualTypeExpr _ ty) = fv ty++instance QuantExpr QualTypeExpr where+  bv (QualTypeExpr _ ty) = bv ty++instance Expr TypeExpr where+  fv (ConstructorType     _) = []+  fv (ApplyType     ty1 ty2) = fv ty1 ++ fv ty2+  fv (VariableType       tv) = [tv]+  fv (TupleType         tys) = fv tys+  fv (ListType           ty) = fv ty+  fv (ArrowType     ty1 ty2) = fv ty1 ++ fv ty2+  fv (ParenType          ty) = fv ty+  fv (ForallType      vs ty) = filter (`notElem` vs) $ fv ty++instance QuantExpr TypeExpr where+  bv (ConstructorType     _) = []+  bv (ApplyType     ty1 ty2) = bv ty1 ++ bv ty2+  bv (VariableType        _) = []+  bv (TupleType         tys) = bv tys+  bv (ListType           ty) = bv ty+  bv (ArrowType     ty1 ty2) = bv ty1 ++ bv ty2+  bv (ParenType          ty) = bv ty+  bv (ForallType     tvs ty) = tvs ++ bv ty++filterBv :: QuantExpr e => e -> [Ident] -> [Ident]+filterBv e = filter (`Set.notMember` Set.fromList (bv e))
+ src/Base/KindSubst.hs view
@@ -0,0 +1,48 @@+{- |+    Module      :  $Header$+    Description :  Kind substitution+    Copyright   :  (c) 2016      Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module implements substitutions on kinds.+-}++module Base.KindSubst+  ( module Base.KindSubst, idSubst, singleSubst, bindSubst, compose+  ) where++import Base.Kinds+import Base.Subst+import Base.TopEnv++import Env.TypeConstructor++type KindSubst = Subst Int Kind++class SubstKind a where+  subst :: KindSubst -> a -> a++bindVar :: Int -> Kind -> KindSubst -> KindSubst+bindVar kv k = compose (bindSubst kv k idSubst)++substVar :: KindSubst -> Int -> Kind+substVar = substVar' KindVariable subst++instance SubstKind Kind where+  subst _     KindStar             = KindStar+  subst sigma (KindVariable    kv) = substVar sigma kv+  subst sigma (KindArrow    k1 k2) = KindArrow (subst sigma k1) (subst sigma k2)++instance SubstKind TypeInfo where+  subst theta (DataType     tc k cs) = DataType tc (subst theta k) cs+  subst theta (RenamingType tc k nc) = RenamingType tc (subst theta k) nc+  subst theta (AliasType  tc k n ty) = AliasType tc (subst theta k) n ty+  subst theta (TypeClass   cls k ms) = TypeClass cls (subst theta k) ms+  subst theta (TypeVar            k) = TypeVar (subst theta k)++instance SubstKind a => SubstKind (TopEnv a) where+  subst = fmap . subst
+ src/Base/Kinds.hs view
@@ -0,0 +1,55 @@+{- |+    Module      :  $Header$+    Description :  Internal representation of kinds+    Copyright   :  (c) 2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module modules provides the definitions for the internal+   representation of kinds in the compiler.+-}++module Base.Kinds where++-- A kind is either *, which is the kind of a value's type, a kind+-- variable, or an arrow kind. Kind variables are used internally during+-- kind inference. Kind variables are not supported in Curry kind+-- expressions and all kind variables that remain free after kind+-- inference are instantiated to *.++data Kind = KindStar+          | KindVariable Int+          | KindArrow Kind Kind+  deriving (Eq, Show)++-- |The function 'kindArity' computes the arity n of a kind.+kindArity :: Kind -> Int+kindArity (KindArrow _ k) = 1 + kindArity k+kindArity _               = 0++-- |The function 'kindVars' returns a list of all kind variables+-- occurring in a kind.+kindVars :: Kind -> [Int]+kindVars k = vars k []+  where+    vars KindStar          kvs = kvs+    vars (KindVariable kv) kvs = kv : kvs+    vars (KindArrow k1 k2) kvs = vars k1 $ vars k2 kvs++-- |The function 'defaultKind' instantiates all kind variables+-- occurring in a kind to *.+defaultKind :: Kind -> Kind+defaultKind (KindArrow k1 k2) = KindArrow (defaultKind k1) (defaultKind k2)+defaultKind _                 = KindStar++-- |The function 'simpleKind' returns the kind of a type+-- constructor with arity n whose arguments all have kind *.+simpleKind :: Int -> Kind+simpleKind n = foldr KindArrow KindStar $ replicate n KindStar++-- |The function 'isSimpleKind' returns whether a kind is simple or not.+isSimpleKind :: Kind -> Bool+isSimpleKind k = k == simpleKind (kindArity k)
+ src/Base/Messages.hs view
@@ -0,0 +1,78 @@+{- |+    Module      :  $Header$+    Description :  Construction and output of compiler messages+    Copyright   :  (c) 2011 - 2016 Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module defines several operations to construct and emit compiler+    messages to the user.+-}+module Base.Messages+  ( -- * Output of user information+    MonadIO (..), status, putMsg, putErrLn, putErrsLn+    -- * program abortion+  , abortWith, abortWithMessage, abortWithMessages, warnOrAbort, internalError+    -- * creating messages+  , Message, message, posMessage+  ) where++import Control.Monad              (unless, when)+import Control.Monad.IO.Class     (MonadIO(..))+import Data.List                  (sort)+import System.IO                  (hFlush, hPutStrLn, stderr, stdout)+import System.Exit                (exitFailure)++import Curry.Base.Message         ( Message, message, posMessage, ppWarning+                                  , ppMessages, ppError)+import Curry.Base.Pretty          (Doc, text)+import CompilerOpts               (Options (..), WarnOpts (..), Verbosity (..))++-- |Print a status message, depending on the current verbosity+status :: MonadIO m => Options -> String -> m ()+status opts msg = unless (optVerbosity opts < VerbStatus) (putMsg msg)++-- |Print a message on 'stdout'+putMsg :: MonadIO m => String -> m ()+putMsg msg = liftIO (putStrLn msg >> hFlush stdout)++-- |Print an error message on 'stderr'+putErrLn :: MonadIO m => String -> m ()+putErrLn msg = liftIO (hPutStrLn stderr msg >> hFlush stderr)++-- |Print a list of error messages on 'stderr'+putErrsLn :: MonadIO m => [String] -> m ()+putErrsLn = mapM_ putErrLn++-- |Print a list of 'String's as error messages on 'stderr'+-- and abort the program+abortWith :: [String] -> IO a+abortWith errs = putErrsLn errs >> exitFailure++-- |Print a single error message on 'stderr' and abort the program+abortWithMessage :: Message -> IO a+abortWithMessage msg = abortWithMessages [msg]++-- |Print a list of error messages on 'stderr' and abort the program+abortWithMessages :: [Message] -> IO a+abortWithMessages msgs = printMessages ppError msgs >> exitFailure++-- |Print a list of warning messages on 'stderr' and abort the program+-- |if the -Werror option is set+warnOrAbort :: WarnOpts -> [Message] -> IO ()+warnOrAbort opts msgs = when (wnWarn opts && not (null msgs)) $ do+  if wnWarnAsError opts+    then abortWithMessages (msgs ++ [message $ text "Failed due to -Werror"])+    else printMessages ppWarning msgs++-- |Print a list of messages on 'stderr'+printMessages :: (Message -> Doc) -> [Message] -> IO ()+printMessages msgType msgs+  = unless (null msgs) $ putErrLn (show $ ppMessages msgType $ sort msgs)++-- |Raise an internal error+internalError :: String -> a+internalError msg = error $ "Internal error: " ++ msg
+ src/Base/NestEnv.hs view
@@ -0,0 +1,120 @@+{- |+    Module      :  $Header$+    Description :  Nested Environments+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux+                       2011 - 2015 Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The 'NestEnv' environment type extends top-level environments  to manage+   nested scopes. Local scopes allow only for a single, unambiguous definition.++   As a matter of convenience, the module 'TopEnv' is exported by+   the module 'NestEnv'. Thus, only the latter needs to be imported.+-}++module Base.NestEnv+  ( module Base.TopEnv+  , NestEnv, emptyEnv, bindNestEnv, qualBindNestEnv+  , lookupNestEnv, qualLookupNestEnv+  , rebindNestEnv, qualRebindNestEnv+  , unnestEnv, toplevelEnv, globalEnv, nestEnv, elemNestEnv+  , qualModifyNestEnv, modifyNestEnv, localNestEnv, qualInLocalNestEnv+  ) where++import qualified Data.Map         as Map+import           Curry.Base.Ident++import Base.Messages (internalError)+import Base.TopEnv++data NestEnv a+  = GlobalEnv (TopEnv  a)+  | LocalEnv  (NestEnv a) (Map.Map Ident a)+    deriving Show++instance Functor NestEnv where+  fmap f (GlobalEnv     env) = GlobalEnv (fmap f  env)+  fmap f (LocalEnv genv env) = LocalEnv  (fmap f genv) (fmap f env)++globalEnv :: TopEnv a -> NestEnv a+globalEnv = GlobalEnv++emptyEnv :: NestEnv a+emptyEnv = globalEnv emptyTopEnv++nestEnv :: NestEnv a -> NestEnv a+nestEnv env = LocalEnv env Map.empty++unnestEnv :: NestEnv a -> NestEnv a+unnestEnv g@(GlobalEnv   _) = g+unnestEnv (LocalEnv genv _) = genv++toplevelEnv :: NestEnv a -> TopEnv a+toplevelEnv (GlobalEnv   env) = env+toplevelEnv (LocalEnv genv _) = toplevelEnv genv++bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a+bindNestEnv x y (GlobalEnv     env) = GlobalEnv $ bindTopEnv x y env+bindNestEnv x y (LocalEnv genv env) = case Map.lookup x env of+  Just  _ -> internalError $ "NestEnv.bindNestEnv: " ++ show x ++ " is already bound"+  Nothing -> LocalEnv genv $ Map.insert x y env++qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a+qualBindNestEnv x y (GlobalEnv     env) = GlobalEnv $ qualBindTopEnv x y env+qualBindNestEnv x y (LocalEnv genv env)+  | isQualified x = internalError $ "NestEnv.qualBindNestEnv " ++ show x+  | otherwise     = case Map.lookup x' env of+      Just  _ -> internalError $ "NestEnv.qualBindNestEnv " ++ show x+      Nothing -> LocalEnv genv $ Map.insert x' y env+    where x' = unqualify x++-- Rebinds a value to a variable, failes if the variable was unbound before+rebindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a+rebindNestEnv = qualRebindNestEnv . qualify++qualRebindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a+qualRebindNestEnv x y (GlobalEnv     env) = GlobalEnv $ qualRebindTopEnv x y env+qualRebindNestEnv x y (LocalEnv genv env)+  | isQualified x = internalError $ "NestEnv.qualRebindNestEnv " ++ show x+  | otherwise     = case Map.lookup x' env of+      Just  _ -> LocalEnv genv $ Map.insert x' y env+      Nothing -> LocalEnv (qualRebindNestEnv x y genv) env+    where x' = unqualify x++lookupNestEnv :: Ident -> NestEnv a -> [a]+lookupNestEnv x (GlobalEnv     env) = lookupTopEnv x env+lookupNestEnv x (LocalEnv genv env) = case Map.lookup x env of+  Just  y -> [y]+  Nothing -> lookupNestEnv x genv++qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]+qualLookupNestEnv x env+  | isQualified x = qualLookupTopEnv x $ toplevelEnv env+  | otherwise     = lookupNestEnv (unqualify x) env++elemNestEnv :: Ident -> NestEnv a -> Bool+elemNestEnv x env = not (null (lookupNestEnv x env))++-- Applies a function to a value binding, does nothing if the variable is unbound+modifyNestEnv :: (a -> a) -> Ident -> NestEnv a -> NestEnv a+modifyNestEnv f = qualModifyNestEnv f . qualify++qualModifyNestEnv :: (a -> a) -> QualIdent -> NestEnv a -> NestEnv a+qualModifyNestEnv f x env = case qualLookupNestEnv x env of+  []    -> env+  y : _ -> qualRebindNestEnv x (f y) env++-- Returns the variables and values bound on the bottom (meaning non-top) scope+localNestEnv :: NestEnv a -> [(Ident, a)]+localNestEnv (GlobalEnv env)  = localBindings env+localNestEnv (LocalEnv _ env) = Map.toList env++-- Returns wether the variable is bound on the bottom (meaning non-top) scope+qualInLocalNestEnv :: QualIdent -> NestEnv a -> Bool+qualInLocalNestEnv x (GlobalEnv  env) = qualElemTopEnv x env+qualInLocalNestEnv x (LocalEnv _ env) =    (not (isQualified x))+                                        && Map.member (unqualify x) env
+ src/Base/PrettyKinds.hs view
@@ -0,0 +1,22 @@+{- |+    Module      :  $Header$+    Description :  TODO+    Copyright   :  (c) 2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   TODO+-}++module Base.PrettyKinds where++import Curry.Base.Pretty++import Base.CurryKinds+import Base.Kinds++instance Pretty Kind where+  pPrint = ppKind
+ src/Base/PrettyTypes.hs view
@@ -0,0 +1,54 @@+{- |+    Module      :  $Header$+    Description :  TODO+    Copyright   :  (c) 2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   TODO+-}++module Base.PrettyTypes where++import Data.Maybe (fromMaybe)+import qualified Data.Set as Set (Set, toAscList)++import Curry.Base.Ident (identSupply)+import Curry.Base.Pretty+import Curry.Syntax.Pretty++import Base.CurryTypes+import Base.Types++instance Pretty Type where+  pPrint = ppTypeExpr 0 . fromType identSupply++instance Pretty Pred where+  pPrint = ppConstraint . fromPred identSupply++instance Pretty a => Pretty (Set.Set a) where+  pPrint = parens . list . map pPrint . Set.toAscList++instance Pretty PredType where+  pPrint = ppQualTypeExpr . fromPredType identSupply++instance Pretty DataConstr where+  pPrint (DataConstr i _ _ tys)      = pPrint i <+> hsep (map pPrint tys)+  pPrint (RecordConstr i _ _ ls tys) =     pPrint i+                                       <+> braces (hsep (punctuate comma pLs))+    where+      pLs = zipWith (\l ty -> pPrint l <+> colon <> colon <+> pPrint ty) ls tys++instance Pretty ClassMethod where+  pPrint (ClassMethod f mar pty) =     pPrint f+                                   <>  text "/" <> int (fromMaybe 0 mar)+                                   <+> colon <> colon <+> pPrint pty++instance Pretty TypeScheme where+  pPrint (ForAll _ ty) = pPrint ty++instance Pretty ExistTypeScheme where+  pPrint (ForAllExist _ _ ty) = pPrint ty
+ src/Base/SCC.hs view
@@ -0,0 +1,62 @@+{- |+    Module      :  $Header$+    Description :  Computation of strongly connected components+    Copyright   :  (c) 2000, 2002 - 2003 Wolfgang Lux+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   At various places in the compiler we had to partition a list of+   declarations into strongly connected components. The function+   'scc' computes this relation in two steps. First, the list is+   topologically sorted downwards using the 'defs' relation.+   Then the resulting list is sorted upwards using the 'uses' relation+   and partitioned into the connected components. Both relations+   are computed within this module using the bound and free names of each+   declaration.++   In order to avoid useless recomputations, the code in the module first+   decorates the declarations with their bound and free names and a+   unique number. The latter is only used to provide a trivial ordering+   so that the declarations can be used as set elements.+-}++module Base.SCC (scc) where++import qualified Data.Set as Set (empty, member, insert)++data Node a b = Node { key :: Int, bvs :: [b], fvs :: [b], node :: a }++instance Eq (Node a b) where+  n1 == n2 = key n1 == key n2++instance Ord (Node b a) where+  n1 `compare` n2 = key n1 `compare` key n2++-- |Computation of strongly connected components+scc :: Eq b => (a -> [b]) -- ^entities defined by node+            -> (a -> [b]) -- ^entities used by node+            -> [a]        -- ^list of nodes+            -> [[a]]      -- ^strongly connected components+scc bvs' fvs' = map (map node) . tsort' . tsort . zipWith wrap [0 ..]+  where wrap i n = Node i (bvs' n) (fvs' n) n++tsort :: Eq b => [Node a b] -> [Node a b]+tsort xs = snd (dfs xs Set.empty []) where+  dfs [] marks stack = (marks,stack)+  dfs (x : xs') marks stack+    | x `Set.member` marks = dfs xs' marks stack+    | otherwise = dfs xs' marks' (x : stack')+    where (marks',stack') = dfs (defs x) (x `Set.insert` marks) stack+          defs x1 = filter (any (`elem` fvs x1) . bvs) xs++tsort' :: Eq b => [Node a b] -> [[Node a b]]+tsort' xs = snd (dfs xs Set.empty []) where+  dfs [] marks stack = (marks,stack)+  dfs (x : xs') marks stack+    | x `Set.member` marks = dfs xs' marks stack+    | otherwise = dfs xs' marks' ((x : concat stack') : stack)+    where (marks',stack') = dfs (uses x) (x `Set.insert` marks) []+          uses x1 = filter (any (`elem` bvs x1) . fvs) xs
+ src/Base/Subst.hs view
@@ -0,0 +1,127 @@+{- |+    Module      :  $Header$+    Description :  General substitution implementation+    Copyright   :  (c) 2002 Wolfgang Lux+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The module Subst implements substitutions. A substitution+   sigma = {x_1 |-> t_1, ... ,x_n |-> t_n} is a finite mapping from+   (finitely many) variables x_1, ... ,x_n to some kind of expression+   or term.++   In order to implement substitutions efficiently,+   composed substitutions are marked with a boolean flag (see below).+-}++module Base.Subst+  ( Subst (..), IntSubst (..), idSubst, singleSubst, bindSubst, unbindSubst+  , substToList, compose, substVar', isubstVar, restrictSubstTo+  ) where++import qualified Data.Map as Map++-- |Data type for substitution+data Subst a b = Subst Bool (Map.Map a b)+  deriving Show++-- |Identity substitution+idSubst :: Subst a b+idSubst = Subst False Map.empty++-- |Convert a substitution to a list of replacements+substToList :: Subst v e -> [(v, e)]+substToList (Subst _ sigma) = Map.toList sigma++-- |Create a substitution for a single replacement+singleSubst :: Ord v => v -> e -> Subst v e+singleSubst v e = bindSubst v e idSubst++-- |Extend a substitution with a single replacement+bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e+bindSubst v e (Subst comp sigma) = Subst comp $ Map.insert v e sigma++-- |Remove a single replacement from a substitution+unbindSubst :: Ord v => v -> Subst v e -> Subst v e+unbindSubst v (Subst comp sigma) = Subst comp $ Map.delete v sigma++-- For any substitution we have the following definitions:+--     sigma(x)     = t_i   if x = x_i+--                    x    otherwise+--     Dom(sigma)   = {x_1, ... , x_n}+--     Codom(sigma) = {t_1, ... , t_n}+-- Note that obviously the set of variables must be a subset of the set+-- of expressions. Also it is usually possible to extend the substitution+-- to a homomorphism on the codomain of the substitution. This is+-- captured by the following class declaration:++-- class Ord v => Subst v e where+--   var :: v -> e+--   subst :: Subst v e -> e -> e++-- With the help of the injection 'var', we can then compute the+-- substitution for a variable sigma(v) and also the composition of+-- two substitutions sigma1 o sigma2(e) := sigma1(sigma2(e)).+-- A naive implementation of the composition were+--+--   compose sigma sigma' =+--     foldr (uncurry bindSubst) sigma (substToList (fmap (subst sigma) sigma'))+--+-- However, such an implementation is very inefficient because the+-- number of substiutions applied to a variable increases in+-- O(n) of the number of compositions.++-- A more efficient implementation is to apply 'subst' again to+-- the value substituted for a variable in Dom(sigma).+-- However, this is correct only as long as the result of the substitution+-- does not include any variables which are in Dom(sigma). For instance,+-- it is impossible to implement simple variable renamings in this way.++-- Therefore we use the simple strategy to apply 'subst' again+-- only in case of a substitution which was returned from 'compose'.++-- substVar :: Subst v e => Subst v e -> v -> e+-- substVar (Subst comp sigma) v = maybe (var v) subst' (Map.lookup v sigma)+--   where subst' = if comp then subst (Subst comp sigma) else id++-- |Compose two substitutions+compose :: Ord v => Subst v e -> Subst v e -> Subst v e+compose sigma sigma' =+  composed (foldr (uncurry bindSubst) sigma' (substToList sigma))+  where composed (Subst _ sigma'') = Subst True sigma''++-- Unfortunately Haskell does not (yet) support multi-parameter type+-- classes. For that reason we have to define a separate class for each+-- kind of variable type for these functions. We implement+-- 'substVar' as a function that takes the class functions as an+-- additional parameters. As an example for the use of this function the+-- module includes a class 'IntSubst' for substitution whose+-- domain are integer numbers.++-- |Apply a substitution to a variable+substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e)+          -> Subst v e -> v -> e+substVar' var subst (Subst comp sigma) v =+  maybe (var v) subst' (Map.lookup v sigma)+  where subst' = if comp then subst (Subst comp sigma) else id++-- |Type class for terms where variables are represented as 'Int's+class IntSubst e where+  -- |Construct a variable from an 'Int'+  ivar :: Int -> e+  -- |Apply a substitution to a term+  isubst :: Subst Int e -> e -> e++-- |Apply a substitution to a term with variables represented as 'Int's+isubstVar :: IntSubst e => Subst Int e -> Int -> e+isubstVar = substVar' ivar isubst++-- |The function 'restrictSubstTo' implements the restriction of a+-- substitution to a given subset of its domain.+restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e+restrictSubstTo vs (Subst comp sigma) =+  foldr (uncurry bindSubst) (Subst comp Map.empty)+        (filter ((`elem` vs) . fst) (Map.toList sigma))
+ src/Base/TopEnv.hs view
@@ -0,0 +1,181 @@+{- |+    Module      :  $Header$+    Description :  Top-Level Environments+    Copyright   :   1999 - 2003 Wolfgang Lux+                    2005        Martin Engelke+                    2011 - 2012 Björn Peemöller+                    2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    The module 'TopEnv' implements environments for qualified and+    possibly ambiguous identifiers. An identifier is ambiguous if two+    different entities are imported under the same name or if a local+    definition uses the same name as an imported entity. Following an idea+    presented in a paper by Diatchki, Jones and Hallgren (2002),+    an identifier is associated with a list of entities in order to handle+    ambiguous names properly.++    In general, two entities are considered equal if the names of their+    original definitions match. However, in the case of algebraic data+    types it is possible to hide some or all of their data constructors on+    import and export, respectively. In this case we have to merge both+    imports such that all data constructors which are visible through any+    import path are visible in the current module. The class+    Entity is used to handle this merge.++    The code in this module ensures that the list of entities returned by+    the functions 'lookupTopEnv' and 'qualLookupTopEnv' contains exactly one+    element for each imported entity regardless of how many times and+    from which module(s) it was imported. Thus, the result of these function+    is a list with exactly one element if and only if the identifier is+    unambiguous. The module names associated with an imported entity identify+    the modules from which the entity was imported.+-}++module Base.TopEnv+  ( -- * Data types+    TopEnv (..), Entity (..)+    -- * creation and insertion+  , emptyTopEnv, predefTopEnv, importTopEnv, qualImportTopEnv+  , bindTopEnv, qualBindTopEnv, rebindTopEnv+  , qualRebindTopEnv, unbindTopEnv, qualUnbindTopEnv+  , lookupTopEnv, qualLookupTopEnv, qualElemTopEnv+  , allImports, moduleImports, localBindings, allLocalBindings, allBindings+  , allEntities+  ) where++import           Control.Arrow        (second)+import qualified Data.Map      as Map+  (Map, empty, insert, findWithDefault, lookup, toList)++import Curry.Base.Ident+import Base.Messages (internalError)++class Entity a where+ origName :: a -> QualIdent+ merge    :: a -> a -> Maybe a+ merge x y+   | origName x == origName y = Just x+   | otherwise                = Nothing++data Source = Local | Import [ModuleIdent] deriving (Eq, Show)++-- |Top level environment+newtype TopEnv a = TopEnv { topEnvMap :: Map.Map QualIdent [(Source, a)] }+  deriving Show++instance Functor TopEnv where+  fmap f (TopEnv env) = TopEnv (fmap (map (second f)) env)++-- local helper+entities :: QualIdent -> Map.Map QualIdent [(Source, a)] -> [(Source, a)]+entities = Map.findWithDefault []++-- |Empty 'TopEnv'+emptyTopEnv :: TopEnv a+emptyTopEnv = TopEnv Map.empty++-- |Insert an 'Entity' into a 'TopEnv' as a predefined 'Entity'+predefTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a+predefTopEnv k v (TopEnv env) = case Map.lookup k env of+  Just  _ -> internalError $ "TopEnv.predefTopEnv " ++ show k+  Nothing -> TopEnv $ Map.insert k [(Import [], v)] env++-- |Insert an 'Entity' as unqualified into a 'TopEnv'+importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a+             -> TopEnv a+importTopEnv m x y env = addImport m (qualify x) y env++-- |Insert an 'Entity' as qualified into a 'TopEnv'+qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a+                 -> TopEnv a+qualImportTopEnv m x y env = addImport m (qualifyWith m x) y env++-- local helper+addImport :: Entity a => ModuleIdent -> QualIdent -> a -> TopEnv a+          -> TopEnv a+addImport m k v (TopEnv env) = TopEnv $+  Map.insert k (mergeImport v (entities k env)) env+  where+  mergeImport :: Entity a => a -> [(Source, a)] -> [(Source, a)]+  mergeImport y []                         = [(Import [m], y)]+  mergeImport y (loc@(Local    ,  _) : xs) = loc : mergeImport y xs+  mergeImport y (imp@(Import ms, y') : xs) = case merge y y' of+    Just y'' -> (Import (m : ms), y'') : xs+    Nothing  -> imp : mergeImport y xs++bindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a+bindTopEnv x y env = qualBindTopEnv (qualify x) y env++qualBindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a+qualBindTopEnv x y (TopEnv env)+  = TopEnv $ Map.insert x (bindLocal y (entities x env)) env+  where+  bindLocal y' ys+    | null [ y'' | (Local, y'') <- ys ] = (Local, y') : ys+    | otherwise = internalError $ "qualBindTopEnv " ++ show x++rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a+rebindTopEnv = qualRebindTopEnv . qualify++qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a+qualRebindTopEnv x y (TopEnv env) =+  TopEnv $ Map.insert x (rebindLocal (entities x env)) env+  where+  rebindLocal []                = internalError+                                $ "TopEnv.qualRebindTopEnv " ++ show x+  rebindLocal ((Local, _) : ys) = (Local, y) : ys+  rebindLocal (imported   : ys) = imported   : rebindLocal ys++unbindTopEnv :: Ident -> TopEnv a -> TopEnv a+unbindTopEnv x (TopEnv env) =+  TopEnv $ Map.insert x' (unbindLocal (entities x' env)) env+  where x' = qualify x+        unbindLocal [] = internalError $ "TopEnv.unbindTopEnv " ++ show x+        unbindLocal ((Local, _) : ys) = ys+        unbindLocal (imported   : ys) = imported : unbindLocal ys++qualUnbindTopEnv :: QualIdent -> TopEnv a -> TopEnv a+qualUnbindTopEnv x (TopEnv env) =+  TopEnv $ Map.insert x (unbind (entities x env)) env+  where unbind [] = internalError $ "TopEnv.qualUnbindTopEnv " ++ show x+        unbind _  = []++lookupTopEnv :: Ident -> TopEnv a -> [a]+lookupTopEnv = qualLookupTopEnv . qualify++qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]+qualLookupTopEnv x (TopEnv env) = map snd (entities x env)++qualElemTopEnv :: QualIdent -> TopEnv a -> Bool+qualElemTopEnv x env = not (null (qualLookupTopEnv x env))++allImports :: TopEnv a -> [(QualIdent, a)]+allImports (TopEnv env) =+  [ (x, y) | (x, ys) <- Map.toList env, (Import _, y) <- ys ]++unqualBindings :: TopEnv a -> [(Ident, (Source, a))]+unqualBindings (TopEnv env) =+  [ (x', y) | (x, ys) <- filter (not . isQualified . fst) (Map.toList env)+            , let x' = unqualify x, y <- ys]++moduleImports :: ModuleIdent -> TopEnv a -> [(Ident, a)]+moduleImports m env =+  [(x, y) | (x, (Import ms, y)) <- unqualBindings env, m `elem` ms]++localBindings :: TopEnv a -> [(Ident, a)]+localBindings env = [ (x, y) | (x, (Local, y)) <- unqualBindings env ]++allLocalBindings :: TopEnv a -> [(QualIdent, a)]+allLocalBindings (TopEnv env) = [ (x, y) | (x, ys)    <- Map.toList env+                                         , (Local, y) <- ys ]++allBindings :: TopEnv a -> [(QualIdent, a)]+allBindings (TopEnv env) = [(x, y) | (x, ys) <- Map.toList env, (_, y) <- ys]++allEntities :: TopEnv a -> [a]+allEntities (TopEnv env) = [ y | (_, ys) <- Map.toList env, (_, y) <- ys]
+ src/Base/TypeExpansion.hs view
@@ -0,0 +1,113 @@+{- |+    Module      :  $Header$+    Description :  Type expansion+    Copyright   :  (c) 2016 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module implements expansion of alias types in types and predicates.+-}++module Base.TypeExpansion+  ( module Base.TypeExpansion+  ) where++import qualified Data.Set.Extra as Set (map)++import Curry.Base.Ident+import Curry.Syntax++import Base.CurryTypes+import Base.Messages+import Base.Types+import Base.TypeSubst++import Env.Class+import Env.TypeConstructor++-- The function 'expandType' expands all type synonyms in a type+-- and also qualifies all type constructors with the name of the module+-- in which the type was defined. Similarly, 'expandPred' expands all+-- type synonyms in a predicate and also qualifies all class identifiers+-- with the name of the module in which the class was defined. The+-- function 'expandPredSet' minimizes the predicate set after expansion.++expandType :: ModuleIdent -> TCEnv -> Type -> Type+expandType m tcEnv ty = expandType' m tcEnv ty []++expandType' :: ModuleIdent -> TCEnv -> Type -> [Type] -> Type+expandType' m tcEnv (TypeConstructor     tc) tys =+  case qualLookupTypeInfo tc tcEnv of+    [DataType       tc' _ _ ] -> applyType (TypeConstructor tc') tys+    [RenamingType   tc' _ _ ] -> applyType (TypeConstructor tc') tys+    [AliasType    _ _   n ty] -> let (tys', tys'') = splitAt n tys+                                 in  applyType (expandAliasType tys' ty) tys''+    _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of+      [DataType       tc' _ _ ] -> applyType (TypeConstructor tc') tys+      [RenamingType   tc' _ _ ] -> applyType (TypeConstructor tc') tys+      [AliasType    _ _   n ty] -> let (tys', tys'') = splitAt n tys+                                   in  applyType (expandAliasType tys' ty) tys''+      _ -> internalError $ "Base.TypeExpansion.expandType: " ++ show tc+expandType' m tcEnv (TypeApply      ty1 ty2) tys =+  expandType' m tcEnv ty1 (expandType m tcEnv ty2 : tys)+expandType' _ _     tv@(TypeVariable      _) tys = applyType tv tys+expandType' _ _     tc@(TypeConstrained _ _) tys = applyType tc tys+expandType' m tcEnv (TypeArrow      ty1 ty2) tys =+  applyType (TypeArrow (expandType m tcEnv ty1) (expandType m tcEnv ty2)) tys+expandType' _ _     ts@(TypeSkolem        _) tys = applyType ts tys+expandType' m tcEnv (TypeForall      tvs ty) tys =+  applyType (TypeForall tvs (expandType m tcEnv ty)) tys++expandPred :: ModuleIdent -> TCEnv -> Pred -> Pred+expandPred m tcEnv (Pred qcls ty) = case qualLookupTypeInfo qcls tcEnv of+  [TypeClass ocls _ _] -> Pred ocls (expandType m tcEnv ty)+  _ -> case qualLookupTypeInfo (qualQualify m qcls) tcEnv of+    [TypeClass ocls _ _] -> Pred ocls (expandType m tcEnv ty)+    _ -> internalError $ "Base.TypeExpansion.expandPred: " ++ show qcls++expandPredSet :: ModuleIdent -> TCEnv -> ClassEnv -> PredSet -> PredSet+expandPredSet m tcEnv clsEnv = minPredSet clsEnv . Set.map (expandPred m tcEnv)++expandPredType :: ModuleIdent -> TCEnv -> ClassEnv -> PredType -> PredType+expandPredType m tcEnv clsEnv (PredType ps ty) =+  PredType (expandPredSet m tcEnv clsEnv ps) (expandType m tcEnv ty)++-- The functions 'expandMonoType' and 'expandPolyType' convert (qualified)+-- type expressions into (predicated) types and also expand all type synonyms+-- and qualify all type constructors during the conversion.++expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type+expandMonoType m tcEnv tvs = expandType m tcEnv . toType tvs++expandPolyType :: ModuleIdent -> TCEnv -> ClassEnv -> QualTypeExpr -> PredType+expandPolyType m tcEnv clsEnv =+  normalize 0 . expandPredType m tcEnv clsEnv . toPredType []++-- The function 'expandConstrType' computes the predicated type for a data+-- or newtype constructor. Similar to 'toConstrType' from 'CurryTypes', the+-- type's context is restricted to those type variables which are free in+-- the argument types. However, type synonyms are expanded and type constructors+-- and type classes are qualified with the name of the module containing their+-- definition.++expandConstrType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> [Ident]+                 -> Context -> [TypeExpr] -> PredType+expandConstrType m tcEnv clsEnv tc tvs cx tys =+  normalize n $ expandPredType m tcEnv clsEnv pty+  where n = length tvs+        pty = toConstrType tc tvs cx tys++-- The function 'expandMethodType' converts the type of a type class method+-- Similar to function 'toMethodType' from 'CurryTypes', the implicit class+-- constraint is added to the method's type and the class' type variable is+-- assigned index 0. However, type synonyms are expanded and type constructors+-- and type classes are qualified with the name of the module containing their+-- definition.++expandMethodType :: ModuleIdent -> TCEnv -> ClassEnv -> QualIdent -> Ident+                 -> QualTypeExpr -> PredType+expandMethodType m tcEnv clsEnv qcls tv =+  normalize 1 . expandPredType m tcEnv clsEnv . toMethodType qcls tv
+ src/Base/TypeSubst.hs view
@@ -0,0 +1,143 @@+{- |+    Module      :  $Header$+    Description :  Type substitution+    Copyright   :  (c) 2003 Wolfgang Lux+                       2016 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module implements substitutions on types.+-}++module Base.TypeSubst+  ( module Base.TypeSubst, idSubst, singleSubst, bindSubst, compose+  ) where++import           Data.List       (nub)+import           Data.Maybe      (fromMaybe)+import qualified Data.Set as Set (Set, map)++import Base.Subst+import Base.TopEnv+import Base.Types++import Env.Value (ValueInfo (..))++type TypeSubst = Subst Int Type++class SubstType a where+  subst :: TypeSubst -> a -> a++bindVar :: Int -> Type -> TypeSubst -> TypeSubst+bindVar tv ty = compose (bindSubst tv ty idSubst)++substVar :: TypeSubst -> Int -> Type+substVar = substVar' TypeVariable subst++instance (Ord a, SubstType a) => SubstType (Set.Set a) where+  subst sigma = Set.map (subst sigma)++instance SubstType a => SubstType [a] where+  subst sigma = map (subst sigma)++instance SubstType Type where+  subst sigma ty = subst' sigma ty []++subst' :: TypeSubst -> Type -> [Type] -> Type+subst' _     tc@(TypeConstructor   _) = foldl TypeApply tc+subst' sigma (TypeApply      ty1 ty2) = subst' sigma ty1 . (subst sigma ty2 :)+subst' sigma (TypeVariable        tv) = applyType (substVar sigma tv)+subst' sigma (TypeArrow      ty1 ty2) =+  foldl TypeApply (TypeArrow (subst sigma ty1) (subst sigma ty2))+subst' sigma (TypeConstrained tys tv) = case substVar sigma tv of+  TypeVariable tv' -> foldl TypeApply (TypeConstrained tys tv')+  ty               -> foldl TypeApply ty+subst' _     ts@(TypeSkolem        _) = foldl TypeApply ts+subst' sigma (TypeForall      tvs ty) =+  applyType (TypeForall tvs (subst sigma ty))++instance SubstType Pred where+  subst sigma (Pred qcls ty) = Pred qcls (subst sigma ty)++instance SubstType PredType where+  subst sigma (PredType ps ty) = PredType (subst sigma ps) (subst sigma ty)++instance SubstType TypeScheme where+  subst sigma (ForAll n ty) =+    ForAll n (subst (foldr unbindSubst sigma [0 .. n-1]) ty)++instance SubstType ExistTypeScheme where+  subst sigma (ForAllExist n n' ty) =+    ForAllExist n n' (subst (foldr unbindSubst sigma [0 .. n + n' - 1]) ty)++instance SubstType ValueInfo where+  subst _     dc@(DataConstructor  _ _ _ _) = dc+  subst _     nc@(NewtypeConstructor _ _ _) = nc+  subst theta (Value             v cm a ty) = Value v cm a (subst theta ty)+  subst theta (Label                l r ty) = Label l r (subst theta ty)++instance SubstType a => SubstType (TopEnv a) where+  subst = fmap . subst++-- The class method 'expandAliasType' expands all occurrences of a+-- type synonym in its second argument.++class ExpandAliasType a where+  expandAliasType :: [Type] -> a -> a++instance ExpandAliasType a => ExpandAliasType [a] where+  expandAliasType tys = map (expandAliasType tys)++instance (Ord a, ExpandAliasType a) => ExpandAliasType (Set.Set a) where+  expandAliasType tys = Set.map (expandAliasType tys)++instance ExpandAliasType Type where+  expandAliasType tys ty = expandAliasType' tys ty []++expandAliasType' :: [Type] -> Type -> [Type] -> Type+expandAliasType' _   tc@(TypeConstructor   _) = applyType tc+expandAliasType' tys (TypeApply      ty1 ty2) =+  expandAliasType' tys ty1 . (expandAliasType tys ty2 :)+expandAliasType' tys tv@(TypeVariable      n)+  | n >= 0    = applyType (tys !! n)+  | otherwise = applyType tv+expandAliasType' _   tc@(TypeConstrained _ _) = applyType tc+expandAliasType' tys (TypeArrow      ty1 ty2) =+  applyType (TypeArrow (expandAliasType tys ty1) (expandAliasType tys ty2))+expandAliasType' _   ts@(TypeSkolem        _) = applyType ts+expandAliasType' tys (TypeForall      tvs ty) =+  applyType (TypeForall tvs (expandAliasType tys ty))++instance ExpandAliasType Pred where+  expandAliasType tys (Pred qcls ty) = Pred qcls (expandAliasType tys ty)++instance ExpandAliasType PredType where+  expandAliasType tys (PredType ps ty) =+    PredType (expandAliasType tys ps) (expandAliasType tys ty)++-- After the expansion we have to reassign the type indices for all type+-- variables. Otherwise, expanding a type synonym like type 'Pair a b = (b,a)'+-- could break the invariant that the universally quantified type variables+-- are assigned indices in the order of their occurrence. This is handled by+-- the function 'normalize'. The function has a threshold parameter that allows+-- preserving the indices of type variables bound on the left hand side+-- of a type declaration and in the head of a type class declaration,+-- respectively.++normalize :: Int -> PredType -> PredType+normalize n ty = expandAliasType [TypeVariable (occur tv) | tv <- [0..]] ty+  where tvs = zip (nub (filter (>= n) (typeVars ty))) [n..]+        occur tv = fromMaybe tv (lookup tv tvs)++-- The function 'instanceType' computes an instance of a polymorphic type by+-- substituting the first type argument for all occurrences of the type+-- variable with index 0 in the second argument. The function carefully+-- assigns new indices to all other type variables of the second argument+-- so that they do not conflict with the type variables of the first argument.++instanceType :: ExpandAliasType a => Type -> a -> a+instanceType ty = expandAliasType (ty : map TypeVariable [n ..])+  where ForAll n _ = polyType ty
+ src/Base/Types.hs view
@@ -0,0 +1,511 @@+{- |+    Module      :  $Header$+    Description :  Internal representation of types+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux+                                   Martin Engelke+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module modules provides the definitions for the internal+   representation of types in the compiler along with some helper functions.+-}++-- TODO: Use MultiParamTypeClasses ?++module Base.Types+  ( -- * Representation of types+    Type (..), applyType, unapplyType, rootOfType+  , isArrowType, arrowArity, arrowArgs, arrowBase, arrowUnapply+  , IsType (..), typeConstrs+  , qualifyType, unqualifyType, qualifyTC+    -- * Representation of predicate, predicate sets and predicated types+  , Pred (..), qualifyPred, unqualifyPred+  , PredSet, emptyPredSet, partitionPredSet, minPredSet, maxPredSet+  , qualifyPredSet, unqualifyPredSet+  , PredType (..), predType, unpredType, qualifyPredType, unqualifyPredType+    -- * Representation of data constructors+  , DataConstr (..), constrIdent, constrTypes, recLabels, recLabelTypes+  , tupleData+    -- * Representation of class methods+  , ClassMethod (..), methodName, methodArity, methodType+    -- * Representation of quantification+  , TypeScheme (..), ExistTypeScheme (..), monoType, polyType, typeScheme+  , rawType+    -- * Predefined types+  , arrowType, unitType, predUnitType, boolType, predBoolType, charType+  , intType, predIntType, floatType, predFloatType, stringType, predStringType+  , listType, consType, ioType, tupleType+  , numTypes, fractionalTypes+  , predefTypes+  ) where++import qualified Data.Set.Extra as Set++import Curry.Base.Ident++import Base.Messages (internalError)++import Env.Class (ClassEnv, allSuperClasses)++-- ---------------------------------------------------------------------------+-- Types+-- ---------------------------------------------------------------------------++-- A type is either a type constructor, a type variable, an application+-- of a type to another type, or an arrow type. Although the latter could+-- be expressed by using 'TypeApply' with the function type constructor,+-- we currently use 'TypeArrow' because arrow types are used so frequently.++-- The 'TypeConstrained' case is used for representing type variables that+-- are restricted to a particular set of types. At present, this is used+-- for typing integer literals, which are restricted to types 'Int' and+-- 'Float'. If the type is not restricted, it defaults to the first type+-- from the constraint list.++-- The case 'TypeSkolem' is used for handling skolem types, which+-- result from the use of existentially quantified data constructors.++-- Type variables are represented with deBruijn style indices. Universally+-- quantified type variables are assigned indices in the order of their+-- occurrence in the type from left to right. This leads to a canonical+-- representation of types where alpha-equivalence of two types+-- coincides with equality of the representation.++-- Note that even though 'TypeConstrained' variables use indices+-- as well, these variables must never be quantified.++-- Note further that the order of constructors is important for the derived+-- 'Ord' instance. In particular, it is essential that the type variable+-- is considered less than the type application (see predicates and predicate+-- sets below for more information).++data Type+  = TypeConstructor QualIdent+  | TypeVariable Int+  | TypeConstrained [Type] Int+  | TypeSkolem Int+  | TypeApply Type Type+  | TypeArrow Type Type+  | TypeForall [Int] Type+  deriving (Eq, Ord, Show)++-- The function 'applyType' applies a type to a list of argument types,+-- whereas applications of the function type constructor to two arguments+-- are converted into an arrow type. The function 'unapplyType' decomposes+-- a type into a root type and a list of argument types.++applyType :: Type -> [Type] -> Type+applyType (TypeConstructor tc) tys+  | tc == qArrowId && length tys == 2 = TypeArrow (tys !! 0) (tys !! 1)+applyType (TypeApply (TypeConstructor tc) ty) tys+  | tc == qArrowId && length tys == 1 = TypeArrow ty (head tys)+applyType ty tys = foldl TypeApply ty tys++unapplyType :: Bool -> Type -> (Type, [Type])+unapplyType dflt ty = unapply ty []+  where+    unapply (TypeConstructor     tc) tys  = (TypeConstructor tc, tys)+    unapply (TypeApply      ty1 ty2) tys  = unapply ty1 (ty2 : tys)+    unapply (TypeVariable        tv) tys  = (TypeVariable tv, tys)+    unapply (TypeArrow      ty1 ty2) tys  =+      (TypeConstructor qArrowId, ty1 : ty2 : tys)+    unapply (TypeConstrained tys tv) tys'+      | dflt      = unapply (head tys) tys'+      | otherwise = (TypeConstrained tys tv, tys')+    unapply (TypeSkolem           k) tys  = (TypeSkolem k, tys)+    unapply (TypeForall     tvs ty') tys  = (TypeForall tvs ty', tys)++-- The function 'rootOfType' returns the name of the type constructor at the+-- root of a type. This function must not be applied to a type whose root is+-- a type variable or a skolem type.++rootOfType :: Type -> QualIdent+rootOfType ty = case fst (unapplyType True ty) of+  TypeConstructor tc -> tc+  _ -> internalError $ "Base.Types.rootOfType: " ++ show ty++-- The function 'isArrowType' checks whether a type is a function+-- type t_1 -> t_2 -> ... -> t_n. The function 'arrowArity' computes+-- the arity n of a function type, 'arrowArgs' computes the types+-- t_1 ... t_n-1 and 'arrowBase' returns the type t_n. 'arrowUnapply'+-- combines 'arrowArgs' and 'arrowBase' in one call.++isArrowType :: Type -> Bool+isArrowType (TypeArrow _ _) = True+isArrowType _               = False++arrowArity :: Type -> Int+arrowArity = length. arrowArgs++arrowArgs :: Type -> [Type]+arrowArgs = fst . arrowUnapply++arrowBase :: Type -> Type+arrowBase = snd. arrowUnapply++arrowUnapply :: Type -> ([Type], Type)+arrowUnapply (TypeArrow ty1 ty2) = (ty1 : tys, ty)+  where (tys, ty) = arrowUnapply ty2+arrowUnapply ty                  = ([], ty)++-- The function 'typeConstrs' returns a list of all type constructors+-- occuring in a type t.++typeConstrs :: Type -> [QualIdent]+typeConstrs ty = constrs ty [] where+  constrs (TypeConstructor  tc) tcs = tc : tcs+  constrs (TypeApply   ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)+  constrs (TypeVariable      _) tcs = tcs+  constrs (TypeConstrained _ _) tcs = tcs+  constrs (TypeArrow   ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)+  constrs (TypeSkolem        _) tcs = tcs+  constrs (TypeForall    _ ty') tcs = constrs ty' tcs++-- The methods 'typeVars' and 'typeSkolems' return a list of all type+-- variables and skolems occurring in a type t, respectively. Note that+-- 'TypeConstrained' variables are not included in the set of type+-- variables because they cannot be generalized.++class IsType t where+  typeVars :: t -> [Int]+  typeSkolems :: t -> [Int]++instance IsType Type where+  typeVars = typeVars'+  typeSkolems = typeSkolems'++typeVars' :: Type -> [Int]+typeVars' ty = vars ty [] where+  vars (TypeConstructor   _) tvs = tvs+  vars (TypeApply   ty1 ty2) tvs = vars ty1 (vars ty2 tvs)+  vars (TypeVariable     tv) tvs = tv : tvs+  vars (TypeConstrained _ _) tvs = tvs+  vars (TypeArrow   ty1 ty2) tvs = vars ty1 (vars ty2 tvs)+  vars (TypeSkolem        _) tvs = tvs+  vars (TypeForall tvs' ty') tvs = filter (`notElem` tvs') (typeVars' ty') ++ tvs++typeSkolems' :: Type -> [Int]+typeSkolems' ty = skolems ty [] where+  skolems (TypeConstructor   _) sks = sks+  skolems (TypeApply   ty1 ty2) sks = skolems ty1 (skolems ty2 sks)+  skolems (TypeVariable      _) sks = sks+  skolems (TypeConstrained _ _) sks = sks+  skolems (TypeArrow   ty1 ty2) sks = skolems ty1 (skolems ty2 sks)+  skolems (TypeSkolem        k) sks = k : sks+  skolems (TypeForall    _ ty') sks = skolems ty' sks++-- The functions 'qualifyType' and 'unqualifyType' add/remove the+-- qualification with a module identifier for type constructors.++qualifyType :: ModuleIdent -> Type -> Type+qualifyType m (TypeConstructor     tc) = TypeConstructor (qualifyTC m tc)+qualifyType m (TypeApply      ty1 ty2) =+  TypeApply (qualifyType m ty1) (qualifyType m ty2)+qualifyType _ tv@(TypeVariable      _) = tv+qualifyType m (TypeConstrained tys tv) =+  TypeConstrained (map (qualifyType m) tys) tv+qualifyType m (TypeArrow      ty1 ty2) =+  TypeArrow (qualifyType m ty1) (qualifyType m ty2)+qualifyType _ ts@(TypeSkolem        _) = ts+qualifyType m (TypeForall      tvs ty) = TypeForall tvs (qualifyType m ty)++unqualifyType :: ModuleIdent -> Type -> Type+unqualifyType m (TypeConstructor     tc) = TypeConstructor (qualUnqualify m tc)+unqualifyType m (TypeApply      ty1 ty2) =+  TypeApply (unqualifyType m ty1) (unqualifyType m ty2)+unqualifyType _ tv@(TypeVariable      _) = tv+unqualifyType m (TypeConstrained tys tv) =+  TypeConstrained (map (unqualifyType m) tys) tv+unqualifyType m (TypeArrow      ty1 ty2) =+  TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)+unqualifyType _ ts@(TypeSkolem        _) = ts+unqualifyType m (TypeForall      tvs ty) = TypeForall tvs (unqualifyType m ty)++qualifyTC :: ModuleIdent -> QualIdent -> QualIdent+qualifyTC m tc | isPrimTypeId tc = tc+               | otherwise       = qualQualify m tc++-- ---------------------------------------------------------------------------+-- Predicates+-- ---------------------------------------------------------------------------++data Pred = Pred QualIdent Type+  deriving (Eq, Show)++-- We provide a custom 'Ord' instance for predicates here where we consider+-- the type component of the predicate before the class component (see predicate+-- sets below for more information).++instance Ord Pred where+  Pred qcls1 ty1 `compare` Pred qcls2 ty2 = case ty1 `compare` ty2 of+    LT -> LT+    EQ -> qcls1 `compare` qcls2+    GT -> GT++instance IsType Pred where+  typeVars (Pred _ ty) = typeVars ty+  typeSkolems (Pred _ ty) = typeSkolems ty++qualifyPred :: ModuleIdent -> Pred -> Pred+qualifyPred m (Pred qcls ty) = Pred (qualQualify m qcls) (qualifyType m ty)++unqualifyPred :: ModuleIdent -> Pred -> Pred+unqualifyPred m (Pred qcls ty) =+  Pred (qualUnqualify m qcls) (unqualifyType m ty)++-- ---------------------------------------------------------------------------+-- Predicate sets+-- ---------------------------------------------------------------------------++-- A predicate set is an ordered set of predicates. This way, we do not+-- have to manually take care of duplicate predicates and have automatically+-- achieved a canonical representation (as only original names for type classes+-- are used). Having the order on types and predicates in mind, we have also+-- ensured that a class method's implicit class constraint is always the minimum+-- element of a method's predicate set, thus making it very easy to remove it.++type PredSet = Set.Set Pred++instance (IsType a, Ord a) => IsType (Set.Set a) where+  typeVars = concat . Set.toList . Set.map typeVars+  typeSkolems = concat . Set.toList . Set.map typeSkolems++emptyPredSet :: PredSet+emptyPredSet = Set.empty++partitionPredSet :: PredSet -> (PredSet, PredSet)+partitionPredSet = Set.partition $ \(Pred _ ty) -> isTypeVariable ty+  where+    isTypeVariable (TypeVariable _) = True+    isTypeVariable (TypeApply ty _) = isTypeVariable ty+    isTypeVariable _                = False++-- The function 'minPredSet' transforms a predicate set by removing all+-- predicates from the predicate set which are implied by other predicates+-- according to the super class hierarchy. Inversely, the function 'maxPredSet'+-- adds all predicates to a predicate set which are implied by the predicates+-- in the given predicate set.++minPredSet :: ClassEnv -> PredSet -> PredSet+minPredSet clsEnv ps =+  ps `Set.difference` Set.concatMap implied ps+  where implied (Pred cls ty) = Set.fromList+          [Pred cls' ty | cls' <- tail (allSuperClasses cls clsEnv)]++maxPredSet :: ClassEnv -> PredSet -> PredSet+maxPredSet clsEnv ps = Set.concatMap implied ps+  where implied (Pred cls ty) = Set.fromList+          [Pred cls' ty | cls' <- allSuperClasses cls clsEnv]++qualifyPredSet :: ModuleIdent -> PredSet -> PredSet+qualifyPredSet m = Set.map (qualifyPred m)++unqualifyPredSet :: ModuleIdent -> PredSet -> PredSet+unqualifyPredSet m = Set.map (unqualifyPred m)++-- ---------------------------------------------------------------------------+-- Predicated types+-- ---------------------------------------------------------------------------++data PredType = PredType PredSet Type+  deriving (Eq, Show)++-- When enumarating the type variables and skolems of a predicated type, we+-- consider the type variables occuring in the predicate set after the ones+-- occuring in the type itself.++instance IsType PredType where+  typeVars (PredType ps ty) = typeVars ty ++ typeVars ps+  typeSkolems (PredType ps ty) = typeSkolems ty ++ typeSkolems ps++predType :: Type -> PredType+predType = PredType emptyPredSet++unpredType :: PredType -> Type+unpredType (PredType _ ty) = ty++qualifyPredType :: ModuleIdent -> PredType -> PredType+qualifyPredType m (PredType ps ty) =+  PredType (qualifyPredSet m ps) (qualifyType m ty)++unqualifyPredType :: ModuleIdent -> PredType -> PredType+unqualifyPredType m (PredType ps ty) =+  PredType (unqualifyPredSet m ps) (unqualifyType m ty)++-- ---------------------------------------------------------------------------+-- Data constructors+-- ---------------------------------------------------------------------------++-- The type 'DataConstr' is used to represent value or record constructors+-- introduced by data or newtype declarations. The 'Int' denotes the number+-- of existentially quantified type variables in the types.++data DataConstr = DataConstr   Ident Int PredSet [Type]+                | RecordConstr Ident Int PredSet [Ident] [Type]+  deriving (Eq, Show)++constrIdent :: DataConstr -> Ident+constrIdent (DataConstr     c _ _ _) = c+constrIdent (RecordConstr c _ _ _ _) = c++constrTypes :: DataConstr -> [Type]+constrTypes (DataConstr     _ _ _ tys) = tys+constrTypes (RecordConstr _ _ _ _ tys) = tys++recLabels :: DataConstr -> [Ident]+recLabels (DataConstr      _ _ _ _) = []+recLabels (RecordConstr _ _ _ ls _) = ls++recLabelTypes :: DataConstr -> [Type]+recLabelTypes (DataConstr       _ _ _ _) = []+recLabelTypes (RecordConstr _ _ _ _ tys) = tys++tupleData :: [DataConstr]+tupleData = [DataConstr (tupleId n) 0 emptyPredSet (take n tvs) | n <- [2 ..]]+  where tvs = map TypeVariable [0 ..]++-- ---------------------------------------------------------------------------+-- Class methods+-- ---------------------------------------------------------------------------++-- The type 'ClassMethod' is used to represent class methods introduced+-- by class declarations. The 'Maybe Int' denotes the arity of the provided+-- default implementation.++data ClassMethod = ClassMethod Ident (Maybe Int) PredType+  deriving (Eq, Show)++methodName :: ClassMethod -> Ident+methodName (ClassMethod f _ _) = f++methodArity :: ClassMethod -> Maybe Int+methodArity (ClassMethod _ a _) = a++methodType :: ClassMethod -> PredType+methodType (ClassMethod _ _ pty) = pty++-- ---------------------------------------------------------------------------+-- Quantification+-- ---------------------------------------------------------------------------++-- We support two kinds of quantifications of types here, universally+-- quantified type schemes (forall alpha . tau(alpha)) and universally+-- and existentially quantified type schemes+-- (forall alpha exists eta . tau(alpha,eta)). In both, quantified type+-- variables are assigned ascending indices starting from 0. Therefore it+-- is sufficient to record the numbers of quantified type variables in+-- the 'ForAll' and 'ForAllExist' constructors. In case of+-- the latter, the first of the two numbers is the number of universally+-- quantified variables and the second the number of existentially+-- quantified variables.++data TypeScheme = ForAll Int PredType deriving (Eq, Show)+data ExistTypeScheme = ForAllExist Int Int PredType deriving (Eq, Show)++instance IsType TypeScheme where+  typeVars (ForAll _ pty) = [tv | tv <- typeVars pty, tv < 0]+  typeSkolems (ForAll _ pty) = typeSkolems pty++instance IsType ExistTypeScheme where+  typeVars (ForAllExist _ _ pty) = [tv | tv <- typeVars pty, tv < 0]+  typeSkolems (ForAllExist _ _ pty) = typeSkolems pty++-- The functions 'monoType' and 'polyType' translate a type tau into a+-- monomorphic type scheme and a polymorphic type scheme, respectively.+-- 'polyType' assumes that all universally quantified variables in the type are+-- assigned indices starting with 0 and does not renumber the variables.++monoType :: Type -> TypeScheme+monoType = ForAll 0 . predType++polyType :: Type -> TypeScheme+polyType = typeScheme . predType++typeScheme :: PredType -> TypeScheme+typeScheme pty = ForAll (maximum (-1 : typeVars pty) + 1) pty++-- The function 'rawType' strips the quantifier and predicate set from a+-- type scheme.++rawType :: TypeScheme -> Type+rawType (ForAll _ (PredType _ ty)) = ty++-- ---------------------------------------------------------------------------+-- Predefined types+-- ---------------------------------------------------------------------------++primType :: QualIdent -> [Type] -> Type+primType = applyType . TypeConstructor++arrowType :: Type -> Type -> Type+arrowType ty1 ty2 = primType qArrowId [ty1, ty2]++unitType :: Type+unitType = primType qUnitId []++predUnitType :: PredType+predUnitType = predType unitType++boolType :: Type+boolType = primType qBoolId []++predBoolType :: PredType+predBoolType = predType boolType++charType :: Type+charType = primType qCharId []++intType :: Type+intType = primType qIntId []++predIntType :: PredType+predIntType = predType intType++floatType :: Type+floatType = primType qFloatId []++predFloatType :: PredType+predFloatType = predType floatType++stringType :: Type+stringType = listType charType++predStringType :: PredType+predStringType = predType stringType++listType :: Type -> Type+listType ty = primType qListId [ty]++consType :: Type -> Type+consType ty = TypeArrow ty (TypeArrow (listType ty) (listType ty))++ioType :: Type -> Type+ioType ty = primType qIOId [ty]++tupleType :: [Type] -> Type+tupleType tys = primType (qTupleId (length tys)) tys++-- 'numTypes' and 'fractionalTypes' define the eligible types for+-- numeric literals in patterns.++numTypes :: [Type]+numTypes = [intType, floatType]++fractionalTypes :: [Type]+fractionalTypes = drop 1 numTypes++predefTypes :: [(Type, [DataConstr])]+predefTypes =+  [ (arrowType a b, [])+  , (unitType     , [ DataConstr unitId 0 emptyPredSet [] ])+  , (listType a   , [ DataConstr nilId  0 emptyPredSet []+                    , DataConstr consId 0 emptyPredSet [a, listType a]+                    ])+  ]+  where a = TypeVariable 0+        b = TypeVariable 1
+ src/Base/Typing.hs view
@@ -0,0 +1,192 @@+{- |+    Module      :  $Header$+    Description :  Type computation of Curry expressions+    Copyright   :  (c) 2003 - 2006 Wolfgang Lux+                       2014 - 2015 Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    After the compiler has attributed patterns and expressions with type+    information during type inference, it is straightforward to recompute+    the type of every pattern and expression. Since all annotated types+    are monomorphic, there is no need to instantiate any variables or+    perform any (non-trivial) unifications.+-}++module Base.Typing+  ( Typeable (..)+  , withType, matchType+  , bindDecls, bindDecl, bindPatterns, bindPattern, declVars, patternVars+  ) where++import Data.List (nub)+import Data.Maybe (fromMaybe)++import Curry.Base.Ident+import Curry.Syntax++import Base.Messages (internalError)+import Base.Types+import Base.TypeSubst+import Base.Utils (fst3)++import Env.Value++class Typeable a where+  typeOf :: a -> Type++instance Typeable Type where+  typeOf = id++instance Typeable PredType where+  typeOf = unpredType++instance Typeable a => Typeable (Rhs a) where+  typeOf (SimpleRhs _ e _) = typeOf e+  typeOf (GuardedRhs es _) = head [typeOf e | CondExpr _ _ e <- es]++instance Typeable a => Typeable (Pattern a) where+  typeOf (LiteralPattern a _) = typeOf a+  typeOf (NegativePattern a _) = typeOf a+  typeOf (VariablePattern a _) = typeOf a+  typeOf (ConstructorPattern a _ _) = typeOf a+  typeOf (InfixPattern a _ _ _) = typeOf a+  typeOf (ParenPattern t) = typeOf t+  typeOf (RecordPattern a _ _) = typeOf a+  typeOf (TuplePattern ts) = tupleType $ map typeOf ts+  typeOf (ListPattern a _) = typeOf a+  typeOf (AsPattern _ t) = typeOf t+  typeOf (LazyPattern t) = typeOf t+  typeOf (FunctionPattern a _ _) = typeOf a+  typeOf (InfixFuncPattern a _ _ _) = typeOf a++instance Typeable a => Typeable (Expression a) where+  typeOf (Literal a _) = typeOf a+  typeOf (Variable a _) = typeOf a+  typeOf (Constructor a _) = typeOf a+  typeOf (Paren e) = typeOf e+  typeOf (Typed e _) = typeOf e+  typeOf (Record a _ _) = typeOf a+  typeOf (RecordUpdate e _) = typeOf e+  typeOf (Tuple es) = tupleType (map typeOf es)+  typeOf (List a _) = typeOf a+  typeOf (ListCompr e _) = listType (typeOf e)+  typeOf (EnumFrom e) = listType (typeOf e)+  typeOf (EnumFromThen e _) = listType (typeOf e)+  typeOf (EnumFromTo e _) = listType (typeOf e)+  typeOf (EnumFromThenTo e _ _) = listType (typeOf e)+  typeOf (UnaryMinus e) = typeOf e+  typeOf (Apply e _) = case typeOf e of+    TypeArrow _ ty -> ty+    _ -> internalError "Base.Typing.typeOf: application"+  typeOf (InfixApply _ op _) = case typeOf (infixOp op) of+    TypeArrow _ (TypeArrow _ ty) -> ty+    _ -> internalError "Base.Typing.typeOf: infix application"+  typeOf (LeftSection _ op) = case typeOf (infixOp op) of+    TypeArrow _ ty -> ty+    _ -> internalError "Base.Typing.typeOf: left section"+  typeOf (RightSection op _) = case typeOf (infixOp op) of+    TypeArrow ty1 (TypeArrow _ ty2) -> TypeArrow ty1 ty2+    _ -> internalError "Base.Typing.typeOf: right section"+  typeOf (Lambda ts e) = foldr (TypeArrow . typeOf) (typeOf e) ts+  typeOf (Let _ e) = typeOf e+  typeOf (Do _ e) = typeOf e+  typeOf (IfThenElse _ e _) = typeOf e+  typeOf (Case _ _ as) = typeOf $ head as++instance Typeable a => Typeable (Alt a) where+  typeOf (Alt _ _ rhs) = typeOf rhs++-- When inlining variable and function definitions, the compiler must+-- eventually update the type annotations of the inlined expression. To+-- that end, the variable or function's annotated type and the type of+-- the inlined expression must be unified. Since the program is type+-- correct, this unification is just a simple one way matching where we+-- only need to match the type variables in the inlined expression's type+-- with the corresponding types in the variable or function's annotated+-- type.++withType :: (Functor f, Typeable (f Type)) => Type -> f Type -> f Type+withType ty e = fmap (subst (matchType (typeOf e) ty idSubst)) e++matchType :: Type -> Type -> TypeSubst -> TypeSubst+matchType ty1 ty2 = fromMaybe noMatch (matchType' ty1 ty2)+  where+    noMatch = internalError $ "Base.Typing.matchType: " +++                                showsPrec 11 ty1 " " ++ showsPrec 11 ty2 ""++matchType' :: Type -> Type -> Maybe (TypeSubst -> TypeSubst)+matchType' (TypeVariable tv) ty+  | ty == TypeVariable tv = Just id+  | otherwise = Just (bindSubst tv ty)+matchType' (TypeConstructor tc1) (TypeConstructor tc2)+  | tc1 == tc2 = Just id+matchType' (TypeConstrained _ tv1) (TypeConstrained _ tv2)+  | tv1 == tv2 = Just id+matchType' (TypeSkolem k1) (TypeSkolem k2)+  | k1 == k2 = Just id+matchType' (TypeApply ty11 ty12) (TypeApply ty21 ty22) =+  fmap (. matchType ty12 ty22) (matchType' ty11 ty21)+matchType' (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =+  Just (matchType ty11 ty21 . matchType ty12 ty22)+matchType' (TypeApply ty11 ty12) (TypeArrow ty21 ty22) =+  fmap (. matchType ty12 ty22)+       (matchType' ty11 (TypeApply (TypeConstructor qArrowId) ty21))+matchType' (TypeArrow ty11 ty12) (TypeApply ty21 ty22) =+  fmap (. matchType ty12 ty22)+       (matchType' (TypeApply (TypeConstructor qArrowId) ty11) ty21)+matchType' (TypeForall _ ty1) (TypeForall _ ty2) = matchType' ty1 ty2+matchType' (TypeForall _ ty1) ty2 = matchType' ty1 ty2+matchType' ty1 (TypeForall _ ty2) = matchType' ty1 ty2+matchType' _ _ = Nothing++-- The functions 'bindDecls', 'bindDecl', 'bindPatterns' and 'bindPattern'+-- augment the value environment with the types of the entities defined in+-- local declaration groups and patterns, respectively, using the types from+-- their type annotations.++bindDecls :: (Eq t, Typeable t, ValueType t) => [Decl t] -> ValueEnv -> ValueEnv+bindDecls = flip $ foldr bindDecl++bindDecl :: (Eq t, Typeable t, ValueType t) => Decl t -> ValueEnv -> ValueEnv+bindDecl d vEnv = bindLocalVars (filter unbound $ declVars d) vEnv+  where unbound v = null $ lookupValue (fst3 v) vEnv++bindPatterns :: (Eq t, Typeable t, ValueType t) => [Pattern t] -> ValueEnv+             -> ValueEnv+bindPatterns = flip $ foldr bindPattern++bindPattern :: (Eq t, Typeable t, ValueType t) => Pattern t -> ValueEnv+            -> ValueEnv+bindPattern t vEnv = bindLocalVars (filter unbound $ patternVars t) vEnv+  where unbound v = null $ lookupValue (fst3 v) vEnv++declVars :: (Eq t, Typeable t, ValueType t) => Decl t -> [(Ident, Int, t)]+declVars (InfixDecl        _ _ _ _) = []+declVars (TypeSig            _ _ _) = []+declVars (FunctionDecl  _ ty f eqs) = [(f, eqnArity $ head eqs, ty)]+declVars (PatternDecl        _ t _) = patternVars t+declVars (FreeDecl            _ vs) = [(v, 0, ty) | Var ty v <- vs]+declVars _                          = internalError "Base.Typing.declVars"++patternVars :: (Eq t, Typeable t, ValueType t) => Pattern t -> [(Ident, Int, t)]+patternVars (LiteralPattern         _ _) = []+patternVars (NegativePattern        _ _) = []+patternVars (VariablePattern       ty v) = [(v, 0, ty)]+patternVars (ConstructorPattern  _ _ ts) = concatMap patternVars ts+patternVars (InfixPattern     _ t1 _ t2) = patternVars t1 ++ patternVars t2+patternVars (ParenPattern             t) = patternVars t+patternVars (RecordPattern       _ _ fs) =+  concat [patternVars t | Field _ _ t <- fs]+patternVars (TuplePattern            ts) = concatMap patternVars ts+patternVars (ListPattern           _ ts) = concatMap patternVars ts+patternVars (AsPattern              v t) =+  (v, 0, toValueType $ typeOf t) : patternVars t+patternVars (LazyPattern              t) = patternVars t+patternVars (FunctionPattern     _ _ ts) = nub $ concatMap patternVars ts+patternVars (InfixFuncPattern _ t1 _ t2) =+  nub $ patternVars t1 ++ patternVars t2
+ src/Base/Utils.hs view
@@ -0,0 +1,94 @@+{- |+    Module      :  $Header$+    Description :  Auxiliary functions+    Copyright   :  (c) 2001 - 2003 Wolfgang Lux+                       2011 - 2015 Björn Peemöler+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  fte@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The module Utils provides a few simple functions that are+   commonly used in the compiler, but not implemented in the Haskell+   Prelude or standard library.+-}++module Base.Utils+  ( fst3, snd3, thd3, curry3, uncurry3+  , (++!), foldr2, mapAccumM, findDouble, findMultiples+  ) where++import Control.Monad (MonadPlus, mzero, mplus)++import Data.List     (partition)++infixr 5 ++!++-- The Prelude does not contain standard functions for triples.+-- We provide projection, (un-)currying, and mapping for triples here.++fst3 :: (a, b, c) -> a+fst3 (x, _, _) = x++snd3 :: (a, b, c) -> b+snd3 (_, y, _) = y++thd3 :: (a, b, c) -> c+thd3 (_, _, z) = z++curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d+curry3 f x y z = f (x,y,z)++uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d+uncurry3 f (x, y, z) = f x y z++-- The function (++!) is variant of the list concatenation operator (++)+-- that ignores the second argument if the first is a non-empty list.+-- When lists are used to encode non-determinism in Haskell,+-- this operator has the same effect as the cut operator in Prolog,+-- hence the ! in the name.++(++!) :: [a] -> [a] -> [a]+xs ++! ys = if null xs then ys else xs++-- Fold operations with two arguments lists can be defined using+-- zip and foldl or foldr, resp. Our definitions are unfolded for+-- efficiency reasons.++-- foldl2 :: (a -> b -> c -> a) -> a -> [b] -> [c] -> a+-- foldl2 _ z []       _        = z+-- foldl2 _ z _        []       = z+-- foldl2 f z (x : xs) (y : ys) = foldl2 f (f z x y) xs ys++foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c+foldr2 _ z []       _        = z+foldr2 _ z _        []       = z+foldr2 f z (x : xs) (y : ys) = f x y (foldr2 f z xs ys)++mapAccumM :: (Monad m, MonadPlus p) => (acc -> x -> m (acc, y)) -> acc -> [x]+          -> m (acc, p y)+mapAccumM _ z [] = return (z, mzero)+mapAccumM f z (x:xs) = do+  (z', y) <- f z x+  (z'', ys) <- mapAccumM f z' xs+  return (z'', return y `mplus` ys)++-- The function 'findDouble' checks whether a list of entities is linear,+-- i.e., if every entity in the list occurs only once. If it is non-linear,+-- the first offending object is returned.++findDouble :: Eq a => [a] -> Maybe a+findDouble []   = Nothing+findDouble (x : xs)+  | x `elem` xs = Just x+  | otherwise   = findDouble xs++findMultiples :: Eq a => [a] -> [[a]]+findMultiples []       = []+findMultiples (x : xs)+  | null same = multiples+  | otherwise = (x : same) : multiples+  where (same, other) = partition (==x) xs+        multiples     = findMultiples other
− src/CaseCompletion.hs
@@ -1,662 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- CaseCompletion - expands case branches with missing constructors------ The MMC translates case expressions into the intermediate language--- representation (IL) without completing them (i.e. without generating--- case branches for missing contructors). Because they are necessary for--- the PAKCS back end this module expands all case expressions accordingly.------ May 2005,--- Martin Engelke, (men@informatik.uni-kiel.de)--- -module CaseCompletion (completeCase) where--import Data.Maybe--import Curry.Base.Position (SrcRef)-import Curry.Base.Ident-import qualified Curry.Syntax--import Base (ModuleEnv, lookupModule)-import IL.Type-import OldScopeEnv -- as ScopeEnv-import IL.Scope--------------------------------------------------------------------------------------- Completes case expressions by adding branches for missing constructors.--- The module environment 'menv' is needed to compute these constructors.------ Call:---      completeCase <module environment>---                   <IL module>----completeCase :: ModuleEnv -> Module -> Module-completeCase menv mod = let (mod', _) = visitModule menv mod in mod'------------------------------------------------------------------------------------- The following functions run through an IL term searching for--- case expressions-----visitModule :: ModuleEnv -> Module -> (Module, [Message])-visitModule menv (Module mident imports decls)-   = ((Module mident (insertUnique preludeMIdent imports) decls'), msgs')- where-   (decls', msgs') = visitList (visitDecl (Module mident imports decls) menv)-		               insertDeclScope-			       []-			       (getModuleScope (Module mident imports decls))-			       decls------visitDecl :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Decl-	     -> (Decl, [Message])-visitDecl mod menv msgs senv (DataDecl qident arity cdecls)-   = ((DataDecl qident arity cdecls), msgs)--visitDecl mod menv msgs senv (NewtypeDecl qident arity cdecl)-   = ((NewtypeDecl qident arity cdecl), msgs)--visitDecl mod menv msgs senv (FunctionDecl qident params typeexpr expr)-   = ((FunctionDecl qident params typeexpr expr'), msgs)- where-   (expr', _, _) = visitExpr mod menv msgs (insertExprScope senv expr) expr--visitDecl mod menv msgs senv (ExternalDecl qident cconv name typeexpr)-   = ((ExternalDecl qident cconv name typeexpr), msgs)------visitExpr :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Expression -	     -> (Expression, [Message],ScopeEnv)-visitExpr mod menv msgs senv (Literal lit) -   = ((Literal lit), msgs, senv)--visitExpr mod menv msgs senv (Variable ident) -   = ((Variable ident), msgs, senv)--visitExpr mod menv msgs senv (Function qident arity) -   = ((Function qident arity), msgs, senv)--visitExpr mod menv msgs senv (Constructor qident arity)-   = ((Constructor qident arity), msgs, senv)--visitExpr mod menv msgs senv (Apply expr1 expr2)-   = ((Apply expr1' expr2'), msgs2, senv2)- where-   (expr1', msgs1, senv1) = visitExpr mod menv msgs (insertExprScope senv expr1) expr1-   (expr2', msgs2, senv2) = visitExpr mod menv msgs1 (insertExprScope senv1 expr2) expr2--visitExpr mod menv msgs senv (Case r evalannot expr alts)-   | null altsR-     = intError "visitExpr" "empty alternative list"-   | evalannot == Flex   -- pattern matching causes flexible case expressions-     = (Case r evalannot expr' altsR, msgs, senv1)-   | isConstrAlt altR-     = (expr2, msgs3, senv3)-   | isLitAlt altR-     = (completeLitAlts r evalannot expr' altsR, msgs3, senv2)-   | isVarAlt altR-     = (completeVarAlts expr' altsR, msgs3, senv2)-   | otherwise -     = intError "visitExpr" "illegal alternative list"- where-   altR           = head altsR-   (expr', _, senv1) = visitExpr mod menv msgs (insertExprScope senv expr) expr-   (alts', _, senv2) = visitListWithEnv (visitAlt mod menv) insertAltScope msgs senv1 alts-   (altsR, msgs3) = removeRedundantAlts msgs alts'-   (expr2, senv3) = completeConsAlts r mod menv senv2 evalannot expr' altsR--visitExpr mod menv msgs senv (Or expr1 expr2)-   = ((Or expr1' expr2'), msgs2, senv3)- where-   (expr1', msgs1, senv2) = visitExpr mod menv msgs (insertExprScope senv expr1) expr1-   (expr2', msgs2, senv3) = visitExpr mod menv msgs1 (insertExprScope senv2 expr2) expr2--visitExpr mod menv msgs senv (Exist ident expr)-   = ((Exist ident expr'), msgs', senv2)- where-   (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr--visitExpr mod menv msgs senv (Let bind expr)-   = ((Let bind' expr'), msgs2, senv3)- where-   (expr', _, senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr-   (bind', msgs2, senv3) = visitBinding mod menv msgs (insertBindingScope senv2 bind) bind--visitExpr mod menv msgs senv (Letrec binds expr)-   = ((Letrec binds' expr'), msgs2, senv3)- where-   (expr', msgs1, senv2)  = visitExpr mod menv msgs (insertExprScope senv expr) expr-   (binds', msgs2, senv3) = visitListWithEnv (visitBinding mod menv)-		               const-			       msgs1-			       (foldl insertBindingScope senv2 binds)-			       binds------visitAlt :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Alt -	    -> (Alt, [Message], ScopeEnv)-visitAlt mod menv msgs senv (Alt pattern expr)-   = ((Alt pattern expr'), msgs', senv2)- where-   (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr------visitBinding :: Module -> ModuleEnv -> [Message] -> ScopeEnv -> Binding -	        -> (Binding, [Message], ScopeEnv)-visitBinding mod menv msgs senv (Binding ident expr)-   = ((Binding ident expr'), msgs', senv2)- where-   (expr', msgs', senv2) = visitExpr mod menv msgs (insertExprScope senv expr) expr------visitList :: ([Message] -> ScopeEnv -> a -> (a, [Message]))-	     -> (ScopeEnv -> a -> ScopeEnv)-	     -> [Message] -> ScopeEnv -> [a]-	     -> ([a], [Message])-visitList visitTerm insertScope msgs senv []-   = ([], msgs)-visitList visitTerm insertScope msgs senv (term:terms)-   = ((term':terms'), msgs2)- where-   (term', msgs1)  = visitTerm msgs (insertScope senv term) term-   (terms', msgs2) = visitList visitTerm insertScope msgs1 senv terms--visitListWithEnv :: ([Message] -> ScopeEnv -> a -> (a, [Message], ScopeEnv))-	     -> (ScopeEnv -> a -> ScopeEnv)-	     -> [Message] -> ScopeEnv -> [a]-	     -> ([a], [Message], ScopeEnv)-visitListWithEnv visitTerm insertScope msgs senv []-   = ([], msgs, senv)-visitListWithEnv visitTerm insertScope msgs senv (term:terms)-   = ((term':terms'), msgs2, senv3)- where-   (term', msgs1, senv2)  = visitTerm msgs (insertScope senv term) term-   (terms', msgs2, senv3) = visitListWithEnv visitTerm insertScope msgs1 senv2 terms-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Functions for completing case alternatives---- Completes a case alternative list which branches via constructor patterns--- by adding alternatives of the form------      comp_pattern -> default_expr------ where "comp_pattern" is a complementary constructor pattern and--- "default_expr" is the expression from the first alternative containing--- a variable pattern. If there is no such alternative the defualt expression--- is set to the prelude function 'failed'.------ This funtions uses a scope environment ('ScopeEnv') to generate fresh--- variables for the arguments of the new constructors.----completeConsAlts :: SrcRef -> Module -> ModuleEnv -> ScopeEnv -		    -> Eval -> Expression -> [Alt]-		    -> (Expression, ScopeEnv)-completeConsAlts r mod menv senv evalannot expr alts-   = (Case r evalannot expr (alts1 ++ alts2), senv2)- where-   (Alt varpatt defaultexpr) = getDefaultAlt alts-   (VariablePattern varid)   = varpatt-   alts1       = filter isConstrAlt alts-   constrs     = (map p_getConsAltIdent alts1)-   cconsinfos  = getComplConstrs mod menv constrs-   (cconstrs,senv2) = -                 foldr p_genConstrTerm-                       ([],senv) -                       cconsinfos-   alts2       = map (\cconstr -> -		      (Alt cconstr -		        (replaceVar varid (cterm2expr cconstr) defaultexpr))) -		     cconstrs--   p_getConsAltIdent (Alt (ConstructorPattern qident _) _) = qident--   p_genConstrTerm (qident, arity) (cconstrs,senv3) =-       let args = OldScopeEnv.genIdentList arity "x" senv3-           senv4 = foldr OldScopeEnv.insertIdent senv3 args-       in (ConstructorPattern qident args : cconstrs, senv4)----- If the alternatives branches via literal pattern complementary--- constructor list cannot be generated because it would become infinite.--- So the function 'completeLitAlts' transforms case expressions like---      case <cexpr> of---        <lit_1> -> <expr_1>---        <lit_2> -> <expr_2>---                    :---        <lit_n> -> <expr_n>---       [<var>   -> <default_expr>]--- to ---      case (<cexpr> == <lit_1>) of---        True  -> <expr_1>---        False -> case (<cexpr> == <lit_2>) of---                   True  -> <expr_2>---                   False -> case ...---                                  :---                               -> case (<cexpr> == <lit_n>) of---                                    True  -> <expr_n>---                                    False -> <default_expr>----completeLitAlts :: SrcRef -> Eval -> Expression -> [Alt] -> Expression-completeLitAlts r evalannot expr [] = failedExpr-completeLitAlts r evalannot expr (alt:alts)-   | isLitAlt alt -     = (Case r evalannot -	     (eqExpr expr (p_makeLitExpr alt))-	     [(Alt truePatt  (getAltExpr alt)),-	      (Alt falsePatt (completeLitAlts r evalannot expr alts))])-   | otherwise-     = case alt of-         Alt (VariablePattern v) expr'-	   -> replaceVar v expr expr'-	 _ -> intError "completeLitAlts" "illegal alternative"- where-   p_makeLitExpr alt-      = case (getAltPatt alt) of-	  LiteralPattern lit -> Literal lit-	  _                  -> intError "completeLitAlts" -				         "literal pattern expected"----- For the unusual case of having only one alternative containing a variable--- pattern it is necessary to tranform it to a 'let' term because FlatCurry--- does not support variable patterns in case alternatives. So the--- case expression---      case <ce> of ---        x -> <expr>--- is transformed ot---      let x = <ce> in <expr>-completeVarAlts :: Expression -> [Alt] -> Expression-completeVarAlts expr [] = failedExpr-completeVarAlts expr (alt:_)-   = (Let (Binding (p_getVarIdent alt) expr) (getAltExpr alt))- where-   p_getVarIdent alt-      = case (getAltPatt alt) of-	  VariablePattern ident -> ident-	  _                     -> intError "completeVarAlts" -				            "variable pattern expected"------------------------------------------------------------------------------------- The function 'removeRedundantAlts' removes case branches which are--- either idle (i.e. they will never be reached) or multiply declared.--- Note: unlike the PAKCS frontend MCC does not support warnings. So--- there will be no messages if alternatives have been removed.- -removeRedundantAlts :: [Message] -> [Alt] -> ([Alt], [Message])-removeRedundantAlts msgs alts-   = let-         (alts1, msgs1) = removeIdleAlts msgs alts-	 (alts2, msgs2) = removeMultipleAlts msgs1 alts1-     in-         (alts2, msgs2)----- An alternative is idle if it occurs anywehere behind another alternative --- which contains a variable pattern. Example:---    case x of---      (y:ys) -> e1---      z      -> e2---      []     -> e3--- Here all alternatives behind (z  -> e2) are idle and will be removed.-removeIdleAlts :: [Message] -> [Alt] -> ([Alt], [Message])-removeIdleAlts msgs alts -   | null alts2 = (alts1, msgs)-   | otherwise  = (alts1, msgs)- where-   (alts1, alts2) = splitAfter isVarAlt alts----- An alternative occures multiply if at least two alternatives--- use the same pattern. Example:---    case x of---      []     -> e1---      (y:ys) -> e2---      []     -> e3--- Here the last alternative occures multiply because its pattern is already--- used in the first alternative. All multiple alternatives will be--- removed except for the first occurrence.-removeMultipleAlts :: [Message] -> [Alt] -> ([Alt], [Message])-removeMultipleAlts msgs alts-   = p_remove msgs [] alts- where-   p_remove msgs altsR []     = ((reverse altsR), msgs)-   p_remove msgs altsR (alt:alts)-      | p_containsAlt alt altsR = p_remove msgs altsR alts-      | otherwise               = p_remove msgs (alt:altsR) alts--   p_containsAlt alt alts = any (p_eqAlt alt) alts--   p_eqAlt (Alt (LiteralPattern lit1) _) alt2-      = case alt2 of-	  (Alt (LiteralPattern lit2) _) -> lit1 == lit2-	  _                             -> False-   p_eqAlt (Alt (ConstructorPattern qident1 _) _) alt2-      = case alt2 of-	  (Alt (ConstructorPattern qident2 _) _) -> qident1 == qident2-	  _                                      -> False-   p_eqAlt (Alt (VariablePattern _) _) alt2-      = case alt2 of-	  (Alt (VariablePattern _) _) -> True-	  _                           -> False------------------------------------------------------------------------------------- Some functions for testing and extracting terms from case alternatives-----isVarAlt :: Alt -> Bool-isVarAlt alt = case (getAltPatt alt) of-	         VariablePattern _ -> True-		 _                 -> False-----isConstrAlt :: Alt -> Bool-isConstrAlt alt = case (getAltPatt alt) of-		    ConstructorPattern _ _ -> True-		    _                      -> False-----isLitAlt :: Alt -> Bool-isLitAlt alt = case (getAltPatt alt) of-	         LiteralPattern _ -> True-		 _                -> False------getAltExpr :: Alt -> Expression-getAltExpr (Alt _ expr) = expr------getAltPatt :: Alt -> ConstrTerm-getAltPatt (Alt cterm _) = cterm----- Note: the newly generated variable 'x!' is just a dummy and will never--- occur in the transformed program-getDefaultAlt :: [Alt] -> Alt-getDefaultAlt alts -   = fromMaybe (Alt (VariablePattern (mkIdent "x!")) failedExpr)-               (find isVarAlt alts)------------------------------------------------------------------------------------- This part of the module contains functions for replacing variables--- with expressions. This is necessary in the case of having a default --- alternative like---      v -> <expr>--- where the variable v occurs in the default expression <expr>. When--- building additional alternatives for this default expression the variable--- must be replaced with the newly generated constructors.---- Call:---      replaceVar <variable id>---                 <replace-with expression>---                 <replace-in expression>----replaceVar :: Ident -> Expression -> Expression -> Expression-replaceVar ident expr (Variable ident')-   | ident == ident' = expr-   | otherwise       = Variable ident'-replaceVar ident expr (Apply expr1 expr2)-   = Apply (replaceVar ident expr expr1) (replaceVar ident expr expr2)-replaceVar ident expr (Case r eval expr' alts)-   = Case r eval -          (replaceVar ident expr expr') -	  (map (replaceVarInAlt ident expr) alts)-replaceVar ident expr (Or expr1 expr2)-   = Or (replaceVar ident expr expr1) (replaceVar ident expr expr2)-replaceVar ident expr (Exist ident' expr')-   | ident == ident' = Exist ident' expr'-   | otherwise       = Exist ident' (replaceVar ident expr expr')-replaceVar ident expr (Let binding expr')-   | varOccursInBinding ident binding-     = Let binding expr'-   | otherwise-     = Let (replaceVarInBinding ident expr binding) -	   (replaceVar ident expr expr')-replaceVar ident expr (Letrec bindings expr')-   | any (varOccursInBinding ident) bindings-     = Letrec bindings expr'-   | otherwise-     = Letrec (map (replaceVarInBinding ident expr) bindings)-              (replaceVar ident expr expr')-replaceVar _ _ expr'-   = expr'------replaceVarInAlt :: Ident -> Expression -> Alt -> Alt-replaceVarInAlt ident expr (Alt patt expr')-   | varOccursInPattern ident patt -     = Alt patt expr'-   | otherwise -     = Alt patt (replaceVar ident expr expr')------replaceVarInBinding :: Ident -> Expression -> Binding -> Binding-replaceVarInBinding ident expr (Binding ident' expr')-   | ident == ident' = Binding ident' expr'-   | otherwise       = Binding ident' (replaceVar ident expr expr')------varOccursInPattern :: Ident -> ConstrTerm -> Bool-varOccursInPattern ident (VariablePattern ident')-   = ident == ident'-varOccursInPattern ident (ConstructorPattern _ idents)-   = elem ident idents-varOccursInPattern _ _-   = False------varOccursInBinding :: Ident -> Binding -> Bool-varOccursInBinding ident (Binding ident' _)-   = ident == ident'------------------------------------------------------------------------------------- The following functions generate several IL expressions and patterns-----failedExpr :: Expression-failedExpr = Function (qualifyWith preludeMIdent (mkIdent "failed")) 0-----eqExpr :: Expression -> Expression -> Expression-eqExpr e1 e2 = Apply-	         (Apply -		   (Function (qualifyWith preludeMIdent (mkIdent "==")) 2)-		   e1)-		 e2------truePatt :: ConstrTerm-truePatt = ConstructorPattern qTrueId []-----falsePatt :: ConstrTerm-falsePatt = ConstructorPattern qFalseId []------cterm2expr :: ConstrTerm -> Expression-cterm2expr (LiteralPattern lit) = Literal lit-cterm2expr (ConstructorPattern qident args)-   = p_genApplic (Constructor qident (length args)) args- where-   p_genApplic expr []     = expr-   p_genApplic expr (v:vs) = p_genApplic (Apply expr (Variable v)) vs-cterm2expr (VariablePattern ident) = Variable ident-------------------------------------------------------------------------------------- The folowing functions compute the missing constructors for generating--- new case alternatives---- Computes the complementary constructors for a list of constructors. All--- specified constructors must have the same type.--- This functions uses the module environment 'menv' which contains all known--- constructors, except for those which are declared in the module and--- except for the list constructors.------ Call:---      getComplConstr <IL module>---                     <module environment>---                     <list of (qualified) constructor ids>----getComplConstrs :: Module -> ModuleEnv -> [QualIdent] -> [(QualIdent, Int)]-getComplConstrs (Module mid _ decls) menv constrs-   | null constrs -     = intError "getComplConstrs" "empty constructor list"-   | cons == qNilId || cons == qConsId-     = getCC constrs [(qNilId, 0), (qConsId, 2)]-   | mid' == mid-     = getCCFromDecls mid constrs decls-   | otherwise-     = maybe [] -- error ...-             (getCCFromIDecls mid' constrs) -	     (lookupModule mid' menv)- where-   cons = head constrs--   mid' = fromMaybe mid (qualidMod cons)----- Find complementary constructors within the declarations of the--- current module-getCCFromDecls :: ModuleIdent -> [QualIdent] -> [Decl] -> [(QualIdent, Int)]-getCCFromDecls _ constrs decls-   = let-         cdecls = maybe [] -- error ...-		        p_extractConstrDecls-			(find (p_declaresConstr (head constrs)) decls)-	 cinfos = map p_getConstrDeclInfo cdecls-     in-         getCC constrs cinfos- where-   p_declaresConstr qident decl-      = case decl of-	  DataDecl _ _ cdecls   -> any (p_isConstrDecl qident) cdecls-	  NewtypeDecl _ _ cdecl -> p_isConstrDecl qident cdecl-	  _                     -> False--   p_isConstrDecl qident (ConstrDecl qid _) = qident == qid--   p_extractConstrDecls decl-      = case decl of-	  DataDecl _ _ cdecls   -> cdecls-	  _                     -> []--   p_getConstrDeclInfo (ConstrDecl qident types) = (qident, length types)----- Find complementary constructors within the module environment-getCCFromIDecls :: ModuleIdent -> [QualIdent] -> [Curry.Syntax.IDecl] -		   -> [(QualIdent, Int)]-getCCFromIDecls mident constrs idecls-   = let-         cdecls = maybe [] -- error ...-		        p_extractIConstrDecls-		        (find (p_declaresIConstr (head constrs)) idecls)-	 cinfos = map (p_getIConstrDeclInfo mident) cdecls-     in-         getCC constrs cinfos- where-   p_declaresIConstr qident idecl-      = case idecl of-	  Curry.Syntax.IDataDecl _ _ _ cdecls-	      -> any (p_isIConstrDecl qident) -		     (map fromJust (filter isJust cdecls))-	  Curry.Syntax.INewtypeDecl _ _ _ ncdecl -	      -> p_isINewConstrDecl qident ncdecl-	  _   -> False--   p_isIConstrDecl qident (Curry.Syntax.ConstrDecl _ _ ident _)-      = (unqualify qident) == ident-   p_isIConstrDecl qident (Curry.Syntax.ConOpDecl _ _ _ ident _)-      = (unqualify qident) == ident--   p_isINewConstrDecl qident (Curry.Syntax.NewConstrDecl _ _ ident _)-      = (unqualify qident) == ident--   p_extractIConstrDecls idecl-      = case idecl of-	  Curry.Syntax.IDataDecl _ _ _ cdecls -	      -> map fromJust (filter isJust cdecls)-	  _   -> []--   p_getIConstrDeclInfo mid (Curry.Syntax.ConstrDecl _ _ ident types)-      = (qualifyWith mid ident, length types)-   p_getIConstrDeclInfo mid (Curry.Syntax.ConOpDecl _ _ _ ident _)-      = (qualifyWith mid ident, 2)----- Compute complementary constructors-getCC :: [QualIdent] -> [(QualIdent, Int)] -> [(QualIdent, Int)]-getCC _ [] = []-getCC constrs ((qident,arity):cis)-   | any ((==) qident) constrs = getCC constrs cis-   | otherwise                 = (qident,arity):(getCC constrs cis)------------------------------------------------------------------------------------- Message handling--- Not in use in this version, but intended for further versions--type Message = String------------------------------------------------------------------------------------- Miscellaneous---- Splits a list behind the first element which satify 'cond'-splitAfter :: (a -> Bool) -> [a] -> ([a], [a])-splitAfter cond xs = p_splitAfter cond [] xs- where-   p_splitAfter c fs []     = ((reverse fs),[])-   p_splitAfter c fs (l:ls) | c l       = ((reverse (l:fs)), ls)-			    | otherwise = p_splitAfter c (l:fs) ls----- Returns the first element which satisfy 'cond'. The returned element is--- embedded in a 'Maybe' term-find :: (a -> Bool) -> [a] -> Maybe a-find _    []     = Nothing-find cond (x:xs) | cond x    = Just x-		 | otherwise = find cond xs----- Prefixes an element to a list if it does not already exit within the--- list-insertUnique :: Eq a => a -> [a] -> [a]-insertUnique x xs | elem x xs = xs-		  | otherwise = x:xs----- Raises an internal error-intError :: String -> String -> a-intError fun msg = error ("CaseCompletion." ++ fun ++ " - " ++ msg)------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/Checks.hs view
@@ -0,0 +1,162 @@+{- |+    Module      :  $Header$+    Description :  Different checks on a Curry module+    Copyright   :  (c) 2011 - 2013 Björn Peemöller+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module subsumes the different checks to be performed on a Curry+    module during compilation, e.g. type checking.+-}+module Checks where++import qualified Checks.InstanceCheck     as INC (instanceCheck)+import qualified Checks.InterfaceCheck    as IC  (interfaceCheck)+import qualified Checks.ImportSyntaxCheck as ISC (importCheck)+import qualified Checks.DeriveCheck       as DC  (deriveCheck)+import qualified Checks.ExportCheck       as EC  (exportCheck, expandExports)+import qualified Checks.ExtensionCheck    as EXC (extensionCheck)+import qualified Checks.KindCheck         as KC  (kindCheck)+import qualified Checks.PrecCheck         as PC  (precCheck)+import qualified Checks.SyntaxCheck       as SC  (syntaxCheck)+import qualified Checks.TypeCheck         as TC  (typeCheck)+import qualified Checks.TypeSyntaxCheck   as TSC (typeSyntaxCheck)+import qualified Checks.WarnCheck         as WC  (warnCheck)++import Curry.Base.Monad+import Curry.Syntax (Module (..), Interface (..), ImportSpec)++import Base.Messages+import Base.Types++import CompilerEnv+import CompilerOpts++type Check m a = Options -> CompEnv a -> CYT m (CompEnv a)++interfaceCheck :: Monad m => Check m Interface+interfaceCheck _ (env, intf)+  | null msgs = ok (env, intf)+  | otherwise = failMessages msgs+  where msgs = IC.interfaceCheck (opPrecEnv env) (tyConsEnv env) (classEnv env)+                                 (instEnv env) (valueEnv env) intf++importCheck :: Monad m => Interface -> Maybe ImportSpec+            -> CYT m (Maybe ImportSpec)+importCheck intf is+  | null msgs = ok is'+  | otherwise = failMessages msgs+  where (is', msgs) = ISC.importCheck intf is++-- |Check for enabled language extensions.+--+-- * Declarations: remain unchanged+-- * Environment:  The enabled language extensions are updated+extensionCheck :: Monad m => Check m (Module a)+extensionCheck opts (env, mdl)+  | null msgs = ok (env { extensions = exts }, mdl)+  | otherwise = failMessages msgs+  where (exts, msgs) = EXC.extensionCheck opts mdl++-- |Check the type syntax of type definitions and signatures.+--+-- * Declarations: Nullary type constructors and type variables are+--                 disambiguated+-- * Environment:  remains unchanged+typeSyntaxCheck :: Monad m => Check m (Module a)+typeSyntaxCheck _ (env, mdl)+  | null msgs = ok (env { extensions = exts }, mdl')+  | otherwise = failMessages msgs+  where ((mdl', exts), msgs) = TSC.typeSyntaxCheck (extensions env)+                                                   (tyConsEnv env) mdl++-- |Check the kinds of type definitions and signatures.+--+-- * Declarations: remain unchanged+-- * Environment:  The type constructor and class environment are updated+kindCheck :: Monad m => Check m (Module a)+kindCheck _ (env, mdl)+  | null msgs = ok (env { tyConsEnv = tcEnv', classEnv = clsEnv' }, mdl)+  | otherwise = failMessages msgs+  where ((tcEnv', clsEnv'), msgs) = KC.kindCheck (tyConsEnv env) (classEnv env)+                                                 mdl++-- |Check for a correct syntax.+--+-- * Declarations: Nullary data constructors and variables are+--                 disambiguated, variables are renamed+-- * Environment:  remains unchanged+syntaxCheck :: Monad m => Check m (Module ())+syntaxCheck _ (env, mdl)+  | null msgs = ok (env { extensions = exts }, mdl')+  | otherwise = failMessages msgs+  where ((mdl', exts), msgs) = SC.syntaxCheck (extensions env) (tyConsEnv env)+                                              (valueEnv env) mdl++-- |Check the precedences of infix operators.+--+-- * Declarations: Expressions are reordered according to the specified+--                 precedences+-- * Environment:  The operator precedence environment is updated+precCheck :: Monad m => Check m (Module a)+precCheck _ (env, Module ps m es is ds)+  | null msgs = ok (env { opPrecEnv = pEnv' }, Module ps m es is ds')+  | otherwise = failMessages msgs+  where (ds', pEnv', msgs) = PC.precCheck (moduleIdent env) (opPrecEnv env) ds++-- |Check the deriving clauses.+--+-- * Declarations: remain unchanged+-- * Environment:  remain unchanged+deriveCheck :: Monad m => Check m (Module a)+deriveCheck _ (env, mdl) = case DC.deriveCheck (tyConsEnv env) mdl of+  msgs | null msgs -> ok (env, mdl)+       | otherwise -> failMessages msgs++-- |Check the instances.+--+-- * Declarations: remain unchanged+-- * Environment:  The instance environment is updated+instanceCheck :: Monad m => Check m (Module a)+instanceCheck _ (env, Module ps m es is ds)+  | null msgs = ok (env { instEnv = inEnv' }, Module ps m es is ds)+  | otherwise = failMessages msgs+  where (inEnv', msgs) = INC.instanceCheck (moduleIdent env) (tyConsEnv env)+                                           (classEnv env) (instEnv env) ds++-- |Apply the correct typing of the module.+--+-- * Declarations: Type annotations are added to all expressions.+-- * Environment:  The value environment is updated.+typeCheck :: Monad m => Options -> CompEnv (Module a)+          -> CYT m (CompEnv (Module PredType))+typeCheck _ (env, Module ps m es is ds)+  | null msgs = ok (env { valueEnv = vEnv' }, Module ps m es is ds')+  | otherwise = failMessages msgs+  where (ds', vEnv', msgs) = TC.typeCheck (moduleIdent env) (tyConsEnv env)+                                          (valueEnv env) (classEnv env)+                                          (instEnv env) ds++-- |Check the export specification+exportCheck :: Monad m => Check m (Module a)+exportCheck _ (env, mdl@(Module _ _ es _ _))+  | null msgs = ok (env, mdl)+  | otherwise = failMessages msgs+  where msgs = EC.exportCheck (moduleIdent env) (aliasEnv env)+                              (tyConsEnv env) (valueEnv env) es++-- |Check the export specification+expandExports :: Monad m => Options -> CompEnv (Module a) -> m (CompEnv (Module a))+expandExports _ (env, Module ps m es is ds)+  = return (env, Module ps m (Just es') is ds)+  where es' = EC.expandExports (moduleIdent env) (aliasEnv env)+                               (tyConsEnv env) (valueEnv env) es++-- |Check for warnings.+warnCheck :: Options -> CompilerEnv -> Module a -> [Message]+warnCheck opts env mdl = WC.warnCheck (optWarnOpts opts) (optCaseMode opts)+  (aliasEnv env) (valueEnv env) (tyConsEnv env) (classEnv env) mdl
+ src/Checks/DeriveCheck.hs view
@@ -0,0 +1,108 @@+{- |+    Module      :  $Header$+    Description :  Checks deriving clauses+    Copyright   :  (c)        2016 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   Before entering derived instances into the instance environment, the+   compiler has to ensure that it is not asked for other instances than+   those of supported type classes.+-}+module Checks.DeriveCheck (deriveCheck) where++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax++import Base.Messages (Message, posMessage)++import Env.TypeConstructor++deriveCheck :: TCEnv -> Module a -> [Message]+deriveCheck tcEnv (Module _ m _ _ ds) = concatMap (checkDecl m tcEnv) ds++-- No instances can be derived for abstract data types as well as for+-- existential data types.++checkDecl :: ModuleIdent -> TCEnv -> Decl a -> [Message]+checkDecl m tcEnv (DataDecl   _ tc _ cs clss)+  | null clss                       = []+  | null cs                         = [errNoAbstractDerive tc]+  | any (not . null . existVars) cs = [errNoExistentialDerive tc]+  | otherwise                       = concatMap (checkDerivable m tcEnv cs) clss+checkDecl m tcEnv (NewtypeDecl _ _ _ nc clss) =+  concatMap (checkDerivable m tcEnv [toConstrDecl nc]) clss+checkDecl _ _     _                           = []++checkDerivable :: ModuleIdent -> TCEnv -> [ConstrDecl] -> QualIdent -> [Message]+checkDerivable m tcEnv cs cls+  | ocls == qEnumId && not (isEnum cs)       = [errNotEnum cls]+  | ocls == qBoundedId && not (isBounded cs) = [errNotBounded cls]+  | ocls `notElem` derivableClasses          = [errNotDerivable ocls]+  | otherwise                                = []+  where ocls = getOrigName m cls tcEnv++derivableClasses :: [QualIdent]+derivableClasses = [qEqId, qOrdId, qEnumId, qBoundedId, qReadId, qShowId]++-- Instances of 'Enum' can be derived only for enumeration types, i.e., types+-- where all data constructors are constants.++isEnum :: [ConstrDecl] -> Bool+isEnum cs = all ((0 ==) . constrArity) cs++-- Instances of 'Bounded' can be derived only for enumerations and for single+-- constructor types.++isBounded :: [ConstrDecl] -> Bool+isBounded cs = length cs == 1 || isEnum cs++-- ---------------------------------------------------------------------------+-- Auxiliary functions+-- ---------------------------------------------------------------------------++toConstrDecl :: NewConstrDecl -> ConstrDecl+toConstrDecl (NewConstrDecl p c      ty) = ConstrDecl p [] [] c [ty]+toConstrDecl (NewRecordDecl p c (l, ty)) =+  RecordDecl p [] [] c [FieldDecl p [l] ty]++constrArity :: ConstrDecl -> Int+constrArity (ConstrDecl  _ _ _ _ tys) = length tys+constrArity (ConOpDecl   _ _ _ _ _ _) = 2+constrArity c@(RecordDecl  _ _ _ _ _) = length $ recordLabels c++existVars :: ConstrDecl -> [Ident]+existVars (ConstrDecl _ evs _ _ _  ) = evs+existVars (ConOpDecl  _ evs _ _ _ _) = evs+existVars (RecordDecl _ evs _ _ _  ) = evs++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errNoAbstractDerive :: HasPosition a => a -> Message+errNoAbstractDerive p = posMessage p $+  text "Instances can only be derived for data types with" <+>+  text "at least one constructor"++errNoExistentialDerive :: HasPosition a => a -> Message+errNoExistentialDerive p = posMessage p $+  text "Instances cannot be derived for existential data types"++errNotDerivable :: QualIdent -> Message+errNotDerivable cls = posMessage cls $ hsep $ map text+  ["Instances of type class", escQualName cls, "cannot be derived"]++errNotEnum :: HasPosition a => a -> Message+errNotEnum p = posMessage p $+  text "Instances for Enum can be derived only for enumeration types"++errNotBounded :: HasPosition a => a -> Message+errNotBounded p = posMessage p $+  text "Instances of Bounded can be derived only for enumeration" <+>+  text "and single constructor types"
+ src/Checks/ExportCheck.hs view
@@ -0,0 +1,482 @@+{- |+    Module      :  $Header$+    Description :  Check the export specification of a module+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux+                       2011 - 2016 Björn Peemöller+                       2015 - 2016 Yannik Potdevin+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module implements a check and expansion of the export specification.+    Any errors in the specification are reported, and if there are no errors,+    the specification is expanded. The expansion does the following:+      * If there is no export specification, a specification exporting the+        entire module is generated.+      * Otherwise, (re)exports of modules are replaced by an export of all+        respective entities.+      * The export of a type with all constructors and fields is replaced+        by an enumeration of all constructors and fields.+      * The export of types without sub-entities is extended with an empty+        list of sub-entities.+-}+{-# LANGUAGE CPP #-}+module Checks.ExportCheck (exportCheck, expandExports) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>))+#endif+import           Control.Monad              (unless)+import qualified Control.Monad.State as S   (State, runState, gets, modify)+import           Data.List                  (nub, union)+import qualified Data.Map            as Map ( Map, elems, empty, insert+                                            , insertWith, lookup, toList )+import           Data.Maybe                 (fromMaybe)+import qualified Data.Set            as Set ( Set, empty, fromList, insert+                                            , member, toList )++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax++import Base.Messages       (Message, internalError, posMessage)+import Base.TopEnv         (allEntities, origName, localBindings, moduleImports)+import Base.Types          ( Type (..), unapplyType, arrowBase, PredType (..)+                           , DataConstr (..), constrIdent, recLabels+                           , ClassMethod, methodName+                           , TypeScheme (..), ExistTypeScheme (..) )+import Base.Utils          (findMultiples)++import Env.ModuleAlias     (AliasEnv)+import Env.TypeConstructor (TCEnv, TypeInfo (..), qualLookupTypeInfoUnique)+import Env.Value           (ValueEnv, ValueInfo (..), qualLookupValueUnique)++currentModuleName :: String+currentModuleName = "Checks.ExportCheck"++-- ---------------------------------------------------------------------------+-- Check and expansion of the export statement+-- ---------------------------------------------------------------------------++expandExports :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv+              -> Maybe ExportSpec -> ExportSpec+expandExports m aEnv tcEnv tyEnv spec = Exporting (exportPos spec) es+  where+  exportPos (Just (Exporting p _)) = p+  exportPos Nothing                = NoPos++  es = expand m aEnv tcEnv tyEnv spec++exportCheck :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv+            -> Maybe ExportSpec -> [Message]+exportCheck m aEnv tcEnv tyEnv spec = case check m aEnv tcEnv tyEnv spec of+  [] -> checkNonUniqueness $ expand m aEnv tcEnv tyEnv spec+  ms -> ms++-- -----------------------------------------------------------------------------+-- Export Check Monad+-- -----------------------------------------------------------------------------++data ECState = ECState+  { moduleIdent  :: ModuleIdent+  , importedMods :: Set.Set ModuleIdent+  , tyConsEnv    :: TCEnv+  , valueEnv     :: ValueEnv+  , errors       :: [Message]+  }++type ECM a = S.State ECState a++runECM :: ECM a -> ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> (a, [Message])+runECM ecm m aEnv tcEnv tyEnv+  = let (a, s') = S.runState ecm initState in (a, reverse $ errors s')+  where+  initState  = ECState m imported tcEnv tyEnv []+  imported   = Set.fromList (Map.elems aEnv)++getModuleIdent :: ECM ModuleIdent+getModuleIdent = S.gets moduleIdent++getImportedModules :: ECM (Set.Set ModuleIdent)+getImportedModules = S.gets importedMods++getTyConsEnv :: ECM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: ECM ValueEnv+getValueEnv = S.gets valueEnv++report :: Message -> ECM ()+report err = S.modify (\ s -> s { errors = err : errors s })++ok :: ECM ()+ok = return ()++-- -----------------------------------------------------------------------------+-- Check+-- -----------------------------------------------------------------------------++check :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec+      -> [Message]+check m aEnv tcEnv tyEnv spec = snd $ runECM (checkSpec spec) m aEnv tcEnv tyEnv++-- |Check export specification.+checkSpec :: Maybe ExportSpec -> ECM ()+checkSpec (Just (Exporting _ es)) = mapM_ checkExport es+checkSpec Nothing                 = ok++-- |Check single export.+checkExport :: Export -> ECM ()+checkExport (Export         x    ) = checkThing x+checkExport (ExportTypeWith tc cs) = checkTypeWith tc cs+checkExport (ExportTypeAll  tc   ) = checkTypeAll tc+checkExport (ExportModule   em   ) = checkModule em++-- |Check export of type constructor / function+checkThing :: QualIdent -> ECM ()+checkThing tc = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfoUnique m tc tcEnv of+    []  -> checkThing' tc Nothing+    [t] -> checkThing' tc (Just [ExportTypeWith (origName t) []])+    ts  -> report (errAmbiguousType tc ts)++-- |Expand export of data cons / function+checkThing' :: QualIdent -> Maybe [Export] -> ECM ()+checkThing' f tcExport = do+  m     <- getModuleIdent+  tyEnv <- getValueEnv+  case qualLookupValueUnique m f tyEnv of+    []  -> justTcOr errUndefinedName+    [v] -> case v of+      Value _ _ _ _ -> ok+      Label   _ _ _ -> report $ errOutsideTypeLabel f (getTc v)+      _             -> justTcOr $ flip errOutsideTypeConstructor (getTc v)+    fs  -> report (errAmbiguousName f fs)+  where+  justTcOr errFun = maybe (report $ errFun f) (const ok) tcExport++  getTc (DataConstructor  _ _ _ (ForAllExist _ _ (PredType _ ty))) = getTc' ty+  getTc (NewtypeConstructor _ _ (ForAllExist _ _ (PredType _ ty))) = getTc' ty+  getTc (Label _ _ (ForAll _ (PredType _ (TypeArrow tc' _)))) =+    let (TypeConstructor tc, _) = unapplyType False tc' in tc+  getTc err = internalError $ currentModuleName ++ ".checkThing'.getTc: " ++ show err++  getTc' ty = let (TypeConstructor tc) = arrowBase ty in tc++checkTypeWith :: QualIdent -> [Ident] -> ECM ()+checkTypeWith tc xs = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfoUnique m tc tcEnv of+    []                   -> report (errUndefinedTypeOrClass tc)+    [DataType _ _ cs]    ->+      mapM_ (checkElement errUndefinedElement (visibleElems cs )) xs'+    [RenamingType _ _ c] ->+      mapM_ (checkElement errUndefinedElement (visibleElems [c])) xs'+    [TypeClass   _ _ ms] ->+      mapM_ (checkElement errUndefinedMethod (visibleMethods ms)) xs'+    [_]                  -> report (errNonDataTypeOrTypeClass tc)+    ts                   -> report (errAmbiguousType tc ts)+  where+  xs' = nub xs+  -- check if given identifier is constructor/label/method of type/class tc+  checkElement err cs' c = unless (c `elem` cs') $ report $ err tc c++-- |Check type constructor with all data constructors and record labels.+checkTypeAll :: QualIdent -> ECM ()+checkTypeAll tc = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfoUnique m tc tcEnv of+    []                   -> report (errUndefinedTypeOrClass tc)+    [DataType     _ _ _] -> ok+    [RenamingType _ _ _] -> ok+    [TypeClass    _ _ _] -> ok+    [_]                  -> report (errNonDataTypeOrTypeClass tc)+    ts                   -> report (errAmbiguousType tc ts)++checkModule :: ModuleIdent -> ECM ()+checkModule em = do+  isLocal   <- (em ==)         <$> getModuleIdent+  isForeign <- (Set.member em) <$> getImportedModules+  unless (isLocal || isForeign) $ report $ errModuleNotImported em++-- Check whether two entities of the same kind (type or constructor/function)+-- share the same unqualified name, which is not allowed since they could+-- not be uniquely resolved at their usage.+-- For instance, consider the following module+-- @+-- module M (Bool, Prelude.Bool) where+-- data Bool = False | True+-- @+-- If this export would be allowed, in a module @M1@ as follows+-- @+-- module M1 where+-- import M (Bool)+-- @+-- the type @Bool@ could not be resolved uniquely to its definition.+-- Naturally, the same applies for constructors or functions.+checkNonUniqueness :: [Export] -> [Message]+checkNonUniqueness es = map errMultipleType (findMultiples types )+                     ++ map errMultipleName (findMultiples values)+  where+  types  = [ unqualify tc | ExportTypeWith tc _  <- es ]+  values = [ c            | ExportTypeWith _  cs <- es, c <- cs ]+        ++ [ unqualify f  | Export f <- es ]++-- -----------------------------------------------------------------------------+-- Expansion+-- -----------------------------------------------------------------------------++expand :: ModuleIdent -> AliasEnv -> TCEnv -> ValueEnv -> Maybe ExportSpec+       -> [Export]+expand m aEnv tcEnv tyEnv spec+  = fst $ runECM ((joinExports . canonExports tcEnv) <$> expandSpec spec)+                 m aEnv tcEnv tyEnv++-- While checking all export specifications, the compiler expands+-- specifications of the form @T(..)@ into @T(C_1,...,C_m,l_1,...,l_n)@,+-- where @C_1,...,C_m@ are the data constructors of type @T@ and @l_1,...,l_n@+-- its field labels, and replaces an export specification+-- @module M@ by specifications for all entities which are defined+-- in module @M@ and imported into the current module with their+-- unqualified name. In order to distinguish exported type constructors+-- from exported functions, the former are translated into the equivalent+-- form @T()@. Note that the export specification @x@ may+-- export a type constructor @x@ /and/ a global function+-- @x@ at the same time.+--+-- /Note:/ This frontend allows redeclaration and export of imported+-- identifiers.++-- |Expand export specification+expandSpec :: Maybe ExportSpec -> ECM [Export]+expandSpec (Just (Exporting _ es)) = concat <$> mapM expandExport es+expandSpec Nothing                 = expandLocalModule++-- |Expand single export+expandExport :: Export -> ECM [Export]+expandExport (Export             x) = expandThing x+expandExport (ExportTypeWith tc cs) = expandTypeWith tc cs+expandExport (ExportTypeAll     tc) = expandTypeAll tc+expandExport (ExportModule      em) = expandModule em++-- |Expand export of type constructor / function+expandThing :: QualIdent -> ECM [Export]+expandThing tc = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfoUnique m tc tcEnv of+    []  -> expandThing' tc Nothing+    [t] -> expandThing' tc (Just [ExportTypeWith (origName t @> tc) []])+    err -> internalError $ currentModuleName ++ ".expandThing: " ++ show err++-- |Expand export of data cons / function+expandThing' :: QualIdent -> Maybe [Export] -> ECM [Export]+expandThing' f tcExport = do+  m     <- getModuleIdent+  tyEnv <- getValueEnv+  case qualLookupValueUnique m f tyEnv of+    [Value f' _ _ _] -> return $ Export (f' @> f) : fromMaybe [] tcExport+    _                -> return $ fromMaybe [] tcExport++-- |Expand type constructor with explicit data constructors and record labels+expandTypeWith :: QualIdent -> [Ident] -> ECM [Export]+expandTypeWith tc xs = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfoUnique m tc tcEnv of+    [t] -> return [ExportTypeWith (origName t @> tc) $ nub xs]+    err -> internalError $ currentModuleName ++ ".expandTypeWith: " ++ show err++-- |Expand type constructor with all data constructors and record labels+expandTypeAll :: QualIdent -> ECM [Export]+expandTypeAll tc = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfoUnique m tc tcEnv of+    [t] -> return [exportType t]+    err -> internalError $ currentModuleName ++ ".expandTypeAll: " ++ show err++expandModule :: ModuleIdent -> ECM [Export]+expandModule em = do+  isLocal   <- (em ==)         <$> getModuleIdent+  isForeign <- (Set.member em) <$> getImportedModules+  locals    <- if isLocal   then expandLocalModule       else return []+  foreigns  <- if isForeign then expandImportedModule em else return []+  return $ locals ++ foreigns++expandLocalModule :: ECM [Export]+expandLocalModule = do+  tcEnv <- getTyConsEnv+  tyEnv <- getValueEnv+  return $+       [ exportType t | (_, t) <- localBindings tcEnv ]+    ++ [ Export f' | (f, Value f' _ _ _) <- localBindings tyEnv, hasGlobalScope f ]+    ++ [ Export l' | (l, Label l' _ _) <- localBindings tyEnv, hasGlobalScope l ]++-- |Expand a module export+expandImportedModule :: ModuleIdent -> ECM [Export]+expandImportedModule m = do+  tcEnv <- getTyConsEnv+  tyEnv <- getValueEnv+  return $ [exportType t |       (_, t) <- moduleImports m tcEnv]+        ++ [Export f | (_, Value f _ _ _) <- moduleImports m tyEnv]+        ++ [Export l | (_, Label l _ _) <- moduleImports m tyEnv]++exportType :: TypeInfo -> Export+exportType t = ExportTypeWith tc xs+  where tc = origName t+        xs = elements t++-- -----------------------------------------------------------------------------+-- Canonicalization and joining of exports+-- -----------------------------------------------------------------------------++-- In contrast to Haskell, the export of field labels and record constructors+-- without their types is NOT allowed.+-- Thus, given the declaration @data T a = C { l :: a }@+-- the label @l@ and the constructor @C@ can only be exported together with the+-- type @T@, i.e., @(T(C,l))@.+-- Since record update operations are desugared to case expressions matching the+-- corresponding constructors of the record, the export of a label without its+-- type could result in a type error, when it is used for an update operation in+-- another module.++canonExports :: TCEnv -> [Export] -> [Export]+canonExports tcEnv es = map (canonExport (canonLabels tcEnv es)) es++canonExport :: Map.Map QualIdent Export -> Export -> Export+canonExport ls (Export x)             = fromMaybe (Export x) (Map.lookup x ls)+canonExport _  (ExportTypeWith tc xs) = ExportTypeWith tc xs+canonExport _  e                      = internalError $+  currentModuleName ++ ".canonExport: " ++ show e++canonLabels :: TCEnv -> [Export] -> Map.Map QualIdent Export+canonLabels tcEnv es = foldr bindLabels Map.empty (allEntities tcEnv)+  where+  tcs = [tc | ExportTypeWith tc _ <- es]+  bindLabels t ls+    | tc' `elem` tcs = foldr (bindLabel tc') ls (elements t)+    | otherwise     = ls+      where+        tc'            = origName t+        bindLabel tc x = Map.insert (qualifyLike tc x) (ExportTypeWith tc [x])++-- The expanded list of exported entities may contain duplicates. These+-- are removed by the function joinExports. In particular, this+-- function removes any field labels from the list of exported values+-- which are also exported along with their types.++joinExports :: [Export] -> [Export]+joinExports es =  [ExportTypeWith tc cs | (tc, cs) <- joinedTypes]+               ++ [Export f             | f        <- joinedFuncs]+  where joinedTypes = Map.toList $ foldr joinType Map.empty es+        joinedFuncs = Set.toList $ foldr joinFun  Set.empty es++joinType :: Export -> Map.Map QualIdent [Ident] -> Map.Map QualIdent [Ident]+joinType (Export             _) tcs = tcs+joinType (ExportTypeWith tc cs) tcs = Map.insertWith union tc cs tcs+joinType export                   _ = internalError $+  currentModuleName ++ ".joinType: " ++ show export++joinFun :: Export -> Set.Set QualIdent -> Set.Set QualIdent+joinFun (Export           f) fs = f `Set.insert` fs+joinFun (ExportTypeWith _ _) fs = fs+joinFun export                _ = internalError $+  currentModuleName ++ ".joinFun: " ++ show export++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++elements :: TypeInfo -> [Ident]+elements (DataType      _ _ cs) = visibleElems cs+elements (RenamingType   _ _ c) = visibleElems [c]+elements (AliasType    _ _ _ _) = []+elements (TypeClass     _ _ ms) = visibleMethods ms+elements (TypeVar            _) =+  error "Checks.ExportCheck.elements: type variable"++-- get visible constructor and label identifiers for given constructor+visibleElems :: [DataConstr] -> [Ident]+visibleElems cs = map constrIdent cs ++ (nub (concatMap recLabels cs))++-- get class method names+visibleMethods :: [ClassMethod] -> [Ident]+visibleMethods = map methodName++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errAmbiguousName :: QualIdent -> [ValueInfo] -> Message+errAmbiguousName x vs = errAmbiguous "name" x (map origName vs)++errAmbiguousType :: QualIdent -> [TypeInfo] -> Message+errAmbiguousType tc tcs = errAmbiguous "type" tc (map origName tcs)++errAmbiguous :: String -> QualIdent -> [QualIdent] -> Message+errAmbiguous what qn qns = posMessage qn+  $   text "Ambiguous" <+> text what <+> text (escQualName qn)+  $+$ text "It could refer to:"+  $+$ nest 2 (vcat (map (text . escQualName) qns))++errModuleNotImported :: ModuleIdent -> Message+errModuleNotImported m = posMessage m $ hsep $ map text+  ["Module", escModuleName m, "not imported"]++errMultipleName :: [Ident] -> Message+errMultipleName = errMultiple "name"++errMultipleType :: [Ident] -> Message+errMultipleType = errMultiple "type"++errMultiple :: String -> [Ident] -> Message+errMultiple _    []     = internalError $+  currentModuleName ++ ".errMultiple: empty list"+errMultiple what (i:is) = posMessage i $+  text "Multiple exports of" <+> text what <+> text (escName i) <+> text "at:"+  $+$ nest 2 (vcat (map showPos (i:is)))+  where showPos = text . showLine . idPosition++errNonDataTypeOrTypeClass :: QualIdent -> Message+errNonDataTypeOrTypeClass tc = posMessage tc $ hsep $ map text+  [escQualName tc, "is not a data type or type class"]++errOutsideTypeConstructor :: QualIdent -> QualIdent -> Message+errOutsideTypeConstructor c tc = errOutsideTypeExport "Data constructor" c tc++errOutsideTypeLabel :: QualIdent -> QualIdent -> Message+errOutsideTypeLabel l tc = errOutsideTypeExport "Label" l tc++errOutsideTypeExport :: String -> QualIdent -> QualIdent -> Message+errOutsideTypeExport what q tc = posMessage q+  $   text what <+> text (escQualName q)+         <+> text "outside type export in export list"+  $+$ text "Use `" <> text (qualName tc) <+> parens (text (qualName q))+  <>  text "' instead"++errUndefinedElement :: QualIdent -> Ident -> Message+errUndefinedElement tc c = posMessage c $ hsep $ map text+  [ escName c, "is not a constructor or label of type", escQualName tc ]++errUndefinedMethod :: QualIdent -> Ident -> Message+errUndefinedMethod cls f = posMessage f $ hsep $ map text+  [ escName f, "is not a method of class", escQualName cls ]++errUndefinedName :: QualIdent -> Message+errUndefinedName = errUndefined "name"++errUndefinedTypeOrClass :: QualIdent -> Message+errUndefinedTypeOrClass = errUndefined "type or class"++errUndefined :: String -> QualIdent -> Message+errUndefined what tc = posMessage tc $ hsep $ map text+  ["Undefined", what, escQualName tc, "in export list"]
+ src/Checks/ExtensionCheck.hs view
@@ -0,0 +1,72 @@+{- |+    Module      :  $Header$+    Description :  Checks extensions+    Copyright   :  (c)        2016 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   First of all, the compiler scans a source file for file-header pragmas+   that may activate language extensions.+-}+module Checks.ExtensionCheck (extensionCheck) where++import qualified Control.Monad.State as S (State, execState, modify)++import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax++import Base.Messages (Message, posMessage)++import CompilerOpts++extensionCheck :: Options -> Module a -> ([KnownExtension], [Message])+extensionCheck opts mdl = execEXC (checkModule mdl) initState+  where+    initState = EXCState (optExtensions opts) []++type EXCM = S.State EXCState++data EXCState = EXCState+  { extensions :: [KnownExtension]+  , errors     :: [Message]+  }++execEXC :: EXCM a -> EXCState -> ([KnownExtension], [Message])+execEXC ecm s =+  let s' = S.execState ecm s in (extensions s', reverse $ errors s')++enableExtension :: KnownExtension -> EXCM ()+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }++report :: Message -> EXCM ()+report msg = S.modify $ \s -> s { errors = msg : errors s }++ok :: EXCM ()+ok = return ()++-- The extension check iterates over all given pragmas in the module and+-- gathers all extensions mentioned in a language pragma. An error is reported+-- if an extension is unkown.++checkModule :: Module a -> EXCM ()+checkModule (Module ps _ _ _ _) = mapM_ checkPragma ps++checkPragma :: ModulePragma -> EXCM ()+checkPragma (LanguagePragma _ exts) = mapM_ checkExtension exts+checkPragma (OptionsPragma  _  _ _) = ok++checkExtension :: Extension -> EXCM ()+checkExtension (KnownExtension   _ e) = enableExtension e+checkExtension (UnknownExtension p e) = report $ errUnknownExtension p e++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUnknownExtension :: Position -> String -> Message+errUnknownExtension p e = posMessage p $+  text "Unknown language extension:" <+> text e
+ src/Checks/ImportSyntaxCheck.hs view
@@ -0,0 +1,278 @@+{- |+    Module      :  $Header$+    Description :  Checking import specifications+    Copyright   :  (c) 2016       Jan Tikovsky+                       2016       Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  jrt@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module provides the function 'importCheck' to check and expand+    the import specifications of all import declarations.+-}+module Checks.ImportSyntaxCheck(importCheck) where++import           Control.Monad              (liftM, unless)+import qualified Control.Monad.State as S   (State, gets, modify, runState)+import           Data.List                  (nub, union)+import qualified Data.Map            as Map+import           Data.Maybe                 (fromMaybe)++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Syntax hiding (Var (..))++import Base.Messages+import Base.TopEnv++importCheck :: Interface -> Maybe ImportSpec -> (Maybe ImportSpec, [Message])+importCheck (Interface m _ ds) is = runExpand (expandSpecs is) m mTCEnv mTyEnv+  where+  mTCEnv = intfEnv types  ds+  mTyEnv = intfEnv values ds++data ITypeInfo = Data  QualIdent [Ident]+               | Alias QualIdent+               | Class QualIdent [Ident]+ deriving Show++instance Entity ITypeInfo where+  origName (Data  tc  _) = tc+  origName (Alias tc   ) = tc+  origName (Class cls _) = cls++  merge (Data tc1 cs1) (Data tc2 cs2)+    | tc1 == tc2 && (null cs1 || null cs2 || cs1 == cs2) =+        Just $ Data tc1 (if null cs1 then cs2 else cs1)+  merge l@(Alias tc1) (Alias tc2)+    | tc1 == tc2 = Just l+  merge (Class cls1 ms1) (Class cls2 ms2)+    | cls1 == cls2 && (null ms1 || null ms2 || ms1 == ms2) =+        Just $ Class cls1 (if null ms1 then ms2 else ms1)+  merge _ _ = Nothing++data IValueInfo = Constr QualIdent+                | Var    QualIdent [QualIdent]+ deriving Show++instance Entity IValueInfo where+  origName (Constr c) = c+  origName (Var  x _) = x++  merge (Constr c1) (Constr c2)+    | c1 == c2 = Just (Constr c1)+  merge (Var x1 cs1) (Var x2 cs2)+    | x1 == x2 = Just (Var x1 (cs1 `union` cs2))+  merge _ _ = Nothing+++intfEnv :: Entity a => (IDecl -> [a]) -> [IDecl] -> IdentMap a+intfEnv idents ds = foldr bindId Map.empty (concatMap idents ds)+  where bindId x = Map.insert (unqualify (origName x)) x++types :: IDecl -> [ITypeInfo]+types (IDataDecl     _ tc _ _ cs hs) = [Data tc (filter (`notElem` hs) xs)]+  where xs = map constrId cs ++ nub (concatMap recordLabels cs)+types (INewtypeDecl  _ tc _ _ nc hs) = [Data tc (filter (`notElem` hs) xs)]+  where xs = nconstrId nc : nrecordLabels nc+types (ITypeDecl         _ tc _ _ _) = [Alias tc]+types (IClassDecl _ _ cls _ _ ms hs) = [Class cls (filter (`notElem` hs) xs)]+  where xs = map imethod ms+types _                              = []++values :: IDecl -> [IValueInfo]+values (IDataDecl     _ tc _ _ cs hs) =+  cidents tc (map constrId cs) hs +++  lidents tc [(l, lconstrs cs l) | l <- nub (concatMap recordLabels cs)] hs+  where lconstrs cons l = [constrId c | c <- cons, l `elem` recordLabels c]+values (INewtypeDecl  _ tc _ _ nc hs) =+  cidents tc [nconstrId nc] hs +++  lidents tc [(l, [c]) | NewRecordDecl _ c (l, _) <- [nc]] hs+values (IFunctionDecl      _ f _ _ _) = [Var f []]+values (IClassDecl _ _ cls _ _ ms hs) = midents cls (map imethod ms) hs+values _                              = []++cidents :: QualIdent -> [Ident] -> [Ident] -> [IValueInfo]+cidents tc cs hs = [Constr (qualifyLike tc c) | c <- cs, c `notElem` hs]++lidents :: QualIdent -> [(Ident, [Ident])] -> [Ident] -> [IValueInfo]+lidents tc ls hs = [ Var (qualifyLike tc l) (map (qualifyLike tc) cs)+                   | (l, cs) <- ls, l `notElem` hs+                   ]++midents :: QualIdent -> [Ident] -> [Ident] -> [IValueInfo]+midents cls fs hs = [Var (qualifyLike cls f) [] | f <- fs, f `notElem` hs]++-- ---------------------------------------------------------------------------+-- Expansion of the import specification+-- ---------------------------------------------------------------------------++-- After the environments have been initialized, the optional import+-- specifications can be checked. There are two kinds of import+-- specifications, a ``normal'' one, which names the entities that shall+-- be imported, and a hiding specification, which lists those entities+-- that shall not be imported.+--+-- There is a subtle difference between both kinds of+-- specifications: While it is not allowed to list a data constructor+-- outside of its type in a ``normal'' specification, it is allowed to+-- hide a data constructor explicitly. E.g., if module \texttt{A} exports+-- the data type \texttt{T} with constructor \texttt{C}, the data+-- constructor can be imported with one of the two specifications+--+-- import A (T(C))+-- import A (T(..))+--+-- but can be hidden in three different ways:+--+-- import A hiding (C)+-- import A hiding (T (C))+-- import A hiding (T (..))+--+-- The functions \texttt{expandImport} and \texttt{expandHiding} check+-- that all entities in an import specification are actually exported+-- from the module. In addition, all imports of type constructors are+-- changed into a \texttt{T()} specification and explicit imports for the+-- data constructors are added.++type IdentMap    = Map.Map Ident++type ExpTCEnv    = IdentMap ITypeInfo+type ExpValueEnv = IdentMap IValueInfo++data ExpandState = ExpandState+  { expModIdent :: ModuleIdent+  , expTCEnv    :: ExpTCEnv+  , expValueEnv :: ExpValueEnv+  , errors      :: [Message]+  }++type ExpandM a = S.State ExpandState a++getModuleIdent :: ExpandM ModuleIdent+getModuleIdent = S.gets expModIdent++getTyConsEnv :: ExpandM ExpTCEnv+getTyConsEnv = S.gets expTCEnv++getValueEnv :: ExpandM ExpValueEnv+getValueEnv = S.gets expValueEnv++report :: Message -> ExpandM ()+report msg = S.modify $ \ s -> s { errors = msg : errors s }++runExpand :: ExpandM a -> ModuleIdent -> ExpTCEnv -> ExpValueEnv -> (a, [Message])+runExpand expand m tcEnv tyEnv =+  let (r, s) = S.runState expand (ExpandState m tcEnv tyEnv [])+  in (r, reverse $ errors s)++expandSpecs :: Maybe ImportSpec -> ExpandM (Maybe ImportSpec)+expandSpecs Nothing                 = return Nothing+expandSpecs (Just (Importing p is)) = (Just . Importing p . concat) `liftM` mapM expandImport is+expandSpecs (Just (Hiding    p is)) = (Just . Hiding    p . concat) `liftM` mapM expandHiding is++expandImport :: Import -> ExpandM [Import]+expandImport (Import             x) =               expandThing    x+expandImport (ImportTypeWith tc cs) = (:[]) `liftM` expandTypeWith tc cs+expandImport (ImportTypeAll     tc) = (:[]) `liftM` expandTypeAll  tc++expandHiding :: Import -> ExpandM [Import]+expandHiding (Import             x) = expandHide x+expandHiding (ImportTypeWith tc cs) = (:[]) `liftM` expandTypeWith tc cs+expandHiding (ImportTypeAll     tc) = (:[]) `liftM` expandTypeAll  tc++-- try to expand as type constructor+expandThing :: Ident -> ExpandM [Import]+expandThing tc = do+  tcEnv <- getTyConsEnv+  case Map.lookup tc tcEnv of+    Just _  -> expandThing' tc $ Just [ImportTypeWith tc []]+    Nothing -> expandThing' tc Nothing++-- try to expand as function / data constructor+expandThing' :: Ident -> Maybe [Import] -> ExpandM [Import]+expandThing' f tcImport = do+  m     <- getModuleIdent+  tyEnv <- getValueEnv+  expand m f (Map.lookup f tyEnv) tcImport+  where+  expand :: ModuleIdent -> Ident+         -> Maybe IValueInfo -> Maybe [Import] -> ExpandM [Import]+  expand m e Nothing  Nothing   = report (errUndefinedEntity m e) >> return []+  expand _ _ Nothing  (Just tc) = return tc+  expand m e (Just v) maybeTc+    | isConstr v = case maybeTc of+        Nothing -> report (errImportDataConstr m e) >> return []+        Just tc -> return tc+    | otherwise  = return [Import e]++  isConstr (Constr _) = True+  isConstr (Var  _ _) = False++-- try to hide as type constructor+expandHide :: Ident -> ExpandM [Import]+expandHide tc = do+  tcEnv <- getTyConsEnv+  case Map.lookup tc tcEnv of+    Just _  -> expandHide' tc $ Just [ImportTypeWith tc []]+    Nothing -> expandHide' tc Nothing++-- try to hide as function / data constructor+expandHide' :: Ident -> Maybe [Import] -> ExpandM [Import]+expandHide' f tcImport = do+  m     <- getModuleIdent+  tyEnv <- getValueEnv+  case Map.lookup f tyEnv of+    Just _  -> return $ Import f : fromMaybe [] tcImport+    Nothing -> case tcImport of+      Nothing -> report (errUndefinedEntity m f) >> return []+      Just tc -> return tc++expandTypeWith ::  Ident -> [Ident] -> ExpandM Import+expandTypeWith tc cs = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  ImportTypeWith tc `liftM` case Map.lookup tc tcEnv of+    Just (Data  _ xs) -> mapM (checkElement errUndefinedElement xs) cs+    Just (Class _ xs) -> mapM (checkElement errUndefinedMethod  xs) cs+    Just (Alias    _) -> report (errNonDataTypeOrTypeClass tc) >> return []+    Nothing           -> report (errUndefinedEntity      m tc) >> return []+  where+  -- check if given identifier is constructor or label of type tc+  checkElement err cs' c = do+    unless (c `elem` cs') $ report $ err tc c+    return c++expandTypeAll :: Ident -> ExpandM Import+expandTypeAll tc = do+  m     <- getModuleIdent+  tcEnv <- getTyConsEnv+  ImportTypeWith tc `liftM` case Map.lookup tc tcEnv of+    Just (Data _  xs) -> return xs+    Just (Class _ xs) -> return xs+    Just (Alias    _) -> report (errNonDataTypeOrTypeClass tc) >> return []+    Nothing           -> report (errUndefinedEntity      m tc) >> return []++-- error messages++errUndefinedElement :: Ident -> Ident -> Message+errUndefinedElement tc c = posMessage c $ hsep $ map text+  [ idName c, "is not a constructor or label of type ", idName tc ]++errUndefinedMethod :: Ident -> Ident -> Message+errUndefinedMethod cls f = posMessage f $ hsep $ map text+  [ idName f, "is not a method of class", idName cls ]++errUndefinedEntity :: ModuleIdent -> Ident -> Message+errUndefinedEntity m x = posMessage x $ hsep $ map text+  [ "Module", moduleName m, "does not export", idName x ]++errNonDataTypeOrTypeClass :: Ident -> Message+errNonDataTypeOrTypeClass tc = posMessage tc $ hsep $ map text+  [ idName tc, "is not a data type or type class" ]++errImportDataConstr :: ModuleIdent -> Ident -> Message+errImportDataConstr _ c = posMessage c $ hsep $ map text+  [ "Explicit import for data constructor", idName c ]
+ src/Checks/InstanceCheck.hs view
@@ -0,0 +1,356 @@+{- |+    Module      :  $Header$+    Description :  Checks instances+    Copyright   :  (c)        2016 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   Before type checking, the compiler checks for every instance declaration+   that all necessary super class instances exist. Furthermore, the compiler+   infers the contexts of the implicit instance declarations introduced by+   deriving clauses in data and newtype declarations. The instances declared+   explicitly and automatically derived by the compiler are added to the+   instance environment . It is also checked that there are no duplicate+   instances and that all types specified in a default declaration are+   instances of the Num class.+-}+module Checks.InstanceCheck (instanceCheck) where++import           Control.Monad.Extra        (concatMapM, whileM)+import qualified Control.Monad.State as S   (State, execState, gets, modify)+import           Data.List                  (nub, partition, sortBy)+import qualified Data.Map            as Map+import qualified Data.Set.Extra      as Set++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax hiding (impls)+import Curry.Syntax.Pretty++import Base.CurryTypes+import Base.Messages (Message, posMessage, message, internalError)+import Base.SCC (scc)+import Base.TypeExpansion+import Base.Types+import Base.TypeSubst+import Base.Utils (fst3, snd3, findMultiples)++import Env.Class+import Env.Instance+import Env.TypeConstructor++instanceCheck :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Decl a]+              -> (InstEnv, [Message])+instanceCheck m tcEnv clsEnv inEnv ds =+  case findMultiples (local ++ imported) of+    [] -> execINCM (checkDecls tcEnv clsEnv ds) state+    iss -> (inEnv, map (errMultipleInstances tcEnv) iss)+  where+    local = map (flip InstSource m) $ concatMap (genInstIdents m tcEnv) ds+    imported = map (uncurry InstSource) $ map (fmap fst3) $ Map.toList inEnv+    state = INCState m inEnv []++-- In order to provide better error messages, we use the following data type+-- to keep track of an instance's source, i.e., the module it was defined in.++data InstSource = InstSource InstIdent ModuleIdent++instance Eq InstSource where+  InstSource i1 _ == InstSource i2 _ = i1 == i2++-- |Instance Check Monad+type INCM = S.State INCState++-- |Internal state of the Instance Check+data INCState = INCState+  { moduleIdent :: ModuleIdent+  , instEnv     :: InstEnv+  , errors      :: [Message]+  }++execINCM :: INCM a -> INCState -> (InstEnv, [Message])+execINCM incm s =+  let s' = S.execState incm s in (instEnv s', reverse $ nub $ errors s')++getModuleIdent :: INCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getInstEnv :: INCM InstEnv+getInstEnv = S.gets instEnv++modifyInstEnv :: (InstEnv -> InstEnv) -> INCM ()+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }++report :: Message -> INCM ()+report err = S.modify (\s -> s { errors = err : errors s })++ok :: INCM ()+ok = return ()++checkDecls :: TCEnv -> ClassEnv -> [Decl a] -> INCM ()+checkDecls tcEnv clsEnv ds = do+  mapM_ (bindInstance tcEnv clsEnv) ids+  mapM (declDeriveInfo tcEnv clsEnv) (filter hasDerivedInstances tds) >>=+    mapM_ (bindDerivedInstances clsEnv) . groupDeriveInfos+  mapM_ (checkInstance tcEnv clsEnv) ids+  mapM_ (checkDefault tcEnv clsEnv) dds+  where (tds, ods) = partition isTypeDecl ds+        ids = filter isInstanceDecl ods+        dds = filter isDefaultDecl ods++-- First, the compiler adds all explicit instance declarations to the+-- instance environment.++bindInstance :: TCEnv -> ClassEnv -> Decl a -> INCM ()+bindInstance tcEnv clsEnv (InstanceDecl _ cx qcls inst ds) = do+  m <- getModuleIdent+  let PredType ps _ = expandPolyType m tcEnv clsEnv $ QualTypeExpr cx inst+  modifyInstEnv $+    bindInstInfo (genInstIdent m tcEnv qcls inst) (m, ps, impls [] ds)+  where impls is [] = is+        impls is (FunctionDecl _ _ f eqs:ds')+          | f' `elem` map fst is = impls is ds'+          | otherwise            = impls ((f', eqnArity $ head eqs) : is) ds'+          where f' = unRenameIdent f+        impls _ _ = internalError "InstanceCheck.bindInstance.impls"+bindInstance _     _      _                                = ok++-- Next, the compiler sorts the data and newtype declarations with non-empty+-- deriving clauses into minimal binding groups and infers contexts for their+-- instance declarations. In the case of (mutually) recursive data types,+-- inference of the appropriate contexts may require a fixpoint calculation.++hasDerivedInstances :: Decl a -> Bool+hasDerivedInstances (DataDecl    _ _ _ _ clss) = not $ null clss+hasDerivedInstances (NewtypeDecl _ _ _ _ clss) = not $ null clss+hasDerivedInstances _                          = False++-- For the purposes of derived instances, a newtype declaration is treated+-- as a data declaration with a single constructor. The compiler also sorts+-- derived classes with respect to the super class hierarchy so that subclass+-- instances are added to the instance environment after their super classes.++data DeriveInfo = DeriveInfo Position QualIdent PredType [Type] [QualIdent]++declDeriveInfo :: TCEnv -> ClassEnv -> Decl a -> INCM DeriveInfo+declDeriveInfo tcEnv clsEnv (DataDecl p tc tvs cs clss) =+  mkDeriveInfo tcEnv clsEnv p tc tvs (concat cxs) (concat tyss) clss+  where (cxs, tyss) = unzip (map constrDeclTypes cs)+        constrDeclTypes (ConstrDecl     _ _ cx _ tys) = (cx, tys)+        constrDeclTypes (ConOpDecl  _ _ cx ty1 _ ty2) = (cx, [ty1, ty2])+        constrDeclTypes (RecordDecl      _ _ cx _ fs) = (cx, tys)+          where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]+declDeriveInfo tcEnv clsEnv (NewtypeDecl p tc tvs nc clss) =+  mkDeriveInfo tcEnv clsEnv p tc tvs [] [nconstrType nc] clss+declDeriveInfo _ _ _ =+  internalError "InstanceCheck.declDeriveInfo: no data or newtype declaration"++mkDeriveInfo :: TCEnv -> ClassEnv -> Position -> Ident -> [Ident] -> Context+           -> [TypeExpr] -> [QualIdent] -> INCM DeriveInfo+mkDeriveInfo tcEnv clsEnv p tc tvs cx tys clss = do+  m <- getModuleIdent+  let otc = qualifyWith m tc+      oclss = map (flip (getOrigName m) tcEnv) clss+      PredType ps ty = expandConstrType m tcEnv clsEnv otc tvs cx tys+      (tys', ty') = arrowUnapply ty+  return $ DeriveInfo p otc (PredType ps ty') tys' $ sortClasses clsEnv oclss++sortClasses :: ClassEnv -> [QualIdent] -> [QualIdent]+sortClasses clsEnv clss = map fst $ sortBy compareDepth $ map adjoinDepth clss+  where (_, d1) `compareDepth` (_, d2) = d1 `compare` d2+        adjoinDepth cls = (cls, length $ allSuperClasses cls clsEnv)++groupDeriveInfos :: [DeriveInfo] -> [[DeriveInfo]]+groupDeriveInfos ds = scc bound free ds+  where bound (DeriveInfo _ tc _ _ _) = [tc]+        free (DeriveInfo _ _ _ tys _) = concatMap typeConstrs tys++bindDerivedInstances :: ClassEnv -> [DeriveInfo] -> INCM ()+bindDerivedInstances clsEnv dis = do+  mapM_ (enterInitialPredSet clsEnv) dis+  whileM $ concatMapM (inferPredSets clsEnv) dis >>= updatePredSets++enterInitialPredSet :: ClassEnv -> DeriveInfo -> INCM ()+enterInitialPredSet clsEnv (DeriveInfo p tc pty _ clss) =+  mapM_ (bindDerivedInstance clsEnv p tc pty []) clss++-- Note: The methods and arities entered into the instance environment have+-- to match methods and arities of the later generated instance declarations.++bindDerivedInstance :: ClassEnv -> Position -> QualIdent -> PredType -> [Type]+                    -> QualIdent -> INCM ()+bindDerivedInstance clsEnv p tc pty tys cls = do+  m <- getModuleIdent+  (i, ps) <- inferPredSet clsEnv p tc pty tys cls+  modifyInstEnv $ bindInstInfo i (m, ps, impls)+  where impls | cls == qEqId      = [(eqOpId, 2)]+              | cls == qOrdId     = [(leqOpId, 2)]+              | cls == qEnumId    = [ (succId, 1), (predId, 1), (toEnumId, 1)+                                    , (fromEnumId, 1), (enumFromId, 1)+                                    , (enumFromThenId, 2)+                                    ]+              | cls == qBoundedId = [(maxBoundId, 1), (minBoundId, 1)]+              | cls == qReadId    = [(readsPrecId, 2)]+              | cls == qShowId    = [(showsPrecId, 2)]+              | otherwise         =+                internalError "InstanceCheck.bindDerivedInstance.impls"++inferPredSets :: ClassEnv -> DeriveInfo -> INCM [(InstIdent, PredSet)]+inferPredSets clsEnv (DeriveInfo p tc pty tys clss) =+  mapM (inferPredSet clsEnv p tc pty tys) clss++inferPredSet :: ClassEnv -> Position -> QualIdent -> PredType -> [Type]+             -> QualIdent -> INCM (InstIdent, PredSet)+inferPredSet clsEnv p tc (PredType ps inst) tys cls = do+  m <- getModuleIdent+  let doc = ppPred m $ Pred cls inst+      sclss = superClasses cls clsEnv+      ps'   = Set.fromList [Pred cls ty | ty <- tys]+      ps''  = Set.fromList [Pred scls inst | scls <- sclss]+      ps''' = ps `Set.union` ps' `Set.union` ps''+  ps'''' <- reducePredSet p "derived instance" doc clsEnv ps'''+  mapM_ (reportUndecidable p "derived instance" doc) $ Set.toList ps''''+  return ((cls, tc), ps'''')++updatePredSets :: [(InstIdent, PredSet)] -> INCM Bool+updatePredSets = (=<<) (return . or) . mapM (uncurry updatePredSet)++updatePredSet :: InstIdent -> PredSet -> INCM Bool+updatePredSet i ps = do+  inEnv <- getInstEnv+  case lookupInstInfo i inEnv of+    Just (m, ps', is)+      | ps == ps' -> return False+      | otherwise -> do+        modifyInstEnv $ bindInstInfo i (m, ps, is)+        return True+    Nothing -> internalError "InstanceCheck.updatePredSet"++reportUndecidable :: Position -> String -> Doc -> Pred -> INCM ()+reportUndecidable p what doc predicate@(Pred _ ty) = do+  m <- getModuleIdent+  case ty of+    TypeVariable _ -> return ()+    _ -> report $ errMissingInstance m p what doc predicate++-- Then, the compiler checks the contexts of all explicit instance+-- declarations to detect missing super class instances. For an instance+-- declaration+--+-- instance cx => C (T u_1 ... u_k) where ...+--+-- the compiler ensures that T is an instance of all of C's super classes+-- and also that the contexts of the corresponding instance declarations are+-- satisfied by cx.++checkInstance :: TCEnv -> ClassEnv -> Decl a -> INCM ()+checkInstance tcEnv clsEnv (InstanceDecl p cx cls inst _) = do+  m <- getModuleIdent+  let PredType ps ty = expandPolyType m tcEnv clsEnv $ QualTypeExpr cx inst+      ocls = getOrigName m cls tcEnv+      ps' = Set.fromList [ Pred scls ty | scls <- superClasses ocls clsEnv ]+      doc = ppPred m $ Pred cls ty+      what = "instance declaration"+  ps'' <- reducePredSet p what doc clsEnv ps'+  Set.mapM_ (report . errMissingInstance m p what doc) $+    ps'' `Set.difference` (maxPredSet clsEnv ps)+checkInstance _ _ _ = ok++-- All types specified in the optional default declaration of a module+-- must be instances of the Num class. Since these types are used to resolve+-- ambiguous type variables, the predicate sets of the respective instances+-- must be empty.++checkDefault :: TCEnv -> ClassEnv -> Decl a -> INCM ()+checkDefault tcEnv clsEnv (DefaultDecl p tys) =+  mapM_ (checkDefaultType p tcEnv clsEnv) tys+checkDefault _ _ _ = ok++checkDefaultType :: Position -> TCEnv -> ClassEnv -> TypeExpr -> INCM ()+checkDefaultType p tcEnv clsEnv ty = do+  m <- getModuleIdent+  let PredType _ ty' = expandPolyType m tcEnv clsEnv $ QualTypeExpr [] ty+  ps <- reducePredSet p what empty clsEnv (Set.singleton $ Pred qNumId ty')+  Set.mapM_ (report . errMissingInstance m p what empty) ps+  where what = "default declaration"++-- The function 'reducePredSet' simplifies a predicate set of the form+-- (C_1 tau_1,..,C_n tau_n) where the tau_i are arbitrary types into a+-- predicate set where all predicates are of the form C u with u being+-- a type variable. An error is reported if the predicate set cannot+-- be transformed into this form. In addition, we remove all predicates+-- that are implied by others within the same set.++reducePredSet :: Position -> String -> Doc -> ClassEnv -> PredSet+              -> INCM PredSet+reducePredSet p what doc clsEnv ps = do+  m <- getModuleIdent+  inEnv <- getInstEnv+  let (ps1, ps2) = partitionPredSet $ minPredSet clsEnv $ reducePreds inEnv ps+  Set.mapM_ (report . errMissingInstance m p what doc) ps2+  return ps1+  where+    reducePreds inEnv = Set.concatMap $ reducePred inEnv+    reducePred inEnv predicate = maybe (Set.singleton predicate)+                                       (reducePreds inEnv)+                                       (instPredSet inEnv predicate)++instPredSet :: InstEnv -> Pred -> Maybe PredSet+instPredSet inEnv (Pred qcls ty) =+  case unapplyType False ty of+    (TypeConstructor tc, tys) ->+      fmap (expandAliasType tys . snd3) (lookupInstInfo (qcls, tc) inEnv)+    _ -> Nothing++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++genInstIdents :: ModuleIdent -> TCEnv -> Decl a -> [InstIdent]+genInstIdents m tcEnv (DataDecl    _ tc _ _ qclss) =+  map (flip (genInstIdent m tcEnv) $ ConstructorType $ qualify tc) qclss+genInstIdents m tcEnv (NewtypeDecl _ tc _ _ qclss) =+  map (flip (genInstIdent m tcEnv) $ ConstructorType $ qualify tc) qclss+genInstIdents m tcEnv (InstanceDecl _ _ qcls ty _) =+  [genInstIdent m tcEnv qcls ty]+genInstIdents _ _     _                            = []++genInstIdent :: ModuleIdent -> TCEnv -> QualIdent -> TypeExpr -> InstIdent+genInstIdent m tcEnv qcls = qualInstIdent m tcEnv . (,) qcls . typeConstr++-- When qualifiying an instance identifier, we replace both the class and+-- type constructor with their original names as found in the type constructor+-- environment.++qualInstIdent :: ModuleIdent -> TCEnv -> InstIdent -> InstIdent+qualInstIdent m tcEnv (cls, tc) = (qual cls, qual tc)+  where+    qual = flip (getOrigName m) tcEnv++unqualInstIdent :: TCEnv -> InstIdent -> InstIdent+unqualInstIdent tcEnv (qcls, tc) = (unqual qcls, unqual tc)+  where+    unqual = head . flip reverseLookupByOrigName tcEnv++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errMultipleInstances :: TCEnv -> [InstSource] -> Message+errMultipleInstances tcEnv iss = message $+  text "Multiple instances for the same class and type" $+$+    nest 2 (vcat (map ppInstSource iss))+  where+    ppInstSource (InstSource i m) = ppInstIdent (unqualInstIdent tcEnv i) <+>+      parens (text "defined in" <+> ppMIdent m)++errMissingInstance :: ModuleIdent -> Position -> String -> Doc -> Pred+                   -> Message+errMissingInstance m p what doc predicate = posMessage p $ vcat+  [ text "Missing instance for" <+> ppPred m predicate+  , text "in" <+> text what <+> doc+  ]
+ src/Checks/InterfaceCheck.hs view
@@ -0,0 +1,315 @@+{- |+    Module      :  $Header$+    Description :  Checks consistency of interface files+    Copyright   :  (c) 2000 - 2007 Wolfgang Lux+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   Interface files include declarations of all entities that are exported+   by the module, but defined in another module. Since these declarations+   can become inconsistent if client modules are not recompiled properly,+   the compiler checks that all imported declarations in an interface+   agree with their original definitions.++   One may ask why we include imported declarations at all, if the+   compiler always has to compare those declarations with the original+   definitions. The main reason for this is that it helps to avoid+   unnecessary recompilations of client modules. As an example, consider+   the three modules:++     module A where { data T = C }+     module B(T(..)) where { import A }+     module C where { import B; f = C }++   where module B could be considered as a public interface of module A,+   which restricts access to type A.T and its constructor C.+   The client module C imports this type via the public interface B.+   If now module A is changed by adding a definition of a new global function++     module A where { data T = C; f = C }++   module B must be recompiled because A's interface is changed.+   On the other hand, module C need not be recompiled because the change in+   A does not affect B's interface. By including the declaration of type A.T+   in B's interface, the compiler can trivially check that B's interface+   remains unchanged and therefore the client module C is not recompiled.++   Another reason for including imported declarations in interfaces is+   that the compiler in principle could avoid loading interfaces of+   modules that are imported only indirectly, which would save processing+   time and allow distributing binary packages of a library with a public+   interface module only. However, this has not been implemented yet.+-}++module Checks.InterfaceCheck (interfaceCheck) where++import           Control.Monad            (unless)+import qualified Control.Monad.State as S+import           Data.List                (sort)+import           Data.Maybe               (fromMaybe)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax++import Base.CurryKinds (toKind')+import Base.CurryTypes+import Base.Messages (Message, posMessage, internalError)+import Base.TopEnv+import Base.Types++import Env.Class+import Env.Instance+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++data ICState = ICState+  { moduleIdent :: ModuleIdent+  , precEnv     :: OpPrecEnv+  , tyConsEnv   :: TCEnv+  , classEnv    :: ClassEnv+  , instEnv     :: InstEnv+  , valueEnv    :: ValueEnv+  , errors      :: [Message]+  }++type IC = S.State ICState++getModuleIdent :: IC ModuleIdent+getModuleIdent = S.gets moduleIdent++getPrecEnv :: IC OpPrecEnv+getPrecEnv = S.gets precEnv++getTyConsEnv :: IC TCEnv+getTyConsEnv = S.gets tyConsEnv++getClassEnv :: IC ClassEnv+getClassEnv = S.gets classEnv++getInstEnv :: IC InstEnv+getInstEnv = S.gets instEnv++getValueEnv :: IC ValueEnv+getValueEnv = S.gets valueEnv++-- |Report a syntax error+report :: Message -> IC ()+report msg = S.modify $ \s -> s { errors = msg : errors s }++ok :: IC ()+ok = return ()++interfaceCheck :: OpPrecEnv -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv+               -> Interface -> [Message]+interfaceCheck pEnv tcEnv clsEnv inEnv tyEnv (Interface m _ ds) = reverse (errors s)+  where s = S.execState (mapM_ checkImport ds) initState+        initState = ICState m pEnv tcEnv clsEnv inEnv tyEnv []++checkImport :: IDecl -> IC ()+checkImport (IInfixDecl p fix pr op) = checkPrecInfo check p op+  where check (PrecInfo op' (OpPrec fix' pr')) =+          op == op' && fix == fix' && pr == pr'+checkImport (HidingDataDecl p tc k tvs) =+  checkTypeInfo "hidden data type" check p tc+  where check (DataType     tc' k' _)+          | tc == tc' && toKind' k (length tvs) == k' = Just ok+        check (RenamingType tc' k' _)+          | tc == tc' && toKind' k (length tvs) == k' = Just ok+        check _ = Nothing+checkImport (IDataDecl p tc k tvs cs _) = checkTypeInfo "data type" check p tc+  where check (DataType     tc' k' cs')+          | tc == tc' && toKind' k (length tvs) == k' &&+            (null cs || map constrId cs == map constrIdent cs')+          = Just (mapM_ (checkConstrImport tc tvs) cs)+        check (RenamingType tc' k'   _)+          | tc == tc' && toKind' k (length tvs) == k' && null cs+          = Just ok+        check _ = Nothing+checkImport (INewtypeDecl p tc k tvs nc _) = checkTypeInfo "newtype" check p tc+  where check (RenamingType tc' k' nc')+          | tc == tc' && toKind' k (length tvs) == k' &&+            nconstrId nc == constrIdent nc'+          = Just (checkNewConstrImport tc tvs nc)+        check _ = Nothing+checkImport (ITypeDecl p tc k tvs ty) = do+  m <- getModuleIdent+  let check (AliasType tc' k' n' ty')+        | tc == tc' && toKind' k (length tvs) == k' &&+          length tvs == n' && toQualType m tvs ty == ty'+        = Just ok+      check _ = Nothing+  checkTypeInfo "synonym type" check p tc+checkImport (IFunctionDecl p f (Just tv) n ty) = do+  m <- getModuleIdent+  let check (Value f' cm' n' (ForAll _ ty')) =+        f == f' && True == cm' && n' == n && toQualPredType m [tv] ty == ty'+      check _ = False+  checkValueInfo "method" check p f+checkImport (IFunctionDecl p f Nothing n ty) = do+  m <- getModuleIdent+  let check (Value f' cm' n' (ForAll _ ty')) =+        f == f' && False == cm' && n' == n && toQualPredType m [] ty == ty'+      check _ = False+  checkValueInfo "function" check p f+checkImport (HidingClassDecl p cx cls k _) = do+  clsEnv <- getClassEnv+  let check (TypeClass cls' k' _)+        | cls == cls' && toKind' k 0 == k' &&+          [cls'' | Constraint cls'' _ <- cx] == superClasses cls' clsEnv+        = Just ok+      check _ = Nothing+  checkTypeInfo "hidden type class" check p cls+checkImport (IClassDecl p cx cls k clsvar ms _) = do+  clsEnv <- getClassEnv+  let check (TypeClass cls' k' fs)+        | cls == cls' && toKind' k 0 == k' &&+          [cls'' | Constraint cls'' _ <- cx] == superClasses cls' clsEnv &&+          map (\m -> (imethod m, imethodArity m)) ms ==+            map (\f -> (methodName f, methodArity f)) fs+        = Just $ mapM_ (checkMethodImport cls clsvar) ms+      check _ = Nothing+  checkTypeInfo "type class" check p cls+checkImport (IInstanceDecl p cx cls ty is m) = do+  checkInstInfo check p (cls, typeConstr ty) m+  where PredType ps _ = toPredType [] $ QualTypeExpr cx ty+        check ps' is' = ps == ps' && sort is == sort is'++checkConstrImport :: QualIdent -> [Ident] -> ConstrDecl -> IC ()+checkConstrImport tc tvs (ConstrDecl p evs cx c tys) = do+  m <- getModuleIdent+  let qc = qualifyLike tc c+      check (DataConstructor c' _ _ (ForAllExist uqvs eqvs pty)) =+        qc == c' && length evs == eqvs && length tvs == uqvs &&+        qualifyPredType m (toConstrType tc tvs cx tys) == pty+      check _ = False+  checkValueInfo "data constructor" check p qc+checkConstrImport tc tvs (ConOpDecl p evs cx ty1 op ty2) = do+  m <- getModuleIdent+  let qc = qualifyLike tc op+      check (DataConstructor c' _ _ (ForAllExist uqvs eqvs pty)) =+        qc == c' && length evs == eqvs && length tvs == uqvs &&+        qualifyPredType m (toConstrType tc tvs cx [ty1, ty2]) == pty+      check _ = False+  checkValueInfo "data constructor" check p qc+checkConstrImport tc tvs (RecordDecl p evs cx c fs) = do+  m <- getModuleIdent+  let qc = qualifyLike tc c+      (ls, tys) = unzip [(l, ty) | FieldDecl _ labels ty <- fs, l <- labels]+      check (DataConstructor c' _ ls' (ForAllExist uqvs eqvs pty)) =+        qc == c' && length evs == eqvs && length tvs == uqvs && ls == ls' &&+        qualifyPredType m (toConstrType tc tvs cx tys) == pty+      check _ = False+  checkValueInfo "data constructor" check p qc++checkNewConstrImport :: QualIdent -> [Ident] -> NewConstrDecl -> IC ()+checkNewConstrImport tc tvs (NewConstrDecl p c ty) = do+  m <- getModuleIdent+  let qc = qualifyLike tc c+      check (NewtypeConstructor c' _ (ForAllExist uqvs _ (PredType _ ty'))) =+        qc == c' && length tvs == uqvs &&toQualType m tvs ty == head (arrowArgs ty')+      check _ = False+  checkValueInfo "newtype constructor" check p qc+checkNewConstrImport tc tvs (NewRecordDecl p c (l, ty)) = do+  m <- getModuleIdent+  let qc = qualifyLike tc c+      check (NewtypeConstructor c' l' (ForAllExist uqvs _ (PredType _ ty'))) =+        qc == c' && length tvs == uqvs && l == l' &&+        toQualType m tvs ty == head (arrowArgs ty')+      check _ = False+  checkValueInfo "newtype constructor" check p qc++checkMethodImport :: QualIdent -> Ident -> IMethodDecl -> IC ()+checkMethodImport qcls clsvar (IMethodDecl p f _ qty) =+  checkValueInfo "method" check p qf+  where qf = qualifyLike qcls f+        check (Value f' cm' _ (ForAll _ pty)) =+          qf == f' && cm' == True && toMethodType qcls clsvar qty == pty+        check _ = False++checkPrecInfo :: (PrecInfo -> Bool) -> Position -> QualIdent -> IC ()+checkPrecInfo check p op = do+  pEnv <- getPrecEnv+  let checkInfo m op' = case qualLookupTopEnv op pEnv of+        []     -> report $ errNoPrecedence p m op'+        [prec] -> unless (check prec)+                         (report $ errImportConflict p "precedence" m op')+        _      -> internalError "checkPrecInfo"+  checkImported checkInfo op++checkTypeInfo :: String -> (TypeInfo -> Maybe (IC ())) -> Position+              -> QualIdent -> IC ()+checkTypeInfo what check p tc = do+  tcEnv <- getTyConsEnv+  let checkInfo m tc' = case qualLookupTopEnv tc tcEnv of+        []   -> report $ errNotExported p what m tc'+        [ti] -> fromMaybe (report $ errImportConflict p what m tc') (check ti)+        _    -> internalError "checkTypeInfo"+  checkImported checkInfo tc++checkInstInfo :: (PredSet -> [(Ident, Int)] -> Bool) -> Position -> InstIdent+              -> Maybe ModuleIdent -> IC ()+checkInstInfo check p i mm = do+  inEnv <- getInstEnv+  let checkInfo m _ = case lookupInstInfo i inEnv of+        Just (m', ps, is)+          | m /= m'   -> report $ errNoInstance p m i+          | otherwise ->+            unless (check ps is) $ report $ errInstanceConflict p m i+        Nothing -> report $ errNoInstance p m i+  checkImported checkInfo (maybe qualify qualifyWith mm anonId)++checkValueInfo :: String -> (ValueInfo -> Bool) -> Position+               -> QualIdent -> IC ()+checkValueInfo what check p x = do+  tyEnv <- getValueEnv+  let checkInfo m x' = case qualLookupTopEnv x tyEnv of+        []   -> report $ errNotExported p what m x'+        [vi] -> unless (check vi) (report $ errImportConflict p what m x')+        _    -> internalError "checkValueInfo"+  checkImported checkInfo x++checkImported :: (ModuleIdent -> Ident -> IC ()) -> QualIdent -> IC ()+checkImported _ (QualIdent Nothing  _) = ok+checkImported f (QualIdent (Just m) x) = f m x++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errNotExported :: Position -> String -> ModuleIdent -> Ident -> Message+errNotExported p what m x = posMessage p $+  text "Inconsistent module interfaces"+  $+$ text "Module" <+> text (moduleName m)+  <+> text "does not export"<+> text what <+> text (escName x)++errNoPrecedence :: Position -> ModuleIdent -> Ident -> Message+errNoPrecedence p m x = posMessage p $+  text "Inconsistent module interfaces"+  $+$ text "Module" <+> text (moduleName m)+  <+> text "does not define a precedence for" <+> text (escName x)++errNoInstance :: Position -> ModuleIdent -> InstIdent -> Message+errNoInstance p m i = posMessage p $+  text "Inconsistent module interfaces"+  $+$ text "Module" <+> text (moduleName m)+  <+> text "does not define an instance for" <+> ppInstIdent i++errImportConflict :: Position -> String -> ModuleIdent -> Ident -> Message+errImportConflict p what m x = posMessage p $+  text "Inconsistent module interfaces"+  $+$ text "Declaration of" <+> text what <+> text (escName x)+  <+> text "does not match its definition in module" <+> text (moduleName m)++errInstanceConflict :: Position -> ModuleIdent -> InstIdent -> Message+errInstanceConflict p m i = posMessage p $+  text "Inconsistent module interfaces"+  $+$ text "Declaration of instance" <+> ppInstIdent i+  <+> text "does not match its definition in module" <+> text (moduleName m)
+ src/Checks/InterfaceSyntaxCheck.hs view
@@ -0,0 +1,356 @@+{- |+    Module      :  $Header$+    Description :  Checks interface declarations+    Copyright   :  (c) 2000 - 2007 Wolfgang Lux+                       2011 - 2015 Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   Similar to Curry source files, some post-processing has to be applied+   to parsed interface files. In particular, the compiler must+   disambiguate nullary type constructors and type variables. In+   addition, the compiler also checks that all type constructor+   applications are saturated. Since interface files are closed -- i.e.,+   they include declarations of all entities which are defined in other+   modules -- the compiler can perform this check without reference to+   the global environments.+-}++module Checks.InterfaceSyntaxCheck (intfSyntaxCheck) where++import           Control.Monad            (liftM, liftM2, unless, when)+import qualified Control.Monad.State as S+import           Data.List                (nub, partition)+import           Data.Maybe               (isNothing)++import Base.Expr+import Base.Messages (Message, posMessage, internalError)+import Base.TopEnv+import Base.Utils    (findMultiples, findDouble)++import Env.TypeConstructor+import Env.Type++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty++data ISCState = ISCState+  { typeEnv :: TypeEnv+  , errors  :: [Message]+  }++type ISC = S.State ISCState++getTypeEnv :: ISC TypeEnv+getTypeEnv = S.gets typeEnv++-- |Report a syntax error+report :: Message -> ISC ()+report msg = S.modify $ \ s -> s { errors = msg : errors s }++intfSyntaxCheck :: Interface -> (Interface, [Message])+intfSyntaxCheck (Interface n is ds) = (Interface n is ds', reverse $ errors s')+  where (ds', s') = S.runState (mapM checkIDecl ds) (ISCState env [])+        env = foldr bindType (fmap toTypeKind initTCEnv) ds++-- The compiler requires information about the arity of each defined type+-- constructor as well as information whether the type constructor+-- denotes an algebraic data type, a renaming type, or a type synonym.+-- The latter must not occur in type expressions in interfaces.++bindType :: IDecl -> TypeEnv -> TypeEnv+bindType (IInfixDecl           _ _ _ _) = id+bindType (HidingDataDecl      _ tc _ _) = qualBindTopEnv tc (Data tc [])+bindType (IDataDecl      _ tc _ _ cs _) =+  qualBindTopEnv tc (Data tc (map constrId cs))+bindType (INewtypeDecl   _ tc _ _ nc _) =+  qualBindTopEnv tc (Data tc [nconstrId nc])+bindType (ITypeDecl         _ tc _ _ _) = qualBindTopEnv tc (Alias tc)+bindType (IFunctionDecl      _ _ _ _ _) = id+bindType (HidingClassDecl  _ _ cls _ _) = qualBindTopEnv cls (Class cls [])+bindType (IClassDecl _ _ cls _ _ ms hs) =+  qualBindTopEnv cls (Class cls (filter (`notElem` hs) (map imethod ms)))+bindType (IInstanceDecl    _ _ _ _ _ _) = id++-- The checks applied to the interface are similar to those performed+-- during syntax checking of type expressions.++checkIDecl :: IDecl -> ISC IDecl+checkIDecl (IInfixDecl  p fix pr op) = return (IInfixDecl p fix pr op)+checkIDecl (HidingDataDecl p tc k tvs) = do+  checkTypeLhs tvs+  return (HidingDataDecl p tc k tvs)+checkIDecl (IDataDecl p tc k tvs cs hs) = do+  checkTypeLhs tvs+  checkHiddenType tc (cons ++ labels) hs+  cs' <- mapM (checkConstrDecl tvs) cs+  return $ IDataDecl p tc k tvs cs' hs+  where cons   = map constrId cs+        labels = nub $ concatMap recordLabels cs+checkIDecl (INewtypeDecl p tc k tvs nc hs) = do+  checkTypeLhs tvs+  checkHiddenType tc (con : labels) hs+  nc' <- checkNewConstrDecl tvs nc+  return $ INewtypeDecl p tc k tvs nc' hs+  where con    = nconstrId nc+        labels = nrecordLabels nc+checkIDecl (ITypeDecl p tc k tvs ty) = do+  checkTypeLhs tvs+  liftM (ITypeDecl p tc k tvs) (checkClosedType tvs ty)+checkIDecl (IFunctionDecl p f cm n qty) =+  liftM (IFunctionDecl p f cm n) (checkQualType qty)+checkIDecl (HidingClassDecl p cx qcls k clsvar) = do+  checkTypeVars "hiding class declaration" [clsvar]+  cx' <- checkClosedContext [clsvar] cx+  checkSimpleContext cx'+  return $ HidingClassDecl p cx' qcls k clsvar+checkIDecl (IClassDecl p cx qcls k clsvar ms hs) = do+  checkTypeVars "class declaration" [clsvar]+  cx' <- checkClosedContext [clsvar] cx+  checkSimpleContext cx'+  ms' <- mapM (checkIMethodDecl clsvar) ms+  checkHidden (errNoElement "method" "class") qcls (map imethod ms') hs+  return $ IClassDecl p cx' qcls k clsvar ms' hs+checkIDecl (IInstanceDecl p cx qcls inst is m) = do+  checkClass qcls+  QualTypeExpr cx' inst' <- checkQualType $ QualTypeExpr cx inst+  checkSimpleContext cx'+  checkInstanceType p inst'+  mapM_ (report . errMultipleImplementation . head) $ findMultiples $ map fst is+  return $ IInstanceDecl p cx' qcls inst' is m++checkHiddenType :: QualIdent -> [Ident] -> [Ident] -> ISC ()+checkHiddenType = checkHidden $ errNoElement "constructor or label" "type"++checkHidden :: (QualIdent -> Ident -> Message) -> QualIdent -> [Ident]+            -> [Ident] -> ISC ()+checkHidden err tc csls hs =+  mapM_ (report . err tc) $ nub $ filter (`notElem` csls) hs++checkTypeLhs :: [Ident] -> ISC ()+checkTypeLhs = checkTypeVars "left hand side of type declaration"++checkExistVars :: [Ident] -> ISC ()+checkExistVars = checkTypeVars "list of existentially quantified type variables"++checkTypeVars :: String -> [Ident] -> ISC ()+checkTypeVars what tvs = do+  tyEnv <- getTypeEnv+  let (tcs, tvs') = partition isTypeConstrOrClass tvs+      isTypeConstrOrClass tv = not (null (lookupTypeKind tv tyEnv))+  mapM_ (report . flip errNoVariable what)       (nub tcs)+  mapM_ (report . flip errNonLinear what . head) (findMultiples tvs')++checkConstrDecl :: [Ident] -> ConstrDecl -> ISC ConstrDecl+checkConstrDecl tvs (ConstrDecl p evs cx c tys) = do+  checkExistVars evs+  cx' <- checkClosedContext tvs' cx+  liftM (ConstrDecl p evs cx' c) (mapM (checkClosedType tvs') tys)+  where tvs' = evs ++ tvs+checkConstrDecl tvs (ConOpDecl p evs cx ty1 op ty2) = do+  checkExistVars evs+  cx' <- checkClosedContext tvs' cx+  liftM2 (\t1 t2 -> ConOpDecl p evs cx' t1 op t2)+         (checkClosedType tvs' ty1)+         (checkClosedType tvs' ty2)+  where tvs' = evs ++ tvs+checkConstrDecl tvs (RecordDecl p evs cx c fs) = do+  checkExistVars evs+  cx' <- checkClosedContext tvs' cx+  liftM (RecordDecl p evs cx' c) (mapM (checkFieldDecl tvs') fs)+  where tvs' = evs ++ tvs++checkFieldDecl :: [Ident] -> FieldDecl -> ISC FieldDecl+checkFieldDecl tvs (FieldDecl p ls ty) =+  liftM (FieldDecl p ls) (checkClosedType tvs ty)++checkNewConstrDecl :: [Ident] -> NewConstrDecl -> ISC NewConstrDecl+checkNewConstrDecl tvs (NewConstrDecl p c ty) =+  liftM (NewConstrDecl p c) (checkClosedType tvs ty)+checkNewConstrDecl tvs (NewRecordDecl p c (l, ty)) = do+  ty' <- checkClosedType tvs ty+  return $ NewRecordDecl p c (l, ty')++checkSimpleContext :: Context -> ISC ()+checkSimpleContext = mapM_ checkSimpleConstraint++checkSimpleConstraint :: Constraint -> ISC ()+checkSimpleConstraint c@(Constraint _ ty) =+  unless (isVariableType ty) $ report $ errIllegalSimpleConstraint c++checkIMethodDecl :: Ident -> IMethodDecl -> ISC IMethodDecl+checkIMethodDecl tv (IMethodDecl p f a qty) = do+  qty' <- checkQualType qty+  unless (tv `elem` fv qty') $ report $ errAmbiguousType p tv+  let QualTypeExpr cx _ = qty'+  when (tv `elem` fv cx) $ report $ errConstrainedClassVariable p tv+  return $ IMethodDecl p f a qty'++checkInstanceType :: Position -> InstanceType -> ISC ()+checkInstanceType p inst = do+  tEnv <- getTypeEnv+  unless (isSimpleType inst &&+    not (isTypeSyn (typeConstr inst) tEnv) &&+    null (filter isAnonId $ typeVars inst) &&+    isNothing (findDouble $ fv inst)) $+      report $ errIllegalInstanceType p inst++checkQualType :: QualTypeExpr -> ISC QualTypeExpr+checkQualType (QualTypeExpr cx ty) = do+  ty' <- checkType ty+  cx' <- checkClosedContext (fv ty') cx+  return $ QualTypeExpr cx' ty'++checkClosedContext :: [Ident] -> Context -> ISC Context+checkClosedContext tvs cx = do+  cx' <- checkContext cx+  mapM_ (\(Constraint _ ty) -> checkClosed tvs ty) cx'+  return cx'++checkContext :: Context -> ISC Context+checkContext = mapM checkConstraint++checkConstraint :: Constraint -> ISC Constraint+checkConstraint (Constraint qcls ty) = do+  checkClass qcls+  Constraint qcls `liftM` checkType ty++checkClass :: QualIdent -> ISC ()+checkClass qcls = do+  tEnv <- getTypeEnv+  case qualLookupTypeKind qcls tEnv of+    [] -> report $ errUndefinedClass qcls+    [Class _ _] -> return ()+    [_] -> report $ errUndefinedClass qcls+    _ -> internalError $ "Checks.InterfaceSyntaxCheck.checkClass: " +++           "ambiguous identifier " ++ show qcls++checkClosedType :: [Ident] -> TypeExpr -> ISC TypeExpr+checkClosedType tvs ty = do+  ty' <- checkType ty+  checkClosed tvs ty'+  return ty'++checkType :: TypeExpr -> ISC TypeExpr+checkType (ConstructorType tc) = checkTypeConstructor tc+checkType (ApplyType  ty1 ty2) = liftM2 ApplyType (checkType ty1) (checkType ty2)+checkType (VariableType    tv) = checkType $ ConstructorType (qualify tv)+checkType (TupleType      tys) = liftM TupleType (mapM checkType tys)+checkType (ListType        ty) = liftM ListType (checkType ty)+checkType (ArrowType  ty1 ty2) = liftM2 ArrowType (checkType ty1) (checkType ty2)+checkType (ParenType       ty) = liftM ParenType (checkType ty)+checkType (ForallType   vs ty) = liftM (ForallType vs) (checkType ty)++checkClosed :: [Ident] -> TypeExpr -> ISC ()+checkClosed _   (ConstructorType _) = return ()+checkClosed tvs (ApplyType ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (VariableType   tv) =+  when (isAnonId tv || tv `notElem` tvs) $ report $ errUnboundVariable tv+checkClosed tvs (TupleType     tys) = mapM_ (checkClosed tvs) tys+checkClosed tvs (ListType       ty) = checkClosed tvs ty+checkClosed tvs (ArrowType ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (ParenType      ty) = checkClosed tvs ty+checkClosed tvs (ForallType  vs ty) = checkClosed (tvs ++ vs) ty++checkTypeConstructor :: QualIdent -> ISC TypeExpr+checkTypeConstructor tc = do+  tyEnv <- getTypeEnv+  case qualLookupTypeKind tc tyEnv of+    [] | not (isQualified tc) -> return $ VariableType $ unqualify tc+       | otherwise            -> do+          report $ errUndefinedType tc+          return $ ConstructorType tc+    [Data _ _] -> return $ ConstructorType tc+    [Alias  _] -> do+                  report $ errBadTypeSynonym tc+                  return $ ConstructorType tc+    _          ->+      internalError "Checks.InterfaceSyntaxCheck.checkTypeConstructor"++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++typeVars :: TypeExpr -> [Ident]+typeVars (ConstructorType       _) = []+typeVars (ApplyType       ty1 ty2) = typeVars ty1 ++ typeVars ty2+typeVars (VariableType         tv) = [tv]+typeVars (TupleType           tys) = concatMap typeVars tys+typeVars (ListType             ty) = typeVars ty+typeVars (ArrowType       ty1 ty2) = typeVars ty1 ++ typeVars ty2+typeVars (ParenType            ty) = typeVars ty+typeVars (ForallType        vs ty) = vs ++ typeVars ty++isTypeSyn :: QualIdent -> TypeEnv -> Bool+isTypeSyn tc tEnv = case qualLookupTypeKind tc tEnv of+  [Alias _] -> True+  _ -> False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUndefined :: String -> QualIdent -> Message+errUndefined what qident = posMessage qident $ hsep $ map text+  ["Undefined", what, qualName qident]++errUndefinedClass :: QualIdent -> Message+errUndefinedClass = errUndefined "class"++errUndefinedType :: QualIdent -> Message+errUndefinedType = errUndefined "type"++errMultipleImplementation :: Ident -> Message+errMultipleImplementation f = posMessage f $ hsep $ map text+  ["Arity information for method", idName f, "occurs more than once"]++errAmbiguousType :: Position -> Ident -> Message+errAmbiguousType p ident = posMessage p $ hsep $ map text+  [ "Method type does not mention class variable", idName ident ]++errConstrainedClassVariable :: Position -> Ident -> Message+errConstrainedClassVariable p ident = posMessage p $ hsep $ map text+  [ "Method context must not constrain class variable", idName ident ]++errNonLinear :: Ident -> String -> Message+errNonLinear tv what = posMessage tv $ hsep $ map text+  [ "Type variable", escName tv, "occurs more than once in", what ]++errNoVariable :: Ident -> String -> Message+errNoVariable tv what = posMessage tv $ hsep $ map text+  [ "Type constructor or type class identifier", escName tv, "used in", what ]++errUnboundVariable :: Ident -> Message+errUnboundVariable tv = posMessage tv $+  text "Undefined type variable" <+> text (escName tv)++errBadTypeSynonym :: QualIdent -> Message+errBadTypeSynonym tc = posMessage tc $ text "Synonym type"+                    <+> text (qualName tc) <+> text "in interface"++errNoElement :: String -> String -> QualIdent -> Ident -> Message+errNoElement what for tc x = posMessage tc $ hsep $ map text+  [ "Hidden", what, escName x, "is not defined for", for, qualName tc ]++errIllegalSimpleConstraint :: Constraint -> Message+errIllegalSimpleConstraint c@(Constraint qcls _) = posMessage qcls $ vcat+  [ text "Illegal class constraint" <+> ppConstraint c+  , text "Constraints in class and instance declarations must be of"+  , text "the form C u, where C is a type class and u is a type variable."+  ]++errIllegalInstanceType :: Position -> InstanceType -> Message+errIllegalInstanceType p inst = posMessage p $ vcat+  [ text "Illegal instance type" <+> ppInstanceType inst+  , text "The instance type must be of the form (T u_1 ... u_n),"+  , text "where T is not a type synonym and u_1, ..., u_n are"+  , text "mutually distinct, non-anonymous type variables."+  ]
+ src/Checks/KindCheck.hs view
@@ -0,0 +1,765 @@+{- |+    Module      :  $Header$+    Description :  Checks type kinds+    Copyright   :  (c) 2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   After the type syntax has been checked und nullary type constructors and+   type variables have been disambiguated, the compiler infers kinds for all+   type constructors and type classes defined in the current module and+   performs kind checking on all type definitions and type signatures.+-}+{-# LANGUAGE CPP #-}+module Checks.KindCheck (kindCheck) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative      ((<$>), (<*>))+#endif+import           Control.Monad            (when, foldM)+import           Control.Monad.Fix        (mfix)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import           Data.List                (partition, nub)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty++import Base.CurryKinds+import Base.Expr+import Base.Kinds+import Base.KindSubst+import Base.Messages (Message, posMessage, internalError)+import Base.SCC+import Base.TopEnv+import Base.Types+import Base.TypeExpansion++import Env.Class+import Env.TypeConstructor++-- In order to infer kinds for type constructors and type classes, the+-- compiler sorts the module's type and class declarations into minimal+-- recursive binding groups and then applies kind inference to each+-- declaration group. Besides inferring kinds for the type constructors+-- and type classes of a group, the compiler also checks that there are+-- no mutually recursive type synonym definitions and that the super class+-- hierarchy is acyclic. The former allows entering fully expanded type+-- synonyms into the type constructor environment.++kindCheck :: TCEnv -> ClassEnv -> Module a -> ((TCEnv, ClassEnv), [Message])+kindCheck tcEnv clsEnv (Module _ m _ _ ds) = runKCM check initState+  where+    check = do+      checkNonRecursiveTypes tds &&> checkAcyclicSuperClasses cds+      errs <- S.gets errors+      if null errs+         then checkDecls+         else return (tcEnv, clsEnv)+    checkDecls = do+      (tcEnv', clsEnv') <- kcDecls tcEnv clsEnv tcds+      mapM_ (kcDecl tcEnv') ods+      return (tcEnv', clsEnv')+    tds = filter isTypeDecl tcds+    cds = filter isClassDecl tcds+    (tcds, ods) = partition isTypeOrClassDecl ds+    initState  = KCState m idSubst 0 []++-- Kind Check Monad+type KCM = S.State KCState++-- |Internal state of the Kind Check+data KCState = KCState+  { moduleIdent :: ModuleIdent -- read only+  , kindSubst   :: KindSubst+  , nextId      :: Int         -- automatic counter+  , errors      :: [Message]+  }++(&&>) :: KCM () -> KCM () -> KCM ()+pre &&> suf = do+  errs <- pre >> S.gets errors+  if null errs then suf else return ()++runKCM :: KCM a -> KCState -> (a, [Message])+runKCM kcm s = let (a, s') = S.runState kcm s in (a, reverse $ errors s')++getModuleIdent :: KCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getKindSubst :: KCM KindSubst+getKindSubst = S.gets kindSubst++modifyKindSubst :: (KindSubst -> KindSubst) -> KCM ()+modifyKindSubst f = S.modify $ \s -> s { kindSubst = f $ kindSubst s }++getNextId :: KCM Int+getNextId = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return nid++report :: Message -> KCM ()+report err = S.modify (\s -> s { errors = err : errors s })++ok :: KCM ()+ok = return ()++-- Minimal recursive declaration groups are computed using the sets of bound+-- and free type constructor and type class identifiers of the declarations.++bt :: Decl a -> [Ident]+bt (DataDecl     _ tc _ _ _) = [tc]+bt (ExternalDataDecl _ tc _) = [tc]+bt (NewtypeDecl  _ tc _ _ _) = [tc]+bt (TypeDecl       _ tc _ _) = [tc]+bt (ClassDecl   _ _ cls _ _) = [cls]+bt _                         = []++ft :: ModuleIdent -> Decl a -> [Ident]+ft m d = fts m d []++class HasType a where+  fts :: ModuleIdent -> a -> [Ident] -> [Ident]++instance HasType a => HasType [a] where+  fts m = flip $ foldr $ fts m++instance HasType a => HasType (Maybe a) where+  fts m = maybe id $ fts m++instance HasType (Decl a) where+  fts _ (InfixDecl             _ _ _ _) = id+  fts m (DataDecl        _ _ _ cs clss) = fts m cs . fts m clss+  fts _ (ExternalDataDecl        _ _ _) = id+  fts m (NewtypeDecl     _ _ _ nc clss) = fts m nc . fts m clss+  fts m (TypeDecl             _ _ _ ty) = fts m ty+  fts m (TypeSig                _ _ ty) = fts m ty+  fts m (FunctionDecl        _ _ _ eqs) = fts m eqs+  fts _ (ExternalDecl              _ _) = id+  fts m (PatternDecl           _ _ rhs) = fts m rhs+  fts _ (FreeDecl                  _ _) = id+  fts m (DefaultDecl             _ tys) = fts m tys+  fts m (ClassDecl         _ cx _ _ ds) = fts m cx . fts m ds+  fts m (InstanceDecl _ cx cls inst ds) =+    fts m cx . fts m cls . fts m inst . fts m ds++instance HasType ConstrDecl where+  fts m (ConstrDecl     _ _ cx _ tys) = fts m cx . fts m tys+  fts m (ConOpDecl  _ _ cx ty1 _ ty2) = fts m cx . fts m ty1 . fts m ty2+  fts m (RecordDecl      _ _ cx _ fs) = fts m cx . fts m fs++instance HasType FieldDecl where+  fts m (FieldDecl _ _ ty) = fts m ty++instance HasType NewConstrDecl where+  fts m (NewConstrDecl      _ _ ty) = fts m ty+  fts m (NewRecordDecl _ _ (_, ty)) = fts m ty++instance HasType Constraint where+  fts m (Constraint qcls _) = fts m qcls++instance HasType QualTypeExpr where+  fts m (QualTypeExpr cx ty) = fts m cx . fts m ty++instance HasType TypeExpr where+  fts m (ConstructorType      tc) = fts m tc+  fts m (ApplyType       ty1 ty2) = fts m ty1 . fts m ty2+  fts _ (VariableType          _) = id+  fts m (TupleType           tys) = (tupleId (length tys) :) . fts m tys+  fts m (ListType             ty) = (listId :) . fts m ty+  fts m (ArrowType       ty1 ty2) = (arrowId :) . fts m ty1 . fts m ty2+  fts m (ParenType            ty) = fts m ty+  fts m (ForallType         _ ty) = fts m ty++instance HasType (Equation a) where+  fts m (Equation _ _ rhs) = fts m rhs++instance HasType (Rhs a) where+  fts m (SimpleRhs  _ e ds) = fts m e . fts m ds+  fts m (GuardedRhs  es ds) = fts m es . fts m ds++instance HasType (CondExpr a) where+  fts m (CondExpr _ g e) = fts m g . fts m e++instance HasType (Expression a) where+  fts _ (Literal             _ _) = id+  fts _ (Variable            _ _) = id+  fts _ (Constructor         _ _) = id+  fts m (Paren                 e) = fts m e+  fts m (Typed              e ty) = fts m e . fts m ty+  fts m (Record           _ _ fs) = fts m fs+  fts m (RecordUpdate       e fs) = fts m e . fts m fs+  fts m (Tuple                es) = fts m es+  fts m (List               _ es) = fts m es+  fts m (ListCompr        e stms) = fts m e . fts m stms+  fts m (EnumFrom              e) = fts m e+  fts m (EnumFromThen      e1 e2) = fts m e1 . fts m e2+  fts m (EnumFromTo        e1 e2) = fts m e1 . fts m e2+  fts m (EnumFromThenTo e1 e2 e3) = fts m e1 . fts m e2 . fts m e3+  fts m (UnaryMinus            e) = fts m e+  fts m (Apply             e1 e2) = fts m e1 . fts m e2+  fts m (InfixApply      e1 _ e2) = fts m e1 . fts m e2+  fts m (LeftSection         e _) = fts m e+  fts m (RightSection        _ e) = fts m e+  fts m (Lambda              _ e) = fts m e+  fts m (Let                ds e) = fts m ds . fts m e+  fts m (Do               stms e) = fts m stms . fts m e+  fts m (IfThenElse     e1 e2 e3) = fts m e1 . fts m e2 . fts m e3+  fts m (Case             _ e as) = fts m e . fts m as++instance HasType (Statement a) where+  fts m (StmtExpr   e) = fts m e+  fts m (StmtDecl  ds) = fts m ds+  fts m (StmtBind _ e) = fts m e++instance HasType (Alt a) where+  fts m (Alt _ _ rhs) = fts m rhs++instance HasType a => HasType (Field a) where+  fts m (Field _ _ x) = fts m x++instance HasType QualIdent where+  fts m qident = maybe id (:) (localIdent m qident)++-- When types are entered into the type constructor environment, all type+-- synonyms occuring in the definitions are fully expanded (except for+-- record types) and all type constructors and type classes are qualified+-- with the name of the module in which they are defined. This is possible+-- because Curry does not allow (mutually) recursive type synonyms or+-- newtypes, which is checked in the function 'checkNonRecursiveTypes' below.++ft' :: ModuleIdent -> Decl a -> [Ident]+ft' _ (DataDecl     _ _ _ _ _) = []+ft' _ (ExternalDataDecl _ _ _) = []+ft' m (NewtypeDecl _ _ _ nc _) = fts m nc []+ft' m (TypeDecl      _ _ _ ty) = fts m ty []+ft' _ _                        = []++checkNonRecursiveTypes :: [Decl a] -> KCM ()+checkNonRecursiveTypes ds = do+  m <- getModuleIdent+  mapM_ checkTypeAndNewtypeDecls $ scc bt (ft' m) ds++checkTypeAndNewtypeDecls :: [Decl a] -> KCM ()+checkTypeAndNewtypeDecls [] =+  internalError "Checks.KindCheck.checkTypeAndNewtypeDecls: empty list"+checkTypeAndNewtypeDecls [DataDecl _ _ _ _ _] = ok+checkTypeAndNewtypeDecls [ExternalDataDecl _ _ _] = ok+checkTypeAndNewtypeDecls [d] | isTypeOrNewtypeDecl d = do+  m <- getModuleIdent+  let tc = typeConstructor d+  when (tc `elem` ft m d) $ report $ errRecursiveTypes [tc]+checkTypeAndNewtypeDecls (d:ds) | isTypeOrNewtypeDecl d =+  report $ errRecursiveTypes $+    typeConstructor d : [typeConstructor d' | d' <- ds, isTypeOrNewtypeDecl d']+checkTypeAndNewtypeDecls _ = internalError+  "Checks.KindCheck.checkTypeAndNewtypeDecls: no type or newtype declarations"++-- The function 'checkAcyclicSuperClasses' checks that the super class+-- hierarchy is acyclic.++fc :: ModuleIdent -> Context -> [Ident]+fc m = foldr fc' []+  where+    fc' (Constraint qcls _) = maybe id (:) (localIdent m qcls)++checkAcyclicSuperClasses :: [Decl a] -> KCM ()+checkAcyclicSuperClasses ds = do+  m <- getModuleIdent+  mapM_ checkClassDecl $ scc bt (\(ClassDecl _ cx _ _ _) -> fc m cx) ds++checkClassDecl :: [Decl a] -> KCM ()+checkClassDecl [] =+  internalError "Checks.KindCheck.checkClassDecl: empty list"+checkClassDecl [ClassDecl _ cx cls _ _] = do+  m <- getModuleIdent+  when (cls `elem` fc m cx) $ report $ errRecursiveClasses [cls]+checkClassDecl (ClassDecl _ _ cls _ _ : ds) =+  report $ errRecursiveClasses $ cls : [cls' | ClassDecl _ _ cls' _ _ <- ds]+checkClassDecl _ =+  internalError "Checks.KindCheck.checkClassDecl: no class declaration"++-- For each declaration group, the kind checker first enters new+-- assumptions into the type constructor environment. For a type+-- constructor with arity n, we enter kind k_1 -> ... -> k_n -> k,+-- where k_i are fresh kind variables and k is * for data and newtype+-- type constructors and a fresh kind variable for type synonym type+-- constructors. For a type class we enter kind k, where k is a fresh+-- kind variable. We also add a type class to the class environment.+-- Next, the kind checker checks the declarations of the group within+-- the extended environment, and finally the kind checker instantiates+-- all remaining free kind variables to *.++-- As noted above, type synonyms are fully expanded while types are+-- entered into the type constructor environment. Furthermore, we uses+-- original names for classes and super classes in the class environment.+-- Unfortunately, both of this requires either sorting type declarations+-- properly or using the final type constructor environment for the expansion+-- and original names. We have chosen the latter option here, which requires+-- recursive monadic bindings which are supported using the 'mfix' method+-- from the 'MonadFix' type class.++bindKind :: ModuleIdent -> TCEnv -> ClassEnv -> TCEnv -> Decl a -> KCM TCEnv+bindKind m tcEnv' clsEnv tcEnv (DataDecl _ tc tvs cs _) = do+  bindTypeConstructor DataType tc tvs (Just KindStar) (map mkData cs) tcEnv+  where+    mkData (ConstrDecl _ evs cx     c  tys) = mkData' evs cx c  tys+    mkData (ConOpDecl  _ evs cx ty1 op ty2) = mkData' evs cx op [ty1, ty2]+    mkData (RecordDecl _ evs cx     c   fs) =+      let (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]+      in  mkRec evs cx c labels tys+    mkData' evs cx c tys = DataConstr c (length evs) ps tys'+      where qtc = qualifyWith m tc+            tvs' = tvs ++ evs+            PredType ps ty = expandConstrType m tcEnv' clsEnv qtc tvs' cx tys+            tys' = arrowArgs ty+    mkRec evs cx c ls tys =+      RecordConstr c (length evs) ps ls tys'+      where qtc = qualifyWith m tc+            tvs' = tvs ++ evs+            PredType ps ty = expandConstrType m tcEnv' clsEnv qtc tvs' cx tys+            tys' = arrowArgs ty+bindKind _ _     _       tcEnv (ExternalDataDecl _ tc tvs) = do+  bindTypeConstructor DataType tc tvs (Just KindStar) [] tcEnv+bindKind m tcEnv' _      tcEnv (NewtypeDecl _ tc tvs nc _) =+  bindTypeConstructor RenamingType tc tvs (Just KindStar) (mkData nc) tcEnv+  where+    mkData (NewConstrDecl _ c      ty) = DataConstr c 0 emptyPredSet [ty']+      where ty'  = expandMonoType m tcEnv' tvs ty+    mkData (NewRecordDecl _ c (l, ty)) = RecordConstr c 0 emptyPredSet [l] [ty']+      where ty'  = expandMonoType m tcEnv' tvs ty+bindKind m tcEnv' _      tcEnv (TypeDecl _ tc tvs ty) =+  bindTypeConstructor aliasType tc tvs Nothing ty' tcEnv+  where+    aliasType tc' k = AliasType tc' k $ length tvs+    ty' = expandMonoType m tcEnv' tvs ty+bindKind m tcEnv' clsEnv tcEnv (ClassDecl _ _ cls tv ds) =+  bindTypeClass cls (concatMap mkMethods ds) tcEnv+  where+    mkMethods (TypeSig _ fs qty) = map (mkMethod qty) fs+    mkMethods _                  = []+    mkMethod qty f = ClassMethod f (findArity f ds) $+                       expandMethodType m tcEnv' clsEnv (qualify cls) tv qty+    findArity _ []                                    = Nothing+    findArity f (FunctionDecl _ _ f' eqs:_) | f == f' =+      Just $ eqnArity $ head eqs+    findArity f (_:ds')                               = findArity f ds'+bindKind _ _      _      tcEnv _                          = return tcEnv++bindTypeConstructor :: (QualIdent -> Kind -> a -> TypeInfo) -> Ident+                    -> [Ident] -> Maybe Kind -> a -> TCEnv -> KCM TCEnv+bindTypeConstructor f tc tvs k x tcEnv = do+  m <- getModuleIdent+  k' <- maybe freshKindVar return k+  ks <- mapM (const freshKindVar) tvs+  let qtc = qualifyWith m tc+      ti = f qtc (foldr KindArrow k' ks) x+  return $ bindTypeInfo m tc ti tcEnv++bindTypeClass :: Ident -> [ClassMethod] -> TCEnv -> KCM TCEnv+bindTypeClass cls ms tcEnv = do+  m <- getModuleIdent+  k <- freshKindVar+  let qcls = qualifyWith m cls+      ti = TypeClass qcls k ms+  return $ bindTypeInfo m cls ti tcEnv++bindFreshKind :: TCEnv -> Ident -> KCM TCEnv+bindFreshKind tcEnv tv = do+  k <- freshKindVar+  return $ bindTypeVar tv k tcEnv++bindTypeVars :: Ident -> [Ident] -> TCEnv -> KCM (Kind, TCEnv)+bindTypeVars tc tvs tcEnv = do+  m <- getModuleIdent+  return $ foldl (\(KindArrow k1 k2, tcEnv') tv ->+                   (k2, bindTypeVar tv k1 tcEnv'))+                 (tcKind m (qualifyWith m tc) tcEnv, tcEnv)+                 tvs++bindTypeVar :: Ident -> Kind -> TCEnv -> TCEnv+bindTypeVar ident k = bindTopEnv ident (TypeVar k)++bindClass :: ModuleIdent -> TCEnv -> ClassEnv -> Decl a -> ClassEnv+bindClass m tcEnv clsEnv (ClassDecl _  cx cls _ ds) =+  bindClassInfo qcls (sclss, ms) clsEnv+  where qcls = qualifyWith m cls+        ms = map (\f -> (f, f `elem` fs)) $ concatMap methods ds+        fs = concatMap impls ds+        sclss = nub $ map (\(Constraint cls' _) -> getOrigName m cls' tcEnv) cx+bindClass _ _ clsEnv _ = clsEnv++instantiateWithDefaultKind :: TypeInfo -> TypeInfo+instantiateWithDefaultKind (DataType tc k cs) =+  DataType tc (defaultKind k) cs+instantiateWithDefaultKind (RenamingType tc k nc) =+  RenamingType tc (defaultKind k) nc+instantiateWithDefaultKind (AliasType tc k n ty) =+  AliasType tc (defaultKind k) n ty+instantiateWithDefaultKind (TypeClass cls k ms) =+  TypeClass cls (defaultKind k) ms+instantiateWithDefaultKind (TypeVar _) =+  internalError "Checks.KindCheck.instantiateWithDefaultKind: type variable"++kcDecls :: TCEnv -> ClassEnv -> [Decl a] -> KCM (TCEnv, ClassEnv)+kcDecls tcEnv clsEnv ds = do+  m <- getModuleIdent+  foldM (uncurry kcDeclGroup) (tcEnv, clsEnv) $ scc bt (ft m) ds++kcDeclGroup :: TCEnv -> ClassEnv -> [Decl a] -> KCM (TCEnv, ClassEnv)+kcDeclGroup tcEnv clsEnv ds = do+  m <- getModuleIdent+  (tcEnv', clsEnv') <- mfix (\ ~(tcEnv', clsEnv') ->+    flip (,) (foldl (bindClass m tcEnv') clsEnv ds) <$>+      foldM (bindKind m tcEnv' clsEnv') tcEnv ds)+  mapM_ (kcDecl tcEnv') ds+  theta <- getKindSubst+  return (fmap (instantiateWithDefaultKind . subst theta) tcEnv', clsEnv')++-- After adding new assumptions to the environment, kind inference is+-- applied to all declarations. The type environment may be extended+-- temporarily with bindings for type variables occurring in the left+-- hand side of type declarations and free type variables of type+-- signatures. While the kinds of the former are determined already by+-- the kinds of their type constructors and type classes, respectively,+-- fresh kind variables are added for the latter.++kcDecl :: TCEnv -> Decl a -> KCM ()+kcDecl _     (InfixDecl _ _ _ _) = ok+kcDecl tcEnv (DataDecl _ tc tvs cs _) = do+  (_, tcEnv') <- bindTypeVars tc tvs tcEnv+  mapM_ (kcConstrDecl tcEnv') cs+kcDecl _     (ExternalDataDecl _ _ _) = ok+kcDecl tcEnv (NewtypeDecl _ tc tvs nc _) = do+  (_, tcEnv') <- bindTypeVars tc tvs tcEnv+  kcNewConstrDecl tcEnv' nc+kcDecl tcEnv t@(TypeDecl p tc tvs ty) = do+  (k, tcEnv') <- bindTypeVars tc tvs tcEnv+  kcType tcEnv' p "type declaration" (ppDecl t) k ty+kcDecl tcEnv (TypeSig p _ qty) = kcTypeSig tcEnv p qty+kcDecl tcEnv (FunctionDecl _ _ _ eqs) = mapM_ (kcEquation tcEnv) eqs+kcDecl _     (ExternalDecl _ _) = ok+kcDecl tcEnv (PatternDecl _ _ rhs) = kcRhs tcEnv rhs+kcDecl _     (FreeDecl _ _) = ok+kcDecl tcEnv (DefaultDecl p tys) = do+  tcEnv' <- foldM bindFreshKind tcEnv $ nub $ fv tys+  mapM_ (kcValueType tcEnv' p "default declaration" empty) tys+kcDecl tcEnv (ClassDecl p cx cls tv ds) = do+  m <- getModuleIdent+  let tcEnv' = bindTypeVar tv (clsKind m (qualifyWith m cls) tcEnv) tcEnv+  kcContext tcEnv' p cx+  mapM_ (kcDecl tcEnv') ds+kcDecl tcEnv (InstanceDecl p cx qcls inst ds) = do+  m <- getModuleIdent+  tcEnv' <- foldM bindFreshKind tcEnv $ fv inst+  kcContext tcEnv' p cx+  kcType tcEnv' p what doc (clsKind m qcls tcEnv) inst+  mapM_ (kcDecl tcEnv') ds+    where+      what = "instance declaration"+      doc = ppDecl (InstanceDecl p cx qcls inst [])++kcConstrDecl :: TCEnv -> ConstrDecl -> KCM ()+kcConstrDecl tcEnv d@(ConstrDecl p evs cx _ tys) = do+  tcEnv' <- foldM bindFreshKind tcEnv evs+  kcContext tcEnv' p cx+  mapM_ (kcValueType tcEnv' p what doc) tys+    where+      what = "data constructor declaration"+      doc = ppConstr d+kcConstrDecl tcEnv d@(ConOpDecl p evs cx ty1 _ ty2) = do+  tcEnv' <- foldM bindFreshKind tcEnv evs+  kcContext tcEnv' p cx+  kcValueType tcEnv' p what doc ty1+  kcValueType tcEnv' p what doc ty2+    where+      what = "data constructor declaration"+      doc = ppConstr d+kcConstrDecl tcEnv (RecordDecl p evs cx _ fs) = do+  tcEnv' <- foldM bindFreshKind tcEnv evs+  kcContext tcEnv' p cx+  mapM_ (kcFieldDecl tcEnv') fs++kcFieldDecl :: TCEnv -> FieldDecl -> KCM ()+kcFieldDecl tcEnv d@(FieldDecl p _ ty) =+  kcValueType tcEnv p "field declaration" (ppFieldDecl d) ty++kcNewConstrDecl :: TCEnv -> NewConstrDecl -> KCM ()+kcNewConstrDecl tcEnv d@(NewConstrDecl p _ ty) =+  kcValueType tcEnv p "newtype constructor declaration" (ppNewConstr d) ty+kcNewConstrDecl tcEnv (NewRecordDecl p _ (l, ty)) =+  kcFieldDecl tcEnv (FieldDecl p [l] ty)++kcEquation :: TCEnv -> Equation a -> KCM ()+kcEquation tcEnv (Equation _ _ rhs) = kcRhs tcEnv rhs++kcRhs :: TCEnv -> Rhs a -> KCM ()+kcRhs tcEnv (SimpleRhs p e ds) = do+  kcExpr tcEnv p e+  mapM_ (kcDecl tcEnv) ds+kcRhs tcEnv (GuardedRhs es ds) = do+  mapM_ (kcCondExpr tcEnv) es+  mapM_ (kcDecl tcEnv) ds++kcCondExpr :: TCEnv -> CondExpr a -> KCM ()+kcCondExpr tcEnv (CondExpr p g e) = kcExpr tcEnv p g >> kcExpr tcEnv p e++kcExpr :: TCEnv -> Position -> Expression a -> KCM ()+kcExpr _     _ (Literal _ _) = ok+kcExpr _     _ (Variable _ _) = ok+kcExpr _     _ (Constructor _ _) = ok+kcExpr tcEnv p (Paren e) = kcExpr tcEnv p e+kcExpr tcEnv p (Typed e qty) = do+  kcExpr tcEnv p e+  kcTypeSig tcEnv p qty+kcExpr tcEnv p (Record _ _ fs) = mapM_ (kcField tcEnv p) fs+kcExpr tcEnv p (RecordUpdate e fs) = do+  kcExpr tcEnv p e+  mapM_ (kcField tcEnv p) fs+kcExpr tcEnv p (Tuple es) = mapM_ (kcExpr tcEnv p) es+kcExpr tcEnv p (List _ es) = mapM_ (kcExpr tcEnv p) es+kcExpr tcEnv p (ListCompr e stms) = do+  kcExpr tcEnv p e+  mapM_ (kcStmt tcEnv p) stms+kcExpr tcEnv p (EnumFrom e) = kcExpr tcEnv p e+kcExpr tcEnv p (EnumFromThen e1 e2) = do+  kcExpr tcEnv p e1+  kcExpr tcEnv p e2+kcExpr tcEnv p (EnumFromTo e1 e2) = do+  kcExpr tcEnv p e1+  kcExpr tcEnv p e2+kcExpr tcEnv p (EnumFromThenTo e1 e2 e3) = do+  kcExpr tcEnv p e1+  kcExpr tcEnv p e2+  kcExpr tcEnv p e3+kcExpr tcEnv p (UnaryMinus e) = kcExpr tcEnv p e+kcExpr tcEnv p (Apply e1 e2) = do+  kcExpr tcEnv p e1+  kcExpr tcEnv p e2+kcExpr tcEnv p (InfixApply e1 _ e2) = do+  kcExpr tcEnv p e1+  kcExpr tcEnv p e2+kcExpr tcEnv p (LeftSection e _) = kcExpr tcEnv p e+kcExpr tcEnv p (RightSection _ e) = kcExpr tcEnv p e+kcExpr tcEnv p (Lambda _ e) = kcExpr tcEnv p e+kcExpr tcEnv p (Let ds e) = do+  mapM_ (kcDecl tcEnv) ds+  kcExpr tcEnv p e+kcExpr tcEnv p (Do stms e) = do+  mapM_ (kcStmt tcEnv p) stms+  kcExpr tcEnv p e+kcExpr tcEnv p (IfThenElse e1 e2 e3) = do+  kcExpr tcEnv p e1+  kcExpr tcEnv p e2+  kcExpr tcEnv p e3+kcExpr tcEnv p (Case _ e alts) = do+  kcExpr tcEnv p e+  mapM_ (kcAlt tcEnv) alts++kcStmt :: TCEnv -> Position -> Statement a -> KCM ()+kcStmt tcEnv p (StmtExpr e) = kcExpr tcEnv p e+kcStmt tcEnv _ (StmtDecl ds) = mapM_ (kcDecl tcEnv) ds+kcStmt tcEnv p (StmtBind _ e) = kcExpr tcEnv p e++kcAlt :: TCEnv -> Alt a -> KCM ()+kcAlt tcEnv (Alt _ _ rhs) = kcRhs tcEnv rhs++kcField :: TCEnv -> Position -> Field (Expression a) -> KCM ()+kcField tcEnv p (Field _ _ e) = kcExpr tcEnv p e++kcContext :: TCEnv -> Position -> Context -> KCM ()+kcContext tcEnv p = mapM_ (kcConstraint tcEnv p)++kcConstraint :: TCEnv -> Position -> Constraint -> KCM ()+kcConstraint tcEnv p sc@(Constraint qcls ty) = do+  m <- getModuleIdent+  kcType tcEnv p "class constraint" doc (clsKind m qcls tcEnv) ty+  where+    doc = ppConstraint sc++kcTypeSig :: TCEnv -> Position -> QualTypeExpr -> KCM ()+kcTypeSig tcEnv p (QualTypeExpr cx ty) = do+  tcEnv' <- foldM bindFreshKind tcEnv free+  kcContext tcEnv' p cx+  kcValueType tcEnv' p "type signature" doc ty+  where+    free = filter (null . flip lookupTypeInfo tcEnv) $ nub $ fv ty+    doc = ppTypeExpr 0 ty++kcValueType :: TCEnv -> Position -> String -> Doc -> TypeExpr -> KCM ()+kcValueType tcEnv p what doc = kcType tcEnv p what doc KindStar++kcType :: TCEnv -> Position -> String -> Doc -> Kind -> TypeExpr -> KCM ()+kcType tcEnv p what doc k ty = do+  k' <- kcTypeExpr tcEnv p "type expression" doc' 0 ty+  unify p what (doc $-$ text "Type:" <+> doc') k k'+  where+    doc' = ppTypeExpr 0 ty++kcTypeExpr :: TCEnv -> Position -> String -> Doc -> Int -> TypeExpr -> KCM Kind+kcTypeExpr tcEnv p _ _ n (ConstructorType tc) = do+  m <- getModuleIdent+  case qualLookupTypeInfo tc tcEnv of+    [AliasType _ _ n' _] -> case n >= n' of+      True -> return $ tcKind m tc tcEnv+      False -> do+        report $ errPartialAlias p tc n' n+        freshKindVar+    _ -> return $ tcKind m tc tcEnv+kcTypeExpr tcEnv p what doc n (ApplyType ty1 ty2) = do+  (alpha, beta) <- kcTypeExpr tcEnv p what doc (n + 1) ty1 >>=+    kcArrow p what (doc $-$ text "Type:" <+> ppTypeExpr 0 ty1)+  kcTypeExpr tcEnv p what doc 0 ty2 >>=+    unify p what (doc $-$ text "Type:" <+> ppTypeExpr 0 ty2) alpha+  return beta+kcTypeExpr tcEnv _ _ _ _ (VariableType tv) = return (varKind tv tcEnv)+kcTypeExpr tcEnv p what doc _ (TupleType tys) = do+  mapM_ (kcValueType tcEnv p what doc) tys+  return KindStar+kcTypeExpr tcEnv p what doc _ (ListType ty) = do+  kcValueType tcEnv p what doc ty+  return KindStar+kcTypeExpr tcEnv p what doc _ (ArrowType ty1 ty2) = do+  kcValueType tcEnv p what doc ty1+  kcValueType tcEnv p what doc ty2+  return KindStar+kcTypeExpr tcEnv p what doc n (ParenType ty) = kcTypeExpr tcEnv p what doc n ty+kcTypeExpr tcEnv p what doc n (ForallType vs ty) = do+  tcEnv' <- foldM bindFreshKind tcEnv $ vs+  kcTypeExpr tcEnv' p what doc n ty++kcArrow :: Position -> String -> Doc -> Kind -> KCM (Kind, Kind)+kcArrow p what doc k = do+  theta <- getKindSubst+  case subst theta k of+    KindStar -> do+      report $ errNonArrowKind p what doc KindStar+      (,) <$> freshKindVar <*> freshKindVar+    KindVariable kv -> do+      alpha <- freshKindVar+      beta <- freshKindVar+      modifyKindSubst $ bindVar kv $ KindArrow alpha beta+      return (alpha, beta)+    KindArrow k1 k2 -> return (k1, k2)++-- ---------------------------------------------------------------------------+-- Unification+-- ---------------------------------------------------------------------------++-- The unification uses Robinson's algorithm.+unify :: Position -> String -> Doc -> Kind -> Kind -> KCM ()+unify p what doc k1 k2 = do+  theta <- getKindSubst+  let k1' = subst theta k1+  let k2' = subst theta k2+  case unifyKinds k1' k2' of+    Nothing -> report $ errKindMismatch p what doc k1' k2'+    Just sigma -> modifyKindSubst (compose sigma)++unifyKinds :: Kind -> Kind -> Maybe KindSubst+unifyKinds KindStar KindStar = Just idSubst+unifyKinds (KindVariable kv1) (KindVariable kv2)+  | kv1 == kv2 = Just idSubst+  | otherwise  = Just (singleSubst kv1 (KindVariable kv2))+unifyKinds (KindVariable kv) k+  | kv `elem` kindVars k = Nothing+  | otherwise            = Just (singleSubst kv k)+unifyKinds k (KindVariable kv)+  | kv `elem` kindVars k = Nothing+  | otherwise            = Just (singleSubst kv k)+unifyKinds (KindArrow k11 k12) (KindArrow k21 k22) = do+  theta <- unifyKinds k11 k21+  theta' <- unifyKinds (subst theta k12) (subst theta k22)+  Just (compose theta' theta)+unifyKinds _ _ = Nothing++-- ---------------------------------------------------------------------------+-- Fresh variables+-- ---------------------------------------------------------------------------++fresh :: (Int -> a) -> KCM a+fresh f = f <$> getNextId++freshKindVar :: KCM Kind+freshKindVar = fresh KindVariable++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++typeConstructor :: Decl a -> Ident+typeConstructor (DataDecl     _ tc _ _ _) = tc+typeConstructor (ExternalDataDecl _ tc _) = tc+typeConstructor (NewtypeDecl  _ tc _ _ _) = tc+typeConstructor (TypeDecl     _ tc _ _  ) = tc+typeConstructor _                        =+  internalError "Checks.KindCheck.typeConstructor: no type declaration"++isTypeOrNewtypeDecl :: Decl a -> Bool+isTypeOrNewtypeDecl (NewtypeDecl _ _ _ _ _) = True+isTypeOrNewtypeDecl (TypeDecl      _ _ _ _) = True+isTypeOrNewtypeDecl _                       = False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errRecursiveTypes :: [Ident] -> Message+errRecursiveTypes []       = internalError+  "KindCheck.errRecursiveTypes: empty list"+errRecursiveTypes [tc]     = posMessage tc $ hsep $ map text+  ["Recursive synonym or renaming type", idName tc]+errRecursiveTypes (tc:tcs) = posMessage tc $+  text "Mutually recursive synonym and/or renaming types" <+>+    text (idName tc) <> types empty tcs+  where+    types _   []         = empty+    types del [tc']      = del <> space <> text "and" <+> typePos tc'+    types _   (tc':tcs') = comma <+> typePos tc' <> types comma tcs'+    typePos tc' =+      text (idName tc') <+> parens (text $ showLine $ idPosition tc')++errRecursiveClasses :: [Ident] -> Message+errRecursiveClasses []         = internalError+  "KindCheck.errRecursiveClasses: empty list"+errRecursiveClasses [cls]      = posMessage cls $ hsep $ map text+  ["Recursive type class", idName cls]+errRecursiveClasses (cls:clss) = posMessage cls $+  text "Mutually recursive type classes" <+> text (idName cls) <>+    classes empty clss+  where+    classes _   []           = empty+    classes del [cls']       = del <> space <> text "and" <+> classPos cls'+    classes _   (cls':clss') = comma <+> classPos cls' <> classes comma clss'+    classPos cls' =+      text (idName cls') <+> parens (text $ showLine $ idPosition cls')++errNonArrowKind :: Position -> String -> Doc -> Kind -> Message+errNonArrowKind p what doc k = posMessage p $ vcat+  [ text "Kind error in" <+> text what, doc+  , text "Kind:" <+> ppKind k+  , text "Cannot be applied"+  ]++errPartialAlias :: Position -> QualIdent -> Int -> Int -> Message+errPartialAlias p tc arity argc = posMessage p $ hsep+  [ text "Type synonym", ppQIdent tc+  , text "requires at least"+  , int arity, text (plural arity "argument") <> comma+  , text "but is applied to only", int argc+  ]+  where+    plural n x = if n == 1 then x else x ++ "s"++errKindMismatch :: Position -> String -> Doc -> Kind -> Kind -> Message+errKindMismatch p what doc k1 k2 = posMessage p $ vcat+  [ text "Kind error in"  <+> text what, doc+  , text "Inferred kind:" <+> ppKind k2+  , text "Expected kind:" <+> ppKind k1+  ]
+ src/Checks/PrecCheck.hs view
@@ -0,0 +1,497 @@+{- |+    Module      :  $Header$+    Description :  Checks precedences of infix operators+    Copyright   :  (c) 2001 - 2004 Wolfgang Lux+                                   Martin Engelke+                                   Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The parser does not know the relative precedences of infix operators+   and therefore parses them as if they all associate to the right and+   have the same precedence. After performing the definition checks,+   the compiler is going to process the infix applications in the module+   and rearrange infix applications according to the relative precedences+   of the operators involved.+-}+{-# LANGUAGE CPP #-}+module Checks.PrecCheck (precCheck) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative      ((<$>), (<*>))+#endif+import           Control.Monad            (unless, when)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import           Data.List                (partition)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax++import Base.Expr+import Base.Messages (Message, posMessage, internalError)+import Base.Utils    (findMultiples)++import Env.OpPrec (OpPrecEnv, OpPrec (..), PrecInfo (..), defaultP, bindP+  , mkPrec, qualLookupP)++precCheck :: ModuleIdent -> OpPrecEnv -> [Decl a] -> ([Decl a], OpPrecEnv, [Message])+precCheck m pEnv decls = runPCM (checkDecls decls) initState+ where initState = PCState m pEnv []++data PCState = PCState+  { moduleIdent :: ModuleIdent+  , precEnv     :: OpPrecEnv+  , errors      :: [Message]+  }++type PCM = S.State PCState -- the Prec Check Monad++runPCM :: PCM a -> PCState -> (a, OpPrecEnv, [Message])+runPCM kcm s = let (a, s') = S.runState kcm s+               in  (a, precEnv s', reverse $ errors s')++getModuleIdent :: PCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getPrecEnv :: PCM OpPrecEnv+getPrecEnv = S.gets precEnv++modifyPrecEnv :: (OpPrecEnv -> OpPrecEnv) -> PCM ()+modifyPrecEnv f = S.modify $ \ s -> s { precEnv = f $ precEnv s }++withLocalPrecEnv :: PCM a -> PCM a+withLocalPrecEnv act = do+  oldEnv <- getPrecEnv+  res <- act+  modifyPrecEnv $ const oldEnv+  return res++report :: Message -> PCM ()+report err = S.modify (\ s -> s { errors = err : errors s })++-- For each declaration group, including the module-level, the compiler+-- first checks that its fixity declarations contain no duplicates and+-- that there is a corresponding value or constructor declaration in that+-- group. The fixity declarations are then used for extending the+-- imported precedence environment.++bindPrecs :: [Decl a] -> PCM ()+bindPrecs ds0 = case findMultiples opFixDecls of+  [] -> case filter (`notElem` bvs) opFixDecls of+    []  -> do+      m <- getModuleIdent+      modifyPrecEnv $ \env -> foldr (bindPrec m) env fixDs+    ops -> mapM_ (report . errUndefinedOperator) ops+  opss -> mapM_ (report . errMultiplePrecedence) opss+  where+    (fixDs, nonFixDs) = partition isInfixDecl ds0+    innerDs           = [ d | ClassDecl _ _ _ _ ds <- ds0, d <- ds ]+    opFixDecls        = [ op | InfixDecl _ _ _ ops <- fixDs, op <- ops ]+    -- Unrenaming is necessary for inner class declarations, because operators+    -- within class declarations have been renamed during syntax checking.+    bvs               = concatMap boundValues nonFixDs +++                          map unRenameIdent (concatMap boundValues innerDs)++bindPrec :: ModuleIdent -> Decl a -> OpPrecEnv -> OpPrecEnv+bindPrec m (InfixDecl _ fix mprec ops) pEnv+  | p == defaultP = pEnv+  | otherwise     = foldr (flip (bindP m) p) pEnv ops+  where p = OpPrec fix (mkPrec mprec)+bindPrec _ _                           pEnv = pEnv++boundValues :: Decl a -> [Ident]+boundValues (DataDecl     _ _ _ cs _) = [ v | c <- cs+                                            , v <- constrId c : recordLabels c]+boundValues (NewtypeDecl  _ _ _ nc _) = nconstrId nc : nrecordLabels nc+boundValues (TypeSig          _ fs _) = fs+boundValues (FunctionDecl    _ _ f _) = [f]+boundValues (ExternalDecl       _ vs) = bv vs+boundValues (PatternDecl       _ t _) = bv t+boundValues (FreeDecl           _ vs) = bv vs+boundValues _                         = []++-- With the help of the precedence environment, the compiler checks all+-- infix applications and sections in the program. This pass will modify+-- the parse tree such that for a nested infix application the operator+-- with the lowest precedence becomes the root and that two adjacent+-- operators with the same precedence will not have conflicting+-- associativities. Note that the top-level precedence environment has to+-- be returned because it is needed for constructing the module's+-- interface.++checkDecls :: [Decl a] -> PCM [Decl a]+checkDecls decls = bindPrecs decls >> mapM checkDecl decls++checkDecl :: Decl a -> PCM (Decl a)+checkDecl (FunctionDecl p a f           eqs) =+  FunctionDecl p a f <$> mapM checkEquation eqs+checkDecl (PatternDecl  p t             rhs) =+  PatternDecl p <$> checkPattern t <*> checkRhs rhs+checkDecl (ClassDecl    p cx cls    tv   ds) =+  ClassDecl p cx cls tv <$> mapM checkDecl ds+checkDecl (InstanceDecl p cx qcls   inst ds) =+  InstanceDecl p cx qcls inst <$> mapM checkDecl ds+checkDecl d                                  = return d++checkEquation :: Equation a -> PCM (Equation a)+checkEquation (Equation p lhs rhs) =+  Equation p <$> checkLhs lhs <*> checkRhs rhs++checkLhs :: Lhs a -> PCM (Lhs a)+checkLhs (FunLhs    f ts) = FunLhs f <$> mapM checkPattern ts+checkLhs (OpLhs t1 op t2) =+  flip OpLhs op <$> (checkPattern t1 >>= checkOpL op)+                <*> (checkPattern t2 >>= checkOpR op)+checkLhs (ApLhs   lhs ts) =+  ApLhs <$> checkLhs lhs <*> mapM checkPattern ts++checkPattern :: Pattern a -> PCM (Pattern a)+checkPattern l@(LiteralPattern        _ _) = return l+checkPattern n@(NegativePattern       _ _) = return n+checkPattern v@(VariablePattern       _ _) = return v+checkPattern (ConstructorPattern   a c ts) =+  ConstructorPattern a c <$> mapM checkPattern ts+checkPattern (InfixPattern     a t1 op t2) = do+  t1' <- checkPattern t1+  t2' <- checkPattern t2+  fixPrecT (InfixPattern a) t1' op t2'+checkPattern (ParenPattern              t) =+  ParenPattern <$> checkPattern t+checkPattern (TuplePattern             ts) =+  TuplePattern <$> mapM checkPattern ts+checkPattern (ListPattern            a ts) =+  ListPattern a <$> mapM checkPattern ts+checkPattern (AsPattern               v t) =+  AsPattern v <$> checkPattern t+checkPattern (LazyPattern               t) =+  LazyPattern <$> checkPattern t+checkPattern (FunctionPattern      a f ts) =+  FunctionPattern a f <$> mapM checkPattern ts+checkPattern (InfixFuncPattern a t1 op t2) = do+  t1' <- checkPattern t1+  t2' <- checkPattern t2+  fixPrecT (InfixFuncPattern a) t1' op t2'+checkPattern (RecordPattern       a c fs) =+  RecordPattern a c <$> mapM (checkField checkPattern) fs++checkRhs :: Rhs a -> PCM (Rhs a)+checkRhs (SimpleRhs p e ds) = withLocalPrecEnv $+  flip (SimpleRhs p) <$> checkDecls ds <*> checkExpr e+checkRhs (GuardedRhs es ds) = withLocalPrecEnv $+  (flip GuardedRhs) <$> checkDecls ds <*> mapM checkCondExpr es++checkCondExpr :: CondExpr a -> PCM (CondExpr a)+checkCondExpr (CondExpr p g e) = CondExpr p <$> checkExpr g <*> checkExpr e++checkExpr :: Expression a -> PCM (Expression a)+checkExpr l@(Literal       _ _) = return l+checkExpr v@(Variable      _ _) = return v+checkExpr c@(Constructor   _ _) = return c+checkExpr (Paren             e) = Paren <$> checkExpr e+checkExpr (Typed          e ty) = flip Typed ty <$> checkExpr e+checkExpr (Record       a c fs) = Record a c <$> mapM (checkField checkExpr) fs+checkExpr (RecordUpdate   e fs) = RecordUpdate <$> (checkExpr e)+                                             <*> mapM (checkField checkExpr) fs+checkExpr (Tuple            es) = Tuple <$> mapM checkExpr es+checkExpr (List           a es) = List a <$> mapM checkExpr es+checkExpr (ListCompr      e qs) = withLocalPrecEnv $+  flip ListCompr <$> mapM checkStmt qs <*> checkExpr e+checkExpr (EnumFrom              e) = EnumFrom <$> checkExpr e+checkExpr (EnumFromThen      e1 e2) =+  EnumFromThen <$> checkExpr e1 <*> checkExpr e2+checkExpr (EnumFromTo        e1 e2) =+  EnumFromTo <$> checkExpr e1 <*> checkExpr e2+checkExpr (EnumFromThenTo e1 e2 e3) =+  EnumFromThenTo <$> checkExpr e1 <*> checkExpr e2 <*> checkExpr e3+checkExpr (UnaryMinus            e) = UnaryMinus <$> checkExpr e+checkExpr (Apply e1 e2) =+  Apply <$> checkExpr e1 <*> checkExpr e2+checkExpr (InfixApply e1 op e2) = do+  e1' <- checkExpr e1+  e2' <- checkExpr e2+  fixPrec e1' op e2'+checkExpr (LeftSection      e op) = checkExpr e >>= checkLSection op+checkExpr (RightSection     op e) = checkExpr e >>= checkRSection op+checkExpr (Lambda           ts e) =+  Lambda <$> mapM checkPattern ts <*> checkExpr e+checkExpr (Let              ds e) = withLocalPrecEnv $+  Let <$> checkDecls ds <*> checkExpr e+checkExpr (Do              sts e) = withLocalPrecEnv $+  Do <$>  mapM checkStmt sts <*> checkExpr e+checkExpr (IfThenElse   e1 e2 e3) =+  IfThenElse <$> checkExpr e1 <*> checkExpr e2 <*> checkExpr e3+checkExpr (Case        ct e alts) =+  Case ct <$> checkExpr e <*> mapM checkAlt alts++checkStmt :: Statement a -> PCM (Statement a)+checkStmt (StmtExpr   e) = StmtExpr <$> checkExpr e+checkStmt (StmtDecl  ds) = StmtDecl <$> checkDecls ds+checkStmt (StmtBind t e) = StmtBind <$> checkPattern t <*> checkExpr e++checkAlt :: Alt a -> PCM (Alt a)+checkAlt (Alt p t rhs) = Alt p <$> checkPattern t <*> checkRhs rhs++checkField :: (a -> PCM a) -> Field a -> PCM (Field a)+checkField check (Field p l x) = Field p l <$> check x++-- The functions 'fixPrec', 'fixUPrec', and 'fixRPrec' check the relative+-- precedences of adjacent infix operators in nested infix applications+-- and unary negations. The expressions will be reordered such that the+-- infix operator with the lowest precedence becomes the root of the+-- expression. The functions rely on the fact that the parser constructs+-- infix applications in a right-associative fashion, i.e., the left argument+-- of an infix application will never be an infix application. In addition,+-- a unary negation will never have an infix application as its argument.++-- The function 'fixPrec' checks whether the left argument of an+-- infix application is a unary negation and eventually reorders the+-- expression if the precedence of the infix operator is higher than that+-- of the negation. This will be done with the help of the function+-- 'fixUPrec'. In any case, the function 'fixRPrec' is used for fixing the+-- precedence of the infix operator and that of its right argument.+-- Note that both arguments already have been checked before 'fixPrec'+-- is called.++fixPrec :: Expression a -> InfixOp a -> Expression a -> PCM (Expression a)+fixPrec (UnaryMinus e1) op e2 = do+  OpPrec fix pr <- getOpPrec op+  if pr < 6 || pr == 6 && fix == InfixL+    then fixRPrec (UnaryMinus e1) op e2+    else if pr > 6+      then fixUPrec e1 op e2+      else do+        report $ errAmbiguousParse "unary" (qualify minusId) (opName op)+        return $ InfixApply (UnaryMinus e1) op e2+fixPrec e1 op e2 = fixRPrec e1 op e2++fixUPrec :: Expression a -> InfixOp a -> Expression a+         -> PCM (Expression a)+fixUPrec e1 op e2@(UnaryMinus _) = do+  report $ errAmbiguousParse "operator" (opName op) (qualify minusId)+  return $ UnaryMinus (InfixApply e1 op e2)+fixUPrec e1 op1 e'@(InfixApply e2 op2 e3) = do+  OpPrec fix2 pr2 <- getOpPrec op2+  if pr2 < 6 || pr2 == 6 && fix2 == InfixL+    then do+      left <- fixUPrec e1 op1 e2+      return $ InfixApply left op2 e3+    else if pr2 > 6+      then do+        op <- fixRPrec e1 op1 $ InfixApply e2 op2 e3+        return $ UnaryMinus op+      else do+        report $ errAmbiguousParse "unary" (qualify minusId) (opName op2)+        return $ InfixApply (UnaryMinus e1) op1 e'+fixUPrec e1 op e2 = return $ UnaryMinus (InfixApply e1 op e2)++fixRPrec :: Expression a -> InfixOp a -> Expression a -> PCM (Expression a)+fixRPrec e1 op (UnaryMinus e2) = do+  OpPrec _ pr <- getOpPrec op+  unless (pr < 6) $ report $ errAmbiguousParse "operator" (opName op) (qualify minusId)+  return $ InfixApply e1 op $ UnaryMinus e2+fixRPrec e1 op1 (InfixApply e2 op2 e3) = do+  OpPrec fix1 pr1 <- getOpPrec op1+  OpPrec fix2 pr2 <- getOpPrec op2+  if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR+     then return $ InfixApply e1 op1 $ InfixApply e2 op2 e3+     else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL+       then do+          left <- fixPrec e1 op1 e2+          return $ InfixApply left op2 e3+       else do+         report $ errAmbiguousParse "operator" (opName op1) (opName op2)+         return $ InfixApply e1 op1 $ InfixApply e2 op2 e3+fixRPrec e1 op e2 = return $ InfixApply e1 op e2++-- The functions 'checkLSection' and 'checkRSection' are used for handling+-- the precedences inside left and right sections.+-- These functions only need to check that an infix operator occurring in+-- the section has either a higher precedence than the section operator+-- or both operators have the same precedence and are both left+-- associative for a left section and right associative for a right+-- section, respectively.++checkLSection :: InfixOp a -> Expression a -> PCM (Expression a)+checkLSection op e@(UnaryMinus _) = do+  OpPrec fix pr <- getOpPrec op+  unless (pr < 6 || pr == 6 && fix == InfixL) $+    report $ errAmbiguousParse "unary" (qualify minusId) (opName op)+  return $ LeftSection e op+checkLSection op1 e@(InfixApply _ op2 _) = do+  OpPrec fix1 pr1 <- getOpPrec op1+  OpPrec fix2 pr2 <- getOpPrec op2+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL) $+    report $ errAmbiguousParse "operator" (opName op1) (opName op2)+  return $ LeftSection e op1+checkLSection op e = return $ LeftSection e op++checkRSection :: InfixOp a -> Expression a -> PCM (Expression a)+checkRSection op e@(UnaryMinus _) = do+  OpPrec _ pr <- getOpPrec op+  unless (pr < 6) $ report $ errAmbiguousParse "unary" (qualify minusId) (opName op)+  return $ RightSection op e+checkRSection op1 e@(InfixApply _ op2 _) = do+  OpPrec fix1 pr1 <- getOpPrec op1+  OpPrec fix2 pr2 <- getOpPrec op2+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR) $+    report $ errAmbiguousParse "operator" (opName op1) (opName op2)+  return $ RightSection op1 e+checkRSection op e = return $ RightSection op e++-- The functions 'fixPrecT' and 'fixRPrecT' check the relative precedences+-- of adjacent infix operators in patterns. The patterns will be reordered+-- such that the infix operator with the lowest precedence becomes the root+-- of the term. The functions rely on the fact that the parser constructs+-- infix patterns in a right-associative fashion, i.e., the left argument+-- of an infix pattern will never be an infix pattern. The functions also+-- check whether the left and right arguments of an infix pattern are negative+-- literals. In this case, the negation must bind more tightly than the+-- operator for the pattern to be accepted.++fixPrecT :: (Pattern a -> QualIdent -> Pattern a -> Pattern a)+         -> Pattern a -> QualIdent -> Pattern a -> PCM (Pattern a)+fixPrecT infixpatt t1@(NegativePattern _ _) op t2 = do+  OpPrec fix pr <- prec op <$> getPrecEnv+  unless (pr < 6 || pr == 6 && fix == InfixL) $+    report $ errInvalidParse "unary operator" minusId op+  fixRPrecT infixpatt t1 op t2+fixPrecT infixpatt t1 op t2 = fixRPrecT infixpatt t1 op t2++fixRPrecT :: (Pattern a -> QualIdent -> Pattern a -> Pattern a)+          -> Pattern a -> QualIdent -> Pattern a -> PCM (Pattern a)+fixRPrecT infixpatt t1 op t2@(NegativePattern _ _) = do+  OpPrec _ pr <- prec op <$> getPrecEnv+  unless (pr < 6) $ report $ errInvalidParse "unary operator" minusId op+  return $ infixpatt t1 op t2+fixRPrecT infixpatt t1 op1 (InfixPattern a t2 op2 t3) = do+  OpPrec fix1 pr1 <- prec op1 <$> getPrecEnv+  OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+  if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR+    then return $ infixpatt t1 op1 (InfixPattern a t2 op2 t3)+    else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL+      then do+        left <- fixPrecT infixpatt t1 op1 t2+        return $ InfixPattern a left op2 t3+      else do+        report $ errAmbiguousParse "operator" op1 op2+        return $ infixpatt t1 op1 (InfixPattern a t2 op2 t3)+fixRPrecT infixpatt t1 op1 (InfixFuncPattern a t2 op2 t3) = do+  OpPrec fix1 pr1 <- prec op1 <$> getPrecEnv+  OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+  if pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR+    then return $ infixpatt t1 op1 (InfixFuncPattern a t2 op2 t3)+    else if pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL+      then do+        left <- fixPrecT infixpatt t1 op1 t2+        return $ InfixFuncPattern a left op2 t3+      else do+        report $ errAmbiguousParse "operator" op1 op2+        return $ infixpatt t1 op1 (InfixFuncPattern a t2 op2 t3)+fixRPrecT infixpatt t1 op t2 = return $ infixpatt t1 op t2++{-fixPrecT :: Position -> OpPrecEnv -> Pattern -> QualIdent -> Pattern+         -> Pattern+fixPrecT p pEnv t1@(NegativePattern uop l) op t2+  | pr < 6 || pr == 6 && fix == InfixL = fixRPrecT p pEnv t1 op t2+  | otherwise = errorAt p $ errInvalidParse "unary" uop op+  where OpPrec fix pr = prec op pEnv+fixPrecT p pEnv t1 op t2 = fixRPrecT p pEnv t1 op t2-}++{-fixRPrecT :: Position -> OpPrecEnv -> Pattern -> QualIdent -> Pattern+          -> Pattern+fixRPrecT p pEnv t1 op t2@(NegativePattern uop l)+  | pr < 6 = InfixPattern t1 op t2+  | otherwise = errorAt p $ errInvalidParse "unary" uop op+  where OpPrec _ pr = prec op pEnv+fixRPrecT p pEnv t1 op1 (InfixPattern t2 op2 t3)+  | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =+      InfixPattern t1 op1 (InfixPattern t2 op2 t3)+  | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =+      InfixPattern (fixPrecT p pEnv t1 op1 t2) op2 t3+  | otherwise = errorAt p $ errAmbiguousParse "operator" op1 op2+  where OpPrec fix1 pr1 = prec op1 pEnv+        OpPrec fix2 pr2 = prec op2 pEnv+fixRPrecT _ _ t1 op t2 = InfixPattern t1 op t2-}++-- The functions 'checkOpL' and 'checkOpR' check the left and right arguments+-- of an operator declaration. If they are infix patterns they must bind+-- more tightly than the operator, otherwise the left-hand side of the+-- declaration is invalid.++checkOpL :: Ident -> Pattern a -> PCM (Pattern a)+checkOpL op t@(NegativePattern _ _) = do+  OpPrec fix pr <- prec (qualify op) <$> getPrecEnv+  unless (pr < 6 || pr == 6 && fix == InfixL) $+    report $ errInvalidParse "unary operator" minusId (qualify op)+  return t+checkOpL op1 t@(InfixPattern _ _ op2 _) = do+  OpPrec fix1 pr1 <- prec (qualify op1) <$> getPrecEnv+  OpPrec fix2 pr2 <- prec op2 <$> getPrecEnv+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL) $+    report $ errInvalidParse "operator" op1 op2+  return t+checkOpL _ t = return t++checkOpR :: Ident -> Pattern a -> PCM (Pattern a)+checkOpR op t@(NegativePattern _ _) = do+  OpPrec _ pr <- prec (qualify op)  <$> getPrecEnv+  when (pr >= 6) $ report $ errInvalidParse "unary operator" minusId (qualify op)+  return t+checkOpR op1 t@(InfixPattern _ _ op2 _) = do+  OpPrec fix1 pr1 <- prec (qualify op1)  <$> getPrecEnv+  OpPrec fix2 pr2 <- prec op2  <$> getPrecEnv+  unless (pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR) $+    report $ errInvalidParse "operator" op1 op2+  return t+checkOpR _ t = return t++-- The functions 'opPrec' and 'prec' return the fixity and operator precedence+-- of an entity. Even though precedence checking is performed after the+-- renaming phase, we have to be prepared to see ambiguous identifiers here.+-- This may happen while checking the root of an operator definition that+-- shadows an imported definition.++getOpPrec :: InfixOp a -> PCM OpPrec+getOpPrec op = opPrec op <$> getPrecEnv++opPrec :: InfixOp a -> OpPrecEnv -> OpPrec+opPrec op = prec (opName op)++prec :: QualIdent -> OpPrecEnv -> OpPrec+prec op env = case qualLookupP op env of+  [] -> defaultP+  PrecInfo _ p : _ -> p++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUndefinedOperator :: Ident -> Message+errUndefinedOperator op = posMessage op $ hsep $ map text+  ["No definition for", escName op, "in this scope"]++errMultiplePrecedence :: [Ident] -> Message+errMultiplePrecedence []       = internalError+  "PrecCheck.errMultiplePrecedence: empty list"+errMultiplePrecedence (op:ops) = posMessage op $+  (hsep $ map text ["More than one fixity declaration for", escName op, "at"])+  $+$ nest 2 (vcat (map (ppPosition . getPosition) (op:ops)))++errInvalidParse :: String -> Ident -> QualIdent -> Message+errInvalidParse what op1 op2 = posMessage op1 $ hsep $ map text+  [ "Invalid use of", what, escName op1, "with", escQualName op2, "in"+  , showLine $ qidPosition op2]++-- FIXME: Messages may have missing positions for minus operators++errAmbiguousParse :: String -> QualIdent -> QualIdent -> Message+errAmbiguousParse what op1 op2 = posMessage op1 $ hsep $ map text+  ["Ambiguous use of", what, escQualName op1, "with", escQualName op2, "in"+  , showLine $ qidPosition op2]
+ src/Checks/SyntaxCheck.hs view
@@ -0,0 +1,1391 @@+{- |+    Module      :  $Header$+    Description :  Syntax checks+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux+                                   Martin Engelke+                                   Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   After the type declarations have been checked, the compiler performs+   a syntax check on the remaining declarations. This check disambiguates+   nullary data constructors and variables which -- in contrast to Haskell --+   is not possible on purely syntactic criteria. In addition, this pass checks+   for undefined as well as ambiguous variables and constructors. In order to+   allow lifting of local definitions in later phases, all local variables are+   renamed by adding a key identifying their scope. Therefore, all variables+   defined in the same scope share the same key so that multiple definitions+   can be recognized. Finally, all (adjacent) equations of a function are+   merged into a single definition.+-}+{-# LANGUAGE CPP #-}+module Checks.SyntaxCheck (syntaxCheck) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+-- <<<<<<< HEAD+import Control.Monad                      (unless, when)+import qualified Control.Monad.State as S ( State, runState, gets, modify+                                          , withState )+import           Data.Function            (on)+import           Data.List                (insertBy, intersect, nub, nubBy)+import qualified Data.Map  as Map         ( Map, empty, findWithDefault+                                          , fromList, insertWith, keys )+import           Data.Maybe               (isJust, isNothing)+import qualified Data.Set as Set          ( Set, empty, insert, member+                                          , singleton, toList, union)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty (ppPattern)++import Base.Expr+import Base.Messages (Message, posMessage, internalError)+import Base.NestEnv+import Base.SCC      (scc)+import Base.Utils    ((++!), findDouble, findMultiples)++import Env.TypeConstructor (TCEnv, clsMethods)+import Env.Value           (ValueEnv, ValueInfo (..))++-- The syntax checking proceeds as follows. First, the compiler extracts+-- information about all imported values and data constructors from the+-- imported (type) environments. Next, the data constructors defined in+-- the current module are entered into this environment. After this,+-- all record labels are entered into the environment. If a record+-- identifier is already assigned to a constructor, then an error will be+-- generated. Class methods defined in the current module are entered into+-- the environment, too. Finally, all declarations are checked within the+-- resulting environment. In addition, this process will also rename the+-- local variables.++syntaxCheck :: [KnownExtension] -> TCEnv -> ValueEnv -> Module ()+            -> ((Module (), [KnownExtension]), [Message])+syntaxCheck exts tcEnv vEnv mdl@(Module _ m _ _ ds) =+  case findMultiples $ concatMap constrs tds of+    []  -> case findMultiples (ls ++ fs ++ cs) of+             []  -> runSC (checkModule mdl) state+             iss -> ((mdl, exts), map (errMultipleDeclarations m) iss)+    css -> ((mdl, exts), map errMultipleDataConstructor css)+  where+    tds   = filter isTypeDecl ds+    vds   = filter isValueDecl ds+    cds   = filter isClassDecl ds+    ls    = nub $ concatMap recLabels tds+    fs    = nub $ concatMap vars vds+    cs    = concatMap (concatMap methods) $ [ds' | ClassDecl _ _ _ _ ds' <- cds]+    rEnv  = globalEnv $ fmap renameInfo vEnv+    state = initState exts m tcEnv rEnv++-- A global state transformer is used for generating fresh integer keys with+-- which the variables are renamed.+-- The state tracks the identifier of the current scope 'scopeId' as well as+-- the next fresh identifier, which is used for introducing new scopes as well+-- as renaming literals and underscore to disambiguate them.++-- |Syntax check monad+type SCM = S.State SCState++-- |Internal state of the syntax check+data SCState = SCState+  { extensions       :: [KnownExtension] -- ^ Enabled language extensions+  , moduleIdent      :: ModuleIdent      -- ^ 'ModuleIdent' of the current module+  , tyConsEnv        :: TCEnv+  , renameEnv        :: RenameEnv        -- ^ Information store+  , scopeId          :: Integer          -- ^ Identifier for the current scope+  , nextId           :: Integer          -- ^ Next fresh identifier+  , funcDeps         :: FuncDeps         -- ^ Stores data about functions dependencies+  , typeClassesCheck :: Bool+  , errors           :: [Message]        -- ^ Syntactic errors in the module+  }++-- |Initial syntax check state+initState :: [KnownExtension] -> ModuleIdent -> TCEnv -> RenameEnv -> SCState+initState exts m tcEnv rEnv =+  SCState exts m tcEnv rEnv globalScopeId 1 noFuncDeps False []++-- |Identifier for global (top-level) declarations+globalScopeId :: Integer+globalScopeId = idUnique (mkIdent "")++-- |Run the syntax check monad+runSC :: SCM a -> SCState -> (a, [Message])+runSC scm s = let (a, s') = S.runState scm s in (a, reverse $ errors s')++-- |Check for an enabled extension+hasExtension :: KnownExtension -> SCM Bool+hasExtension ext = S.gets (elem ext . extensions)++-- |Enable an additional 'Extension' to avoid redundant complaints about+-- missing extensions+enableExtension :: KnownExtension -> SCM ()+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }++-- |Retrieve all enabled extensions+getExtensions :: SCM [KnownExtension]+getExtensions = S.gets extensions++-- |Retrieve the 'ModuleIdent' of the current module+getModuleIdent :: SCM ModuleIdent+getModuleIdent = S.gets moduleIdent++-- |Retrieve the 'TCEnv'+getTyConsEnv :: SCM TCEnv+getTyConsEnv = S.gets tyConsEnv++-- |Retrieve the 'RenameEnv'+getRenameEnv :: SCM RenameEnv+getRenameEnv = S.gets renameEnv++-- |Modify the 'RenameEnv'+modifyRenameEnv :: (RenameEnv -> RenameEnv) -> SCM ()+modifyRenameEnv f = S.modify $ \s -> s { renameEnv = f $ renameEnv s }++-- |Retrieve the current scope identifier+getScopeId :: SCM Integer+getScopeId = S.gets scopeId++-- |Create a new identifier and return it+newId :: SCM Integer+newId = do+  curId <- S.gets nextId+  S.modify $ \s -> s { nextId = succ curId }+  return curId++-- |Checks whether a type classes check is running+isTypeClassesCheck :: SCM Bool+isTypeClassesCheck = S.gets typeClassesCheck++-- |Performs a type classes check in a nested scope+performTypeClassesCheck :: SCM a -> SCM a+performTypeClassesCheck = inNestedScope .+  S.withState (\s -> s { typeClassesCheck = True })++-- |Increase the nesting of the 'RenameEnv' to introduce a new local scope.+-- This also increases the scope identifier.+incNesting :: SCM ()+incNesting = do+  newScopeId <- newId+  S.modify $ \s -> s { scopeId = newScopeId }+  modifyRenameEnv nestEnv++withLocalEnv :: SCM a -> SCM a+withLocalEnv act = do+  oldEnv <- getRenameEnv+  res    <- act+  modifyRenameEnv $ const oldEnv+  return res++-- |Perform an action in a nested scope (by creating a nested 'RenameEnv')+-- and discard the nested 'RenameEnv' afterwards+inNestedScope :: SCM a -> SCM a+inNestedScope act = withLocalEnv (incNesting >> act)++-- |Modify the `FuncDeps'+modifyFuncDeps :: (FuncDeps -> FuncDeps) -> SCM ()+modifyFuncDeps f = S.modify $ \ s -> s { funcDeps = f $ funcDeps s }++-- |Report a syntax error+report :: Message -> SCM ()+report msg = S.modify $ \s -> s { errors = msg : errors s }++-- |Everything is checked+ok :: SCM ()+ok = return ()++-- FuncDeps contains information to deal with dependencies between functions.+-- This is used for checking whether functional patterns are cyclic.+-- curGlobalFunc contains the identifier of the global function that is+-- currently being checked, if any.+-- data X = X+-- f = let g = lookup 42 in g [1,2,3]+-- While `X' is being checked `curGlobalFunc' should be `Nothing',+-- while `lookup' is being checked is should be `f's identifier.+-- globalDeps collects all dependencies (other functions) of global functions+-- funcPats collects all functional patterns and the global function they're+-- used in+data FuncDeps = FuncDeps+  { curGlobalFunc :: Maybe QualIdent+  , globalDeps    :: GlobalDeps+  , funcPats      :: [(QualIdent, QualIdent)]+  }+type GlobalDeps = Map.Map QualIdent (Set.Set QualIdent)++-- |Initial state for FuncDeps+noFuncDeps :: FuncDeps+noFuncDeps = FuncDeps Nothing Map.empty []++-- |Perform an action inside a function, settìng `curGlobalFunc' to that function+inFunc :: Ident -> SCM a -> SCM a+inFunc i scm = do+  m      <- getModuleIdent+  global <- isNothing <$> S.gets (curGlobalFunc . funcDeps)+  when global $ modifyFuncDeps $ \ fd -> fd { curGlobalFunc = Just (qualifyWith m i) }+  res    <- scm+  when global $ modifyFuncDeps $ \ fd -> fd { curGlobalFunc = Nothing }+  return res++-- |Add a dependency to `curGlobalFunction'+addGlobalDep :: QualIdent -> SCM ()+addGlobalDep dep = do+  maybeF <- S.gets (curGlobalFunc . funcDeps)+  case maybeF of+    Nothing -> internalError "SyntaxCheck.addFuncPat: no global function set"+    Just  f -> modifyFuncDeps $ \ fd -> fd+                { globalDeps = Map.insertWith (Set.union) f+                              (Set.singleton dep) (globalDeps fd) }++-- |Add a functional pattern to `curGlobalFunction'+addFuncPat :: QualIdent -> SCM ()+addFuncPat fp = do+  maybeF <- S.gets (curGlobalFunc . funcDeps)+  case maybeF of+    Nothing -> internalError "SyntaxCheck.addFuncPat: no global function set"+    Just  f -> modifyFuncDeps $ \ fd -> fd { funcPats = (fp, f) : funcPats fd }++-- |Return dependencies of global functions+getGlobalDeps :: SCM GlobalDeps+getGlobalDeps = globalDeps <$> S.gets funcDeps++-- |Return used functional patterns+getFuncPats :: SCM [(QualIdent, QualIdent)]+getFuncPats = funcPats <$> S.gets funcDeps+++-- A nested environment is used for recording information about the data+-- constructors and variables in the module. For every data constructor+-- its arity is saved. This is used for checking that all constructor+-- applications in patterns are saturated. For local variables the+-- environment records the new name of the variable after renaming.+-- Global variables are recorded with qualified identifiers in order+-- to distinguish multiply declared entities.++-- Currently, records must explicitly be declared together with their labels.+-- When constructing or updating a record, it is necessary to compute+-- all its labels using just one of them. Thus for each label+-- the record identifier and all its labels are entered into the environment++-- Note: the function 'qualLookupVar' has been extended to allow the usage of+-- the qualified list constructor (prelude.:).++type RenameEnv = NestEnv RenameInfo++data RenameInfo+  -- |Arity of data constructor+  = Constr      QualIdent Int+  -- |Constructors of a record label+  | RecordLabel QualIdent [QualIdent]+  -- |Arity of global function+  | GlobalVar   QualIdent Int+  -- |Arity of local function+  | LocalVar    Ident Int+    deriving (Eq, Show)++ppRenameInfo :: RenameInfo -> Doc+ppRenameInfo (Constr      qn _) = text (escQualName qn)+ppRenameInfo (RecordLabel qn _) = text (escQualName qn)+ppRenameInfo (GlobalVar   qn _) = text (escQualName qn)+ppRenameInfo (LocalVar     n _) = text (escName      n)++-- Since record types are currently translated into data types, it is necessary+-- to ensure that all identifiers for records and constructors are different.+-- Furthermore, it is not allowed to declare a label more than once.++renameInfo :: ValueInfo -> RenameInfo+renameInfo (DataConstructor    qid    a _ _) = Constr      qid a+renameInfo (NewtypeConstructor qid      _ _) = Constr      qid 1+renameInfo (Value              qid _  a   _) = GlobalVar   qid a+renameInfo (Label              qid cs     _) = RecordLabel qid cs++bindGlobal :: Bool -> ModuleIdent -> Ident -> RenameInfo -> RenameEnv+           -> RenameEnv+bindGlobal tcc m c r+  | not tcc   = bindNestEnv c r . qualBindNestEnv (qualifyWith m c) r+  | otherwise = id++bindLocal :: Ident -> RenameInfo -> RenameEnv -> RenameEnv+bindLocal = bindNestEnv++-- ------------------------------------------------------------------------------++-- |Bind type constructor information and record label information+bindTypeDecl :: Decl a -> SCM ()+bindTypeDecl (DataDecl    _ _ _ cs _) =+  mapM_ bindConstr cs >> bindRecordLabels cs+bindTypeDecl (NewtypeDecl _ _ _ nc _) = bindNewConstr nc+bindTypeDecl _                        = ok++bindConstr :: ConstrDecl -> SCM ()+bindConstr (ConstrDecl _ _ _ c tys) = do+  m <- getModuleIdent+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) $ length tys)+bindConstr (ConOpDecl _ _ _ _ op _) = do+  m <- getModuleIdent+  modifyRenameEnv $ bindGlobal False m op (Constr (qualifyWith m op) 2)+bindConstr (RecordDecl _ _ _ c fs)  = do+  m <- getModuleIdent+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) (length labels))+    where labels = [l | FieldDecl _ ls _ <- fs, l <- ls]++bindNewConstr :: NewConstrDecl -> SCM ()+bindNewConstr (NewConstrDecl _ c _) = do+  m <- getModuleIdent+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) 1)+bindNewConstr (NewRecordDecl _ c (l, _)) = do+  m <- getModuleIdent+  bindRecordLabel (l, [c])+  modifyRenameEnv $ bindGlobal False m c (Constr (qualifyWith m c) 1)++bindRecordLabels :: [ConstrDecl] -> SCM ()+bindRecordLabels cs =+  mapM_ bindRecordLabel [(l, constr l) | l <- nub (concatMap recordLabels cs)]+  where constr l = [constrId c | c <- cs, l `elem` recordLabels c]++bindRecordLabel :: (Ident, [Ident]) -> SCM ()+bindRecordLabel (l, cs) = do+  m   <- getModuleIdent+  new <- (null . lookupVar l) <$> getRenameEnv+  unless new $ report $ errDuplicateDefinition l+  modifyRenameEnv $ bindGlobal False m l $+    RecordLabel (qualifyWith m l) (map (qualifyWith m) cs)++-- ------------------------------------------------------------------------------++-- |Bind a global function declaration in the 'RenameEnv'+bindFuncDecl :: Bool -> ModuleIdent -> Decl a -> RenameEnv -> RenameEnv+bindFuncDecl _   _ (FunctionDecl _ _ _ []) _+  = internalError "SyntaxCheck.bindFuncDecl: no equations"+bindFuncDecl tcc m (FunctionDecl _ _ f (eq:_)) env+  = let arty = length $ snd $ getFlatLhs eq+    in  bindGlobal tcc m f (GlobalVar (qualifyWith m f) arty) env+bindFuncDecl tcc m (TypeSig _ fs (QualTypeExpr _ ty)) env+  = foldr bindTS env $ map (qualifyWith m) fs+  where+    bindTS qf env'+      | null $ qualLookupVar qf env'+        = bindGlobal tcc m (unqualify qf) (GlobalVar qf (typeArity ty)) env'+      | otherwise = env'+bindFuncDecl _   _ _ env = env++-- ------------------------------------------------------------------------------++-- |Bind type class information, i.e. class methods+bindClassDecl :: Decl a -> SCM ()+bindClassDecl (ClassDecl _ _ _ _ ds) = mapM_ bindClassMethod ds+bindClassDecl _ = ok++bindClassMethod :: Decl a -> SCM ()+bindClassMethod ts@(TypeSig _ _ _) = do+  m <- getModuleIdent+  modifyRenameEnv $ bindFuncDecl False m ts+bindClassMethod _ = ok++-- ------------------------------------------------------------------------------++-- |Bind a local declaration (function, variables) in the 'RenameEnv'+bindVarDecl :: Decl a -> RenameEnv -> RenameEnv+bindVarDecl (FunctionDecl    _ _ f eqs) env+  | null eqs  = internalError "SyntaxCheck.bindVarDecl: no equations"+  | otherwise = let arty = length $ snd $ getFlatLhs $ head eqs+                in  bindLocal (unRenameIdent f) (LocalVar f arty) env+bindVarDecl (PatternDecl         _ t _) env = foldr bindVar env (bv t)+bindVarDecl (FreeDecl             _ vs) env =+  foldr bindVar env (map varIdent vs)+bindVarDecl _                           env = env++bindVar :: Ident -> RenameEnv -> RenameEnv+bindVar v | isAnonId v = id+          | otherwise  = bindLocal (unRenameIdent v) (LocalVar v 0)++lookupVar :: Ident -> RenameEnv -> [RenameInfo]+lookupVar v env = lookupNestEnv v env ++! lookupTupleConstr v++qualLookupVar :: QualIdent -> RenameEnv -> [RenameInfo]+qualLookupVar v env =  qualLookupNestEnv v env+                   ++! qualLookupListCons v env+                   ++! lookupTupleConstr (unqualify v)++lookupTupleConstr :: Ident -> [RenameInfo]+lookupTupleConstr v+  | isTupleId v = let a = tupleArity v+                  in  [Constr (qualifyWith preludeMIdent $ tupleId a) a]+  | otherwise   = []++qualLookupListCons :: QualIdent -> RenameEnv -> [RenameInfo]+qualLookupListCons v env+  | v == qualifyWith preludeMIdent consId+  = qualLookupNestEnv (qualify $ qidIdent v) env+  | otherwise+  = []++-- When a module is checked, the global declaration group is checked. The+-- resulting renaming environment can be discarded. The same is true for+-- a goal. Note that all declarations in the goal must be considered as+-- local declarations. Class and instance declarations define their own scope,+-- thus defined functions will be renamed as well. For class and instance+-- declarations several checks have to be disabled (for instance, type+-- signatures without corresponding function declaration are allowed in class+-- declarations), while some have to be performed extra (for instance, no+-- other functions than specified by the type signatures within a class+-- declaration are allowed to be declared).++checkModule :: Module () -> SCM (Module (), [KnownExtension])+checkModule (Module ps m es is ds) = do+  mapM_ bindTypeDecl tds+  mapM_ bindClassDecl cds+  ds' <- checkTopDecls ds+  cds' <- mapM (performTypeClassesCheck . checkClassDecl) cds+  ids' <- mapM (performTypeClassesCheck . checkInstanceDecl) ids+  let ds'' = updateClassAndInstanceDecls cds' ids' ds'+  checkFuncPatDeps+  exts <- getExtensions+  return (Module ps m es is ds'', exts)+  where tds = filter isTypeDecl ds+        cds = filter isClassDecl ds+        ids = filter isInstanceDecl ds++-- |Checks whether a function in a functional pattern contains cycles+-- |(depends on its own global function)+checkFuncPatDeps :: SCM ()+checkFuncPatDeps = do+  fps  <- getFuncPats+  deps <- getGlobalDeps+  let levels   = scc (:[])+                     (\k -> Set.toList (Map.findWithDefault (Set.empty) k deps))+                     (Map.keys deps)+      levelMap = Map.fromList [ (f, l) | (fs, l) <- zip levels [1 ..], f <- fs ]+      level f  = Map.findWithDefault (0 :: Int) f levelMap+  mapM_ (checkFuncPatDep level) fps++checkFuncPatDep :: Ord a => (QualIdent -> a) -> (QualIdent, QualIdent) -> SCM ()+checkFuncPatDep level (fp, f) = unless (level fp < level f) $+  report $ errFuncPatCyclic fp f++checkTopDecls :: [Decl ()] -> SCM [Decl ()]+checkTopDecls ds = do+  m <- getModuleIdent+  tcc <- isTypeClassesCheck+  checkDeclGroup (bindFuncDecl tcc m) ds++checkClassDecl :: Decl () -> SCM (Decl ())+checkClassDecl (ClassDecl p cx cls tv ds) = do+  checkMethods (qualify cls) (concatMap methods ds) ds+  ClassDecl p cx cls tv <$> checkTopDecls ds+checkClassDecl _ =+  internalError "SyntaxCheck.checkClassDecl: no class declaration"++checkInstanceDecl :: Decl () -> SCM (Decl ())+checkInstanceDecl (InstanceDecl p cx qcls ty ds) = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  checkMethods qcls (clsMethods m qcls tcEnv) ds+  InstanceDecl p cx qcls ty <$> checkTopDecls ds+checkInstanceDecl _ =+  internalError "SyntaxCheck.checkInstanceDecl: no instance declaration"++checkMethods :: QualIdent -> [Ident] -> [Decl a] -> SCM ()+checkMethods qcls ms ds =+  mapM_ (report . errUndefinedMethod qcls) $ filter (`notElem` ms) fs+  where fs = [f | FunctionDecl _ _ f _ <- ds]++updateClassAndInstanceDecls :: [Decl a] -> [Decl a] -> [Decl a] -> [Decl a]+updateClassAndInstanceDecls [] [] ds = ds+updateClassAndInstanceDecls (c:cs) is (ClassDecl _ _ _ _ _:ds) =+  c : updateClassAndInstanceDecls cs is ds+updateClassAndInstanceDecls cs (i:is) (InstanceDecl _ _ _ _ _:ds) =+  i : updateClassAndInstanceDecls cs is ds+updateClassAndInstanceDecls cs is (d:ds) =+  d : updateClassAndInstanceDecls cs is ds+updateClassAndInstanceDecls _ _ _ =+  internalError "SyntaxCheck.updateClassAndInstanceDecls"++-- Each declaration group opens a new scope and uses a distinct key+-- for renaming the variables in this scope. In a declaration group,+-- first the left hand sides of all declarations are checked, next the+-- compiler checks that there is a definition for every type signature+-- and evaluation annotation in this group. Finally, the right hand sides+-- are checked and adjacent equations for the same function are merged+-- into a single definition.++-- The function 'checkDeclLhs' also handles the case where a pattern+-- declaration is recognized as a function declaration by the parser.+-- This happens, e.g., for the declaration+--      where Just x = y+-- because the parser cannot distinguish nullary constructors and functions.+-- Note that pattern declarations are not allowed on the top-level.++checkDeclGroup :: (Decl () -> RenameEnv -> RenameEnv) -> [Decl ()] -> SCM [Decl ()]+checkDeclGroup bindDecl ds = do+  checkedLhs <- mapM checkDeclLhs $ sortFuncDecls ds+  joinEquations checkedLhs >>= checkDecls bindDecl++checkDeclLhs :: Decl () -> SCM (Decl ())+checkDeclLhs (InfixDecl    p fix' pr ops) =+  InfixDecl p fix' <$> checkPrecedence p pr <*> mapM renameVar ops+checkDeclLhs (TypeSig            p vs ty) =+  (\vs' -> TypeSig p vs' ty) <$> mapM (checkVar "type signature") vs+checkDeclLhs (FunctionDecl     p _ f eqs) =+  inFunc f $ checkEquationsLhs p eqs+checkDeclLhs (ExternalDecl          p vs) =+  ExternalDecl p <$> mapM (checkVar' "external declaration") vs+checkDeclLhs (PatternDecl        p t rhs) =+  (\t' -> PatternDecl p t' rhs) <$> checkPattern p t+checkDeclLhs (FreeDecl              p vs) =+  FreeDecl p <$> mapM (checkVar' "free variables declaration") vs+checkDeclLhs d                            = return d++checkPrecedence :: Position -> Maybe Precedence -> SCM (Maybe Precedence)+checkPrecedence _ Nothing  = return Nothing+checkPrecedence p (Just i) = do+  unless (0 <= i && i <= 9) $ report $ errPrecedenceOutOfRange p i+  return $ Just i++checkVar' :: String -> Var a -> SCM (Var a)+checkVar' what (Var a v) = Var a <$> checkVar what v++checkVar :: String -> Ident -> SCM Ident+checkVar _what v = do+  -- isDC <- S.gets (isDataConstr v . renameEnv)+  -- when isDC $ report $ nonVariable what v -- TODO Why is this disabled?+  renameVar v++renameVar :: Ident -> SCM Ident+renameVar v = renameIdent v <$> getScopeId++checkEquationsLhs :: Position -> [Equation ()] -> SCM (Decl ())+checkEquationsLhs p [Equation p' lhs rhs] = do+  lhs' <- checkEqLhs p' lhs+  case lhs' of+    Left  l -> return $ funDecl' l+    Right r -> patDecl' r >>= checkDeclLhs+  where funDecl' (f, lhs') = FunctionDecl p () f [Equation p' lhs' rhs]+        patDecl' t = do+          k <- getScopeId+          when (k == globalScopeId) $ report $ errToplevelPattern p+          return $ PatternDecl p' t rhs+checkEquationsLhs _ _ = internalError "SyntaxCheck.checkEquationsLhs"++checkEqLhs :: Position -> Lhs () -> SCM (Either (Ident, Lhs ()) (Pattern ()))+checkEqLhs p toplhs = do+  m   <- getModuleIdent+  k   <- getScopeId+  env <- getRenameEnv+  case toplhs of+    FunLhs f ts+      | not $ isDataConstr f env -> return left+      | k /= globalScopeId       -> return right+      | null infos               -> return left+      | otherwise                -> do report $ errToplevelPattern p+                                       return right+      where f'    = renameIdent f k+            infos = qualLookupVar (qualifyWith m f) env+            left  = Left  (f', FunLhs f' ts)+            right = Right $ ConstructorPattern () (qualify f) ts+    OpLhs t1 op t2+      | not $ isDataConstr op env -> return left+      | k /= globalScopeId        -> return right+      | null infos                -> return left+      | otherwise                 -> do report $ errToplevelPattern p+                                        return right+      where op'   = renameIdent op k+            infos = qualLookupVar (qualifyWith m op) env+            left  = Left (op', OpLhs t1 op' t2)+            right = checkOpLhs k env (infixPattern t1 (qualify op)) t2+            infixPattern (InfixPattern a' t1' op1 t2') op2 t3 =+              InfixPattern a' t1' op1 (infixPattern t2' op2 t3)+            infixPattern t1' op1 t2' = InfixPattern () t1' op1 t2'+    ApLhs lhs ts -> do+      checked <- checkEqLhs p lhs+      case checked of+        Left (f', lhs') -> return $ Left (f', ApLhs lhs' ts)+        r               -> do report $ errNonVariable "curried definition" f+                              return $ r+        where (f, _) = flatLhs lhs++checkOpLhs :: Integer -> RenameEnv -> (Pattern a -> Pattern a)+           -> Pattern a -> Either (Ident, Lhs a) (Pattern a)+checkOpLhs k env f (InfixPattern a t1 op t2)+  | isJust m || isDataConstr op' env+  = checkOpLhs k env (f . InfixPattern a t1 op) t2+  | otherwise+  = Left (op'', OpLhs (f t1) op'' t2)+  where (m,op') = (qidModule op, qidIdent op)+        op''    = renameIdent op' k+checkOpLhs _ _ f t = Right (f t)++-- -- ---------------------------------------------------------------------------++joinEquations :: [Decl a] -> SCM [Decl a]+joinEquations [] = return []+joinEquations (FunctionDecl a p f eqs : FunctionDecl _ _ f' [eq] : ds)+  | f == f' = do+    when (getArity (head eqs) /= getArity eq) $ report $ errDifferentArity [f, f']+    joinEquations (FunctionDecl a p f (eqs ++ [eq]) : ds)+  where getArity = length . snd . getFlatLhs+joinEquations (d : ds) = (d :) <$> joinEquations ds++checkDecls :: (Decl () -> RenameEnv -> RenameEnv) -> [Decl ()] -> SCM [Decl ()]+checkDecls bindDecl ds = do+  let dblVar = findDouble bvs+  onJust (report . errDuplicateDefinition) dblVar+  let mulTys = findMultiples tys+  mapM_ (report . errDuplicateTypeSig) mulTys+  let missingTys = [v | ExternalDecl _ vs <- ds, Var _ v <- vs, v `notElem` tys]+  mapM_ (report . errNoTypeSig) missingTys+  if isNothing dblVar && null mulTys && null missingTys+    then do+      modifyRenameEnv $ \env -> foldr bindDecl env (tds ++ vds)+      mapM (checkDeclRhs bvs) ds+    else return ds -- skip further checking+  where vds    = filter isValueDecl ds+        tds    = filter isTypeSig ds+        bvs    = concatMap vars vds+        tys    = concatMap vars tds+        onJust = maybe ok++-- -- ---------------------------------------------------------------------------++checkDeclRhs :: [Ident] -> Decl () -> SCM (Decl ())+checkDeclRhs _   (DataDecl   p tc tvs cs clss) =+  flip (DataDecl p tc tvs) clss <$> mapM checkDeclLabels cs+checkDeclRhs bvs (TypeSig        p vs ty) =+  (\vs' -> TypeSig p vs' ty) <$> mapM (checkLocalVar bvs) vs+checkDeclRhs _   (FunctionDecl a p f eqs) =+  FunctionDecl a p f <$> inFunc f (mapM checkEquation eqs)+checkDeclRhs _   (PatternDecl    p t rhs) =+  PatternDecl p t <$> checkRhs rhs+checkDeclRhs _   d                        = return d++checkDeclLabels :: ConstrDecl -> SCM ConstrDecl+checkDeclLabels rd@(RecordDecl _ _ _ _ fs) = do+  onJust (report . errDuplicateLabel "declaration")+         (findDouble $ map qualify labels)+  return rd+  where+    onJust = maybe ok+    labels = [l | FieldDecl _ ls _ <- fs, l <- ls]+checkDeclLabels d = return d++checkLocalVar :: [Ident] -> Ident -> SCM Ident+checkLocalVar bvs v = do+  tcc <- isTypeClassesCheck+  when (v `notElem` bvs && not tcc) $ report $ errNoBody v+  return v++checkEquation :: Equation () -> SCM (Equation ())+checkEquation (Equation p lhs rhs) = inNestedScope $ do+  lhs' <- checkLhs p lhs >>= addBoundVariables False+  rhs' <- checkRhs rhs+  return $ Equation p lhs' rhs'++checkLhs :: Position -> Lhs () -> SCM (Lhs ())+checkLhs p (FunLhs    f ts) = FunLhs f <$> mapM (checkPattern p) ts+checkLhs p (OpLhs t1 op t2) = do+  let wrongCalls = concatMap (checkParenPattern (Just $ qualify op)) [t1,t2]+  unless (null wrongCalls) $ report $ errInfixWithoutParens+    (idPosition op) wrongCalls+  flip OpLhs op <$> checkPattern p t1 <*> checkPattern p t2+checkLhs p (ApLhs   lhs ts) =+  ApLhs <$> checkLhs p lhs <*> mapM (checkPattern p) ts++-- checkParen+-- @param Aufrufende InfixFunktion+-- @param Pattern+-- @return Liste mit fehlerhaften Funktionsaufrufen++checkParenPattern :: (Maybe QualIdent) -> Pattern a -> [(QualIdent, QualIdent)]+checkParenPattern _ (LiteralPattern          _ _) = []+checkParenPattern _ (NegativePattern         _ _) = []+checkParenPattern _ (VariablePattern         _ _) = []+checkParenPattern _ (ConstructorPattern   _ _ cs) =+  concatMap (checkParenPattern Nothing) cs+checkParenPattern o (InfixPattern     _ t1 op t2) =+  maybe [] (\c -> [(c, op)]) o+  ++ checkParenPattern Nothing t1 ++ checkParenPattern Nothing t2+checkParenPattern _ (ParenPattern              t) =+  checkParenPattern Nothing t+checkParenPattern _ (RecordPattern        _ _ fs) =+  concatMap (\(Field _ _ t) -> checkParenPattern Nothing t) fs+checkParenPattern _ (TuplePattern             ts) =+  concatMap (checkParenPattern Nothing) ts+checkParenPattern _ (ListPattern            _ ts) =+  concatMap (checkParenPattern Nothing) ts+checkParenPattern o (AsPattern               _ t) =+  checkParenPattern o t+checkParenPattern o (LazyPattern               t) =+  checkParenPattern o t+checkParenPattern _ (FunctionPattern      _ _ ts) =+  concatMap (checkParenPattern Nothing) ts+checkParenPattern o (InfixFuncPattern _ t1 op t2) =+  maybe [] (\c -> [(c, op)]) o+  ++ checkParenPattern Nothing t1 ++ checkParenPattern Nothing t2++checkPattern :: Position -> Pattern () -> SCM (Pattern ())+checkPattern _ (LiteralPattern        a l) =+  return $ LiteralPattern a l+checkPattern _ (NegativePattern       a l) =+  return $ NegativePattern a l+checkPattern p (VariablePattern       a v)+  | isAnonId v = (VariablePattern a . renameIdent v) <$> newId+  | otherwise  = checkConstructorPattern p (qualify v) []+checkPattern p (ConstructorPattern _ c ts) =+  checkConstructorPattern p c ts+checkPattern p (InfixPattern   _ t1 op t2) =+  checkInfixPattern p t1 op t2+checkPattern p (ParenPattern            t) =+  ParenPattern <$> checkPattern p t+checkPattern p (RecordPattern      _ c fs) =+  checkRecordPattern p c fs+checkPattern p (TuplePattern           ts) =+  TuplePattern <$> mapM (checkPattern p) ts+checkPattern p (ListPattern          a ts) =+  ListPattern a <$> mapM (checkPattern p) ts+checkPattern p (AsPattern             v t) = do+  AsPattern <$> checkVar "@ pattern" v <*> checkPattern p t+checkPattern p (LazyPattern             t) = do+  t' <- checkPattern p t+  banFPTerm "lazy pattern" p t'+  return (LazyPattern t')+checkPattern _ (FunctionPattern     _ _ _) = internalError $+  "SyntaxCheck.checkPattern: function pattern not defined"+checkPattern _ (InfixFuncPattern  _ _ _ _) = internalError $+  "SyntaxCheck.checkPattern: infix function pattern not defined"++checkConstructorPattern :: Position -> QualIdent -> [Pattern ()]+                        -> SCM (Pattern ())+checkConstructorPattern p c ts = do+  env <- getRenameEnv+  m <- getModuleIdent+  k <- getScopeId+  case qualLookupVar c env of+    [Constr _ n] -> processCons c n+    [r]          -> processVarFun r k+    rs -> case qualLookupVar (qualQualify m c) env of+      [Constr _ n] -> processCons (qualQualify m c) n+      [r]          -> processVarFun r k+      []+        | null ts && not (isQualified c) ->+            return $ VariablePattern () $ renameIdent (unqualify c) k+        | null rs -> do+            ts' <- mapM (checkPattern p) ts+            report $ errUndefinedData c+            return $ ConstructorPattern () c ts'+      _ -> do ts' <- mapM (checkPattern p) ts+              report $ errAmbiguousData rs c+              return $ ConstructorPattern () c ts'+  where+  n' = length ts+  processCons qc n = do+    when (n /= n') $ report $ errWrongArity c n n'+    ConstructorPattern () qc <$> mapM (checkPattern p) ts+  processVarFun r k+    | null ts && not (isQualified c)+    = return $ VariablePattern () $ renameIdent (unqualify c) k -- (varIdent r) k+    | otherwise = do+      let n = arity r+      checkFuncPatsExtension p+      checkFuncPatCall r c+      ts' <- mapM (checkPattern p) ts+      mapM_ (checkFPTerm p) ts'+      return $ if n' > n+                 then let (ts1, ts2) = splitAt n ts'+                      in  genFuncPattAppl+                          (FunctionPattern () (qualVarIdent r) ts1) ts2+                 else FunctionPattern () (qualVarIdent r) ts'++checkInfixPattern :: Position -> Pattern () -> QualIdent -> Pattern ()+                  -> SCM (Pattern ())+checkInfixPattern p t1 op t2 = do+  m <- getModuleIdent+  env <- getRenameEnv+  case qualLookupVar op env of+    [Constr _ n] -> infixPattern op n+    [r]          -> funcPattern r op+    rs           -> case qualLookupVar (qualQualify m op) env of+      [Constr _ n] -> infixPattern (qualQualify m op) n+      [r]          -> funcPattern r (qualQualify m op)+      rs'          -> do if (null rs && null rs')+                            then report $ errUndefinedData op+                            else report $ errAmbiguousData rs op+                         flip (InfixPattern ()) op <$> checkPattern p t1+                                                  <*> checkPattern p t2+  where+  infixPattern qop n = do+    when (n /= 2) $ report $ errWrongArity op n 2+    flip (InfixPattern ()) qop <$> checkPattern p t1 <*> checkPattern p t2+  funcPattern r qop = do+    checkFuncPatsExtension p+    checkFuncPatCall r qop+    ts'@[t1',t2'] <- mapM (checkPattern p) [t1,t2]+    mapM_ (checkFPTerm p) ts'+    return $ InfixFuncPattern () t1' qop t2'++checkRecordPattern :: Position -> QualIdent -> [Field (Pattern ())]+                   -> SCM (Pattern ())+checkRecordPattern p c fs = do+  env <- getRenameEnv+  m   <- getModuleIdent+  case qualLookupVar c env of+    [Constr c' _] -> processRecPat (Just c') fs+    rs            -> case qualLookupVar (qualQualify m c) env of+      [Constr c' _] -> processRecPat (Just c') fs+      rs'           -> if (null rs && null rs')+                          then do report $ errUndefinedData c+                                  processRecPat Nothing fs+                          else do report $ errAmbiguousData rs c+                                  processRecPat Nothing fs+  where+  processRecPat mcon fields = do+    fs' <- mapM (checkField (checkPattern p)) fields+    checkFieldLabels "pattern" p mcon fs'+    return $ RecordPattern () c fs'++checkFuncPatCall :: RenameInfo -> QualIdent -> SCM ()+checkFuncPatCall r f = case r of+  GlobalVar dep _ -> do+    addGlobalDep dep+    addFuncPat (dep @> f)+  _           -> report $ errFuncPatNotGlobal f++-- Note: process decls first+checkRhs :: Rhs () -> SCM (Rhs ())+checkRhs (SimpleRhs p e ds) = inNestedScope $+  flip (SimpleRhs p) <$> checkDeclGroup bindVarDecl ds <*> checkExpr p e+checkRhs (GuardedRhs es ds) = inNestedScope $+  flip GuardedRhs <$> checkDeclGroup bindVarDecl ds <*> mapM checkCondExpr es++checkCondExpr :: CondExpr () -> SCM (CondExpr ())+checkCondExpr (CondExpr p g e) =  CondExpr p <$> checkExpr p g <*> checkExpr p e++checkExpr :: Position -> Expression () -> SCM (Expression ())+checkExpr _ (Literal       a l) = return $ Literal a l+checkExpr _ (Variable      a v) = checkVariable a v+checkExpr _ (Constructor   a c) = checkVariable a c+checkExpr p (Paren           e) = Paren         <$> checkExpr p e+checkExpr p (Typed        e ty) = flip Typed ty <$> checkExpr p e+checkExpr p (Record     _ c fs) = checkRecordExpr p c fs+checkExpr p (RecordUpdate e fs) = checkRecordUpdExpr p e fs+checkExpr p (Tuple          es) = Tuple <$> mapM (checkExpr p) es+checkExpr p (List         a es) = List a <$> mapM (checkExpr p) es+checkExpr p (ListCompr    e qs) = withLocalEnv $ flip ListCompr <$>+  -- Note: must be flipped to insert qs into RenameEnv first+  mapM (checkStatement "list comprehension" p) qs <*> checkExpr p e+checkExpr p (EnumFrom              e) = EnumFrom <$> checkExpr p e+checkExpr p (EnumFromThen      e1 e2) =+  EnumFromThen <$> checkExpr p e1 <*> checkExpr p e2+checkExpr p (EnumFromTo        e1 e2) =+  EnumFromTo <$> checkExpr p e1 <*> checkExpr p e2+checkExpr p (EnumFromThenTo e1 e2 e3) =+  EnumFromThenTo <$> checkExpr p e1 <*> checkExpr p e2 <*> checkExpr p e3+checkExpr p (UnaryMinus            e) = UnaryMinus <$> checkExpr p e+checkExpr p (Apply             e1 e2) =+  Apply <$> checkExpr p e1 <*> checkExpr p e2+checkExpr p (InfixApply     e1 op e2) =+  InfixApply <$> checkExpr p e1 <*> checkOp op <*> checkExpr p e2+checkExpr p (LeftSection        e op) =+  LeftSection <$> checkExpr p e <*> checkOp op+checkExpr p (RightSection       op e) =+  RightSection <$> checkOp op <*> checkExpr p e+checkExpr p (Lambda             ts e) = inNestedScope $ checkLambda p ts e+checkExpr p (Let                ds e) = inNestedScope $+  Let <$> checkDeclGroup bindVarDecl ds <*> checkExpr p e+checkExpr p (Do                sts e) = withLocalEnv $+  Do <$> mapM (checkStatement "do sequence" p) sts <*> checkExpr p e+checkExpr p (IfThenElse     e1 e2 e3) =+  IfThenElse <$> checkExpr p e1 <*> checkExpr p e2 <*> checkExpr p e3+checkExpr p (Case          ct e alts) =+  Case ct <$> checkExpr p e <*> mapM checkAlt alts++checkLambda :: Position -> [Pattern ()] -> Expression () -> SCM (Expression ())+checkLambda p ts e = case findMultiples (bvNoAnon ts) of+  []      -> do+    ts' <- mapM (bindPattern "lambda expression" p) ts+    Lambda ts' <$> checkExpr p e+  errVars -> do+    mapM_ (report . errDuplicateVariables) errVars+    let nubTs = nubBy (\t1 t2 -> (not . null) (on intersect bvNoAnon t1 t2)) ts+    mapM_ (bindPattern "lambda expression" p) nubTs+    Lambda ts <$> checkExpr p e+  where+    bvNoAnon t = filter (not . isAnonId) $ bv t++checkVariable :: a -> QualIdent -> SCM (Expression a)+checkVariable a v+    -- anonymous free variable+  | isAnonId (unqualify v) = do+    checkAnonFreeVarsExtension $ qidPosition v+    (\n -> Variable a $ updQualIdent id (flip renameIdent n) v) <$> newId+    -- return $ Variable v+    -- normal variable+  | otherwise             = do+    env <- getRenameEnv+    case qualLookupVar v env of+      []              -> do report $ errUndefinedVariable v+                            return $ Variable a v+      [Constr    _ _]   -> return $ Constructor a v+      [GlobalVar f _]   -> addGlobalDep f >> return (Variable a v)+      [LocalVar v' _]   -> return $ Variable a $ qualify v' @> v+      [RecordLabel _ _] -> return $ Variable a v+      rs -> do+        m <- getModuleIdent+        case qualLookupVar (qualQualify m v) env of+          []              -> do report $ errAmbiguousIdent rs v+                                return $ Variable a v+          [Constr    _ _]   -> return $ Constructor a v+          [GlobalVar f _]   -> addGlobalDep f >> return (Variable a v)+          [LocalVar v' _]   -> return $ Variable a $ qualify v' @> v+          [RecordLabel _ _] -> return $ Variable a v+          rs'               -> do report $ errAmbiguousIdent rs' v+                                  return $ Variable a v++checkRecordExpr :: Position -> QualIdent -> [Field (Expression ())]+                -> SCM (Expression ())+checkRecordExpr _ c [] = do+  m   <- getModuleIdent+  env <- getRenameEnv+  case qualLookupVar c env of+    [Constr _ _] -> return $ Record () c []+    rs           -> case qualLookupVar (qualQualify m c) env of+      [Constr _ _] -> return $ Record () c []+      rs'          -> if (null rs && null rs')+                         then do report $ errUndefinedData c+                                 return $ Record () c []+                         else do report $ errAmbiguousData rs c+                                 return $ Record () c []+checkRecordExpr p c fs = checkExpr p (RecordUpdate (Constructor () c) fs)++checkRecordUpdExpr :: Position -> Expression () -> [Field (Expression ())]+                   -> SCM (Expression ())+checkRecordUpdExpr p e fs = do+  e'  <- checkExpr p e+  fs' <- mapM (checkField (checkExpr p)) fs+  case e' of+    Constructor a c -> do checkFieldLabels "construction" p (Just c) fs'+                          return $ Record a c fs'+    _               -> do checkFieldLabels "update" p Nothing fs'+                          return $ RecordUpdate e' fs'++-- * Because patterns or decls eventually introduce new variables, the+--   scope has to be nested one level.+-- * Because statements are processed list-wise, inNestedEnv can not be+--   used as this nesting must be visible to following statements.+checkStatement :: String -> Position -> Statement () -> SCM (Statement ())+checkStatement _ p (StmtExpr   e) = StmtExpr <$> checkExpr p e+checkStatement s p (StmtBind t e) =+  flip StmtBind <$> checkExpr p e <*> (incNesting >> bindPattern s p t)+checkStatement _ _ (StmtDecl  ds) =+  StmtDecl <$> (incNesting >> checkDeclGroup bindVarDecl ds)++bindPattern :: String -> Position -> Pattern () -> SCM (Pattern ())+bindPattern s p t = do+  t' <- checkPattern p t+  banFPTerm s p t'+  addBoundVariables True t'++banFPTerm :: String -> Position -> Pattern a -> SCM ()+banFPTerm _ _ (LiteralPattern           _ _) = ok+banFPTerm _ _ (NegativePattern          _ _) = ok+banFPTerm _ _ (VariablePattern          _ _) = ok+banFPTerm s p (ConstructorPattern    _ _ ts) = mapM_ (banFPTerm s p) ts+banFPTerm s p (InfixPattern       _ t1 _ t2) = mapM_ (banFPTerm s p) [t1, t2]+banFPTerm s p (ParenPattern               t) = banFPTerm s p t+banFPTerm s p (RecordPattern         _ _ fs) = mapM_ banFPTermField fs+  where banFPTermField (Field _ _ x) = banFPTerm s p x+banFPTerm s p (TuplePattern              ts) = mapM_ (banFPTerm s p) ts+banFPTerm s p (ListPattern             _ ts) = mapM_ (banFPTerm s p) ts+banFPTerm s p (AsPattern                _ t) = banFPTerm s p t+banFPTerm s p (LazyPattern                t) = banFPTerm s p t+banFPTerm s p pat@(FunctionPattern    _ _ _)+ = report $ errUnsupportedFuncPattern s p pat+banFPTerm s p pat@(InfixFuncPattern _ _ _ _)+ = report $ errUnsupportedFuncPattern s p pat++checkOp :: InfixOp a -> SCM (InfixOp a)+checkOp op = do+  env <- getRenameEnv+  case qualLookupVar v env of+    []              -> report (errUndefinedVariable v) >> return op+    [Constr _ _]    -> return $ InfixConstr a v+    [GlobalVar f _] -> addGlobalDep f >> return (InfixOp a v)+    [LocalVar v' _] -> return $ InfixOp a $ qualify v'+    rs              -> do+      m <- getModuleIdent+      case qualLookupVar (qualQualify m v) env of+        []              -> report (errAmbiguousIdent rs v) >> return op+        [Constr _ _]    -> return $ InfixConstr a v+        [GlobalVar f _] -> addGlobalDep f >> return (InfixOp a v)+        [LocalVar v' _] -> return $ InfixOp a $ qualify v'+        rs'             -> report (errAmbiguousIdent rs' v) >> return op+  where v = opName op+        a = opAnnotation op++checkAlt :: Alt () -> SCM (Alt ())+checkAlt (Alt p t rhs) = inNestedScope $+  Alt p <$> bindPattern "case expression" p t <*> checkRhs rhs++addBoundVariables :: (QuantExpr t) => Bool -> t -> SCM t+addBoundVariables checkDuplicates ts = do+  when checkDuplicates $ mapM_ (report . errDuplicateVariables)+                               (findMultiples bvs)+  modifyRenameEnv $ \ env -> foldr bindVar env (nub bvs)+  return ts+  where bvs = bv ts++-- For record patterns and expressions the compiler checks that all field+-- labels belong to the pattern or expression's constructor. For record+-- update expressions, the compiler checks that there is at least one+-- constructor which has all the specified field labels. In addition, the+-- compiler always checks that no field label occurs twice. Field labels+-- are always looked up in the global environment since they cannot be+-- shadowed by local variables (cf.\ Sect.~3.15.1 of the revised+-- Haskell'98 report~\cite{PeytonJones03:Haskell}).++checkFieldLabels :: String -> Position -> Maybe QualIdent -> [Field a] -> SCM ()+checkFieldLabels what p c fs = do+  mapM checkFieldLabel ls' >>= checkLabels p c ls'+  onJust (report . errDuplicateLabel what) (findDouble ls)+  where ls  = [l | Field _ l _ <- fs]+        ls' = nub ls+        onJust = maybe ok++checkFieldLabel :: QualIdent -> SCM [QualIdent]+checkFieldLabel l = do+  m   <- getModuleIdent+  env <- getRenameEnv+  case qualLookupVar l env of+    [RecordLabel _ cs] -> processLabel cs+    rs                 -> case qualLookupVar (qualQualify m l) env of+      [RecordLabel _ cs] -> processLabel cs+      rs'                -> if (null rs && null rs')+                               then do report $ errUndefinedLabel l+                                       return []+                               else do report $+                                         errAmbiguousIdent rs (qualQualify m l)+                                       return []+  where+  processLabel cs' = do+    when (null cs') $ report $ errUndefinedLabel l+    return cs'++checkLabels :: Position -> Maybe QualIdent -> [QualIdent] -> [[QualIdent]]+            -> SCM ()+checkLabels _ (Just c) ls css = do+  env <- getRenameEnv+  case qualLookupVar c env of+    [Constr c' _] -> mapM_ (report . errNoLabel c)+                           [l | (l, cs) <- zip ls css, c' `notElem` cs]+    _             -> internalError $+                       "Checks.SyntaxCheck.checkLabels: " ++ show c+checkLabels p Nothing ls css =+  when (null (foldr1 intersect css)) $ report $ errNoCommonCons p ls++checkField :: (a -> SCM a) -> Field a -> SCM (Field a)+checkField check (Field p l x) = Field p l <$> check x++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++constrs :: Decl a -> [Ident]+constrs (DataDecl    _ _ _ cs _) = map constrId cs+constrs (NewtypeDecl _ _ _ nc _) = [nconstrId nc]+constrs _                        = []++vars :: Decl a -> [Ident]+vars (TypeSig          _ fs _) = fs+vars (FunctionDecl    _ _ f _) = [f]+vars (ExternalDecl       _ vs) = bv vs+vars (PatternDecl       _ t _) = bv t+vars (FreeDecl           _ vs) = bv vs+vars _                         = []++recLabels :: Decl a -> [Ident]+recLabels (DataDecl    _ _ _ cs _) = concatMap recordLabels cs+recLabels (NewtypeDecl _ _ _ nc _) = nrecordLabels nc+recLabels _                        = []++-- Since the compiler expects all rules of the same function to be together,+-- it is necessary to sort the list of declarations.++sortFuncDecls :: [Decl a] -> [Decl a]+sortFuncDecls decls = sortFD Set.empty [] decls+ where+ sortFD _   res []              = reverse res+ sortFD env res (decl : decls') = case decl of+   FunctionDecl _ _ ident _+    | ident `Set.member` env+    -> sortFD env (insertBy cmpFuncDecl decl res) decls'+    | otherwise+    -> sortFD (Set.insert ident env) (decl:res) decls'+   _    -> sortFD env (decl:res) decls'++cmpFuncDecl :: Decl a -> Decl a -> Ordering+cmpFuncDecl (FunctionDecl _ _ id1 _) (FunctionDecl _ _ id2 _)+   | id1 == id2 = EQ+   | otherwise  = GT+cmpFuncDecl _ _ = GT++-- Due to the lack of a capitalization convention in Curry, it is+-- possible that an identifier may ambiguously refer to a data+-- constructor and a function provided that both are imported from some+-- other module. When checking whether an identifier denotes a+-- constructor there are two options with regard to ambiguous+-- identifiers:+--   * Handle the identifier as a data constructor if at least one of+--     the imported names is a data constructor.+--   * Handle the identifier as a data constructor only if all imported+--     entities are data constructors.+-- We choose the first possibility here because in the second case a+-- redefinition of a constructor can magically become possible if a+-- function with the same name is imported. It seems better to warn+-- the user about the fact that the identifier is ambiguous.++isDataConstr :: Ident -> RenameEnv -> Bool+isDataConstr v = any isConstr . lookupVar v . globalEnv . toplevelEnv++isConstr :: RenameInfo -> Bool+isConstr (Constr      _ _) = True+isConstr (GlobalVar   _ _) = False+isConstr (LocalVar    _ _) = False+isConstr (RecordLabel _ _) = False++isLabel :: RenameInfo -> Bool+isLabel (Constr      _ _) = False+isLabel (GlobalVar   _ _) = False+isLabel (LocalVar    _ _) = False+isLabel (RecordLabel _ _) = True++-- varIdent :: RenameInfo -> Ident+-- varIdent (GlobalVar _ v) = unqualify v+-- varIdent (LocalVar  _ v) = v+-- varIdent _ = internalError "SyntaxCheck.varIdent: no variable"++qualVarIdent :: RenameInfo -> QualIdent+qualVarIdent (GlobalVar v _) = v+qualVarIdent (LocalVar  v _) = qualify v+qualVarIdent _ = internalError "SyntaxCheck.qualVarIdent: no variable"++arity :: RenameInfo -> Int+arity (Constr      _ n) = n+arity (GlobalVar   _ n) = n+arity (LocalVar    _ n) = n+arity (RecordLabel _ _) = 1++-- Unlike expressions, constructor terms have no possibility to represent+-- over-applications in functional patterns. Therefore it is necessary to+-- transform them to nested function patterns using the prelude function+-- apply. E.g., the function pattern (id id 10) is transformed to+-- (apply (id id) 10).++genFuncPattAppl :: Pattern () -> [Pattern ()] -> Pattern ()+genFuncPattAppl term []     = term+genFuncPattAppl term (t:ts)+   = FunctionPattern () qApplyId [genFuncPattAppl term ts, t]++checkFPTerm :: Position -> Pattern a -> SCM ()+checkFPTerm _ (LiteralPattern        _ _) = ok+checkFPTerm _ (NegativePattern       _ _) = ok+checkFPTerm _ (VariablePattern       _ _) = ok+checkFPTerm p (ConstructorPattern _ _ ts) = mapM_ (checkFPTerm p) ts+checkFPTerm p (InfixPattern    _ t1 _ t2) = mapM_ (checkFPTerm p) [t1, t2]+checkFPTerm p (ParenPattern            t) = checkFPTerm p t+checkFPTerm p (TuplePattern           ts) = mapM_ (checkFPTerm p) ts+checkFPTerm p (ListPattern          _ ts) = mapM_ (checkFPTerm p) ts+checkFPTerm p (AsPattern             _ t) = checkFPTerm p t+checkFPTerm p t@(LazyPattern           _) = report $ errUnsupportedFPTerm "Lazy" p t+checkFPTerm p (RecordPattern      _ _ fs) = mapM_ (checkFPTerm p)+                                            [ t | Field _ _ t <- fs ]+checkFPTerm _ (FunctionPattern     _ _ _) = ok -- do not check again+checkFPTerm _ (InfixFuncPattern  _ _ _ _) = ok -- do not check again++-- ---------------------------------------------------------------------------+-- Miscellaneous functions+-- ---------------------------------------------------------------------------++checkFuncPatsExtension :: Position -> SCM ()+checkFuncPatsExtension p = checkUsedExtension p+  "Functional Patterns" FunctionalPatterns++checkAnonFreeVarsExtension :: Position -> SCM ()+checkAnonFreeVarsExtension p = checkUsedExtension p+  "Anonymous free variables" AnonFreeVars++checkUsedExtension :: Position -> String -> KnownExtension -> SCM ()+checkUsedExtension pos msg ext = do+  enabled <- hasExtension ext+  unless enabled $ do+    report $ errMissingLanguageExtension pos msg ext+    enableExtension ext -- to avoid multiple warnings++typeArity :: TypeExpr -> Int+typeArity (ArrowType _ t2) = 1 + typeArity t2+typeArity _                = 0++getFlatLhs :: Equation a -> (Ident, [Pattern a])+getFlatLhs (Equation  _ lhs _) = flatLhs lhs++opAnnotation :: InfixOp a -> a+opAnnotation (InfixOp     a _) = a+opAnnotation (InfixConstr a _) = a++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errUnsupportedFPTerm :: String -> Position -> Pattern a -> Message+errUnsupportedFPTerm s p pat = posMessage p $ text s+  <+> text "patterns are not supported inside a functional pattern."+  $+$ ppPattern 0 pat++errUnsupportedFuncPattern :: String -> Position -> Pattern a -> Message+errUnsupportedFuncPattern s p pat = posMessage p $+  text "Functional patterns are not supported inside a" <+> text s <> dot+  $+$ ppPattern 0 pat++errFuncPatNotGlobal :: QualIdent -> Message+errFuncPatNotGlobal f = posMessage f $ hsep $ map text+  ["Function", escQualName f, "in functional pattern is not global"]++errFuncPatCyclic :: QualIdent -> QualIdent -> Message+errFuncPatCyclic fp f = posMessage fp $ hsep $ map text+  [ "Function", escName $ unqualify fp, "used in functional pattern depends on"+  , escName $ unqualify f, " causing a cyclic dependency"]++errPrecedenceOutOfRange :: Position -> Integer -> Message+errPrecedenceOutOfRange p i = posMessage p $ hsep $ map text+  ["Precedence out of range:", show i]++errUndefinedVariable :: QualIdent -> Message+errUndefinedVariable v = posMessage v $ hsep $ map text+  [escQualName v, "is undefined"]++errUndefinedData :: QualIdent -> Message+errUndefinedData c = posMessage c $ hsep $ map text+  ["Undefined data constructor", escQualName c]++errUndefinedLabel :: QualIdent -> Message+errUndefinedLabel l = posMessage l $  hsep $ map text+  ["Undefined record label", escQualName l]++errUndefinedMethod :: QualIdent -> Ident -> Message+errUndefinedMethod qcls f = posMessage f $ hsep $ map text+  [escName f, "is not a (visible) method of class", escQualName qcls]++errAmbiguousIdent :: [RenameInfo] -> QualIdent -> Message+errAmbiguousIdent rs qn | any isConstr rs = errAmbiguousData rs qn+                        | any isLabel  rs = errAmbiguousLabel rs qn+                        | otherwise       = errAmbiguous "variable" rs qn++errAmbiguousData :: [RenameInfo] -> QualIdent -> Message+errAmbiguousData = errAmbiguous "data constructor"++errAmbiguousLabel :: [RenameInfo] -> QualIdent -> Message+errAmbiguousLabel = errAmbiguous "field label"++errAmbiguous :: String -> [RenameInfo] -> QualIdent -> Message+errAmbiguous what rs qn = posMessage qn+  $   text "Ambiguous" <+> text what <+> text (escQualName qn)+  $+$ text "It could refer to:"+  $+$ nest 2 (vcat (map ppRenameInfo rs))++errDuplicateDefinition :: Ident -> Message+errDuplicateDefinition v = posMessage v $ hsep $ map text+  ["More than one definition for", escName v]++errDuplicateVariables :: [Ident] -> Message+errDuplicateVariables [] = internalError+  "SyntaxCheck.errDuplicateVariables: empty list"+errDuplicateVariables (v:vs) = posMessage v $+  text (escName v) <+> text "occurs more than one in pattern at:" $+$+  nest 2 (vcat (map (ppPosition . getPosition) (v:vs)))++errMultipleDataConstructor :: [Ident] -> Message+errMultipleDataConstructor [] = internalError+  "SyntaxCheck.errMultipleDataDeclaration: empty list"+errMultipleDataConstructor (i:is) = posMessage i $+  text "Multiple definitions for data/record constructor" <+> text (escName i)+  <+> text "at:" $+$+  nest 2 (vcat (map (ppPosition . getPosition) (i:is)))++errMultipleDeclarations :: ModuleIdent -> [Ident] -> Message+errMultipleDeclarations _ [] = internalError+  "SyntaxCheck.errMultipleDeclarations: empty list"+errMultipleDeclarations m (i:is) = posMessage i $+  text "Multiple declarations of" <+> text (escQualName (qualifyWith m i))+  $+$ text "Declared at:" $+$+  nest 2 (vcat (map (ppPosition . getPosition) (i:is)))++errDuplicateTypeSig :: [Ident] -> Message+errDuplicateTypeSig [] = internalError+  "SyntaxCheck.errDuplicateTypeSig: empty list"+errDuplicateTypeSig (v:vs) = posMessage v $+  text "More than one type signature for" <+> text (escName v)+  <+> text "at:" $+$+  nest 2 (vcat (map (ppPosition . getPosition) (v:vs)))++errDuplicateLabel :: String -> QualIdent -> Message+errDuplicateLabel what l = posMessage l $ hsep $ map text+  ["Field label", escQualName l, "occurs more than once in record", what]++errNonVariable :: String -> Ident -> Message+errNonVariable what c = posMessage c $ hsep $ map text+  ["Data constructor", escName c, "in left hand side of", what]++errNoBody :: Ident -> Message+errNoBody v = posMessage v $  hsep $ map text ["No body for", escName v]++errNoCommonCons :: Position -> [QualIdent] -> Message+errNoCommonCons p ls = posMessage p $+  text "No constructor has all of these fields:"+  $+$ nest 2 (vcat (map (text . escQualName) ls))++errNoLabel :: QualIdent -> QualIdent -> Message+errNoLabel c l = posMessage l $ hsep $ map text+  [escQualName l, "is not a field label of constructor", escQualName c]++errNoTypeSig :: Ident -> Message+errNoTypeSig f = posMessage f $ hsep $ map text+  ["No type signature for external function", escName f]++errToplevelPattern :: Position -> Message+errToplevelPattern p = posMessage p $ text+  "Pattern declaration not allowed at top-level"++errDifferentArity :: [Ident] -> Message+errDifferentArity [] = internalError+  "SyntaxCheck.errDifferentArity: empty list"+errDifferentArity (i:is) = posMessage i $+  text "Equations for" <+> text (escName i) <+> text "have different arities"+  <+> text "at:" $+$+  nest 2 (vcat (map (ppPosition . getPosition) (i:is)))++errWrongArity :: QualIdent -> Int -> Int -> Message+errWrongArity c arity' argc = posMessage c $ hsep (map text+  ["Data constructor", escQualName c, "expects", arguments arity'])+  <> comma <+> text "but is applied to" <+> text (show argc)+  where arguments 0 = "no arguments"+        arguments 1 = "1 argument"+        arguments n = show n ++ " arguments"++errMissingLanguageExtension :: Position -> String -> KnownExtension -> Message+errMissingLanguageExtension p what ext = posMessage p $+  text what <+> text "are not supported in standard Curry." $+$+  nest 2 (text "Use flag or -X" <+> text (show ext)+          <+> text "to enable this extension.")++errInfixWithoutParens :: Position -> [(QualIdent, QualIdent)] -> Message+errInfixWithoutParens p calls = posMessage p $+  text "Missing parens in infix patterns:" $+$+  vcat (map showCall calls)+  where+  showCall (q1, q2) = showWithPos q1 <+> text "calls" <+> showWithPos q2+  showWithPos q =  text (qualName q)+               <+> parens (text $ showLine $ qidPosition q)
+ src/Checks/TypeCheck.hs view
@@ -0,0 +1,1811 @@+{- |+    Module      :  $Header$+    Description :  Type checking Curry programs+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux+                                   Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2014 - 2015 Jan Tikovsky+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module implements the type checker of the Curry compiler. The+   type checker is invoked after the syntactic correctness of the program+   has been verified and kind checking has been applied to all type+   expressions. Local variables have been renamed already. Thus the+   compiler can maintain a flat type environment. The type checker now+   checks the correct typing of all expressions and also verifies that+   the type signatures given by the user match the inferred types. The+   type checker uses the algorithm by Damas and Milner (1982) for inferring+   the types of unannotated declarations, but allows for polymorphic+   recursion when a type annotation is present.++   The result of type checking is a (flat) top-level environment+   containing the types of all constructors, variables, and functions+   defined at the top level of a module. In addition, a type annotated+   source module is returned. Note that type annotations on the+   left hand side of a declaration hold the function or variable's+   generalized type with the type scheme's universal quantifier left+   implicit. Type annotations on the right hand side of a declaration+   hold the particular instance at which a polymorphic function or+   variable is used.+-}+{-# LANGUAGE CPP #-}+module Checks.TypeCheck (typeCheck) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import           Control.Monad.Extra        ( (&&^), allM, filterM, foldM+                                            , liftM, notM, replicateM, unless+                                            , unlessM )+import qualified Control.Monad.State as S   (State, runState, gets, modify)+import           Data.List                  (nub, nubBy, partition, sortBy)+import           Data.Function              (on)+import qualified Data.Map            as Map (Map, empty, insert, lookup)+import           Data.Maybe                 (fromJust, fromMaybe, isJust)+import qualified Data.Set.Extra      as Set ( Set, concatMap, deleteMin, empty+                                            , fromList, insert, member+                                            , notMember, partition, singleton+                                            , toList, union, unions )++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty++import Base.CurryTypes+import Base.Expr+import Base.Kinds+import Base.Messages (Message, posMessage, internalError)+import Base.SCC+import Base.TopEnv+import Base.TypeExpansion+import Base.Types+import Base.TypeSubst+import Base.Utils (foldr2, fst3, snd3, thd3, uncurry3, mapAccumM)++import Env.Class+import Env.Instance+import Env.TypeConstructor+import Env.Value++-- Type checking proceeds as follows. First, the types of all data+-- constructors, field labels and class methods are entered into the+-- value environment and then a type inference for all function and+-- value definitions is performed.++typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> ClassEnv -> InstEnv -> [Decl a]+          -> ([Decl PredType], ValueEnv, [Message])+typeCheck m tcEnv vEnv clsEnv inEnv ds = runTCM (checkDecls ds) initState+  where initState = TcState m tcEnv vEnv clsEnv (inEnv, Map.empty)+                            [intType, floatType] idSubst emptySigEnv 1 []++checkDecls :: [Decl a] -> TCM [Decl PredType]+checkDecls ds = do+  bindConstrs+  mapM_ checkFieldLabel (filter isTypeDecl ds) &&> bindLabels+  bindClassMethods+  mapM_ setDefaults $ filter isDefaultDecl ds+  (_, bpds') <- tcPDecls bpds+  tpds' <- mapM tcTopPDecl tpds+  theta <- getTypeSubst+  return $ map (fmap $ subst theta) $ fromPDecls $ tpds' ++ bpds'+  where (bpds, tpds) = partition (isBlockDecl . snd) $ toPDecls ds++-- The type checker makes use of a state monad in order to maintain the value+-- environment, the current substitution, and a counter which is used for+-- generating fresh type variables.++-- Additionally, an extended instance environment is used in order to handle+-- the introduction of local instances when matching a data constructor with a+-- non-empty context. This extended instance environment is composed of the+-- static top-level environment and a dynamic environment that maps each class+-- on the instances which are in scope for it. The rationale behind using this+-- representation is that it makes it easy to apply the current substitution to+-- the dynamic part of the environment.++type TCM = S.State TcState++type InstEnv' = (InstEnv, Map.Map QualIdent [Type])++data TcState = TcState+  { moduleIdent  :: ModuleIdent -- read only+  , tyConsEnv    :: TCEnv+  , valueEnv     :: ValueEnv+  , classEnv     :: ClassEnv+  , instEnv      :: InstEnv'    -- instances (static and dynamic)+  , defaultTypes :: [Type]+  , typeSubst    :: TypeSubst+  , sigEnv       :: SigEnv+  , nextId       :: Int         -- automatic counter+  , errors       :: [Message]+  }++(&&>) :: TCM () -> TCM () -> TCM ()+pre &&> suf = do+  errs <- pre >> S.gets errors+  if null errs then suf else return ()++(>>-) :: TCM (a, b, c) -> (a -> b -> TCM a) -> TCM (a, c)+m >>- f = do+  (u, v, w) <- m+  u' <- f u v+  return (u', w)++(>>=-) :: TCM (a, b, d) -> (b -> TCM c) -> TCM (a, c, d)+m >>=- f = do+  (u, v, x) <- m+  w <- f v+  return (u, w, x)++runTCM :: TCM a -> TcState -> (a, ValueEnv, [Message])+runTCM tcm s = let (a, s') = S.runState tcm s+               in  (a, typeSubst s' `subst` valueEnv s', reverse $ errors s')++getModuleIdent :: TCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTyConsEnv :: TCM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: TCM ValueEnv+getValueEnv = S.gets valueEnv++modifyValueEnv :: (ValueEnv -> ValueEnv) -> TCM ()+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }++withLocalValueEnv :: TCM a -> TCM a+withLocalValueEnv act = do+  oldEnv <- getValueEnv+  res <- act+  modifyValueEnv $ const oldEnv+  return res++getClassEnv :: TCM ClassEnv+getClassEnv = S.gets classEnv++getInstEnv :: TCM InstEnv'+getInstEnv = S.gets instEnv++modifyInstEnv :: (InstEnv' -> InstEnv') -> TCM ()+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }++getDefaultTypes :: TCM [Type]+getDefaultTypes = S.gets defaultTypes++setDefaultTypes :: [Type] -> TCM ()+setDefaultTypes tys = S.modify $ \s -> s { defaultTypes = tys }++getTypeSubst :: TCM TypeSubst+getTypeSubst = S.gets typeSubst++modifyTypeSubst :: (TypeSubst -> TypeSubst) -> TCM ()+modifyTypeSubst f = S.modify $ \s -> s { typeSubst = f $ typeSubst s }++getSigEnv :: TCM SigEnv+getSigEnv = S.gets sigEnv++setSigEnv :: SigEnv -> TCM ()+setSigEnv sigs = S.modify $ \s -> s { sigEnv = sigs }++withLocalSigEnv :: TCM a -> TCM a+withLocalSigEnv act = do+  oldSigs <- getSigEnv+  res <- act+  setSigEnv oldSigs+  return res++getNextId :: TCM Int+getNextId = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return nid++report :: Message -> TCM ()+report err = S.modify $ \s -> s { errors = err : errors s }++ok :: TCM ()+ok = return ()++-- Because the type check may mess up the order of the declarations, we+-- associate each declaration with a number. At the end of the type check,+-- we can use these numbers to restore the original declaration order.++type PDecl a = (Int, Decl a)++toPDecls :: [Decl a] -> [PDecl a]+toPDecls = zip [0 ..]++fromPDecls :: [PDecl a] -> [Decl a]+fromPDecls = map snd . sortBy (compare `on` fst)++-- During the type check we also have to convert the type of declarations+-- without annotations which is done by the function 'untyped' below.++untyped :: PDecl a -> PDecl b+untyped = fmap $ fmap $ internalError "TypeCheck.untyped"++-- Defining Data Constructors:+-- In the next step, the types of all data constructors are entered into+-- the value environment using the information entered into the type constructor+-- environment before.++bindConstrs :: TCM ()+bindConstrs = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  modifyValueEnv $ bindConstrs' m tcEnv++bindConstrs' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv+bindConstrs' m tcEnv vEnv = foldr (bindData . snd) vEnv $ localBindings tcEnv+  where+    bindData (DataType tc k cs) vEnv' =+      let n = kindArity k in foldr (bindConstr m n (constrType' tc n)) vEnv' cs+    bindData (RenamingType tc k c) vEnv' =+      let n = kindArity k in bindNewConstr m n (constrType' tc n) c vEnv'+    bindData _ vEnv' = vEnv'++bindConstr :: ModuleIdent -> Int -> Type -> DataConstr -> ValueEnv -> ValueEnv+bindConstr m n ty (DataConstr c n' ps tys) =+  bindGlobalInfo (\qc tyScheme -> DataConstructor qc arity ls tyScheme) m c+                 (ForAllExist n n' (PredType ps (foldr TypeArrow ty tys)))+  where arity = length tys+        ls    = replicate arity anonId+bindConstr m n ty (RecordConstr c n' ps ls tys) =+  bindGlobalInfo (\qc tyScheme -> DataConstructor qc arity ls tyScheme) m c+                 (ForAllExist n n' (PredType ps (foldr TypeArrow ty tys)))+  where arity = length tys++bindNewConstr :: ModuleIdent -> Int -> Type -> DataConstr -> ValueEnv+              -> ValueEnv+bindNewConstr m n cty (DataConstr c n' _ [lty]) =+  bindGlobalInfo (\qc tyScheme -> NewtypeConstructor qc anonId tyScheme) m c+                 (ForAllExist n n' (predType (TypeArrow lty cty)))+bindNewConstr m n cty (RecordConstr c n' _ [l] [lty]) =+  bindGlobalInfo (\qc tyScheme -> NewtypeConstructor qc l tyScheme) m c+                 (ForAllExist n n' (predType (TypeArrow lty cty)))+bindNewConstr _ _ _ _ = internalError+  "TypeCheck.bindConstrs'.bindNewConstr: newtype with illegal constructors"++constrType' :: QualIdent -> Int -> Type+constrType' tc n =+  applyType (TypeConstructor tc) $ map TypeVariable [0 .. n - 1]++-- When a field label occurs in more than one constructor declaration of+-- a data type, the compiler ensures that the label is defined+-- consistently, i.e. both occurrences have the same type. In addition,+-- the compiler ensures that no existentially quantified type variable occurs+-- in the type of a field label because such type variables necessarily escape+-- their scope with the type of the record selection function associated with+-- the field label.++checkFieldLabel :: Decl a -> TCM ()+checkFieldLabel (DataDecl _ _ tvs cs _) = do+  ls' <- mapM (tcFieldLabel tvs) labels+  mapM_ tcFieldLabels (groupLabels ls')+  where labels = [(l, p, ty) | RecordDecl _ _ _ _ fs <- cs,+                               FieldDecl p ls ty <- fs, l <- ls]+checkFieldLabel (NewtypeDecl _ _ tvs (NewRecordDecl p _ (l, ty)) _) = do+  _ <- tcFieldLabel tvs (l, p, ty)+  ok+checkFieldLabel _ = ok++tcFieldLabel :: [Ident] -> (Ident, Position, TypeExpr)+             -> TCM (Ident, Position, Type)+tcFieldLabel tvs (l, p, ty) = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  let ForAll n (PredType _ ty') = polyType $ expandMonoType m tcEnv tvs ty+  unless (n <= length tvs) $ report $ errSkolemFieldLabel p l+  return (l, p, ty')++groupLabels :: Eq a => [(a, b, c)] -> [(a, b, [c])]+groupLabels []               = []+groupLabels ((x, y, z):xyzs) =+  (x, y, z : map thd3 xyzs') : groupLabels xyzs''+  where (xyzs', xyzs'') = partition ((x ==) . fst3) xyzs++tcFieldLabels :: (Ident, Position, [Type]) -> TCM ()+tcFieldLabels (_, _, [])     = return ()+tcFieldLabels (l, p, ty:tys) = unless (null (filter (ty /=) tys)) $ do+  m <- getModuleIdent+  report $ errIncompatibleLabelTypes p m l ty (head tys)++-- Defining Field Labels:+-- Next the types of all field labels are added to the value environment.++bindLabels :: TCM ()+bindLabels = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  modifyValueEnv $ bindLabels' m tcEnv++bindLabels' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv+bindLabels' m tcEnv vEnv = foldr (bindData . snd) vEnv $ localBindings tcEnv+  where+    bindData (DataType tc k cs) vEnv' =+      foldr (bindLabel m n (constrType' tc n)) vEnv' $ nubBy sameLabel clabels+      where+        n = kindArity k+        labels = zip (concatMap recLabels cs) (concatMap recLabelTypes cs)+        clabels = [(l, constr l, ty) | (l, ty) <- labels]+        constr l = map (qualifyLike tc) $+          [constrIdent c | c <- cs, l `elem` recLabels c]+        sameLabel (l1,_,_) (l2,_,_) = l1 == l2+    bindData (RenamingType tc k (RecordConstr c _ _ [l] [lty])) vEnv' =+      bindLabel m n (constrType' tc n) (l, [qc], lty) vEnv'+      where+        n = kindArity k+        qc = qualifyLike tc c+    bindData (RenamingType _ _ (RecordConstr _ _ _ _ _)) _ =+      internalError $ "Checks.TypeCheck.bindLabels'.bindData: " +++        "RenamingType with more than one record label"+    bindData _ vEnv' = vEnv'++bindLabel :: ModuleIdent -> Int -> Type -> (Ident, [QualIdent], Type)+          -> ValueEnv -> ValueEnv+bindLabel m n ty (l, lcs, lty) =+  bindGlobalInfo (\qc tyScheme -> Label qc lcs tyScheme) m l+                 (ForAll n (predType (TypeArrow ty lty)))++-- Defining class methods:+-- Last, the types of all class methods are added to the value environment.++bindClassMethods :: TCM ()+bindClassMethods = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  modifyValueEnv $ bindClassMethods' m tcEnv++bindClassMethods' :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv+bindClassMethods' m tcEnv vEnv =+  foldr (bindMethods . snd) vEnv $ localBindings tcEnv+  where+    bindMethods (TypeClass _ _ ms) vEnv' =+      foldr (bindClassMethod m) vEnv' ms+    bindMethods _ vEnv' = vEnv'++-- Since the implementations of class methods can differ in their arity,+-- we assume an arity of 0 when we enter one into the value environment.++bindClassMethod :: ModuleIdent -> ClassMethod -> ValueEnv -> ValueEnv+bindClassMethod m (ClassMethod f _ pty) =+  bindGlobalInfo (\qc tySc -> Value qc True 0 tySc) m f (typeScheme pty)++-- Default Types:+-- The list of default types is given either by a default declaration in+-- the source code or defaults to the predefined list of numeric data types.++setDefaults :: Decl a -> TCM ()+setDefaults (DefaultDecl _ tys) = mapM toDefaultType tys >>= setDefaultTypes+  where+    toDefaultType =+      liftM snd . (inst =<<) . liftM typeScheme . expandPoly . QualTypeExpr []+setDefaults _ = ok++-- Type Signatures:+-- The type checker collects type signatures in a flat environment.+-- The types are not expanded so that the signature is available for+-- use in the error message that is printed when the inferred type is+-- less general than the signature.++type SigEnv = Map.Map Ident QualTypeExpr++emptySigEnv :: SigEnv+emptySigEnv = Map.empty++bindTypeSig :: Ident -> QualTypeExpr -> SigEnv -> SigEnv+bindTypeSig = Map.insert++bindTypeSigs :: Decl a -> SigEnv -> SigEnv+bindTypeSigs (TypeSig _ vs qty) env =+  foldr (flip bindTypeSig qty) env vs+bindTypeSigs _                  env = env++lookupTypeSig :: Ident -> SigEnv -> Maybe QualTypeExpr+lookupTypeSig = Map.lookup++-- Declaration groups:+-- Before type checking a group of declarations, a dependency analysis is+-- performed and the declaration group is eventually transformed into+-- nested declaration groups which are checked separately. Within each+-- declaration group, first the value environment is extended with new+-- bindings for all variables and functions defined in the group. Next,+-- types are inferred for all declarations without an explicit type signature+-- and the inferred types are then generalized. Finally, the types of all+-- explicitly typed declarations are checked.++-- Within a group of mutually recursive declarations, all type variables+-- that appear in the types of the variables defined in the group and+-- whose type cannot be generalized must not be generalized in the other+-- declarations of that group as well.++tcDecls :: [Decl a] -> TCM (PredSet, [Decl PredType])+tcDecls = liftM (fmap fromPDecls) . tcPDecls . toPDecls++tcPDecls :: [PDecl a] -> TCM (PredSet, [PDecl PredType])+tcPDecls pds = withLocalSigEnv $ do+  let (vpds, opds) = partition (isValueDecl . snd) pds+  setSigEnv $ foldr (bindTypeSigs . snd) emptySigEnv $ opds+  m <- getModuleIdent+  (ps, vpdss') <-+    mapAccumM tcPDeclGroup emptyPredSet $ scc (bv . snd) (qfv m . snd) vpds+  return (ps, map untyped opds ++ concat (vpdss' :: [[PDecl PredType]]))++tcPDeclGroup :: PredSet -> [PDecl a] -> TCM (PredSet, [PDecl PredType])+tcPDeclGroup ps [(i, ExternalDecl p fs)] = do+  tys <- mapM (tcExternal . varIdent) fs+  return (ps, [(i, ExternalDecl p (zipWith (fmap . const . predType) tys fs))])+tcPDeclGroup ps [(i, FreeDecl p fvs)] = do+  vs <- mapM (tcDeclVar False) (bv fvs)+  m <- getModuleIdent+  modifyValueEnv $ flip (bindVars m) vs+  return (ps, [(i, FreeDecl p (map (\(v, _, ForAll _ pty) -> Var pty v) vs))])+tcPDeclGroup ps pds = do+  vEnv <- getValueEnv+  vss <- mapM (tcDeclVars . snd) pds+  m <- getModuleIdent+  modifyValueEnv $ flip (bindVars m) $ concat vss+  sigs <- getSigEnv+  let (impPds, expPds) = partitionPDecls sigs pds+  (ps', impPds') <- mapAccumM tcPDecl ps impPds+  theta <- getTypeSubst+  tvs <- liftM (concatMap $ typeVars . subst theta . fst) $+           filterM (notM . isNonExpansive . snd . snd) impPds'+  let fvs = foldr Set.insert (fvEnv (subst theta vEnv)) tvs+      (gps, lps) = splitPredSet fvs ps'+  lps' <- foldM (uncurry . defaultPDecl fvs) lps impPds'+  theta' <- getTypeSubst+  let impPds'' = map (uncurry (fixType . gen fvs lps' . subst theta')) impPds'+  modifyValueEnv $ flip (rebindVars m) (concatMap (declVars . snd) impPds'')+  (ps'', expPds') <- mapAccumM (uncurry . tcCheckPDecl) gps expPds+  return (ps'', impPds'' ++ expPds')++partitionPDecls :: SigEnv -> [PDecl a] -> ([PDecl a], [(QualTypeExpr, PDecl a)])+partitionPDecls sigs =+  foldr (\pd -> maybe (implicit pd) (explicit pd) (typeSig $ snd pd)) ([], [])+  where implicit pd ~(impPds, expPds) = (pd : impPds, expPds)+        explicit pd qty ~(impPds, expPds) = (impPds, (qty, pd) : expPds)+        typeSig (FunctionDecl _ _ f _) = lookupTypeSig f sigs+        typeSig (PatternDecl _ (VariablePattern _ v) _) = lookupTypeSig v sigs+        typeSig _ = Nothing++bindVars :: ModuleIdent -> ValueEnv -> [(Ident, Int, TypeScheme)] -> ValueEnv+bindVars m = foldr $ uncurry3 $ flip (bindFun m) False++rebindVars :: ModuleIdent -> ValueEnv -> [(Ident, Int, TypeScheme)] -> ValueEnv+rebindVars m = foldr $ uncurry3 $ flip (rebindFun m) False++tcDeclVars :: Decl a -> TCM [(Ident, Int, TypeScheme)]+tcDeclVars (FunctionDecl _ _ f eqs) = do+  sigs <- getSigEnv+  let n = eqnArity $ head eqs+  case lookupTypeSig f sigs of+    Just qty -> do+      pty <- expandPoly qty+      return [(f, n, typeScheme pty)]+    Nothing -> do+      tys <- replicateM (n + 1) freshTypeVar+      return [(f, n, monoType $ foldr1 TypeArrow tys)]+tcDeclVars (PatternDecl _ t _) = case t of+  VariablePattern _ v -> return <$> tcDeclVar True v+  _ -> mapM (tcDeclVar False) (bv t)+tcDeclVars _ = internalError "TypeCheck.tcDeclVars"++tcDeclVar :: Bool -> Ident -> TCM (Ident, Int, TypeScheme)+tcDeclVar poly v = do+  sigs <- getSigEnv+  case lookupTypeSig v sigs of+    Just qty+      | poly || null (fv qty) -> do+        pty <- expandPoly qty+        return (v, 0, typeScheme pty)+      | otherwise -> do+        report $ errPolymorphicVar v+        lambdaVar v+    Nothing -> lambdaVar v++tcPDecl :: PredSet -> PDecl a -> TCM (PredSet, (Type, PDecl PredType))+tcPDecl ps (i, FunctionDecl p _ f eqs) = do+  vEnv <- getValueEnv+  tcFunctionPDecl i ps (varType f vEnv) p f eqs+tcPDecl ps (i, d@(PatternDecl p t rhs)) = do+  (ps', ty', t') <- tcPattern p t+  (ps'', rhs') <- tcRhs rhs >>-+    unifyDecl p "pattern declaration" (ppDecl d) (ps `Set.union` ps') ty'+  return (ps'', (ty', (i, PatternDecl p t' rhs')))+tcPDecl _ _ = internalError "TypeCheck.tcPDecl"++-- The function 'tcFunctionPDecl' ignores the context of a function's type+-- signature. This prevents missing instance errors when the inferred type+-- of a function is less general than the declared type.++tcFunctionPDecl :: Int -> PredSet -> TypeScheme -> Position -> Ident+                -> [Equation a] -> TCM (PredSet, (Type, PDecl PredType))+tcFunctionPDecl i ps tySc@(ForAll _ pty) p f eqs = do+  (_, ty) <- inst tySc+  fs <- computeFsEnv+  (ps', eqs') <- mapAccumM (tcEquation fs ty) ps eqs+  return (ps', (ty, (i, FunctionDecl p pty f eqs')))++tcEquation :: Set.Set Int -> Type -> PredSet -> Equation a+           -> TCM (PredSet, Equation PredType)+tcEquation fs ty ps eqn@(Equation p lhs rhs) =+  tcEqn fs p lhs rhs >>- unifyDecl p "equation" (ppEquation eqn) ps ty++tcEqn :: Set.Set Int -> Position -> Lhs a -> Rhs a+      -> TCM (PredSet, Type, Equation PredType)+tcEqn fs p lhs rhs = do+  (ps, tys, lhs', ps', ty, rhs') <- withLocalValueEnv $ do+    bindLambdaVars lhs+    (ps, tys, lhs') <- tcLhs p lhs+    (ps', ty, rhs') <- tcRhs rhs+    return (ps, tys, lhs', ps', ty, rhs')+  ps'' <- reducePredSet p "equation" (ppEquation (Equation p lhs' rhs')) (ps `Set.union` ps')+  checkSkolems p "Equation" ppEquation fs ps'' (foldr TypeArrow ty tys)+    (Equation p lhs' rhs')++bindLambdaVars :: QuantExpr t => t -> TCM ()+bindLambdaVars t = do+  m <- getModuleIdent+  vs <- mapM lambdaVar (nub $ bv t)+  modifyValueEnv $ flip (bindVars m) vs++lambdaVar :: Ident -> TCM (Ident, Int, TypeScheme)+lambdaVar v = do+  ty <- freshTypeVar+  return (v, 0, monoType ty)++unifyDecl :: Position -> String -> Doc -> PredSet -> Type -> PredSet -> Type+          -> TCM PredSet+unifyDecl p what doc psLhs tyLhs psRhs tyRhs = do+  ps <- unify p what doc psLhs tyLhs psRhs tyRhs+  fvs <- computeFvEnv+  applyDefaultsDecl p what doc fvs ps tyLhs++-- After inferring types for a group of mutually recursive declarations+-- and computing the set of its constrained type variables, the compiler+-- has to be prepared for some of the constrained type variables to not+-- appear in some of the inferred types, i.e., there may be ambiguous+-- types that have not been reported by 'unifyDecl' above at the level+-- of individual function equations and pattern declarations.++defaultPDecl :: Set.Set Int -> PredSet -> Type -> PDecl a -> TCM PredSet+defaultPDecl fvs ps ty (_, FunctionDecl p _ f _) =+  applyDefaultsDecl p ("function " ++ escName f) empty fvs ps ty+defaultPDecl fvs ps ty (_, PatternDecl p t _) = case t of+  VariablePattern _ v ->+    applyDefaultsDecl p ("variable " ++ escName v) empty fvs ps ty+  _ -> return ps+defaultPDecl _ _ _ _ = internalError "TypeCheck.defaultPDecl"++applyDefaultsDecl :: Position -> String -> Doc -> Set.Set Int -> PredSet -> Type+                  -> TCM PredSet+applyDefaultsDecl p what doc fvs ps ty = do+  theta <- getTypeSubst+  let ty' = subst theta ty+      fvs' = foldr Set.insert fvs $ typeVars ty'+  applyDefaults p what doc fvs' ps ty'++-- After 'tcDeclGroup' has generalized the types of the implicitly+-- typed declarations of a declaration group it must update their left+-- hand side type annotations and the type environment accordingly.+-- Recall that the compiler generalizes only the types of variable and+-- function declarations.++fixType :: TypeScheme -> PDecl PredType -> PDecl PredType+fixType ~(ForAll _ pty) (i, FunctionDecl p _ f eqs) =+  (i, FunctionDecl p pty f eqs)+fixType ~(ForAll _ pty) pd@(i, PatternDecl p t rhs) = case t of+  VariablePattern _ v -> (i, PatternDecl p (VariablePattern pty v) rhs)+  _ -> pd+fixType _ _ = internalError "TypeCheck.fixType"++declVars :: Decl PredType -> [(Ident, Int, TypeScheme)]+declVars (FunctionDecl _ pty f eqs) = [(f, eqnArity $ head eqs, typeScheme pty)]+declVars (PatternDecl _ t _) = case t of+  VariablePattern pty v -> [(v, 0, typeScheme pty)]+  _ -> []+declVars _ = internalError "TypeCheck.declVars"++-- The function 'tcCheckPDecl' checks the type of an explicitly typed function+-- or variable declaration. After inferring a type for the declaration, the+-- inferred type is compared with the type signature. Since the inferred type+-- of an explicitly typed function or variable declaration is automatically an+-- instance of its type signature, the type signature is correct only if the+-- inferred type matches the type signature exactly except for the inferred+-- predicate set, which may contain only a subset of the declared context+-- because the context of a function's type signature is ignored in the+-- function 'tcFunctionPDecl' above.++tcCheckPDecl :: PredSet -> QualTypeExpr -> PDecl a -> TCM (PredSet, PDecl PredType)+tcCheckPDecl ps qty pd = do+  (ps', (ty, pd')) <- tcPDecl ps pd+  fvs <- computeFvEnv+  theta <- getTypeSubst+  poly <- isNonExpansive $ snd pd+  let (gps, lps) = splitPredSet fvs ps'+      ty' = subst theta ty+      tySc = if poly then gen fvs lps ty' else monoType ty'+  checkPDeclType qty gps tySc pd'++checkPDeclType :: QualTypeExpr -> PredSet -> TypeScheme -> PDecl PredType+               -> TCM (PredSet, PDecl PredType)+checkPDeclType qty ps tySc (i, FunctionDecl p _ f eqs) = do+  pty <- expandPoly qty+  unlessM (checkTypeSig pty tySc) $ do+    m <- getModuleIdent+    report $ errTypeSigTooGeneral p m (text "Function:" <+> ppIdent f) qty tySc+  return (ps, (i, FunctionDecl p pty f eqs))+checkPDeclType qty ps tySc (i, PatternDecl p (VariablePattern _ v) rhs) = do+  pty <- expandPoly qty+  unlessM (checkTypeSig pty tySc) $ do+    m <- getModuleIdent+    report $ errTypeSigTooGeneral p m (text "Variable:" <+> ppIdent v) qty tySc+  return (ps, (i, PatternDecl p (VariablePattern pty v) rhs))+checkPDeclType _ _ _ _ = internalError "TypeCheck.checkPDeclType"++checkTypeSig :: PredType -> TypeScheme -> TCM Bool+checkTypeSig (PredType sigPs sigTy) (ForAll _ (PredType ps ty)) = do+  clsEnv <- getClassEnv+  return $+    ty `eqTypes` sigTy && all (`Set.member` maxPredSet clsEnv sigPs) (Set.toList ps)++-- The function 'equTypes' computes whether two types are equal modulo+-- renaming of type variables.+-- WARNING: This operation is not reflexive and expects the second type to be+-- the type signature provided by the programmer.+eqTypes :: Type -> Type -> Bool+eqTypes t1 t2 = fst (eq [] t1 t2)+ where+ -- @is@ is an AssocList of type variable indices+ eq is (TypeConstructor   qid1) (TypeConstructor   qid2) = (qid1 == qid2, is)+ eq is (TypeVariable        i1) (TypeVariable        i2) = eqVar is i1 i2+ eq is (TypeConstrained ts1 i1) (TypeConstrained ts2 i2)+   = let (res1, is1) = eqs   is  ts1 ts2+         (res2, is2) = eqVar is1 i1  i2+     in  (res1 && res2, is2)+ eq is (TypeSkolem          i1) (TypeSkolem          i2) = eqVar is i1 i2+ eq is (TypeApply      ta1 tb1) (TypeApply      ta2 tb2)+   = let (res1, is1) = eq is  ta1 ta2+         (res2, is2) = eq is1 tb1 tb2+     in  (res1 && res2, is2)+ eq is (TypeArrow      tf1 tt1) (TypeArrow      tf2 tt2)+   = let (res1, is1) = eq is  tf1 tf2+         (res2, is2) = eq is1 tt1 tt2+     in  (res1 && res2, is2)+ eq is (TypeForall     is1 t1') (TypeForall     is2 t2')+   = let (res1, is') = eqs [] (map TypeVariable is1) (map TypeVariable is2)+         (res2, _  ) = eq is' t1' t2'+     in  (res1 && res2, is)+ eq is _                        _                        = (False, is)++ eqVar is i1 i2 = case lookup i1 is of+   Nothing  -> (True, (i1, i2) : is)+   Just i2' -> (i2 == i2', is)++ eqs is []        []        = (True , is)+ eqs is (t1':ts1) (t2':ts2)+    = let (res1, is1) = eq  is t1'  t2'+          (res2, is2) = eqs is1 ts1 ts2+      in  (res1 && res2, is2)+ eqs is _         _         = (False, is)++-- In Curry, a non-expansive expression is either+--+-- * a literal,+-- * a variable,+-- * an application of a constructor with arity n to at most n+--   non-expansive expressions,+-- * an application of a function with arity n to at most n-1+--   non-expansive expressions, or+-- * a let expression whose body is a non-expansive expression and+--   whose local declarations are either function declarations or+--   variable declarations of the form x=e where e is a non-expansive+--   expression, or+-- * an expression whose desugared form is one of the above.+--+-- At first it may seem strange that variables are included in the list+-- above because a variable may be bound to a logical variable. However,+-- this is no problem because type variables that are present among the+-- typing assumptions of the environment enclosing a let expression+-- cannot be generalized.++class Binding a where+  isNonExpansive :: a -> TCM Bool++instance Binding a => Binding [a] where+  isNonExpansive = allM isNonExpansive++instance Binding (Decl a) where+  isNonExpansive (InfixDecl       _ _ _ _) = return True+  isNonExpansive (TypeSig           _ _ _) = return True+  isNonExpansive (FunctionDecl    _ _ _ _) = return True+  isNonExpansive (ExternalDecl        _ _) = return True+  isNonExpansive (PatternDecl       _ _ _) = return False+    -- TODO: Uncomment when polymorphic let declarations are fully supported+  {-isNonExpansive (PatternDecl     _ t rhs) = case t of+    VariablePattern _ _ -> isNonExpansive rhs+    _                   -> return False-}+  isNonExpansive (FreeDecl            _ _) = return False+  isNonExpansive _                         =+    internalError "TypeCheck.isNonExpansive: declaration"++instance Binding (Rhs a) where+  isNonExpansive (SimpleRhs _ e ds) = withLocalValueEnv $ do+    m <- getModuleIdent+    tcEnv <- getTyConsEnv+    clsEnv <- getClassEnv+    sigs <- getSigEnv+    modifyValueEnv $ flip (foldr (bindDeclArity m tcEnv clsEnv sigs)) ds+    isNonExpansive e &&^ isNonExpansive ds+  isNonExpansive (GuardedRhs   _ _) = return False++-- A record construction is non-expansive only if all field labels are present.++instance Binding (Expression a) where+  isNonExpansive = isNonExpansive' 0++isNonExpansive' :: Int -> Expression a -> TCM Bool+isNonExpansive' _ (Literal         _ _) = return True+isNonExpansive' n (Variable        _ v)+  | v' == anonId = return False+  | isRenamed v' = do+    vEnv <- getValueEnv+    return $ n == 0 || n < varArity v vEnv+  | otherwise = do+    vEnv <- getValueEnv+    return $ n < varArity v vEnv+  where v' = unqualify v+isNonExpansive' _ (Constructor     _ _) = return True+isNonExpansive' n (Paren             e) = isNonExpansive' n e+isNonExpansive' n (Typed           e _) = isNonExpansive' n e+isNonExpansive' _ (Record       _ c fs) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  liftM ((length (constrLabels m c vEnv) == length fs) &&) (isNonExpansive fs)+isNonExpansive' _ (Tuple            es) = isNonExpansive es+isNonExpansive' _ (List           _ es) = isNonExpansive es+isNonExpansive' n (Apply           f e) =+  isNonExpansive' (n + 1) f &&^ isNonExpansive e+isNonExpansive' n (InfixApply e1 op e2) =+  isNonExpansive' (n + 2) (infixOp op) &&^ isNonExpansive e1 &&^+    isNonExpansive e2+isNonExpansive' n (LeftSection    e op) =+  isNonExpansive' (n + 1) (infixOp op) &&^ isNonExpansive e+isNonExpansive' n (Lambda         ts e) = withLocalValueEnv $ do+  modifyValueEnv $ flip (foldr bindVarArity) (bv ts)+  liftM ((n < length ts) ||)+    (liftM ((all isVariablePattern ts) &&) (isNonExpansive' (n - length ts) e))+isNonExpansive' n (Let            ds e) = withLocalValueEnv $ do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  clsEnv <- getClassEnv+  sigs <- getSigEnv+  modifyValueEnv $ flip (foldr (bindDeclArity m tcEnv clsEnv sigs)) ds+  isNonExpansive ds &&^ isNonExpansive' n e+isNonExpansive' _ _                     = return False++instance Binding a => Binding (Field a) where+  isNonExpansive (Field _ _ e) = isNonExpansive e++bindDeclArity :: ModuleIdent -> TCEnv -> ClassEnv -> SigEnv ->  Decl a+              -> ValueEnv -> ValueEnv+bindDeclArity _ _     _      _    (InfixDecl        _ _ _ _) = id+bindDeclArity _ _     _      _    (TypeSig            _ _ _) = id+bindDeclArity _ _     _      _    (FunctionDecl   _ _ f eqs) =+  bindArity f (eqnArity $ head eqs)+bindDeclArity m tcEnv clsEnv sigs (ExternalDecl        _ fs) =+  flip (foldr $ \(Var _ f) -> bindArity f $ arrowArity $ ty f) fs+  where ty = unpredType . expandPolyType m tcEnv clsEnv . fromJust .+               flip lookupTypeSig sigs+bindDeclArity _ _     _      _    (PatternDecl        _ t _) =+  flip (foldr bindVarArity) (bv t)+bindDeclArity _ _     _      _    (FreeDecl            _ vs) =+  flip (foldr bindVarArity) (bv vs)+bindDeclArity _ _     _      _    _                          =+  internalError "TypeCheck.bindDeclArity"++bindVarArity :: Ident -> ValueEnv -> ValueEnv+bindVarArity v = bindArity v 0++bindArity :: Ident -> Int -> ValueEnv -> ValueEnv+bindArity v n = bindTopEnv v (Value (qualify v) False n undefined)++-- Class and instance declarations:+-- When checking method implementations in class and instance+-- declarations, the compiler must check that the inferred type matches+-- the method's declared type. This is straight forward in class+-- declarations (the only difference with respect to an overloaded+-- function with an explicit type signature is that a class method's type+-- signature is composed of its declared type signature and the context+-- from the class declaration), but a little bit more complicated for+-- instance declarations because the instance type must be substituted+-- for the type variable used in the type class declaration.+--+-- When checking inferred method types against their expected types, we+-- have to be careful because the class' type variable is always assigned+-- index 0 in the method types recorded in the value environment. However,+-- in the inferred type scheme returned from 'tcMethodDecl', type variables+-- are assigned indices in the order of their occurrence. In order to avoid+-- incorrectly reporting errors when the type class variable is not the first+-- variable that appears in a method's type, 'tcInstMethodDecl' normalizes+-- the expected method type before applying 'checkInstMethodType' to it and+-- 'checkClassMethodType' uses 'expandPolyType' instead of 'expandMethodType'+-- in order to convert the method's type signature. Unfortunately, this means+-- that the compiler has to add the class constraint explicitly to the type+-- signature.++tcTopPDecl :: PDecl a -> TCM (PDecl PredType)+tcTopPDecl (i, DataDecl p tc tvs cs clss) =+  return (i, DataDecl p tc tvs cs clss)+tcTopPDecl (i, ExternalDataDecl p tc tvs) =+  return (i, ExternalDataDecl p tc tvs)+tcTopPDecl (i, NewtypeDecl p tc tvs nc clss) =+  return (i, NewtypeDecl p tc tvs nc clss)+tcTopPDecl (i, TypeDecl p tc tvs ty) = return (i, TypeDecl p tc tvs ty)+tcTopPDecl (i, DefaultDecl p tys) = return (i, DefaultDecl p tys)+tcTopPDecl (i, ClassDecl p cx cls tv ds) = withLocalSigEnv $ do+  setSigEnv $ foldr (bindTypeSigs . snd) emptySigEnv opds+  vpds' <- mapM (tcClassMethodPDecl (qualify cls) tv) vpds+  return (i, ClassDecl p cx cls tv $ fromPDecls $ map untyped opds ++ vpds')+  where (vpds, opds) = partition (isValueDecl . snd) $ toPDecls ds+tcTopPDecl (i, InstanceDecl p cx qcls ty ds) = do+  tcEnv <- getTyConsEnv+  let ocls = origName $ head $ qualLookupTypeInfo qcls tcEnv+  pty <- expandPoly $ QualTypeExpr cx ty+  vpds' <- mapM (tcInstanceMethodPDecl ocls pty) vpds+  return (i, InstanceDecl p cx qcls ty $ fromPDecls $ map untyped opds ++ vpds')+  where (vpds, opds) = partition (isValueDecl . snd) $ toPDecls ds+tcTopPDecl _ = internalError "Checks.TypeCheck.tcTopDecl"++tcClassMethodPDecl :: QualIdent -> Ident -> PDecl a -> TCM (PDecl PredType)+tcClassMethodPDecl qcls tv pd@(_, FunctionDecl _ _ f _) = do+  methTy <- classMethodType qualify f+  (tySc, pd') <- tcMethodPDecl methTy pd+  sigs <- getSigEnv+  let QualTypeExpr cx ty = fromJust $ lookupTypeSig f sigs+      qty = QualTypeExpr (Constraint qcls (VariableType tv) : cx) ty+  checkClassMethodType qty tySc pd'+tcClassMethodPDecl _ _ _ = internalError "TypeCheck.tcClassMethodPDecl"++tcInstanceMethodPDecl :: QualIdent -> PredType -> PDecl a -> TCM (PDecl PredType)+tcInstanceMethodPDecl qcls pty pd@(_, FunctionDecl _ _ f _) = do+  methTy <- instMethodType (qualifyLike qcls) pty f+  (tySc, pd') <- tcMethodPDecl (typeScheme methTy) pd+  checkInstMethodType (normalize 0 methTy) tySc pd'+tcInstanceMethodPDecl _ _ _ = internalError "TypeCheck.tcInstanceMethodPDecl"++tcMethodPDecl :: TypeScheme -> PDecl a -> TCM (TypeScheme, PDecl PredType)+tcMethodPDecl tySc (i, FunctionDecl p _ f eqs) = withLocalValueEnv $ do+  m <- getModuleIdent+  modifyValueEnv $ bindFun m f True (eqnArity $ head eqs) tySc+  (ps, (ty, pd)) <- tcFunctionPDecl i emptyPredSet tySc p f eqs+  theta <- getTypeSubst+  return (gen Set.empty ps $ subst theta ty, pd)+tcMethodPDecl _ _ = internalError "TypeCheck.tcMethodPDecl"++checkClassMethodType :: QualTypeExpr -> TypeScheme -> PDecl PredType+                     -> TCM (PDecl PredType)+checkClassMethodType qty tySc pd@(_, FunctionDecl p _ f _) = do+  pty <- expandPoly qty+  unlessM (checkTypeSig pty tySc) $ do+    m <- getModuleIdent+    report $ errTypeSigTooGeneral p m (text "Method:" <+> ppIdent f) qty tySc+  return pd+checkClassMethodType _ _ _ = internalError "TypeCheck.checkClassMethodType"++checkInstMethodType :: PredType -> TypeScheme -> PDecl PredType+                    -> TCM (PDecl PredType)+checkInstMethodType pty tySc pd@(_, FunctionDecl p _ f _) = do+  unlessM (checkTypeSig pty tySc) $ do+    m <- getModuleIdent+    report $+      errMethodTypeTooSpecific p m (text "Method:" <+> ppIdent f) pty tySc+  return pd+checkInstMethodType _ _ _ = internalError "TypeCheck.checkInstMethodType"++classMethodType :: (Ident -> QualIdent) -> Ident -> TCM TypeScheme+classMethodType qual f = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  return $ funType m (qual $ unRenameIdent f) vEnv++-- Due to the sorting of the predicate set, we can simply remove the minimum+-- element as this is guaranteed to be the class constraint (see module 'Types'+-- for more information).++instMethodType :: (Ident -> QualIdent) -> PredType -> Ident -> TCM PredType+instMethodType qual (PredType ps ty) f = do+  ForAll _ (PredType ps' ty') <- classMethodType qual f+  let PredType ps'' ty'' = instanceType ty (PredType (Set.deleteMin ps') ty')+  return $ PredType (ps `Set.union` ps'') ty''++-- External functions:++tcExternal :: Ident -> TCM Type+tcExternal f = do+  sigs <- getSigEnv+  case lookupTypeSig f sigs of+    Nothing -> internalError "TypeCheck.tcExternal: type signature not found"+    Just (QualTypeExpr _ ty) -> do+      m <- getModuleIdent+      PredType _ ty' <- expandPoly $ QualTypeExpr [] ty+      modifyValueEnv $ bindFun m f False (arrowArity ty') (polyType ty')+      return ty'++-- Patterns and Expressions:+-- Note that the type attribute associated with a constructor or infix+-- pattern is the type of the whole pattern and not the type of the+-- constructor itself. Overloaded (numeric) literals are not supported in+-- patterns.++tcLiteral :: Bool -> Literal -> TCM (PredSet, Type)+tcLiteral _ (Char _) = return (emptyPredSet, charType)+tcLiteral poly (Int _)+  | poly = freshNumType+  | otherwise = liftM ((,) emptyPredSet) (freshConstrained numTypes)+tcLiteral poly (Float _)+  | poly = freshFractionalType+  | otherwise = liftM ((,) emptyPredSet) (freshConstrained fractionalTypes)+tcLiteral _ (String _) = return (emptyPredSet, stringType)++tcLhs :: Position -> Lhs a -> TCM (PredSet, [Type], Lhs PredType)+tcLhs p (FunLhs f ts) = do+  (pss, tys, ts') <- liftM unzip3 $ mapM (tcPattern p) ts+  return (Set.unions pss, tys, FunLhs f ts')+tcLhs p (OpLhs t1 op t2) = do+  (ps1, ty1, t1') <- tcPattern p t1+  (ps2, ty2, t2') <- tcPattern p t2+  return (ps1 `Set.union` ps2, [ty1, ty2], OpLhs t1' op t2')+tcLhs p (ApLhs lhs ts) = do+  (ps, tys1, lhs') <- tcLhs p lhs+  (pss, tys2, ts') <- liftM unzip3 $ mapM (tcPattern p) ts+  return (Set.unions (ps:pss), tys1 ++ tys2, ApLhs lhs' ts')++-- When computing the type of a variable in a pattern, we ignore the+-- predicate set of the variable's type (which can only be due to a type+-- signature in the same declaration group) for just the same reason as+-- in 'tcFunctionPDecl'. Infix and infix functional patterns are currently+-- checked as constructor and functional patterns, respectively, resulting+-- in slighty misleading error messages if the type check fails.++tcPattern :: Position -> Pattern a -> TCM (PredSet, Type, Pattern PredType)+tcPattern _ (LiteralPattern _ l) = do+  (ps, ty) <- tcLiteral False l+  return (ps, ty, LiteralPattern (predType ty) l)+tcPattern _ (NegativePattern _ l) = do+  (ps, ty) <- tcLiteral False l+  return (ps, ty, NegativePattern (predType ty) l)+tcPattern _ (VariablePattern _ v) = do+  vEnv <- getValueEnv+  (_, ty) <- inst (varType v vEnv)+  return (emptyPredSet, ty, VariablePattern (predType ty) v)+tcPattern p t@(ConstructorPattern _ c ts) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, (tys, ty')) <- liftM (fmap arrowUnapply) (skol (constrType m c vEnv))+  (ps', ts') <- mapAccumM (uncurry . tcPatternArg p "pattern" (ppPattern 0 t)) ps (zip tys ts)+  return (ps', ty', ConstructorPattern (predType ty') c ts')+tcPattern p (InfixPattern a t1 op t2) = do+  (ps, ty, ConstructorPattern a' op' [t1', t2']) <-+    tcPattern p (ConstructorPattern a op [t1, t2])+  return (ps, ty, InfixPattern a' t1' op' t2')+tcPattern p (ParenPattern t) = do+  (ps, ty, t') <- tcPattern p t+  return (ps, ty, ParenPattern t')+tcPattern _ t@(RecordPattern _ c fs) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- liftM (fmap arrowBase) (skol (constrType m c vEnv))+  (ps', fs') <- mapAccumM (tcField tcPattern "pattern" (\t' -> ppPattern 0 t $-$ text "Term:" <+> ppPattern 0 t') ty) ps fs+  return (ps', ty, RecordPattern (predType ty) c fs')+tcPattern p (TuplePattern ts) = do+  (pss, tys, ts') <- liftM unzip3 $ mapM (tcPattern p) ts+  return (Set.unions pss, tupleType tys, TuplePattern ts')+tcPattern p t@(ListPattern _ ts) = do+  ty <- freshTypeVar+  (ps, ts') <- mapAccumM (flip (tcPatternArg p "pattern" (ppPattern 0 t)) ty) emptyPredSet ts+  return (ps, listType ty, ListPattern (predType $ listType ty) ts')+tcPattern p t@(AsPattern v t') = do+  vEnv <- getValueEnv+  (_, ty) <- inst (varType v vEnv)+  (ps, t'') <- tcPattern p t' >>-+    unify p "pattern" (ppPattern 0 t) emptyPredSet ty+  return (ps, ty, AsPattern v t'')+tcPattern p (LazyPattern t) = do+  (ps, ty, t') <- tcPattern p t+  return (ps, ty, LazyPattern t')+tcPattern p t@(FunctionPattern _ f ts) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- inst (funType m f vEnv)+  tcFuncPattern p (ppPattern 0 t) f id ps ty ts+tcPattern p (InfixFuncPattern a t1 op t2) = do+  (ps, ty, FunctionPattern a' op' [t1', t2']) <-+    tcPattern p (FunctionPattern a op [t1, t2])+  return (ps, ty, InfixFuncPattern a' t1' op' t2')++tcFuncPattern :: Position -> Doc -> QualIdent+              -> ([Pattern PredType] -> [Pattern PredType])+              -> PredSet -> Type -> [Pattern a]+              -> TCM (PredSet, Type, Pattern PredType)+tcFuncPattern _ _ f ts ps ty [] =+  return (ps, ty, FunctionPattern (predType ty) f (ts []))+tcFuncPattern p doc f ts ps ty (t':ts') = do+  (alpha, beta) <-+    tcArrow p "functional pattern" (doc $-$ text "Term:" <+> ppPattern 0 t) ty+  (ps', t'') <- tcPatternArg p "functional pattern" doc ps alpha t'+  tcFuncPattern p doc f (ts . (t'' :)) ps' beta ts'+  where t = FunctionPattern (predType ty) f (ts [])++tcPatternArg :: Position -> String -> Doc -> PredSet -> Type+             -> Pattern a -> TCM (PredSet, Pattern PredType)+tcPatternArg p what doc ps ty t =+  tcPattern p t >>-+    unify p what (doc $-$ text "Term:" <+> ppPattern 0 t) ps ty++tcRhs :: Rhs a -> TCM (PredSet, Type, Rhs PredType)+tcRhs (SimpleRhs p e ds) = do+  (ps, ds', ps', ty, e') <- withLocalValueEnv $ do+    (ps, ds') <- tcDecls ds+    (ps', ty, e') <- tcExpr p e+    return (ps, ds', ps', ty, e')+  ps'' <- reducePredSet p "expression" (ppExpr 0 e') (ps `Set.union` ps')+  return (ps'', ty, SimpleRhs p e' ds')+tcRhs (GuardedRhs es ds) = withLocalValueEnv $ do+  (ps, ds') <- tcDecls ds+  ty <- freshTypeVar+  (ps', es') <- mapAccumM (tcCondExpr ty) ps es+  return (ps', ty, GuardedRhs es' ds')++tcCondExpr :: Type -> PredSet -> CondExpr a -> TCM (PredSet, CondExpr PredType)+tcCondExpr ty ps (CondExpr p g e) = do+  (ps', g') <- tcExpr p g >>- unify p "guard" (ppExpr 0 g) ps boolType+  (ps'', e') <- tcExpr p e >>- unify p "guarded expression" (ppExpr 0 e) ps' ty+  return (ps'', CondExpr p g' e')++tcExpr :: Position -> Expression a -> TCM (PredSet, Type, Expression PredType)+tcExpr _ (Literal _ l) = do+  (ps, ty) <- tcLiteral True l+  return (ps, ty, Literal (predType ty) l)+tcExpr _ (Variable _ v) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- if isAnonId (unqualify v) then freshPredType []+                                        else inst (funType m v vEnv)+  return (ps, ty, Variable (predType ty) v)+tcExpr _ (Constructor _ c) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- instExist (constrType m c vEnv)+  return (ps, ty, Constructor (predType ty) c)+tcExpr p (Paren e) = do+  (ps, ty, e') <- tcExpr p e+  return (ps, ty, Paren e')+tcExpr p (Typed e qty) = do+  pty <- expandPoly qty+  (ps, ty) <- inst (typeScheme pty)+  (ps', e') <- tcExpr p e >>-+    unifyDecl p "explicitly typed expression" (ppExpr 0 e) emptyPredSet ty+  fvs <- computeFvEnv+  theta <- getTypeSubst+  let (gps, lps) = splitPredSet fvs ps'+      tySc = gen fvs lps (subst theta ty)+  unlessM (checkTypeSig pty tySc) $ do+    m <- getModuleIdent+    report $+      errTypeSigTooGeneral p m (text "Expression:" <+> ppExpr 0 e) qty tySc+  return (ps `Set.union` gps, ty, Typed e' qty)+tcExpr _ e@(Record _ c fs) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- liftM (fmap arrowBase) (instExist (constrType m c vEnv))+  (ps', fs') <- mapAccumM (tcField tcExpr "construction" (\e' -> ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e') ty) ps fs+  return (ps', ty, Record (predType ty) c fs')+tcExpr p e@(RecordUpdate e1 fs) = do+  (ps, ty, e1') <- tcExpr p e1+  (ps', fs') <- mapAccumM (tcField tcExpr "update" (\e' -> ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e') ty) ps fs+  return (ps', ty, RecordUpdate e1' fs')+tcExpr p (Tuple es) = do+  (pss, tys, es') <- liftM unzip3 $ mapM (tcExpr p) es+  return (Set.unions pss, tupleType tys, Tuple es')+tcExpr p e@(List _ es) = do+  ty <- freshTypeVar+  (ps, es') <-+    mapAccumM (flip (tcArg p "expression" (ppExpr 0 e)) ty) emptyPredSet es+  return (ps, listType ty, List (predType $ listType ty) es')+tcExpr p (ListCompr e qs) = do+  fs <- computeFsEnv+  (ps, qs', ps', ty, e') <- withLocalValueEnv $ do+    (ps, qs') <- mapAccumM (tcQual p) emptyPredSet qs+    (ps', ty, e') <- tcExpr p e+    return (ps, qs', ps', ty, e')+  ps'' <- reducePredSet p "expression" (ppExpr 0 e') (ps `Set.union` ps')+  checkSkolems p "Expression" (ppExpr 0) fs ps'' (listType ty)+    (ListCompr e' qs')+tcExpr p e@(EnumFrom e1) = do+  (ps, ty) <- freshEnumType+  (ps', e1') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps ty e1+  return (ps', listType ty, EnumFrom e1')+tcExpr p e@(EnumFromThen e1 e2) = do+  (ps, ty) <- freshEnumType+  (ps', e1') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps ty e1+  (ps'', e2') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps' ty e2+  return (ps'', listType ty, EnumFromThen e1' e2')+tcExpr p e@(EnumFromTo e1 e2) = do+  (ps, ty) <- freshEnumType+  (ps', e1') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps ty e1+  (ps'', e2') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps' ty e2+  return (ps'', listType ty, EnumFromTo e1' e2')+tcExpr p e@(EnumFromThenTo e1 e2 e3) = do+  (ps, ty) <- freshEnumType+  (ps', e1') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps ty e1+  (ps'', e2') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps' ty e2+  (ps''', e3') <- tcArg p "arithmetic sequence" (ppExpr 0 e) ps'' ty e3+  return (ps''', listType ty, EnumFromThenTo e1' e2' e3')+tcExpr p e@(UnaryMinus e1) = do+  (ps, ty) <- freshNumType+  (ps', e1') <- tcArg p "unary negation" (ppExpr 0 e) ps ty e1+  return (ps', ty, UnaryMinus e1')+tcExpr p e@(Apply e1 e2) = do+  (ps, (alpha, beta), e1') <- tcExpr p e1 >>=-+    tcArrow p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)+  (ps', e2') <- tcArg p "application" (ppExpr 0 e) ps alpha e2+  return (ps', beta, Apply e1' e2')+tcExpr p e@(InfixApply e1 op e2) = do+  (ps, (alpha, beta, gamma), op') <- tcInfixOp op >>=-+    tcBinary p "infix application" (ppExpr 0 e $-$ text "Operator:" <+> ppOp op)+  (ps', e1') <- tcArg p "infix application" (ppExpr 0 e) ps alpha e1+  (ps'', e2') <- tcArg p "infix application" (ppExpr 0 e) ps' beta e2+  return (ps'', gamma, InfixApply e1' op' e2')+tcExpr p e@(LeftSection e1 op) = do+  (ps, (alpha, beta), op') <- tcInfixOp op >>=-+    tcArrow p "left section" (ppExpr 0 e $-$ text "Operator:" <+> ppOp op)+  (ps', e1') <- tcArg p "left section" (ppExpr 0 e) ps alpha e1+  return (ps', beta, LeftSection e1' op')+tcExpr p e@(RightSection op e1) = do+  (ps, (alpha, beta, gamma), op') <- tcInfixOp op >>=-+    tcBinary p "right section" (ppExpr 0 e $-$ text "Operator:" <+> ppOp op)+  (ps', e1') <- tcArg p "right section" (ppExpr 0 e) ps beta e1+  return (ps', TypeArrow alpha gamma, RightSection op' e1')+tcExpr p (Lambda ts e) = do+  fs <- computeFsEnv+  (pss, tys, ts', ps, ty, e')<- withLocalValueEnv $ do+    bindLambdaVars ts+    (pss, tys, ts') <- liftM unzip3 $ mapM (tcPattern p) ts+    (ps, ty, e') <- tcExpr p e+    return (pss, tys, ts', ps, ty, e')+  ps' <- reducePredSet p "expression" (ppExpr 0 e') (Set.unions $ ps : pss)+  checkSkolems p "Expression" (ppExpr 0) fs ps' (foldr TypeArrow ty tys)+    (Lambda ts' e')+tcExpr p (Let ds e) = do+  fs <- computeFsEnv+  (ps, ds', ps', ty, e') <- withLocalValueEnv $ do+    (ps, ds') <- tcDecls ds+    (ps', ty, e') <- tcExpr p e+    return (ps, ds', ps', ty, e')+  ps'' <- reducePredSet p "expression" (ppExpr 0 e') (ps `Set.union` ps')+  checkSkolems p "Expression" (ppExpr 0) fs ps'' ty (Let ds' e')+tcExpr p (Do sts e) = do+  fs <- computeFsEnv+  (sts', ty, ps', e') <- withLocalValueEnv $ do+    ((ps, mTy), sts') <-+      mapAccumM (uncurry (tcStmt p)) (emptyPredSet, Nothing) sts+    ty <- liftM (maybe id TypeApply mTy) freshTypeVar+    (ps', e') <- tcExpr p e >>- unify p "statement" (ppExpr 0 e) ps ty+    return (sts', ty, ps', e')+  checkSkolems p "Expression" (ppExpr 0) fs ps' ty (Do sts' e')+tcExpr p e@(IfThenElse e1 e2 e3) = do+  (ps, e1') <- tcArg p "expression" (ppExpr 0 e) emptyPredSet boolType e1+  (ps', ty, e2') <- tcExpr p e2+  (ps'', e3') <- tcArg p "expression" (ppExpr 0 e) (ps `Set.union` ps') ty e3+  return (ps'', ty, IfThenElse e1' e2' e3')+tcExpr p (Case ct e as) = do+  (ps, tyLhs, e') <- tcExpr p e+  tyRhs <- freshTypeVar+  fs <- computeFsEnv+  (ps', as') <- mapAccumM (tcAlt fs tyLhs tyRhs) ps as+  return (ps', tyRhs, Case ct e' as')++tcArg :: Position -> String -> Doc -> PredSet -> Type -> Expression a+      -> TCM (PredSet, Expression PredType)+tcArg p what doc ps ty e =+  tcExpr p e >>- unify p what (doc $-$ text "Term:" <+> ppExpr 0 e) ps ty++tcAlt :: Set.Set Int -> Type -> Type -> PredSet -> Alt a+      -> TCM (PredSet, Alt PredType)+tcAlt fs tyLhs tyRhs ps a@(Alt p t rhs) =+  tcAltern fs tyLhs p t rhs >>-+    unify p "case alternative" (ppAlt a) ps tyRhs++tcAltern :: Set.Set Int -> Type -> Position -> Pattern a+         -> Rhs a -> TCM (PredSet, Type, Alt PredType)+tcAltern fs tyLhs p t rhs = do+  (ps, t', ps', ty', rhs') <- withLocalValueEnv $ do+    bindLambdaVars t+    (ps, t') <-+      tcPatternArg p "case pattern" (ppAlt (Alt p t rhs)) emptyPredSet tyLhs t+    (ps', ty', rhs') <- tcRhs rhs+    return (ps, t', ps', ty', rhs')+  ps'' <- reducePredSet p "alternative" (ppAlt (Alt p t' rhs')) (ps `Set.union` ps')+  checkSkolems p "Alternative" ppAlt fs ps'' ty' (Alt p t' rhs')++tcQual :: Position -> PredSet -> Statement a+       -> TCM (PredSet, Statement PredType)+tcQual p ps (StmtExpr e) = do+  (ps', e') <- tcExpr p e >>- unify p "guard" (ppExpr 0 e) ps boolType+  return (ps', StmtExpr e')+tcQual _ ps (StmtDecl ds) = do+  (ps', ds') <- tcDecls ds+  return (ps `Set.union` ps', StmtDecl ds')+tcQual p ps q@(StmtBind t e) = do+  alpha <- freshTypeVar+  (ps', e') <- tcArg p "generator" (ppStmt q) ps (listType alpha) e+  bindLambdaVars t+  (ps'', t') <- tcPatternArg p "generator" (ppStmt q) ps' alpha t+  return (ps'', StmtBind t' e')++tcStmt :: Position -> PredSet -> Maybe Type -> Statement a+       -> TCM ((PredSet, Maybe Type), Statement PredType)+tcStmt p ps mTy (StmtExpr e) = do+  (ps', ty) <- maybe freshMonadType (return . (,) emptyPredSet) mTy+  alpha <- freshTypeVar+  (ps'', e') <- tcExpr p e >>-+    unify p "statement" (ppExpr 0 e) (ps `Set.union` ps') (applyType ty [alpha])+  return ((ps'', Just ty), StmtExpr e')+tcStmt _ ps mTy (StmtDecl ds) = do+  (ps', ds') <- tcDecls ds+  return ((ps `Set.union` ps', mTy), StmtDecl ds')+tcStmt p ps mTy st@(StmtBind t e) = do+  (ps', ty) <- maybe freshMonadType (return . (,) emptyPredSet) mTy+  alpha <- freshTypeVar+  (ps'', e') <-+    tcArg p "statement" (ppStmt st) (ps `Set.union` ps') (applyType ty [alpha]) e+  bindLambdaVars t+  (ps''', t') <- tcPatternArg p "statement" (ppStmt st) ps'' alpha t+  return ((ps''', Just ty), StmtBind t' e')++tcInfixOp :: InfixOp a -> TCM (PredSet, Type, InfixOp PredType)+tcInfixOp (InfixOp _ op) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- inst (funType m op vEnv)+  return (ps, ty, InfixOp (predType ty) op)+tcInfixOp (InfixConstr _ op) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps, ty) <- instExist (constrType m op vEnv)+  return (ps, ty, InfixConstr (predType ty) op)++-- The first unification in 'tcField' cannot fail; it serves only for+-- instantiating the type variables in the field label's type.++tcField :: (Position -> a b -> TCM (PredSet, Type, a PredType))+        -> String -> (a b -> Doc) -> Type -> PredSet -> Field (a b)+        -> TCM (PredSet, Field (a PredType))+tcField check what doc ty ps (Field p l x) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  (ps', TypeArrow ty1 ty2) <- inst (labelType m l vEnv)+  _ <- unify p "field label" empty emptyPredSet ty emptyPredSet ty1+  (ps'', x') <- check p x >>-+    unify p ("record " ++ what) (doc x) (ps `Set.union` ps') ty2+  return (ps'', Field p l x')++-- The function 'tcArrow' checks that its argument can be used as+-- an arrow type a -> b and returns the pair (a,b).++tcArrow :: Position -> String -> Doc -> Type -> TCM (Type, Type)+tcArrow p what doc ty = do+  theta <- getTypeSubst+  unaryArrow (subst theta ty)+  where+  unaryArrow (TypeArrow ty1 ty2) = return (ty1, ty2)+  unaryArrow (TypeVariable   tv) = do+    alpha <- freshTypeVar+    beta  <- freshTypeVar+    modifyTypeSubst $ bindVar tv $ TypeArrow alpha beta+    return (alpha, beta)+  unaryArrow ty'                 = do+    m <- getModuleIdent+    report $ errNonFunctionType p what doc m ty'+    (,) <$> freshTypeVar <*> freshTypeVar++-- The function 'tcBinary' checks that its argument can be used as an arrow type+-- a -> b -> c and returns the triple (a,b,c).++tcBinary :: Position -> String -> Doc -> Type -> TCM (Type, Type, Type)+tcBinary p what doc ty = tcArrow p what doc ty >>= uncurry binaryArrow+  where+  binaryArrow ty1 (TypeArrow ty2 ty3) = return (ty1, ty2, ty3)+  binaryArrow ty1 (TypeVariable   tv) = do+    beta  <- freshTypeVar+    gamma <- freshTypeVar+    modifyTypeSubst $ bindVar tv $ TypeArrow beta gamma+    return (ty1, beta, gamma)+  binaryArrow ty1 ty2                 = do+    m <- getModuleIdent+    report $ errNonBinaryOp p what doc m (TypeArrow ty1 ty2)+    (,,) <$> return ty1 <*> freshTypeVar <*> freshTypeVar++-- Unification: The unification uses Robinson's algorithm.++unify :: Position -> String -> Doc -> PredSet -> Type -> PredSet -> Type+      -> TCM PredSet+unify p what doc ps1 ty1 ps2 ty2 = do+  theta <- getTypeSubst+  let ty1' = subst theta ty1+      ty2' = subst theta ty2+  m <- getModuleIdent+  case unifyTypes m ty1' ty2' of+    Left reason -> report $ errTypeMismatch p what doc m ty1' ty2' reason+    Right sigma -> modifyTypeSubst (compose sigma)+  reducePredSet p what doc $ ps1 `Set.union` ps2++unifyTypes :: ModuleIdent -> Type -> Type -> Either Doc TypeSubst+unifyTypes _ (TypeVariable tv1) (TypeVariable tv2)+  | tv1 == tv2            = Right idSubst+  | otherwise             = Right (singleSubst tv1 (TypeVariable tv2))+unifyTypes m (TypeVariable tv) ty+  | tv `elem` typeVars ty = Left  (errRecursiveType m tv ty)+  | otherwise             = Right (singleSubst tv ty)+unifyTypes m ty (TypeVariable tv)+  | tv `elem` typeVars ty = Left  (errRecursiveType m tv ty)+  | otherwise             = Right (singleSubst tv ty)+unifyTypes _ (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2)+  | tv1  == tv2           = Right idSubst+  | tys1 == tys2          = Right (singleSubst tv1 (TypeConstrained tys2 tv2))+unifyTypes m (TypeConstrained tys tv) ty =+  foldr (choose . unifyTypes m ty) (Left (errIncompatibleTypes m ty (head tys)))+        tys+  where choose (Left _) theta' = theta'+        choose (Right theta) _ = Right (bindSubst tv ty theta)+unifyTypes m ty (TypeConstrained tys tv) =+  foldr (choose . unifyTypes m ty) (Left (errIncompatibleTypes m ty (head tys)))+        tys+  where choose (Left _) theta' = theta'+        choose (Right theta) _ = Right (bindSubst tv ty theta)+unifyTypes _ (TypeConstructor tc1) (TypeConstructor tc2)+  | tc1 == tc2 = Right idSubst+unifyTypes m (TypeApply ty11 ty12) (TypeApply ty21 ty22) =+  unifyTypeLists m [ty11, ty12] [ty21, ty22]+unifyTypes m ty1@(TypeApply _ _) (TypeArrow ty21 ty22) =+  unifyTypes m ty1 (TypeApply (TypeApply (TypeConstructor qArrowId) ty21) ty22)+unifyTypes m (TypeArrow ty11 ty12) ty2@(TypeApply _ _) =+  unifyTypes m (TypeApply (TypeApply (TypeConstructor qArrowId) ty11) ty12) ty2+unifyTypes m (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =+  unifyTypeLists m [ty11, ty12] [ty21, ty22]+unifyTypes _ (TypeSkolem k1) (TypeSkolem k2)+  | k1 == k2 = Right idSubst+unifyTypes m ty1 ty2 = Left (errIncompatibleTypes m ty1 ty2)++unifyTypeLists :: ModuleIdent -> [Type] -> [Type] -> Either Doc TypeSubst+unifyTypeLists _ []           _            = Right idSubst+unifyTypeLists _ _            []           = Right idSubst+unifyTypeLists m (ty1 : tys1) (ty2 : tys2) =+  either Left unifyTypesTheta (unifyTypeLists m tys1 tys2)+  where+    unifyTypesTheta theta =+      either Left (Right . flip compose theta)+                  (unifyTypes m (subst theta ty1) (subst theta ty2))++-- After performing a unification, the resulting substitution is applied+-- to the current predicate set and the resulting predicate set is subject+-- to a reduction. This predicate set reduction retains all predicates whose+-- types are simple variables and which are not implied but other+-- predicates in the predicate set. For all other predicates, the compiler+-- checks whether an instance exists and replaces them by applying the+-- instances' predicate set to the respective types. A minor complication+-- arises due to constrained types, which at present are used to+-- implement overloading of guard expressions and of numeric literals in+-- patterns. The set of admissible types of a constrained type may be+-- restricted by the current predicate set after the reduction and thus+-- may cause a further extension of the current type substitution.++reducePredSet :: Position -> String -> Doc -> PredSet -> TCM PredSet+reducePredSet p what doc ps = do+  m <- getModuleIdent+  clsEnv <- getClassEnv+  theta <- getTypeSubst+  inEnv <- (fmap $ fmap $ subst theta) <$> getInstEnv+  let ps' = subst theta ps+      (ps1, ps2) = partitionPredSet $ minPredSet clsEnv $ reducePreds inEnv ps'+  theta' <-+    foldM (reportMissingInstance m p what doc inEnv) idSubst $ Set.toList ps2+  modifyTypeSubst $ compose theta'+  return ps1+  where+    reducePreds inEnv = Set.concatMap $ reducePred inEnv+    reducePred inEnv pr@(Pred qcls ty) =+      maybe (Set.singleton pr) (reducePreds inEnv) (instPredSet inEnv qcls ty)++instPredSet :: InstEnv' -> QualIdent -> Type -> Maybe PredSet+instPredSet inEnv qcls ty = case Map.lookup qcls $ snd inEnv of+  Just tys | ty `elem` tys -> Just emptyPredSet+  _ -> case unapplyType False ty of+    (TypeConstructor tc, tys) ->+      fmap (expandAliasType tys . snd3) (lookupInstInfo (qcls, tc) $ fst inEnv)+    _ -> Nothing++reportMissingInstance :: ModuleIdent -> Position -> String -> Doc -> InstEnv'+                      -> TypeSubst -> Pred -> TCM TypeSubst+reportMissingInstance m p what doc inEnv theta (Pred qcls ty) =+  case subst theta ty of+    ty'@(TypeConstrained tys tv) ->+      case filter (hasInstance inEnv qcls) tys of+        [] -> do+          report $ errMissingInstance m p what doc (Pred qcls ty')+          return theta+        [ty''] -> return (bindSubst tv ty'' theta)+        tys'+          | length tys == length tys' -> return theta+          | otherwise ->+              liftM (flip (bindSubst tv) theta) (freshConstrained tys')+    ty'+      | hasInstance inEnv qcls ty' -> return theta+      | otherwise -> do+        report $ errMissingInstance m p what doc (Pred qcls ty')+        return theta++hasInstance :: InstEnv' -> QualIdent -> Type -> Bool+hasInstance inEnv qcls = isJust . instPredSet inEnv qcls++-- When a constrained type variable that is not free in the type environment+-- disappears from the current type, the type becomes ambiguous. For instance,+-- the type of the expression+--+-- let x = read "" in show x+--+-- is ambiguous assuming that 'read' and 'show' have types+--+-- read :: Read a => String -> a+-- show :: Show a => a -> String+--+-- because the compiler cannot determine which 'Read' and 'Show' instances to+-- use.+--+-- In the case of expressions with an ambiguous numeric type, i.e., a type that+-- must be an instance of 'Num' or one of its subclasses, the compiler tries to+-- resolve the ambiguity by choosing the first type from the list of default+-- types that satisfies all constraints for the ambiguous type variable. An+-- error is reported if no such type exists.++applyDefaults :: Position -> String -> Doc -> Set.Set Int -> PredSet -> Type+              -> TCM PredSet+applyDefaults p what doc fvs ps ty = do+  m <- getModuleIdent+  clsEnv <- getClassEnv+  inEnv <- getInstEnv+  defs <- getDefaultTypes+  let theta = foldr (bindDefault defs inEnv ps) idSubst $ nub+                [ tv | Pred qcls (TypeVariable tv) <- Set.toList ps+                     , tv `Set.notMember` fvs, isNumClass clsEnv qcls ]+      ps'   = fst (partitionPredSet (subst theta ps))+      ty'   = subst theta ty+      tvs'  = nub $ filter (`Set.notMember` fvs) (typeVars ps')+  mapM_ (report . errAmbiguousTypeVariable m p what doc ps' ty') tvs'+  modifyTypeSubst $ compose theta+  return ps'++bindDefault :: [Type] -> InstEnv' -> PredSet -> Int -> TypeSubst -> TypeSubst+bindDefault defs inEnv ps tv =+  case foldr (defaultType inEnv tv) defs (Set.toList ps) of+    [] -> id+    ty:_ -> bindSubst tv ty++defaultType :: InstEnv' -> Int -> Pred -> [Type] -> [Type]+defaultType inEnv tv (Pred qcls (TypeVariable tv'))+  | tv == tv' = filter (hasInstance inEnv qcls)+  | otherwise = id+defaultType _ _ _ = id++isNumClass :: ClassEnv -> QualIdent -> Bool+isNumClass = (elem qNumId .) . flip allSuperClasses++-- Whenever type inference succeeds for a function equation, case alternative,+-- etc., which may open an existentially quantified data type and thus bring+-- fresh skolem constants into scope, the compiler checks that none of those+-- skolem constants escape their scope through the result type or the type+-- environment. E.g., for the program+--+-- data Key a = forall b . Key b (b -> a)+-- f (Key x _) = x+-- g k x = fcase k of { Key _ f -> f x }+--+-- a skolem constant escapes in the (result) type of 'f' and in the type of the+-- environment variable 'x' for the fcase expression in the definition of 'g'.++checkSkolems :: Position -> String -> (a -> Doc) -> Set.Set Int -> PredSet+             -> Type -> a -> TCM (PredSet, Type, a)+checkSkolems p what pp fs ps ty x = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  theta <- getTypeSubst+  let escape = any (`Set.notMember` fs) . typeSkolems . snd+      esc    = filter escape $ [ (v, subst theta pty)+                               | (v, pty) <- (empty, PredType ps ty) : ptys ]+      ptys   = [ (text "Variable:" <+> ppIdent v, pty)+               | (v, Value _ _ _ (ForAll _ pty)) <- localBindings vEnv ]+  mapM_ (report . errSkolemEscapingScope p m what (pp x)) esc+  return (ps, ty, x)++-- Instantiation and Generalization:+-- We use negative offsets for fresh type variables.++fresh :: (Int -> a) -> TCM a+fresh f = f <$> getNextId++freshVar :: (Int -> a) -> TCM a+freshVar f = fresh $ \n -> f (- n)++freshTypeVar :: TCM Type+freshTypeVar = freshVar TypeVariable++freshPredType :: [QualIdent] -> TCM (PredSet, Type)+freshPredType qclss = do+  ty <- freshTypeVar+  return (foldr (\qcls -> Set.insert $ Pred qcls ty) emptyPredSet qclss, ty)++freshEnumType :: TCM (PredSet, Type)+freshEnumType = freshPredType [qEnumId]++freshNumType :: TCM (PredSet, Type)+freshNumType = freshPredType [qNumId]++freshFractionalType :: TCM (PredSet, Type)+freshFractionalType = freshPredType [qFractionalId]++freshMonadType :: TCM (PredSet, Type)+freshMonadType = freshPredType [qMonadId]++freshConstrained :: [Type] -> TCM Type+freshConstrained = freshVar . TypeConstrained++freshSkolem :: TCM Type+freshSkolem = fresh TypeSkolem++inst :: TypeScheme -> TCM (PredSet, Type)+inst (ForAll n (PredType ps ty)) = do+  tys <- replicateM n freshTypeVar+  return (expandAliasType tys ps, expandAliasType tys ty)++instExist :: ExistTypeScheme -> TCM (PredSet, Type)+instExist (ForAllExist n n' (PredType ps ty)) = do+  tys <- replicateM (n + n') freshTypeVar+  return (expandAliasType tys ps, expandAliasType tys ty)++-- The function 'skol' instantiates the type of data and newtype+-- constructors in patterns. All universally quantified type variables+-- are instantiated with fresh type variables and all existentially+-- quantified type variables are instantiated with fresh skolem types.+-- All constraints that appear on the right hand side of the+-- constructor's declaration are added to the dynamic instance+-- environment.++skol :: ExistTypeScheme -> TCM (PredSet, Type)+skol (ForAllExist n n' (PredType ps ty)) = do+  tys <- replicateM n freshTypeVar+  tys' <- replicateM n' freshSkolem+  let tys'' = tys ++ tys'+  clsEnv <- getClassEnv+  modifyInstEnv $+    fmap $ bindSkolemInsts $ expandAliasType tys'' $ maxPredSet clsEnv ps+  return (emptyPredSet, expandAliasType tys'' ty)+  where bindSkolemInsts = flip (foldr bindSkolemInst) . Set.toList+        bindSkolemInst (Pred qcls ty') dInEnv =+          Map.insert qcls (ty' : fromMaybe [] (Map.lookup qcls dInEnv)) dInEnv++-- The function 'gen' generalizes a predicate set ps and a type tau into+-- a type scheme forall alpha . ps -> tau by universally quantifying all+-- type variables that are free in tau and not fixed by the environment.+-- The set of the latter is given by gvs.++gen :: Set.Set Int -> PredSet -> Type -> TypeScheme+gen gvs ps ty = ForAll (length tvs) (subst theta (PredType ps ty))+  where tvs = [tv | tv <- nub (typeVars ty), tv `Set.notMember` gvs]+        tvs' = map TypeVariable [0 ..]+        theta = foldr2 bindSubst idSubst tvs tvs'++-- Auxiliary Functions:+-- The functions 'constrType', 'varType', 'funType' and 'labelType' are used+-- to retrieve the type of constructors, pattern variables, variables and+-- labels in expressions, respectively, from the value environment. Because+-- the syntactical correctness has already been verified by the syntax checker,+-- none of these functions should fail.++-- Note that 'varType' can handle ambiguous identifiers and returns the first+-- available type. This function is used for looking up the type of an+-- identifier on the left hand side of a rule where it unambiguously refers+-- to the local definition.++-- The function 'constrLabels' returns a list of all labels belonging to a+-- data constructor. The function 'varArity' works like 'varType' but returns+-- a variable's arity instead of its type.++constrType :: ModuleIdent -> QualIdent -> ValueEnv -> ExistTypeScheme+constrType m c vEnv = case qualLookupValue c vEnv of+  [DataConstructor  _ _ _ tySc] -> tySc+  [NewtypeConstructor _ _ tySc] -> tySc+  _ -> case qualLookupValue (qualQualify m c) vEnv of+    [DataConstructor  _ _ _ tySc] -> tySc+    [NewtypeConstructor _ _ tySc] -> tySc+    _ -> internalError $ "TypeCheck.constrType: " ++ show c++constrLabels :: ModuleIdent -> QualIdent -> ValueEnv -> [Ident]+constrLabels m c vEnv = case qualLookupValue c vEnv of+  [DataConstructor _ _ ls _] -> ls+  [NewtypeConstructor _ l _] -> [l]+  _ -> case qualLookupValue (qualQualify m c) vEnv of+    [DataConstructor _ _ ls _] -> ls+    [NewtypeConstructor _ l _] -> [l]+    _ -> internalError $ "TypeCheck.constrLabels: " ++ show c++varType :: Ident -> ValueEnv -> TypeScheme+varType v vEnv = case lookupValue v vEnv of+  Value _ _ _ tySc : _ -> tySc+  _ -> internalError $ "TypeCheck.varType: " ++ show v++varArity :: QualIdent -> ValueEnv -> Int+varArity v vEnv = case qualLookupValue v vEnv of+  Value _ _ n _ : _ -> n+  Label   _ _ _ : _ -> 1+  _ -> internalError $ "TypeCheck.varArity: " ++ show v++funType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme+funType m f vEnv = case qualLookupValue f vEnv of+  [Value _ _ _ tySc] -> tySc+  [Label _ _ tySc] -> tySc+  _ -> case qualLookupValue (qualQualify m f) vEnv of+    [Value _ _ _ tySc] -> tySc+    [Label _ _ tySc] -> tySc+    _ -> internalError $ "TypeCheck.funType: " ++ show f++labelType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme+labelType m l vEnv = case qualLookupValue l vEnv of+  [Label _ _ tySc] -> tySc+  _ -> case qualLookupValue (qualQualify m l) vEnv of+    [Label _ _ tySc] -> tySc+    _ -> internalError $ "TypeCheck.labelType: " ++ show l++-- The function 'expandPoly' handles the expansion of type aliases.++expandPoly :: QualTypeExpr -> TCM PredType+expandPoly qty = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  clsEnv <- getClassEnv+  return $ expandPolyType m tcEnv clsEnv qty++-- The function 'splitPredSet' splits a predicate set into a pair of predicate+-- set such that all type variables that appear in the types of the predicates+-- in the first predicate set are elements of a given set of type variables.++splitPredSet :: Set.Set Int -> PredSet -> (PredSet, PredSet)+splitPredSet fvs = Set.partition (all (`Set.member` fvs) . typeVars)++-- The functions 'fvEnv' and 'fsEnv' compute the set of free type variables+-- and free skolems of a type environment, respectively. We ignore the types+-- of data constructors here because we know that they are closed.++fvEnv :: ValueEnv -> Set.Set Int+fvEnv vEnv =+  Set.fromList [tv | tySc <- localTypes vEnv, tv <- typeVars tySc, tv < 0]++computeFvEnv :: TCM (Set.Set Int)+computeFvEnv = do+  theta <- getTypeSubst+  vEnv <- getValueEnv+  return $ fvEnv (subst theta vEnv)++fsEnv :: ValueEnv -> Set.Set Int+fsEnv = Set.unions . map (Set.fromList . typeSkolems) . localTypes++computeFsEnv :: TCM (Set.Set Int)+computeFsEnv = do+  theta <- getTypeSubst+  vEnv <- getValueEnv+  return $ fsEnv (subst theta vEnv)++localTypes :: ValueEnv -> [TypeScheme]+localTypes vEnv = [tySc | (_, Value _ _ _ tySc) <- localBindings vEnv]++-- ---------------------------------------------------------------------------+-- Error functions+-- ---------------------------------------------------------------------------++errPolymorphicVar :: Ident -> Message+errPolymorphicVar v = posMessage v $ hsep $ map text+  ["Variable", idName v, "has a polymorphic type"]++errTypeSigTooGeneral :: Position -> ModuleIdent -> Doc -> QualTypeExpr+                     -> TypeScheme -> Message+errTypeSigTooGeneral p m what qty tySc = posMessage p $ vcat+  [ text "Type signature too general", what+  , text "Inferred type:"  <+> ppTypeScheme m tySc+  , text "Type signature:" <+> ppQualTypeExpr qty+  ]++errMethodTypeTooSpecific :: Position -> ModuleIdent -> Doc -> PredType+                         -> TypeScheme -> Message+errMethodTypeTooSpecific p m what pty tySc = posMessage p $ vcat+  [ text "Method type too specific", what+  , text "Inferred type:" <+> ppTypeScheme m tySc+  , text "Expected type:" <+> ppPredType m pty+  ]++errNonFunctionType :: Position -> String -> Doc -> ModuleIdent -> Type+                   -> Message+errNonFunctionType p what doc m ty = posMessage p $ vcat+  [ text "Type error in" <+> text what, doc+  , text "Type:" <+> ppType m ty+  , text "Cannot be applied"+  ]++errNonBinaryOp :: Position -> String -> Doc -> ModuleIdent -> Type -> Message+errNonBinaryOp p what doc m ty = posMessage p $ vcat+  [ text "Type error in" <+> text what, doc+  , text "Type:" <+> ppType m ty+  , text "Cannot be used as binary operator"+  ]++errTypeMismatch :: Position -> String -> Doc -> ModuleIdent -> Type -> Type+                -> Doc -> Message+errTypeMismatch p what doc m ty1 ty2 reason = posMessage p $ vcat+  [ text "Type error in"  <+> text what, doc+  , text "Inferred type:" <+> ppType m ty2+  , text "Expected type:" <+> ppType m ty1+  , reason+  ]++errSkolemFieldLabel :: Position -> Ident -> Message+errSkolemFieldLabel p l = posMessage p $ hsep $ map text+  ["Existential type escapes with type of record selector", escName l]++errSkolemEscapingScope :: Position -> ModuleIdent -> String -> Doc+                       -> (Doc, PredType) -> Message+errSkolemEscapingScope p m what doc (whence, pty) = posMessage p $ vcat+  [ text "Existential type escapes out of its scope"+  , sep [text what <> colon, nest 2 doc], whence+  , text "Type:" <+> ppPredType m pty+  ]++errRecursiveType :: ModuleIdent -> Int -> Type -> Doc+errRecursiveType m tv ty = errIncompatibleTypes m (TypeVariable tv) ty++errIncompatibleTypes :: ModuleIdent -> Type -> Type -> Doc+errIncompatibleTypes m ty1 ty2 = sep+  [ text "Types" <+> ppType m ty1+  , nest 2 $ text "and" <+> ppType m ty2+  , text "are incompatible"+  ]++errIncompatibleLabelTypes :: Position -> ModuleIdent -> Ident -> Type -> Type+                          -> Message+errIncompatibleLabelTypes p m l ty1 ty2 = posMessage p $ sep+  [ text "Labeled types" <+> ppIdent l <+> text "::" <+> ppType m ty1+  , nest 10 $ text "and" <+> ppIdent l <+> text "::" <+> ppType m ty2+  , text "are incompatible"+  ]++errMissingInstance :: ModuleIdent -> Position -> String -> Doc -> Pred+                   -> Message+errMissingInstance m p what doc pr = posMessage p $ vcat+  [ text "Missing instance for" <+> ppPred m pr+  , text "in" <+> text what+  , doc+  ]++errAmbiguousTypeVariable :: ModuleIdent -> Position -> String -> Doc -> PredSet+                         -> Type -> Int -> Message+errAmbiguousTypeVariable m p what doc ps ty tv = posMessage p $ vcat+  [ text "Ambiguous type variable" <+> ppType m (TypeVariable tv)+  , text "in type" <+> ppPredType m (PredType ps ty)+  , text "inferred for" <+> text what+  , doc+  ]
+ src/Checks/TypeSyntaxCheck.hs view
@@ -0,0 +1,686 @@+{- |+    Module      :  $Header$+    Description :  Checks type syntax+    Copyright   :  (c) 2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   After the source file has been parsed and all modules have been+   imported, the compiler first checks all type definitions and+   signatures. In particular, this module disambiguates nullary type+   constructors and type variables, which -- in contrast to Haskell -- is+   not possible on purely syntactic criteria. In addition it is checked+   that all type constructors and type variables occurring on the right+   hand side of a type declaration are actually defined and no identifier+   is defined more than once.+-}+{-# LANGUAGE CPP #-}+module Checks.TypeSyntaxCheck (typeSyntaxCheck) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative      ((<$>), (<*>), pure)+#endif+import           Control.Monad            (unless, when)+import qualified Control.Monad.State as S (State, runState, gets, modify)+import           Data.List                (nub)+import qualified Data.Map as Map+import           Data.Maybe               (fromMaybe, isNothing)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty++import Base.Expr (Expr (fv))+import Base.Messages (Message, posMessage, internalError)+import Base.TopEnv+import Base.Utils (findMultiples, findDouble)++import Env.TypeConstructor (TCEnv)+import Env.Type++-- In order to check type constructor applications, the compiler+-- maintains an environment containing all known type constructors and+-- type classes. The function 'typeSyntaxCheck' expects a type constructor+-- environment that is already initialized with the imported type constructors+-- and type classes. The type constructor environment is converted to a type+-- identifier environment, before all locally defined type constructors and+-- type classes are added to this environment and the declarations are checked+-- within this environment.++typeSyntaxCheck :: [KnownExtension] -> TCEnv -> Module a+                -> ((Module a, [KnownExtension]), [Message])+typeSyntaxCheck exts tcEnv mdl@(Module _ m _ _ ds) =+  case findMultiples $ map getIdent tcds of+    [] -> if length dfds <= 1+            then runTSCM (checkModule mdl) state+            else ((mdl, exts), [errMultipleDefaultDeclarations dfps])+    tss -> ((mdl, exts), map errMultipleDeclarations tss)+  where+    tcds = filter isTypeOrClassDecl ds+    dfds = filter isDefaultDecl ds+    dfps = map (\(DefaultDecl p _) -> p) dfds+    tEnv = foldr (bindType m) (fmap toTypeKind tcEnv) tcds+    state = TSCState m tEnv exts Map.empty 1 []++-- Type Syntax Check Monad+type TSCM = S.State TSCState++-- |Internal state of the Type Syntax Check+data TSCState = TSCState+  { moduleIdent :: ModuleIdent+  , typeEnv     :: TypeEnv+  , extensions  :: [KnownExtension]+  , renameEnv   :: RenameEnv+  , nextId      :: Integer+  , errors      :: [Message]+  }++runTSCM :: TSCM a -> TSCState -> (a, [Message])+runTSCM tscm s = let (a, s') = S.runState tscm s in (a, reverse $ errors s')++getModuleIdent :: TSCM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTypeEnv :: TSCM TypeEnv+getTypeEnv = S.gets typeEnv++hasExtension :: KnownExtension -> TSCM Bool+hasExtension ext = S.gets (elem ext . extensions)++enableExtension :: KnownExtension -> TSCM ()+enableExtension e = S.modify $ \s -> s { extensions = e : extensions s }++getExtensions :: TSCM [KnownExtension]+getExtensions = S.gets extensions++getRenameEnv :: TSCM RenameEnv+getRenameEnv = S.gets renameEnv++modifyRenameEnv :: (RenameEnv -> RenameEnv) -> TSCM ()+modifyRenameEnv f = S.modify $ \s -> s { renameEnv = f $ renameEnv s }++withLocalEnv :: TSCM a -> TSCM a+withLocalEnv act = do+  oldEnv <- getRenameEnv+  res <- act+  modifyRenameEnv $ const oldEnv+  return res++resetEnv :: TSCM ()+resetEnv = modifyRenameEnv $ const Map.empty++newId :: TSCM Integer+newId = do+  curId <- S.gets nextId+  S.modify $ \s -> s { nextId = succ curId }+  return curId++report :: Message -> TSCM ()+report err = S.modify (\s -> s { errors = err : errors s })++ok :: TSCM ()+ok = return ()++bindType :: ModuleIdent -> Decl a -> TypeEnv -> TypeEnv+bindType m (DataDecl _ tc _ cs _) = bindTypeKind m tc (Data qtc ids)+  where+    qtc = qualifyWith m tc+    ids = map constrId cs ++ nub (concatMap recordLabels cs)+bindType m (ExternalDataDecl _ tc _) = bindTypeKind m tc (Data qtc [])+  where+    qtc = qualifyWith m tc+bindType m (NewtypeDecl _ tc _ nc _) = bindTypeKind m tc (Data qtc ids)+  where+    qtc = qualifyWith m tc+    ids = nconstrId nc : nrecordLabels nc+bindType m (TypeDecl _ tc _ _) = bindTypeKind m tc (Alias qtc)+  where+    qtc = qualifyWith m tc+bindType m (ClassDecl _ _ cls _ ds) = bindTypeKind m cls (Class qcls ms)+  where+    qcls = qualifyWith m cls+    ms = concatMap methods ds+bindType _ _ = id++-- As preparation for the kind check, type variables within type declarations+-- have to be renamed since existentially quantified type variable may shadow+-- a universally quantified variable from the left hand side of a type+-- declaration.++-- TODO: This renaming may be used to support scoped type variables in future.++-- TODO: In the long run, this renaming may be merged with the syntax check+-- renaming and moved into a separate module.++type RenameEnv = Map.Map Ident Ident++class Rename a where+  rename :: a -> TSCM a++renameTypeSig :: (Expr a, Rename a) => a -> TSCM a+renameTypeSig x = withLocalEnv $ do+  env <- getRenameEnv+  bindVars (filter (`notElem` Map.keys env) $ fv x)+  rename x++renameReset :: Rename a => a -> TSCM a+renameReset x = withLocalEnv $ resetEnv >> rename x++instance Rename a => Rename [a] where+  rename = mapM rename++instance Rename (Decl a) where+  rename (InfixDecl p fix pr ops) = return $ InfixDecl p fix pr ops+  rename (DataDecl p tc tvs cs clss) = withLocalEnv $ do+    bindVars tvs+    DataDecl p tc <$> rename tvs <*> rename cs <*> pure clss+  rename (ExternalDataDecl p tc tvs) = withLocalEnv $ do+    bindVars tvs+    ExternalDataDecl p tc <$> rename tvs+  rename (NewtypeDecl p tc tvs nc clss) = withLocalEnv $ do+    bindVars tvs+    NewtypeDecl p tc <$> rename tvs <*> rename nc <*> pure clss+  rename (TypeDecl p tc tvs ty) = withLocalEnv $ do+    bindVars tvs+    TypeDecl p tc <$> rename tvs <*> rename ty+  rename (TypeSig p fs qty) = TypeSig p fs <$> renameTypeSig qty+  rename (FunctionDecl p a f eqs) = FunctionDecl p a f <$> renameReset eqs+  rename (ExternalDecl p fs) = return $ ExternalDecl p fs+  rename (PatternDecl p ts rhs) = PatternDecl p ts <$> renameReset rhs+  rename (FreeDecl p fvs) = return $ FreeDecl p fvs+  rename (DefaultDecl p tys) = DefaultDecl p <$> mapM renameTypeSig tys+  rename (ClassDecl p cx cls tv ds) = withLocalEnv $ do+    bindVar tv+    ClassDecl p <$> rename cx <*> pure cls <*> rename tv <*> rename ds+  rename (InstanceDecl p cx cls ty ds) = withLocalEnv $ do+    bindVars (fv ty)+    InstanceDecl p <$> rename cx <*> pure cls <*> rename ty <*> renameReset ds++instance Rename ConstrDecl where+  rename (ConstrDecl p evs cx c tys) = withLocalEnv $ do+    bindVars evs+    ConstrDecl p <$> rename evs <*> rename cx <*> pure c <*> rename tys+  rename (ConOpDecl p evs cx ty1 op ty2) = withLocalEnv $ do+    bindVars evs+    ConOpDecl p <$> rename evs <*> rename cx <*> rename ty1 <*> pure op+                <*> rename ty2+  rename (RecordDecl p evs cx c fs) = withLocalEnv $ do+    bindVars evs+    RecordDecl p <$> rename evs <*> rename cx <*> pure c <*> rename fs++instance Rename FieldDecl where+  rename (FieldDecl p ls ty) = FieldDecl p ls <$> rename ty++instance Rename NewConstrDecl where+  rename (NewConstrDecl p c ty) = NewConstrDecl p c <$> rename ty+  rename (NewRecordDecl p c (l, ty)) = NewRecordDecl p c . (,) l <$> rename ty++instance Rename Constraint where+  rename (Constraint cls ty) = Constraint cls <$> rename ty++instance Rename QualTypeExpr where+  rename (QualTypeExpr cx ty) = QualTypeExpr <$> rename cx <*> rename ty++instance Rename TypeExpr where+  rename (ConstructorType tc) = return $ ConstructorType tc+  rename (ApplyType ty1 ty2) = ApplyType <$> rename ty1 <*> rename ty2+  rename (VariableType tv) = VariableType <$> rename tv+  rename (TupleType tys) = TupleType <$> rename tys+  rename (ListType ty) = ListType <$> rename ty+  rename (ArrowType ty1 ty2) = ArrowType <$> rename ty1 <*> rename ty2+  rename (ParenType ty) = ParenType <$> rename ty+  rename (ForallType vs ty) = do+    bindVars vs+    ForallType <$> mapM rename vs <*> rename ty++instance Rename (Equation a) where+  rename (Equation p lhs rhs) = Equation p lhs <$> rename rhs++instance Rename (Rhs a) where+  rename (SimpleRhs p e ds) = SimpleRhs p <$> rename e <*> rename ds+  rename (GuardedRhs es ds) = GuardedRhs <$> rename es <*> rename ds++instance Rename (CondExpr a) where+  rename (CondExpr p c e) = CondExpr p <$> rename c <*> rename e++instance Rename (Expression a) where+  rename (Literal a l) = return $ Literal a l+  rename (Variable a v) = return $ Variable a v+  rename (Constructor a c) = return $ Constructor a c+  rename (Paren e) = Paren <$> rename e+  rename (Typed e qty) = Typed <$> rename e <*> renameTypeSig qty+  rename (Record a c fs) = Record a c <$> rename fs+  rename (RecordUpdate e fs) = RecordUpdate <$> rename e <*> rename fs+  rename (Tuple es) = Tuple <$> rename es+  rename (List a es) = List a <$> rename es+  rename (ListCompr e stmts) = ListCompr <$> rename e <*> rename stmts+  rename (EnumFrom e) = EnumFrom <$> rename e+  rename (EnumFromThen e1 e2) = EnumFromThen <$> rename e1 <*> rename e2+  rename (EnumFromTo e1 e2) = EnumFromTo <$> rename e1 <*> rename e2+  rename (EnumFromThenTo e1 e2 e3) =+    EnumFromThenTo <$> rename e1 <*> rename e2 <*> rename e3+  rename (UnaryMinus e) = UnaryMinus <$> rename e+  rename (Apply e1 e2) = Apply <$> rename e1 <*> rename e2+  rename (InfixApply e1 op e2) = flip InfixApply op <$> rename e1 <*> rename e2+  rename (LeftSection e op) = flip LeftSection op <$> rename e+  rename (RightSection op e) = RightSection op <$> rename e+  rename (Lambda ts e) = Lambda ts <$> rename e+  rename (Let ds e) = Let <$> rename ds <*> rename e+  rename (Do stmts e) = Do <$> rename stmts <*> rename e+  rename (IfThenElse c e1 e2) =+    IfThenElse <$> rename c <*> rename e1 <*> rename e2+  rename (Case ct e alts) = Case ct <$> rename e <*> rename alts++instance Rename (Statement a) where+  rename (StmtExpr e) = StmtExpr <$> rename e+  rename (StmtDecl ds) = StmtDecl <$> rename ds+  rename (StmtBind t e) = StmtBind t <$> rename e++instance Rename (Alt a) where+  rename (Alt p t rhs) = Alt p t <$> rename rhs++instance Rename a => Rename (Field a) where+  rename (Field p l x) = Field p l <$> rename x++instance Rename Ident where+  rename tv | isAnonId tv = renameIdent tv <$> newId+            | otherwise   = fromMaybe tv <$> lookupVar tv++bindVar :: Ident -> TSCM ()+bindVar tv = do+  k <- newId+  modifyRenameEnv $ Map.insert tv (renameIdent tv k)++bindVars :: [Ident] -> TSCM ()+bindVars = mapM_ bindVar++lookupVar :: Ident -> TSCM (Maybe Ident)+lookupVar tv = do+  env <- getRenameEnv+  return $ Map.lookup tv env++-- When type declarations are checked, the compiler will allow anonymous+-- type variables on the left hand side of the declaration, but not on+-- the right hand side. Function and pattern declarations must be+-- traversed because they can contain local type signatures.++checkModule :: Module a -> TSCM (Module a, [KnownExtension])+checkModule (Module ps m es is ds) = do+  ds' <- mapM checkDecl ds+  ds'' <- rename ds'+  exts <- getExtensions+  return (Module ps m es is ds'', exts)++checkDecl :: Decl a -> TSCM (Decl a)+checkDecl (DataDecl p tc tvs cs clss) = do+  checkTypeLhs tvs+  cs' <- mapM (checkConstrDecl tvs) cs+  mapM_ checkClass clss+  return $ DataDecl p tc tvs cs' clss+checkDecl (NewtypeDecl p tc tvs nc clss) = do+  checkTypeLhs tvs+  nc' <- checkNewConstrDecl tvs nc+  mapM_ checkClass clss+  return $ NewtypeDecl p tc tvs nc' clss+checkDecl (TypeDecl p tc tvs ty) = do+  checkTypeLhs tvs+  ty' <- checkClosedType tvs ty+  return $ TypeDecl p tc tvs ty'+checkDecl (TypeSig p vs qty) =+  TypeSig p vs <$> checkQualType qty+checkDecl (FunctionDecl a p f eqs) =+  FunctionDecl a p f <$> mapM checkEquation eqs+checkDecl (PatternDecl p t rhs) =+  PatternDecl p t <$> checkRhs rhs+checkDecl (DefaultDecl p tys) = DefaultDecl p <$> mapM checkType tys+checkDecl (ClassDecl p cx cls clsvar ds) = do+  checkTypeVars "class declaration" [clsvar]+  cx' <- checkClosedContext [clsvar] cx+  checkSimpleContext cx'+  ds' <- mapM checkDecl ds+  mapM_ (checkClassMethod clsvar) ds'+  return $ ClassDecl p cx' cls clsvar ds'+checkDecl (InstanceDecl p cx qcls inst ds) = do+  checkClass qcls+  QualTypeExpr cx' inst' <- checkQualType $ QualTypeExpr cx inst+  checkSimpleContext cx'+  checkInstanceType p inst'+  InstanceDecl p cx' qcls inst' <$> mapM checkDecl ds+checkDecl d = return d++checkConstrDecl :: [Ident] -> ConstrDecl -> TSCM ConstrDecl+checkConstrDecl tvs (ConstrDecl p evs cx c tys) = do+  checkExistVars evs+  tys' <- mapM (checkClosedType (evs ++ tvs)) tys+  cx' <- checkClosedContext (fv tys') cx+  return $ ConstrDecl p evs cx' c tys'+checkConstrDecl tvs (ConOpDecl p evs cx ty1 op ty2) = do+  checkExistVars evs+  [ty1', ty2'] <- mapM (checkClosedType (evs ++ tvs)) [ty1, ty2]+  cx' <- checkClosedContext (fv ty1' ++ fv ty2') cx+  return $ ConOpDecl p evs cx' ty1' op ty2'+checkConstrDecl tvs (RecordDecl p evs cx c fs) = do+  checkExistVars evs+  fs' <- mapM (checkFieldDecl (evs ++ tvs)) fs+  cx' <- checkClosedContext (concatMap fv [ty | FieldDecl _ _ ty <- fs]) cx+  return $ RecordDecl p evs cx' c fs'++checkFieldDecl :: [Ident] -> FieldDecl -> TSCM FieldDecl+checkFieldDecl tvs (FieldDecl p ls ty) =+  FieldDecl p ls <$> checkClosedType tvs ty++checkNewConstrDecl :: [Ident] -> NewConstrDecl -> TSCM NewConstrDecl+checkNewConstrDecl tvs (NewConstrDecl p c ty) = do+  ty'  <- checkClosedType tvs ty+  return $ NewConstrDecl p c ty'+checkNewConstrDecl tvs (NewRecordDecl p c (l, ty)) = do+  ty'  <- checkClosedType tvs ty+  return $ NewRecordDecl p c (l, ty')++checkSimpleContext :: Context -> TSCM ()+checkSimpleContext = mapM_ checkSimpleConstraint++checkSimpleConstraint :: Constraint -> TSCM ()+checkSimpleConstraint c@(Constraint _ ty) =+  unless (isVariableType ty) $ report $ errIllegalSimpleConstraint c++-- Class method's type signatures have to obey a few additional restrictions.+-- The class variable must appear in the method's type and the method's+-- context must not contain any additional constraints for that class variable.++checkClassMethod :: Ident -> Decl a -> TSCM ()+checkClassMethod tv (TypeSig p _ qty) = do+  unless (tv `elem` fv qty) $ report $ errAmbiguousType p tv+  let QualTypeExpr cx _ = qty+  when (tv `elem` fv cx) $ report $ errConstrainedClassVariable p tv+checkClassMethod _ _ = ok++checkInstanceType :: Position -> InstanceType -> TSCM ()+checkInstanceType p inst = do+  tEnv <- getTypeEnv+  unless (isSimpleType inst &&+    not (isTypeSyn (typeConstr inst) tEnv) &&+    null (filter isAnonId $ typeVariables inst) &&+    isNothing (findDouble $ fv inst)) $+      report $ errIllegalInstanceType p inst++checkTypeLhs :: [Ident] -> TSCM ()+checkTypeLhs = checkTypeVars "left hand side of type declaration"++checkExistVars :: [Ident] -> TSCM ()+checkExistVars evs = do+  unless (null evs) $ checkUsedExtension (idPosition $ head evs)+    "Existentially quantified types" ExistentialQuantification+  checkTypeVars "list of existentially quantified type variables" evs++-- |Checks a list of type variables for+-- * Anonymous type variables are allowed+-- * only type variables (no type constructors)+-- * linearity+checkTypeVars :: String -> [Ident] -> TSCM ()+checkTypeVars _    []         = ok+checkTypeVars what (tv : tvs) = do+  unless (isAnonId tv) $ do+    isTypeConstrOrClass <- (not . null . lookupTypeKind tv) <$> getTypeEnv+    when isTypeConstrOrClass $ report $ errNoVariable tv what+    when (tv `elem` tvs) $ report $ errNonLinear tv what+  checkTypeVars what tvs++-- Checking expressions is rather straight forward. The compiler must+-- only traverse the structure of expressions in order to find local+-- declaration groups.++checkEquation :: Equation a -> TSCM (Equation a)+checkEquation (Equation p lhs rhs) = Equation p lhs <$> checkRhs rhs++checkRhs :: Rhs a -> TSCM (Rhs a)+checkRhs (SimpleRhs p e ds) = SimpleRhs p <$> checkExpr e <*> mapM checkDecl ds+checkRhs (GuardedRhs es ds) = GuardedRhs  <$> mapM checkCondExpr es+                                          <*> mapM checkDecl ds++checkCondExpr :: CondExpr a -> TSCM (CondExpr a)+checkCondExpr (CondExpr p g e) = CondExpr p <$> checkExpr g <*> checkExpr e++checkExpr :: Expression a -> TSCM (Expression a)+checkExpr l@(Literal           _ _) = return l+checkExpr v@(Variable          _ _) = return v+checkExpr c@(Constructor       _ _) = return c+checkExpr (Paren                 e) = Paren <$> checkExpr e+checkExpr (Typed             e qty) = Typed <$> checkExpr e+                                            <*> checkQualType qty+checkExpr (Record           a c fs) = Record a c <$> mapM checkFieldExpr fs+checkExpr (RecordUpdate       e fs) = RecordUpdate <$> checkExpr e+                                                   <*> mapM checkFieldExpr fs+checkExpr (Tuple                es) = Tuple <$> mapM checkExpr es+checkExpr (List               a es) = List a <$> mapM checkExpr es+checkExpr (ListCompr          e qs) = ListCompr <$> checkExpr e+                                                <*> mapM checkStmt qs+checkExpr (EnumFrom              e) = EnumFrom <$> checkExpr e+checkExpr (EnumFromThen      e1 e2) = EnumFromThen <$> checkExpr e1+                                                   <*> checkExpr e2+checkExpr (EnumFromTo        e1 e2) = EnumFromTo <$> checkExpr e1+                                                 <*> checkExpr e2+checkExpr (EnumFromThenTo e1 e2 e3) = EnumFromThenTo <$> checkExpr e1+                                                     <*> checkExpr e2+                                                     <*> checkExpr e3+checkExpr (UnaryMinus            e) = UnaryMinus <$> checkExpr e+checkExpr (Apply             e1 e2) = Apply <$> checkExpr e1 <*> checkExpr e2+checkExpr (InfixApply     e1 op e2) = InfixApply <$> checkExpr e1+                                                 <*> return op+                                                 <*> checkExpr e2+checkExpr (LeftSection        e op) = flip LeftSection op <$> checkExpr e+checkExpr (RightSection       op e) = RightSection op <$> checkExpr e+checkExpr (Lambda             ts e) = Lambda ts <$> checkExpr e+checkExpr (Let                ds e) = Let <$> mapM checkDecl ds <*> checkExpr e+checkExpr (Do                sts e) = Do <$> mapM checkStmt sts <*> checkExpr e+checkExpr (IfThenElse     e1 e2 e3) = IfThenElse <$> checkExpr e1+                                                 <*> checkExpr e2+                                                 <*> checkExpr e3+checkExpr (Case          ct e alts) = Case ct <$> checkExpr e+                                              <*> mapM checkAlt alts++checkStmt :: Statement a -> TSCM (Statement a)+checkStmt (StmtExpr   e) = StmtExpr <$> checkExpr e+checkStmt (StmtBind t e) = StmtBind t <$> checkExpr e+checkStmt (StmtDecl  ds) = StmtDecl <$> mapM checkDecl ds++checkAlt :: Alt a -> TSCM (Alt a)+checkAlt (Alt p t rhs) = Alt p t <$> checkRhs rhs++checkFieldExpr :: Field (Expression a) -> TSCM (Field (Expression a))+checkFieldExpr (Field p l e) = Field p l <$> checkExpr e++-- The parser cannot distinguish unqualified nullary type constructors+-- and type variables. Therefore, if the compiler finds an unbound+-- identifier in a position where a type variable is admissible, it will+-- interpret the identifier as such.++checkQualType :: QualTypeExpr -> TSCM QualTypeExpr+checkQualType (QualTypeExpr cx ty) = do+  ty' <- checkType ty+  cx' <- checkClosedContext (fv ty') cx+  return $ QualTypeExpr cx' ty'++checkClosedContext :: [Ident] -> Context -> TSCM Context+checkClosedContext tvs cx = do+  cx' <- checkContext cx+  mapM_ (\(Constraint _ ty) -> checkClosed tvs ty) cx'+  return cx'++checkContext :: Context -> TSCM Context+checkContext = mapM checkConstraint++checkConstraint :: Constraint -> TSCM Constraint+checkConstraint c@(Constraint qcls ty) = do+  checkClass qcls+  ty' <- checkType ty+  unless (isVariableType $ rootType ty') $ report $ errIllegalConstraint c+  return $ Constraint qcls ty'+  where+    rootType (ApplyType ty' _) = ty'+    rootType ty'               = ty'++checkClass :: QualIdent -> TSCM ()+checkClass qcls = do+  m <- getModuleIdent+  tEnv <- getTypeEnv+  case qualLookupTypeKind qcls tEnv of+    [] -> report $ errUndefinedClass qcls+    [Class _ _] -> ok+    [_] -> report $ errUndefinedClass qcls+    tks -> case qualLookupTypeKind (qualQualify m qcls) tEnv of+      [Class _ _] -> ok+      [_] -> report $ errUndefinedClass qcls+      _ -> report $ errAmbiguousIdent qcls $ map origName tks++checkClosedType :: [Ident] -> TypeExpr -> TSCM TypeExpr+checkClosedType tvs ty = do+  ty' <- checkType ty+  checkClosed tvs ty'+  return ty'++checkType :: TypeExpr -> TSCM TypeExpr+checkType c@(ConstructorType tc) = do+  m <- getModuleIdent+  tEnv <- getTypeEnv+  case qualLookupTypeKind tc tEnv of+    []+      | isQTupleId tc -> return c+      | not (isQualified tc) -> return $ VariableType $ unqualify tc+      | otherwise -> report (errUndefinedType tc) >> return c+    [Class _ _] -> report (errUndefinedType tc) >> return c+    [_] -> return c+    tks -> case qualLookupTypeKind (qualQualify m tc) tEnv of+      [Class _ _] -> report (errUndefinedType tc) >> return c+      [_] -> return c+      _ -> report (errAmbiguousIdent tc $ map origName tks) >> return c+checkType (ApplyType ty1 ty2) = ApplyType  <$> checkType ty1 <*> checkType ty2+checkType v@(VariableType tv)+  | isAnonId tv = return v+  | otherwise   = checkType $ ConstructorType (qualify tv)+checkType (TupleType     tys) = TupleType  <$> mapM checkType tys+checkType (ListType       ty) = ListType   <$> checkType ty+checkType (ArrowType ty1 ty2) = ArrowType  <$> checkType ty1 <*> checkType ty2+checkType (ParenType      ty) = ParenType  <$> checkType ty+checkType (ForallType  vs ty) = ForallType vs <$> checkType ty++checkClosed :: [Ident] -> TypeExpr -> TSCM ()+checkClosed _   (ConstructorType _) = ok+checkClosed tvs (ApplyType ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (VariableType   tv) =+  when (isAnonId tv || tv `notElem` tvs) $ report $ errUnboundVariable tv+checkClosed tvs (TupleType     tys) = mapM_ (checkClosed tvs) tys+checkClosed tvs (ListType       ty) = checkClosed tvs ty+checkClosed tvs (ArrowType ty1 ty2) = mapM_ (checkClosed tvs) [ty1, ty2]+checkClosed tvs (ParenType      ty) = checkClosed tvs ty+checkClosed tvs (ForallType  vs ty) = checkClosed (tvs ++ vs) ty++checkUsedExtension :: Position -> String -> KnownExtension -> TSCM ()+checkUsedExtension pos msg ext = do+  enabled <- hasExtension ext+  unless enabled $ do+    report $ errMissingLanguageExtension pos msg ext+    enableExtension ext++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++getIdent :: Decl a -> Ident+getIdent (DataDecl     _ tc _ _ _) = tc+getIdent (ExternalDataDecl _ tc _) = tc+getIdent (NewtypeDecl  _ tc _ _ _) = tc+getIdent (TypeDecl       _ tc _ _) = tc+getIdent (ClassDecl   _ _ cls _ _) = cls+getIdent _                         =+  internalError "Checks.TypeSyntaxCheck.getIdent: no type or class declaration"++isTypeSyn :: QualIdent -> TypeEnv -> Bool+isTypeSyn tc tEnv = case qualLookupTypeKind tc tEnv of+  [Alias _] -> True+  _ -> False++-- ---------------------------------------------------------------------------+-- Error messages+-- ---------------------------------------------------------------------------++errMultipleDefaultDeclarations :: [Position] -> Message+errMultipleDefaultDeclarations ps = posMessage (head ps) $+  text "More than one default declaration:" $+$+    nest 2 (vcat $ map showPos ps)+  where showPos = text . showLine++errMultipleDeclarations :: [Ident] -> Message+errMultipleDeclarations is = posMessage i $+  text "Multiple declarations of" <+> text (escName i) <+> text "at:" $+$+    nest 2 (vcat $ map showPos is)+  where i = head is+        showPos = text . showLine . idPosition++errMissingLanguageExtension :: Position -> String -> KnownExtension -> Message+errMissingLanguageExtension p what ext = posMessage p $+  text what <+> text "are not supported in standard Curry." $+$+  nest 2 (text "Use flag -X" <+> text (show ext)+          <+> text "to enable this extension.")++errUndefined :: String -> QualIdent -> Message+errUndefined what qident = posMessage qident $ hsep $ map text+  ["Undefined", what, qualName qident]++errUndefinedClass :: QualIdent -> Message+errUndefinedClass = errUndefined "class"++errUndefinedType :: QualIdent -> Message+errUndefinedType = errUndefined "type"++errAmbiguousIdent :: QualIdent -> [QualIdent] -> Message+errAmbiguousIdent qident qidents = posMessage qident $+  text "Ambiguous identifier" <+> text (escQualName qident) $+$+    text "It could refer to:" $+$ nest 2 (vcat (map (text . qualName) qidents))++errAmbiguousType :: Position -> Ident -> Message+errAmbiguousType p ident = posMessage p $ hsep $ map text+  [ "Method type does not mention class variable", idName ident ]++errConstrainedClassVariable :: Position -> Ident -> Message+errConstrainedClassVariable p ident = posMessage p $ hsep $ map text+  [ "Method context must not constrain class variable", idName ident ]++errNonLinear :: Ident -> String -> Message+errNonLinear tv what = posMessage tv $ hsep $ map text+  [ "Type variable", idName tv, "occurs more than once in", what ]++errNoVariable :: Ident -> String -> Message+errNoVariable tv what = posMessage tv $ hsep $ map text $+  [ "Type constructor or type class identifier", idName tv, "used in", what ]++errUnboundVariable :: Ident -> Message+errUnboundVariable tv = posMessage tv $ hsep $ map text+  [ "Unbound type variable", idName tv ]++errIllegalConstraint :: Constraint -> Message+errIllegalConstraint c@(Constraint qcls _) = posMessage qcls $ vcat+  [ text "Illegal class constraint" <+> ppConstraint c+  , text "Constraints must be of the form C u or C (u t1 ... tn),"+  , text "where C is a type class, u is a type variable and t1, ..., tn are types."+  ]++errIllegalSimpleConstraint :: Constraint -> Message+errIllegalSimpleConstraint c@(Constraint qcls _) = posMessage qcls $ vcat+  [ text "Illegal class constraint" <+> ppConstraint c+  , text "Constraints in class and instance declarations must be of"+  , text "the form C u, where C is a type class and u is a type variable."+  ]++errIllegalInstanceType :: Position -> InstanceType -> Message+errIllegalInstanceType p inst = posMessage p $ vcat+  [ text "Illegal instance type" <+> ppInstanceType inst+  , text "The instance type must be of the form (T u_1 ... u_n),"+  , text "where T is not a type synonym and u_1, ..., u_n are"+  , text "mutually distinct, non-anonymous type variables."+  ]
+ src/Checks/WarnCheck.hs view
@@ -0,0 +1,1483 @@+{- |+    Module      :  $Header$+    Description :  Checks for irregular code+    Copyright   :  (c) 2006        Martin Engelke+                       2011 - 2014 Björn Peemöller+                       2014 - 2015 Jan Tikovsky+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module searches for potentially irregular code and generates+    warning messages.+-}+module Checks.WarnCheck (warnCheck) where++import           Control.Monad+  (filterM, foldM_, guard, liftM, liftM2, when, unless)+import           Control.Monad.State.Strict    (State, execState, gets, modify)+import qualified Data.IntSet         as IntSet+  (IntSet, empty, insert, notMember, singleton, union, unions)+import qualified Data.Map            as Map    (empty, insert, lookup)+import           Data.Maybe+  (catMaybes, fromMaybe, listToMaybe)+import           Data.List+  ((\\), intersect, intersectBy, nub, sort, unionBy)+import           Data.Char+  (isLower, isUpper, toLower, toUpper, isAlpha)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Syntax+import Curry.Syntax.Pretty (ppDecl, ppPattern, ppExpr, ppIdent)++import Base.CurryTypes (ppTypeScheme)+import Base.Messages   (Message, posMessage, internalError)+import Base.NestEnv    ( NestEnv, emptyEnv, localNestEnv, nestEnv, unnestEnv+                       , qualBindNestEnv, qualInLocalNestEnv, qualLookupNestEnv+                       , qualModifyNestEnv)++import Base.Types+import Base.Utils (findMultiples)+import Env.ModuleAlias+import Env.Class (ClassEnv, classMethods, hasDefaultImpl)+import Env.TypeConstructor ( TCEnv, TypeInfo (..), lookupTypeInfo+                           , qualLookupTypeInfo, getOrigName )+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++import CompilerOpts++-- Find potentially incorrect code in a Curry program and generate warnings+-- for the following issues:+--   - multiply imported modules, multiply imported/hidden values+--   - unreferenced variables+--   - shadowing variables+--   - idle case alternatives+--   - overlapping case alternatives+--   - non-adjacent function rules+--   - wrong case mode+warnCheck :: WarnOpts -> CaseMode -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv+          -> Module a -> [Message]+warnCheck wOpts cOpts aEnv valEnv tcEnv clsEnv mdl+  = runOn (initWcState mid aEnv valEnv tcEnv clsEnv (wnWarnFlags wOpts) cOpts) $ do+      checkImports   is+      checkDeclGroup ds+      checkExports   es+      checkMissingTypeSignatures ds+      checkModuleAlias is+      checkCaseMode  ds+  where Module _ mid es is ds = fmap (const ()) mdl++type ScopeEnv = NestEnv IdInfo++-- Current state of generating warnings+data WcState = WcState+  { moduleId    :: ModuleIdent+  , scope       :: ScopeEnv+  , aliasEnv    :: AliasEnv+  , valueEnv    :: ValueEnv+  , tyConsEnv   :: TCEnv+  , classEnv    :: ClassEnv+  , warnFlags   :: [WarnFlag]+  , caseMode    :: CaseMode+  , warnings    :: [Message]+  }++-- The monadic representation of the state allows the usage of monadic+-- syntax (do expression) for dealing easier and safer with its+-- contents.+type WCM = State WcState++initWcState :: ModuleIdent -> AliasEnv -> ValueEnv -> TCEnv -> ClassEnv+            -> [WarnFlag] -> CaseMode -> WcState+initWcState mid ae ve te ce wf cm = WcState mid emptyEnv ae ve te ce wf cm []++getModuleIdent :: WCM ModuleIdent+getModuleIdent = gets moduleId++modifyScope :: (ScopeEnv -> ScopeEnv) -> WCM ()+modifyScope f = modify $ \s -> s { scope = f $ scope s }++warnFor :: WarnFlag -> WCM () -> WCM ()+warnFor f act = do+  warn <- gets $ \s -> f `elem` warnFlags s+  when warn act++report :: Message -> WCM ()+report w = modify $ \ s -> s { warnings = w : warnings s }++unAlias :: QualIdent -> WCM QualIdent+unAlias q = do+  aEnv <- gets aliasEnv+  case qidModule q of+    Nothing -> return q+    Just m  -> case Map.lookup m aEnv of+      Nothing -> return q+      Just m' -> return $ qualifyWith m' (unqualify q)++ok :: WCM ()+ok = return ()++-- |Run a 'WCM' action and return the list of messages+runOn :: WcState -> WCM a -> [Message]+runOn s f = sort $ warnings $ execState f s++-- ---------------------------------------------------------------------------+-- checkExports+-- ---------------------------------------------------------------------------++checkExports :: Maybe ExportSpec -> WCM () -- TODO checks+checkExports Nothing                      = ok+checkExports (Just (Exporting _ exports)) = do+  mapM_ visitExport exports+  reportUnusedGlobalVars+    where+      visitExport (Export qid) = visitQId qid+      visitExport _            = ok++-- ---------------------------------------------------------------------------+-- checkImports+-- ---------------------------------------------------------------------------++-- Check import declarations for multiply imported modules and multiply+-- imported/hidden values.+-- The function uses a map of the already imported or hidden entities to+-- collect the entities throughout multiple import statements.+checkImports :: [ImportDecl] -> WCM ()+checkImports = warnFor WarnMultipleImports . foldM_ checkImport Map.empty+  where+  checkImport env (ImportDecl pos mid _ _ spec) = case Map.lookup mid env of+    Nothing   -> setImportSpec env mid $ fromImpSpec spec+    Just ishs -> checkImportSpec env pos mid ishs spec++  checkImportSpec env _ mid (_, _)    Nothing = do+    report $ warnMultiplyImportedModule mid+    return env++  checkImportSpec env _ mid (is, hs) (Just (Importing _ is'))+    | null is && any (`notElem` hs) is' = do+        report $ warnMultiplyImportedModule mid+        setImportSpec env mid (is', hs)+    | null iis  = setImportSpec env mid (is' ++ is, hs)+    | otherwise = do+        mapM_ (report . (warnMultiplyImportedSymbol mid) . impName) iis+        setImportSpec env mid (unionBy cmpImport is' is, hs)+    where iis = intersectBy cmpImport is' is++  checkImportSpec env _ mid (is, hs) (Just (Hiding _ hs'))+    | null ihs  = setImportSpec env mid (is, hs' ++ hs)+    | otherwise = do+        mapM_ (report . (warnMultiplyHiddenSymbol mid) . impName) ihs+        setImportSpec env mid (is, unionBy cmpImport hs' hs)+    where ihs = intersectBy cmpImport hs' hs++  fromImpSpec Nothing                 = ([], [])+  fromImpSpec (Just (Importing _ is)) = (is, [])+  fromImpSpec (Just (Hiding    _ hs)) = ([], hs)++  setImportSpec env mid ishs = return $ Map.insert mid ishs env++  cmpImport (ImportTypeWith id1 cs1) (ImportTypeWith id2 cs2)+    = id1 == id2 && null (intersect cs1 cs2)+  cmpImport i1 i2 = (impName i1) == (impName i2)++  impName (Import           v) = v+  impName (ImportTypeAll    t) = t+  impName (ImportTypeWith t _) = t++warnMultiplyImportedModule :: ModuleIdent -> Message+warnMultiplyImportedModule mid = posMessage mid $ hsep $ map text+  ["Module", moduleName mid, "is imported more than once"]++warnMultiplyImportedSymbol :: ModuleIdent -> Ident -> Message+warnMultiplyImportedSymbol mid ident = posMessage ident $ hsep $ map text+  [ "Symbol", escName ident, "from module", moduleName mid+  , "is imported more than once" ]++warnMultiplyHiddenSymbol :: ModuleIdent -> Ident -> Message+warnMultiplyHiddenSymbol mid ident = posMessage ident $ hsep $ map text+  [ "Symbol", escName ident, "from module", moduleName mid+  , "is hidden more than once" ]++-- ---------------------------------------------------------------------------+-- checkDeclGroup+-- ---------------------------------------------------------------------------++checkDeclGroup :: [Decl ()] -> WCM ()+checkDeclGroup ds = do+  mapM_ insertDecl   ds+  mapM_ checkDecl    ds+  checkRuleAdjacency ds++checkLocalDeclGroup :: [Decl ()] -> WCM ()+checkLocalDeclGroup ds = do+  mapM_ checkLocalDecl ds+  checkDeclGroup       ds++-- ---------------------------------------------------------------------------+-- Find function rules which are disjoined+-- ---------------------------------------------------------------------------++checkRuleAdjacency :: [Decl a] -> WCM ()+checkRuleAdjacency decls = warnFor WarnDisjoinedRules+                         $ foldM_ check (mkIdent "", Map.empty) decls+  where+  check (prevId, env) (FunctionDecl p _ f _) = do+    cons <- isConsId f+    if cons || prevId == f+      then return (f, env)+      else case Map.lookup f env of+        Nothing -> return (f, Map.insert f p env)+        Just p' -> do+          report $ warnDisjoinedFunctionRules f p'+          return (f, env)+  check (_    , env) _                     = return (mkIdent "", env)++warnDisjoinedFunctionRules :: Ident -> Position -> Message+warnDisjoinedFunctionRules ident pos = posMessage ident $ hsep (map text+  [ "Rules for function", escName ident, "are disjoined" ])+  <+> parens (text "first occurrence at" <+> text (showLine pos))++checkDecl :: Decl () -> WCM ()+checkDecl (DataDecl        _ _ vs cs _) = inNestedScope $ do+  mapM_ insertTypeVar   vs+  mapM_ checkConstrDecl cs+  reportUnusedTypeVars  vs+checkDecl (NewtypeDecl     _ _ vs nc _) = inNestedScope $ do+  mapM_ insertTypeVar   vs+  checkNewConstrDecl nc+  reportUnusedTypeVars vs+checkDecl (TypeDecl          _ _ vs ty) = inNestedScope $ do+  mapM_ insertTypeVar  vs+  checkTypeExpr ty+  reportUnusedTypeVars vs+checkDecl (FunctionDecl      p _ f eqs) = checkFunctionDecl p f eqs+checkDecl (PatternDecl         _ p rhs) = checkPattern p >> checkRhs rhs+checkDecl (DefaultDecl           _ tys) = mapM_ checkTypeExpr tys+checkDecl (ClassDecl        _ _ _ _ ds) = mapM_ checkDecl ds+checkDecl (InstanceDecl p cx cls ty ds) = do+  checkOrphanInstance p cx cls ty+  checkMissingMethodImplementations p cls ds+  mapM_ checkDecl ds+checkDecl _                             = ok++--TODO: shadowing und context etc.+checkConstrDecl :: ConstrDecl -> WCM ()+checkConstrDecl (ConstrDecl     _ vs _ c tys) = inNestedScope $ do+  mapM_ checkTypeShadowing vs+  mapM_ insertTypeVar vs+  visitId c+  mapM_ checkTypeExpr tys+  reportUnusedTypeVars vs+checkConstrDecl (ConOpDecl _ vs _ ty1 op ty2) = inNestedScope $ do+  mapM_ checkTypeShadowing vs+  mapM_ insertTypeVar vs+  visitId op+  mapM_ checkTypeExpr [ty1, ty2]+  reportUnusedTypeVars vs+checkConstrDecl (RecordDecl      _ vs _ c fs) = inNestedScope $ do+  mapM_ checkTypeShadowing vs+  mapM_ insertTypeVar vs+  visitId c+  mapM_ checkTypeExpr tys+  reportUnusedTypeVars vs+  where+    tys = [ty | FieldDecl _ _ ty <- fs]++checkNewConstrDecl :: NewConstrDecl -> WCM ()+checkNewConstrDecl (NewConstrDecl _ c      ty) = do+  visitId c+  checkTypeExpr ty+checkNewConstrDecl (NewRecordDecl _ c (_, ty)) = do+  visitId c+  checkTypeExpr ty++checkTypeExpr :: TypeExpr -> WCM ()+checkTypeExpr (ConstructorType     qid) = visitQTypeId qid+checkTypeExpr (ApplyType       ty1 ty2) = mapM_ checkTypeExpr [ty1, ty2]+checkTypeExpr (VariableType          v) = visitTypeId v+checkTypeExpr (TupleType           tys) = mapM_ checkTypeExpr tys+checkTypeExpr (ListType             ty) = checkTypeExpr ty+checkTypeExpr (ArrowType       ty1 ty2) = mapM_ checkTypeExpr [ty1, ty2]+checkTypeExpr (ParenType            ty) = checkTypeExpr ty+checkTypeExpr (ForallType        vs ty) = do+  mapM_ insertTypeVar vs+  checkTypeExpr ty++-- Checks locally declared identifiers (i.e. functions and logic variables)+-- for shadowing+checkLocalDecl :: Decl a -> WCM ()+checkLocalDecl (FunctionDecl _ _ f _) = checkShadowing f+checkLocalDecl (FreeDecl        _ vs) = mapM_ (checkShadowing . varIdent) vs+checkLocalDecl (PatternDecl    _ p _) = checkPattern p+checkLocalDecl _                      = ok++checkFunctionDecl :: Position -> Ident -> [Equation ()] -> WCM ()+checkFunctionDecl _ _ []  = ok+checkFunctionDecl p f eqs = inNestedScope $ do+  mapM_ checkEquation eqs+  checkFunctionPatternMatch p f eqs++checkFunctionPatternMatch :: Position -> Ident -> [Equation ()] -> WCM ()+checkFunctionPatternMatch p f eqs = do+  let pats = map (\(Equation _ lhs _) -> snd (flatLhs lhs)) eqs+  (nonExhaustive, overlapped, nondet) <- checkPatternMatching pats+  unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $+    warnMissingPattern p ("an equation for " ++ escName f) nonExhaustive+  when (nondet || not (null overlapped)) $ warnFor WarnOverlapping $ report $+    warnNondetOverlapping p ("Function " ++ escName f)++-- Check an equation for warnings.+-- This is done in a seperate scope as the left-hand-side may introduce+-- new variables.+checkEquation :: Equation () -> WCM ()+checkEquation (Equation _ lhs rhs) = inNestedScope $ do+  checkLhs lhs+  checkRhs rhs+  reportUnusedVars++checkLhs :: Lhs a -> WCM ()+checkLhs (FunLhs    _ ts) = do+  mapM_ checkPattern ts+  mapM_ (insertPattern False) ts+checkLhs (OpLhs t1 op t2) = checkLhs (FunLhs op [t1, t2])+checkLhs (ApLhs   lhs ts) = do+  checkLhs lhs+  mapM_ checkPattern ts+  mapM_ (insertPattern False) ts++checkPattern :: Pattern a -> WCM ()+checkPattern (VariablePattern        _ v) = checkShadowing v+checkPattern (ConstructorPattern  _ _ ps) = mapM_ checkPattern ps+checkPattern (InfixPattern     a p1 f p2) = checkPattern+                                            (ConstructorPattern a f [p1, p2])+checkPattern (ParenPattern             p) = checkPattern p+checkPattern (RecordPattern       _ _ fs) = mapM_ (checkField checkPattern) fs+checkPattern (TuplePattern            ps) = mapM_ checkPattern ps+checkPattern (ListPattern           _ ps) = mapM_ checkPattern ps+checkPattern (AsPattern              v p) = checkShadowing v >> checkPattern p+checkPattern (LazyPattern              p) = checkPattern p+checkPattern (FunctionPattern     _ _ ps) = mapM_ checkPattern ps+checkPattern (InfixFuncPattern a p1 f p2) = checkPattern+                                            (FunctionPattern a f [p1, p2])+checkPattern _                            = ok++-- Check the right-hand-side of an equation.+-- Because local declarations may introduce new variables, we need+-- another scope nesting.+checkRhs :: Rhs () -> WCM ()+checkRhs (SimpleRhs _ e ds) = inNestedScope $ do+  checkLocalDeclGroup ds+  checkExpr e+  reportUnusedVars+checkRhs (GuardedRhs ce ds) = inNestedScope $ do+  checkLocalDeclGroup ds+  mapM_ checkCondExpr ce+  reportUnusedVars++checkCondExpr :: CondExpr () -> WCM ()+checkCondExpr (CondExpr _ c e) = checkExpr c >> checkExpr e++checkExpr :: Expression () -> WCM ()+checkExpr (Variable            _ v) = visitQId v+checkExpr (Paren                 e) = checkExpr e+checkExpr (Typed               e _) = checkExpr e+checkExpr (Record           _ _ fs) = mapM_ (checkField checkExpr) fs+checkExpr (RecordUpdate       e fs) = do+  checkExpr e+  mapM_ (checkField checkExpr) fs+checkExpr (Tuple                es) = mapM_ checkExpr es+checkExpr (List               _ es) = mapM_ checkExpr es+checkExpr (ListCompr         e sts) = checkStatements sts e+checkExpr (EnumFrom              e) = checkExpr e+checkExpr (EnumFromThen      e1 e2) = mapM_ checkExpr [e1, e2]+checkExpr (EnumFromTo        e1 e2) = mapM_ checkExpr [e1, e2]+checkExpr (EnumFromThenTo e1 e2 e3) = mapM_ checkExpr [e1, e2, e3]+checkExpr (UnaryMinus            e) = checkExpr e+checkExpr (Apply             e1 e2) = mapM_ checkExpr [e1, e2]+checkExpr (InfixApply     e1 op e2) = do+  visitQId (opName op)+  mapM_ checkExpr [e1, e2]+checkExpr (LeftSection         e _) = checkExpr e+checkExpr (RightSection        _ e) = checkExpr e+checkExpr (Lambda             ps e) = inNestedScope $ do+  mapM_ checkPattern ps+  mapM_ (insertPattern False) ps+  checkExpr e+  reportUnusedVars+checkExpr (Let                ds e) = inNestedScope $ do+  checkLocalDeclGroup ds+  checkExpr e+  reportUnusedVars+checkExpr (Do                sts e) = checkStatements sts e+checkExpr (IfThenElse     e1 e2 e3) = mapM_ checkExpr [e1, e2, e3]+checkExpr (Case          ct e alts) = do+  checkExpr e+  mapM_ checkAlt alts+  checkCaseAlts ct alts+checkExpr _                       = ok++checkStatements :: [Statement ()] -> Expression () -> WCM ()+checkStatements []     e = checkExpr e+checkStatements (s:ss) e = inNestedScope $ do+  checkStatement s >> checkStatements ss e+  reportUnusedVars++checkStatement :: Statement () -> WCM ()+checkStatement (StmtExpr   e) = checkExpr e+checkStatement (StmtDecl  ds) = checkLocalDeclGroup ds+checkStatement (StmtBind p e) = do+  checkPattern p >> insertPattern False p+  checkExpr e++checkAlt :: Alt () -> WCM ()+checkAlt (Alt _ p rhs) = inNestedScope $ do+  checkPattern p >> insertPattern False p+  checkRhs rhs+  reportUnusedVars++checkField :: (a -> WCM ()) -> Field a -> WCM ()+checkField check (Field _ _ x) = check x++-- -----------------------------------------------------------------------------+-- Check for orphan instances+-- -----------------------------------------------------------------------------++checkOrphanInstance :: Position -> Context -> QualIdent -> TypeExpr -> WCM ()+checkOrphanInstance p cx cls ty = warnFor WarnOrphanInstances $ do+  m <- getModuleIdent+  tcEnv <- gets tyConsEnv+  let ocls = getOrigName m cls tcEnv+      otc  = getOrigName m tc  tcEnv+  unless (isLocalIdent m ocls || isLocalIdent m otc) $ report $+    warnOrphanInstance p $ ppDecl $ InstanceDecl p cx cls ty []+  where tc = typeConstr ty++warnOrphanInstance :: Position -> Doc -> Message+warnOrphanInstance p doc = posMessage p $ text "Orphan instance:" <+> doc++-- -----------------------------------------------------------------------------+-- Check for missing method implementations+-- -----------------------------------------------------------------------------++checkMissingMethodImplementations :: Position -> QualIdent -> [Decl a] -> WCM ()+checkMissingMethodImplementations p cls ds = warnFor WarnMissingMethods $ do+  m <- getModuleIdent+  tcEnv <- gets tyConsEnv+  clsEnv <- gets classEnv+  let ocls = getOrigName m cls tcEnv+      ms   = classMethods ocls clsEnv+  mapM_ (report . warnMissingMethodImplementation p) $+    filter ((null fs ||) . not . flip (hasDefaultImpl ocls) clsEnv) $ ms \\ fs+  where fs = map unRenameIdent $ concatMap impls ds++warnMissingMethodImplementation :: Position -> Ident -> Message+warnMissingMethodImplementation p f = posMessage p $ hsep $ map text+  ["No explicit implementation for method", escName f]++-- -----------------------------------------------------------------------------+-- Check for missing type signatures+-- -----------------------------------------------------------------------------++-- |Check if every top-level function has an accompanying type signature.+-- For external function declarations, this check is already performed+-- during syntax checking.+checkMissingTypeSignatures :: [Decl a] -> WCM ()+checkMissingTypeSignatures ds = warnFor WarnMissingSignatures $ do+  let typedFs   = [f | TypeSig       _ fs _ <- ds, f <- fs]+      untypedFs = [f | FunctionDecl _ _ f _ <- ds, f `notElem` typedFs]+  unless (null untypedFs) $ do+    mid   <- getModuleIdent+    tyScs <- mapM getTyScheme untypedFs+    mapM_ report $ zipWith (warnMissingTypeSignature mid) untypedFs tyScs++getTyScheme :: Ident -> WCM TypeScheme+getTyScheme q = do+  m     <- getModuleIdent+  tyEnv <- gets valueEnv+  return $ case qualLookupValue (qualifyWith m q) tyEnv of+    [Value  _ _ _ tys] -> tys+    _ -> internalError $ "Checks.WarnCheck.getTyScheme: " ++ show q++warnMissingTypeSignature :: ModuleIdent -> Ident -> TypeScheme -> Message+warnMissingTypeSignature mid i tys = posMessage i $ fsep+  [ text "Top-level binding with no type signature:"+  , nest 2 $ text (showIdent i) <+> text "::" <+> ppTypeScheme mid tys+  ]++-- -----------------------------------------------------------------------------+-- Check for overlapping module alias names+-- -----------------------------------------------------------------------------++-- check if module aliases in import declarations overlap with the module name+-- or another module alias++checkModuleAlias :: [ImportDecl] -> WCM ()+checkModuleAlias is = do+  mid <- getModuleIdent+  let alias      = catMaybes [a | ImportDecl _ _ _ a _ <- is]+      modClash   = [a | a <- alias, a == mid]+      aliasClash = findMultiples alias+  unless (null   modClash) $ mapM_ (report . warnModuleNameClash) modClash+  unless (null aliasClash) $ mapM_ (report . warnAliasNameClash ) aliasClash++warnModuleNameClash :: ModuleIdent -> Message+warnModuleNameClash mid = posMessage mid $ hsep $ map text+  ["The module alias", escModuleName mid+  , "overlaps with the current module name"]++warnAliasNameClash :: [ModuleIdent] -> Message+warnAliasNameClash []         = internalError+  "WarnCheck.warnAliasNameClash: empty list"+warnAliasNameClash mids = posMessage (head mids) $ text+  "Overlapping module aliases" $+$ nest 2 (vcat (map myppAlias mids))+  where myppAlias mid@(ModuleIdent pos _) =+          ppLine pos <> text ":" <+> text (escModuleName mid)++-- -----------------------------------------------------------------------------+-- Check for overlapping/unreachable and non-exhaustive case alternatives+-- -----------------------------------------------------------------------------++checkCaseAlts :: CaseType -> [Alt ()] -> WCM ()+checkCaseAlts _  []                   = ok+checkCaseAlts ct alts@(Alt p _ _ : _) = do+  let pats = map (\(Alt _ pat _) -> [pat]) alts+  (nonExhaustive, overlapped, nondet) <- checkPatternMatching pats+  case ct of+    Flex -> do+      unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $+        warnMissingPattern p "an fcase alternative" nonExhaustive+      when (nondet || not (null overlapped)) $ warnFor WarnOverlapping $ report+        $ warnNondetOverlapping p "An fcase expression"+    Rigid -> do+      unless (null nonExhaustive) $ warnFor WarnIncompletePatterns $ report $+        warnMissingPattern p "a case alternative" nonExhaustive+      unless (null overlapped) $ warnFor WarnOverlapping $ report $+        warnUnreachablePattern p overlapped++-- -----------------------------------------------------------------------------+-- Check for non-exhaustive and overlapping patterns.+-- For an example, consider the following function definition:+-- @+-- f [True]    = 0+-- f (False:_) = 1+-- @+-- In this declaration, the following patterns are not matched:+-- @+-- [] _+-- (True:_:_)+-- @+-- This is identified and reported by the following code,, both for pattern+-- matching in function declarations and (f)case expressions.+-- -----------------------------------------------------------------------------++checkPatternMatching :: [[Pattern ()]]+                     -> WCM ([ExhaustivePats], [[Pattern ()]], Bool)+checkPatternMatching pats = do+  -- 1. We simplify the patterns by removing syntactic sugar temporarily+  --    for a simpler implementation.+  simplePats <- mapM (mapM simplifyPat) pats+  -- 2. We compute missing and used pattern matching alternatives+  (missing, used, nondet) <- processEqs (zip [1..] simplePats)+  -- 3. If any, we report the missing patterns, whereby we re-add the syntactic+  --    sugar removed in step (1) for a more precise output.+  nonExhaustive <- mapM tidyExhaustivePats missing+  let overlap = [ eqn | (i, eqn) <- zip [1..] pats, i `IntSet.notMember` used]+  return (nonExhaustive , overlap, nondet)++-- |Simplify a 'Pattern' until it only consists of+--   * Variables+--   * Integer, Float or Char literals+--   * Constructors+-- All other patterns like as-patterns, list patterns and alike are desugared.+simplifyPat :: Pattern () -> WCM (Pattern ())+simplifyPat p@(LiteralPattern      _ l) = return $ case l of+  String s -> simplifyListPattern $ map (LiteralPattern () . Char) s+  _        -> p+simplifyPat (NegativePattern       a l) = return $ LiteralPattern a (negateLit l)+  where+  negateLit (Int   n) = Int   (-n)+  negateLit (Float d) = Float (-d)+  negateLit x         = x+simplifyPat v@(VariablePattern     _ _) = return v+simplifyPat (ConstructorPattern a c ps) =+  ConstructorPattern a c `liftM` mapM simplifyPat ps+simplifyPat (InfixPattern    a p1 c p2) =+  ConstructorPattern a c `liftM` mapM simplifyPat [p1, p2]+simplifyPat (ParenPattern            p) = simplifyPat p+simplifyPat (RecordPattern      _ c fs) = do+  (_, ls) <- getAllLabels c+  let ps = map (getPattern (map field2Tuple fs)) ls+  simplifyPat (ConstructorPattern () c ps)+  where+    getPattern fs' l' =+      fromMaybe wildPat (lookup l' [(unqualify l, p) | (l, p) <- fs'])+simplifyPat (TuplePattern           ps) =+  ConstructorPattern () (qTupleId (length ps)) `liftM` mapM simplifyPat ps+simplifyPat (ListPattern          _ ps) =+  simplifyListPattern `liftM` mapM simplifyPat ps+simplifyPat (AsPattern             _ p) = simplifyPat p+simplifyPat (LazyPattern             _) = return wildPat+simplifyPat (FunctionPattern     _ _ _) = return wildPat+simplifyPat (InfixFuncPattern  _ _ _ _) = return wildPat++getAllLabels :: QualIdent -> WCM (QualIdent, [Ident])+getAllLabels c = do+  tyEnv <- gets valueEnv+  case qualLookupValue c tyEnv of+    [DataConstructor qc _ ls _] -> return (qc, ls)+    _                           -> internalError $+          "Checks.WarnCheck.getAllLabels: " ++ show c++-- |Create a simplified list pattern by applying @:@ and @[]@.+simplifyListPattern :: [Pattern ()] -> Pattern ()+simplifyListPattern = foldr (\p1 p2 -> ConstructorPattern () qConsId [p1, p2])+                            (ConstructorPattern () qNilId [])++-- |'ExhaustivePats' describes those pattern missing for an exhaustive+-- pattern matching, where a value can be thought of as a missing equation.+-- The first component contains the unmatched patterns, while the second+-- pattern contains an identifier and the literals matched for this identifier.+--+-- This is necessary when checking literal patterns because of the sheer+-- number of possible patterns. Missing literals are therefore converted+-- into the form @ ... x ... with x `notElem` [l1, ..., ln]@.+type EqnPats = [Pattern ()]+type EqnNo   = Int+type EqnInfo = (EqnNo, EqnPats)++type ExhaustivePats = (EqnPats, [(Ident, [Literal])])+type EqnSet  = IntSet.IntSet++-- |Compute the missing pattern by inspecting the first patterns and+-- categorize them as literal, constructor or variable patterns.+processEqs :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processEqs []              = return ([], IntSet.empty, False)+processEqs eqs@((n, ps):_)+  | null ps                    = return ([], IntSet.singleton n, length eqs > 1)+  | any isLitPat firstPats     = processLits eqs+  | any isConPat firstPats     = processCons eqs+  | all isVarPat firstPats     = processVars eqs+  | otherwise                  = internalError "Checks.WarnCheck.processEqs"+  where firstPats = map firstPat eqs++-- |Literal patterns are checked by extracting the matched literals+--  and constructing a pattern for any missing case.+processLits :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processLits []       = error "WarnCheck.processLits"+processLits qs@(q:_) = do+  -- Check any patterns starting with the literals used+  (missing1, used1, nd1) <- processUsedLits usedLits qs+  if null defaults+    then return $ (defaultPat : missing1, used1, nd1)+    else do+      -- Missing patterns for the default alternatives+      (missing2, used2, nd2) <- processEqs defaults+      return ( [ (wildPat : ps, cs) | (ps, cs) <- missing2 ] ++ missing1+             , IntSet.union used1 used2, nd1 || nd2 )+  where+  -- The literals occurring in the patterns+  usedLits   = nub $ concatMap (getLit . firstPat) qs+  -- default alternatives (variable pattern)+  defaults   = [ shiftPat q' | q' <- qs, isVarPat (firstPat q') ]+  -- Pattern for all non-matched literals+  defaultPat = ( VariablePattern () newVar :+                   replicate (length (snd q) - 1) wildPat+               , [(newVar, usedLits)]+               )+  newVar     = mkIdent "x"++-- |Construct exhaustive patterns starting with the used literals+processUsedLits :: [Literal] -> [EqnInfo]+                -> WCM ([ExhaustivePats], EqnSet, Bool)+processUsedLits lits qs = do+  (eps, idxs, nds) <- unzip3 `liftM` mapM process lits+  return (concat eps, IntSet.unions idxs, or nds)+  where+  process lit = do+    let qs' = [shiftPat q | q <- qs, isVarLit lit (firstPat q)]+        ovlp = length qs' > 1+    (missing, used, nd) <- processEqs qs'+    return ( map (\(xs, ys) -> (LiteralPattern () lit : xs, ys)) missing+           , used+           , nd && ovlp+           )++-- |Constructor patterns are checked by extracting the matched constructors+--  and constructing a pattern for any missing case.+processCons :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processCons []       = error "WarnCheck.processCons"+processCons qs@(q:_) = do+  -- Compute any missing patterns starting with the used constructors+  (missing1, used1, nd) <- processUsedCons used_cons qs+  -- Determine unused constructors+  unused   <- getUnusedCons (map fst used_cons)+  if null unused+    then return (missing1, used1, nd)+    else if null defaults+      then return $ (map defaultPat unused ++ missing1, used1, nd)+      else do+        -- Missing patterns for the default alternatives+        (missing2, used2, nd2) <- processEqs defaults+        return ( [ (mkPattern c : ps, cs) | c <- unused, (ps, cs) <- missing2 ]+                  ++ missing1+               , IntSet.union used1 used2, nd || nd2)+  where+  -- used constructors (occurring in a pattern)+  used_cons    = nub $ concatMap (getCon . firstPat) qs+  -- default alternatives (variable pattern)+  defaults     = [ shiftPat q' | q' <- qs, isVarPat (firstPat q') ]+  -- Pattern for a non-matched constructors+  defaultPat c = (mkPattern c : replicate (length (snd q) - 1) wildPat, [])+  mkPattern  c = ConstructorPattern ()+                  (qualifyLike (fst $ head used_cons) (constrIdent c))+                  (replicate (length $ constrTypes c) wildPat)++-- |Construct exhaustive patterns starting with the used constructors+processUsedCons :: [(QualIdent, Int)] -> [EqnInfo]+                -> WCM ([ExhaustivePats], EqnSet, Bool)+processUsedCons cons qs = do+  (eps, idxs, nds) <- unzip3 `liftM` mapM process cons+  return (concat eps, IntSet.unions idxs, or nds)+  where+  process (c, a) = do+    let qs' = [ removeFirstCon c a q | q <- qs , isVarCon c (firstPat q)]+        ovlp = length qs' > 1+    (missing, used, nd) <- processEqs qs'+    return (map (\(xs, ys) -> (makeCon c a xs, ys)) missing, used, nd && ovlp)++  makeCon c a ps = let (args, rest) = splitAt a ps+                   in ConstructorPattern () c args : rest++  removeFirstCon c a (n, p:ps)+    | isVarPat p = (n, replicate a wildPat ++ ps)+    | isCon c  p = (n, patArgs p           ++ ps)+  removeFirstCon _ _ _ = internalError "Checks.WarnCheck.removeFirstCon"++-- |Variable patterns are exhaustive, so they are checked by simply+-- checking the following patterns.+processVars :: [EqnInfo] -> WCM ([ExhaustivePats], EqnSet, Bool)+processVars []               = error "WarnCheck.processVars"+processVars eqs@((n, _) : _) = do+  let ovlp = length eqs > 1+  (missing, used, nd) <- processEqs (map shiftPat eqs)+  return ( map (\(xs, ys) -> (wildPat : xs, ys)) missing+         , IntSet.insert n used, nd && ovlp)++-- |Return the constructors of a type not contained in the list of constructors.+getUnusedCons :: [QualIdent] -> WCM [DataConstr]+getUnusedCons []       = internalError "Checks.WarnCheck.getUnusedCons"+getUnusedCons qs@(q:_) = do+  allCons <- getConTy q >>= getTyCons . rootOfType . arrowBase+  return [c | c <- allCons, (constrIdent c) `notElem` map unqualify qs]++-- |Retrieve the type of a given constructor.+getConTy :: QualIdent -> WCM Type+getConTy q = do+  tyEnv <- gets valueEnv+  tcEnv <- gets tyConsEnv+  case qualLookupValue q tyEnv of+    [DataConstructor  _ _ _ (ForAllExist _ _ (PredType _ ty))] -> return ty+    [NewtypeConstructor _ _ (ForAllExist _ _ (PredType _ ty))] -> return ty+    _ -> case qualLookupTypeInfo q tcEnv of+      [AliasType _ _ _ ty] -> return ty+      _ -> internalError $ "Checks.WarnCheck.getConTy: " ++ show q++-- |Retrieve all constructors of a given type.+getTyCons :: QualIdent -> WCM [DataConstr]+getTyCons tc = do+  tc'   <- unAlias tc+  tcEnv <- gets tyConsEnv+  return $ case lookupTypeInfo (unqualify tc) tcEnv of+    [DataType     _ _ cs] -> cs+    [RenamingType _ _ nc] -> [nc]+    _ -> case qualLookupTypeInfo tc' tcEnv of+      [DataType     _ _ cs] -> cs+      [RenamingType _ _ nc] -> [nc]+      err -> internalError $ "Checks.WarnCheck.getTyCons: " +++                               show tc ++ ' ' : show err ++ '\n' : show tcEnv++-- |Resugar the exhaustive patterns previously desugared at 'simplifyPat'.+tidyExhaustivePats :: ExhaustivePats -> WCM ExhaustivePats+tidyExhaustivePats (xs, ys) = mapM tidyPat xs >>= \xs' -> return (xs', ys)++-- |Resugar a pattern previously desugared at 'simplifyPat', i.e.+--   * Convert a tuple constructor pattern into a tuple pattern+--   * Convert a list constructor pattern representing a finite list+--     into a list pattern+tidyPat :: Pattern () -> WCM (Pattern ())+tidyPat p@(LiteralPattern        _ _) = return p+tidyPat p@(VariablePattern       _ _) = return p+tidyPat p@(ConstructorPattern _ c ps)+  | isQTupleId c                      =+    TuplePattern `liftM` mapM tidyPat ps+  | c == qConsId && isFiniteList p    =+    ListPattern () `liftM` mapM tidyPat (unwrapFinite p)+  | c == qConsId                      = unwrapInfinite p+  | otherwise                         =+    ConstructorPattern () c `liftM` mapM tidyPat ps+  where+  isFiniteList (ConstructorPattern _ d []     )                = d == qNilId+  isFiniteList (ConstructorPattern _ d [_, e2]) | d == qConsId = isFiniteList e2+  isFiniteList _                                               = False++  unwrapFinite (ConstructorPattern _ _ []     ) = []+  unwrapFinite (ConstructorPattern _ _ [p1,p2]) = p1 : unwrapFinite p2+  unwrapFinite pat+    = internalError $ "WarnCheck.tidyPat.unwrapFinite: " ++ show pat++  unwrapInfinite (ConstructorPattern a d [p1,p2]) =+    liftM2 (flip (InfixPattern a) d) (tidyPat p1) (unwrapInfinite p2)+  unwrapInfinite p0                               = return p0++tidyPat p = internalError $ "Checks.WarnCheck.tidyPat: " ++ show p++-- |Get the first pattern of a list.+firstPat :: EqnInfo -> Pattern ()+firstPat (_, []   ) = internalError "Checks.WarnCheck.firstPat: empty list"+firstPat (_, (p:_)) = p++-- |Drop the first pattern of a list.+shiftPat :: EqnInfo -> EqnInfo+shiftPat (_, []    ) = internalError "Checks.WarnCheck.shiftPat: empty list"+shiftPat (n, (_:ps)) = (n, ps)++-- |Wildcard pattern.+wildPat :: Pattern ()+wildPat = VariablePattern () anonId++-- |Retrieve any literal out of a pattern.+getLit :: Pattern a -> [Literal]+getLit (LiteralPattern _ l) = [l]+getLit _                    = []++-- |Retrieve the constructor name and its arity for a pattern.+getCon :: Pattern a -> [(QualIdent, Int)]+getCon (ConstructorPattern _ c ps) = [(c, length ps)]+getCon _                           = []++-- |Is a pattern a variable or literal pattern?+isVarLit :: Literal -> Pattern a -> Bool+isVarLit l p = isVarPat p || isLit l p++-- |Is a pattern a variable or a constructor pattern with the given constructor?+isVarCon :: QualIdent -> Pattern a -> Bool+isVarCon c p = isVarPat p || isCon c p++-- |Is a pattern a pattern matching for the given constructor?+isCon :: QualIdent -> Pattern a -> Bool+isCon c (ConstructorPattern _ d _) = c == d+isCon _ _                          = False++-- |Is a pattern a pattern matching for the given literal?+isLit :: Literal -> Pattern a -> Bool+isLit l (LiteralPattern _ m) = l == m+isLit _ _                    = False++-- |Is a pattern a literal pattern?+isLitPat :: Pattern a -> Bool+isLitPat (LiteralPattern  _ _) = True+isLitPat _                     = False++-- |Is a pattern a variable pattern?+isVarPat :: Pattern a -> Bool+isVarPat (VariablePattern _ _) = True+isVarPat _                     = False++-- |Is a pattern a constructor pattern?+isConPat :: Pattern a -> Bool+isConPat (ConstructorPattern _ _ _) = True+isConPat _                          = False++-- |Retrieve the arguments of a pattern.+patArgs :: Pattern a -> [Pattern a]+patArgs (ConstructorPattern _ _ ps) = ps+patArgs _                           = []++-- |Warning message for non-exhaustive patterns.+-- To shorten the output only the first 'maxPattern' are printed,+-- additional pattern are abbreviated by dots.+warnMissingPattern :: Position -> String -> [ExhaustivePats] -> Message+warnMissingPattern p loc pats = posMessage p+  $   text "Pattern matches are non-exhaustive"+  $+$ text "In" <+> text loc <> char ':'+  $+$ nest 2 (text "Patterns not matched:" $+$ nest 2 (vcat (ppExPats pats)))+  where+  ppExPats ps+    | length ps > maxPattern = ppPats ++ [text "..."]+    | otherwise              = ppPats+    where ppPats = map ppExPat (take maxPattern ps)+  ppExPat (ps, cs)+    | null cs   = ppPats+    | otherwise = ppPats <+> text "with" <+> hsep (map ppCons cs)+    where ppPats = hsep (map (ppPattern 2) ps)+  ppCons (i, lits) = ppIdent i <+> text "`notElem`"+                 <+> ppExpr 0 (List () (map (Literal ()) lits))++-- |Warning message for unreachable patterns.+-- To shorten the output only the first 'maxPattern' are printed,+-- additional pattern are abbreviated by dots.+warnUnreachablePattern :: Position  -> [[Pattern a]] -> Message+warnUnreachablePattern p pats = posMessage p+  $   text "Pattern matches are potentially unreachable"+  $+$ text "In a case alternative:"+  $+$ nest 2 (vcat (ppExPats pats) <+> text "->" <+> text "...")+  where+  ppExPats ps+    | length ps > maxPattern = ppPats ++ [text "..."]+    | otherwise              = ppPats+    where ppPats = map ppPat (take maxPattern ps)+  ppPat ps = hsep (map (ppPattern 2) ps)++-- |Maximum number of missing patterns to be shown.+maxPattern :: Int+maxPattern = 4++warnNondetOverlapping :: Position -> String -> Message+warnNondetOverlapping p loc = posMessage p $+  text loc <+> text "is potentially non-deterministic due to overlapping rules"++-- -----------------------------------------------------------------------------++checkShadowing :: Ident -> WCM ()+checkShadowing x = warnFor WarnNameShadowing $+  shadowsVar x >>= maybe ok (report . warnShadowing x)++checkTypeShadowing :: Ident -> WCM ()+checkTypeShadowing x = warnFor WarnNameShadowing $+  shadowsTypeVar x >>= maybe ok (report . warnTypeShadowing x)++reportUnusedVars :: WCM ()+reportUnusedVars = reportAllUnusedVars WarnUnusedBindings++reportUnusedGlobalVars :: WCM ()+reportUnusedGlobalVars = reportAllUnusedVars WarnUnusedGlobalBindings++reportAllUnusedVars :: WarnFlag -> WCM ()+reportAllUnusedVars wFlag = warnFor wFlag $ do+  unused <- returnUnrefVars+  unless (null unused) $ mapM_ report $ map warnUnrefVar unused++reportUnusedTypeVars :: [Ident] -> WCM ()+reportUnusedTypeVars vs = warnFor WarnUnusedBindings $ do+  unused <- filterM isUnrefTypeVar vs+  unless (null unused) $ mapM_ report $ map warnUnrefTypeVar unused++-- ---------------------------------------------------------------------------+-- For detecting unreferenced variables, the following functions update the+-- current check state by adding identifiers occuring in declaration left hand+-- sides.++insertDecl :: Decl a -> WCM ()+insertDecl (DataDecl     _ d _ cs _) = do+  insertTypeConsId d+  mapM_ insertConstrDecl cs+insertDecl (ExternalDataDecl  _ d _) = insertTypeConsId d+insertDecl (NewtypeDecl  _ d _ nc _) = do+  insertTypeConsId d+  insertNewConstrDecl nc+insertDecl (TypeDecl       _ t _ ty) = do+  insertTypeConsId t+  insertTypeExpr ty+insertDecl (FunctionDecl    _ _ f _) = do+  cons <- isConsId f+  unless cons $ insertVar f+insertDecl (ExternalDecl       _ vs) = mapM_ (insertVar . varIdent) vs+insertDecl (PatternDecl       _ p _) = insertPattern False p+insertDecl (FreeDecl           _ vs) = mapM_ (insertVar . varIdent) vs+insertDecl (ClassDecl _ _ cls _  ds) = do+  insertTypeConsId cls+  mapM_ insertVar $ concatMap methods ds+insertDecl _                         = ok++insertTypeExpr :: TypeExpr -> WCM ()+insertTypeExpr (VariableType        _) = ok+insertTypeExpr (ConstructorType     _) = ok+insertTypeExpr (ApplyType     ty1 ty2) = mapM_ insertTypeExpr [ty1,ty2]+insertTypeExpr (TupleType         tys) = mapM_ insertTypeExpr tys+insertTypeExpr (ListType           ty) = insertTypeExpr ty+insertTypeExpr (ArrowType     ty1 ty2) = mapM_ insertTypeExpr [ty1,ty2]+insertTypeExpr (ParenType          ty) = insertTypeExpr ty+insertTypeExpr (ForallType       _ ty) = insertTypeExpr ty++insertConstrDecl :: ConstrDecl -> WCM ()+insertConstrDecl (ConstrDecl _ _ _    c _) = insertConsId c+insertConstrDecl (ConOpDecl  _ _ _ _ op _) = insertConsId op+insertConstrDecl (RecordDecl _ _ _    c _) = insertConsId c++insertNewConstrDecl :: NewConstrDecl -> WCM ()+insertNewConstrDecl (NewConstrDecl _ c _) = insertConsId c+insertNewConstrDecl (NewRecordDecl _ c _) = insertConsId c++-- 'fp' indicates whether 'checkPattern' deals with the arguments+-- of a function pattern or not.+-- Since function patterns are not recognized before syntax check, it is+-- necessary to determine whether a constructor pattern represents a+-- constructor or a function.+insertPattern :: Bool -> Pattern a -> WCM ()+insertPattern fp (VariablePattern        _ v) = do+  cons <- isConsId v+  unless cons $ do+    var <- isVarId v+    if and [fp, var, not (isAnonId v)] then visitId v else insertVar v+insertPattern fp (ConstructorPattern  _ c ps) = do+  cons <- isQualConsId c+  mapM_ (insertPattern (not cons || fp)) ps+insertPattern fp (InfixPattern     a p1 c p2)+  = insertPattern fp (ConstructorPattern a c [p1, p2])+insertPattern fp (ParenPattern             p) = insertPattern fp p+insertPattern fp (RecordPattern       _ _ fs) = mapM_ (insertFieldPattern fp) fs+insertPattern fp (TuplePattern            ps) = mapM_ (insertPattern fp) ps+insertPattern fp (ListPattern           _ ps) = mapM_ (insertPattern fp) ps+insertPattern fp (AsPattern              v p) = insertVar v >> insertPattern fp p+insertPattern fp (LazyPattern              p) = insertPattern fp p+insertPattern _  (FunctionPattern     _ f ps) = do+  visitQId f+  mapM_ (insertPattern True) ps+insertPattern _  (InfixFuncPattern a p1 f p2)+  = insertPattern True (FunctionPattern a f [p1, p2])+insertPattern _ _ = ok++insertFieldPattern :: Bool -> Field (Pattern a) -> WCM ()+insertFieldPattern fp (Field _ _ p) = insertPattern fp p++-- ---------------------------------------------------------------------------++-- Data type for distinguishing identifiers as either (type) constructors or+-- (type) variables (including functions).+data IdInfo+  = ConsInfo           -- ^ Constructor+  | VarInfo Ident Bool -- ^ Variable with original definition (for position)+                       --   and used flag+  deriving Show++isVariable :: IdInfo -> Bool+isVariable (VarInfo _ _) = True+isVariable _             = False++getVariable :: IdInfo -> Maybe Ident+getVariable (VarInfo v _) = Just v+getVariable _             = Nothing++isConstructor :: IdInfo -> Bool+isConstructor ConsInfo = True+isConstructor _        = False++variableVisited :: IdInfo -> Bool+variableVisited (VarInfo _ v) = v+variableVisited _             = True++visitVariable :: IdInfo -> IdInfo+visitVariable (VarInfo v _) = VarInfo v True+visitVariable  info         = info++insertScope :: QualIdent -> IdInfo -> WCM ()+insertScope qid info = modifyScope $ qualBindNestEnv qid info++insertVar :: Ident -> WCM ()+insertVar v = unless (isAnonId v) $ do+  known <- isKnownVar v+  if known then visitId v else insertScope (commonId v) (VarInfo v False)++insertTypeVar :: Ident -> WCM ()+insertTypeVar v = unless (isAnonId v)+                $ insertScope (typeId v) (VarInfo v False)++insertConsId :: Ident -> WCM ()+insertConsId c = insertScope (commonId c) ConsInfo++insertTypeConsId :: Ident -> WCM ()+insertTypeConsId c = insertScope (typeId c) ConsInfo++isVarId :: Ident -> WCM Bool+isVarId v = gets (isVar $ commonId v)++isConsId :: Ident -> WCM Bool+isConsId c = gets (isCons $ qualify c)++isQualConsId :: QualIdent -> WCM Bool+isQualConsId qid = gets (isCons qid)++shadows :: QualIdent -> WcState -> Maybe Ident+shadows qid s = do+  guard $ not (qualInLocalNestEnv qid sc)+  info      <- listToMaybe $ qualLookupNestEnv qid sc+  getVariable info+  where sc = scope s++shadowsVar :: Ident -> WCM (Maybe Ident)+shadowsVar v = gets (shadows $ commonId v)++shadowsTypeVar :: Ident -> WCM (Maybe Ident)+shadowsTypeVar v = gets (shadows $ typeId v)++visitId :: Ident -> WCM ()+visitId v = modifyScope (qualModifyNestEnv visitVariable (commonId v))++visitQId :: QualIdent -> WCM ()+visitQId v = do+  mid <- getModuleIdent+  maybe ok visitId (localIdent mid v)++visitTypeId :: Ident -> WCM ()+visitTypeId v = modifyScope (qualModifyNestEnv visitVariable (typeId v))++visitQTypeId :: QualIdent -> WCM ()+visitQTypeId v = do+  mid <- getModuleIdent+  maybe ok visitTypeId (localIdent mid v)++isKnownVar :: Ident -> WCM Bool+isKnownVar v = gets $ \s -> isKnown s (commonId v)++isUnrefTypeVar :: Ident -> WCM Bool+isUnrefTypeVar v = gets (\s -> isUnref s (typeId v))++returnUnrefVars :: WCM [Ident]+returnUnrefVars = gets (\s ->+  let ids    = map fst (localNestEnv (scope s))+      unrefs = filter (isUnref s . qualify) ids+  in  unrefs )++inNestedScope :: WCM a -> WCM ()+inNestedScope m = beginScope >> m >> endScope++beginScope :: WCM ()+beginScope = modifyScope nestEnv++endScope :: WCM ()+endScope = modifyScope unnestEnv++------------------------------------------------------------------------------++isKnown :: WcState -> QualIdent -> Bool+isKnown s qid = qualInLocalNestEnv qid (scope s)++isUnref :: WcState -> QualIdent -> Bool+isUnref s qid = let sc = scope s+                in  (any (not . variableVisited) (qualLookupNestEnv qid sc))+                    && qualInLocalNestEnv qid sc++isVar :: QualIdent -> WcState -> Bool+isVar qid s = maybe (isAnonId (unqualify qid))+                    isVariable+                    (listToMaybe (qualLookupNestEnv qid (scope s)))++isCons :: QualIdent -> WcState -> Bool+isCons qid s = maybe (isImportedCons s qid)+                      isConstructor+                      (listToMaybe (qualLookupNestEnv qid (scope s)))+ where isImportedCons s' qid' = case qualLookupValue qid' (valueEnv s') of+          (DataConstructor  _ _ _ _) : _ -> True+          (NewtypeConstructor _ _ _) : _ -> True+          _                              -> False++-- Since type identifiers and normal identifiers (e.g. functions, variables+-- or constructors) don't share the same namespace, it is necessary+-- to distinguish them in the scope environment of the check state.+-- For this reason type identifiers are annotated with 1 and normal+-- identifiers are annotated with 0.+commonId :: Ident -> QualIdent+commonId = qualify . unRenameIdent++typeId :: Ident -> QualIdent+typeId = qualify . flip renameIdent 1+++-- --------------------------------------------------------------------------+-- Check Case Mode+-- --------------------------------------------------------------------------+++-- The following functions traverse the AST and search for (defining)+-- identifiers and check if their names have the appropriate case mode.+checkCaseMode :: [Decl a] -> WCM ()+checkCaseMode = warnFor WarnIrregularCaseMode . mapM_ checkCaseModeDecl++checkCaseModeDecl :: Decl a -> WCM ()+checkCaseModeDecl (DataDecl _ tc vs cs _) = do+  checkCaseModeID isDataDeclName tc+  mapM_ (checkCaseModeID isVarName) vs+  mapM_ checkCaseModeConstr cs+checkCaseModeDecl (NewtypeDecl _ tc vs nc _) = do+  checkCaseModeID isDataDeclName tc+  mapM_ (checkCaseModeID isVarName) vs+  checkCaseModeNewConstr nc+checkCaseModeDecl (TypeDecl _ tc vs ty) = do+  checkCaseModeID isDataDeclName tc+  mapM_ (checkCaseModeID isVarName) vs+  checkCaseModeTypeExpr ty+checkCaseModeDecl (TypeSig _ fs qty) = do+  mapM_ (checkCaseModeID isFuncName) fs+  checkCaseModeQualTypeExpr qty+checkCaseModeDecl (FunctionDecl _ _ f eqs) = do+  checkCaseModeID isFuncName f+  mapM_ checkCaseModeEquation eqs+checkCaseModeDecl (ExternalDecl _ vs) =+  mapM_ (checkCaseModeID isFuncName . varIdent) vs+checkCaseModeDecl (PatternDecl _ t rhs) = do+  checkCaseModePattern t+  checkCaseModeRhs rhs+checkCaseModeDecl (FreeDecl  _ vs) =+  mapM_ (checkCaseModeID isVarName . varIdent) vs+checkCaseModeDecl (DefaultDecl _ tys) = mapM_ checkTypeExpr tys+checkCaseModeDecl (ClassDecl _ cx cls tv ds) = do+  checkCaseModeContext cx+  checkCaseModeID isClassDeclName cls+  checkCaseModeID isVarName tv+  mapM_ checkCaseModeDecl ds+checkCaseModeDecl (InstanceDecl _ cx _ inst ds) = do+  checkCaseModeContext cx+  checkCaseModeTypeExpr inst+  mapM_ checkCaseModeDecl ds+checkCaseModeDecl _ = ok++checkCaseModeConstr :: ConstrDecl -> WCM ()+checkCaseModeConstr (ConstrDecl _ evs cx c tys) = do+  mapM_ (checkCaseModeID isVarName) evs+  checkCaseModeContext cx+  checkCaseModeID isConstrName c+  mapM_ checkCaseModeTypeExpr tys+checkCaseModeConstr (ConOpDecl  _ evs cx ty1 c ty2) = do+  mapM_ (checkCaseModeID isVarName) evs+  checkCaseModeContext cx+  checkCaseModeTypeExpr ty1+  checkCaseModeID isConstrName c+  checkCaseModeTypeExpr ty2+checkCaseModeConstr (RecordDecl _ evs cx c fs) = do+  mapM_ (checkCaseModeID isVarName) evs+  checkCaseModeContext cx+  checkCaseModeID isConstrName c+  mapM_ checkCaseModeFieldDecl fs++checkCaseModeFieldDecl :: FieldDecl -> WCM ()+checkCaseModeFieldDecl (FieldDecl _ fs ty) = do+  mapM_ (checkCaseModeID isFuncName) fs+  checkCaseModeTypeExpr ty++checkCaseModeNewConstr :: NewConstrDecl -> WCM ()+checkCaseModeNewConstr (NewConstrDecl _ nc ty) = do+  checkCaseModeID isConstrName nc+  checkCaseModeTypeExpr ty+checkCaseModeNewConstr (NewRecordDecl _ nc (f, ty)) = do+  checkCaseModeID isConstrName nc+  checkCaseModeID isFuncName f+  checkCaseModeTypeExpr ty++checkCaseModeContext :: Context -> WCM ()+checkCaseModeContext = mapM_ checkCaseModeConstraint++checkCaseModeConstraint :: Constraint -> WCM ()+checkCaseModeConstraint (Constraint _ ty) = checkCaseModeTypeExpr ty++checkCaseModeTypeExpr :: TypeExpr -> WCM ()+checkCaseModeTypeExpr (ApplyType ty1 ty2) = do+  checkCaseModeTypeExpr ty1+  checkCaseModeTypeExpr ty2+checkCaseModeTypeExpr (VariableType tv) = checkCaseModeID isVarName tv+checkCaseModeTypeExpr (TupleType tys) = mapM_ checkCaseModeTypeExpr tys+checkCaseModeTypeExpr (ListType ty) = checkCaseModeTypeExpr ty+checkCaseModeTypeExpr (ArrowType ty1 ty2) = do+  checkCaseModeTypeExpr ty1+  checkCaseModeTypeExpr ty2+checkCaseModeTypeExpr (ParenType ty) = checkCaseModeTypeExpr ty+checkCaseModeTypeExpr (ForallType tvs ty) = do+  mapM_ (checkCaseModeID isVarName) tvs+  checkCaseModeTypeExpr ty+checkCaseModeTypeExpr _ = ok++checkCaseModeQualTypeExpr :: QualTypeExpr -> WCM ()+checkCaseModeQualTypeExpr (QualTypeExpr cx ty) = do+  checkCaseModeContext cx+  checkCaseModeTypeExpr ty++checkCaseModeEquation :: Equation a -> WCM ()+checkCaseModeEquation (Equation _ lhs rhs) = do+  checkCaseModeLhs lhs+  checkCaseModeRhs rhs++checkCaseModeLhs :: Lhs a -> WCM ()+checkCaseModeLhs (FunLhs f ts) = do+  checkCaseModeID isFuncName f+  mapM_ checkCaseModePattern ts+checkCaseModeLhs (OpLhs t1 f t2) = do+  checkCaseModePattern t1+  checkCaseModeID isFuncName f+  checkCaseModePattern t2+checkCaseModeLhs (ApLhs lhs ts) = do+  checkCaseModeLhs lhs+  mapM_ checkCaseModePattern ts++checkCaseModeRhs :: Rhs a -> WCM ()+checkCaseModeRhs (SimpleRhs _ e ds) = do+  checkCaseModeExpr e+  mapM_ checkCaseModeDecl ds+checkCaseModeRhs (GuardedRhs es ds) = do+  mapM_ checkCaseModeCondExpr es+  mapM_ checkCaseModeDecl ds++checkCaseModeCondExpr :: CondExpr a -> WCM ()+checkCaseModeCondExpr (CondExpr _ g e) = do+  checkCaseModeExpr g+  checkCaseModeExpr e++checkCaseModePattern :: Pattern a -> WCM ()+checkCaseModePattern (VariablePattern _ v) = checkCaseModeID isVarName v+checkCaseModePattern (ConstructorPattern _ _ ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (InfixPattern _ t1 _ t2) = do+  checkCaseModePattern t1+  checkCaseModePattern t2+checkCaseModePattern (ParenPattern t) = checkCaseModePattern t+checkCaseModePattern (RecordPattern _ _ fs) = mapM_ checkCaseModeFieldPattern fs+checkCaseModePattern (TuplePattern ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (ListPattern _ ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (AsPattern v t) = do+  checkCaseModeID isVarName v+  checkCaseModePattern t+checkCaseModePattern (LazyPattern t) = checkCaseModePattern t+checkCaseModePattern (FunctionPattern _ _ ts) = mapM_ checkCaseModePattern ts+checkCaseModePattern (InfixFuncPattern _ t1 _ t2) = do+  checkCaseModePattern t1+  checkCaseModePattern t2+checkCaseModePattern _ = ok++checkCaseModeExpr :: Expression a -> WCM ()+checkCaseModeExpr (Paren e) = checkCaseModeExpr e+checkCaseModeExpr (Typed e qty) = do+  checkCaseModeExpr e+  checkCaseModeQualTypeExpr qty+checkCaseModeExpr (Record _ _ fs) = mapM_ checkCaseModeFieldExpr fs+checkCaseModeExpr (RecordUpdate e fs) = do+  checkCaseModeExpr e+  mapM_ checkCaseModeFieldExpr fs+checkCaseModeExpr (Tuple es) = mapM_ checkCaseModeExpr es+checkCaseModeExpr (List  _ es) = mapM_ checkCaseModeExpr es+checkCaseModeExpr (ListCompr e stms)  = do+  checkCaseModeExpr e+  mapM_ checkCaseModeStatement stms+checkCaseModeExpr (EnumFrom e) = checkCaseModeExpr e+checkCaseModeExpr (EnumFromThen e1 e2) = do+  checkCaseModeExpr e1+  checkCaseModeExpr e2+checkCaseModeExpr (EnumFromTo e1 e2) = do+  checkCaseModeExpr e1+  checkCaseModeExpr e2+checkCaseModeExpr (EnumFromThenTo e1 e2 e3) = do+  checkCaseModeExpr e1+  checkCaseModeExpr e2+  checkCaseModeExpr e3+checkCaseModeExpr (UnaryMinus e) = checkCaseModeExpr e+checkCaseModeExpr (Apply e1 e2) = do+  checkCaseModeExpr e1+  checkCaseModeExpr e2+checkCaseModeExpr (InfixApply e1 _ e2) = do+  checkCaseModeExpr e1+  checkCaseModeExpr e2+checkCaseModeExpr (LeftSection e _) = checkCaseModeExpr e+checkCaseModeExpr (RightSection _ e) = checkCaseModeExpr e+checkCaseModeExpr (Lambda ts e) = do+  mapM_ checkCaseModePattern ts+  checkCaseModeExpr e+checkCaseModeExpr (Let ds e) = do+  mapM_ checkCaseModeDecl ds+  checkCaseModeExpr e+checkCaseModeExpr (Do stms e) = do+  mapM_ checkCaseModeStatement stms+  checkCaseModeExpr e+checkCaseModeExpr (IfThenElse e1 e2 e3) = do+  checkCaseModeExpr e1+  checkCaseModeExpr e2+  checkCaseModeExpr e3+checkCaseModeExpr (Case _ e as) = do+  mapM_ checkCaseModeAlt as+  checkCaseModeExpr e+checkCaseModeExpr _ = ok++checkCaseModeStatement :: Statement a -> WCM ()+checkCaseModeStatement (StmtExpr e) = checkCaseModeExpr e+checkCaseModeStatement (StmtDecl ds) = mapM_ checkCaseModeDecl ds+checkCaseModeStatement (StmtBind t e) = do+  checkCaseModePattern t+  checkCaseModeExpr e++checkCaseModeAlt :: Alt a -> WCM ()+checkCaseModeAlt (Alt _ t rhs) = checkCaseModePattern t >> checkCaseModeRhs rhs++checkCaseModeFieldPattern :: Field (Pattern a) -> WCM ()+checkCaseModeFieldPattern (Field _ _ t) = checkCaseModePattern t++checkCaseModeFieldExpr :: Field (Expression a) -> WCM ()+checkCaseModeFieldExpr (Field _ _ e) = checkCaseModeExpr e++checkCaseModeID :: (CaseMode -> String -> Bool) -> Ident -> WCM ()+checkCaseModeID f i@(Ident _ name _) = do+  c <- gets caseMode+  unless (f c name) (report $ warnCaseMode i c)++isVarName :: CaseMode -> String -> Bool+isVarName CaseModeProlog  (x:_) | isAlpha x = isUpper x+isVarName CaseModeGoedel  (x:_) | isAlpha x = isLower x+isVarName CaseModeHaskell (x:_) | isAlpha x = isLower x+isVarName _               _     = True++isFuncName :: CaseMode -> String -> Bool+isFuncName CaseModeHaskell (x:_) | isAlpha x = isLower x+isFuncName CaseModeGoedel  (x:_) | isAlpha x = isUpper x+isFuncName CaseModeProlog  (x:_) | isAlpha x = isLower x+isFuncName _               _     = True++isConstrName :: CaseMode -> String -> Bool+isConstrName = isDataDeclName++isClassDeclName :: CaseMode -> String -> Bool+isClassDeclName = isDataDeclName++isDataDeclName :: CaseMode -> String -> Bool+isDataDeclName CaseModeProlog  (x:_) | isAlpha x = isLower x+isDataDeclName CaseModeGoedel  (x:_) | isAlpha x = isUpper x+isDataDeclName CaseModeHaskell (x:_) | isAlpha x = isUpper x+isDataDeclName _               _     = True++-- ---------------------------------------------------------------------------+-- Warnings messages+-- ---------------------------------------------------------------------------++warnCaseMode :: Ident -> CaseMode -> Message+warnCaseMode i@(Ident _ name _ ) c = posMessage i $+  text "Wrong case mode in symbol" <+> text (escName i) <+>+  text "due to selected case mode" <+> text (escapeCaseMode c) <> comma <+>+  text "try renaming to" <+> text (caseSuggestion name) <+> text "instead"++caseSuggestion :: String -> String+caseSuggestion (x:xs) | isLower x = (toUpper x : xs)+                      | isUpper x = (toLower x : xs)+caseSuggestion _      = internalError+ "Checks.WarnCheck.caseSuggestion: Identifier starts with illegal Symbol"++escapeCaseMode :: CaseMode -> String+escapeCaseMode CaseModeFree    = "`free`"+escapeCaseMode CaseModeHaskell = "`haskell`"+escapeCaseMode CaseModeProlog  = "`prolog`"+escapeCaseMode CaseModeGoedel  = "`goedel`"++warnUnrefTypeVar :: Ident -> Message+warnUnrefTypeVar v = posMessage v $ hsep $ map text+  [ "Unreferenced type variable", escName v ]++warnUnrefVar :: Ident -> Message+warnUnrefVar v = posMessage v $ hsep $ map text+  [ "Unused declaration of variable", escName v ]++warnShadowing :: Ident -> Ident -> Message+warnShadowing x v = posMessage x $+  text "Shadowing symbol" <+> text (escName x)+  <> comma <+> text "bound at:" <+> ppPosition (getPosition v)++warnTypeShadowing :: Ident -> Ident -> Message+warnTypeShadowing x v = posMessage x $+  text "Shadowing type variable" <+> text (escName x)+  <> comma <+> text "bound at:" <+> ppPosition (getPosition v)
+ src/CompilerEnv.hs view
@@ -0,0 +1,117 @@+{- |+    Module      :  $Header$+    Description :  Environment containing the module's information+    Copyright   :  (c) 2011 - 2015 Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module defines the compilation environment for a single module,+     containing the information needed throughout the compilation process.+-}+module CompilerEnv where++import qualified Data.Map as Map (Map, keys, toList)++import Curry.Base.Ident    (ModuleIdent, moduleName)+import Curry.Base.Pretty+import Curry.Base.Span   (Span)+import Curry.Syntax++import Base.TopEnv (allBindings, allLocalBindings)++import Env.Class+import Env.Instance+import Env.Interface+import Env.ModuleAlias (AliasEnv, initAliasEnv)+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++type CompEnv a = (CompilerEnv, a)++-- |A compiler environment contains information about the module currently+--  compiled. The information is updated during the different stages of+--  compilation.+data CompilerEnv = CompilerEnv+  { moduleIdent  :: ModuleIdent         -- ^ identifier of the module+  , filePath     :: FilePath            -- ^ 'FilePath' of compilation target+  , extensions   :: [KnownExtension]    -- ^ enabled language extensions+  , tokens       :: [(Span, Token)]     -- ^ token list of module+  , interfaceEnv :: InterfaceEnv        -- ^ declarations of imported interfaces+  , aliasEnv     :: AliasEnv            -- ^ aliases for imported modules+  , tyConsEnv    :: TCEnv               -- ^ type constructors and type classes+  , classEnv     :: ClassEnv            -- ^ all type classes with their super classes+  , instEnv      :: InstEnv             -- ^ instances+  , valueEnv     :: ValueEnv            -- ^ functions and data constructors+  , opPrecEnv    :: OpPrecEnv           -- ^ operator precedences+  }++-- |Initial 'CompilerEnv'+initCompilerEnv :: ModuleIdent -> CompilerEnv+initCompilerEnv mid = CompilerEnv+  { moduleIdent  = mid+  , filePath     = []+  , extensions   = []+  , tokens       = []+  , interfaceEnv = initInterfaceEnv+  , aliasEnv     = initAliasEnv+  , tyConsEnv    = initTCEnv+  , classEnv     = initClassEnv+  , instEnv      = initInstEnv+  , valueEnv     = initDCEnv+  , opPrecEnv    = initOpPrecEnv+  }++-- |Show the 'CompilerEnv'+showCompilerEnv :: CompilerEnv -> Bool -> Bool -> String+showCompilerEnv env allBinds simpleEnv = show $ vcat+  [ header "Module Identifier  " $ text  $ moduleName $ moduleIdent env+  , header "FilePath"            $ text  $ filePath    env+  , header "Language Extensions" $ text  $ show $ extensions  env+  , header "Interfaces         " $ hcat  $ punctuate comma+                                         $ map (text . moduleName)+                                         $ Map.keys $ interfaceEnv env+  , header "Module Aliases     " $ ppMap simpleEnv $ aliasEnv env+  , header "Precedences        " $ ppAL simpleEnv $ bindings $ opPrecEnv env+  , header "Type Constructors  " $ ppAL simpleEnv $ bindings $ tyConsEnv env+  , header "Classes            " $ ppMap simpleEnv $ classEnv env+  , header "Instances          " $ ppMap simpleEnv $ instEnv env+  , header "Values             " $ ppAL simpleEnv $ bindings $ valueEnv  env+  ]+  where+  header hdr content = hang (text hdr <+> colon) 4 content+  bindings = if allBinds then allBindings else allLocalBindings++-- |Pretty print a 'Map'+ppMap :: (Show a, Pretty a, Show b, Pretty b) => Bool-> Map.Map a b -> Doc+ppMap True  = ppMapPretty+ppMap False = ppMapShow++ppMapShow :: (Show a, Show b) => Map.Map a b -> Doc+ppMapShow = ppALShow . Map.toList++ppMapPretty :: (Pretty a, Pretty b) => Map.Map a b -> Doc+ppMapPretty = ppALPretty . Map.toList++-- |Pretty print an association list+ppAL :: (Show a, Pretty a, Show b, Pretty b) => Bool -> [(a, b)] -> Doc+ppAL True  = ppALPretty+ppAL False = ppALShow++ppALShow :: (Show a, Show b) => [(a, b)] -> Doc+ppALShow xs = vcat+        $ map (\(a,b) -> text (pad a keyWidth) <+> equals <+> text b) showXs+  where showXs   = map (\(a,b) -> (show a, show b)) xs+        keyWidth = maximum (0 : map (length .fst) showXs)+        pad s n  = take n (s ++ repeat ' ')++ppALPretty :: (Pretty a, Pretty b) => [(a, b)] -> Doc+ppALPretty xs = vcat+        $ map (\(a,b) -> text (pad a keyWidth) <+> equals <+> text b) showXs+  where showXs   = map (\(a,b) -> (render (pPrint a), render (pPrint b))) xs+        keyWidth = maximum (0 : map (length .fst) showXs)+        pad s n  = take n (s ++ repeat ' ')+
+ src/CompilerOpts.hs view
@@ -0,0 +1,588 @@+{- |+    Module      :  $Header$+    Description :  Compiler options+    Copyright   :  (c) 2005        Martin Engelke+                       2007        Sebastian Fischer+                       2011 - 2016 Björn Peemöller+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module defines data structures holding options for the+    compilation of Curry programs, and utility functions for printing+    help information as well as parsing the command line arguments.+-}+module CompilerOpts+  ( Options (..), CppOpts (..), PrepOpts (..), WarnOpts (..), DebugOpts (..)+  , CaseMode (..), CymakeMode (..), Verbosity (..), TargetType (..)+  , WarnFlag (..), KnownExtension (..), DumpLevel (..), dumpLevel+  , defaultOptions, defaultPrepOpts, defaultWarnOpts, defaultDebugOpts+  , getCompilerOpts, updateOpts, usage+  ) where++import           Data.List             (intercalate, nub)+import           Data.Maybe            (isJust)+import           Data.Char             (isDigit)+import qualified Data.Map    as Map    (Map, empty, insert)+import System.Console.GetOpt+import System.Environment              (getArgs, getProgName)+import System.FilePath                 ( addTrailingPathSeparator, normalise+                                       , splitSearchPath )++import Curry.Files.Filenames           (currySubdir)+import Curry.Syntax.Extension++-- -----------------------------------------------------------------------------+-- Option data structures+-- -----------------------------------------------------------------------------++-- |Compiler options+data Options = Options+  -- general+  { optMode         :: CymakeMode         -- ^ modus operandi+  , optVerbosity    :: Verbosity          -- ^ verbosity level+  -- compilation+  , optForce        :: Bool               -- ^ force (re-)compilation of target+  , optLibraryPaths :: [FilePath]         -- ^ directories to search in+                                          --   for libraries+  , optImportPaths  :: [FilePath]         -- ^ directories to search in+                                          --   for imports+  , optHtmlDir      :: Maybe FilePath     -- ^ output directory for HTML+  , optUseSubdir    :: Bool               -- ^ use subdir for output?+  , optInterface    :: Bool               -- ^ create a FlatCurry interface file?+  , optPrepOpts     :: PrepOpts           -- ^ preprocessor options+  , optWarnOpts     :: WarnOpts           -- ^ warning options+  , optTargetTypes  :: [TargetType]       -- ^ what to generate+  , optExtensions   :: [KnownExtension]   -- ^ enabled language extensions+  , optDebugOpts    :: DebugOpts          -- ^ debug options+  , optCaseMode     :: CaseMode           -- ^ case mode+  , optCppOpts      :: CppOpts            -- ^ C preprocessor options+  } deriving Show++-- |C preprocessor options+data CppOpts = CppOpts+  { cppRun         :: Bool                -- ^ run C preprocessor+  , cppDefinitions :: Map.Map String Int  -- ^ defintions for the C preprocessor+  } deriving Show++-- |Preprocessor options+data PrepOpts = PrepOpts+  { ppPreprocess :: Bool      -- ^ apply custom preprocessor+  , ppCmd        :: String    -- ^ preprocessor command+  , ppOpts       :: [String]  -- ^ preprocessor options+  } deriving Show++data CaseMode+  = CaseModeFree+  | CaseModeHaskell+  | CaseModeProlog+  | CaseModeGoedel+  deriving (Eq, Show)++-- |Warning options+data WarnOpts = WarnOpts+  { wnWarn         :: Bool       -- ^ show warnings? (legacy option)+  , wnWarnFlags    :: [WarnFlag] -- ^ Warnings flags (see below)+  , wnWarnAsError  :: Bool       -- ^ Should warnings be treated as errors?+  } deriving Show++-- |Debug options+data DebugOpts = DebugOpts+  { dbDumpLevels      :: [DumpLevel] -- ^ dump levels+  , dbDumpEnv         :: Bool        -- ^ dump compilation environment+  , dbDumpRaw         :: Bool        -- ^ dump data structure+  , dbDumpAllBindings :: Bool        -- ^ dump all bindings instead of just the+                                     --   local bindings+  , dbDumpSimple      :: Bool        -- ^ print more readable environments+  } deriving Show++-- | Default compiler options+defaultOptions :: Options+defaultOptions = Options+  { optMode         = ModeMake+  , optVerbosity    = VerbStatus+  , optForce        = False+  , optLibraryPaths = []+  , optImportPaths  = []+  , optHtmlDir      = Nothing+  , optUseSubdir    = True+  , optInterface    = True+  , optPrepOpts     = defaultPrepOpts+  , optWarnOpts     = defaultWarnOpts+  , optTargetTypes  = []+  , optExtensions   = []+  , optDebugOpts    = defaultDebugOpts+  , optCaseMode     = CaseModeFree+  , optCppOpts      = defaultCppOpts+  }++-- | Default C preprocessor options+defaultCppOpts :: CppOpts+defaultCppOpts = CppOpts+  { cppRun         = False+  , cppDefinitions = Map.empty+  }++-- | Default preprocessor options+defaultPrepOpts :: PrepOpts+defaultPrepOpts = PrepOpts+  { ppPreprocess = False+  , ppCmd        = ""+  , ppOpts       = []+  }++-- | Default warning options+defaultWarnOpts :: WarnOpts+defaultWarnOpts = WarnOpts+  { wnWarn        = True+  , wnWarnFlags   = stdWarnFlags+  , wnWarnAsError = False+  }++-- | Default dump options+defaultDebugOpts :: DebugOpts+defaultDebugOpts = DebugOpts+  { dbDumpLevels      = []+  , dbDumpEnv         = False+  , dbDumpRaw         = False+  , dbDumpAllBindings = False+  , dbDumpSimple      = False+  }++-- |Modus operandi of the program+data CymakeMode+  = ModeHelp           -- ^ Show help information and exit+  | ModeVersion        -- ^ Show version and exit+  | ModeNumericVersion -- ^ Show numeric version, suitable for later processing+  | ModeMake           -- ^ Compile with dependencies+  deriving (Eq, Show)++-- |Verbosity level+data Verbosity+  = VerbQuiet  -- ^ be quiet+  | VerbStatus -- ^ show status of compilation+  deriving (Eq, Ord, Show)++-- |Description and flag of verbosities+verbosities :: [(Verbosity, String, String)]+verbosities = [ ( VerbQuiet , "0", "quiet" )+              , ( VerbStatus, "1", "status")+              ]++-- |Type of the target file+data TargetType+  = Tokens               -- ^ Source code tokens+  | Parsed               -- ^ Parsed source code+  | FlatCurry            -- ^ FlatCurry+  | TypedFlatCurry       -- ^ Typed FlatCurry+  | AbstractCurry        -- ^ AbstractCurry+  | UntypedAbstractCurry -- ^ Untyped AbstractCurry+  | Html                 -- ^ HTML documentation+    deriving (Eq, Show)++-- |Warnings flags+data WarnFlag+  = WarnMultipleImports      -- ^ Warn for multiple imports+  | WarnDisjoinedRules       -- ^ Warn for disjoined function rules+  | WarnUnusedGlobalBindings -- ^ Warn for unused global bindings+  | WarnUnusedBindings       -- ^ Warn for unused local bindings+  | WarnNameShadowing        -- ^ Warn for name shadowing+  | WarnOverlapping          -- ^ Warn for overlapping rules/alternatives+  | WarnIncompletePatterns   -- ^ Warn for incomplete pattern matching+  | WarnMissingSignatures    -- ^ Warn for missing type signatures+  | WarnMissingMethods       -- ^ Warn for missing method implementations+  | WarnOrphanInstances      -- ^ Warn for orphan instances+  | WarnIrregularCaseMode+    deriving (Eq, Bounded, Enum, Show)++-- |Warning flags enabled by default+stdWarnFlags :: [WarnFlag]+stdWarnFlags =+  [ WarnMultipleImports   , WarnDisjoinedRules   --, WarnUnusedGlobalBindings+  , WarnUnusedBindings    , WarnNameShadowing    , WarnOverlapping+  , WarnIncompletePatterns, WarnMissingSignatures, WarnMissingMethods+  , WarnIrregularCaseMode+  ]++-- |Description and flag of warnings flags+warnFlags :: [(WarnFlag, String, String)]+warnFlags =+  [ ( WarnMultipleImports     , "multiple-imports"+    , "multiple imports"               )+  , ( WarnDisjoinedRules      , "disjoined-rules"+    , "disjoined function rules"       )+  , ( WarnUnusedGlobalBindings, "unused-global-bindings"+    , "unused bindings"                )+  , ( WarnUnusedBindings      , "unused-bindings"+    , "unused bindings"                )+  , ( WarnNameShadowing       , "name-shadowing"+    , "name shadowing"                 )+  , ( WarnOverlapping         , "overlapping"+    , "overlapping function rules"     )+  , ( WarnIncompletePatterns  , "incomplete-patterns"+    , "incomplete pattern matching"    )+  , ( WarnMissingSignatures   , "missing-signatures"+    , "missing type signatures"        )+  , ( WarnMissingMethods      , "missing-methods"+    , "missing method implementations" )+  , ( WarnOrphanInstances     , "orphan-instances"+    , "orphan instances"               )+  , ( WarnIrregularCaseMode   , "irregular-case-mode"+    , "irregular case mode")+  ]++-- |Dump level+data DumpLevel+  = DumpCondCompiled      -- ^ dump source code after conditional compiling+  | DumpParsed            -- ^ dump source code after parsing+  | DumpExtensionChecked  -- ^ dump source code after extension checking+  | DumpTypeSyntaxChecked -- ^ dump source code after type syntax checking+  | DumpKindChecked       -- ^ dump source code after kind checking+  | DumpSyntaxChecked     -- ^ dump source code after syntax checking+  | DumpPrecChecked       -- ^ dump source code after precedence checking+  | DumpDeriveChecked     -- ^ dump source code after derive checking+  | DumpInstanceChecked   -- ^ dump source code after instance checking+  | DumpTypeChecked       -- ^ dump source code after type checking+  | DumpExportChecked     -- ^ dump source code after export checking+  | DumpQualified         -- ^ dump source code after qualification+  | DumpDerived           -- ^ dump source code after deriving+  | DumpDesugared         -- ^ dump source code after desugaring+  | DumpDictionaries      -- ^ dump source code after dictionary transformation+  | DumpNewtypes          -- ^ dump source code after removing newtype constructors+  | DumpSimplified        -- ^ dump source code after simplification+  | DumpLifted            -- ^ dump source code after lambda-lifting+  | DumpTranslated        -- ^ dump IL code after translation+  | DumpCaseCompleted     -- ^ dump IL code after case completion+  | DumpTypedFlatCurry    -- ^ dump typed FlatCurry code+  | DumpFlatCurry         -- ^ dump FlatCurry code+    deriving (Eq, Bounded, Enum, Show)++-- |Description and flag of dump levels+dumpLevel :: [(DumpLevel, String, String)]+dumpLevel = [ (DumpCondCompiled     , "dump-cond" , "conditional compiling"           )+            , (DumpParsed           , "dump-parse", "parsing"                         )+            , (DumpExtensionChecked , "dump-exc"  , "extension checking"              )+            , (DumpTypeSyntaxChecked, "dump-tsc"  , "type syntax checking"            )+            , (DumpKindChecked      , "dump-kc"   , "kind checking"                   )+            , (DumpSyntaxChecked    , "dump-sc"   , "syntax checking"                 )+            , (DumpPrecChecked      , "dump-pc"   , "precedence checking"             )+            , (DumpDeriveChecked    , "dump-dc"   , "derive checking"                 )+            , (DumpInstanceChecked  , "dump-inc"  , "instance checking"               )+            , (DumpTypeChecked      , "dump-tc"   , "type checking"                   )+            , (DumpExportChecked    , "dump-ec"   , "export checking"                 )+            , (DumpQualified        , "dump-qual" , "qualification"                   )+            , (DumpDerived          , "dump-deriv", "deriving"                        )+            , (DumpDesugared        , "dump-ds"   , "desugaring"                      )+            , (DumpDictionaries     , "dump-dict" , "dictionary insertion"            )+            , (DumpNewtypes         , "dump-new"  , "removing newtype constructors"   )+            , (DumpLifted           , "dump-lift" , "lifting"                         )+            , (DumpSimplified       , "dump-simpl", "simplification"                  )+            , (DumpTranslated       , "dump-trans", "pattern matching compilation"    )+            , (DumpCaseCompleted    , "dump-cc"   , "case completion"                 )+            , (DumpTypedFlatCurry   , "dump-tflat", "translation into typed FlatCurry")+            , (DumpFlatCurry        , "dump-flat" , "translation into FlatCurry"      )+            ]++-- |Description and flag of language extensions+extensions :: [(KnownExtension, String, String)]+extensions =+  [ ( AnonFreeVars             , "AnonFreeVars"+    , "enable anonymous free variables"              )+  , ( CPP                      , "CPP"+    , "run C preprocessor"                           )+  , ( ExistentialQuantification, "ExistentialQuantification"+    , "enable existentially quantified types"        )+  , ( FunctionalPatterns       , "FunctionalPatterns"+    , "enable functional patterns"                   )+  , ( NegativeLiterals         , "NegativeLiterals"+    , "desugar negated literals as negative literal" )+  , ( NoImplicitPrelude        , "NoImplicitPrelude"+    , "do not implicitly import the Prelude"         )+  ]++-- -----------------------------------------------------------------------------+-- Parsing of the command line options.+--+-- Because some flags require additional arguments, the structure is slightly+-- more complicated to enable malformed arguments to be reported.+-- -----------------------------------------------------------------------------++-- |Instead of just returning the resulting 'Options' structure, we also+-- collect errors from arguments passed to specific options.+type OptErr = (Options, [String])++-- |An 'OptErrTable' consists of a list of entries of the following form:+--   * a flag to be recognized on the command line+--   * an explanation text for the usage information+--   * a modification funtion adjusting the options structure+-- The type is parametric about the option's type to adjust.+type OptErrTable opt = [(String, String, opt -> opt)]++onOpts :: (Options -> Options) -> OptErr -> OptErr+onOpts f (opts, errs) = (f opts, errs)++onCppOpts :: (CppOpts -> CppOpts) -> OptErr -> OptErr+onCppOpts f (opts, errs) = (opts { optCppOpts = f (optCppOpts opts) }, errs)++onPrepOpts :: (PrepOpts -> PrepOpts) -> OptErr -> OptErr+onPrepOpts f (opts, errs) = (opts { optPrepOpts = f (optPrepOpts opts) }, errs)++onWarnOpts :: (WarnOpts -> WarnOpts) -> OptErr -> OptErr+onWarnOpts f (opts, errs) = (opts { optWarnOpts = f (optWarnOpts opts) }, errs)++onDebugOpts :: (DebugOpts -> DebugOpts) -> OptErr -> OptErr+onDebugOpts f (opts, errs)+  = (opts { optDebugOpts = f (optDebugOpts opts) }, errs)++withArg :: ((a -> b) -> OptErr -> OptErr)+        -> (String -> a -> b) -> String -> OptErr -> OptErr+withArg lift f arg = lift (f arg)++addErr :: String -> OptErr -> OptErr+addErr err (opts, errs) = (opts, errs ++ [err])++mkOptDescr :: ((opt -> opt) -> OptErr -> OptErr)+           -> String -> [String] -> String -> String -> OptErrTable opt+           -> OptDescr (OptErr -> OptErr)+mkOptDescr lift flags longFlags arg what tbl = Option flags longFlags+  (ReqArg (parseOptErr lift what tbl) arg)+  ("set " ++ what ++ " `" ++ arg ++ "', where `" ++ arg ++ "' is one of\n"+    ++ renderOptErrTable tbl)++parseOptErr :: ((opt -> opt) -> OptErr -> OptErr)+            -> String -> OptErrTable opt -> String -> OptErr -> OptErr+parseOptErr lift what table opt = case lookup3 opt table of+  Just f  -> lift f+  Nothing -> addErr $ "unrecognized " ++ what ++ '`' : opt ++ "'\n"+  where+  lookup3 _ []                  = Nothing+  lookup3 k ((k', _, v2) : kvs)+    | k == k'                   = Just v2+    | otherwise                 = lookup3 k kvs++renderOptErrTable :: OptErrTable opt -> String+renderOptErrTable ds+  = intercalate "\n" $ map (\(k, d, _) -> "  " ++ rpad maxLen k ++ ": " ++ d) ds+  where+  maxLen = maximum $ map (\(k, _, _) -> length k) ds+  rpad n x = x ++ replicate (n - length x) ' '++-- | All available compiler options+options :: [OptDescr (OptErr -> OptErr)]+options =+  -- modus operandi+  [ Option "h?" ["help"]+      (NoArg (onOpts $ \ opts -> opts { optMode = ModeHelp }))+      "display this help and exit"+  , Option "V"  ["version"]+      (NoArg (onOpts $ \ opts -> opts { optMode = ModeVersion }))+      "show the version number and exit"+  , Option ""   ["numeric-version"]+      (NoArg (onOpts $ \ opts -> opts { optMode = ModeNumericVersion }))+      "show the numeric version number and exit"+  -- verbosity+  , mkOptDescr onOpts "v" ["verbosity"] "n" "verbosity level" verbDescriptions+  , Option "q"  ["no-verb"]+      (NoArg (onOpts $ \ opts -> opts { optVerbosity = VerbQuiet } ))+      "set verbosity level to quiet"+  -- compilation+  , Option "f"  ["force"]+      (NoArg (onOpts $ \ opts -> opts { optForce = True }))+      "force compilation of target file"+  , Option "P"  ["lib-dir"]+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optLibraryPaths =+        nub $ optLibraryPaths opts ++ splitSearchPath arg}) "dir[:dir]")+      "search for libraries in dir[:dir]"+  , Option "i"  ["import-dir"]+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optImportPaths =+        nub $ optImportPaths opts +++              map (normalise . addTrailingPathSeparator) (splitSearchPath arg)+              }) "dir[:dir]")+      "search for imports in dir[:dir]"+  , Option []   ["htmldir"]+      (ReqArg (withArg onOpts $ \ arg opts -> opts { optHtmlDir =+        Just arg }) "dir")+      "write HTML documentation into directory `dir'"+  , Option ""   ["no-subdir"]+      (NoArg (onOpts $ \ opts -> opts { optUseSubdir = False }))+      ("disable writing to `" ++ currySubdir ++ "' subdirectory")+  , Option ""   ["no-intf"]+      (NoArg (onOpts $ \ opts -> opts { optInterface = False }))+      "do not create an interface file"+    -- legacy warning flags+  , Option ""   ["no-warn"]+      (NoArg (onWarnOpts $ \ opts -> opts { wnWarn = False }))+      "do not print warnings"+  , Option ""   ["no-overlap-warn"]+      (NoArg (onWarnOpts $ \ opts -> opts {wnWarnFlags =+        addFlag WarnOverlapping (wnWarnFlags opts) }))+      "do not print warnings for overlapping rules"+  -- target types+  , targetOption Tokens               "tokens"+      "generate token stream"+  , targetOption Parsed               "parse-only"+      "generate source representation"+  , targetOption FlatCurry            "flat"+      "generate FlatCurry code"+  , targetOption TypedFlatCurry       "typed-flat"+      "generate typed FlatCurry code"+  , targetOption AbstractCurry        "acy"+      "generate typed AbstractCurry"+  , targetOption UntypedAbstractCurry "uacy"+      "generate untyped AbstractCurry"+  , targetOption Html                 "html"+      "generate html documentation"+  , Option "F"  []+      (NoArg (onPrepOpts $ \ opts -> opts { ppPreprocess = True }))+      "use custom preprocessor"+  , Option ""   ["pgmF"]+      (ReqArg (withArg onPrepOpts $ \ arg opts -> opts { ppCmd = arg})+        "cmd")+      "execute preprocessor command <cmd>"+  , Option ""   ["optF"]+      (ReqArg (withArg onPrepOpts $ \ arg opts ->+        opts { ppOpts = ppOpts opts ++ [arg]}) "option")+      "execute preprocessor with option <option>"+  -- extensions+  , Option "e"  ["extended"]+      (NoArg (onOpts $ \ opts -> opts { optExtensions =+        nub $ kielExtensions ++ optExtensions opts }))+      "enable extended Curry functionalities"+  , mkOptDescr onOpts      "c" ["case-mode"] "mode" "case mode"          caseModeDescriptions+  , mkOptDescr onOpts      "X" []            "ext"  "language extension" extDescriptions+  , mkOptDescr onWarnOpts  "W" []            "opt"  "warning option"     warnDescriptions+  , mkOptDescr onDebugOpts "d" []            "opt"  "debug option"       debugDescriptions+  , Option ""   ["cpp"]+      (NoArg (onCppOpts $ \ opts -> opts { cppRun = True }))+      "run C preprocessor"+  , Option "D"  []+      (ReqArg (withArg ($) parseCppDefinition) "s=v")+      "define symbol `s` with value `v` for the C preprocessor"+  ]++parseCppDefinition :: String -> OptErr -> OptErr+parseCppDefinition arg optErr+  | not (null s) && not (null v) && all isDigit v+  = onCppOpts (addCppDefinition s v) optErr+  | otherwise+  = addErr (cppDefinitionErr arg) optErr+  where (s, v) = fmap (drop 1) $ break ('=' ==) arg++addCppDefinition :: String -> String -> CppOpts -> CppOpts+addCppDefinition s v opts =+  opts { cppDefinitions = Map.insert s (read v) (cppDefinitions opts) }++cppDefinitionErr :: String -> String+cppDefinitionErr = (++) "Invalid format for option '-D': "++targetOption :: TargetType -> String -> String -> OptDescr (OptErr -> OptErr)+targetOption ty flag desc+  = Option "" [flag] (NoArg (onOpts $ \ opts -> opts { optTargetTypes =+      nub $ ty : optTargetTypes opts })) desc++verbDescriptions :: OptErrTable Options+verbDescriptions = map toDescr verbosities+  where+  toDescr (flag, name, desc)+    = (name, desc, \ opts -> opts { optVerbosity = flag })++extDescriptions :: OptErrTable Options+extDescriptions = map toDescr extensions+  where+  toDescr (flag, name, desc)+    = (name, desc,+        \opts -> let cppOpts = optCppOpts opts+                 in opts { optCppOpts    =+                             cppOpts { cppRun = cppRun cppOpts || flag == CPP }+                         , optExtensions = addFlag flag (optExtensions opts)+                         })+++caseModeDescriptions :: OptErrTable Options+caseModeDescriptions+  = [ ( "free"   , "use free case mode"+        , \ opts -> opts { optCaseMode = CaseModeFree    } )+    , ( "haskell", "use haskell style case mode"+        , \ opts -> opts { optCaseMode = CaseModeHaskell } )+    , ( "prolog" , "use prolog style case mode"+        , \ opts -> opts { optCaseMode = CaseModeProlog  } )+    , ( "goedel"  , "use goedel case mode"+        , \ opts -> opts { optCaseMode = CaseModeGoedel  } )+    ]++warnDescriptions :: OptErrTable WarnOpts+warnDescriptions+  = [ ( "all"  , "turn on all warnings"+        , \ opts -> opts { wnWarnFlags = [minBound .. maxBound] } )+    , ("none" , "turn off all warnings"+        , \ opts -> opts { wnWarnFlags = []                     } )+    , ("error", "treat warnings as errors"+        , \ opts -> opts { wnWarnAsError = True                 } )+    ] ++ map turnOn warnFlags ++ map turnOff warnFlags+  where+  turnOn (flag, name, desc)+    = (name, "warn for " ++ desc+      , \ opts -> opts { wnWarnFlags = addFlag flag (wnWarnFlags opts)})+  turnOff (flag, name, desc)+    = ("no-" ++ name, "do not warn for " ++ desc+      , \ opts -> opts { wnWarnFlags = removeFlag flag (wnWarnFlags opts)})++debugDescriptions :: OptErrTable DebugOpts+debugDescriptions =+  [ ( "dump-all"          , "dump everything"+    , \ opts -> opts { dbDumpLevels = [minBound .. maxBound]    })+  , ( "dump-none"         , "dump nothing"+    , \ opts -> opts { dbDumpLevels = []                        })+  , ( "dump-env"          , "additionally dump compiler environment"+    , \ opts -> opts { dbDumpEnv = True                         })+  , ( "dump-raw"          , "dump as raw AST (instead of pretty printing)"+    , \ opts -> opts { dbDumpRaw = True                         })+  , ( "dump-all-bindings" , "when dumping bindings, dump all instead of just local ones"+    , \ opts -> opts { dbDumpAllBindings = True                 })+  , ( "dump-simple" , "print a simplified, more readable environment"+    , \ opts -> opts { dbDumpSimple = True                      })++  ] ++ map toDescr dumpLevel+  where+  toDescr (flag, name, desc)+    = (name , "dump code after " ++ desc+        , \ opts -> opts { dbDumpLevels = addFlag flag (dbDumpLevels opts)})++addFlag :: Eq a => a -> [a] -> [a]+addFlag o opts = nub $ o : opts++removeFlag :: Eq a => a -> [a] -> [a]+removeFlag o opts = filter (/= o) opts++-- |Update the 'Options' record by the parsed and processed arguments+updateOpts :: Options -> [String] -> (Options, [String], [String])+updateOpts opts args = (opts', files, errs ++ errs2 ++ checkOpts opts files)+  where+  (opts', errs2) = foldl (flip ($)) (opts, []) optErrs+  (optErrs, files, errs) = getOpt Permute options args++-- |Parse the command line arguments+parseOpts :: [String] -> (Options, [String], [String])+parseOpts = updateOpts defaultOptions++-- |Check options and files and return a list of error messages+checkOpts :: Options -> [String] -> [String]+checkOpts opts _+  = [ "The option '--htmldir' is only valid for HTML generation mode"+    | isJust (optHtmlDir opts) && Html `notElem` optTargetTypes opts ]++-- |Print the usage information of the command line tool.+usage :: String -> String+usage prog = usageInfo header options+  where header = "usage: " ++ prog ++ " [OPTION] ... MODULES ..."++-- |Retrieve the compiler 'Options'+getCompilerOpts :: IO (String, Options, [String], [String])+getCompilerOpts = do+  args <- getArgs+  prog <- getProgName+  let (opts, files, errs) = parseOpts args+  return (prog, opts, files, errs)
+ src/CondCompile.hs view
@@ -0,0 +1,26 @@+{- |+    Module      :  $Header$+    Description :  Conditional compilation+    Copyright   :  (c)        2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  fte@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    TODO+-}++module CondCompile (condCompile) where++import Curry.Base.Monad+import Curry.CondCompile.Transform (condTransform)++import CompilerOpts (CppOpts (..))++condCompile :: CppOpts -> FilePath -> String -> CYIO String+condCompile opts fn p+  | not (cppRun opts) = return p+  | otherwise         = either (failMessages . (: []))+                               ok+                               (condTransform (cppDefinitions opts) fn p)
− src/Curry/Files/CymakePath.hs
@@ -1,15 +0,0 @@-module Curry.Files.CymakePath (getCymake,cymakeVersion) where--import Data.Version-import System.FilePath-import Paths_curry_frontend---- | Retrieve the version number of cymake-cymakeVersion :: String-cymakeVersion = showVersion version---- | Retrieve the location of the cymake executable-getCymake :: IO String-getCymake     = do-  cymakeDir <- getBinDir-  return (cymakeDir </> "cymake")
− src/Curry/Syntax.hs
@@ -1,43 +0,0 @@-{--  A simple interface for reading and manipulating Curry-  source code.--  (c) 2009, Holger Siegel.--}--module Curry.Syntax-  ( module Curry.Syntax.Type-  , parseModule-  , parseHeader-  ) where--import Control.Monad-import Data.List--import Curry.Base.MessageMonad-import Curry.Syntax.Type-import qualified Curry.Syntax.Parser as CSP-import Curry.Syntax.Unlit---- | Parses a curry module.-parseModule :: Bool -> FilePath -> String -> MsgMonad Module-parseModule likeFlat fn =-  unlitLiterate fn >=> CSP.parseSource likeFlat fn---- | Pares a curry header-parseHeader :: FilePath -> String -> MsgMonad Module-parseHeader fn =-  unlitLiterate fn >=> CSP.parseHeader fn---- Literate source files use the extension ".lcurry"-unlitLiterate :: FilePath -> String -> MsgMonad String-unlitLiterate fn s-  | isLiterateSource fn = unlit fn s-  | otherwise = return s---- | Compute if a file contains literate curry by its extension-isLiterateSource :: FilePath -> Bool-isLiterateSource fn = litExt `isSuffixOf` fn--litExt = ".lcurry"-
− src/Curry/Syntax/Frontend.hs
@@ -1,202 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Frontend - Provides an API for dealing with several kinds of Curry---            program representations------ December 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module Curry.Syntax.Frontend (lex, parse, fullParse, typingParse)where--import Data.Maybe-import qualified Data.Map as Map-import Control.Monad.Writer-import Control.Monad.Error-import Prelude hiding (lex)---import Curry.Base.MessageMonad-import Curry.Base.Ident-import Curry.Base.Position--import Curry.Files.Filenames-import Curry.Files.PathUtils--import qualified Curry.Syntax as CS-import Curry.Syntax.Lexer--import Modules-import CurryBuilder-import CurryCompilerOpts--import CurryDeps--import Base(ModuleEnv)--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Returns the result of a lexical analysis of the source program 'src'.--- The result is a list of tuples consisting of a position and a token--- (see Modules "Position" and "CurryLexer")-lex :: FilePath -> String -> MsgMonad [(Position,Token)]-lex fn src = lexFile (first fn) src False []----- Returns the result of a syntactical analysis of the source program 'src'.--- The result is the syntax tree of the program (type 'Module'; see Module--- "CurrySyntax").-parse :: FilePath -> String -> MsgMonad CS.Module-parse fn src = CS.parseModule True fn src >>= genCurrySyntax fn----- Returns the syntax tree of the source program 'src' (type 'Module'; see--- Module "CurrySyntax") after resolving the category (i.e. function,--- constructor or variable) of an identifier. 'fullParse' always--- searches for standard Curry libraries in the path defined in the--- environment variable "PAKCSLIBPATH". Additional search paths can--- be defined using the argument 'paths'.-fullParse :: [FilePath] -> FilePath -> String -> IO (MsgMonad CS.Module)-fullParse paths fn src = -- liftM msgmonad2result $-                         genFullCurrySyntax simpleCheckModule paths fn (parse fn src)---- Behaves like 'fullParse', but Returns the syntax tree of the source --- program 'src' (type 'Module'; see Module "CurrySyntax") after inferring --- the types of identifiers.-typingParse :: [FilePath] -> FilePath -> String -> IO (MsgMonad CS.Module)-typingParse paths fn src = genFullCurrySyntax checkModule paths fn (parse fn src)--{---- Compiles the source programm 'src' to an AbstractCurry program.--- 'fullParse' always searches for standard Curry libraries in the path --- defined in the environment variable "PAKCSLIBPATH". Additional search --- paths can be defined using the argument 'paths'.--- Notes: Due to the lack of error handling in the current version of the--- front end, this function may fail when an error occurs-abstractIO :: [FilePath] -> FilePath -> String -> IO (MsgMonad ACY.CurryProg)-abstractIO paths fn src = genAbstractIO paths fn (parse fn src)---- Compiles the source program 'src' to a FlatCurry program.--- 'fullParse' always searches for standard Curry libraries in the path --- defined in the environment variable "PAKCSLIBPATH". Additional search --- paths can be defined using the argument 'paths'.--- Note: Due to the lack of error handling in the current version of the--- front end, this function may fail when an error occurs-flatIO :: [FilePath] -> FilePath -> String -> IO (MsgMonad FCY.Prog)-flatIO paths fn src = genFlatIO paths fn (parse fn src)--}-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Privates...---opts paths = defaultOpts{ -                     importPaths = paths,-		     noVerb      = True,-		     noWarn      = True,-		     abstract    = True-		   }------genCurrySyntax :: FilePath -> CS.Module -> MsgMonad (CS.Module)-genCurrySyntax fn mod-    = let mod'@(CS.Module mid _ _) = patchModuleId fn (importPrelude fn mod)-      in if isValidModuleId fn mid-	 then return mod'-	 else failWith $ err_invalidModuleName mid------genFullCurrySyntax :: (Options -> Base.ModuleEnv -> CS.Module -> IO (t1, t2, t3, CS.Module, t4, [WarnMsg]))-                   -> [FilePath] -> t -> MsgMonad CS.Module -> IO (MsgMonad CS.Module)-genFullCurrySyntax check paths fn m-   = runMsgIO m $ \mod -> do errs <- makeInterfaces paths mod-	                     if null errs-	                       then do mEnv <- loadInterfaces paths mod-		                       (_, _, _, mod', _, msgs') <- check (opts paths) mEnv mod-		                       return (tell msgs' >> return  mod')-	                       else return (failWith (head errs))---{--genAbstractIO :: [FilePath] -> FilePath -> MsgMonad CS.Module-	      -> IO (MsgMonad ACY.CurryProg)-genAbstractIO paths fn m-   = runMsgIO m $ \mod ->-     do errs <- makeInterfaces paths mod-	if null errs-	   then do mEnv <- loadInterfaces paths mod-		   (tyEnv, tcEnv, _, mod', _, msgs')-		       <- simpleCheckModule (opts paths) mEnv mod-		   return (tell msgs' >> return (genTypedAbstract tyEnv tcEnv mod'))-	   else return (failWith $ head errs)------genFlatIO :: [FilePath] -> FilePath -> MsgMonad CS.Module -> IO (MsgMonad FCY.Prog)-genFlatIO paths fn m-   = runMsgIO m $ \ mod -> -     do errs <- makeInterfaces paths mod-	if null errs then-	   (do mEnv <- loadInterfaces paths mod-	       (tyEnv, tcEnv, aEnv, mod', intf, msgs') <- -	           checkModule (opts paths) mEnv mod-	       let (il, aEnv', _) -	              = transModule True True False mEnv tyEnv tcEnv aEnv mod'-	           il' = completeCase mEnv il-	           cEnv = curryEnv mEnv tcEnv intf mod'-	           (prog,msgs'') = genFlatCurry (opts paths) cEnv mEnv -	                                        tyEnv tcEnv aEnv' il'-               return (tell msgs'' >> tell msgs' >> return prog)-	   )-	   else return (failWith $ head errs)--}-------------------------------------------------------------------------------------- Generates interface files for importes modules, if they don't exist or--- if they are not up-to-date.-makeInterfaces ::  [FilePath] -> CS.Module -> IO [String]-makeInterfaces paths (CS.Module mid _ decls)-  = do let imports = [preludeMIdent | mid /= preludeMIdent] -		      ++ [imp | CS.ImportDecl _ imp _ _ _ <- decls]-       (deps, errs) <- fmap flattenDeps (foldM (moduleDeps paths []) Map.empty imports)-       when (null errs) (mapM_ (compile deps . snd) deps)-       return errs- where- compile deps (Source file' mods)-    = do smake [flatName file', flatIntName file']-	       (file':mapMaybe (flatInterface deps) mods)-	       (compileModule (opts paths) file')-	       (return Nothing)-	 return ()- compile _ _ = return ()-- flatInterface deps mod -    = case (lookup mod deps) of-        Just (Source file _)  -> Just (flatIntName (dropExtension file))-	Just (Interface file) -> Just (flatIntName (dropExtension file))-	_                     -> Nothing----- Returns 'True', if file name and module name are equal.-isValidModuleId :: FilePath -> ModuleIdent -> Bool-isValidModuleId fn mid-   = last (moduleQualifiers mid) == takeBaseName fn------------------------------------------------------------------------------------- Messages--err_invalidModuleName :: ModuleIdent -> String-err_invalidModuleName mid -   = "module \"" ++ moduleName mid -     ++ "\" must be in a file \"" ++ moduleName mid ++ ".curry\""------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/Curry/Syntax/LLParseComb.lhs
@@ -1,288 +0,0 @@-% $Id: LLParseComb.lhs,v 1.26 2004/02/15 23:11:30 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{LLParseComb.lhs}-\section{Parsing Combinators}\label{sec:ll-parsecomb}-The parsing combinators implemented in the module \texttt{LLParseComb}-are based on the LL(1) parsing combinators developed by Swierstra and-Duponcheel~\cite{SwierstraDuponcheel96:Parsers}. They have been-adapted to using continuation passing style in order to work with the-lexing combinators described in the previous section. In addition, the-facilities for error correction are omitted in this implementation.--The two functions \texttt{applyParser} and \texttt{prefixParser} use-the specified parser for parsing a string. When \texttt{applyParser}-is used, an error is reported if the parser does not consume the whole-string, whereas \texttt{prefixParser} discards the rest of the input-string in this case.-\begin{verbatim}--> module Curry.Syntax.LLParseComb(Symbol(..),Parser,->                    applyParser,prefixParser, position,succeed,symbol,->                    (<?>),(<|>),(<|?>),(<*>),(<\>),(<\\>),->                    opt,(<$>),(<$->),(<*->),(<-*>),(<**>),(<??>),(<.>),->                    many,many1, sepBy,sepBy1, chainr,chainr1,chainl,chainl1,->                    bracket,ops, layoutOn,layoutOff,layoutEnd) where--> import Control.Monad-> import Data.Maybe-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Syntax.LexComb-> import Curry.Base.MessageMonad-> import Curry.Base.Position---> infixl 5 <\>, <\\>-> infixl 4 <*>, <$>, <$->, <*->, <-*>, <**>, <??>, <.>-> infixl 3 <|>, <|?>-> infixl 2 <?>, `opt`--\end{verbatim}-\paragraph{Parser types}-\begin{verbatim}--> class (Ord s,Show s) => Symbol s where->   isEOF :: s -> Bool--> type SuccessCont s a = Position -> s -> P a-> type FailureCont a = Position -> String -> P a-> type Lexer s a = SuccessCont s a -> FailureCont a -> P a-> type ParseFun s a b = (a -> SuccessCont s b) -> FailureCont b->                     -> SuccessCont s b--> data Parser s a b = Parser (Maybe (ParseFun s a b))->                            (Map.Map s (Lexer s b -> ParseFun s a b))--> instance Symbol s => Show (Parser s a b) where->   showsPrec p (Parser e ps) = showParen (p >= 10) $->     showString "Parser " . shows (isJust e) .->     showChar ' ' . shows (Map.keysSet ps)--> applyParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String->             -> MsgMonad a-> applyParser p lexer = parse (lexer (choose p lexer done failP) failP)->   where done x pos s->           | isEOF s = returnP x->           | otherwise = failP pos (unexpected s)--> prefixParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String->              -> MsgMonad a-> prefixParser p lexer = parse (lexer (choose p lexer discard failP) failP)->   where discard x _ _ = returnP x--> choose :: Symbol s => Parser s a b -> Lexer s b -> ParseFun s a b-> choose (Parser e ps) lexer success fail pos s =->   case Map.lookup s ps of->     Just p -> p lexer success fail pos s->     Nothing ->->       case e of->         Just p -> p success fail pos s->         Nothing -> fail pos (unexpected s)--> unexpected :: Symbol s => s -> String-> unexpected s->   | isEOF s = "Unexpected end-of-file"->   | otherwise = "Unexpected token " ++ show s--\end{verbatim}-\paragraph{Basic combinators}-\begin{verbatim}--> position :: Symbol s => Parser s Position b-> position = Parser (Just p) Map.empty->   where p success _ pos = success pos pos--> succeed :: Symbol s => a -> Parser s a b-> succeed x = Parser (Just p) Map.empty->   where p success _ = success x--> symbol :: Symbol s => s -> Parser s s a-> symbol s = Parser Nothing (Map.singleton s p)->   where p lexer success fail pos s = lexer (success s) fail--> (<?>) :: Symbol s => Parser s a b -> String -> Parser s a b-> p <?> msg = p <|> Parser (Just pfail) Map.empty->   where pfail _ fail pos _ = fail pos msg--> (<|>) :: Symbol s => Parser s a b -> Parser s a b -> Parser s a b-> Parser e1 ps1 <|> Parser e2 ps2->   | isJust e1 && isJust e2 = error "Ambiguous parser for empty word"->   | not (Set.null common) = error ("Ambiguous parser for " ++ show common)->   | otherwise = Parser (e1 `mplus` e2) (Map.union ps1 ps2)->   where common = Map.keysSet ps1 `Set.intersection` Map.keysSet ps2--\end{verbatim}-The parsing combinators presented so far require that the grammar-being parsed is LL(1). In some cases it may be difficult or even-impossible to transform a grammar into LL(1) form. As a remedy, we-include a non-deterministic version of the choice combinator in-addition to the deterministic combinator adapted from the paper. For-every symbol from the intersection of the parser's first sets, the-combinator \texttt{(<|?>)} applies both parsing functions to the input-stream and uses that one which processes the longer prefix of the-input stream irrespective of whether it succeeds or fails. If both-functions recognize the same prefix, we choose the one that succeeds-and report an ambiguous parse error if both succeed.-\begin{verbatim}--> (<|?>) :: Symbol s => Parser s a b -> Parser s a b -> Parser s a b-> Parser e1 ps1 <|?> Parser e2 ps2->   | isJust e1 && isJust e2 = error "Ambiguous parser for empty word"->   | otherwise = Parser (e1 `mplus` e2) (Map.union ps1' ps2)->   where ps1' = Map.fromList [(s,maybe p (try p) (Map.lookup s ps2))->                           | (s,p) <- Map.toList ps1]->         try p1 p2 lexer success fail pos s =->           closeP1 p2s `thenP` \p2s' ->->           closeP1 p2f `thenP` \p2f' ->->           parse p1 (retry p2s') (retry p2f')->           where p2s r1 = parse p2 (select True r1) (select False r1)->                 p2f r1 = parse p2 (flip (select False) r1) (select False r1)->                 parse p psucc pfail =->                   p lexer (successK psucc) (failK pfail) pos s->                 successK k x pos s = k (pos,success x pos s)->                 failK k pos msg = k (pos,fail pos msg)->                 retry k (pos,p) = closeP0 p `thenP` curry k pos->         select suc (pos1,p1) (pos2,p2) =->           case pos1 `compare` pos2 of->             GT -> p1->             EQ->               | suc -> error ("Ambiguous parse before " ++ show pos1)->               | otherwise -> p1->             LT -> p2--> (<*>) :: Symbol s => Parser s (a -> b) c -> Parser s a c -> Parser s b c-> Parser (Just p1) ps1 <*> ~p2@(Parser e2 ps2) =->   Parser (fmap (seqEE p1) e2)->          (Map.union (fmap (flip seqPP p2) ps1) (fmap (seqEP p1) ps2))-> Parser Nothing ps1 <*> p2 = Parser Nothing (fmap (flip seqPP p2) ps1)--> seqEE :: Symbol s => ParseFun s (a -> b) c -> ParseFun s a c->       -> ParseFun s b c-> seqEE p1 p2 success fail = p1 (\f -> p2 (success . f) fail) fail--> seqEP :: Symbol s => ParseFun s (a -> b) c -> (Lexer s c -> ParseFun s a c)->       -> Lexer s c -> ParseFun s b c-> seqEP p1 p2 lexer success fail = p1 (\f -> p2 lexer (success . f) fail) fail--> seqPP :: Symbol s => (Lexer s c -> ParseFun s (a -> b) c) -> Parser s a c->       -> Lexer s c -> ParseFun s b c-> seqPP p1 p2 lexer success fail =->   p1 lexer (\f -> choose p2 lexer (success . f) fail) fail--\end{verbatim}-The combinators \verb|<\\>| and \verb|<\>| can be used to restrict-the first set of a parser. This is useful for combining two parsers-with an overlapping first set with the deterministic combinator <|>.-\begin{verbatim}--> (<\>) :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c-> p <\> Parser _ ps = p <\\> Map.keys ps--> (<\\>) :: Symbol s => Parser s a b -> [s] -> Parser s a b-> Parser e ps <\\> xs = Parser e (foldr Map.delete ps xs)--\end{verbatim}-\paragraph{Other combinators.}-Note that some of these combinators have not been published in the-paper, but were taken from the implementation found on the web.-\begin{verbatim}--> opt :: Symbol s => Parser s a b -> a -> Parser s a b-> p `opt` x = p <|> succeed x--> (<$>) :: Symbol s => (a -> b) -> Parser s a c -> Parser s b c-> f <$> p = succeed f <*> p--> (<$->) :: Symbol s => a -> Parser s b c -> Parser s a c-> f <$-> p = const f <$> p--> (<*->) :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c-> p <*-> q = const <$> p <*> q--> (<-*>) :: Symbol s => Parser s a c -> Parser s b c -> Parser s b c-> p <-*> q = const id <$> p <*> q--> (<**>) :: Symbol s => Parser s a c -> Parser s (a -> b) c -> Parser s b c-> p <**> q = flip ($) <$> p <*> q--> (<??>) :: Symbol s => Parser s a b -> Parser s (a -> a) b -> Parser s a b-> p <??> q = p <**> (q `opt` id)--> (<.>) :: Symbol s => Parser s (a -> b) d -> Parser s (b -> c) d->       -> Parser s (a -> c) d-> p1 <.> p2 = p1 <**> ((.) <$> p2)--> many :: Symbol s => Parser s a b -> Parser s [a] b-> many p = many1 p `opt` []--> many1 :: Symbol s => Parser s a b -> Parser s [a] b-> -- many1 p = (:) <$> p <*> many p-> many1 p = (:) <$> p <*> (many1 p `opt` [])--\end{verbatim}-The first definition of \texttt{many1} is commented out because it-does not compile under nhc. This is due to a -- known -- bug in the-type checker of nhc which expects a default declaration when compiling-mutually recursive functions with class constraints. However, no such-default can be given in the above case because neither of the types-involved is a numeric type.-\begin{verbatim}--> sepBy :: Symbol s => Parser s a c -> Parser s b c -> Parser s [a] c-> p `sepBy` q = p `sepBy1` q `opt` []--> sepBy1 :: Symbol s => Parser s a c -> Parser s b c -> Parser s [a] c-> p `sepBy1` q = (:) <$> p <*> many (q <-*> p)--> chainr :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b -> a->        -> Parser s a b-> chainr p op x = chainr1 p op `opt` x--> chainr1 :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b->         -> Parser s a b-> chainr1 p op = r->   where r = p <**> (flip <$> op <*> r `opt` id)--> chainl :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b -> a->        -> Parser s a b-> chainl p op x = chainl1 p op `opt` x--> chainl1 :: Symbol s => Parser s a b -> Parser s (a -> a -> a) b->         -> Parser s a b-> chainl1 p op = foldF <$> p <*> many (flip <$> op <*> p)->   where foldF x [] = x->         foldF x (f:fs) = foldF (f x) fs--> bracket :: Symbol s => Parser s a c -> Parser s b c -> Parser s a c->         -> Parser s b c-> bracket open p close = open <-*> p <*-> close--> ops :: Symbol s => [(s,a)] -> Parser s a b-> ops [] = error "internal error: ops"-> ops [(s,x)] = x <$-> symbol s-> ops ((s,x):rest) = x <$-> symbol s <|> ops rest--\end{verbatim}-\paragraph{Layout combinators}-Note that the layout functions grab the next token (and its position).-After modifying the layout context, the continuation is called with-the same token and an undefined result.-\begin{verbatim}--> layoutOn :: Symbol s => Parser s a b-> layoutOn = Parser (Just on) Map.empty->   where on success _ pos = pushContext (column pos) . success undefined pos--> layoutOff :: Symbol s => Parser s a b-> layoutOff = Parser (Just off) Map.empty->   where off success _ pos = pushContext (-1) . success undefined pos--> layoutEnd :: Symbol s => Parser s a b-> layoutEnd = Parser (Just end) Map.empty->   where end success _ pos = popContext . success undefined pos--\end{verbatim}
− src/Curry/Syntax/LexComb.lhs
@@ -1,104 +0,0 @@-% -*- LaTeX -*--% $Id: LexComb.lhs,v 1.16 2004/01/20 16:44:14 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{LexComb.lhs}-\section{Lexing combinators}-The module \texttt{LexComb} provides the basic types and combinators-to implement the lexers. The combinators use continuation passing code-in a monadic style. The first argument of the continuation function is-the current position, and the second is the string to be parsed. The third-argument is a flag which signals the lexer that it is lexing the-beginning of a line and therefore has to check for layout tokens. The-fourth argument is a stack of indentations that is used to handle-nested layout groups.-\begin{verbatim}--> module Curry.Syntax.LexComb where--> import Data.Char--> import Curry.Base.MessageMonad-> import Curry.Base.Position--> infixl 1 `thenP`, `thenP_`--> type Indent = Int-> type Context = [Indent]-> type P a = Position -> String -> Bool -> Context -> MsgMonad a--> parse :: P a -> FilePath -> String -> MsgMonad a-> parse p fn s = p (first fn) s False []--\end{verbatim}-Monad functions for the lexer.-\begin{verbatim}--> returnP :: a -> P a-> returnP x _ _ _ _ = return x--> thenP :: P a -> (a -> P b) -> P b-> thenP lex k pos s bol ctxt = lex pos s bol ctxt >>= \x -> k x pos s bol ctxt--> thenP_ :: P a -> P b -> P b-> p1 `thenP_` p2 = p1 `thenP` \_ -> p2--> failP :: Position -> String -> P a-> failP pos msg _ _ _ _ = failWith (parseError pos msg)--> closeP0 :: P a -> P (P a)-> closeP0 lex pos s bol ctxt = return (\_ _ _ _ -> lex pos s bol ctxt)--> closeP1 :: (a -> P b) -> P (a -> P b)-> closeP1 f pos s bol ctxt = return (\x _ _ _ _ -> f x pos s bol ctxt)--> parseError :: Position -> String -> String-> parseError p what = "\n" ++ show p ++ ": " ++ what--\end{verbatim}-Combinators that handle layout.-\begin{verbatim}--> pushContext :: Int -> P a -> P a-> pushContext col cont pos s bol ctxt = cont pos s bol (col:ctxt)--> popContext :: P a -> P a-> popContext cont pos s bol (_:ctxt) = cont pos s bol ctxt-> popContext cont pos s bol [] =->    error "parse error: popping layout from empty context stack. \->          \Perhaps you have inserted too many '}'?"--\end{verbatim}-Conversions from strings into numbers.-\begin{verbatim}--> convertSignedIntegral :: Num a => a -> String -> a-> convertSignedIntegral b ('+':s) = convertIntegral b s-> convertSignedIntegral b ('-':s) = - convertIntegral b s-> convertSignedIntegral b s = convertIntegral b s--> convertIntegral :: Num a => a -> String -> a-> convertIntegral b = foldl op 0->   where m `op` n | isDigit n = b * m + fromIntegral (ord n - ord0)->                  | isUpper n = b * m + fromIntegral (ord n - ordA)->                  | otherwise = b * m + fromIntegral (ord n - orda)->         ord0 = ord '0'->         ordA = ord 'A' - 10->         orda = ord 'a' - 10--> convertSignedFloating :: Fractional a => String -> String -> Int -> a-> convertSignedFloating ('+':m) f e = convertFloating m f e-> convertSignedFloating ('-':m) f e = - convertFloating m f e-> convertSignedFloating m f e = convertFloating m f e--> convertFloating :: Fractional a => String -> String -> Int -> a-> convertFloating m f e->   | e' == 0 = m'->   | e' > 0  = m' * 10^e'->   | otherwise = m' / 10^(-e')->   where m' = convertIntegral 10 (m ++ f)->         e' = e - length f--\end{verbatim}
− src/Curry/Syntax/Lexer.lhs
@@ -1,630 +0,0 @@--% $Id: CurryLexer.lhs,v 1.40 2004/03/04 22:39:12 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurryLexer.lhs}-\section{A Lexer for Curry}-In this section a lexer for Curry is implemented.-\begin{verbatim}- -> module Curry.Syntax.Lexer (lexFile,lexer, Token (..), Category(..), Attributes(..)) where--> import Data.Char -> import Data.List-> import qualified Data.Map as Map--> import Curry.Syntax.LexComb-> import Curry.Base.Position----\end{verbatim}-\paragraph{Tokens} Note that the equality and ordering instances of-\texttt{Token} disregard the attributes.-\begin{verbatim}--> data Token = Token Category Attributes--> instance Eq Token where->   Token t1 _ == Token t2 _ = t1 == t2-> instance Ord Token where->   Token t1 _ `compare` Token t2 _ = t1 `compare` t2--> data Category =->   -- literals->     CharTok | IntTok | FloatTok | IntegerTok | StringTok->   -- identifiers->   | Id | QId | Sym | QSym->   -- punctuation symbols->   | LeftParen | RightParen | Semicolon | LeftBrace | RightBrace->   | LeftBracket | RightBracket | Comma | Underscore | Backquote->   -- turn off layout (inserted by bbr)->   | LeftBraceSemicolon->   -- virtual punctation (inserted by layout)->   | VSemicolon | VRightBrace->   -- reserved identifiers->   | KW_case | KW_choice | KW_data | KW_do | KW_else | KW_eval | KW_external->   | KW_free | KW_if | KW_import | KW_in | KW_infix | KW_infixl | KW_infixr->   | KW_let | KW_module | KW_newtype | KW_of | KW_rigid | KW_then | KW_type->   | KW_where->   -- reserved operators->   | At | Colon | DotDot | DoubleColon | Equals | Backslash | Bar->   | LeftArrow | RightArrow | Tilde | Binds->   -- special identifiers->   | Id_as | Id_ccall | Id_forall | Id_hiding | Id_interface | Id_primitive->   | Id_qualified->   -- special operators->   | Sym_Dot | Sym_Minus | Sym_MinusDot->   -- end-of-file token->   | EOF->   -- comments (only for full lexer) inserted by men & bbr->   | LineComment | NestedComment ->   deriving (Eq,Ord)--\end{verbatim}-There are different kinds of attributes associated with the tokens.-Most attributes simply save the string corresponding to the token.-However, for qualified identifiers, we also record the list of module-qualifiers. The values corresponding to a literal token are properly-converted already. To simplify the creation and extraction of-attribute values we make use of records.-\begin{verbatim}--> data Attributes =->     NoAttributes->   | CharAttributes{ cval :: Char, original :: String}->   | IntAttributes{ ival :: Int , original :: String}->   | FloatAttributes{ fval :: Double, original :: String}->   | IntegerAttributes{ intval :: Integer, original :: String}->   | StringAttributes{ sval :: String, original :: String}->   | IdentAttributes{ modul :: [String], sval :: String}--> instance Show Attributes where->   showsPrec _ NoAttributes = showChar '_'->   showsPrec _ (CharAttributes cval _) = shows cval->   showsPrec _ (IntAttributes ival _) = shows ival->   showsPrec _ (FloatAttributes fval _) = shows fval->   showsPrec _ (IntegerAttributes intval _) = shows intval->   showsPrec _ (StringAttributes sval _) = shows sval->   showsPrec _ (IdentAttributes mIdent ident) =->     showString ("`" ++ concat (intersperse "." (mIdent ++ [ident])) ++ "'")--\end{verbatim}-The following functions can be used to construct tokens with-specific attributes.-\begin{verbatim}--> tok :: Category -> Token-> tok t = Token t NoAttributes--> idTok :: Category -> [String] -> String -> Token-> idTok t mIdent ident = Token t IdentAttributes{ modul = mIdent, sval = ident }--> charTok :: Char -> String -> Token-> charTok c o = Token CharTok CharAttributes{ cval = c, original = o }--> intTok :: Int -> String -> Token-> intTok base digits =->   Token IntTok IntAttributes{ ival = convertIntegral base digits,->                               original = digits}--> floatTok :: String -> String -> Int -> String -> Token-> floatTok mant frac exp rest =->   Token FloatTok FloatAttributes{ fval = convertFloating mant frac exp, ->                                   original = mant++"."++frac++rest}- -> integerTok :: Integer -> String -> Token-> integerTok base digits =->   Token IntegerTok->         IntegerAttributes{intval = (convertIntegral base digits) :: Integer,->                           original = digits}--> stringTok :: String -> String -> Token-> stringTok cs o = Token StringTok StringAttributes{ sval = cs, original = o }--> lineCommentTok :: String -> Token-> lineCommentTok s = Token LineComment StringAttributes{ sval = s, original = s}--> nestedCommentTok :: String -> Token-> nestedCommentTok s = Token NestedComment StringAttributes{ sval = s, original = s }--\end{verbatim}-The \texttt{Show} instance of \texttt{Token} is designed to display-all tokens in their source representation.-\begin{verbatim}--> instance Show Token where->   showsPrec _ (Token Id a) = showString "identifier " . shows a->   showsPrec _ (Token QId a) = showString "qualified identifier " . shows a->   showsPrec _ (Token Sym a) = showString "operator " . shows a->   showsPrec _ (Token QSym a) = showString "qualified operator " . shows a->   showsPrec _ (Token IntTok a) = showString "integer " . shows a->   showsPrec _ (Token FloatTok a) = showString "float " . shows a->   showsPrec _ (Token CharTok a) = showString "character " . shows a->   showsPrec _ (Token IntegerTok a) = showString "integer " . shows a->   showsPrec _ (Token StringTok a) = showString "string " . shows a->   showsPrec _ (Token LeftParen _) = showString "`('"->   showsPrec _ (Token RightParen _) = showString "`)'"->   showsPrec _ (Token Semicolon _) = showString "`;'"->   showsPrec _ (Token LeftBrace _) = showString "`{'"->   showsPrec _ (Token RightBrace _) = showString "`}'"->   showsPrec _ (Token LeftBracket _) = showString "`['"->   showsPrec _ (Token RightBracket _) = showString "`]'"->   showsPrec _ (Token Comma _) = showString "`,'"->   showsPrec _ (Token Underscore _) = showString "`_'"->   showsPrec _ (Token Backquote _) = showString "``'"->   showsPrec _ (Token VSemicolon _) =->     showString "`;' (inserted due to layout)"->   showsPrec _ (Token VRightBrace _) =->     showString "`}' (inserted due to layout)"->   showsPrec _ (Token At _) = showString "`@'"->   showsPrec _ (Token Colon _) = showString "`:'"->   showsPrec _ (Token DotDot _) = showString "`..'"->   showsPrec _ (Token DoubleColon _) = showString "`::'"->   showsPrec _ (Token Equals _) = showString "`='"->   showsPrec _ (Token Backslash _) = showString "`\\'"->   showsPrec _ (Token Bar _) = showString "`|'"->   showsPrec _ (Token LeftArrow _) = showString "`<-'"->   showsPrec _ (Token RightArrow _) = showString "`->'"->   showsPrec _ (Token Tilde _) = showString "`~'"->   showsPrec _ (Token Binds _) = showString "`:='"->   showsPrec _ (Token Sym_Dot _) = showString "operator `.'"->   showsPrec _ (Token Sym_Minus _) = showString "operator `-'"->   showsPrec _ (Token Sym_MinusDot _) = showString "operator `-.'"->   showsPrec _ (Token KW_case _) = showString "`case'"->   showsPrec _ (Token KW_choice _) = showString "`choice'"->   showsPrec _ (Token KW_data _) = showString "`data'"->   showsPrec _ (Token KW_do _) = showString "`do'"->   showsPrec _ (Token KW_else _) = showString "`else'"->   showsPrec _ (Token KW_eval _) = showString "`eval'"->   showsPrec _ (Token KW_external _) = showString "`external'"->   showsPrec _ (Token KW_free _) = showString "`free'"->   showsPrec _ (Token KW_if _) = showString "`if'"->   showsPrec _ (Token KW_import _) = showString "`import'"->   showsPrec _ (Token KW_in _) = showString "`in'"->   showsPrec _ (Token KW_infix _) = showString "`infix'"->   showsPrec _ (Token KW_infixl _) = showString "`infixl'"->   showsPrec _ (Token KW_infixr _) = showString "`infixr'"->   showsPrec _ (Token KW_let _) = showString "`let'"->   showsPrec _ (Token KW_module _) = showString "`module'"->   showsPrec _ (Token KW_newtype _) = showString "`newtype'"->   showsPrec _ (Token KW_of _) = showString "`of'"->   showsPrec _ (Token KW_rigid _) = showString "`rigid'"->   showsPrec _ (Token KW_then _) = showString "`then'"->   showsPrec _ (Token KW_type _) = showString "`type'"->   showsPrec _ (Token KW_where _) = showString "`where'"->   showsPrec _ (Token Id_as _) = showString "identifier `as'"->   showsPrec _ (Token Id_ccall _) = showString "identifier `ccall'"->   showsPrec _ (Token Id_forall _) = showString "identifier `forall'"->   showsPrec _ (Token Id_hiding _) = showString "identifier `hiding'"->   showsPrec _ (Token Id_interface _) = showString "identifier `interface'"->   showsPrec _ (Token Id_primitive _) = showString "identifier `primitive'"->   showsPrec _ (Token Id_qualified _) = showString "identifier `qualified'"->   showsPrec _ (Token EOF _) = showString "<end-of-file>"->   showsPrec _ (Token LineComment a) = shows a->   showsPrec _ (Token NestedComment a) = shows a--\end{verbatim}-Tables for reserved operators and identifiers-\begin{verbatim}--> reserved_ops, reserved_and_special_ops :: Map.Map String Category-> reserved_ops = Map.fromList [->     ("@",  At),->     ("::", DoubleColon),->     ("..", DotDot),->     ("=",  Equals),->     ("\\", Backslash),->     ("|",  Bar),->     ("<-", LeftArrow),->     ("->", RightArrow),->     ("~",  Tilde),->     (":=", Binds)->   ]-> reserved_and_special_ops = foldr (uncurry Map.insert) reserved_ops [->     (":",  Colon),->     (".",  Sym_Dot),->     ("-",  Sym_Minus),->     ("-.", Sym_MinusDot)->   ]--> reserved_ids, reserved_and_special_ids :: Map.Map String Category-> reserved_ids = Map.fromList [->     ("case",     KW_case),->     ("choice",   KW_choice),->     ("data",     KW_data),->     ("do",       KW_do),->     ("else",     KW_else),->     ("eval",     KW_eval),->     ("external", KW_external),->     ("free",     KW_free),->     ("if",       KW_if),->     ("import",   KW_import),->     ("in",       KW_in),->     ("infix",    KW_infix),->     ("infixl",   KW_infixl),->     ("infixr",   KW_infixr),->     ("let",      KW_let),->     ("module",   KW_module),->     ("newtype",  KW_newtype),->     ("of",       KW_of),->     ("rigid",    KW_rigid),->     ("then",     KW_then),->     ("type",     KW_type),->     ("where",    KW_where)->   ]-> reserved_and_special_ids = foldr (uncurry Map.insert) reserved_ids [->     ("as",        Id_as),->     ("ccall",     Id_ccall),->     ("forall",    Id_forall),->     ("hiding",    Id_hiding),->     ("interface", Id_interface),->     ("primitive", Id_primitive),->     ("qualified", Id_qualified)->   ]--\end{verbatim}-Character classes-\begin{verbatim}--> isIdent, isSym, isOctit, isHexit :: Char -> Bool-> isIdent c = isAlphaNum c || c `elem` "'_"-> isSym c = c `elem` "~!@#$%^&*+-=<>:?./|\\"-> isOctit c = c >= '0' && c <= '7'-> isHexit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'--inserted for full lexing (men&bbr)--> isLineComment, isNestedComment :: String -> Bool-> isLineComment ('-':'-':_) = True-> isLineComment _ = False-> isNestedComment ('{':'-':s) = True-> isNestedComment _ = False---\end{verbatim}-Lexing functions-\begin{verbatim}--> type SuccessP a = Position -> Token -> P a-> type FailP a = Position -> String -> P a--> lexFile :: P [(Position,Token)]-> lexFile = fullLexer tokens failP->   where tokens p t@(Token c _)->           | c == EOF = returnP [(p,t)]->           | otherwise = lexFile `thenP` returnP . ((p,t):)--> lexer :: SuccessP a -> FailP a -> P a-> lexer success fail = skipBlanks->   where -- skipBlanks moves past whitespace and comments->         skipBlanks p [] bol = success p (tok EOF) p [] bol->         skipBlanks p ('\t':s) bol = skipBlanks (tab p) s bol->         skipBlanks p ('\n':s) bol = skipBlanks (nl p) s True->         skipBlanks p ('-':'-':s) bol =->           skipBlanks (nl p) (tail' (dropWhile (/= '\n') s)) True->         skipBlanks p ('{':'-':s) bol =->           nestedComment p skipBlanks fail (incr p 2) s bol->         skipBlanks p (c:s) bol->           | isSpace c = skipBlanks (next p) s bol->           | otherwise =->               (if bol then lexBOL else lexToken) success fail p (c:s) bol->         tail' [] = []->         tail' (_:tl) = tl--> fullLexer :: SuccessP a -> FailP a -> P a-> fullLexer success fail = skipBlanks->   where -- skipBlanks moves past whitespace ->         skipBlanks p [] bol = success p (tok EOF) p [] bol->         skipBlanks p ('\t':s) bol = skipBlanks (tab p) s bol->         skipBlanks p ('\n':s) bol = skipBlanks (nl p) s True->         skipBlanks p s@('-':'-':_) bol = lexLineComment success p s bol->         skipBlanks p s@('{':'-':_) bol =->           lexNestedComment 0 id p success fail p s bol->         skipBlanks p (c:s) bol->           | isSpace c = skipBlanks (next p) s bol->           | otherwise =->               (if bol then lexBOL else lexToken) success fail p (c:s) bol->         tail' [] = []->         tail' (_:tl) = tl--> lexLineComment :: SuccessP a -> P a-> lexLineComment success p s = case break (=='\n') s of->   (comment,rest) -> success p (lineCommentTok comment) (incr p (length comment)) rest- -> lexNestedComment :: Int -> (String -> String) -> ->                     Position -> SuccessP a -> FailP a -> P a-> lexNestedComment 1 comment p0 success fail p ('-':'}':s) = ->   success p0 (nestedCommentTok (comment "-}") ) (incr p 2) s -> lexNestedComment n comment p0 success fail p ('{':'-':s) = ->   lexNestedComment (n+1) (comment . ("{-"++)) p0 success fail (incr p 2) s-> lexNestedComment n comment p0 success fail p ('-':'}':s) = ->   lexNestedComment (n-1) (comment . ("-}"++)) p0 success fail (incr p 2) s-> lexNestedComment n comment p0 success fail p (c@'\t':s) = ->   lexNestedComment n (comment . (c:)) p0 success fail (tab p) s-> lexNestedComment n comment p0 success fail p (c@'\n':s) = ->   lexNestedComment n (comment . (c:)) p0 success fail (nl p) s-> lexNestedComment n comment p0 success fail p (c:s) = ->   lexNestedComment n (comment . (c:)) p0 success fail (next p) s-> lexNestedComment n comment p0 success fail p "" = ->   fail p0 "Unterminated nested comment" p []--> nestedComment :: Position -> P a -> FailP a -> P a-> nestedComment p0 success fail p ('-':'}':s) = success (incr p 2) s-> nestedComment p0 success fail p ('{':'-':s) =->   nestedComment p (nestedComment p0 success fail) fail (incr p 2) s-> nestedComment p0 success fail p ('\t':s) =->   nestedComment p0 success fail (tab p) s-> nestedComment p0 success fail p ('\n':s) =->   nestedComment p0 success fail (nl p) s-> nestedComment p0 success fail p (_:s) =->   nestedComment p0 success fail (next p) s-> nestedComment p0 success fail p [] =->   fail p0 "Unterminated nested comment at end-of-file" p []---> lexBOL :: SuccessP a -> FailP a -> P a-> lexBOL success fail p s _ [] = lexToken success fail p s False []-> lexBOL success fail p s _ ctxt@(n:rest)->   | col < n = success p (tok VRightBrace) p s True rest->   | col == n = success p (tok VSemicolon) p s False ctxt->   | otherwise = lexToken success fail p s False ctxt->   where col = column p--> lexToken :: SuccessP a -> FailP a -> P a-> lexToken success fail p [] = success p (tok EOF) p []-> lexToken success fail p (c:s)->   | c == '(' = token LeftParen->   | c == ')' = token RightParen->   | c == ',' = token Comma->   | c == ';' = token Semicolon->   | c == '[' = token LeftBracket->   | c == ']' = token RightBracket->   | c == '_' = token Underscore->   | c == '`' = token Backquote->   | c == '{' = lexLeftBrace (token LeftBrace) (next p) (success p) s ->   | c == '}' = \bol -> token RightBrace bol . drop 1->   | c == '\'' = lexChar p success fail (next p) s->   | c == '\"' = lexString p success fail (next p) s->   | isAlpha c = lexIdent (success p) p (c:s)->   | isSym c = lexSym (success p) p (c:s)->   | isDigit c = lexNumber (success p) p (c:s)->   | otherwise = fail p ("Illegal character " ++ show c) p s->   where token t = success p (tok t) (next p) s--> lexIdent :: (Token -> P a) -> P a-> lexIdent cont p s =->   maybe (lexOptQual cont (token Id) [ident]) (cont . token)->         (Map.lookup ident reserved_and_special_ids)->         (incr p (length ident)) rest->   where (ident,rest) = span isIdent s->         token t = idTok t [] ident--> lexSym :: (Token -> P a) -> P a-> lexSym cont p s =->   cont (idTok (maybe Sym id (Map.lookup sym reserved_and_special_ops)) [] sym)->        (incr p (length sym)) rest->   where (sym,rest) = span isSym s--> lexLeftBrace leftBrace _ _       []    = leftBrace-> lexLeftBrace leftBrace p cont (c:s) ->   | c==';'    = cont (tok LeftBraceSemicolon) (next p) s->   | otherwise = leftBrace--\end{verbatim}-{\em Note:} the function \texttt{lexOptQual} has been extended to provide-the qualified use of the Prelude list operators and tuples.-\begin{verbatim}--> lexOptQual :: (Token -> P a) -> Token -> [String] -> P a-> lexOptQual cont token mIdent p ('.':c:s)->   | isAlpha c = lexQualIdent cont identCont mIdent (next p) (c:s)->   | isSym c = lexQualSym cont identCont mIdent (next p) (c:s)->   | c=='(' || c=='[' ->     = lexQualPreludeSym cont token identCont mIdent (next p) (c:s)->  where identCont _ _ = cont token p ('.':c:s)-> lexOptQual cont token mIdent p s = cont token p s--> lexQualIdent :: (Token -> P a) -> P a -> [String] -> P a-> lexQualIdent cont identCont mIdent p s =->   maybe (lexOptQual cont (idTok QId mIdent ident) (mIdent ++ [ident]))->         (const identCont)->         (Map.lookup ident reserved_ids)->         (incr p (length ident)) rest->   where (ident,rest) = span isIdent s--> lexQualSym :: (Token -> P a) -> P a -> [String] -> P a-> lexQualSym cont identCont mIdent p s =->   maybe (cont (idTok QSym mIdent sym)) (const identCont)->         (Map.lookup sym reserved_ops)->         (incr p (length sym)) rest->   where (sym,rest) = span isSym s---> lexQualPreludeSym :: (Token -> P a) -> Token -> P a -> [String] -> P a-> lexQualPreludeSym cont _ identCont mIdent p ('[':']':rest) =->   cont (idTok QId mIdent "[]") (incr p 2) rest-> lexQualPreludeSym cont _ identCont mIdent p ('(':rest)->   | not (null rest') && head rest'==')' ->   = cont (idTok QId mIdent ('(':tup++")")) (incr p (length tup+2)) (tail rest')->   where (tup,rest') = span (==',') rest-> lexQualPreludeSym cont token _ _ p s =  cont token p s---\end{verbatim}-{\em Note:} since Curry allows an unlimited range of integer numbers,-read numbers must be converted to Haskell type \texttt{Integer}.-\begin{verbatim}--> lexNumber :: (Token -> P a) -> P a-> lexNumber cont p ('0':c:s)->   | c `elem` "oO" = lexOctal cont nullCont (incr p 2) s->   | c `elem` "xX" = lexHexadecimal cont nullCont (incr p 2) s->   where nullCont _ _ = cont (intTok 10 "0") (next p) (c:s)-> lexNumber cont p s->     = lexOptFraction cont (integerTok 10 digits) digits->                      (incr p (length digits)) rest->   where (digits,rest) = span isDigit s->         num           = (read digits) :: Integer--> lexOctal :: (Token -> P a) -> P a -> P a-> lexOctal cont nullCont p s->   | null digits = nullCont undefined undefined->   | otherwise = cont (integerTok 8 digits) (incr p (length digits)) rest->   where (digits,rest) = span isOctit s--> lexHexadecimal :: (Token -> P a) -> P a -> P a-> lexHexadecimal cont nullCont p s->   | null digits = nullCont undefined undefined->   | otherwise = cont (integerTok 16 digits) (incr p (length digits)) rest->   where (digits,rest) = span isHexit s--> lexOptFraction :: (Token -> P a) -> Token -> String -> P a-> lexOptFraction cont _ mant p ('.':c:s)->   | isDigit c = lexOptExponent cont (floatTok mant frac 0 "") mant frac->                                (incr p (length frac+1)) rest->   where (frac,rest) = span isDigit (c:s)-> lexOptFraction cont token mant p (c:s)->   | c `elem` "eE" = lexSignedExponent cont intCont mant "" [c] (next p) s->   where intCont _ _ = cont token p (c:s)-> lexOptFraction cont token _ p s = cont token p s--> lexOptExponent :: (Token -> P a) -> Token -> String -> String -> P a-> lexOptExponent cont token mant frac p (c:s)->   | c `elem` "eE" = lexSignedExponent cont floatCont mant frac [c] (next p) s->   where floatCont _ _ = cont token p (c:s)-> lexOptExponent cont token mant frac p s = cont token p s--> lexSignedExponent :: (Token -> P a) -> P a -> String -> String -> String -> P a-> lexSignedExponent cont floatCont mant frac e p ('+':c:s)->   | isDigit c = lexExponent cont mant frac (e++"+") id (next p) (c:s)-> lexSignedExponent cont floatCont mant frac e p ('-':c:s)->   | isDigit c = lexExponent cont mant frac (e++"-") negate (next p) (c:s)-> lexSignedExponent cont floatCont mant frac e p (c:s)->   | isDigit c = lexExponent cont mant frac e id p (c:s)-> lexSignedExponent cont floatCont mant frac e p s = floatCont p s--> lexExponent :: (Token -> P a) -> String -> String -> String -> (Int -> Int) -> P a-> lexExponent cont mant frac e expSign p s =->   cont (floatTok mant frac exp (e++digits)) (incr p (length digits)) rest->   where (digits,rest) = span isDigit s->         exp = expSign (convertIntegral 10 digits)--> lexChar :: Position -> SuccessP a -> FailP a -> P a-> lexChar p0 success fail p [] = fail p0 "Illegal character constant" p []-> lexChar p0 success fail p (c:s)->   | c == '\\' = lexEscape p (lexCharEnd p0 success fail) fail (next p) s->   | c == '\n' = fail p0 "Illegal character constant" p (c:s)->   | c == '\t' = lexCharEnd p0 success fail c "\t" (tab p) s->   | otherwise = lexCharEnd p0 success fail c [c] (next p) s--> lexCharEnd :: Position -> SuccessP a -> FailP a -> Char -> String -> P a-> lexCharEnd p0 success fail c o p ('\'':s) = success p0 (charTok c o) (next p) s-> lexCharEnd p0 success fail c o p s =->   fail p0 "Improperly terminated character constant" p s--> lexString :: Position -> SuccessP a -> FailP a -> P a-> lexString p0 success fail = lexStringRest p0 success fail "" id--> lexStringRest :: Position -> SuccessP a -> FailP a -> String -> (String -> String) -> P a-> lexStringRest p0 success fail s0 so p [] = ->   fail p0 "Improperly terminated string constant" p []-> lexStringRest p0 success fail s0 so p (c:s)->   | c == '\\' =->       lexStringEscape p (lexStringRest p0 success fail) fail s0 so (next p) s->   | c == '\"' = success p0 (stringTok (reverse s0) (so "")) (next p) s->   | c == '\n' = fail p0 "Improperly terminated string constant" p []->   | c == '\t' = lexStringRest p0 success fail (c:s0) (so . (c:)) (tab p) s->   | otherwise = lexStringRest p0 success fail (c:s0) (so . (c:)) (next p) s--> lexStringEscape ::  Position -> (String -> (String -> String) -> P a) -> FailP a -> ->                                  String -> (String -> String) -> P a-> lexStringEscape p0 success fail s0 so p [] = lexEscape p0 undefined fail p []-> lexStringEscape p0 success fail s0 so p (c:s)->   | c == '&' = success s0 (so . ("\\&"++)) (next p) s->   | isSpace c = lexStringGap (success s0) fail so p (c:s)->   | otherwise = lexEscape p0 (\ c' s' -> success (c':s0) (so . (s'++))) fail p (c:s)--> lexStringGap :: ((String -> String) -> P a) -> FailP a -> (String -> String) -> P a-> lexStringGap success fail so p [] = fail p "End of file in string gap" p []-> lexStringGap success fail so p (c:s)->   | c == '\\' = success (so . (c:)) (next p) s->   | c == '\t' = lexStringGap success fail (so . (c:)) (tab p) s->   | c == '\n' = lexStringGap success fail (so . (c:)) (nl p) s->   | isSpace c = lexStringGap success fail (so . (c:)) (next p) s->   | otherwise = fail p ("Illegal character in string gap " ++ show c) p s--> lexEscape :: Position -> (Char -> String -> P a) -> FailP a -> P a-> lexEscape p0 success fail p ('a':s) = success '\a' "\\a" (next p) s-> lexEscape p0 success fail p ('b':s) = success '\b' "\\b" (next p) s-> lexEscape p0 success fail p ('f':s) = success '\f' "\\f" (next p) s-> lexEscape p0 success fail p ('n':s) = success '\n' "\\n" (next p) s-> lexEscape p0 success fail p ('r':s) = success '\r' "\\r" (next p) s-> lexEscape p0 success fail p ('t':s) = success '\t' "\\t" (next p) s-> lexEscape p0 success fail p ('v':s) = success '\v' "\\v" (next p) s-> lexEscape p0 success fail p ('\\':s) = success '\\' "\\\\" (next p) s-> lexEscape p0 success fail p ('"':s) = success '\"' "\\\"" (next p) s-> lexEscape p0 success fail p ('\'':s) = success '\'' "\\\'" (next p) s-> lexEscape p0 success fail p ('^':c:s)->   | isUpper c || c `elem` "@[\\]^_" =->       success (chr (ord c `mod` 32)) ("\\^"++[c]) (incr p 2) s-> lexEscape p0 success fail p ('o':c:s)->   | isOctit c = numEscape p0 success fail 8 isOctit ("\\o"++) (next p) (c:s)-> lexEscape p0 success fail p ('x':c:s)->   | isHexit c = numEscape p0 success fail 16 isHexit ("\\x"++) (next p) (c:s)-> lexEscape p0 success fail p (c:s)->   | isDigit c = numEscape p0 success fail 10 isDigit ("\\"++) p (c:s)-> lexEscape p0 success fail p s = asciiEscape p0 success fail p s--> asciiEscape :: Position -> (Char -> String -> P a) -> FailP a -> P a-> asciiEscape p0 success fail p ('N':'U':'L':s) = success '\NUL' "\\NUL" (incr p 3) s-> asciiEscape p0 success fail p ('S':'O':'H':s) = success '\SOH' "\\SOH" (incr p 3) s-> asciiEscape p0 success fail p ('S':'T':'X':s) = success '\STX' "\\STX" (incr p 3) s-> asciiEscape p0 success fail p ('E':'T':'X':s) = success '\ETX' "\\ETX" (incr p 3) s-> asciiEscape p0 success fail p ('E':'O':'T':s) = success '\EOT' "\\EOT" (incr p 3) s-> asciiEscape p0 success fail p ('E':'N':'Q':s) = success '\ENQ' "\\ENQ" (incr p 3) s-> asciiEscape p0 success fail p ('A':'C':'K':s) = success '\ACK' "\\ACK" (incr p 3) s -> asciiEscape p0 success fail p ('B':'E':'L':s) = success '\BEL' "\\BEL" (incr p 3) s-> asciiEscape p0 success fail p ('B':'S':s) = success '\BS' "\\BS" (incr p 2) s-> asciiEscape p0 success fail p ('H':'T':s) = success '\HT' "\\HT" (incr p 2) s-> asciiEscape p0 success fail p ('L':'F':s) = success '\LF' "\\LF" (incr p 2) s-> asciiEscape p0 success fail p ('V':'T':s) = success '\VT' "\\VT" (incr p 2) s-> asciiEscape p0 success fail p ('F':'F':s) = success '\FF' "\\FF" (incr p 2) s-> asciiEscape p0 success fail p ('C':'R':s) = success '\CR' "\\CR" (incr p 2) s-> asciiEscape p0 success fail p ('S':'O':s) = success '\SO' "\\SO" (incr p 2) s-> asciiEscape p0 success fail p ('S':'I':s) = success '\SI' "\\SI" (incr p 2) s-> asciiEscape p0 success fail p ('D':'L':'E':s) = success '\DLE' "\\DLE" (incr p 3) s -> asciiEscape p0 success fail p ('D':'C':'1':s) = success '\DC1' "\\DC1" (incr p 3) s-> asciiEscape p0 success fail p ('D':'C':'2':s) = success '\DC2' "\\DC2" (incr p 3) s-> asciiEscape p0 success fail p ('D':'C':'3':s) = success '\DC3' "\\DC3" (incr p 3) s-> asciiEscape p0 success fail p ('D':'C':'4':s) = success '\DC4' "\\DC4" (incr p 3) s-> asciiEscape p0 success fail p ('N':'A':'K':s) = success '\NAK' "\\NAK" (incr p 3) s-> asciiEscape p0 success fail p ('S':'Y':'N':s) = success '\SYN' "\\SYN" (incr p 3) s-> asciiEscape p0 success fail p ('E':'T':'B':s) = success '\ETB' "\\ETB" (incr p 3) s-> asciiEscape p0 success fail p ('C':'A':'N':s) = success '\CAN' "\\CAN" (incr p 3) s -> asciiEscape p0 success fail p ('E':'M':s) = success '\EM' "\\EM" (incr p 2) s-> asciiEscape p0 success fail p ('S':'U':'B':s) = success '\SUB' "\\SUB" (incr p 3) s-> asciiEscape p0 success fail p ('E':'S':'C':s) = success '\ESC' "\\ESC" (incr p 3) s-> asciiEscape p0 success fail p ('F':'S':s) = success '\FS' "\\FS" (incr p 2) s-> asciiEscape p0 success fail p ('G':'S':s) = success '\GS' "\\GS" (incr p 2) s-> asciiEscape p0 success fail p ('R':'S':s) = success '\RS' "\\RS" (incr p 2) s-> asciiEscape p0 success fail p ('U':'S':s) = success '\US' "\\US" (incr p 2) s-> asciiEscape p0 success fail p ('S':'P':s) = success '\SP' "\\SP" (incr p 2) s-> asciiEscape p0 success fail p ('D':'E':'L':s) = success '\DEL' "\\DEL" (incr p 3) s-> asciiEscape p0 success fail p s = fail p0 "Illegal escape sequence" p s--> numEscape :: Position -> (Char -> String -> P a) -> FailP a -> Int->           -> (Char -> Bool) -> (String -> String) -> P a-> numEscape p0 success fail b isDigit so p s->   | n >= min && n <= max = success (chr n) (so digits) (incr p (length digits)) rest->   | otherwise = fail p0 "Numeric escape out-of-range" p s->   where (digits,rest) = span isDigit s->         n = convertIntegral b digits->         min = ord minBound->         max = ord maxBound--\end{verbatim}
− src/Curry/Syntax/Parser.lhs
@@ -1,806 +0,0 @@--% $Id: CurryParser.lhs,v 1.75 2004/02/15 23:11:28 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurryParser.lhs}-\section{A Parser for Curry}-The Curry parser is implemented using the (mostly) LL(1) parsing-combinators described in appendix~\ref{sec:ll-parsecomb}.-\begin{verbatim}--> module Curry.Syntax.Parser where--> import Curry.Base.Ident-> import Curry.Base.Position-> import Curry.Base.MessageMonad-> import Curry.Syntax.LLParseComb-> import Curry.Syntax.Type-> import Curry.Syntax.Lexer--> instance Symbol Token where->   isEOF (Token c _) = c == EOF--\end{verbatim}-\paragraph{Modules}-\begin{verbatim}--> parseSource :: Bool -> FilePath -> String -> MsgMonad Module-> parseSource flat path = ->    fmap addSrcRefs . applyParser ( moduleHeader <*> decls flat) lexer path--> parseHeader :: FilePath -> String -> MsgMonad Module-> parseHeader = prefixParser (moduleHeader <*->->                             (leftBrace `opt` undefined) <*>->                             many (importDecl <*-> many semicolon))->                            lexer--> moduleHeader :: Parser Token ([Decl] -> Module) a-> moduleHeader = Module <$-> token KW_module->                       <*> (mIdent <?> "module name expected")->                       <*> ((Just <$> exportSpec) `opt` Nothing)->                       <*-> (token KW_where <?> "where expected")->          `opt` Module mainMIdent Nothing--> exportSpec :: Parser Token ExportSpec a-> exportSpec = Exporting <$> position <*> parens (export `sepBy` comma)--> export :: Parser Token Export a-> export = qtycon <**> (parens spec `opt` Export)->      <|> Export <$> qfun <\> qtycon->      <|> ExportModule <$-> token KW_module <*> mIdent->   where spec = ExportTypeAll <$-> token DotDot->            <|> flip ExportTypeWith <$> con `sepBy` comma--\end{verbatim}-\paragraph{Interfaces}-Since this modified version of MCC uses FlatCurry interfaces instead of-".icurry" files, a separate parser is not required any longer.-\begin{verbatim}--> --parseInterface :: FilePath -> String -> Error Interface-> --parseInterface fn s = applyParser parseIface lexer fn s--> --parseIface :: Parser Token Interface a-> --parseIface = Interface <$-> token Id_interface-> --                       <*> (mIdent <?> "module name expected")-> --                       <*-> (token KW_where <?> "where expected")-> --                       <*> braces intfDecls--\end{verbatim}----\paragraph{Declarations}-\begin{verbatim}--> decls :: Bool -> Parser Token [Decl] a-> decls = layout . globalDecls--> globalDecls :: Bool -> Parser Token [Decl] a-> globalDecls flat =->       (:) <$> importDecl <*> (semicolon <-*> globalDecls flat `opt` [])->   <|> topDecl flat `sepBy` semicolon--> topDecl :: Bool -> Parser Token Decl a-> topDecl flat->   | flat = infixDecl <|> dataDecl flat <|> typeDecl <|> functionDecl flat->   | otherwise = infixDecl->             <|> dataDecl flat <|> newtypeDecl <|> typeDecl->             <|> functionDecl flat <|> externalDecl--> localDefs :: Bool -> Parser Token [Decl] a-> localDefs flat = token KW_where <-*> layout (valueDecls flat)->            `opt` []--> valueDecls :: Bool -> Parser Token [Decl] a-> valueDecls flat = localDecl flat `sepBy` semicolon->   where localDecl flat->           | flat = infixDecl <|> valueDecl flat->           | otherwise = infixDecl <|> valueDecl flat <|> externalDecl--> importDecl :: Parser Token Decl a-> importDecl =->   flip . ImportDecl <$> position <*-> token KW_import ->                     <*> (True <$-> token Id_qualified `opt` False)->                     <*> mIdent->                     <*> (Just <$-> token Id_as <*> mIdent `opt` Nothing)->                     <*> (Just <$> importSpec `opt` Nothing)--> importSpec :: Parser Token ImportSpec a-> importSpec = position <**> (Hiding <$-> token Id_hiding `opt` Importing)->                       <*> parens (spec `sepBy` comma)->   where spec = tycon <**> (parens constrs `opt` Import)->            <|> Import <$> fun <\> tycon->         constrs = ImportTypeAll <$-> token DotDot->               <|> flip ImportTypeWith <$> con `sepBy` comma--> infixDecl :: Parser Token Decl a-> infixDecl = infixDeclLhs InfixDecl <*> funop `sepBy1` comma--> infixDeclLhs :: (Position -> Infix -> Integer -> a) -> Parser Token a b-> infixDeclLhs f = f <$> position <*> tokenOps infixKW <*> integer->   where infixKW = [(KW_infix,Infix),(KW_infixl,InfixL),(KW_infixr,InfixR)]--> dataDecl :: Bool -> Parser Token Decl a-> dataDecl flat = typeDeclLhs DataDecl KW_data <*> constrs->   where constrs = equals <-*> constrDecl flat `sepBy1` bar->             `opt` []--> newtypeDecl :: Parser Token Decl a-> newtypeDecl =->   typeDeclLhs NewtypeDecl KW_newtype <*-> equals <*> newConstrDecl--> typeDecl :: Parser Token Decl a-> typeDecl = typeDeclLhs TypeDecl KW_type <*-> equals <*> typeDeclRhs --type0--> typeDeclLhs :: (Position -> Ident -> [Ident] -> a) -> Category->             -> Parser Token a b-> typeDeclLhs f kw = f <$> position <*-> token kw <*> tycon <*> many typeVar->   where typeVar = tyvar <|> anonId <$-> token Underscore--> typeDeclRhs :: Parser Token TypeExpr a-> typeDeclRhs = type0->	        <|> flip RecordType Nothing->		   <$> (layoutOff <-*> braces (labelDecls `sepBy` comma))--> labelDecls = (,) <$> labId `sepBy1` comma <*-> token DoubleColon <*> type0--> constrDecl :: Bool -> Parser Token ConstrDecl a-> constrDecl flat = position <**> (existVars <**> constr)->   where constr = conId <**> identDecl->              <|> leftParen <-*> parenDecl->              <|> type1 <\> conId <\> leftParen <**> opDecl->         identDecl = many type2 <**> (conType <$> opDecl `opt` conDecl)->         parenDecl = conOpDeclPrefix ->	              <$> conSym <*-> rightParen <*> type2 <*> type2->                 <|> tupleType <*-> rightParen <**> opDecl->         opDecl = conOpDecl <$> conop <*> type1->         conType f tys c = f (ConstructorType (qualify c) tys)->         conDecl tys c tvs p = ConstrDecl p tvs c tys->         conOpDecl op ty2 ty1 tvs p = ConOpDecl p tvs ty1 op ty2->         conOpDeclPrefix op ty1 ty2 tvs p = ConOpDecl p tvs ty1 op ty2--> newConstrDecl :: Parser Token NewConstrDecl a-> newConstrDecl =->   NewConstrDecl <$> position <*> existVars <*> con <*> type2--> existVars :: Parser Token [Ident] a-> {--> existVars flat->   | flat = succeed []->   | otherwise = token Id_forall <-*> many1 tyvar <*-> dot `opt` []-> -}-> existVars = succeed []--> functionDecl :: Bool -> Parser Token Decl a-> functionDecl flat = position <**> decl->   where decl = fun `sepBy1` comma <**> funListDecl flat->           <|?> funDecl <$> lhs <*> declRhs flat->         lhs = (\f -> (f,FunLhs f [])) <$> fun->          <|?> funLhs--> valueDecl :: Bool -> Parser Token Decl a-> valueDecl flat = position <**> decl->   where decl = var `sepBy1` comma <**> valListDecl flat->           <|?> valDecl <$> constrTerm0 <*> declRhs flat->           <|?> funDecl <$> curriedLhs <*> declRhs flat->         valDecl t@(ConstructorPattern c ts)->           | not (isConstrId c) = funDecl (f,FunLhs f ts)->           where f = unqualify c->         valDecl t = opDecl id t->         opDecl f (InfixPattern t1 op t2)->           | isConstrId op = opDecl (f . InfixPattern t1 op) t2->           | otherwise = funDecl (op',OpLhs (f t1) op' t2)->           where op' = unqualify op->         opDecl f t = patDecl (f t)->         isConstrId c = c == qConsId || isQualified c || isQTupleId c--> funDecl :: (Ident,Lhs) -> Rhs -> Position -> Decl-> funDecl (f,lhs) rhs p = FunctionDecl p f [Equation p lhs rhs]--> patDecl :: ConstrTerm -> Rhs -> Position -> Decl-> patDecl t rhs p = PatternDecl p t rhs--> funListDecl :: Bool -> Parser Token ([Ident] -> Position -> Decl) a-> funListDecl flat->   | flat = typeSig <$-> token DoubleColon <*> type0->        <|> evalAnnot <$-> token KW_eval <*> tokenOps evalKW->        <|> externalDecl <$-> token KW_external->   | otherwise = typeSig <$-> token DoubleColon <*> type0->             <|> evalAnnot <$-> token KW_eval <*> tokenOps evalKW->   where typeSig ty vs p = TypeSig p vs ty->         evalAnnot ev vs p = EvalAnnot p vs ev->         evalKW = [(KW_rigid,EvalRigid),(KW_choice,EvalChoice)]->         externalDecl vs p = FlatExternalDecl p vs--> valListDecl :: Bool -> Parser Token ([Ident] -> Position -> Decl) a-> valListDecl flat = funListDecl flat <|> extraVars <$-> token KW_free->   where extraVars vs p = ExtraVariables p vs--> funLhs :: Parser Token (Ident,Lhs) a-> funLhs = funLhs <$> fun <*> many1 constrTerm2->     <|?> flip ($ id) <$> constrTerm1 <*> opLhs'->     <|?> curriedLhs->   where opLhs' = opLhs <$> funSym <*> constrTerm0->              <|> infixPat <$> gConSym <\> funSym <*> constrTerm1 <*> opLhs'->              <|> backquote <-*> opIdLhs->         opIdLhs = opLhs <$> funId <*-> checkBackquote <*> constrTerm0->               <|> infixPat <$> qConId <\> funId <*-> backquote <*> constrTerm1->                            <*> opLhs'->         funLhs f ts = (f,FunLhs f ts)->         opLhs op t2 f t1 = (op,OpLhs (f t1) op t2)->         infixPat op t2 f g t1 = f (g . InfixPattern t1 op) t2--> curriedLhs :: Parser Token (Ident,Lhs) a-> curriedLhs = apLhs <$> parens funLhs <*> many1 constrTerm2->   where apLhs (f,lhs) ts = (f,ApLhs lhs ts)--> declRhs :: Bool -> Parser Token Rhs a-> declRhs flat = rhs flat equals--> rhs :: Bool -> Parser Token a b -> Parser Token Rhs b-> rhs flat eq = rhsExpr <*> localDefs flat->   where rhsExpr = SimpleRhs <$-> eq <*> position <*> expr flat->               <|> GuardedRhs <$> many1 (condExpr flat eq)--> externalDecl :: Parser Token Decl a-> externalDecl =->   ExternalDecl <$> position <*-> token KW_external->                <*> callConv <*> (Just <$> string `opt` Nothing)->                <*> fun <*-> token DoubleColon <*> type0->   where callConv = CallConvPrimitive <$-> token Id_primitive->                <|> CallConvCCall <$-> token Id_ccall->                <?> "Unsupported calling convention"--\end{verbatim}-\paragraph{Interface declarations}-\begin{verbatim}--> --intfDecls :: Parser Token [IDecl] a-> --intfDecls = (:) <$> iImportDecl <*> (semicolon <-*> intfDecls `opt` [])-> --        <|> intfDecl `sepBy` semicolon--> --intfDecl :: Parser Token IDecl a-> --intfDecl = iInfixDecl-> --       <|> iHidingDecl <|> iDataDecl <|> iNewtypeDecl <|> iTypeDecl-> --       <|> iFunctionDecl <\> token Id_hiding--> --iImportDecl :: Parser Token IDecl a-> --iImportDecl = IImportDecl <$> position <*-> token KW_import <*> mIdent--> --iInfixDecl :: Parser Token IDecl a-> --iInfixDecl = infixDeclLhs IInfixDecl <*> qfunop--> --iHidingDecl :: Parser Token IDecl a-> --iHidingDecl = position <*-> token Id_hiding <**> (dataDecl <|> funcDecl)-> --  where dataDecl = hiddenData <$-> token KW_data <*> tycon <*> many tyvar-> --        funcDecl = hidingFunc <$-> token DoubleColon <*> type0-> --        hiddenData tc tvs p = HidingDataDecl p tc tvs-> --        hidingFunc ty p = IFunctionDecl p hidingId ty-> --        hidingId = qualify (mkIdent "hiding")--> --iDataDecl :: Parser Token IDecl a-> --iDataDecl = iTypeDeclLhs IDataDecl KW_data <*> constrs-> --  where constrs = equals <-*> iConstrDecl `sepBy1` bar-> --            `opt` []-> --        iConstrDecl = Just <$> constrDecl False <\> token Underscore-> --                  <|> Nothing <$-> token Underscore--> --iNewtypeDecl :: Parser Token IDecl a-> --iNewtypeDecl =-> --  iTypeDeclLhs INewtypeDecl KW_newtype <*-> equals <*> newConstrDecl--> --iTypeDecl :: Parser Token IDecl a-> --iTypeDecl = iTypeDeclLhs ITypeDecl KW_type <*-> equals <*> type0--> --iTypeDeclLhs :: (Position -> QualIdent -> [Ident] -> a) -> Category-> --             -> Parser Token a b-> --iTypeDeclLhs f kw = f <$> position <*-> token kw <*> qtycon <*> many tyvar--> --iFunctionDecl :: Parser Token IDecl a-> --iFunctionDecl = IFunctionDecl <$> position <*> qfun <*-> token DoubleColon-> --                              <*> type0--\end{verbatim}-\paragraph{Types}-\begin{verbatim}--> type0 :: Parser Token TypeExpr a-> type0 = type1 `chainr1` (ArrowType <$-> token RightArrow)--> type1 :: Parser Token TypeExpr a-> type1 = ConstructorType <$> qtycon <*> many type2->     <|> type2 <\> qtycon--> type2 :: Parser Token TypeExpr a-> type2 = anonType <|> identType <|> parenType <|> listType--> anonType :: Parser Token TypeExpr a-> anonType = VariableType anonId <$-> token Underscore--> identType :: Parser Token TypeExpr a-> identType = VariableType <$> tyvar->         <|> flip ConstructorType [] <$> qtycon <\> tyvar--> parenType :: Parser Token TypeExpr a-> parenType = parens tupleType--> tupleType :: Parser Token TypeExpr a-> tupleType = type0 <??> (tuple <$> many1 (comma <-*> type0))->       `opt` TupleType []->   where tuple tys ty = TupleType (ty:tys)--> listType :: Parser Token TypeExpr a-> listType = ListType <$> brackets type0--\end{verbatim}-\paragraph{Literals}-\begin{verbatim}--> literal :: Parser Token Literal a-> literal = mk Char   <$> char->       <|> mkInt     <$> integer->       <|> mk Float  <$> float->       <|> mk String <$> string--\end{verbatim}-\paragraph{Patterns}-\begin{verbatim}--> constrTerm0 :: Parser Token ConstrTerm a-> constrTerm0 = constrTerm1 `chainr1` (flip InfixPattern <$> gconop)--> constrTerm1 :: Parser Token ConstrTerm a-> constrTerm1 = varId <**> identPattern->	    <|> ConstructorPattern <$> qConId <\> varId <*> many constrTerm2->           <|> minus <**> negNum->           <|> fminus <**> negFloat->           <|> leftParen <-*> parenPattern->           <|> constrTerm2 <\> qConId <\> leftParen->   where identPattern = optAsPattern->                    <|> conPattern <$> many1 constrTerm2->         parenPattern = minus <**> minusPattern negNum->                    <|> fminus <**> minusPattern negFloat->                    <|> gconPattern->                    <|> funSym <\> minus <\> fminus <*-> rightParen->                                                    <**> identPattern->                    <|> parenTuplePattern <\> minus <\> fminus <*-> rightParen->         minusPattern p = rightParen <-*> identPattern->                      <|> parenMinusPattern p <*-> rightParen->         gconPattern = ConstructorPattern <$> gconId <*-> rightParen->                                          <*> many constrTerm2->         conPattern ts = flip ConstructorPattern ts . qualify--> constrTerm2 :: Parser Token ConstrTerm a-> constrTerm2 = literalPattern <|> anonPattern <|> identPattern->           <|> parenPattern <|> listPattern <|> lazyPattern->	    <|> recordPattern--> literalPattern :: Parser Token ConstrTerm a-> literalPattern = LiteralPattern <$> literal--> anonPattern :: Parser Token ConstrTerm a-> anonPattern = VariablePattern anonId <$-> token Underscore--> identPattern :: Parser Token ConstrTerm a-> identPattern = varId <**> optAsPattern->            <|> flip ConstructorPattern [] <$> qConId <\> varId--> parenPattern :: Parser Token ConstrTerm a-> parenPattern = leftParen <-*> parenPattern->   where parenPattern = minus <**> minusPattern negNum->                    <|> fminus <**> minusPattern negFloat->                    <|> flip ConstructorPattern [] <$> gconId <*-> rightParen->                    <|> funSym <\> minus <\> fminus <*-> rightParen->                                                    <**> optAsPattern->                    <|> parenTuplePattern <\> minus <\> fminus <*-> rightParen->         minusPattern p = rightParen <-*> optAsPattern->                      <|> parenMinusPattern p <*-> rightParen--> listPattern :: Parser Token ConstrTerm a-> listPattern = mk' ListPattern <$> brackets (constrTerm0 `sepBy` comma)--> lazyPattern :: Parser Token ConstrTerm a-> lazyPattern = mk LazyPattern <$-> token Tilde <*> constrTerm2--> recordPattern :: Parser Token ConstrTerm a-> recordPattern = layoutOff <-*> braces content->   where->   content = RecordPattern <$> fields <*> record->   fields = fieldPatt `sepBy` comma->   fieldPatt = Field <$> position <*> labId <*-> checkEquals <*> constrTerm0->   record = Just <$-> checkBar <*> constrTerm2 `opt` Nothing--\end{verbatim}-Partial patterns used in the combinators above, but also for parsing-the left-hand side of a declaration.-\begin{verbatim}--> gconId :: Parser Token QualIdent a-> gconId = colon <|> tupleCommas--> negNum,negFloat :: Parser Token (Ident -> ConstrTerm) a-> negNum = flip NegativePattern ->          <$> (mkInt <$> integer <|> mk Float <$> float)-> negFloat = flip NegativePattern . mk Float ->            <$> (fromIntegral <$> integer <|> float)--> optAsPattern :: Parser Token (Ident -> ConstrTerm) a-> optAsPattern = flip AsPattern <$-> token At <*> constrTerm2->          `opt` VariablePattern--> optInfixPattern :: Parser Token (ConstrTerm -> ConstrTerm) a-> optInfixPattern = infixPat <$> gconop <*> constrTerm0->             `opt` id->   where infixPat op t2 t1 = InfixPattern t1 op t2--> optTuplePattern :: Parser Token (ConstrTerm -> ConstrTerm) a-> optTuplePattern = tuple <$> many1 (comma <-*> constrTerm0)->             `opt` ParenPattern->   where tuple ts t = mk TuplePattern (t:ts)--> parenMinusPattern :: Parser Token (Ident -> ConstrTerm) a->                   -> Parser Token (Ident -> ConstrTerm) a-> parenMinusPattern p = p <.> optInfixPattern <.> optTuplePattern--> parenTuplePattern :: Parser Token ConstrTerm a-> parenTuplePattern = constrTerm0 <**> optTuplePattern->               `opt` mk TuplePattern []--\end{verbatim}-\paragraph{Expressions}-\begin{verbatim}--> condExpr :: Bool -> Parser Token a b -> Parser Token CondExpr b-> condExpr flat eq =->   CondExpr <$> position <*-> bar <*> expr0 flat <*-> eq <*> expr flat--> expr :: Bool -> Parser Token Expression a-> expr flat = expr0 flat <??> (flip Typed <$-> token DoubleColon <*> type0)--> expr0 :: Bool -> Parser Token Expression a-> expr0 flat = expr1 flat `chainr1` (flip InfixApply <$> infixOp)--> expr1 :: Bool -> Parser Token Expression a-> expr1 flat = UnaryMinus <$> (minus <|> fminus) <*> expr2 flat->          <|> expr2 flat--> expr2 :: Bool -> Parser Token Expression a-> expr2 flat = lambdaExpr flat <|> letExpr flat <|> doExpr flat->          <|> ifExpr flat <|> caseExpr flat->          <|> expr3 flat <**> applicOrSelect->   where->   applicOrSelect = flip RecordSelection ->	                  <$-> (token RightArrow <?> "-> expected")->			  <*> labId->		 <|?> (\es e -> foldl1 Apply (e:es))->		          <$> many (expr3 flat) --> expr3 :: Bool -> Parser Token Expression a-> expr3 flat = expr3' ->   where->   expr3' = constant <|> variable <|> parenExpr flat->        <|> listExpr flat <|> recordExpr flat--> constant :: Parser Token Expression a-> constant = Literal <$> literal--> variable :: Parser Token Expression a-> variable = Variable <$> qFunId--> parenExpr :: Bool -> Parser Token Expression a-> parenExpr flat = parens pExpr->   where pExpr = (minus <|> fminus) <**> minusOrTuple->             <|> Constructor <$> tupleCommas->             <|> leftSectionOrTuple <\> minus <\> fminus->             <|> opOrRightSection <\> minus <\> fminus->           `opt` mk Tuple []->         minusOrTuple = flip UnaryMinus <$> expr1 flat <.> infixOrTuple->                  `opt` Variable . qualify->         leftSectionOrTuple = expr1 flat <**> infixOrTuple->         infixOrTuple = ($ id) <$> infixOrTuple'->         infixOrTuple' = infixOp <**> leftSectionOrExp->                     <|> (.) <$> (optType <.> tupleExpr)->         leftSectionOrExp = expr1 flat <**> (infixApp <$> infixOrTuple')->                      `opt` leftSection->         optType = flip Typed <$-> token DoubleColon <*> type0->             `opt` id->         tupleExpr = tuple <$> many1 (comma <-*> expr flat)->               `opt` Paren->         opOrRightSection = qFunSym <**> optRightSection->                        <|> colon <**> optCRightSection->                        <|> infixOp <\> colon <\> qFunSym <**> rightSection->         optRightSection = (. InfixOp) <$> rightSection `opt` Variable->         optCRightSection = (. InfixConstr) <$> rightSection `opt` Constructor->         rightSection = flip RightSection <$> expr0 flat->         infixApp f e2 op g e1 = f (g . InfixApply e1 op) e2->         leftSection op f e = LeftSection (f e) op->         tuple es e = mk Tuple (e:es)--> infixOp :: Parser Token InfixOp a-> infixOp = InfixOp <$> qfunop->       <|> InfixConstr <$> colon--> listExpr :: Bool -> Parser Token Expression a-> listExpr flat = brackets (elements `opt` mk' List [])->   where elements = expr flat <**> rest->         rest = comprehension->            <|> enumeration (flip EnumFromTo) EnumFrom->            <|> comma <-*> expr flat <**>->                (enumeration (flip3 EnumFromThenTo) (flip EnumFromThen)->                <|> list <$> many (comma <-*> expr flat))->          `opt` (\e -> mk' List [e])->         comprehension = flip (mk ListCompr) <$-> bar <*> quals flat->         enumeration enumTo enum =->           token DotDot <-*> (enumTo <$> expr flat `opt` enum)->         list es e2 e1 = mk' List (e1:e2:es)->         flip3 f x y z = f z y x--> recordExpr :: Bool -> Parser Token Expression a-> recordExpr flat = layoutOff <-*> braces content->   where content = RecordConstr <$> fieldConstr `sepBy` comma->	            <|?> RecordUpdate <$> fieldUpdate `sepBy` comma->		                      <*-> checkBar <*> expr flat->	  fieldConstr = Field <$> position <*> labId ->		              <*-> checkEquals <*> expr flat->	  fieldUpdate = Field <$> position <*> labId ->		              <*-> checkBinds <*> expr flat--> lambdaExpr :: Bool -> Parser Token Expression a-> lambdaExpr flat =->   mk Lambda <$-> token Backslash <*> many1 constrTerm2->          <*-> (token RightArrow <?> "-> expected") <*> expr flat--> letExpr :: Bool -> Parser Token Expression a-> letExpr flat = Let <$-> token KW_let <*> layout (valueDecls flat)->                    <*-> (token KW_in <?> "in expected") <*> expr flat--> doExpr :: Bool -> Parser Token Expression a-> doExpr flat = uncurry Do <$-> token KW_do <*> layout (stmts flat)--> ifExpr :: Bool -> Parser Token Expression a-> ifExpr flat =->   mk IfThenElse <$-> token KW_if <*> expr flat->              <*-> (token KW_then <?> "then expected") <*> expr flat->              <*-> (token KW_else <?> "else expected") <*> expr flat--> caseExpr :: Bool -> Parser Token Expression a-> caseExpr flat = mk Case <$-> token KW_case <*> expr flat->                 <*-> (token KW_of <?> "of expected") <*> layout (alts flat)--> alts :: Bool -> Parser Token [Alt] a-> alts flat = alt flat `sepBy1` semicolon--> alt :: Bool -> Parser Token Alt a-> alt flat = Alt <$> position <*> constrTerm0->                <*> rhs flat (token RightArrow <?> "-> expected")--\end{verbatim}-\paragraph{Statements in list comprehensions and \texttt{do} expressions}-Parsing statements is a bit difficult because the syntax of patterns-and expressions largely overlaps. The parser will first try to-recognize the prefix \emph{Pattern}~\texttt{<-} of a binding statement-and if this fails fall back into parsing an expression statement. In-addition, we have to be prepared that the sequence-\texttt{let}~\emph{LocalDefs} can be either a let-statement or the-prefix of a let expression.-\begin{verbatim}--> stmts :: Bool -> Parser Token ([Statement],Expression) a-> stmts flat = stmt flat (reqStmts flat) (optStmts flat)--> reqStmts :: Bool -> Parser Token (Statement -> ([Statement],Expression)) a-> reqStmts flat = (\(sts,e) st -> (st : sts,e)) <$-> semicolon <*> stmts flat--> optStmts :: Bool -> Parser Token (Expression -> ([Statement],Expression)) a-> optStmts flat = succeed (mk StmtExpr) <.> reqStmts flat->           `opt` (,) []--> quals :: Bool -> Parser Token [Statement] a-> quals flat = stmt flat (succeed id) (succeed $ mk StmtExpr) `sepBy1` comma--> stmt :: Bool -> Parser Token (Statement -> a) b->      -> Parser Token (Expression -> a) b -> Parser Token a b-> stmt flat stmtCont exprCont = letStmt flat stmtCont exprCont->                           <|> exprOrBindStmt flat stmtCont exprCont--> letStmt :: Bool -> Parser Token (Statement -> a) b->         -> Parser Token (Expression -> a) b -> Parser Token a b-> letStmt flat stmtCont exprCont =->   token KW_let <-*> layout (valueDecls flat) <**> optExpr->   where optExpr = flip Let <$-> token KW_in <*> expr flat <.> exprCont->               <|> succeed StmtDecl <.> stmtCont--> exprOrBindStmt :: Bool -> Parser Token (Statement -> a) b->                -> Parser Token (Expression -> a) b->                -> Parser Token a b-> exprOrBindStmt flat stmtCont exprCont =->        mk StmtBind <$> constrTerm0 <*-> leftArrow <*> expr flat <**> stmtCont->   <|?> expr flat <\> token KW_let <**> exprCont--\end{verbatim}-\paragraph{Literals, identifiers, and (infix) operators}-\begin{verbatim}--> char :: Parser Token Char a-> char = cval <$> token CharTok--> int, checkInt :: Parser Token Int a-> int = ival <$> token IntTok-> checkInt = int <?> "integer number expected"--> float, checkFloat :: Parser Token Double a-> float = fval <$> token FloatTok-> checkFloat = float <?> "floating point number expected"--> integer, checkInteger :: Parser Token Integer a-> integer = intval <$> token IntegerTok-> checkInteger = integer <?> "integer number expected"--> string :: Parser Token String a-> string = sval <$> token StringTok--> tycon, tyvar :: Parser Token Ident a-> tycon = conId-> tyvar = varId--> qtycon :: Parser Token QualIdent a-> qtycon = qConId--> varId, funId, conId, labId :: Parser Token Ident a-> varId = ident-> funId = ident-> conId = ident-> labId = renameLabel <$> ident--> funSym, conSym :: Parser Token Ident a-> funSym = sym-> conSym = sym--> var, fun, con :: Parser Token Ident a-> var = varId <|> parens (funSym <?> "operator symbol expected")-> fun = funId <|> parens (funSym <?> "operator symbol expected")-> con = conId <|> parens (conSym <?> "operator symbol expected")--> funop, conop :: Parser Token Ident a-> funop = funSym <|> backquotes (funId <?> "operator name expected")-> conop = conSym <|> backquotes (conId <?> "operator name expected")--> qFunId, qConId, qLabId :: Parser Token QualIdent a-> qFunId = qIdent-> qConId = qIdent-> qLabId = qIdent--> qFunSym, qConSym :: Parser Token QualIdent a-> qFunSym = qSym-> qConSym = qSym-> gConSym = qConSym <|> colon--> qfun, qcon :: Parser Token QualIdent a-> qfun = qFunId <|> parens (qFunSym <?> "operator symbol expected")-> qcon = qConId <|> parens (qConSym <?> "operator symbol expected")--> qfunop, qconop, gconop :: Parser Token QualIdent a-> qfunop = qFunSym <|> backquotes (qFunId <?> "operator name expected")-> qconop = qConSym <|> backquotes (qConId <?> "operator name expected")-> gconop = gConSym <|> backquotes (qConId <?> "operator name expected")--> ident :: Parser Token Ident a-> ident = (\ pos -> mkIdentPosition pos . sval) <$> position <*> ->        tokens [Id,Id_as,Id_ccall,Id_forall,Id_hiding,->                Id_interface,Id_primitive,Id_qualified]--> qIdent :: Parser Token QualIdent a-> qIdent = qualify <$> ident <|> mkQIdent <$> position <*> token QId->   where mkQIdent p a = qualifyWith (mkMIdent (modul a)) ->                                    (mkIdentPosition p (sval a))--> mIdent :: Parser Token ModuleIdent a-> mIdent = mIdent <$> position <*> ->      tokens [Id,QId,Id_as,Id_ccall,Id_forall,Id_hiding,->              Id_interface,Id_primitive,Id_qualified]->   where mIdent p a = addPositionModuleIdent p $ ->                      mkMIdent (modul a ++ [sval a])--> sym :: Parser Token Ident a-> sym = (\ pos -> mkIdentPosition pos . sval) <$> position <*> ->       tokens [Sym,Sym_Dot,Sym_Minus,Sym_MinusDot]--> qSym :: Parser Token QualIdent a-> qSym = qualify <$> sym <|> mkQIdent <$> position <*> token QSym->   where mkQIdent p a = qualifyWith (mkMIdent (modul a)) ->                                    (mkIdentPosition p (sval a))--> colon :: Parser Token QualIdent a-> colon = (\ p _ -> qualify $ addPositionIdent p consId) <$> ->         position <*> token Colon--> minus :: Parser Token Ident a-> minus = (\ p _ -> addPositionIdent p minusId) <$> ->         position <*> token Sym_Minus--> fminus :: Parser Token Ident a-> fminus = (\ p _ -> addPositionIdent p fminusId) <$> ->         position <*> token Sym_MinusDot--> tupleCommas :: Parser Token QualIdent a-> tupleCommas = (\ p -> qualify . addPositionIdent p . tupleId . succ . length )->               <$> position <*> many1 comma--\end{verbatim}-\paragraph{Layout}-\begin{verbatim}--> layout :: Parser Token a b -> Parser Token a b-> layout p = layoutOff <-*> bracket leftBraceSemicolon p rightBrace->        <|> layoutOn <-*> p <*-> (token VRightBrace <|> layoutEnd)--\end{verbatim}-\paragraph{More combinators}-\begin{verbatim}--> braces, brackets, parens, backquotes :: Parser Token a b -> Parser Token a b-> braces p = bracket leftBrace p rightBrace-> brackets p = bracket leftBracket p rightBracket-> parens p = bracket leftParen p rightParen-> backquotes p = bracket backquote p checkBackquote--\end{verbatim}-\paragraph{Simple token parsers}-\begin{verbatim}--> token :: Category -> Parser Token Attributes a-> token c = attr <$> symbol (Token c NoAttributes)->   where attr (Token _ a) = a--> tokens :: [Category] -> Parser Token Attributes a-> tokens = foldr1 (<|>) . map token--> tokenOps :: [(Category,a)] -> Parser Token a b-> tokenOps cs = ops [(Token c NoAttributes,x) | (c,x) <- cs]--> dot, comma, semicolon, bar, equals, binds :: Parser Token Attributes a-> dot = token Sym_Dot-> comma = token Comma-> semicolon = token Semicolon <|> token VSemicolon-> bar = token Bar-> equals = token Equals-> binds = token Binds--> checkBar, checkEquals, checkBinds :: Parser Token Attributes a-> checkBar = bar <?> "| expected"-> checkEquals = equals <?> "= expected"-> checkBinds = binds <?> ":= expected"--> backquote, checkBackquote :: Parser Token Attributes a-> backquote = token Backquote-> checkBackquote = backquote <?> "backquote (`) expected"--> leftParen, rightParen :: Parser Token Attributes a-> leftParen = token LeftParen-> rightParen = token RightParen--> leftBracket, rightBracket :: Parser Token Attributes a-> leftBracket = token LeftBracket-> rightBracket = token RightBracket--> leftBrace, leftBraceSemicolon, rightBrace :: Parser Token Attributes a-> leftBrace = token LeftBrace-> leftBraceSemicolon = token LeftBraceSemicolon-> rightBrace = token RightBrace--> leftArrow :: Parser Token Attributes a-> leftArrow = token LeftArrow--\end{verbatim}-\paragraph{Ident}-\begin{verbatim}--> mkIdentPosition :: Position -> String -> Ident-> mkIdentPosition pos = addPositionIdent pos . mkIdent--\end{verbatim}
− src/Curry/Syntax/Pretty.lhs
@@ -1,368 +0,0 @@--% $Id: CurryPP.lhs,v 1.50 2004/02/15 22:10:27 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurryPP.lhs}-\section{A Pretty Printer for Curry}\label{sec:CurryPP}-This module implements a pretty printer for Curry expressions. It was-derived from the Haskell pretty printer provided in Simon Marlow's-Haskell parser.-\begin{verbatim}--> module Curry.Syntax.Pretty where--> import Text.PrettyPrint.HughesPJ--> import Curry.Base.Ident-> import Curry.Syntax.Type---\end{verbatim}-Pretty print a module-\begin{verbatim}--> ppModule :: Module -> Doc-> ppModule (Module m es ds) = ppModuleHeader m es $$ ppBlock ds--\end{verbatim}-Module header-\begin{verbatim}--> ppModuleHeader :: ModuleIdent -> Maybe ExportSpec -> Doc-> ppModuleHeader m es =->   text "module" <+> ppMIdent m <+> maybePP ppExportSpec es <+> text "where"--> ppExportSpec :: ExportSpec -> Doc-> ppExportSpec (Exporting _ es) = parenList (map ppExport es)--> ppExport :: Export -> Doc-> ppExport (Export x) = ppQIdent x-> ppExport (ExportTypeWith tc cs) = ppQIdent tc <> parenList (map ppIdent cs)-> ppExport (ExportTypeAll tc) = ppQIdent tc <> text "(..)"-> ppExport (ExportModule m) = text "module" <+> ppMIdent m--\end{verbatim}-Declarations-\begin{verbatim}--> ppBlock :: [Decl] -> Doc-> ppBlock = vcat . map ppDecl--> ppDecl :: Decl -> Doc-> ppDecl (ImportDecl _ m q asM is) =->   text "import" <+> ppQualified q <+> ppMIdent m <+> maybePP ppAs asM->                 <+> maybePP ppImportSpec is->   where ppQualified q = if q then text "qualified" else empty->         ppAs m = text "as" <+> ppMIdent m-> ppDecl (InfixDecl _ fix p ops) = ppPrec fix p <+> list (map ppInfixOp ops)-> ppDecl (DataDecl _ tc tvs cs) =->   sep (ppTypeDeclLhs "data" tc tvs :->        map indent (zipWith (<+>) (equals : repeat vbar) (map ppConstr cs)))-> ppDecl (NewtypeDecl _ tc tvs nc) =->   sep [ppTypeDeclLhs "newtype" tc tvs <+> equals,indent (ppNewConstr nc)]-> ppDecl (TypeDecl _ tc tvs ty) =->   sep [ppTypeDeclLhs "type" tc tvs <+> equals,indent (ppTypeExpr 0 ty)]-> ppDecl (TypeSig _ fs ty) =->   list (map ppIdent fs) <+> text "::" <+> ppTypeExpr 0 ty-> ppDecl (EvalAnnot _ fs ev) =->   list (map ppIdent fs) <+> text "eval" <+> ppEval ev->   where ppEval EvalRigid = text "rigid"->         ppEval EvalChoice = text "choice"-> ppDecl (FunctionDecl _ _ eqs) = vcat (map ppEquation eqs)-> ppDecl (ExternalDecl p cc impent f ty) =->   sep [text "external" <+> ppCallConv cc <+> maybePP (text . show) impent,->        indent (ppDecl (TypeSig p [f] ty))]->   where ppCallConv CallConvPrimitive = text "primitive"->         ppCallConv CallConvCCall = text "ccall"-> ppDecl (FlatExternalDecl _ fs) = list (map ppIdent fs) <+> text "external"-> ppDecl (PatternDecl _ t rhs) = ppRule (ppConstrTerm 0 t) equals rhs-> ppDecl (ExtraVariables _ vs) = list (map ppIdent vs) <+> text "free"--> ppImportSpec :: ImportSpec -> Doc-> ppImportSpec (Importing _ is) = parenList (map ppImport is)-> ppImportSpec (Hiding _ is) = text "hiding" <+> parenList (map ppImport is)--> ppImport :: Import -> Doc-> ppImport (Import x) = ppIdent x-> ppImport (ImportTypeWith tc cs) = ppIdent tc <> parenList (map ppIdent cs)-> ppImport (ImportTypeAll tc) = ppIdent tc <> text "(..)"--> ppPrec :: Infix -> Integer -> Doc-> ppPrec fix p = ppAssoc fix <+> ppPrio p->   where ppAssoc InfixL = text "infixl"->         ppAssoc InfixR = text "infixr"->         ppAssoc Infix = text "infix"->         ppPrio p = if p < 0 then empty else integer p--> ppTypeDeclLhs :: String -> Ident -> [Ident] -> Doc-> ppTypeDeclLhs kw tc tvs = text kw <+> ppIdent tc <+> hsep (map ppIdent tvs)--> ppConstr :: ConstrDecl -> Doc-> ppConstr (ConstrDecl _ tvs c tys) =->   sep [ppExistVars tvs,ppIdent c <+> fsep (map (ppTypeExpr 2) tys)]-> ppConstr (ConOpDecl _ tvs ty1 op ty2) =->   sep [ppExistVars tvs,ppTypeExpr 1 ty1,ppInfixOp op <+> ppTypeExpr 1 ty2]--> ppNewConstr :: NewConstrDecl -> Doc-> ppNewConstr (NewConstrDecl _ tvs c ty) =->   sep [ppExistVars tvs,ppIdent c <+> ppTypeExpr 2 ty]--> ppExistVars :: [Ident] -> Doc-> ppExistVars tvs->   | null tvs = empty->   | otherwise = text "forall" <+> hsep (map ppIdent tvs) <+> char '.'--> ppEquation :: Equation -> Doc-> ppEquation (Equation _ lhs rhs) = ppRule (ppLhs lhs) equals rhs--> ppLhs :: Lhs -> Doc-> ppLhs (FunLhs f ts) = ppIdent f <+> fsep (map (ppConstrTerm 2) ts)-> ppLhs (OpLhs t1 f t2) =->   ppConstrTerm 1 t1 <+> ppInfixOp f <+> ppConstrTerm 1 t2-> ppLhs (ApLhs lhs ts) = parens (ppLhs lhs) <+> fsep (map (ppConstrTerm 2) ts)--> ppRule :: Doc -> Doc -> Rhs -> Doc-> ppRule lhs eq (SimpleRhs _ e ds) =->   sep [lhs <+> eq,indent (ppExpr 0 e)] $$ ppLocalDefs ds-> ppRule lhs eq (GuardedRhs es ds) =->   sep [lhs,indent (vcat (map (ppCondExpr eq) es))] $$ ppLocalDefs ds--> ppLocalDefs :: [Decl] -> Doc-> ppLocalDefs ds->   | null ds = empty->   | otherwise = indent (text "where" <+> ppBlock ds)--\end{verbatim}-Interfaces-\begin{verbatim}--> ppInterface :: Interface -> Doc-> ppInterface (Interface m ds) =->   text "interface" <+> ppMIdent m <+> text "where" <+> lbrace->     $$ vcat (punctuate semi (map ppIDecl ds)) $$ rbrace--> ppIDecl :: IDecl -> Doc-> ppIDecl (IImportDecl _ m) = text "import" <+> ppMIdent m-> ppIDecl (IInfixDecl _ fix p op) = ppPrec fix p <+> ppQInfixOp op-> ppIDecl (HidingDataDecl _ tc tvs) =->   text "hiding" <+> ppITypeDeclLhs "data" (qualify tc) tvs-> ppIDecl (IDataDecl _ tc tvs cs) =->   sep (ppITypeDeclLhs "data" tc tvs :->        map indent (zipWith (<+>) (equals : repeat vbar) (map ppIConstr cs)))->   where ppIConstr = maybe (char '_') ppConstr-> ppIDecl (INewtypeDecl _ tc tvs nc) =->   sep [ppITypeDeclLhs "newtype" tc tvs <+> equals,indent (ppNewConstr nc)]-> ppIDecl (ITypeDecl _ tc tvs ty) =->   sep [ppITypeDeclLhs "type" tc tvs <+> equals,indent (ppTypeExpr 0 ty)]-> ppIDecl (IFunctionDecl _ f _ ty) = ppQIdent f <+> text "::" <+> ppTypeExpr 0 ty--> ppITypeDeclLhs :: String -> QualIdent -> [Ident] -> Doc-> ppITypeDeclLhs kw tc tvs = text kw <+> ppQIdent tc <+> hsep (map ppIdent tvs)--\end{verbatim}-Types-\begin{verbatim}--> ppTypeExpr :: Int -> TypeExpr -> Doc-> ppTypeExpr p (ConstructorType tc tys) =->   parenExp (p > 1 && not (null tys))->            (ppQIdent tc <+> fsep (map (ppTypeExpr 2) tys))-> ppTypeExpr _ (VariableType tv) = ppIdent tv-> ppTypeExpr _ (TupleType tys) = parenList (map (ppTypeExpr 0) tys)-> ppTypeExpr _ (ListType ty) = brackets (ppTypeExpr 0 ty)-> ppTypeExpr p (ArrowType ty1 ty2) =->   parenExp (p > 0) (fsep (ppArrowType (ArrowType ty1 ty2)))->   where ppArrowType (ArrowType ty1 ty2) =->           ppTypeExpr 1 ty1 <+> rarrow : ppArrowType ty2->         ppArrowType ty = [ppTypeExpr 0 ty]-> ppTypeExpr p (RecordType fs rty) = ->   braces (list (map ppTypedField fs) ->           <> maybe empty (\ty -> space <> char '|' <+> ppTypeExpr 0 ty) rty)->   where->   ppTypedField (ls,ty) = ->     list (map ppIdent ls) <> text "::" <> ppTypeExpr 0 ty----\end{verbatim}-Literals-\begin{verbatim}--> ppLiteral :: Literal -> Doc-> ppLiteral (Char _ c)   = text (show c)-> ppLiteral (Int _ i)    = integer i-> ppLiteral (Float _ f)  = double f-> ppLiteral (String _ s) = text (show s)--\end{verbatim}-Patterns-\begin{verbatim}--> ppConstrTerm :: Int -> ConstrTerm -> Doc-> ppConstrTerm p (LiteralPattern l) =->   parenExp (p > 1 && isNegative l) (ppLiteral l)->   where isNegative (Char _ _)   = False->         isNegative (Int _ i)    = i < 0->         isNegative (Float _ f)  = f < 0.0->         isNegative (String _ _) = False-> ppConstrTerm p (NegativePattern op l) =->   parenExp (p > 1) (ppInfixOp op <> ppLiteral l)-> ppConstrTerm _ (VariablePattern v) = ppIdent v-> ppConstrTerm p (ConstructorPattern c ts) =->   parenExp (p > 1 && not (null ts))->            (ppQIdent c <+> fsep (map (ppConstrTerm 2) ts))-> ppConstrTerm p (InfixPattern t1 c t2) =->   parenExp (p > 0)->            (sep [ppConstrTerm 1 t1 <+> ppQInfixOp c,->                  indent (ppConstrTerm 0 t2)])-> ppConstrTerm _ (ParenPattern t) = parens (ppConstrTerm 0 t)-> ppConstrTerm _ (TuplePattern _ ts) = parenList (map (ppConstrTerm 0) ts)-> ppConstrTerm _ (ListPattern _ ts) = bracketList (map (ppConstrTerm 0) ts)-> ppConstrTerm _ (AsPattern v t) = ppIdent v <> char '@' <> ppConstrTerm 2 t-> ppConstrTerm _ (LazyPattern _ t) = char '~' <> ppConstrTerm 2 t-> ppConstrTerm p (FunctionPattern f ts) =->   parenExp (p > 1 && not (null ts))->            (ppQIdent f <+> fsep (map (ppConstrTerm 2) ts))-> ppConstrTerm p (InfixFuncPattern t1 f t2) =->   parenExp (p > 0)->            (sep [ppConstrTerm 1 t1 <+> ppQInfixOp f,->                  indent (ppConstrTerm 0 t2)])-> ppConstrTerm p (RecordPattern fs rt) =->   braces (list (map ppFieldPatt fs)->          <> (maybe empty (\t -> space <> char '|' <+> ppConstrTerm 0 t) rt))--> ppFieldPatt :: Field ConstrTerm -> Doc-> ppFieldPatt (Field _ l t) = ppIdent l <> equals <> ppConstrTerm 0 t--\end{verbatim}-Expressions-\begin{verbatim}--> ppCondExpr :: Doc -> CondExpr -> Doc-> ppCondExpr eq (CondExpr _ g e) =->   vbar <+> sep [ppExpr 0 g <+> eq,indent (ppExpr 0 e)]--> ppExpr :: Int -> Expression -> Doc-> ppExpr _ (Literal l) = ppLiteral l-> ppExpr _ (Variable v) = ppQIdent v-> ppExpr _ (Constructor c) = ppQIdent c-> ppExpr _ (Paren e) = parens (ppExpr 0 e)-> ppExpr p (Typed e ty) =->   parenExp (p > 0) (ppExpr 0 e <+> text "::" <+> ppTypeExpr 0 ty)-> ppExpr _ (Tuple _ es) = parenList (map (ppExpr 0) es)-> ppExpr _ (List _ es) = bracketList (map (ppExpr 0) es)-> ppExpr _ (ListCompr _ e qs) =->   brackets (ppExpr 0 e <+> vbar <+> list (map ppStmt qs))-> ppExpr _ (EnumFrom e) = brackets (ppExpr 0 e <+> text "..")-> ppExpr _ (EnumFromThen e1 e2) =->   brackets (ppExpr 0 e1 <> comma <+> ppExpr 0 e2 <+> text "..")-> ppExpr _ (EnumFromTo e1 e2) =->   brackets (ppExpr 0 e1 <+> text ".." <+> ppExpr 0 e2)-> ppExpr _ (EnumFromThenTo e1 e2 e3) =->   brackets (ppExpr 0 e1 <> comma <+> ppExpr 0 e2->               <+> text ".." <+> ppExpr 0 e3)-> ppExpr p (UnaryMinus op e) = parenExp (p > 1) (ppInfixOp op <> ppExpr 1 e)-> ppExpr p (Apply e1 e2) =->   parenExp (p > 1) (sep [ppExpr 1 e1,indent (ppExpr 2 e2)])-> ppExpr p (InfixApply e1 op e2) =->   parenExp (p > 0) (sep [ppExpr 1 e1 <+> ppQInfixOp (opName op),->                          indent (ppExpr 1 e2)])-> ppExpr _ (LeftSection e op) = parens (ppExpr 1 e <+> ppQInfixOp (opName op))-> ppExpr _ (RightSection op e) = parens (ppQInfixOp (opName op) <+> ppExpr 1 e)-> ppExpr p (Lambda _ t e) =->   parenExp (p > 0)->            (sep [backsl <> fsep (map (ppConstrTerm 2) t) <+> rarrow,->                  indent (ppExpr 0 e)])-> ppExpr p (Let ds e) =->   parenExp (p > 0)->            (sep [text "let" <+> ppBlock ds <+> text "in",ppExpr 0 e])-> ppExpr p (Do sts e) =->   parenExp (p > 0) (text "do" <+> (vcat (map ppStmt sts) $$ ppExpr 0 e))-> ppExpr p (IfThenElse _ e1 e2 e3) =->   parenExp (p > 0)->            (text "if" <+>->             sep [ppExpr 0 e1,->                  text "then" <+> ppExpr 0 e2,->                  text "else" <+> ppExpr 0 e3])-> ppExpr p (Case _ e alts) =->   parenExp (p > 0)->            (text "case" <+> ppExpr 0 e <+> text "of" $$->             indent (vcat (map ppAlt alts)))-> ppExpr p (RecordConstr fs) =->   braces (list (map (ppFieldExpr equals) fs))-> ppExpr p (RecordSelection e l) =->   parenExp (p > 0)->            (ppExpr 1 e <+> text "->" <+> ppIdent l)-> ppExpr p (RecordUpdate fs e) =->   braces (list (map (ppFieldExpr (text ":=")) fs)->          <+> char '|' <+> ppExpr 0 e)--> ppStmt :: Statement -> Doc-> ppStmt (StmtExpr _ e) = ppExpr 0 e-> ppStmt (StmtBind _ t e) = sep [ppConstrTerm 0 t <+> larrow,indent (ppExpr 0 e)]-> ppStmt (StmtDecl ds) = text "let" <+> ppBlock ds--> ppAlt :: Alt -> Doc-> ppAlt (Alt _ t rhs) = ppRule (ppConstrTerm 0 t) rarrow rhs--> ppFieldExpr :: Doc -> Field Expression -> Doc-> ppFieldExpr comb (Field _ l e) = ppIdent l <> comb <> ppExpr 0 e--> ppOp :: InfixOp -> Doc-> ppOp (InfixOp op) = ppQInfixOp op-> ppOp (InfixConstr op) = ppQInfixOp op--\end{verbatim}--Names-\begin{verbatim}--> ppIdent :: Ident -> Doc-> ppIdent x = parenExp (isInfixOp x) (text (name x))--> ppQIdent :: QualIdent -> Doc-> ppQIdent x = parenExp (isQInfixOp x) (text (qualName x))--> ppInfixOp :: Ident -> Doc-> ppInfixOp x = backQuoteExp (not (isInfixOp x)) (text (name x))--> ppQInfixOp :: QualIdent -> Doc-> ppQInfixOp x = backQuoteExp (not (isQInfixOp x)) (text (qualName x))--> ppMIdent :: ModuleIdent -> Doc-> ppMIdent m = text (moduleName m)--\end{verbatim}-Print printing utilities-\begin{verbatim}--> indent :: Doc -> Doc-> indent = nest 2--> maybePP :: (a -> Doc) -> Maybe a -> Doc-> maybePP pp = maybe empty pp--> parenExp :: Bool -> Doc -> Doc-> parenExp b doc = if b then parens doc else doc--> backQuoteExp :: Bool -> Doc -> Doc-> backQuoteExp b doc = if b then backQuote <> doc <> backQuote else doc--> list, parenList, bracketList, braceList :: [Doc] -> Doc-> list = fsep . punctuate comma-> parenList = parens . list-> bracketList = brackets . list-> braceList = braces . list--> backQuote,backsl,vbar,rarrow,larrow :: Doc-> backQuote = char '`'-> backsl = char '\\'-> vbar = char '|'-> rarrow = text "->"-> larrow = text "<-"--\end{verbatim}
− src/Curry/Syntax/ShowModule.hs
@@ -1,499 +0,0 @@---- Transform a CurrySyntax module into a string representation without any---- pretty printing.---- Behaves like a derived Show instance even on parts with a specific one.---- ---- @author Sebastian Fischer (sebf@informatik.uni-kiel.de)---- @version December 2008---- bug fixed by bbr---module Curry.Syntax.ShowModule ( showModule ) where--import Curry.Base.Ident-import Curry.Base.Position-import Curry.Syntax.Type--showModule :: Module -> String-showModule m = showsModule m "\n"--showsModule :: Module -> ShowS-showsModule (Module mident espec decls)-  = showsString "Module "-  . showsModuleIdent mident . newline-  . showsMaybe showsExportSpec espec . newline-  . showsList (\d -> showsDecl d . newline) decls--showsPosition :: Position -> ShowS-showsPosition Position{line=row,column=col} = showsPair shows shows (row,col)--- showsPosition (Position file row col)---   = showsString "(Position "---   . shows file . space---   . shows row . space---   . shows col---   . showsString ")"--showsExportSpec :: ExportSpec -> ShowS-showsExportSpec (Exporting pos exports)-  = showsString "(Exporting "-  . showsPosition pos . space-  . showsList showsExport exports-  . showsString ")"--showsExport :: Export -> ShowS-showsExport (Export qident)-  = showsString "(Export " . showsQualIdent qident . showsString ")"-showsExport (ExportTypeWith qident ids)-  = showsString "(ExportTypeWith "-  . showsQualIdent qident . space-  . showsList showsIdent ids-  . showsString ")"-showsExport (ExportTypeAll qident)-  = showsString "(ExportTypeAll " . showsQualIdent qident . showsString ")"-showsExport (ExportModule m) -  = showsString "(ExportModule " . showsModuleIdent m . showChar ')'--showsImportSpec :: ImportSpec -> ShowS-showsImportSpec (Importing pos imports)-  = showsString "(Importing "-  . showsPosition pos . space-  . showsList showsImport imports-  . showsString ")"-showsImportSpec (Hiding pos imports)-  = showsString "(Hiding "-  . showsPosition pos . space-  . showsList showsImport imports-  . showsString ")"--showsImport :: Import -> ShowS-showsImport (Import ident)-  = showsString "(Import " . showsIdent ident . showsString ")"-showsImport (ImportTypeWith ident idents)-  = showsString "(ImportTypeWith "-  . showsIdent ident . space-  . showsList showsIdent idents-  . showsString ")"-showsImport (ImportTypeAll ident)-  = showsString "(ImportTypeAll " . showsIdent ident . showsString ")"--showsDecl :: Decl -> ShowS-showsDecl (ImportDecl pos mident quali mmident mimpspec)-  = showsString "(ImportDecl "-  . showsPosition pos . space-  . showsModuleIdent mident . space-  . shows quali . space-  . showsMaybe showsModuleIdent mmident . space-  . showsMaybe showsImportSpec mimpspec-  . showsString ")"-showsDecl (InfixDecl pos infx prec idents)-  = showsString "(InfixDecl "-  . showsPosition pos . space-  . shows infx . space-  . shows prec . space-  . showsList showsIdent idents-  . showsString ")"-showsDecl (DataDecl pos ident idents consdecls)-  = showsString "(DataDecl "-  . showsPosition pos . space-  . showsIdent ident . space-  . showsList showsIdent idents . space-  . showsList showsConsDecl consdecls-  . showsString ")"-showsDecl (NewtypeDecl pos ident idents newconsdecl)-  = showsString "(NewtypeDecl "-  . showsPosition pos . space-  . showsIdent ident . space-  . showsList showsIdent idents . space-  . showsNewConsDecl newconsdecl-  . showsString ")"-showsDecl (TypeDecl pos ident idents typ)-  = showsString "(TypeDecl "-  . showsPosition pos . space-  . showsIdent ident . space-  . showsList showsIdent idents . space-  . showsTypeExpr typ-  . showsString ")"-showsDecl (TypeSig pos idents typ)-  = showsString "(TypeSig "-  . showsPosition pos . space-  . showsList showsIdent idents . space-  . showsTypeExpr typ-  . showsString ")"-showsDecl (EvalAnnot pos idents annot)-  = showsString "(EvalAnnot "-  . showsPosition pos . space-  . showsList showsIdent idents . space-  . shows annot-  . showsString ")"-showsDecl (FunctionDecl pos ident eqs)-  = showsString "(FunctionDecl "-  . showsPosition pos . space-  . showsIdent ident . space-  . showsList showsEquation eqs-  . showsString ")"-showsDecl (ExternalDecl pos cconv mstr ident typ)-  = showsString "(ExternalDecl "-  . showsPosition pos . space-  . shows cconv . space-  . shows mstr . space-  . showsIdent ident . space-  . showsTypeExpr typ-  . showsString ")"-showsDecl (FlatExternalDecl pos idents)-  = showsString "(FlatExternalDecl "-  . showsPosition pos . space-  . showsList showsIdent idents-  . showsString ")"-showsDecl (PatternDecl pos cons rhs)-  = showsString "(PatternDecl "-  . showsPosition pos . space-  . showsConsTerm cons . space-  . showsRhs rhs-  . showsString ")"-showsDecl (ExtraVariables pos idents)-  = showsString "(ExtraVariables "-  . showsPosition pos . space-  . showsList showsIdent idents-  . showsString ")"--showsConsDecl :: ConstrDecl -> ShowS-showsConsDecl (ConstrDecl pos idents ident types)-  = showsString "(ConstrDecl "-  . showsPosition pos . space-  . showsList showsIdent idents . space-  . showsIdent ident . space-  . showsList showsTypeExpr types-  . showsString ")"--showsNewConsDecl :: NewConstrDecl -> ShowS-showsNewConsDecl (NewConstrDecl pos idents ident typ)-  = showsString "(NewConstrDecl "-  . showsPosition pos . space-  . showsList showsIdent idents . space-  . showsIdent ident . space-  . showsTypeExpr typ-  . showsString ")"--showsTypeExpr :: TypeExpr -> ShowS-showsTypeExpr (ConstructorType qident types)-  = showsString "(ConstructorType "-  . showsQualIdent qident . space-  . showsList showsTypeExpr types-  . showsString ")"-showsTypeExpr (VariableType ident)-  = showsString "(VariableType " . showsIdent ident . showsString ")"-showsTypeExpr (TupleType types)-  = showsString "(TupleType " . showsList showsTypeExpr types . showsString ")"-showsTypeExpr (ListType typ)-  = showsString "(ListType " . showsTypeExpr typ . showsString ")"-showsTypeExpr (ArrowType dom ran)-  = showsString "(ArrowType "-  . showsTypeExpr dom . space-  . showsTypeExpr ran-  . showsString ")"-showsTypeExpr (RecordType fieldts mtyp)-  = showsString "(RecordType "-  . showsList (showsPair (showsList showsIdent) showsTypeExpr) fieldts . space-  . showsMaybe showsTypeExpr mtyp-  . showsString ")"--showsEquation :: Equation -> ShowS-showsEquation (Equation pos lhs rhs)-  = showsString "(Equation "-  . showsPosition pos . space-  . showsLhs lhs . space-  . showsRhs rhs-  . showsString ")"--showsLhs :: Lhs -> ShowS-showsLhs (FunLhs ident conss)-  = showsString "(FunLhs "-  . showsIdent ident . space-  . showsList showsConsTerm conss-  . showsString ")"-showsLhs (OpLhs cons1 ident cons2)-  = showsString "(OpLhs "-  . showsConsTerm cons1 . space-  . showsIdent ident . space-  . showsConsTerm cons2-  . showsString ")"-showsLhs (ApLhs lhs conss)-  = showsString "(ApLhs "-  . showsLhs lhs . space-  . showsList showsConsTerm conss-  . showsString ")"--showsRhs :: Rhs -> ShowS-showsRhs (SimpleRhs pos exp decls)-  = showsString "(SimpleRhs "-  . showsPosition pos . space-  . showsExpression exp . space-  . showsList showsDecl decls-  . showsString ")"-showsRhs (GuardedRhs cexps decls)-  = showsString "(GuardedRhs "-  . showsList showsCondExpr cexps . space-  . showsList showsDecl decls-  . showsString ")"--showsCondExpr :: CondExpr -> ShowS-showsCondExpr (CondExpr pos exp1 exp2)-  = showsString "(CondExpr "-  . showsPosition pos . space-  . showsExpression exp1 . space-  . showsExpression exp2-  . showsString ")"--showsLiteral :: Literal -> ShowS-showsLiteral (Char _ c) = showsString "(Char " . shows c . showsString ")"-showsLiteral (Int ident n)-  = showsString "(Int "-  . showsIdent ident . space-  . shows n-  . showsString ")"-showsLiteral (Float _ x) = showsString "(Float " . shows x . showsString ")"-showsLiteral (String _ s) = showsString "(String " . shows s . showsString ")"--showsConsTerm :: ConstrTerm -> ShowS-showsConsTerm (LiteralPattern lit)-  = showsString "(LiteralPattern "-  . showsLiteral lit-  . showsString ")"-showsConsTerm (NegativePattern ident lit)-  = showsString "(NegativePattern "-  . showsIdent ident . space-  . showsLiteral lit-  . showsString ")"-showsConsTerm (VariablePattern ident)-  = showsString "(VariablePattern "-  . showsIdent ident -  . showsString ")"-showsConsTerm (ConstructorPattern qident conss)-  = showsString "(ConstructorPattern "-  . showsQualIdent qident . space-  . showsList showsConsTerm conss-  . showsString ")"-showsConsTerm (InfixPattern cons1 qident cons2)-  = showsString "(InfixPattern "-  . showsConsTerm cons1 . space-  . showsQualIdent qident . space-  . showsConsTerm cons2-  . showsString ")"-showsConsTerm (ParenPattern cons)-  = showsString "(ParenPattern "-  . showsConsTerm cons-  . showsString ")"-showsConsTerm (TuplePattern _ conss)-  = showsString "(TuplePattern "-  . showsList showsConsTerm conss-  . showsString ")"-showsConsTerm (ListPattern _ conss)-  = showsString "(ListPattern "-  . showsList showsConsTerm conss-  . showsString ")"-showsConsTerm (AsPattern ident cons)-  = showsString "(AsPattern "-  . showsIdent ident . space-  . showsConsTerm cons-  . showsString ")"-showsConsTerm (LazyPattern _ cons)-  = showsString "(LazyPattern "-  . showsConsTerm cons-  . showsString ")"-showsConsTerm (FunctionPattern qident conss)-  = showsString "(FunctionPattern "-  . showsQualIdent qident . space-  . showsList showsConsTerm conss-  . showsString ")"-showsConsTerm (InfixFuncPattern cons1 qident cons2)-  = showsString "(InfixFuncPattern "-  . showsConsTerm cons1 . space-  . showsQualIdent qident . space-  . showsConsTerm cons2-  . showsString ")"-showsConsTerm (RecordPattern cfields mcons)-  = shows "(RecordPattern "-  . showsList (showsField showsConsTerm) cfields . space-  . showsMaybe showsConsTerm mcons-  . showsString ")"--showsExpression :: Expression -> ShowS-showsExpression (Literal lit)-  = showsString "(Literal " . showsLiteral lit . showsString ")"-showsExpression (Variable qident)-  = showsString "(Variable " . showsQualIdent qident . showsString ")"-showsExpression (Constructor qident)-  = showsString "(Constructor " . showsQualIdent qident . showsString ")"-showsExpression (Paren exp)-  = showsString "(Paren " . showsExpression exp . showsString ")"-showsExpression (Typed exp typ)-  = showsString "(Typed "-  . showsExpression exp . space-  . showsTypeExpr typ-  . showsString ")"-showsExpression (Tuple _ exps)-  = showsString "(Tuple " . showsList showsExpression exps . showsString ")"-showsExpression (List _ exps)-  = showsString "(List " . showsList showsExpression exps . showsString ")"-showsExpression (ListCompr _ exp stmts)-  = showsString "(ListCompr "-  . showsExpression exp . space-  . showsList showsStatement stmts-  . showsString ")"-showsExpression (EnumFrom exp)-  = showsString "(EnumFrom " . showsExpression exp . showsString ")"-showsExpression (EnumFromThen exp1 exp2)-  = showsString "(EnumFromThen "-  . showsExpression exp1 . space-  . showsExpression exp2-  . showsString ")"-showsExpression (EnumFromTo exp1 exp2)-  = showsString "(EnumFromTo "-  . showsExpression exp1 . space-  . showsExpression exp2-  . showsString ")"-showsExpression (EnumFromThenTo exp1 exp2 exp3)-  = showsString "(EnumFromThenTo "-  . showsExpression exp1 . space-  . showsExpression exp2 . space-  . showsExpression exp3-  . showsString ")"-showsExpression (UnaryMinus ident exp)-  = showsString "(UnaryMinus "-  . showsIdent ident . space-  . showsExpression exp-  . showsString ")"-showsExpression (Apply exp1 exp2)-  = showsString "(Apply "-  . showsExpression exp1 . space-  . showsExpression exp2-  . showsString ")"-showsExpression (InfixApply exp1 op exp2)-  = showsString "(InfixApply "-  . showsExpression exp1 . space-  . showsInfixOp op . space-  . showsExpression exp2-  . showsString ")"-showsExpression (LeftSection exp op)-  = showsString "(LeftSection "-  . showsExpression exp . space-  . showsInfixOp op-  . showsString ")"-showsExpression (RightSection op exp)-  = showsString "(RightSection "-  . showsInfixOp op . space-  . showsExpression exp-  . showsString ")"-showsExpression (Lambda _ conss exp)-  = showsString "(Lambda "-  . showsList showsConsTerm conss . space-  . showsExpression exp -  . showsString ")"-showsExpression (Let decls exp)-  = showsString "(Let "-  . showsList showsDecl decls . space-  . showsExpression exp -  . showsString ")"-showsExpression (Do stmts exp)-  = showsString "(Do "-  . showsList showsStatement stmts . space-  . showsExpression exp-  . showsString ")"-showsExpression (IfThenElse _ exp1 exp2 exp3)-  = showsString "(IfThenElse "-  . showsExpression exp1 . space-  . showsExpression exp2 . space-  . showsExpression exp3-  . showsString ")"-showsExpression (Case _ exp alts)-  = showsString "(Case "-  . showsExpression exp . space-  . showsList showsAlt alts-  . showsString ")"-showsExpression (RecordConstr efields)-  = showsString "(RecordConstr "-  . showsList (showsField showsExpression) efields-  . showsString ")"-showsExpression (RecordSelection exp ident)-  = showsString "(RecordSelection "-  . showsExpression exp . space-  . showsIdent ident-  . showsString ")"-showsExpression (RecordUpdate efields exp)-  = showsString "(RecordUpdate "-  . showsList (showsField showsExpression) efields . space-  . showsExpression exp-  . showsString ")"--showsInfixOp :: InfixOp -> ShowS-showsInfixOp (InfixOp qident)-  = showsString "(InfixOp " . showsQualIdent qident . showsString ")"-showsInfixOp (InfixConstr qident)-  = showsString "(InfixConstr " . showsQualIdent qident . showsString ")"--showsStatement :: Statement -> ShowS-showsStatement (StmtExpr _ exp)-  = showsString "(StmtExpr " . showsExpression exp . showsString ")"-showsStatement (StmtDecl decls)-  = showsString "(StmtDecl " . showsList showsDecl decls . showsString ")"-showsStatement (StmtBind _ cons exp)-  = showsString "(StmtBind "-  . showsConsTerm cons . space-  . showsExpression exp-  . showsString ")"--showsAlt :: Alt -> ShowS-showsAlt (Alt pos cons rhs)-  = showsString "(Alt "-  . showsPosition pos . space-  . showsConsTerm cons . space-  . showsRhs rhs-  . showsString ")"--showsField :: (a -> ShowS) -> Field a -> ShowS-showsField sa (Field pos ident a)-  = showsString "(Field "-  . showsPosition pos . space-  . showsIdent ident . space-  . sa a-  . showsString ")"--showsString :: String -> ShowS-showsString = (++)--space :: ShowS-space = showsString " "--newline :: ShowS-newline = showsString "\n"--showsMaybe :: (a -> ShowS) -> Maybe a -> ShowS-showsMaybe shs-  = maybe (showsString "Nothing")-          (\x -> showsString "(Just " . shs x . showsString ")")--showsList :: (a -> ShowS) -> [a] -> ShowS-showsList _ [] = showsString "[]"-showsList shs (x:xs)-  = showsString "["-  . foldl (\sys y -> sys . showsString "," . shs y) (shs x) xs-  . showsString "]"--showsPair :: (a -> ShowS) -> (b -> ShowS) -> (a,b) -> ShowS-showsPair sa sb (a,b)-  = showsString "(" . sa a . showsString "," . sb b . showsString ")"---showsIdent :: Ident -> ShowS-showsIdent (Ident _ name n)-  = showsString "(Ident " . shows name . space . shows n . showsString ")"--showsQualIdent :: QualIdent -> ShowS-showsQualIdent (QualIdent mident ident)-    = showsString "(QualIdent "-      . showsMaybe showsModuleIdent mident -      . space-      . showsIdent ident-      . showsString ")"--showsModuleIdent :: ModuleIdent -> ShowS-showsModuleIdent = shows . moduleName
− src/Curry/Syntax/Type.lhs
@@ -1,315 +0,0 @@-> {-# LANGUAGE DeriveDataTypeable #-}--% $Id: CurrySyntax.lhs,v 1.43 2004/02/15 22:10:31 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{CurrySyntax.lhs}-\section{The Parse Tree}-This module provides the necessary data structures to maintain the-parsed representation of a Curry program.--\em{Note:} this modified version uses haskell type \texttt{Integer}-instead of \texttt{Int} for representing integer values. This allows-an unlimited range of integer constants in Curry programs.-\begin{verbatim}--> module Curry.Syntax.Type where--> import Curry.Base.Ident-> import Curry.Base.Position-> import Data.Generics-> import Control.Monad.State--\end{verbatim}-\paragraph{Modules}-\begin{verbatim}--> data Module = Module ModuleIdent (Maybe ExportSpec) [Decl] ->  deriving (Eq,Show,Read,Typeable,Data)--> data ExportSpec = Exporting Position [Export] deriving (Eq,Show,Read,Typeable,Data)-> data Export =->     Export         QualIdent                  -- f/T->   | ExportTypeWith QualIdent [Ident]          -- T(C1,...,Cn)->   | ExportTypeAll  QualIdent                  -- T(..)->   | ExportModule   ModuleIdent->   deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Module declarations}-\begin{verbatim}--> data ImportSpec =->     Importing Position [Import]->   | Hiding Position [Import]->   deriving (Eq,Show,Read,Typeable,Data)-> data Import =->     Import         Ident            -- f/T->   | ImportTypeWith Ident [Ident]    -- T(C1,...,Cn)->   | ImportTypeAll  Ident            -- T(..)->   deriving (Eq,Show,Read,Typeable,Data)--> data Decl =->     ImportDecl Position ModuleIdent Qualified (Maybe ModuleIdent)->                (Maybe ImportSpec)->   | InfixDecl Position Infix Integer [Ident]->   | DataDecl Position Ident [Ident] [ConstrDecl]->   | NewtypeDecl Position Ident [Ident] NewConstrDecl->   | TypeDecl Position Ident [Ident] TypeExpr->   | TypeSig Position [Ident] TypeExpr->   | EvalAnnot Position [Ident] EvalAnnotation->   | FunctionDecl Position Ident [Equation]->   | ExternalDecl Position CallConv (Maybe String) Ident TypeExpr->   | FlatExternalDecl Position [Ident]->   | PatternDecl Position ConstrTerm Rhs->   | ExtraVariables Position [Ident]->   deriving (Eq,Show,Read,Typeable,Data)--> data ConstrDecl =->     ConstrDecl Position [Ident] Ident [TypeExpr]->   | ConOpDecl Position [Ident] TypeExpr Ident TypeExpr->   deriving (Eq,Show,Read,Typeable,Data)-> data NewConstrDecl =->   NewConstrDecl Position [Ident] Ident TypeExpr->   deriving (Eq,Show,Read,Typeable,Data)--> type Qualified = Bool-> data Infix = InfixL | InfixR | Infix deriving (Eq,Show,Read,Typeable,Data)-> data EvalAnnotation = EvalRigid | EvalChoice deriving (Eq,Show,Read,Typeable,Data)-> data CallConv = CallConvPrimitive | CallConvCCall deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Module interfaces}-Interface declarations are restricted to type declarations and signatures. -Note that an interface function declaration additionaly contains the -function arity (= number of parameters) in order to generate-correct FlatCurry function applications.-\begin{verbatim}--> data Interface = Interface ModuleIdent [IDecl] deriving (Eq,Show,Read,Typeable,Data)--> data IDecl =->     IImportDecl Position ModuleIdent->   | IInfixDecl Position Infix Integer QualIdent->   | HidingDataDecl Position Ident [Ident] ->   | IDataDecl Position QualIdent [Ident] [Maybe ConstrDecl]->   | INewtypeDecl Position QualIdent [Ident] NewConstrDecl->   | ITypeDecl Position QualIdent [Ident] TypeExpr->   | IFunctionDecl Position QualIdent Int TypeExpr->   deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Types}-\begin{verbatim}--> data TypeExpr =->     ConstructorType QualIdent [TypeExpr]->   | VariableType Ident->   | TupleType [TypeExpr]->   | ListType TypeExpr->   | ArrowType TypeExpr TypeExpr->   | RecordType [([Ident],TypeExpr)] (Maybe TypeExpr) ->     -- {l1 :: t1,...,ln :: tn | r}->   deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Functions}-\begin{verbatim}--> data Equation = Equation Position Lhs Rhs deriving (Eq,Show,Read,Typeable,Data)-> data Lhs =->     FunLhs Ident [ConstrTerm]->   | OpLhs ConstrTerm Ident ConstrTerm->   | ApLhs Lhs [ConstrTerm]->   deriving (Eq,Show,Read,Typeable,Data)-> data Rhs =->     SimpleRhs Position Expression [Decl]->   | GuardedRhs [CondExpr] [Decl]->   deriving (Eq,Show,Read,Typeable,Data)-> data CondExpr = CondExpr Position Expression Expression deriving (Eq,Show,Read,Typeable,Data)--> flatLhs :: Lhs -> (Ident,[ConstrTerm])-> flatLhs lhs = flat lhs []->   where flat (FunLhs f ts) ts' = (f,ts ++ ts')->         flat (OpLhs t1 op t2) ts = (op,t1:t2:ts)->         flat (ApLhs lhs ts) ts' = flat lhs (ts ++ ts')--\end{verbatim}-\paragraph{Literals} The \texttt{Ident} argument of an \texttt{Int}-literal is used for supporting ad-hoc polymorphism on integer-numbers. An integer literal can be used either as an integer number or-as a floating-point number depending on its context. The compiler uses-the identifier of the \texttt{Int} literal for maintaining its type.-\begin{verbatim}--> data Literal =->     Char SrcRef Char                         -- should be Int to handle Unicode->   | Int Ident Integer->   | Float SrcRef Double->   | String SrcRef String                     -- should be [Int] to handle Unicode->   deriving (Eq,Show,Read,Typeable,Data)--> mk' :: ([SrcRef] -> a) -> a-> mk' = ($[])--> mk :: (SrcRef -> a) -> a-> mk = ($noRef)--> mkInt :: Integer -> Literal-> mkInt i = mk (\r -> Int (addPositionIdent (AST  r) anonId) i) --\end{verbatim}-\paragraph{Patterns}-\begin{verbatim}--> data ConstrTerm =->     LiteralPattern Literal->   | NegativePattern Ident Literal->   | VariablePattern Ident->   | ConstructorPattern QualIdent [ConstrTerm]->   | InfixPattern ConstrTerm QualIdent ConstrTerm->   | ParenPattern ConstrTerm->   | TuplePattern SrcRef [ConstrTerm]->   | ListPattern [SrcRef] [ConstrTerm]->   | AsPattern Ident ConstrTerm->   | LazyPattern SrcRef ConstrTerm->   | FunctionPattern QualIdent [ConstrTerm]->   | InfixFuncPattern ConstrTerm QualIdent ConstrTerm->   | RecordPattern [Field ConstrTerm] (Maybe ConstrTerm)  ->         -- {l1 = p1, ..., ln = pn}  oder {l1 = p1, ..., ln = pn | p}->   deriving (Eq,Show,Read,Typeable,Data)--\end{verbatim}-\paragraph{Expressions}-\begin{verbatim}--> data Expression =->     Literal Literal->   | Variable QualIdent->   | Constructor QualIdent->   | Paren Expression->   | Typed Expression TypeExpr->   | Tuple SrcRef [Expression]->   | List [SrcRef] [Expression]->   | ListCompr SrcRef Expression [Statement] -- the ref corresponds to the main list  ->   | EnumFrom Expression->   | EnumFromThen Expression Expression->   | EnumFromTo Expression Expression->   | EnumFromThenTo Expression Expression Expression->   | UnaryMinus Ident Expression->   | Apply Expression Expression->   | InfixApply Expression InfixOp Expression->   | LeftSection Expression InfixOp->   | RightSection InfixOp Expression->   | Lambda SrcRef [ConstrTerm] Expression->   | Let [Decl] Expression->   | Do [Statement] Expression->   | IfThenElse SrcRef Expression Expression Expression->   | Case SrcRef Expression [Alt]->   | RecordConstr [Field Expression]            -- {l1 = e1,...,ln = en}->   | RecordSelection Expression Ident           -- e -> l->   | RecordUpdate [Field Expression] Expression -- {l1 := e1,...,ln := en | e}->   deriving (Eq,Show,Read,Typeable,Data)--> data InfixOp = InfixOp QualIdent | InfixConstr QualIdent deriving (Eq,Show,Read,Typeable,Data)--> data Statement =->     StmtExpr SrcRef Expression->   | StmtDecl [Decl]->   | StmtBind SrcRef ConstrTerm Expression->   deriving (Eq,Show,Read,Typeable,Data)--> data Alt = Alt Position ConstrTerm Rhs deriving (Eq,Show,Read,Typeable,Data)--> data Field a = Field Position Ident a deriving (Eq, Show,Read,Typeable,Data)--> fieldLabel :: Field a -> Ident-> fieldLabel (Field _ l _) = l--> fieldTerm :: Field a -> a-> fieldTerm (Field _ _ t) = t--> field2Tuple :: Field a -> (Ident,a)-> field2Tuple (Field _ l t) = (l,t)--> opName :: InfixOp -> QualIdent-> opName (InfixOp op) = op-> opName (InfixConstr c) = c--\end{verbatim}--> instance SrcRefOf ConstrTerm where->   srcRefOf (LiteralPattern l) = srcRefOf l->   srcRefOf (NegativePattern i _) = srcRefOf i->   srcRefOf (VariablePattern i) = srcRefOf i->   srcRefOf (ConstructorPattern i _) = srcRefOf i->   srcRefOf (InfixPattern _ i _) = srcRefOf i->   srcRefOf (ParenPattern c) = srcRefOf c->   srcRefOf (TuplePattern s _) = s->   srcRefOf (ListPattern s _) = error "list pattern has several source refs"->   srcRefOf (AsPattern i _) = srcRefOf i->   srcRefOf (LazyPattern s _) = s->   srcRefOf (FunctionPattern i _) = srcRefOf i->   srcRefOf (InfixFuncPattern _ i _) = srcRefOf i--> instance SrcRefOf Literal where->   srcRefOf (Char s _)   = s->   srcRefOf (Int i _)    = srcRefOf i->   srcRefOf (Float s _)  = s->   srcRefOf (String s _) = s-------------------------------- add source references------------------------------> type M a = a -> State Int a-> -> addSrcRefs :: Module -> Module-> addSrcRefs x = evalState (addRef x) 0->   where ->     addRef :: Data a' => M a' ->     addRef = down `extM` addRefPos   ->                   `extM` addRefSrc   ->                   `extM` addRefIdent->                   `extM` addRefListPat->                   `extM` addRefListExp->       where->         down :: Data a' => M a'->         down = gmapM addRef-> ->         addRefPos :: M [SrcRef]->         addRefPos _ = liftM (:[]) next-> ->         addRefSrc :: M SrcRef->         addRefSrc _ = next-> ->         addRefIdent :: M Ident->         addRefIdent ident = liftM (flip addRefId ident) next->->         addRefListPat :: M ConstrTerm->         addRefListPat (ListPattern _ ts) = do->           liftM (uncurry ListPattern) (addRefList ts)->         addRefListPat ct = gmapM addRef ct->   ->         addRefListExp :: M Expression->         addRefListExp (List _ ts) = do->           liftM (uncurry List) (addRefList ts)->         addRefListExp ct = gmapM addRef ct->   ->         addRefList :: Data a' => [a'] -> State Int ([SrcRef],[a'])->         addRefList ts = do->           i <- next->           let add t = do t' <- addRef t;j <- next; return (j,t')->           ists <- sequence (map add ts)->           let (is,ts') = unzip ists->           return (i:is,ts')->         ->         next :: State Int SrcRef->         next = do->           i <- get->           put $! i+1->           return (SrcRef [i])
− src/Curry/Syntax/Unlit.hs
@@ -1,61 +0,0 @@-{--  Since version 0.7 of the language report, Curry accepts literate-  source programs. In a literate source all program lines must begin-  with a greater sign in the first column. All other lines are assumed-  to be documentation. In order to avoid some common errors with-  literate programs, Curry requires at least one program line to be-  present in the file. In addition, every block of program code must be-  preceded by a blank line and followed by a blank line.--  This module has been rewritten by Holger Siegel in 2009.--  (c) Holger Siegel, 2009.--}---module Curry.Syntax.Unlit(unlit) where--import Control.Monad(when, zipWithM)-import Data.Char--import Curry.Base.Position-import Curry.Base.MessageMonad---data Line = Program !Int String-          | Blank | Comment--classify :: Int -> String -> Line-classify l ('>':cs)  = Program l cs-classify _ cs-  | all isSpace cs = Blank-  | otherwise      = Comment--{--  Process a literate program into error messages (if any) and the-  corresponding non-literate program.--}--unlit :: FilePath -> String -> MsgMonad String-unlit fn lcy = do ls <- progLines fn (zipWith classify [1..] $ lines lcy)-                  when (all null ls) $-                       failWith (fn ++ ": no code in literate script")-                  return (unlines ls)--{--  Check that each program line is not adjacent to a comment line and-  there is at least one program line.--}-progLines :: FilePath -> [Line] -> MsgMonad [String]-progLines fn cs -   = zipWithM adjacent (Blank : cs) cs-  where-    adjacent :: Line -> Line -> MsgMonad String-    adjacent (Program p _) Comment     = message fn p "followed"-    adjacent Comment     (Program p _) = message fn p "preceded"-    adjacent _ (Program _ s)           = return s-    adjacent _ _                       = return ""--message :: String -> Int -> String -> MsgMonad a-message file p w = failWithAt (Position file p 1 noRef) msg-    where msg = "When reading literate source: Program line is " ++ w ++ " by comment line."
− src/Curry/Syntax/Utils.hs
@@ -1,257 +0,0 @@-module Curry.Syntax.Utils(Expr, fv, qfv,-                          QuantExpr, bv,--                          isEvalAnnot, isTypeSig,-                          infixOp,-                          isTypeDecl, isValueDecl,-                          isInfixDecl,-                          isRecordDecl, isImportDecl) where--import qualified Data.Set as Set---import Curry.Base.Ident -import Curry.Syntax.Type--{--  Free and bound variables-  -  The compiler needs to compute the sets of free and bound variables for-  various different entities. We will devote three type classes to that-  purpose. The \texttt{QualExpr} class is expected to take into account-  that it is possible to use a qualified name to refer to a function-  defined in the current module and therefore \emph{M.x} and $x$, where-  $M$ is the current module name, should be considered the same name.-  However note that this is correct only after renaming all local-  definitions as \emph{M.x} always denotes an entity defined at the-  top-level.-  -  The \texttt{Decl} instance of \texttt{QualExpr} returns all free-  variables on the right hand side, regardless of whether they are bound-  on the left hand side. This is more convenient as declarations are-  usually processed in a declaration group where the set of free-  variables cannot be computed independently for each declaration. Also-  note that the operator in a unary minus expression is not a free-  variable. This operator always refers to a global function from the-  prelude.--}--class Expr e where-  fv :: e -> [Ident]-class QualExpr e where-  qfv :: ModuleIdent -> e -> [Ident]-class QuantExpr e where-  bv :: e -> [Ident]--instance Expr e => Expr [e] where-  fv = concat . map fv-instance QualExpr e => QualExpr [e] where-  qfv m = concat . map (qfv m)-instance QuantExpr e => QuantExpr [e] where-  bv = concat . map bv--instance QualExpr Decl where-  qfv m (FunctionDecl _ _ eqs) = qfv m eqs-  qfv m (PatternDecl _ _ rhs) = qfv m rhs-  qfv _ _ = []--instance QuantExpr Decl where-  bv (TypeSig _ vs _) = vs-  bv (EvalAnnot _ fs _) = fs-  bv (FunctionDecl _ f _) = [f]-  bv (ExternalDecl _ _ _ f _) = [f]-  bv (FlatExternalDecl _ fs) = fs-  bv (PatternDecl _ t _) = bv t-  bv (ExtraVariables _ vs) = vs-  bv _ = []--instance QualExpr Equation where-  qfv m (Equation _ lhs rhs) = filterBv lhs (qfv m lhs ++ qfv m rhs)--instance QuantExpr Lhs where-  bv = bv . snd . flatLhs--instance QualExpr Lhs where-  qfv m lhs = qfv m (snd (flatLhs lhs))--instance QualExpr Rhs where-  qfv m (SimpleRhs _ e ds) = filterBv ds (qfv m e ++ qfv m ds)-  qfv m (GuardedRhs es ds) = filterBv ds (qfv m es ++ qfv m ds)--instance QualExpr CondExpr where-  qfv m (CondExpr _ g e) = qfv m g ++ qfv m e--instance QualExpr Expression where-  qfv _ (Literal _) = []-  qfv m (Variable v) = maybe [] return (localIdent m v)-  qfv _ (Constructor _) = []-  qfv m (Paren e) = qfv m e-  qfv m (Typed e _) = qfv m e-  qfv m (Tuple _ es) = qfv m es-  qfv m (List _ es) = qfv m es-  qfv m (ListCompr _ e qs) = foldr (qfvStmt m) (qfv m e) qs-  qfv m (EnumFrom e) = qfv m e-  qfv m (EnumFromThen e1 e2) = qfv m e1 ++ qfv m e2-  qfv m (EnumFromTo e1 e2) = qfv m e1 ++ qfv m e2-  qfv m (EnumFromThenTo e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3-  qfv m (UnaryMinus _ e) = qfv m e-  qfv m (Apply e1 e2) = qfv m e1 ++ qfv m e2-  qfv m (InfixApply e1 op e2) = qfv m op ++ qfv m e1 ++ qfv m e2-  qfv m (LeftSection e op) = qfv m op ++ qfv m e-  qfv m (RightSection op e) = qfv m op ++ qfv m e-  qfv m (Lambda _ ts e) = filterBv ts (qfv m e)-  qfv m (Let ds e) = filterBv ds (qfv m ds ++ qfv m e)-  qfv m (Do sts e) = foldr (qfvStmt m) (qfv m e) sts-  qfv m (IfThenElse _ e1 e2 e3) = qfv m e1 ++ qfv m e2 ++ qfv m e3-  qfv m (Case _ e alts) = qfv m e ++ qfv m alts-  qfv m (RecordConstr fs) = qfv m fs-  qfv m (RecordSelection e _) = qfv m e-  qfv m (RecordUpdate fs e) = qfv m e ++ qfv m fs--qfvStmt :: ModuleIdent -> Statement -> [Ident] -> [Ident]-qfvStmt m st fvs = qfv m st ++ filterBv st fvs--instance QualExpr Statement where-  qfv m (StmtExpr _ e) = qfv m e-  qfv m (StmtDecl ds) = filterBv ds (qfv m ds)-  qfv m (StmtBind _ t e) = qfv m e--instance QualExpr Alt where-  qfv m (Alt _ t rhs) = filterBv t (qfv m rhs)--instance QuantExpr a => QuantExpr (Field a) where-  bv (Field _ _ t) = bv t--instance QualExpr a => QualExpr (Field a) where-  qfv m (Field _ _ t) = qfv m t--instance QuantExpr Statement where-  bv (StmtExpr _ e) = []-  bv (StmtBind _ t e) = bv t-  bv (StmtDecl ds) = bv ds--instance QualExpr InfixOp where-  qfv m (InfixOp op) = qfv m (Variable op)-  qfv _ (InfixConstr _) = []--instance QuantExpr ConstrTerm where-  bv (LiteralPattern _) = []-  bv (NegativePattern _ _) = []-  bv (VariablePattern v) = [v]-  bv (ConstructorPattern c ts) = bv ts-  bv (InfixPattern t1 op t2) = bv t1 ++ bv t2-  bv (ParenPattern t) = bv t-  bv (TuplePattern _ ts) = bv ts-  bv (ListPattern _ ts) = bv ts-  bv (AsPattern v t) = v : bv t-  bv (LazyPattern _ t) = bv t-  bv (FunctionPattern f ts) = bvFuncPatt (FunctionPattern f ts)-  bv (InfixFuncPattern t1 op t2) = bvFuncPatt (InfixFuncPattern t1 op t2)-  bv (RecordPattern fs r) = (maybe [] bv r) ++ bv fs--instance QualExpr ConstrTerm where-  qfv _ (LiteralPattern _) = []-  qfv _ (NegativePattern _ _) = []-  qfv _ (VariablePattern _) = []-  qfv m (ConstructorPattern _ ts) = qfv m ts-  qfv m (InfixPattern t1 _ t2) = qfv m [t1,t2]-  qfv m (ParenPattern t) = qfv m t-  qfv m (TuplePattern _ ts) = qfv m ts-  qfv m (ListPattern _ ts) = qfv m ts-  qfv m (AsPattern _ ts) = qfv m ts-  qfv m (LazyPattern _ t) = qfv m t-  qfv m (FunctionPattern f ts) -    = (maybe [] return (localIdent m f)) ++ qfv m ts-  qfv m (InfixFuncPattern t1 op t2) -    = (maybe [] return (localIdent m op)) ++ qfv m [t1,t2]-  qfv m (RecordPattern fs r) = (maybe [] (qfv m) r) ++ qfv m fs--instance Expr TypeExpr where-  fv (ConstructorType _ tys) = fv tys-  fv (VariableType tv)-    | tv == anonId = []-    | otherwise = [tv]-  fv (TupleType tys) = fv tys-  fv (ListType ty) = fv ty-  fv (ArrowType ty1 ty2) = fv ty1 ++ fv ty2-  fv (RecordType fs rty) = (maybe [] fv rty) ++ fv (map snd fs)--filterBv :: QuantExpr e => e -> [Ident] -> [Ident]-filterBv e = filter (`Set.notMember` Set.fromList (bv e))--{--  Since multiple variable occurrences are allowed in function patterns,-  it is necessary to compute the list of bound variables in a different way:-  Each variable occuring in the function pattern will be unique in the result-  list.- -}--bvFuncPatt :: ConstrTerm -> [Ident]-bvFuncPatt = bvfp []- where- bvfp bvs (LiteralPattern _) = bvs- bvfp bvs (NegativePattern _ _) = bvs- bvfp bvs (VariablePattern v)-    | elem v bvs = bvs-    | otherwise  = v:bvs- bvfp bvs (ConstructorPattern c ts) = foldl bvfp bvs ts- bvfp bvs (InfixPattern t1 op t2) = foldl bvfp bvs [t1,t2]- bvfp bvs (ParenPattern t) = bvfp bvs t- bvfp bvs (TuplePattern _ ts) = foldl bvfp bvs ts- bvfp bvs (ListPattern _ ts) = foldl bvfp bvs ts- bvfp bvs (AsPattern v t)-    | elem v bvs = bvfp bvs t-    | otherwise  = bvfp (v:bvs) t- bvfp bvs (LazyPattern _ t) = bvfp bvs t- bvfp bvs (FunctionPattern f ts) = foldl bvfp bvs ts- bvfp bvs (InfixFuncPattern t1 op t2) = foldl bvfp bvs [t1, t2]- bvfp bvs (RecordPattern fs r)-    = foldl bvfp (maybe bvs (bvfp bvs) r) (map fieldTerm fs)----{--  Here is a list of predicates identifying various kinds of-  declarations.--}--isImportDecl, isInfixDecl, isTypeDecl :: Decl -> Bool-isTypeSig, isEvalAnnot, isValueDecl :: Decl -> Bool--isImportDecl (ImportDecl _ _ _ _ _) = True-isImportDecl _ = False--isInfixDecl (InfixDecl _ _ _ _) = True-isInfixDecl _ = False--isTypeDecl (DataDecl _ _ _ _) = True-isTypeDecl (NewtypeDecl _ _ _ _) = True-isTypeDecl (TypeDecl _ _ _ _) = True-isTypeDecl _ = False--isTypeSig (TypeSig _ _ _) = True-isTypeSig (ExternalDecl _ _ _ _ _) = True-isTypeSig _ = False--isEvalAnnot (EvalAnnot _ _ _) = True-isEvalAnnot _ = False--isValueDecl (FunctionDecl _ _ _) = True-isValueDecl (ExternalDecl _ _ _ _ _) = True-isValueDecl (FlatExternalDecl _ _) = True-isValueDecl (PatternDecl _ _ _) = True-isValueDecl (ExtraVariables _ _) = True-isValueDecl _ = False--isRecordDecl (TypeDecl _ _ _ (RecordType _ _)) = True-isRecordDecl _ = False---{--  The function \texttt{infixOp} converts an infix operator into an-  expression.--}--infixOp :: InfixOp -> Expression-infixOp (InfixOp op) = Variable op-infixOp (InfixConstr op) = Constructor op
src/CurryBuilder.hs view
@@ -1,202 +1,235 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- CurryBuilder - Generates Curry representations for a Curry source file---                including all imported modules.------ September 2005,--- Martin Engelke (men@informatik.uni-kiel.de)--- March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)----module CurryBuilder (buildCurry, smake) where+{- |+    Module      :  $Header$+    Description :  Build tool for compiling multiple Curry modules+    Copyright   :  (c) 2005        Martin Engelke+                       2007        Sebastian Fischer+                       2011 - 2015 Björn Peemöller+    License     :  BSD-3-clause -import System.Exit-import System.Time-import Control.Monad-import qualified Data.Map as Map-import Data.Maybe-import Data.List -import System.IO+    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable -import Curry.Base.Ident+    This module contains functions to generate Curry representations for a+    Curry source file including all imported modules.+-}+module CurryBuilder (buildCurry, findCurry) where -import Modules (compileModule)-import CurryCompilerOpts -import CurryDeps+import Control.Monad   (foldM, liftM)+import Data.Char       (isSpace)+import Data.Maybe      (catMaybes, fromMaybe, mapMaybe)+import System.FilePath ((</>), normalise)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.Position (Position)+import Curry.Base.Pretty import Curry.Files.Filenames import Curry.Files.PathUtils+import Curry.Syntax ( ModulePragma (..), Extension (KnownExtension)+                    , KnownExtension (CPP), Tool (CYMAKE, FRONTEND) ) +import Base.Messages -flatName' :: Options -> FilePath -> FilePath-flatName' o-    | extendedFlat o = extFlatName-    | otherwise      = flatName+import CompilerOpts ( Options (..), CppOpts (..), DebugOpts (..)+                    , TargetType (..), defaultDebugOpts, updateOpts )+import CurryDeps    (Source (..), flatDeps)+import Modules      (compileModule) --------------------------------------------------------------------------------+-- |Compile the Curry module in the given source file including all imported+-- modules w.r.t. the given 'Options'.+buildCurry :: Options -> String -> CYIO ()+buildCurry opts s = do+  fn   <- findCurry opts s+  deps <- flatDeps  opts fn+  makeCurry opts' deps+  where+  opts' | null $ optTargetTypes opts = opts { optTargetTypes = [FlatCurry] }+        | otherwise                  = opts --- Compiles the Curry program 'file' including all imported modules, depending--- on the options 'options'. The compilation was successful, if the returned--- list is empty, otherwise it contains error messages.-buildCurry :: Options -> FilePath -> IO ()-buildCurry options file-   = do let paths = importPaths options-	file'          <- getCurryPath paths file-	(cfile, errs1) <- return (maybe ("", [missingModule file])-			                (\f -> (f,[]))-				        file')-	unless (null errs1) (abortWith errs1)-	(deps, errs2) <- genDeps paths cfile-	unless (null errs2) (abortWith errs2)-	makeCurry options deps cfile+-- |Search for a compilation target identified by the given 'String'.+findCurry :: Options -> String -> CYIO FilePath+findCurry opts s = do+  mbTarget <- findFile `orIfNotFound` findModule+  case mbTarget of+    Nothing -> failMessages [complaint]+    Just fn -> ok fn+  where+  canBeFile    = isCurryFilePath s+  canBeModule  = isValidModuleName s+  moduleFile   = moduleNameToFile $ fromModuleName s+  paths        = "." : optImportPaths opts+  findFile     = if canBeFile+                    then liftIO $ lookupCurryFile paths s+                    else return Nothing+  findModule   = if canBeModule+                    then liftIO $ lookupCurryFile paths moduleFile+                    else return Nothing+  complaint+    | canBeFile && canBeModule = errMissing "target" s+    | canBeFile                = errMissing "file"   s+    | canBeModule              = errMissing "module" s+    | otherwise                = errUnrecognized  s+  first `orIfNotFound` second = do+    mbFile <- first+    case mbFile of+      Nothing -> second+      justFn  -> return justFn +-- |Compiles the given source modules, which must be in topological order.+makeCurry :: Options -> [(ModuleIdent, Source)] ->  CYIO ()+makeCurry opts srcs = mapM_ process' (zip [1 ..] srcs)+  where+  total    = length srcs+  tgtDir m = addCurrySubdirModule (optUseSubdir opts) m --------------------------------------------------------------------------------+  process' :: (Int, (ModuleIdent, Source)) -> CYIO ()+  process' (n, (m, Source fn ps is)) = do+    opts' <- processPragmas opts ps+    process (adjustOptions (n == total) opts') (n, total) m fn deps+    where+    deps = fn : mapMaybe curryInterface is -makeCurry :: Options -> [(ModuleIdent,Source)] -> FilePath -> IO ()-makeCurry options deps file-   = mapM compile (map snd deps) >> return ()- where- compile (Source file' mods)-    | dropExtension file == dropExtension file'-      = do -           flatIntfExists <- doesModuleExist (flatIntName file')-	   if flatIntfExists && not (force options) && null (dump options)-	    then smake (targetNames file')-                       (file':(catMaybes (map flatInterface mods)))-		       (generateFile file')-		       (skipFile file')-	    else generateFile file'-    | otherwise-      = do -           flatIntfExists <- doesModuleExist (flatIntName file')-	   if flatIntfExists-            then  smake [flatName' options file'] --[flatName file', flatIntName file']-	                (file':(catMaybes (map flatInterface mods)))-			(compileFile file')-			(skipFile file')-	    else compileFile file'- compile _ = return ()+    curryInterface i = case lookup i srcs of+      Just (Source    fn' _ _) -> Just $ tgtDir i $ interfName fn'+      Just (Interface fn'    ) -> Just $ tgtDir i $ interfName fn'+      _                        -> Nothing - compileFile file-    = do unless (noVerb options) (putStrLn ("compiling " ++ file ++ " ..."))-	 compileModule (compOpts True) file-	 return ()+  process' _ = return () - skipFile file-    = do unless (noVerb options)-		(putStrLn ("skipping " ++ file ++ " ..."))+adjustOptions :: Bool -> Options -> Options+adjustOptions final opts+  | final      = opts { optForce = optForce opts || isDump }+  | otherwise  = opts { optForce       = False+                      , optDebugOpts   = defaultDebugOpts+                      }+  where+  isDump = not $ null $ dbDumpLevels $ optDebugOpts opts - generateFile file-    = do unless (noVerb options) -		(putStrLn ("generating "  -			   ++ (head (targetNames file))               -			   ++ " ..."))-	 compileModule (compOpts False) file-	 return () - targetNames fn         -        | flat options            = [flatName' options fn] -- , flatIntName fn]-		| flatXml options         = [xmlName fn]-		| abstract options        = [acyName fn]-		| untypedAbstract options = [uacyName fn]-		| parseOnly options       = [maybe (sourceRepName fn) id (output options)]-		| otherwise               = [flatName' options fn] -- , flatIntName fn]-- flatInterface mod -    = case (lookup mod deps) of-        Just (Source file _)  -> Just (flatIntName (dropExtension file))-	Just (Interface file) -> Just (flatIntName (dropExtension file))-	_                     -> Nothing-- compOpts isImport-    | isImport -      = options -	   { flat = True,-	     flatXml = False,-	     abstract = False,-	     untypedAbstract = False,-	     parseOnly = False,-	     dump = []-	   }-    | otherwise = options------------------------------------------------------------------------------------- Computes a dependency list for the Curry file 'file' (such a list--- usualy starts with the prelude and ends with 'file'). The result --- is a tuple containing an association list (type [(ModuleIdent,Source)]; --- see module "CurryDeps") and a list of error messages.-genDeps :: [FilePath] -> FilePath-	   -> IO ([(ModuleIdent,Source)], [String])-genDeps paths file-   = fmap flattenDeps (deps paths [] Map.empty file)+processPragmas :: Options -> [ModulePragma] -> CYIO Options+processPragmas opts0 ps = do+  let opts1 = foldl processLanguagePragma opts0+                [ e | LanguagePragma _ es <- ps, KnownExtension _ e <- es ]+  foldM processOptionPragma opts1 $+    [ (p, s) | OptionsPragma p (Just FRONTEND) s <- ps ] +++      [ (p, s) | OptionsPragma p (Just CYMAKE) s <- ps ]+  where+  processLanguagePragma opts CPP+    = opts { optCppOpts = (optCppOpts opts) { cppRun = True } }+  processLanguagePragma opts _+    = opts+  processOptionPragma opts (p, s)+    | not (null unknownFlags)+    = failMessages [errUnknownOptions p unknownFlags]+    | optMode         opts /= optMode         opts'+    = failMessages [errIllegalOption p "Cannot change mode"]+    | optLibraryPaths opts /= optLibraryPaths opts'+    = failMessages [errIllegalOption p "Cannot change library path"]+    | optImportPaths  opts /= optImportPaths  opts'+    = failMessages [errIllegalOption p "Cannot change import path"]+    | optTargetTypes  opts /= optTargetTypes  opts'+    = failMessages [errIllegalOption p "Cannot change target type"]+    | otherwise+    = return opts'+    where+    (opts', files, errs) = updateOpts opts (quotedWords s)+    unknownFlags = files ++ errs +quotedWords :: String -> [String]+quotedWords str = case dropWhile isSpace str of+  []        -> []+  s@('\'' : cs) -> case break (== '\'') cs of+    (_     , []      ) -> def s+    (quoted, (_:rest)) -> quoted : quotedWords rest+  s@('"'  : cs) -> case break (== '"') cs of+    (_     , []      ) -> def s+    (quoted, (_:rest)) -> quoted : quotedWords rest+  s         -> def s+  where+  def s = let (w, rest) = break isSpace s in  w : quotedWords rest ----------------------------------------------------------------------------------- A simple make function+-- |Compile a single source module.+process :: Options -> (Int, Int)+        -> ModuleIdent -> FilePath -> [FilePath] -> CYIO ()+process opts idx m fn deps+  | optForce opts = compile+  | otherwise     = smake (tgtDir (interfName fn) : destFiles) deps compile skip+  where+  skip    = status opts $ compMessage idx "Skipping" m (fn, head destFiles)+  compile = do+    status opts $ compMessage idx "Compiling" m (fn, head destFiles)+    compileModule opts m fn --- smake <destination files>---       <dependencies> ---       <io action, if dependencies are newer than destination files>---       <io action, if destination files are newer than dependencies>-smake :: [FilePath] -> [FilePath] -> IO a -> IO a -> IO a-smake dests deps cmd alt-   = do destTimes <- getDestTimes dests-	depTimes  <- getDepTimes deps-	make destTimes depTimes- where- make destTimes depTimes-    | (length destTimes) < (length dests) -      = catch cmd (\err -> abortWith [show err]) -    | null depTimes -      = abortWith ["unknown dependencies"]-    | outOfDate destTimes depTimes-      = catch cmd (\err -> abortWith [show err])-    | otherwise-      = alt+  tgtDir = addCurrySubdirModule (optUseSubdir opts) m ----getDestTimes :: [FilePath] -> IO [ClockTime]-getDestTimes [] = return []-getDestTimes (file:files)-   = catch (do time  <- getModuleModTime file-	       times <- getDestTimes files-	       return (time:times))-           (const (getDestTimes files))+  destFiles = [ gen fn | (t, gen) <- nameGens, t `elem` optTargetTypes opts]+  nameGens  =+    [ (Tokens              , tgtDir . tokensName   )+    , (Parsed              , tgtDir . sourceRepName)+    , (FlatCurry           , tgtDir . flatName     )+    , (TypedFlatCurry      , tgtDir . typedFlatName)+    , (AbstractCurry       , tgtDir . acyName      )+    , (UntypedAbstractCurry, tgtDir . uacyName     )+    , (Html                , const (fromMaybe "." (optHtmlDir opts) </> htmlName m))+    ] ----getDepTimes :: [String] -> IO [ClockTime]-getDepTimes [] = return []-getDepTimes (file:files)-   = catch (do time  <- getModuleModTime file-	       times <- getDepTimes files-	       return (time:times))-           (\err -> abortWith [show err])+-- |Create a status message like+-- @[m of n] Compiling Module          ( M.curry, .curry/M.fcy )@+compMessage :: (Int, Int) -> String -> ModuleIdent+            -> (FilePath, FilePath) -> String+compMessage (curNum, maxNum) what m (src, dst)+  =  '[' : lpad (length sMaxNum) (show curNum) ++ " of " ++ sMaxNum  ++ "]"+  ++ ' ' : rpad 9 what ++ ' ' : rpad 16 (moduleName m)+  ++ " ( " ++ normalise src ++ ", " ++ normalise dst ++ " )"+  where+  sMaxNum  = show maxNum+  lpad n s = replicate (n - length s) ' ' ++ s+  rpad n s = s ++ replicate (n - length s) ' ' ----outOfDate :: [ClockTime] -> [ClockTime] -> Bool-outOfDate tgtimes dptimes = or (map (\t -> or (map ((<) t) dptimes)) tgtimes)+-- |A simple make function+smake :: [FilePath] -- ^ destination files+      -> [FilePath] -- ^ dependency files+      -> CYIO a     -- ^ action to perform if depedency files are newer+      -> CYIO a     -- ^ action to perform if destination files are newer+      -> CYIO a+smake dests deps actOutdated actUpToDate = do+  destTimes <- catMaybes `liftM` mapM (liftIO . getModuleModTime) dests+  depTimes  <- mapM (cancelMissing getModuleModTime) deps+  make destTimes depTimes+  where+  make destTimes depTimes+    | length destTimes < length dests = actOutdated+    | outOfDate destTimes depTimes    = actOutdated+    | otherwise                       = actUpToDate ----------------------------------------------------------------------------------- Error handling+  outOfDate tgtimes dptimes = or [ tg < dp | tg <- tgtimes, dp <- dptimes] --- Prints an error message on 'stderr'-putErrLn :: String -> IO ()-putErrLn = hPutStrLn stderr+cancelMissing :: (FilePath -> IO (Maybe a)) -> FilePath -> CYIO a+cancelMissing act f = liftIO (act f) >>= \res -> case res of+  Nothing  -> failMessages [errModificationTime f]+  Just val -> ok val --- Prints a list of error messages on 'stderr'-putErrsLn :: [String] -> IO ()-putErrsLn = mapM_ putErrLn+errUnknownOptions :: Position -> [String] -> Message+errUnknownOptions p errs = posMessage p $+  text "Unknown flag(s) in {-# OPTIONS_FRONTEND #-} pragma:"+  <+> sep (punctuate comma $ map text errs) --- Prints a list of error messages on 'stderr' and aborts the program-abortWith :: [String] -> IO a-abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)+errIllegalOption :: Position -> String -> Message+errIllegalOption p err = posMessage p $+  text "Illegal option in {-# OPTIONS_FRONTEND #-} pragma:" <+> text err +errMissing :: String -> String -> Message+errMissing what which = message $ sep $ map text+  [ "Missing", what, quote which ] --- Error messages+errUnrecognized :: String -> Message+errUnrecognized f = message $ sep $ map text+  [ "Unrecognized input", quote f ] -missingModule :: FilePath -> String-missingModule file = "Error: missing module \"" ++ file ++ "\""+errModificationTime :: FilePath -> Message+errModificationTime f = message $ sep $ map text+  [ "Could not inspect modification time of file", quote f ] ----------------------------------------------------------------------------------------------------------------------------------------------------------------+quote :: String -> String+quote s = "\"" ++ s ++ "\""
− src/CurryCompilerOpts.hs
@@ -1,166 +0,0 @@--- -------------------------------------------------------------------------------- |--- CurryCompilerOpts - Defines data structures containing options for---                     compiling Curry programs (see module "CurryCompiler")------ September 2005,--- Martin Engelke (men@informatik.uni-kiel.de)--- March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)------ -------------------------------------------------------------------------------module CurryCompilerOpts where--import System.Console.GetOpt----- | Data type for recording compiler options-data Options-  = Options-  { force :: Bool             -- ^ force compilation-  , html :: Bool              -- ^ generate Html code-  , importPaths :: [FilePath] -- ^ directories for searching imports-  , output :: Maybe FilePath  -- ^ name of output file-  , noInterface :: Bool       -- ^ do not create an interface file-  , noVerb :: Bool            -- ^ verbosity on/off-  , noWarn :: Bool            -- ^ warnings on/off-  , noOverlapWarn :: Bool     -- ^ "overlap" warnings on/off-  , flat :: Bool              -- ^ generate FlatCurry code-  , extendedFlat :: Bool      -- ^ generate FlatCurry code with extensions-  , flatXml :: Bool           -- ^ generate flat XML code-  , abstract :: Bool          -- ^ generate typed AbstracCurry code-  , untypedAbstract :: Bool   -- ^ generate untyped AbstractCurry code-  , parseOnly :: Bool         -- ^ generate source representation-  , withExtensions :: Bool    -- ^ enable extended functionalities-  , dump :: [Dump]            -- ^ dumps-  , writeToSubdir :: Bool     -- ^ should the output be written to the subdir?-  } deriving Show----- | Default compiler options-defaultOpts = Options-  { force           = False-  , html            = False-  , importPaths     = []-  , output          = Nothing-  , noInterface     = False-  , noVerb          = False-  , noWarn          = False-  , noOverlapWarn   = False-  , extendedFlat    = False-  , flat            = False-  , flatXml         = False-  , abstract        = False-  , untypedAbstract = False-  , parseOnly       = False-  , withExtensions  = False-  , dump            = []-  , writeToSubdir   = True-  }----- | Data type for representing all available options (needed to read and parse---   the options from the command line; see module 'GetOpt')-data Option-  = Help | Force | Html-  | ImportPath FilePath | Output FilePath-  | NoInterface | NoVerb | NoWarn | NoOverlapWarn-  | FlatXML | Flat | ExtFlat | Abstract | UntypedAbstract | ParseOnly-  | WithExtensions-  | Dump [Dump]-  | WriteToSubdir-  deriving Eq----- | All available compiler options-options =-  [ Option "f"  ["force"] (NoArg Force)-              "force compilation of dependent files"-  , Option ""   ["html"] (NoArg Html)-              "generate html code"-  , Option "i"  ["import-dir"] (ReqArg ImportPath "DIR")-              "search for imports in DIR"-  , Option "o"  ["output"] (ReqArg Output "FILE")-              "write code to FILE"-  , Option ""   ["no-intf"] (NoArg NoInterface)-              "do not create an interface file"-  , Option ""   ["no-verb"] (NoArg NoVerb)-          "do not print compiler messages"-  , Option ""   ["no-warn"] (NoArg NoWarn)-          "do not print warnings"-  , Option ""   ["no-overlap-warn"] (NoArg NoOverlapWarn)-          "do not print warnings for overlapping rules"-  , Option ""   ["flat"] (NoArg Flat)-              "generate FlatCurry code"-  , Option ""   ["extended-flat"] (NoArg ExtFlat)-              "generate FlatCurry code with source references"-  , Option ""   ["xml"] (NoArg FlatXML)-              "generate flat xml code"-  , Option ""   ["acy"] (NoArg Abstract)-              "generate (type infered) AbstractCurry code"-  , Option ""   ["uacy"] (NoArg UntypedAbstract)-              "generate untyped AbstractCurry code"-  , Option ""   ["parse-only"] (NoArg ParseOnly)-              "generate source representation"-  , Option "e"  ["extended"] (NoArg WithExtensions)-              "enable extended Curry functionalities"-  , Option ""   ["dump-all"] (NoArg (Dump [minBound..maxBound]))-              "dump everything"-  , Option ""   ["dump-renamed"] (NoArg (Dump [DumpRenamed]))-              "dump source code after renaming"-  , Option ""   ["dump-types"] (NoArg (Dump [DumpTypes]))-              "dump types after type-checking"-  , Option ""   ["dump-desugared"] (NoArg (Dump [DumpDesugared]))-              "dump source code after desugaring"-  , Option ""   ["dump-simplified"] (NoArg (Dump [DumpSimplified]))-              "dump source code after simplification"-  , Option ""   ["dump-lifted"] (NoArg (Dump [DumpLifted]))-              "dump source code after lambda-lifting"-  , Option ""   ["dump-il"] (NoArg (Dump [DumpIL]))-              "dump intermediate language before lifting"-  , Option ""   ["dump-case"] (NoArg (Dump [DumpCase]))-              "dump intermediate language after case simplification"-  , Option "?h" ["help"] (NoArg Help)-              "display this help and exit"-  , Option ""   ["no-hidden-subdir"] (NoArg WriteToSubdir)-              "write all output to hidden .curry subdirectory"-  ]----- | Marks an 'Option' as selected in the 'Options' record-selectOption :: Option -> Options -> Options-selectOption Force opts           = opts { force = True }-selectOption (ImportPath dir) opts-   = opts { importPaths = dir:(importPaths opts) }-selectOption (Output file) opts   = opts { output = Just file }-selectOption NoInterface opts     = opts { noInterface = True }-selectOption NoVerb opts          = opts { noVerb = True }-selectOption NoWarn opts          = opts { noWarn = True }-selectOption NoOverlapWarn opts   = opts { noOverlapWarn = True }-selectOption Flat opts            = opts { flat = True }-selectOption ExtFlat opts         = opts { extendedFlat = True }-selectOption Html opts            = opts { html = True }-selectOption FlatXML opts         = opts { flatXml = True }-selectOption Abstract opts        = opts { abstract = True }-selectOption UntypedAbstract opts = opts { untypedAbstract = True }-selectOption ParseOnly opts       = opts { parseOnly = True }-selectOption WithExtensions opts  = opts { withExtensions = True }-selectOption (Dump ds) opts       = opts { dump = ds ++ dump opts }-selectOption WriteToSubdir opts   = opts { writeToSubdir = False }----- | Data type for representing code dumps---   TODO: dump FlatCurry code, dump AbstractCurry code, dump after 'case'---   expansion-data Dump-  = DumpRenamed      -- ^ dump source after renaming-  | DumpTypes        -- ^ dump types after typechecking-  | DumpDesugared    -- ^ dump source after desugaring-  | DumpSimplified   -- ^ dump source after simplification-  | DumpLifted       -- ^ dump source after lambda-lifting-  | DumpIL           -- ^ dump IL code after translation-  | DumpCase         -- ^ dump IL code after case elimination-    deriving (Eq,Bounded,Enum,Show)-----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/CurryDeps.hs view
@@ -0,0 +1,187 @@+{- |+    Module      :  $Header$+    Description :  Computation of module dependencies+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux+                       2005        Martin Engelke+                       2007        Sebastian Fischer+                       2011 - 2013 Björn Peemöller+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module implements the functions to compute the dependency+    information between Curry modules. This is used to create Makefile+    dependencies and to update programs composed of multiple modules.+-}++module CurryDeps+  ( Source (..), flatDeps, deps, flattenDeps, sourceDeps, moduleDeps ) where++import           Control.Monad   (foldM)+import           Data.List       (isSuffixOf, nub)+import qualified Data.Map as Map (Map, empty, insert, lookup, toList)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.Pretty+import Curry.Files.Filenames+import Curry.Files.PathUtils+import Curry.Syntax+  ( Module (..), ModulePragma (..), ImportDecl (..), parseHeader, parsePragmas+  , patchModuleId, hasLanguageExtension)++import Base.Messages+import Base.SCC (scc)+import CompilerOpts (Options (..), CppOpts (..), KnownExtension (..))+import CondCompile (condCompile)++-- |Different types of source files+data Source+    -- | A source file with pragmas and module imports+  = Source FilePath [ModulePragma] [ModuleIdent]+    -- | An interface file+  | Interface FilePath+    -- | An unknown file+  | Unknown+    deriving (Eq, Show)++type SourceEnv = Map.Map ModuleIdent Source++-- |Retrieve the dependencies of a source file in topological order+-- and possible errors during flattering+flatDeps :: Options -> FilePath -> CYIO [(ModuleIdent, Source)]+flatDeps opts fn = do+  sEnv <- deps opts Map.empty fn+  case flattenDeps sEnv of+    (env, []  ) -> ok env+    (_  , errs) -> failMessages errs++-- |Retrieve the dependencies of a source file as a 'SourceEnv'+deps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv+deps opts sEnv fn+  | ext   ==   icurryExt  = return sEnv+  | ext `elem` sourceExts = sourceDeps opts sEnv fn+  | otherwise             = targetDeps opts sEnv fn+  where ext = takeExtension fn++-- The following functions are used to lookup files related to a given+-- module. Source files for targets are looked up in the current+-- directory only. Two different search paths are used to look up+-- imported modules, the first is used to find source modules, whereas+-- the library path is used only for finding matching interface files. As+-- the compiler does not distinguish these paths, we actually check for+-- interface files in the source paths as well.++-- In order to compute the dependency graph, source files for each module+-- need to be looked up. When a source module is found, its header is+-- parsed in order to determine the modules that it imports, and+-- dependencies for these modules are computed recursively. The prelude+-- is added implicitly to the list of imported modules except for the+-- prelude itself.++-- |Retrieve the dependencies of a given target file+targetDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv+targetDeps opts sEnv fn = do+  mFile <- liftIO $ lookupFile [""] sourceExts fn+  case mFile of+    Nothing   -> return $ Map.insert (mkMIdent [fn]) Unknown sEnv+    Just file -> sourceDeps opts sEnv file++-- |Retrieve the dependencies of a given source file+sourceDeps :: Options -> SourceEnv -> FilePath -> CYIO SourceEnv+sourceDeps opts sEnv fn = readHeader opts fn >>= moduleDeps opts sEnv fn++-- |Retrieve the dependencies of a given module+moduleDeps :: Options -> SourceEnv -> FilePath -> Module a -> CYIO SourceEnv+moduleDeps opts sEnv fn mdl@(Module ps m _ _ _) = case Map.lookup m sEnv of+  Just  _ -> return sEnv+  Nothing -> do+    let imps  = imports opts mdl+        sEnv' = Map.insert m (Source fn ps imps) sEnv+    foldM (moduleIdentDeps opts) sEnv' imps++-- |Retrieve the imported modules and add the import of the Prelude+-- according to the compiler options.+imports :: Options -> Module a -> [ModuleIdent]+imports opts mdl@(Module _ m _ is _) = nub $+     [preludeMIdent | m /= preludeMIdent && not noImplicitPrelude]+  ++ [m' | ImportDecl _ m' _ _ _ <- is]+  where noImplicitPrelude = NoImplicitPrelude `elem` optExtensions opts+                              || mdl `hasLanguageExtension` NoImplicitPrelude++-- |Retrieve the dependencies for a given 'ModuleIdent'+moduleIdentDeps :: Options -> SourceEnv -> ModuleIdent -> CYIO SourceEnv+moduleIdentDeps opts sEnv m = case Map.lookup m sEnv of+  Just _  -> return sEnv+  Nothing -> do+    mFile <- liftIO $ lookupCurryModule ("." : optImportPaths opts)+                                        (optLibraryPaths opts) m+    case mFile of+      Nothing -> return $ Map.insert m Unknown sEnv+      Just fn+        | icurryExt `isSuffixOf` fn ->+            return $ Map.insert m (Interface fn) sEnv+        | otherwise                 -> do+            hdr@(Module _ m' _ _ _) <- readHeader opts fn+            if (m == m') then moduleDeps opts sEnv fn hdr+                         else failMessages [errWrongModule m m']++readHeader :: Options -> FilePath -> CYIO (Module ())+readHeader opts fn = do+  mbFile <- liftIO $ readModule fn+  case mbFile of+    Nothing  -> failMessages [errMissingFile fn]+    Just src -> do+      prgs <- liftCYM $ parsePragmas fn src+      let cppOpts  = optCppOpts opts+          cppOpts' =+            cppOpts { cppRun = cppRun cppOpts || hasLanguageExtension prgs CPP }+      condC <- condCompile cppOpts' fn src+      hdr <- liftCYM $ parseHeader fn condC+      return $ patchModuleId fn hdr++-- If we want to compile the program instead of generating Makefile+-- dependencies, the environment has to be sorted topologically. Note+-- that the dependency graph should not contain any cycles.+flattenDeps :: SourceEnv -> ([(ModuleIdent, Source)], [Message])+flattenDeps = fdeps . sortDeps+  where+  sortDeps :: SourceEnv -> [[(ModuleIdent, Source)]]+  sortDeps = scc idents imported . Map.toList++  idents (m, _) = [m]++  imported (_, Source _ _ ms) = ms+  imported (_,             _) = []++  fdeps :: [[(ModuleIdent, Source)]] -> ([(ModuleIdent, Source)], [Message])+  fdeps = foldr checkdep ([], [])++  checkdep []    (srcs, errs) = (srcs      , errs      )+  checkdep [src] (srcs, errs) = (src : srcs, errs      )+  checkdep dep   (srcs, errs) = (srcs      , err : errs)+    where err = errCyclicImport $ map fst dep++errMissingFile :: FilePath -> Message+errMissingFile fn = message $ sep $ map text [ "Missing file:", fn ]++errWrongModule :: ModuleIdent -> ModuleIdent -> Message+errWrongModule m m' = message $ sep $+  [ text "Expected module for", text (moduleName m) <> comma+  , text "but found", text (moduleName m') ]++errCyclicImport :: [ModuleIdent] -> Message+errCyclicImport []  = internalError "CurryDeps.errCyclicImport: empty list"+errCyclicImport [m] = message $ sep $ map text+  [ "Recursive import for module", moduleName m ]+errCyclicImport ms  = message $ sep $+  text "Cyclic import dependency between modules" : punctuate comma inits+  ++ [text "and", lastm]+  where+  (inits, lastm)     = splitLast $ map (text . moduleName) ms+  splitLast []       = internalError "CurryDeps.splitLast: empty list"+  splitLast (x : []) = ([]    , x)+  splitLast (x : xs) = (x : ys, y) where (ys, y) = splitLast xs
− src/CurryDeps.lhs
@@ -1,144 +0,0 @@--% $Id: CurryDeps.lhs,v 1.14 2004/02/09 17:10:05 wlux Exp $-%-% Copyright (c) 2002-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-% Extended by Sebastian Fischer (sebf@informatik.uni-kiel.de)-\nwfilename{CurryDeps.lhs}-\section{Building Programs}-This module implements the functions to compute the dependency-information between Curry modules. This is used to create Makefile-dependencies and to update programs composed of multiple modules.-\begin{verbatim}--> module CurryDeps(Source(..),->                  deps, flattenDeps, sourceDeps, moduleDeps->                 ) where--> import Data.List-> import qualified Data.Map as Map-> import Data.Maybe-> import Control.Monad--> import Curry.Base.Ident-> import Curry.Base.MessageMonad--> import Curry.Files.Filenames-> import Curry.Files.PathUtils--> import Curry.Syntax hiding(Interface(..))--> import SCC---> data Source = Source FilePath [ModuleIdent]->             | Interface FilePath->             | Unknown->             deriving (Eq,Ord,Show)-> type SourceEnv = Map.Map ModuleIdent Source--> deps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath -> IO SourceEnv-> deps paths libraryPaths mEnv fn->   | e `elem` sourceExts = sourceDeps paths libraryPaths (mkMIdent [r]) mEnv fn->   | e == icurryExt = return Map.empty->   | e `elem` objectExts = targetDeps paths libraryPaths mEnv r->   | otherwise = targetDeps paths libraryPaths mEnv fn->   where r = dropExtension fn->         e = takeExtension fn--> targetDeps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath->            -> IO SourceEnv-> targetDeps paths libraryPaths mEnv fn =->   lookupFile [""] sourceExts fn >>=->   maybe (return (Map.insert m Unknown mEnv)) (sourceDeps paths libraryPaths m mEnv)->   where m = mkMIdent [fn]--\end{verbatim}-The following functions are used to lookup files related to a given-module. Source files for targets are looked up in the current-directory only. Two different search paths are used to look up-imported modules, the first is used to find source modules, whereas-the library path is used only for finding matching interface files. As-the compiler does not distinguish these paths, we actually check for-interface files in the source paths as well.--Note that the functions \texttt{buildScript} and \texttt{makeDepend}-already remove all directories that are included in the both search-paths from the library paths in order to avoid scanning such-directories more than twice.-\begin{verbatim}--\end{verbatim}-In order to compute the dependency graph, source files for each module-need to be looked up. When a source module is found, its header is-parsed in order to determine the modules that it imports, and-dependencies for these modules are computed recursively. The prelude-is added implicitly to the list of imported modules except for the-prelude itself. Any errors reported by the parser are ignored.-\begin{verbatim}--> moduleDeps :: [FilePath] -> [FilePath] -> SourceEnv -> ModuleIdent->            -> IO SourceEnv-> moduleDeps paths libraryPaths mEnv m =->   case Map.lookup m mEnv of->     Just _ -> return mEnv->     Nothing ->->       do->         mbFn <- lookupModule paths libraryPaths m->         case mbFn of->           Just fn->             | icurryExt `isSuffixOf` fn ->->                 return (Map.insert m (Interface fn) mEnv)->             | otherwise -> sourceDeps paths libraryPaths m mEnv fn->           Nothing -> return (Map.insert m Unknown mEnv)--> sourceDeps :: [FilePath] -> [FilePath] -> ModuleIdent -> SourceEnv->            -> FilePath -> IO SourceEnv-> sourceDeps paths libraryPaths m mEnv fn =->   do->     s <- readModule fn->     case fst $ runMsg $ parseHeader fn s of->       Right (Module m' _ ds) ->->         let ms = imports m' ds in->         foldM (moduleDeps paths libraryPaths) (Map.insert m (Source fn ms) mEnv) ms->       Left _ -> return (Map.insert m (Source fn []) mEnv)--> imports :: ModuleIdent -> [Decl] -> [ModuleIdent]-> imports m ds = nub $->   [preludeMIdent | m /= preludeMIdent] ++ [m | ImportDecl _ m _ _ _ <- ds]----If we want to compile the program instead of generating Makefile-dependencies the environment has to be sorted topologically. Note-that the dependency graph should not contain any cycles.--> flattenDeps :: SourceEnv -> ([(ModuleIdent,Source)],[String])-> flattenDeps = fdeps . sortDeps->     where->     sortDeps :: SourceEnv -> [[(ModuleIdent,Source)]]->     sortDeps = scc modules imports . Map.toList->->     modules (m, _) = [m]->->     imports (_,Source _ ms) = ms->     imports (_,Interface _) = []->     imports (_,Unknown) = []->->     fdeps :: [[(ModuleIdent,Source)]] -> ([(ModuleIdent,Source)],[String])->     fdeps = foldr checkdep ([], [])->     ->     checkdep [] (ms', es')  = (ms',es')->     checkdep [m] (ms', es') = (m:ms',es')->     checkdep dep (ms', es') = (ms',cyclicError (map fst dep) : es')->->     cyclicError :: [ModuleIdent] -> String->     cyclicError (m:ms) =->         "Cylic import dependency between modules " ++ show m ++ rest ms->->     rest [m] = " and " ++ show m->     rest ms  = rest' ms->     rest' [m] = ", and " ++ show m->     rest' (m:ms) = ", " ++ show m ++ rest' ms
− src/CurryEnv.hs
@@ -1,181 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- CurryEnv - Generates a record containing extracted and prepared data---            from a CurrySyntax module------ November 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module CurryEnv (CurryEnv(..), curryEnv) where--import Data.Maybe--import Curry.Base.Position-import Curry.Base.Ident--import Curry.Syntax--import Types-import Base------------------------------------------------------------------------------------- A record containing the following data for a module 'm':------    moduleId    - the name of 'm'---    exports     - the export list extracted from 'm'---    interface   - all exported declarations in 'm' (including exported ---                  imports)---    infixDecls  - interfaces of all infix declarations in 'm'---    typeSynonym - interfaces of all type synonyms in 'm'----data CurryEnv = CurryEnv{ moduleId     :: ModuleIdent,-			  exports      :: [Export],-			  imports      :: [IDecl],-			  interface    :: [IDecl],-			  infixDecls   :: [IDecl],-			  typeSynonyms :: [IDecl]-			} deriving Show-			  ------------------------------------------------------------------------------------- Returns a Curry environment for the module 'mod' and its corresponding--- environments 'mEnv' (imported modules), 'tcEnv' (table of type--- constructors) and 'intf' (the interface of 'mod')-curryEnv :: ModuleEnv -> TCEnv -> Interface -> Module -> CurryEnv-curryEnv mEnv tcEnv (Interface iid idecls) mod@(Module mid mExp decls)-   | iid == mid-     = CurryEnv{ moduleId     = mid,-		 exports      = maybe [] (\ (Exporting _ exps) -> exps) mExp,-		 imports      = genImportIntf decls,-		 interface    = idecls,-		 infixDecls   = genInfixDecls mod,-		 typeSynonyms = genTypeSyns tcEnv mod-	       }-   | otherwise-     = internalError ("CurryEnv: interface \"" ++ show iid -		      ++ "\" does not match module \"" ++ show mid ++ "\"")---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Generate interfaces for import declarations-genImportIntf :: [Decl] -> [IDecl]-genImportIntf decls = reverse (map snd (foldl genImpIntf [] decls))-----genImpIntf imps (ImportDecl pos mid _ _ _)-   = maybe ((mid, IImportDecl pos mid):imps) (const imps) (lookup mid imps)-genImpIntf imps _ = imps-------------------------------------------------------------------------------------- Generate interface declaration for all infix declarations in the module-genInfixDecls :: Module -> [IDecl]-genInfixDecls (Module mident _ decls) = collectIInfixDecls mident decls-----collectIInfixDecls :: ModuleIdent -> [Decl] -> [IDecl]-collectIInfixDecls mident [] = []-collectIInfixDecls mident ((InfixDecl pos infixspec prec idents):decls)-   = (map (\ident -	   -> IInfixDecl pos infixspec prec (qualifyWith mident ident)) -	   idents)-     ++ (collectIInfixDecls mident decls)-collectIInfixDecls mident (_:decls) = collectIInfixDecls mident decls-------------------------------------------------------------------------------------- Generate interface declarations for all type synonyms in the module.-genTypeSyns :: TCEnv -> Module -> [IDecl]-genTypeSyns tcEnv (Module mident _ decls)-   = concatMap (genTypeSynDecl mident tcEnv) (filter isTypeSyn decls)-----genTypeSynDecl :: ModuleIdent -> TCEnv -> Decl -> [IDecl]-genTypeSynDecl mid tcEnv (TypeDecl pos ident params texpr)-   = [genTypeDecl pos mid ident params tcEnv texpr]-genTypeSynDecl _ _ _ -   = []-----genTypeDecl :: Position -> ModuleIdent -> Ident -> [Ident] -> TCEnv-	    -> TypeExpr -> IDecl-genTypeDecl pos mid ident params tcEnv texpr-   = ITypeDecl pos (qualifyWith mid ident) params-               (modifyTypeExpr tcEnv texpr)------modifyTypeExpr :: TCEnv -> TypeExpr -> TypeExpr-modifyTypeExpr tcEnv (ConstructorType qident typeexprs)-   = case (qualLookupTC qident tcEnv) of-       [AliasType _ arity rhstype]-          -> modifyTypeExpr tcEnv -	                    (genTypeSynDeref (zip [0 .. (arity-1)] typeexprs)-			                     rhstype)-       _  -> ConstructorType (fromMaybe qident (lookupTCId qident tcEnv))-                             (map (modifyTypeExpr tcEnv) typeexprs)-modifyTypeExpr _ (VariableType ident)-   = VariableType ident-modifyTypeExpr tcEnv (ArrowType type1 type2)-   = ArrowType (modifyTypeExpr tcEnv type1) (modifyTypeExpr tcEnv type2)-modifyTypeExpr tcEnv (TupleType typeexprs)-   | null typeexprs -     = ConstructorType qUnitId []-   | otherwise-     = ConstructorType (qTupleId (length typeexprs)) -                       (map (modifyTypeExpr tcEnv) typeexprs)-modifyTypeExpr tcEnv (ListType typeexpr)-   = ConstructorType (qualify listId) [(modifyTypeExpr tcEnv typeexpr)]-modifyTypeExpr tcEnv (RecordType fields rtype)-   = RecordType (map (\ (labs, texpr) -> (labs, (modifyTypeExpr tcEnv texpr)))-		     fields)-                (maybe Nothing (Just . modifyTypeExpr tcEnv) rtype)-----genTypeSynDeref :: [(Int,TypeExpr)] -> Type -> TypeExpr-genTypeSynDeref its (TypeConstructor qident typeexprs)-   = ConstructorType qident (map (genTypeSynDeref its) typeexprs)-genTypeSynDeref its (TypeVariable i)-   = fromMaybe (internalError ("@CurryInfo.genTypeSynDeref: " ++-			       "unkown type var index"))-               (lookup i its)-genTypeSynDeref its (TypeConstrained typeexprs i)-   = internalError ("@CurryInfo.genTypeSynDeref: " ++-		    "illegal constrained type occured")-genTypeSynDeref its (TypeArrow type1 type2)-   = ArrowType (genTypeSynDeref its type1) (genTypeSynDeref its type2)-genTypeSynDeref its (TypeSkolem i)-   = internalError ("@CurryInfo.genTypeSynDeref: " ++-		    "illegal skolem type occured")-genTypeSynDeref its (TypeRecord fields ri)-   = RecordType (map (\ (lab, texpr) -> ([lab], genTypeSynDeref its texpr))-		     fields)-                (maybe Nothing -		       (\i -> Just (genTypeSynDeref its (TypeVariable i)))-		       ri)-----lookupTCId :: QualIdent -> TCEnv -> Maybe QualIdent-lookupTCId qident tcEnv-   = case (qualLookupTC qident tcEnv) of-       [DataType qident' _ _]     -> Just qident'-       [RenamingType qident' _ _] -> Just qident'-       [AliasType qident' _ _]    -> Just qident'-       _                          -> Nothing----isTypeSyn :: Decl -> Bool-isTypeSyn (TypeDecl _ _ _ texpr)-   = case texpr of-       RecordType _ _ -> False-       _              -> True-isTypeSyn _ = False
− src/CurryHtml.hs
@@ -1,190 +0,0 @@-module CurryHtml(source2html) where--import Data.Char hiding(Space)-import Control.Exception--import Curry.Base.Ident-import Curry.Base.MessageMonad--import Curry.Files.PathUtils (readModule, writeModule, getCurryPath)--import SyntaxColoring-import Curry.Syntax.Frontend as Frontend------- translate source file into HTML file with syntaxcoloring---- @param outputfilename---- @param sourcefilename-source2html :: [String] -> String -> String -> IO ()-source2html imports outputfilename sourcefilename = do-        let sourceprogname = removeExtension sourcefilename-            output = if null outputfilename -                     then sourceprogname ++ "_curry.html"-                     else outputfilename -            modulname = fileName sourceprogname-        fullfname <- getCurryPath imports sourcefilename-        program <- filename2program imports (maybe sourcefilename id fullfname)-        (if null outputfilename then writeModule True output -                                else writeFile   output)-           (program2html modulname program)-             ---- @param importpaths---- @param filename                  ---- @return program-filename2program :: [String] -> String -> IO Program-filename2program paths filename-    = do cont <- readModule filename-         typingParseResult <- (catchError (typingParse paths filename  cont))-         fullParseResult <- (catchError (fullParse paths filename  cont))-         parseResult <- (catchError (return (parse filename cont)))-         lexResult <- (catchError (return (Frontend.lex filename cont)))-         return (genProgram cont (typingParseResult : fullParseResult : [parseResult]) lexResult)------ this function intercepts errors and converts it to Messages      ---- @param a show-function for (Result a)                    ---- @param a function that generates a (Result a)---- @return (Result a) without runtimeerrors   ---- FIXME This is ugly. Avoid exceptions and report failure via MsgMonad instead! (hsi)-catchError :: Show a =>IO (MsgMonad a) -> IO (MsgMonad a)-catchError toDo = Control.Exception.catch (toDo >>= returnNF) handler -  where     -    -- This refers to base3-    handler (ErrorCall str) = return (failWith str)-    handler  e = return (failWith (show e))  -             -    returnNF a = normalform a `seq` return a-    normalform = length . show . runMsg-                -       ----- generates htmlcode with syntax highlighting            ---- @param modulname---- @param a program---- @return HTMLcode-program2html :: String ->Program -> String-program2html modulname codes =-    "<html>\n<head>\n<title>Module "++ -    modulname++-    "</title>\n" ++-    "<link rel=\"stylesheet\" type=\"text/css\" href=\"currydoc.css\">"++-    "</link>\n</head>\n<body style=\"font-family:'Courier New', Arial;\">\n<pre>\n" ++-    concat (map (code2html True . (\(_,_,c) -> c)) codes) ++-    "<pre>\n</body>\n</html>"            -            -            ---- which code has which color ---- @param code---- @return color of the code  -code2class :: Code -> String                          -code2class (Keyword _) = "keyword"-code2class (Space _)= ""-code2class NewLine = ""-code2class (ConstructorName ConstrPattern _) = "constructorname_constrpattern"-code2class (ConstructorName ConstrCall _) = "constructorname_constrcall"-code2class (ConstructorName ConstrDecla _) = "constructorname_constrdecla"-code2class (ConstructorName OtherConstrKind _) = "constructorname_otherconstrkind"-code2class (Function InfixFunction _) = "function_infixfunction"-code2class (Function TypSig _) = "function_typsig"-code2class (Function FunDecl _) = "function_fundecl"-code2class (Function FunctionCall _) = "function_functioncall"-code2class (Function OtherFunctionKind _) = "function_otherfunctionkind"-code2class (ModuleName _) = "modulename"-code2class (Commentary _) = "commentary"-code2class (NumberCode _) = "numbercode"-code2class (StringCode _) = "stringcode"-code2class (CharCode _) = "charcode"-code2class (Symbol _) = "symbol"-code2class (Identifier IdDecl _) = "identifier_iddecl"-code2class (Identifier IdOccur _) = "identifier_idoccur"-code2class (Identifier UnknownId _) = "identifier_unknownid"-code2class (TypeConstructor TypeDecla _) = "typeconstructor_typedecla"-code2class (TypeConstructor TypeUse _) = "typeconstructor_typeuse"-code2class (TypeConstructor TypeExport _) = "typeconstructor_typeexport"-code2class (CodeWarning _ _) = "codewarning"-code2class (NotParsed _) = "notparsed"---code2html :: Bool -> Code -> String    -code2html ownClass code@(CodeWarning _ c) =-     (if ownClass then spanTag (code2class code) else id)-              (code2html False c)       -code2html ownClass code@(Commentary _) =-    (if ownClass then spanTag (code2class code) else id)-      (replace '<' "<span>&lt</span>" (code2string code))                -code2html ownClass c-      | isCall c && ownClass = maybe tag (addHtmlLink tag) (getQualIdent c) -      | isDecl c && ownClass= maybe tag (addHtmlAnchor tag) (getQualIdent c)-      | otherwise = tag-    where tag = (if ownClass then spanTag (code2class c) else id)-                      (htmlQuote (code2string c)) -                                        -spanTag :: String -> String -> String-spanTag [] str = str-spanTag cl str = "<span class=\""++ cl ++ "\">" ++ str ++ "</span>"--replace :: Char -> String -> String -> String-replace old new = foldr (\ x -> if x == old then (new ++) else ([x]++)) ""--addHtmlAnchor :: String -> QualIdent -> String-addHtmlAnchor html qualIdent = "<a name=\""++ string2urlencoded (show (unqualify qualIdent)) ++"\"></a>" ++ html--addHtmlLink :: String -> QualIdent -> String-addHtmlLink html qualIdent =-   let (maybeModuleIdent,ident) = (qualidMod qualIdent, qualidId qualIdent) in-   "<a href=\"" ++ -   (maybe "" (\x -> show x ++ "_curry.html") maybeModuleIdent) ++ -   "#"++ -   string2urlencoded (show ident) ++-   "\">"++ -   html ++-   "</a>"--isCall :: Code -> Bool-isCall (TypeConstructor TypeExport _) = True-isCall (TypeConstructor _ _) = False-isCall (Identifier _ _) = False-isCall code = not (isDecl code) &&-                maybe False (const True) (getQualIdent code)--     -isDecl :: Code -> Bool-isDecl (ConstructorName ConstrDecla _) = True-isDecl (Function FunDecl _) = True-isDecl (TypeConstructor TypeDecla _) = True-isDecl _ = False ---fileName = reverse . takeWhile (/='/') . reverse --removeExtension = reverse . drop 1 . dropWhile (/='.') . reverse ------ Translates arbitrary strings into equivalent urlencoded string.-string2urlencoded :: String -> String-string2urlencoded = id-{--string2urlencoded [] = []-string2urlencoded (c:cs)-  | isAlphaNum c = c : string2urlencoded cs-  | c == ' '     = '+' : string2urlencoded cs-  | otherwise = show (ord c) ++ (if null cs then "" else ".") ++ string2urlencoded cs--}--htmlQuote :: String -> String-htmlQuote [] = []-htmlQuote (c:cs) | c=='<' = "&lt;"   ++ htmlQuote cs-                 | c=='>' = "&gt;"   ++ htmlQuote cs-                 | c=='&' = "&amp;"  ++ htmlQuote cs-                 | c=='"' = "&quot;" ++ htmlQuote cs-                 | c=='\228' = "&auml;" ++ htmlQuote cs-                 | c=='\246' = "&ouml;" ++ htmlQuote cs-                 | c=='\252' = "&uuml;" ++ htmlQuote cs-                 | c=='\196' = "&Auml;" ++ htmlQuote cs-                 | c=='\214' = "&Ouml;" ++ htmlQuote cs-                 | c=='\220' = "&Uuml;" ++ htmlQuote cs-                 | c=='\223' = "&szlig;"++ htmlQuote cs-                 | otherwise = c : htmlQuote cs-  
− src/Desugar.lhs
@@ -1,843 +0,0 @@-% $Id: Desugar.lhs,v 1.42 2004/02/15 22:10:32 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Desugar.lhs}-\section{Desugaring Curry Expressions}-The desugaring pass removes all syntactic sugar from the module. In-particular, the output of the desugarer will have the following-properties.-\begin{itemize}-\item All function definitions are $\eta$-expanded.\\-  {\em Note:} Since this version is used as a frontend for PAKCS, the -  $\eta$-expansion had been disabled.-\item No guarded right hand sides occur in equations, pattern-  declarations, and case alternatives. In addition, the declaration-  lists of the right hand sides are empty; local declarations are-  transformed into let expressions.-\item Patterns in equations and case alternatives are composed only of-  \begin{itemize}-  \item literals,-  \item variables,-  \item constructor applications, and-  \item as patterns.-  \end{itemize}-\item Expressions are composed only of-  \begin{itemize}-  \item literals,-  \item variables,-  \item constructors,-  \item (binary) applications,-  \item let expressions, and-  \item case expressions.-  \end{itemize}-\item Applications $N\:x$ in patterns and expressions, where $N$ is a-  newtype constructor, are replaced by a $x$. Note that neither the-  newtype declaration itself nor partial applications of newtype-  constructors are changed.\footnote{It were possible to replace-  partial applications of newtype constructor by \texttt{prelude.id}.-  However, our solution yields a more accurate output when the result-  of a computation includes partial applications.}-\item Function patterns are replaced by variables and are integrated-  in a guarded right hand side using the \texttt{=:<=} operator-\item Records, which currently must be declared using the keyword-  \texttt{type}, are transformed into data types with one constructor.-  Record construction and pattern matching are represented using the-  record constructor. Selection and update are represented using selector-  and update functions which are generated for each record declaration.-  The record constructor must be entered into the type environment as well-  as the selector functions and the update functions. -\end{itemize}--\ToDo{Use a different representation for the restricted code instead-of using the syntax tree from \texttt{CurrySyntax}.}--\textbf{As we are going to insert references to real prelude entities,-all names must be properly qualified before calling this module.}-\begin{verbatim}--> module Desugar(desugar) where--> import Data.Maybe-> import Control.Arrow(second)-> import Control.Monad.State as S-> import Data.List--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax.Utils-> import Curry.Syntax--> import Types-> import Base-> import Typing-> import Utils----posE = undefined--\end{verbatim}-New identifiers may be introduced while desugaring pattern-declarations, case and $\lambda$-expressions, and list comprehensions.-As usual, we use a state monad transformer for generating unique-names. In addition, the state is also used for passing through the-type environment, which must be augmented with the types of these new-variables.-\begin{verbatim}--> type DesugarState a = S.StateT ValueEnv (S.State Int) a--> run :: DesugarState a -> ValueEnv -> a-> run m tyEnv = S.evalState (S.evalStateT m tyEnv) 1--\end{verbatim}-The desugaring phase keeps only the type, function, and value-declarations of the module. In the current version record declarations-are transformed into data types. The remaining type declarations are-not desugared and cannot occur in local declaration groups.-They are filtered out separately.--In order to use records within other modules, the export specification-of the module has to be extended with the selector and update functions of-all exported labels.--Actually, the transformation is slightly more general than necessary-as it allows value declarations at the top-level of a module.-\begin{verbatim}--> desugar :: ValueEnv -> TCEnv -> Module -> (Module,ValueEnv)-> desugar tyEnv tcEnv (Module m es ds) = (Module m es ds',tyEnv')->   where (ds',tyEnv') = run (desugarModule m tcEnv ds) tyEnv--> desugarModule :: ModuleIdent -> TCEnv -> [Decl] ->	        -> DesugarState ([Decl],ValueEnv)-> desugarModule m tcEnv ds = ->   do->     dss <- mapM (desugarRecordDecl m tcEnv) ds->     let ds' = concat dss->     ds'' <- desugarDeclGroup m tcEnv ds'->     tyEnv' <- S.get->     return (filter isTypeDecl ds' ++ ds'', tyEnv')--\end{verbatim}---Within a declaration group, all type signatures and evaluation-annotations are discarded. First, the patterns occurring in the left-hand sides are desugared. Due to lazy patterns this may add further-declarations to the group that must be desugared as well.-\begin{verbatim}--> desugarDeclGroup :: ModuleIdent -> TCEnv -> [Decl] -> DesugarState [Decl]-> desugarDeclGroup m tcEnv ds =->   do->     dss' <- mapM (desugarDeclLhs m tcEnv) (filter isValueDecl ds)->     mapM (desugarDeclRhs m tcEnv) (concat dss')--> desugarDeclLhs :: ModuleIdent -> TCEnv -> Decl -> DesugarState [Decl]-> desugarDeclLhs m tcEnv (PatternDecl p t rhs) =->   do->     (ds',t') <- desugarTerm m tcEnv p [] t->     dss' <- mapM (desugarDeclLhs m tcEnv) ds'->     return (PatternDecl p t' rhs : concat dss')-> desugarDeclLhs m tcEnv (FlatExternalDecl p fs) =->   do->     tyEnv <- S.get->     return (map (externalDecl tyEnv p) fs)->   where externalDecl tyEnv p f =->           ExternalDecl p CallConvPrimitive (Just (name f)) f->                        (fromType (typeOf tyEnv (Variable (qual f))))->         qual f->           | unRenameIdent f == f = qualifyWith m f->           | otherwise = qualify f-> desugarDeclLhs _ _ d = return [d]--\end{verbatim}-After desugaring its right hand side, each equation is $\eta$-expanded-by adding as many variables as necessary to the argument list and-applying the right hand side to those variables ({\em Note:} $\eta$-expansion-is disabled in the version for PAKCS).-Furthermore every occurrence of a record type within the type of a function-is simplified to the corresponding type constructor from the record-declaration. This is possible because currently records must not be empty-and a record label belongs to only one record declaration.-\begin{verbatim}--> desugarDeclRhs :: ModuleIdent -> TCEnv -> Decl -> DesugarState Decl-> desugarDeclRhs m tcEnv (FunctionDecl p f eqs) =->   do->     tyEnv <- S.get->     let ty =  (flip typeOf (Variable (qual f))) tyEnv->     liftM (FunctionDecl p f) ->	    (mapM (desugarEquation m tcEnv (arrowArgs ty)) eqs)->   where qual f->           | unRenameIdent f == f = qualifyWith m f->           | otherwise = qualify f-> desugarDeclRhs _ tcEnv (ExternalDecl p cc ie f ty) =->   return (ExternalDecl p cc (ie `mplus` Just (name f)) f ty)-> desugarDeclRhs m tcEnv (PatternDecl p t rhs) =->   liftM (PatternDecl p t) (desugarRhs m tcEnv p rhs)-> desugarDeclRhs _ tcEnv (ExtraVariables p vs) = return (ExtraVariables p vs)--> desugarEquation :: ModuleIdent -> TCEnv -> [Type] -> Equation ->	          -> DesugarState Equation-> desugarEquation m tcEnv tys (Equation p lhs rhs) =->   do->     (ds',ts') <- mapAccumM (desugarTerm m tcEnv p) [] ts->     rhs' <- desugarRhs m tcEnv p (addDecls ds' rhs)->     (ts'', rhs'') <- desugarFunctionPatterns m p ts' rhs'->     return (Equation p (FunLhs f ts'') rhs'')->   where (f,ts) = flatLhs lhs---\end{verbatim}-The transformation of patterns is straight forward except for lazy-patterns. A lazy pattern \texttt{\~}$t$ is replaced by a fresh-variable $v$ and a new local declaration $t$~\texttt{=}~$v$ in the-scope of the pattern. In addition, as-patterns $v$\texttt{@}$t$ where-$t$ is a variable or an as-pattern are replaced by $t$ in combination-with a local declaration for $v$.-\begin{verbatim}--> desugarLiteral :: Literal -> DesugarState (Either Literal ([SrcRef],[Literal]))-> desugarLiteral (Char p c) = return (Left (Char p c))-> desugarLiteral (Int v i)  = liftM (Left . fixType) S.get->   where ->    fixType tyEnv->      | typeOf tyEnv v == floatType ->          = Float (srcRefOf $ positionOfIdent v) (fromIntegral i)->      | otherwise = Int v i-> desugarLiteral (Float p f) = return (Left (Float p f))-> desugarLiteral (String (SrcRef [i]) cs) ->   = return (Right (consRefs i cs,zipWith (Char . SrcRef . (:[])) [i,i+2..] cs))->   where consRefs r []     = [SrcRef [r]]->         consRefs r (_:xs) = let r'=r+2 in r' `seq` (SrcRef [r']:consRefs r' xs)-> desugarLiteral (String is _) = error $ "internal error desugarLiteral; "++->                                        "wrong source ref for string: "  ++ show is--> desugarList :: [SrcRef] -> (SrcRef -> b -> b -> b) -> (SrcRef -> b) -> [b] -> b-> desugarList pos cons nil xs = snd (foldr cons' nil' xs)->   where rNil:rCs = reverse pos ->         nil'                = (rCs,nil rNil)->         cons' t (rC:rCs,ts) = (rCs,cons rC t ts)--> desugarTerm :: ModuleIdent -> TCEnv -> Position -> [Decl] -> ConstrTerm->             -> DesugarState ([Decl],ConstrTerm)-> desugarTerm m tcEnv p ds (LiteralPattern l) =->   desugarLiteral l >>=->   either (return . (,) ds . LiteralPattern)->          (\ (pos,ls) -> desugarTerm m tcEnv p ds $ ListPattern pos $ map LiteralPattern ls)-> desugarTerm m tcEnv p ds (NegativePattern _ l) =->   desugarTerm m tcEnv p ds (LiteralPattern (negateLiteral l))->   where negateLiteral (Int v i) = Int v (-i)->         negateLiteral (Float p f) = Float p (-f)->         negateLiteral _ = internalError "negateLiteral"-> desugarTerm _ _ _ ds (VariablePattern v) = return (ds,VariablePattern v)-> desugarTerm m tcEnv p ds (ConstructorPattern c [t]) =->   do->     tyEnv <- S.get->     liftM (if isNewtypeConstr tyEnv c then id else second (constrPat c))->           (desugarTerm m tcEnv p ds t)->   where constrPat c t = ConstructorPattern c [t]-> desugarTerm m tcEnv p ds (ConstructorPattern c ts) =->   liftM (second (ConstructorPattern c)) (mapAccumM (desugarTerm m tcEnv p) ds ts)-> desugarTerm m tcEnv p ds (InfixPattern t1 op t2) =->   desugarTerm m tcEnv p ds (ConstructorPattern op [t1,t2])-> desugarTerm m tcEnv p ds (ParenPattern t) = desugarTerm m tcEnv p ds t-> desugarTerm m tcEnv p ds (TuplePattern pos ts) =->   desugarTerm m tcEnv p ds (ConstructorPattern (tupleConstr ts) ts)->   where tupleConstr ts = addRef pos $ ->                          if null ts then qUnitId else qTupleId (length ts)-> desugarTerm m tcEnv p ds (ListPattern pos ts) =->   liftM (second (desugarList pos cons nil)) (mapAccumM (desugarTerm m tcEnv p) ds ts)->   where nil  p' = ConstructorPattern (addRef p' qNilId) []->         cons p' t ts = ConstructorPattern (addRef p' qConsId) [t,ts]--> desugarTerm m tcEnv p ds (AsPattern v t) =->   liftM (desugarAs p v) (desugarTerm m tcEnv p ds t)-> desugarTerm m tcEnv p ds (LazyPattern pos t) = desugarLazy pos m p ds t-> desugarTerm m tcEnv p ds (FunctionPattern f ts) =->   liftM (second (FunctionPattern f)) (mapAccumM (desugarTerm m tcEnv p) ds ts)-> desugarTerm m tcEnv p ds (InfixFuncPattern t1 f t2) =->   desugarTerm m tcEnv p ds (FunctionPattern f [t1,t2])-> desugarTerm m tcEnv p ds (RecordPattern fs _)->   | null fs = internalError "desugarTerm: empty record"->   | otherwise =->     do tyEnv <- S.get ->	 case (lookupValue (fieldLabel (head fs)) tyEnv) of->          [Label _ r _] -> ->            desugarRecordPattern m tcEnv p ds (map field2Tuple fs) r->          _ -> internalError "desugarTerm: no label"--> desugarAs :: Position -> Ident -> ([Decl],ConstrTerm) -> ([Decl],ConstrTerm)-> desugarAs p v (ds,t) =->  case t of->    VariablePattern v' -> (varDecl p v (mkVar v') : ds,t)->    AsPattern v' _ -> (varDecl p v (mkVar v') : ds,t)->    _ -> (ds,AsPattern v t)--> desugarLazy :: SrcRef -> ModuleIdent -> Position -> [Decl] -> ConstrTerm->             -> DesugarState ([Decl],ConstrTerm)-> desugarLazy pos m p ds t =->   case t of->     VariablePattern _ -> return (ds,t)->     ParenPattern t' -> desugarLazy pos m p ds t'->     AsPattern v t' -> liftM (desugarAs p v) (desugarLazy pos m p ds t')->     LazyPattern pos t' -> desugarLazy pos m p ds t'->     _ ->->       do->         v0 <- S.get >>= freshIdent m "_#lazy" . monoType . flip typeOf t->         let v' = addPositionIdent (AST pos) v0->         return (patDecl p{astRef=pos} t (mkVar v') : ds,VariablePattern v')---\end{verbatim}-A list of boolean guards is expanded into a nested if-then-else-expression, whereas a constraint guard is replaced by a case-expression. Note that if the guard type is \texttt{Success} only a-single guard is allowed for each equation.\footnote{This change was-introduced in version 0.8 of the Curry report.} We check for the-type \texttt{Bool} of the guard because the guard's type defaults to-\texttt{Success} if it is not restricted by the guard expression.-\begin{verbatim}--> desugarRhs :: ModuleIdent -> TCEnv -> Position -> Rhs -> DesugarState Rhs-> desugarRhs m tcEnv p rhs =->   do->     tyEnv <- S.get->     e' <- desugarExpr m tcEnv p (expandRhs tyEnv prelFailed rhs)->     return (SimpleRhs p e' [])--> expandRhs :: ValueEnv -> Expression -> Rhs -> Expression-> expandRhs tyEnv _ (SimpleRhs _ e ds) = Let ds e-> expandRhs tyEnv e0 (GuardedRhs es ds) = Let ds (expandGuards tyEnv e0 es)--> expandGuards :: ValueEnv -> Expression -> [CondExpr] -> Expression-> expandGuards tyEnv e0 es->   | booleanGuards tyEnv es = foldr mkIfThenElse e0 es->   | otherwise = mkCond es->   where mkIfThenElse (CondExpr p g e) = IfThenElse (srcRefOf p) g e->         mkCond [CondExpr p g e] = Apply (Apply prelCond g) e--> booleanGuards :: ValueEnv -> [CondExpr] -> Bool-> booleanGuards _ [] = False-> booleanGuards tyEnv (CondExpr _ g _ : es) =->   not (null es) || typeOf tyEnv g == boolType--> desugarExpr :: ModuleIdent -> TCEnv -> Position -> Expression->             -> DesugarState Expression-> desugarExpr m tcEnv p (Literal l) =->   desugarLiteral l >>=->   either (return . Literal) (\ (pos,ls) -> desugarExpr m tcEnv p $ List pos $ map Literal ls)-> desugarExpr _ _ _ (Variable v) = return (Variable v)-> desugarExpr _ _ _ (Constructor c) = return (Constructor c)-> desugarExpr m tcEnv p (Paren e) = desugarExpr m tcEnv p e-> desugarExpr m tcEnv p (Typed e _) = desugarExpr m tcEnv p e-> desugarExpr m tcEnv p (Tuple pos es) =->   liftM (apply (Constructor (tupleConstr es))) ->         (mapM (desugarExpr m tcEnv p) es)->   where tupleConstr es = addRef pos $ if null es then qUnitId else qTupleId (length es)-> desugarExpr m tcEnv p (List pos es) =->   liftM (desugarList pos cons nil) (mapM (desugarExpr m tcEnv p) es)->   where nil p'  = Constructor (addRef p' qNilId)->         cons p' = Apply . Apply (Constructor $ addRef p' qConsId)-> desugarExpr m tcEnv p (ListCompr pos e []) = desugarExpr m tcEnv p (List [pos,pos] [e])-> desugarExpr m tcEnv p (ListCompr r e (q:qs)) = ->   desugarQual m tcEnv p q (ListCompr r e qs)-> desugarExpr m tcEnv p (EnumFrom e) = ->   liftM (Apply prelEnumFrom) (desugarExpr m tcEnv p e)-> desugarExpr m tcEnv p (EnumFromThen e1 e2) =->   liftM (apply prelEnumFromThen) (mapM (desugarExpr m tcEnv p) [e1,e2])-> desugarExpr m tcEnv p (EnumFromTo e1 e2) =->   liftM (apply prelEnumFromTo) (mapM (desugarExpr m tcEnv p) [e1,e2])-> desugarExpr m tcEnv p (EnumFromThenTo e1 e2 e3) =->   liftM (apply prelEnumFromThenTo) (mapM (desugarExpr m tcEnv p) [e1,e2,e3])-> desugarExpr m tcEnv p (UnaryMinus op e) =->   do->     tyEnv <- S.get->     liftM (Apply (unaryMinus op (typeOf tyEnv e))) (desugarExpr m tcEnv p e)->   where unaryMinus op ty->           | op == minusId =->               if ty == floatType then prelNegateFloat else prelNegate->           | op == fminusId = prelNegateFloat->           | otherwise = internalError "unaryMinus"-> desugarExpr m tcEnv p (Apply (Constructor c) e) =->   do->     tyEnv <- S.get->     liftM (if isNewtypeConstr tyEnv c then id else (Apply (Constructor c)))->           (desugarExpr m tcEnv p e)-> desugarExpr m tcEnv p (Apply e1 e2) =->   do->     e1' <- desugarExpr m tcEnv p e1->     e2' <- desugarExpr m tcEnv p e2->     return (Apply e1' e2')-> desugarExpr m tcEnv p (InfixApply e1 op e2) =->   do->     op' <- desugarExpr m tcEnv p (infixOp op)->     e1' <- desugarExpr m tcEnv p e1->     e2' <- desugarExpr m tcEnv p e2->     return (Apply (Apply op' e1') e2')-> desugarExpr m tcEnv p (LeftSection e op) =->   do->     op' <- desugarExpr m tcEnv p (infixOp op)->     e' <- desugarExpr m tcEnv p e->     return (Apply op' e')-> desugarExpr m tcEnv p (RightSection op e) =->   do->     op' <- desugarExpr m tcEnv p (infixOp op)->     e' <- desugarExpr m tcEnv p e->     return (Apply (Apply prelFlip op') e')-> desugarExpr m tcEnv p exp@(Lambda r ts e) =->   do->     f <- S.get >>=->          freshIdent m "_#lambda" . polyType . flip typeOf exp->     desugarExpr m tcEnv p (Let [funDecl (AST r) f ts e] (mkVar f))-> desugarExpr m tcEnv p (Let ds e) =->   do->     ds' <- desugarDeclGroup m tcEnv ds->     e' <- desugarExpr m tcEnv p e->     return (if null ds' then e' else Let ds' e')-> desugarExpr m tcEnv p (Do sts e) = ->   desugarExpr m tcEnv p (foldr desugarStmt e sts)->   where desugarStmt (StmtExpr r e) e' = apply (prelBind_ r) [e,e']->         desugarStmt (StmtBind r t e) e' = apply (prelBind r) [e,Lambda r [t] e']->         desugarStmt (StmtDecl ds) e' = Let ds e'-> desugarExpr m tcEnv p (IfThenElse r e1 e2 e3) =->   do->     e1' <- desugarExpr m tcEnv p e1->     e2' <- desugarExpr m tcEnv p e2->     e3' <- desugarExpr m tcEnv p e3->     return (Case r e1' [caseAlt p truePattern e2',caseAlt p falsePattern e3'])-> desugarExpr m tcEnv p (Case r e alts)->   | null alts = return prelFailed->   | otherwise =->       do->         e' <- desugarExpr m tcEnv p e->         v <- S.get >>= freshIdent m "_#case" . monoType . flip typeOf e->         alts' <- mapM (desugarAltLhs m tcEnv) alts->         tyEnv <- S.get->         alts'' <- mapM (desugarAltRhs m tcEnv)->                        (map (expandAlt tyEnv v) (init (tails alts')))->         return (mkCase m v e' alts'')->   where mkCase m v e alts->           | v `elem` qfv m alts = Let [varDecl p v e] (Case r (mkVar v) alts)->           | otherwise = Case r e alts-> desugarExpr m tcEnv p (RecordConstr fs)->   | null fs = internalError "desugarExpr: empty record construction"->   | otherwise =->       do let l = fieldLabel (head fs)->	       fs' = map field2Tuple fs->          tyEnv <- S.get->	   case (lookupValue l tyEnv) of->            [Label l' r _] -> desugarRecordConstr m tcEnv p r fs'->            _  -> internalError "desugarExpr: illegal record construction"-> desugarExpr m tcEnv p (RecordSelection e l) =->   do tyEnv <- S.get->      case (lookupValue l tyEnv) of->        [Label _ r _] -> desugarRecordSelection m tcEnv p r l e->        _ -> internalError "desugarExpr: illegal record selection"-> desugarExpr m tcEnv p (RecordUpdate fs rexpr)->   | null fs = internalError "desugarExpr: empty record update"->   | otherwise =->       do let l = fieldLabel (head fs)->	       fs' = map field2Tuple fs->          tyEnv <- S.get->	   case (lookupValue l tyEnv) of->            [Label _ r _] -> desugarRecordUpdate m tcEnv p r rexpr fs'->            _  -> internalError "desugarExpr: illegal record update"--desugarExpr _ _ _ x = internalError $ "desugarExpr: unexpected expression " ++ show x--\end{verbatim}-If an alternative in a case expression has boolean guards and all of-these guards return \texttt{False}, the enclosing case expression does-not fail but continues to match the remaining alternatives against the-selector expression. In order to implement this semantics, which is-compatible with Haskell, we expand an alternative with boolean guards-such that it evaluates a case expression with the remaining cases that-are compatible with the matched pattern when the guards fail.-\begin{verbatim}--> desugarAltLhs :: ModuleIdent -> TCEnv -> Alt -> DesugarState Alt-> desugarAltLhs m tcEnv (Alt p t rhs) =->   do->     (ds',t') <- desugarTerm m tcEnv p [] t->     return (Alt p t' (addDecls ds' rhs))--> desugarAltRhs :: ModuleIdent -> TCEnv -> Alt -> DesugarState Alt-> desugarAltRhs m tcEnv (Alt p t rhs) = ->   liftM (Alt p t) (desugarRhs m tcEnv p rhs)--> expandAlt :: ValueEnv -> Ident -> [Alt] -> Alt-> expandAlt tyEnv v (Alt p t rhs : alts) = caseAlt p t (expandRhs tyEnv e0 rhs)->   where e0 = Case (srcRefOf p) (mkVar v) ->                   (filter (isCompatible t . altPattern) alts)->         altPattern (Alt _ t _) = t--> isCompatible :: ConstrTerm -> ConstrTerm -> Bool-> isCompatible (VariablePattern _) _ = True-> isCompatible _ (VariablePattern _) = True-> isCompatible (AsPattern _ t1) t2 = isCompatible t1 t2-> isCompatible t1 (AsPattern _ t2) = isCompatible t1 t2-> isCompatible (ConstructorPattern c1 ts1) (ConstructorPattern c2 ts2) =->   and ((c1 == c2) : zipWith isCompatible ts1 ts2)-> isCompatible (LiteralPattern l1) (LiteralPattern l2) = canon l1 == canon l2->   where canon (Int _ i) = Int anonId i->         canon l = l--\end{verbatim}-The frontend provides several extensions of the Curry functionality, which-have to be desugared as well. This part transforms the following extensions:-\begin{itemize}-\item runction patterns-\item records-\end{itemize}-\begin{verbatim}--> desugarFunctionPatterns :: ModuleIdent -> Position -> [ConstrTerm] -> Rhs->	                     -> DesugarState ([ConstrTerm], Rhs)-> desugarFunctionPatterns m p ts rhs = ->   do (ts', its) <- elimFunctionPattern m p ts->      rhs' <- genFunctionPatternExpr m p its rhs->      return (ts', rhs')--> desugarRecordDecl :: ModuleIdent -> TCEnv -> Decl -> DesugarState [Decl]-> desugarRecordDecl m tcEnv (TypeDecl p r vs (RecordType fss _)) =->   case (qualLookupTC r' tcEnv) of->     [AliasType _ n (TypeRecord fs' _)] ->->       do tyEnv <- S.get->	   let tys = concatMap (\ (ls,ty) -> replicate (length ls) ty) fss->	       --tys' = map (elimRecordTypes tyEnv) tys->	       rdecl = DataDecl p r vs [ConstrDecl p [] r tys]->	       rty' = TypeConstructor r' (map TypeVariable [0 .. n-1])->              rcts' = ForAllExist 0 n (foldr TypeArrow rty' (map snd fs'))->	   rfuncs <- mapM (genRecordFuncs m tcEnv p r' rty' (map fst fs')) fs'->	   S.modify (bindGlobalInfo DataConstructor m r rcts')->          return (rdecl:(concat rfuncs))->     _ -> internalError "desugarRecordDecl: no record"->   where r' = qualifyWith m r-> desugarRecordDecl _ _ decl = return [decl]--> desugarRecordPattern :: ModuleIdent -> TCEnv -> Position -> [Decl]->		       -> [(Ident,ConstrTerm)] -> QualIdent->		       -> DesugarState ([Decl],ConstrTerm)-> desugarRecordPattern m tcEnv p ds fs r =->   case (qualLookupTC r tcEnv) of->     [AliasType _ _ (TypeRecord fs' _)] ->->       do let ts = map (\ (l,_) ->		         -> fromMaybe (VariablePattern anonId)->		                      (lookup l fs))->		        fs'->	   desugarTerm m tcEnv p ds (ConstructorPattern r ts)--> desugarRecordConstr :: ModuleIdent -> TCEnv -> Position -> QualIdent ->	              -> [(Ident,Expression)] -> DesugarState Expression-> desugarRecordConstr m tcEnv p r fs =->   case (qualLookupTC r tcEnv) of->     [AliasType _ _ (TypeRecord fs' _)] ->->       do let cts = map (\ (l,_) -> ->	                  fromMaybe (internalError "desugarRecordConstr")->		                    (lookup l fs)) fs'->	   desugarExpr m tcEnv p (foldl Apply (Constructor r) cts)->     _ -> internalError "desugarRecordConstr: wrong type"--> desugarRecordSelection :: ModuleIdent -> TCEnv -> Position -> QualIdent ->		         -> Ident -> Expression -> DesugarState Expression-> desugarRecordSelection m tcEnv p r l e =->   desugarExpr m tcEnv p (Apply (Variable (qualRecSelectorId m r l)) e)--> desugarRecordUpdate :: ModuleIdent -> TCEnv -> Position -> QualIdent->	              -> Expression -> [(Ident,Expression)] ->	              -> DesugarState Expression-> desugarRecordUpdate m tcEnv p r rexpr fs =->   desugarExpr m tcEnv p (foldl (genRecordUpdate m r) rexpr fs)->   where->   genRecordUpdate m r rexpr (l,e) =->     Apply (Apply (Variable (qualRecUpdateId m r l)) rexpr) e--> elimFunctionPattern :: ModuleIdent -> Position -> [ConstrTerm]->		         -> DesugarState ([ConstrTerm], [(Ident,ConstrTerm)])-> elimFunctionPattern m p [] = return ([],[])-> elimFunctionPattern m p (t:ts)->    | containsFunctionPattern t->      = do tyEnv <- S.get->	    ident <- freshIdent m "_#funpatt" (monoType (typeOf tyEnv t))->	    (ts',its') <- elimFunctionPattern m p ts->           return ((VariablePattern ident):ts', (ident,t):its')->    | otherwise->      = do (ts', its') <- elimFunctionPattern m p ts->	    return (t:ts', its')--> containsFunctionPattern :: ConstrTerm -> Bool-> containsFunctionPattern (ConstructorPattern _ ts)->    = any containsFunctionPattern ts-> containsFunctionPattern (InfixPattern t1 _ t2)->    = any containsFunctionPattern [t1,t2]-> containsFunctionPattern (ParenPattern t)->    = containsFunctionPattern t-> containsFunctionPattern (TuplePattern _ ts)->    = any containsFunctionPattern ts-> containsFunctionPattern (ListPattern _ ts)->    = any containsFunctionPattern ts-> containsFunctionPattern (AsPattern _ t)->    = containsFunctionPattern t-> containsFunctionPattern (LazyPattern _ t)->    = containsFunctionPattern t-> containsFunctionPattern (FunctionPattern _ _) = True-> containsFunctionPattern (InfixFuncPattern _ _ _) = True-> containsFunctionPattern _ = False--> genFunctionPatternExpr :: ModuleIdent -> Position -> [(Ident, ConstrTerm)]->		            -> Rhs -> DesugarState Rhs-> genFunctionPatternExpr m _ its rhs@(SimpleRhs p expr decls)->    | null its = return rhs->    | otherwise->      = let ies = map (\ (i,t) -> (i, constrTerm2Expr t)) its->	     fpexprs = map (\ (ident, expr) ->		            -> Apply (Apply prelFuncPattEqu expr) ->		                     (Variable (qualify ident)))->	                   ies->	     fpexpr =  foldl (\e1 e2 -> Apply (Apply prelConstrConj e1) e2)->	                     (head fpexprs) ->		             (tail fpexprs)->	     freevars = foldl getConstrTermVars [] (map snd its)->            rhsexpr = Let [ExtraVariables p freevars]->		           (Apply (Apply prelCond fpexpr) expr)->        in  return (SimpleRhs p rhsexpr decls)  -> genFunctionPatternExpr _ _ _ rhs->    = internalError "genFunctionPatternExpr: unexpected right-hand-side"--> constrTerm2Expr :: ConstrTerm -> Expression-> constrTerm2Expr (LiteralPattern lit)->    = Literal lit-> constrTerm2Expr (VariablePattern ident)->    = Variable (qualify ident)-> constrTerm2Expr (ConstructorPattern qident cts)->    = foldl (\e1 e2 -> Apply e1 e2) ->            (Constructor qident) ->            (map constrTerm2Expr cts)-> constrTerm2Expr (FunctionPattern qident cts)->    = foldl (\e1 e2 -> Apply e1 e2) ->            (Variable qident) ->            (map constrTerm2Expr cts)-> constrTerm2Expr _->    = internalError "constrTerm2Expr: unexpected constructor term"--> getConstrTermVars :: [Ident] -> ConstrTerm -> [Ident]-> getConstrTermVars ids (VariablePattern ident)->    | elem ident ids = ids->    | otherwise      = ident:ids-> getConstrTermVars ids (ConstructorPattern _ cts)->    = foldl getConstrTermVars ids cts-> getConstrTermVars ids (InfixPattern c1 qid c2)->    = getConstrTermVars ids (ConstructorPattern qid [c1,c2])-> getConstrTermVars ids (ParenPattern c)->    = getConstrTermVars ids c-> getConstrTermVars ids (TuplePattern _ cts)->    = foldl getConstrTermVars ids cts-> getConstrTermVars ids (ListPattern _ cts)->    = foldl getConstrTermVars ids cts-> getConstrTermVars ids (AsPattern _ c)->    = getConstrTermVars ids c-> getConstrTermVars ids (LazyPattern _ c)->    = getConstrTermVars ids c-> getConstrTermVars ids (FunctionPattern _ cts)->    = foldl getConstrTermVars ids cts-> getConstrTermVars ids (InfixFuncPattern c1 qid c2)->    = getConstrTermVars ids (FunctionPattern qid [c1,c2])-> getConstrTermVars ids _->    = ids--> genRecordFuncs :: ModuleIdent -> TCEnv -> Position -> QualIdent -> Type ->	         -> [Ident] -> (Ident, Type) -> DesugarState [Decl]-> genRecordFuncs m tcEnv p r rty ls (l,ty) =->   case (qualLookupTC r tcEnv) of->     [AliasType _ n (TypeRecord fs _)] ->->       do let (selId, selFunc) = genSelectorFunc m p r ls l->              (updId, updFunc) = genUpdateFunc m p r ls l->	       selType = polyType (TypeArrow rty ty)->	       updType = polyType (TypeArrow rty (TypeArrow ty rty))->	   S.modify (bindFun m selId selType . bindFun m updId updType)->	   return [selFunc,updFunc]->     _ -> internalError "genRecordFuncs: wrong type"--> genSelectorFunc :: ModuleIdent -> Position -> QualIdent -> [Ident] -> Ident->	          -> (Ident, Decl)-> genSelectorFunc m p r ls l =->   let selId = recSelectorId r l->       cpatt = ConstructorPattern r (map VariablePattern ls)->	selLhs = FunLhs selId [cpatt]->	selRhs = SimpleRhs p (Variable (qualify l)) []->   in  (selId, FunctionDecl p selId [Equation p selLhs selRhs])--> genUpdateFunc :: ModuleIdent -> Position -> QualIdent -> [Ident] -> Ident->	        -> (Ident, Decl)-> genUpdateFunc m p r ls l =->   let updId = recUpdateId r l->	ls' = replaceIdent l anonId ls->	cpatt1 = ConstructorPattern r (map VariablePattern ls')->       cpatt2 = VariablePattern l->	cexpr = foldl Apply ->	              (Constructor r)->	              (map (Variable . qualify) ls) ->	updLhs = FunLhs updId [cpatt1, cpatt2]->	updRhs = SimpleRhs p cexpr []->   in  (updId, FunctionDecl p updId [Equation p updLhs updRhs])--> replaceIdent :: Ident -> Ident -> [Ident] -> [Ident]-> replaceIdent _ _ [] = []-> replaceIdent what with (id:ids)->   | what == id = with:ids->   | otherwise  = id:(replaceIdent what with ids)--\end{verbatim}-In general, a list comprehension of the form-\texttt{[}$e$~\texttt{|}~$t$~\texttt{<-}~$l$\texttt{,}~\emph{qs}\texttt{]}-is transformed into an expression \texttt{foldr}~$f$~\texttt{[]}~$l$ where $f$-is a new function defined as-\begin{quote}-  \begin{tabbing}-    $f$ $x$ \emph{xs} \texttt{=} \\-    \quad \= \texttt{case} $x$ \texttt{of} \\-          \> \quad \= $t$ \texttt{->} \texttt{[}$e$ \texttt{|} \emph{qs}\texttt{]} \texttt{++} \emph{xs} \\-          \>       \> \texttt{\_} \texttt{->} \emph{xs}-  \end{tabbing}-\end{quote}-Note that this translation evaluates the elements of $l$ rigidly,-whereas the translation given in the Curry report is flexible.-However, it does not seem very useful to have the comprehension-generate instances of $t$ which do not contribute to the list.--Actually, we generate slightly better code in a few special cases.-When $t$ is a plain variable, the \texttt{case} expression degenerates-into a let-binding and the auxiliary function thus becomes an alias-for \texttt{(++)}. Instead of \texttt{foldr~(++)} we use the-equivalent prelude function \texttt{concatMap}. In addition, if the-remaining list comprehension in the body of the auxiliary function has-no qualifiers -- i.e., if it is equivalent to \texttt{[$e$]} -- we-avoid the construction of the singleton list by calling \texttt{(:)}-instead of \texttt{(++)} and \texttt{map} in place of-\texttt{concatMap}, respectively. -}-\begin{verbatim}--> desugarQual :: ModuleIdent -> TCEnv -> Position -> Statement -> Expression->      -> DesugarState Expression-> desugarQual m tcEnv p (StmtExpr pos b) e = ->   desugarExpr m tcEnv p (IfThenElse pos b e (List [pos] []))-> desugarQual m tcEnv p (StmtBind refBind t l) e->   | isVarPattern t = desugarExpr m tcEnv p (qualExpr t e l)->   | otherwise =->       do->         tyEnv <- S.get->         v0 <- freshIdent m "_#var" (monoType (typeOf tyEnv t))->         l0 <- freshIdent m "_#var" (monoType (typeOf tyEnv e))->         let v  = addRefId refBind v0->             l' = addRefId refBind l0->         desugarExpr m tcEnv p (apply (prelFoldr refBind) ->                                      [foldFunct v l' e,List [refBind] [],l])->   where ->     qualExpr v (ListCompr _ e []) l ->       = apply (prelMap refBind) [Lambda refBind [v] e,l]->     qualExpr v e l = apply (prelConcatMap refBind) [Lambda refBind [v] e,l]-->     foldFunct v l e =->           Lambda refBind (map VariablePattern [v,l])->             (Case refBind (mkVar v)->                   [caseAlt {-refBind-} p t (append e (mkVar l)),->                    caseAlt {-refBind-} p (VariablePattern v) (mkVar l)])->->     append (ListCompr _ e []) l = apply (Constructor $ addRef refBind $ qConsId) [e,l]->     append e l = apply (prelAppend refBind) [e,l]->-> desugarQual m tcEnv p (StmtDecl ds) e = desugarExpr m tcEnv p (Let ds e)--\end{verbatim}-Generation of fresh names-\begin{verbatim}--> freshIdent :: ModuleIdent -> String -> TypeScheme -> DesugarState Ident-> freshIdent m prefix ty =->   do->     x <- liftM (mkName prefix) (S.lift (S.modify succ >> S.get))->     S.modify (bindFun m x ty)->     return x->   where mkName pre n = mkIdent (pre ++ show n)--\end{verbatim}-Prelude entities-\begin{verbatim}--> prelBind = prel ">>="-> prelBind_ = prel ">>"-> prelFlip = Variable $ preludeIdent "flip"-> prelEnumFrom = Variable $ preludeIdent "enumFrom"-> prelEnumFromTo = Variable $ preludeIdent "enumFromTo"-> prelEnumFromThen = Variable $ preludeIdent "enumFromThen"-> prelEnumFromThenTo = Variable $ preludeIdent "enumFromThenTo"-> prelFailed = Variable $ preludeIdent "failed"-> prelMap r = Variable $ addRef r $ preludeIdent "map"-> prelFoldr = prel "foldr"-> prelAppend = prel "++"-> prelConcatMap = prel "concatMap"-> prelNegate = Variable $ preludeIdent "negate"-> prelNegateFloat = Variable $ preludeIdent "negateFloat"-> prelCond = Variable $ preludeIdent "cond"-> prelFuncPattEqu = Variable $ preludeIdent "=:<="-> prelConstrConj = Variable $ preludeIdent "&"--> prel s r = Variable (addRef r (preludeIdent s))--> truePattern = ConstructorPattern qTrueId []-> falsePattern = ConstructorPattern qFalseId []---> preludeIdent :: String -> QualIdent-> preludeIdent = qualifyWith preludeMIdent . mkIdent--\end{verbatim}-Auxiliary definitions-\begin{verbatim}--> isNewtypeConstr :: ValueEnv -> QualIdent -> Bool-> isNewtypeConstr tyEnv c =->   case qualLookupValue c tyEnv of->     [DataConstructor _ _] -> False->     [NewtypeConstructor _ _] -> True->     _ -> internalError ("isNewtypeConstr " ++ show c) --internalError "isNewtypeConstr"--> isVarPattern :: ConstrTerm -> Bool-> isVarPattern (VariablePattern _) = True-> isVarPattern (ParenPattern t) = isVarPattern t-> isVarPattern (AsPattern _ t) = isVarPattern t-> isVarPattern (LazyPattern _ _) = True-> isVarPattern _ = False--> funDecl :: Position -> Ident -> [ConstrTerm] -> Expression -> Decl-> funDecl p f ts e =->   FunctionDecl p f [Equation p (FunLhs f ts) (SimpleRhs p e [])]--> patDecl :: Position -> ConstrTerm -> Expression -> Decl-> patDecl p t e = PatternDecl p t (SimpleRhs p e [])--> varDecl :: Position -> Ident -> Expression -> Decl-> varDecl p = patDecl p . VariablePattern--> addDecls :: [Decl] -> Rhs -> Rhs-> addDecls ds (SimpleRhs p e ds') = SimpleRhs p e (ds ++ ds')-> addDecls ds (GuardedRhs es ds') = GuardedRhs es (ds ++ ds')--> caseAlt :: Position -> ConstrTerm -> Expression -> Alt-> caseAlt p t e = Alt p t (SimpleRhs p e [])--> apply :: Expression -> [Expression] -> Expression-> apply = foldl Apply--> mkVar :: Ident -> Expression-> mkVar = Variable . qualify---\end{verbatim}
+ src/Env/Class.hs view
@@ -0,0 +1,76 @@+{- |+    Module      :  $Header$+    Description :  Environment of classes+    Copyright   :  (c) 2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    The compiler maintains information about all type classes in an+    environment that maps type classes to a list of their direct+    superclasses and all their associated class methods with an+    additional boolean flag stating whether an default implementation+    has been provided or not. For both the type class identifier and+    the list of super classes original names are used. Thus, the use+    of a flat environment is sufficient.+-}++module Env.Class+  ( ClassEnv, initClassEnv+  , ClassInfo, bindClassInfo, mergeClassInfo, lookupClassInfo+  , superClasses, allSuperClasses, classMethods, hasDefaultImpl+  ) where++import           Data.List       (nub, sort)+import qualified Data.Map as Map (Map, empty, insertWith, lookup)++import Curry.Base.Ident++import Base.Messages (internalError)++type ClassInfo = ([QualIdent], [(Ident, Bool)])++type ClassEnv = Map.Map QualIdent ClassInfo++initClassEnv :: ClassEnv+initClassEnv = Map.empty++bindClassInfo :: QualIdent -> ClassInfo -> ClassEnv -> ClassEnv+bindClassInfo cls (sclss, ms) =+  Map.insertWith mergeClassInfo cls (sort sclss, ms)++-- We have to be careful when merging two class infos into one as hidden class+-- declarations in interfaces provide no information about class methods. If+-- one of the method lists is empty, we simply take the other one. This way,+-- we do overwrite the list of class methods that may have been entered into+-- the class environment before with an empty list.++mergeClassInfo :: ClassInfo -> ClassInfo -> ClassInfo+mergeClassInfo (sclss1, ms1) (_, ms2) = (sclss1, if null ms1 then ms2 else ms1)++lookupClassInfo :: QualIdent -> ClassEnv -> Maybe ClassInfo+lookupClassInfo = Map.lookup++superClasses :: QualIdent -> ClassEnv -> [QualIdent]+superClasses cls clsEnv = case lookupClassInfo cls clsEnv of+  Just (sclss, _) -> sclss+  _ -> internalError $ "Env.Classes.superClasses: " ++ show cls++allSuperClasses :: QualIdent -> ClassEnv -> [QualIdent]+allSuperClasses cls clsEnv = nub $ classes cls+  where+    classes cls' = cls' : concatMap classes (superClasses cls' clsEnv)++classMethods :: QualIdent -> ClassEnv -> [Ident]+classMethods cls clsEnv = case lookupClassInfo cls clsEnv of+  Just (_, ms) -> map fst ms+  _ -> internalError $ "Env.Classes.classMethods: " ++ show cls++hasDefaultImpl :: QualIdent -> Ident -> ClassEnv -> Bool+hasDefaultImpl cls f clsEnv = case lookupClassInfo cls clsEnv of+  Just (_, ms) -> case lookup f ms of+    Just dflt -> dflt+    Nothing -> internalError $ "Env.Classes.hasDefaultImpl: " ++ show f+  _ -> internalError $ "Env.Classes.hasDefaultImpl: " ++ show cls
+ src/Env/Instance.hs view
@@ -0,0 +1,50 @@+{- |+    Module      :  $Header$+    Description :  Environment of instances+    Copyright   :  (c) 2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    The compiler maintains information about defined instances in an+    environment that maps pairs of type classes and type constructors+    to the name of the module where the instance is declared, the context+    as given in the instance declaration, and a list of the class methods+    implemented in the specific instance along with their arity. A flat+    environment is sufficient because instances are visible globally and+    cannot be hidden. Instances are recorded only with the original names+    of the type class and type constructor involved.+-}++module Env.Instance+  ( InstIdent, ppInstIdent, InstInfo+  , InstEnv, initInstEnv, bindInstInfo, lookupInstInfo+  ) where++import qualified Data.Map as Map (Map, empty, insert, lookup)++import Curry.Base.Ident+import Curry.Base.Pretty+import Curry.Syntax.Pretty++import Base.Types++type InstIdent = (QualIdent, QualIdent)++ppInstIdent :: InstIdent -> Doc+ppInstIdent (qcls, qtc) = ppQIdent qcls <+> ppQIdent qtc++type InstInfo = (ModuleIdent, PredSet, [(Ident, Int)])++type InstEnv = Map.Map InstIdent InstInfo++initInstEnv :: InstEnv+initInstEnv = Map.empty++bindInstInfo :: InstIdent -> InstInfo -> InstEnv -> InstEnv+bindInstInfo = Map.insert++lookupInstInfo :: InstIdent -> InstEnv -> Maybe InstInfo+lookupInstInfo = Map.lookup
+ src/Env/Interface.hs view
@@ -0,0 +1,31 @@+{- |+    Module      :  $Header$+    Description :  Environment of imported interfaces+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux+                       2011 - 2013 Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module provides an environment for imported interfaces.+-}+module Env.Interface where++import qualified Data.Map as Map (Map, empty, lookup)++import Curry.Base.Ident (ModuleIdent)+import Curry.Syntax     (Interface)++-- |Environment which maps the 'ModuleIdent' of an imported module+-- to the corresponding 'Interface'.+type InterfaceEnv = Map.Map ModuleIdent Interface++-- |Initial 'InterfaceEnv'.+initInterfaceEnv :: InterfaceEnv+initInterfaceEnv = Map.empty++-- |Lookup the 'Interface' for an imported module.+lookupInterface :: ModuleIdent -> InterfaceEnv -> Maybe Interface+lookupInterface = Map.lookup
+ src/Env/ModuleAlias.hs view
@@ -0,0 +1,41 @@+{- |+    Module      :  $Header$+    Description :  Environment of module aliases+    Copyright   :  (c) 2002 - 2004, Wolfgang Lux+                       2011 - 2013, Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module provides an environment for resolving module aliases.++    For example, if module @FiniteMap@ is imported via++    @import FiniteMap as FM@++    then @FM@ is an alias for @FiniteMap@, and @FiniteMap@ is aliased by @FM@.+-}+module Env.ModuleAlias ( AliasEnv, initAliasEnv, importAliases ) where++import qualified Data.Map   as Map (Map, empty, insert)+import           Data.Maybe        (fromMaybe)++import Curry.Base.Ident (ModuleIdent)+import Curry.Syntax     (ImportDecl (..))++-- |Mapping from the original name of an imported module to its alias.+type AliasEnv = Map.Map ModuleIdent ModuleIdent++-- |Initial alias environment+initAliasEnv :: AliasEnv+initAliasEnv = Map.empty++-- |Create an alias environment from a list of import declarations+importAliases :: [ImportDecl] -> AliasEnv+importAliases = foldr bindAlias initAliasEnv++-- |Bind an alias for a module from a single import declaration+bindAlias :: ImportDecl -> AliasEnv -> AliasEnv+bindAlias (ImportDecl _ mid _ alias _) = Map.insert mid $ fromMaybe mid alias
+ src/Env/OpPrec.hs view
@@ -0,0 +1,111 @@+{- |+    Module      :  $Header$+    Description :  Environment of operator precedences+    Copyright   :  (c) 2002 - 2004, Wolfgang Lux+                       2011 - 2013, Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    In order to parse infix expressions correctly, the compiler must know+    the precedence and fixity of each operator. Operator precedences are+    associated with entities and will be checked after renaming was+    applied. Nevertheless, we need to save precedences for ambiguous names+    in order to handle them correctly while computing the exported+    interface of a module.++    If no fixity is assigned to an operator, it will be given the default+    precedence 9 and assumed to be a left-associative operator.++    /Note:/ this modified version uses Haskell type 'Integer'+    for representing the precedence. This change had to be done due to the+    introduction of unlimited integer constants in the parser / lexer.+-}+module Env.OpPrec+  ( OpPrec (..), defaultP, defaultAssoc, defaultPrecedence, mkPrec+  , OpPrecEnv,  PrecInfo (..), bindP, lookupP, qualLookupP, initOpPrecEnv+  ) where++import Curry.Base.Ident+import Curry.Base.Pretty (Pretty(..))+import Curry.Syntax      (Infix (..))++import Base.TopEnv++import Data.Maybe        (fromMaybe)++import Text.PrettyPrint++-- |Operator precedence.+data OpPrec = OpPrec Infix Precedence deriving Eq++type Precedence = Integer++-- TODO: Change to real show instance and provide Pretty instance+-- if used anywhere.+instance Show OpPrec where+  showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p+    where+    assoc InfixL = "left "+    assoc InfixR = "right "+    assoc Infix  = "non-assoc "++instance Pretty OpPrec where+  pPrint (OpPrec fix p) = pPrint fix <+> integer p++-- |Default operator declaration (associativity and precedence).+defaultP :: OpPrec+defaultP = OpPrec defaultAssoc defaultPrecedence++-- |Default operator associativity.+defaultAssoc :: Infix+defaultAssoc = InfixL++-- |Default operator precedence.+defaultPrecedence :: Precedence+defaultPrecedence = 9++mkPrec :: Maybe Precedence -> Precedence+mkPrec mprec = fromMaybe defaultPrecedence mprec++-- |Precedence information for an identifier.+data PrecInfo = PrecInfo QualIdent OpPrec deriving (Eq, Show)++instance Entity PrecInfo where+  origName (PrecInfo op _) = op++instance Pretty PrecInfo where+  pPrint (PrecInfo qid prec) = pPrint qid <+> pPrint prec++-- |Environment mapping identifiers to their operator precedence.+type OpPrecEnv = TopEnv PrecInfo++-- |Initial 'OpPrecEnv'.+initOpPrecEnv :: OpPrecEnv+initOpPrecEnv = predefTopEnv qConsId consPrec emptyTopEnv++-- |Precedence of list constructor.+consPrec :: PrecInfo+consPrec = PrecInfo qConsId (OpPrec InfixR 5)++-- |Bind an operator precedence.+bindP :: ModuleIdent -> Ident -> OpPrec -> OpPrecEnv -> OpPrecEnv+bindP m op p+  | hasGlobalScope op = bindTopEnv op info . qualBindTopEnv qop info+  | otherwise         = bindTopEnv op info+  where qop  = qualifyWith m op+        info = PrecInfo qop p++-- The lookup functions for the environment which maintains the operator+-- precedences are simpler than for the type and value environments+-- because they do not need to handle tuple constructors.++-- |Lookup the operator precedence for an 'Ident'.+lookupP :: Ident -> OpPrecEnv -> [PrecInfo]+lookupP = lookupTopEnv++-- |Lookup the operator precedence for an 'QualIdent'.+qualLookupP :: QualIdent -> OpPrecEnv -> [PrecInfo]+qualLookupP = qualLookupTopEnv
+ src/Env/Type.hs view
@@ -0,0 +1,70 @@+{- |+    Module      :  $Header$+    Description :  Environment of type identifiers+    Copyright   :  (c) 2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    At the type level, we distinguish data and renaming types, synonym+    types, and type classes. Type variables are not recorded. Type+    synonyms use a kind of their own so that the compiler can verify that+    no type synonyms are used in type expressions in interface files.+-}++module Env.Type+  ( TypeKind (..), toTypeKind,+    TypeEnv, bindTypeKind, lookupTypeKind, qualLookupTypeKind+  ) where++import Curry.Base.Ident++import Base.Messages (internalError)+import Base.TopEnv+import Base.Types (constrIdent, methodName)++import Env.TypeConstructor (TypeInfo (..))++import Data.List (union)++data TypeKind+  = Data  QualIdent [Ident]+  | Alias QualIdent+  | Class QualIdent [Ident]+  deriving (Eq, Show)++instance Entity TypeKind where+  origName (Data  tc  _) = tc+  origName (Alias tc   ) = tc+  origName (Class cls _) = cls++  merge (Data tc cs) (Data tc' cs')+    | tc == tc' = Just $ Data tc $ cs `union` cs'+  merge (Alias tc) (Alias tc')+    | tc == tc' = Just $ Alias tc+  merge (Class cls ms) (Class cls' ms')+    | cls == cls' = Just $Class cls $ ms `union` ms'+  merge _ _ = Nothing++toTypeKind :: TypeInfo -> TypeKind+toTypeKind (DataType     tc    _ cs) = Data tc (map constrIdent cs)+toTypeKind (RenamingType tc    _ nc) = Data tc [constrIdent nc]+toTypeKind (AliasType    tc  _ _  _) = Alias tc+toTypeKind (TypeClass    cls   _ ms) = Class cls (map methodName ms)+toTypeKind (TypeVar               _) =+  internalError "Env.Type.toTypeKind: type variable"++type TypeEnv = TopEnv TypeKind++bindTypeKind :: ModuleIdent -> Ident -> TypeKind -> TypeEnv -> TypeEnv+bindTypeKind m ident tk = bindTopEnv ident tk . qualBindTopEnv qident tk+  where+    qident = qualifyWith m ident++lookupTypeKind :: Ident -> TypeEnv -> [TypeKind]+lookupTypeKind = lookupTopEnv++qualLookupTypeKind :: QualIdent -> TypeEnv -> [TypeKind]+qualLookupTypeKind = qualLookupTopEnv
+ src/Env/TypeConstructor.hs view
@@ -0,0 +1,217 @@+{- |+    Module      :  $Header$+    Description :  Environment of type constructors+    Copyright   :  (c) 2002 - 2004 Wolfgang Lux+                       2011        Björn Peemöller+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    For all defined types the compiler must maintain kind information.+    For algebraic data types and renaming types the compiler also records+    all data constructors belonging to that type, for alias types the+    type expression to be expanded is saved. Futhermore, recording the+    arity is necessary for alias types because the right hand side, i.e.,+    the type expression, can have arbitrary kind and therefore the type+    alias' arity cannot be determined from its own kind. For instance,+    the type alias type List = [] has the kind * -> *, but its arity is 0.+    In order to manage the import and export of types, the names of the+    original definitions are also recorded. On import two types are+    considered equal if their original names match.++    The information for a data constructor comprises the number of+    existentially quantified type variables, the context and the list+    of the argument types. Note that renaming type constructors have only+    one type argument.++    For type classes the all their methods are saved. Type classes are+    recorded in the type constructor environment because type constructors+    and type classes share a common name space.++    For type variables only their kind is recorded in the environment.++    Importing and exporting algebraic data types and renaming types is+    complicated by the fact that the constructors of the type may be+    (partially) hidden in the interface. This facilitates the definition+    of abstract data types. An abstract type is always represented as a+    data type without constructors in the interface regardless of whether+    it is defined as a data type or as a renaming type. When only some+    constructors of a data type are hidden, those constructors are+    replaced by underscores in the interface. Furthermore, if the+    right-most constructors of a data type are hidden, they are not+    exported at all in order to make the interface more stable against+    changes which are private to the module.+-}++module Env.TypeConstructor+  ( TypeInfo (..), tcKind, clsKind, varKind, clsMethods+  , TCEnv, initTCEnv, bindTypeInfo, rebindTypeInfo+  , lookupTypeInfo, qualLookupTypeInfo, qualLookupTypeInfoUnique+  , getOrigName, reverseLookupByOrigName+  ) where++import Curry.Base.Ident+import Curry.Base.Pretty (Pretty(..), blankLine)++import Base.Kinds+import Base.Messages (internalError)+import Base.PrettyKinds ()+import Base.PrettyTypes ()+import Base.TopEnv+import Base.Types+import Base.Utils         ((++!))++import Text.PrettyPrint++data TypeInfo+  = DataType     QualIdent Kind [DataConstr]+  | RenamingType QualIdent Kind DataConstr+  | AliasType    QualIdent Kind Int Type+  | TypeClass    QualIdent Kind [ClassMethod]+  | TypeVar      Kind+    deriving Show++instance Entity TypeInfo where+  origName (DataType     tc    _ _) = tc+  origName (RenamingType tc    _ _) = tc+  origName (AliasType    tc  _ _ _) = tc+  origName (TypeClass    cls   _ _) = cls+  origName (TypeVar              _) =+    internalError "Env.TypeConstructor.origName: type variable"++  merge (DataType tc k cs) (DataType tc' k' cs')+    | tc == tc' && k == k' && (null cs || null cs' || cs == cs') =+    Just $ DataType tc k $ if null cs then cs' else cs+  merge (DataType tc k _) (RenamingType tc' k' nc)+    | tc == tc' && k == k' = Just (RenamingType tc k nc)+  merge l@(RenamingType tc k _) (DataType tc' k' _)+    | tc == tc' && k == k' = Just l+  merge l@(RenamingType tc k _) (RenamingType tc' k' _)+    | tc == tc' && k == k' = Just l+  merge l@(AliasType tc k _ _) (AliasType tc' k' _ _)+    | tc == tc' && k == k' = Just l+  merge (TypeClass cls k ms) (TypeClass cls' k' ms')+    | cls == cls' && k == k' && (null ms || null ms' || ms == ms') =+    Just $ TypeClass cls k $ if null ms then ms' else ms+  merge _ _ = Nothing++instance Pretty TypeInfo where+  pPrint (DataType qid k cs)    =      text "data" <+> pPrint qid+                                   <>  text "/" <> pPrint k+                                   <+> equals+                                   <+> hsep (punctuate (text "|") (map pPrint cs))+  pPrint (RenamingType qid k c) =      text "newtype" <+> pPrint qid+                                   <>  text "/" <> pPrint k+                                   <+> equals <+> pPrint c+  pPrint (AliasType qid k ar ty)=      text "type" <+> pPrint qid+                                   <>  text "/" <> pPrint k <> text "/" <> int ar+                                   <+> equals <+> pPrint ty+  pPrint (TypeClass qid k ms)   =      text "class" <+> pPrint qid+                                   <>  text "/" <> pPrint k+                                   <+> equals+                                   <+> vcat (blankLine : map pPrint ms)+  pPrint (TypeVar _)            =+    internalError $ "Env.TypeConstructor.Pretty.TypeInfo.pPrint: type variable"++tcKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind+tcKind m tc tcEnv = case qualLookupTypeInfo tc tcEnv of+  [DataType     _ k   _] -> k+  [RenamingType _ k   _] -> k+  [AliasType    _ k _ _] -> k+  _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of+    [DataType     _ k   _] -> k+    [RenamingType _ k   _] -> k+    [AliasType    _ k _ _] -> k+    _ -> internalError $+           "Env.TypeConstructor.tcKind: no type constructor: " ++ show tc++clsKind :: ModuleIdent -> QualIdent -> TCEnv -> Kind+clsKind m cls tcEnv = case qualLookupTypeInfo cls tcEnv of+  [TypeClass _ k _] -> k+  _ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of+    [TypeClass _ k _] -> k+    _ -> internalError $+           "Env.TypeConstructor.clsKind: no type class: " ++ show cls++varKind :: Ident -> TCEnv -> Kind+varKind tv tcEnv+  | isAnonId tv = KindStar+  | otherwise = case lookupTypeInfo tv tcEnv of+    [TypeVar k] -> k+    _ -> internalError "Env.TypeConstructor.varKind: no type variable"++clsMethods :: ModuleIdent -> QualIdent -> TCEnv -> [Ident]+clsMethods m cls tcEnv = case qualLookupTypeInfo cls tcEnv of+  [TypeClass _ _ ms] -> map methodName ms+  _ -> case qualLookupTypeInfo (qualQualify m cls) tcEnv of+    [TypeClass _ _ ms] -> map methodName ms+    _ -> internalError $ "Env.TypeConstructor.clsMethods: " ++ show cls++-- Types can only be defined on the top-level; no nested environments are+-- needed for them. Tuple types must be handled as a special case because+-- there is an infinite number of potential tuple types making it+-- impossible to insert them into the environment in advance.++type TCEnv = TopEnv TypeInfo++initTCEnv :: TCEnv+initTCEnv = foldr (uncurry $ predefTC . unapplyType False) emptyTopEnv predefTypes+  where+    predefTC (TypeConstructor tc, tys) =+      predefTopEnv tc . DataType tc (simpleKind $ length tys)+    predefTC _                        =+      internalError "Env.TypeConstructor.initTCEnv.predefTC: no type constructor"++bindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv+bindTypeInfo m ident ti = bindTopEnv ident ti . qualBindTopEnv qident ti+  where+    qident = qualifyWith m ident++rebindTypeInfo :: ModuleIdent -> Ident -> TypeInfo -> TCEnv -> TCEnv+rebindTypeInfo m ident ti = rebindTopEnv ident ti . qualRebindTopEnv qident ti+  where+    qident = qualifyWith m ident++lookupTypeInfo :: Ident -> TCEnv -> [TypeInfo]+lookupTypeInfo ident tcEnv = lookupTopEnv ident tcEnv ++! lookupTupleTC ident++qualLookupTypeInfo :: QualIdent -> TCEnv -> [TypeInfo]+qualLookupTypeInfo ident tcEnv =+  qualLookupTopEnv ident tcEnv ++! lookupTupleTC (unqualify ident)++qualLookupTypeInfoUnique :: ModuleIdent -> QualIdent -> TCEnv -> [TypeInfo]+qualLookupTypeInfoUnique m qident tcEnv =+  case qualLookupTypeInfo qident tcEnv of+    []   -> []+    [ti] -> [ti]+    tis  -> case qualLookupTypeInfo (qualQualify m qident) tcEnv of+      []  -> tis+      [ti] -> [ti]+      tis' -> tis'++getOrigName :: ModuleIdent -> QualIdent -> TCEnv -> QualIdent+getOrigName m tc tcEnv = case qualLookupTypeInfo tc tcEnv of+  [y] -> origName y+  _ -> case qualLookupTypeInfo (qualQualify m tc) tcEnv of+    [y] -> origName y+    _ -> internalError $ "Env.TypeConstructor.getOrigName: " ++ show tc++reverseLookupByOrigName :: QualIdent -> TCEnv -> [QualIdent]+reverseLookupByOrigName on+  | isQTupleId on = const [on]+  | otherwise     = map fst . filter ((== on) . origName . snd) . allBindings++lookupTupleTC :: Ident -> [TypeInfo]+lookupTupleTC tc | isTupleId tc = [tupleTCs !! (tupleArity tc - 2)]+                 | otherwise    = []++tupleTCs :: [TypeInfo]+tupleTCs = map typeInfo tupleData+  where+    typeInfo dc@(DataConstr _ _ _ tys) =+      let n = length tys in DataType (qTupleId n) (simpleKind n) [dc]+    typeInfo (RecordConstr  _ _ _ _ _) =+      internalError "Env.TypeConstructor.tupleTCs: record constructor"
+ src/Env/Value.hs view
@@ -0,0 +1,203 @@+{- |+    Module      :  $Header$+    Description :  Environment for functions, constructors and labels+    Copyright   :  (c) 2001 - 2004 Wolfgang Lux+                       2011        Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    In order to test the type correctness of a module, the compiler needs+    to determine the type of every data constructor, function and+    variable in the module.+    For the purpose of type checking there is no+    need for distinguishing between variables and functions. For all objects+    their original names and their types are saved. In addition, the compiler+    also saves the (optional) list of field labels for data and newtype+    constructors. Data constructors and functions also contain arity+    information. On import two values are considered equal if their original+    names match.+-}++module Env.Value+  ( ValueEnv, ValueInfo (..)+  , bindGlobalInfo, bindFun, qualBindFun, rebindFun, unbindFun+  , lookupValue, qualLookupValue, qualLookupValueUnique+  , initDCEnv+  , ValueType (..), bindLocalVars, bindLocalVar+  ) where++import Curry.Base.Ident+import Curry.Base.Pretty (Pretty(..))++import Base.Messages (internalError)+import Base.PrettyTypes ()+import Base.TopEnv+import Base.Types+import Base.Utils ((++!))++import Text.PrettyPrint++data ValueInfo+  -- |Data constructor with original name, arity, list of record labels and type+  = DataConstructor    QualIdent      Int [Ident] ExistTypeScheme+  -- |Newtype constructor with original name, record label and type+  -- (arity is always 1)+  | NewtypeConstructor QualIdent          Ident   ExistTypeScheme+  -- |Value with original name, class method flag, arity and type+  | Value              QualIdent Bool Int         TypeScheme+  -- |Record label with original name, list of constructors for which label+  -- is valid field and type (arity is always 1)+  | Label              QualIdent [QualIdent]      TypeScheme+    deriving Show++instance Entity ValueInfo where+  origName (DataConstructor    orgName _ _ _) = orgName+  origName (NewtypeConstructor orgName   _ _) = orgName+  origName (Value              orgName _ _ _) = orgName+  origName (Label              orgName   _ _) = orgName++  merge (DataConstructor c1 ar1 ls1 ty1) (DataConstructor c2 ar2 ls2 ty2)+    | c1 == c2 && ar1 == ar2 && ty1 == ty2 = do+      ls' <- sequence (zipWith mergeLabel ls1 ls2)+      Just (DataConstructor c1 ar1 ls' ty1)+  merge (NewtypeConstructor c1 l1 ty1) (NewtypeConstructor c2 l2 ty2)+    | c1 == c2 && ty1 == ty2 = do+      l' <- mergeLabel l1 l2+      Just (NewtypeConstructor c1 l' ty1)+  merge (Value x1 ar1 cm1 ty1) (Value x2 ar2 cm2 ty2)+    | x1 == x2 && ar1 == ar2 && cm1 == cm2 && ty1 == ty2 =+      Just (Value x1 ar1 cm1 ty1)+  merge (Label l1 cs1 ty1) (Label l2 cs2 ty2)+    | l1 == l2 && cs1 == cs2 && ty1 == ty2 = Just (Label l1 cs1 ty1)+  merge _ _ = Nothing++instance Pretty ValueInfo where+  pPrint (DataConstructor qid ar _ tySc) =     text "data" <+> pPrint qid+                                           <>  text "/" <> int ar+                                           <+> equals <+> pPrint tySc+  pPrint (NewtypeConstructor qid _ tySc) =     text "newtype" <+> pPrint qid+                                           <+> equals <+> pPrint tySc+  pPrint (Value qid _ ar tySc)           =     pPrint qid+                                           <>  text "/" <> int ar+                                           <+> equals <+> pPrint tySc+  pPrint (Label qid _ tySc)              =     text "label" <+> pPrint qid+                                           <+> equals <+> pPrint tySc++mergeLabel :: Ident -> Ident -> Maybe Ident+mergeLabel l1 l2+  | l1 == anonId = Just l2+  | l2 == anonId = Just l1+  | l1 == l2     = Just l1+  | otherwise    = Nothing++-- Even though value declarations may be nested, the compiler uses only+-- flat environments for saving type information. This is possible+-- because all identifiers are renamed by the compiler. Here we need+-- special cases for handling tuple constructors.+--+-- Note: the function 'qualLookupValue' has been extended to+-- allow the usage of the qualified list constructor (Prelude.:).++type ValueEnv = TopEnv ValueInfo++bindGlobalInfo :: (QualIdent -> a -> ValueInfo) -> ModuleIdent -> Ident -> a+               -> ValueEnv -> ValueEnv+bindGlobalInfo f m c ty = bindTopEnv c v . qualBindTopEnv qc v+  where qc = qualifyWith m c+        v  = f qc ty++bindFun :: ModuleIdent -> Ident -> Bool -> Int -> TypeScheme -> ValueEnv+        -> ValueEnv+bindFun m f cm a ty+  | hasGlobalScope f = bindTopEnv f v . qualBindTopEnv qf v+  | otherwise        = bindTopEnv f v+  where qf = qualifyWith m f+        v  = Value qf cm a ty++qualBindFun :: ModuleIdent -> Ident -> Bool -> Int -> TypeScheme -> ValueEnv+            -> ValueEnv+qualBindFun m f cm a ty = qualBindTopEnv qf $ Value qf cm a ty+  where qf = qualifyWith m f++rebindFun :: ModuleIdent -> Ident -> Bool -> Int -> TypeScheme -> ValueEnv+          -> ValueEnv+rebindFun m f cm a ty+  | hasGlobalScope f = rebindTopEnv f v . qualRebindTopEnv qf v+  | otherwise        = rebindTopEnv f v+  where qf = qualifyWith m f+        v  = Value qf cm a ty++unbindFun :: Ident -> ValueEnv -> ValueEnv+unbindFun = unbindTopEnv++lookupValue :: Ident -> ValueEnv -> [ValueInfo]+lookupValue x tyEnv = lookupTopEnv x tyEnv ++! lookupTuple x++qualLookupValue :: QualIdent -> ValueEnv -> [ValueInfo]+qualLookupValue x tyEnv = qualLookupTopEnv x tyEnv+                      ++! lookupTuple (unqualify x)++qualLookupValueUnique :: ModuleIdent -> QualIdent -> ValueEnv -> [ValueInfo]+qualLookupValueUnique m x tyEnv = case qualLookupValue x tyEnv of+  []  -> []+  [v] -> [v]+  vs  -> case qualLookupValue (qualQualify m x) tyEnv of+    []  -> vs+    [v] -> [v]+    qvs -> qvs++lookupTuple :: Ident -> [ValueInfo]+lookupTuple c | isTupleId c = [tupleDCs !! (tupleArity c - 2)]+              | otherwise   = []++tupleDCs :: [ValueInfo]+tupleDCs = map dataInfo tupleData+  where dataInfo (DataConstr _ _ _ tys) =+          let n = length tys+          in  DataConstructor (qTupleId n) n (replicate n anonId) $+                ForAllExist n 0 $ predType $ foldr TypeArrow (tupleType tys) tys+        dataInfo (RecordConstr _ _ _ _ _) =+          internalError $ "Env.Value.tupleDCs: " ++ show tupleDCs++-- Since all predefined types are free of existentially quantified type+-- variables and have an empty predicate set, we can ignore both of them+-- when entering the types into the value environment.++initDCEnv :: ValueEnv+initDCEnv = foldr predefDC emptyTopEnv+  [ (c, length tys, constrType (polyType ty) tys)+  | (ty, cs) <- predefTypes, DataConstr c _ _ tys <- cs ]+  where predefDC (c, a, ty) = predefTopEnv c' (DataConstructor c' a ls ty)+          where ls = replicate a anonId+                c' = qualify c+        constrType (ForAll n (PredType ps ty)) =+          ForAllExist n 0 . PredType ps . foldr TypeArrow ty++-- The functions 'bindLocalVar' and 'bindLocalVars' add the type of one or+-- many local variables or functions to the value environment. In contrast+-- to global functions, we do not care about the name of the module containing+-- the variable or function's definition.++class ValueType t where+  toValueType :: Type -> t+  fromValueType :: t -> PredType++instance ValueType Type where+  toValueType = id+  fromValueType = predType++instance ValueType PredType where+  toValueType = predType+  fromValueType = id++bindLocalVars :: ValueType t => [(Ident, Int, t)] -> ValueEnv -> ValueEnv+bindLocalVars = flip $ foldr bindLocalVar++bindLocalVar :: ValueType t => (Ident, Int, t) -> ValueEnv -> ValueEnv+bindLocalVar (v, a, ty) =+  bindTopEnv v $ Value (qualify v) False a $ typeScheme $ fromValueType ty
− src/Eval.lhs
@@ -1,96 +0,0 @@--% $Id: Eval.lhs,v 1.12 2004/02/08 15:35:12 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Eval.lhs}-\section{Collecting Evaluation Annotations}-The module \texttt{Eval} computes the evaluation annotation-environment. There is no need to check the annotations because this-happens already while checking the definitions of the module.-\begin{verbatim}--> module Eval(evalEnv) where--> import qualified Data.Map as Map--> import Curry.Syntax-> import Base---\end{verbatim}-The function \texttt{evalEnv} collects all evaluation annotations of-the module by traversing the syntax tree.-\begin{verbatim}--> evalEnv :: [Decl] -> EvalEnv-> evalEnv = foldr collectAnnotsDecl Map.empty--> collectAnnotsDecl :: Decl -> EvalEnv -> EvalEnv-> collectAnnotsDecl (EvalAnnot _ fs ev) env = foldr (flip Map.insert ev) env fs-> collectAnnotsDecl (FunctionDecl _ _ eqs) env = foldr collectAnnotsEqn env eqs-> collectAnnotsDecl (PatternDecl _ _ rhs) env = collectAnnotsRhs rhs env-> collectAnnotsDecl _ env = env--> collectAnnotsEqn :: Equation -> EvalEnv -> EvalEnv-> collectAnnotsEqn (Equation _ _ rhs) env = collectAnnotsRhs rhs env--> collectAnnotsRhs :: Rhs -> EvalEnv -> EvalEnv-> collectAnnotsRhs (SimpleRhs _ e ds) env =->   collectAnnotsExpr e (foldr collectAnnotsDecl env ds)-> collectAnnotsRhs (GuardedRhs es ds) env =->   foldr collectAnnotsCondExpr (foldr collectAnnotsDecl env ds) es--> collectAnnotsCondExpr :: CondExpr -> EvalEnv -> EvalEnv-> collectAnnotsCondExpr (CondExpr _ g e) env =->   collectAnnotsExpr g (collectAnnotsExpr e env)--> collectAnnotsExpr :: Expression -> EvalEnv -> EvalEnv-> collectAnnotsExpr (Literal _) env = env-> collectAnnotsExpr (Variable _) env = env-> collectAnnotsExpr (Constructor _) env = env-> collectAnnotsExpr (Paren e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Typed e _) env = collectAnnotsExpr e env-> collectAnnotsExpr (Tuple _ es) env = foldr collectAnnotsExpr env es-> collectAnnotsExpr (List _ es) env = foldr collectAnnotsExpr env es-> collectAnnotsExpr (ListCompr _ e qs) env =->   collectAnnotsExpr e (foldr collectAnnotsStmt env qs)-> collectAnnotsExpr (EnumFrom e) env = collectAnnotsExpr e env-> collectAnnotsExpr (EnumFromThen e1 e2) env =->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (EnumFromTo e1 e2) env =->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (EnumFromThenTo e1 e2 e3) env =->   collectAnnotsExpr e1 (collectAnnotsExpr e2 (collectAnnotsExpr e3 env))-> collectAnnotsExpr (UnaryMinus _ e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Apply e1 e2) env =->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (InfixApply e1 _ e2) env =->   collectAnnotsExpr e1 (collectAnnotsExpr e2 env)-> collectAnnotsExpr (LeftSection e _) env = collectAnnotsExpr e env-> collectAnnotsExpr (RightSection _ e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Lambda _ _ e) env = collectAnnotsExpr e env-> collectAnnotsExpr (Let ds e) env =->   foldr collectAnnotsDecl (collectAnnotsExpr e env) ds-> collectAnnotsExpr (Do sts e) env =->   foldr collectAnnotsStmt (collectAnnotsExpr e env) sts-> collectAnnotsExpr (IfThenElse _ e1 e2 e3) env =->   collectAnnotsExpr e1 (collectAnnotsExpr e2 (collectAnnotsExpr e3 env))-> collectAnnotsExpr (Case _ e alts) env =->   collectAnnotsExpr e (foldr collectAnnotsAlt env alts)-> collectAnnotsExpr (RecordConstr fs) env =->   foldr collectAnnotsExpr env (map fieldTerm fs)-> collectAnnotsExpr (RecordSelection e _) env = collectAnnotsExpr e env-> collectAnnotsExpr (RecordUpdate fs e) env =->   foldr collectAnnotsExpr (collectAnnotsExpr e env) (map fieldTerm fs)--> collectAnnotsStmt :: Statement -> EvalEnv -> EvalEnv-> collectAnnotsStmt (StmtExpr _ e) env = collectAnnotsExpr e env-> collectAnnotsStmt (StmtDecl ds) env = foldr collectAnnotsDecl env ds-> collectAnnotsStmt (StmtBind _ _ e) env = collectAnnotsExpr e env--> collectAnnotsAlt :: Alt -> EvalEnv -> EvalEnv-> collectAnnotsAlt (Alt _ _ rhs) env = collectAnnotsRhs rhs env--\end{verbatim}
+ src/Exports.hs view
@@ -0,0 +1,425 @@+{- |+    Module      :  $Header$+    Description :  Computation of export interface+    Copyright   :  (c) 2000 - 2004 Wolfgang Lux+                       2005        Martin Engelke+                       2011 - 2016 Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module provides the computation of the exported interface of a+    compiled module. The function 'exportInterface' uses the expanded export+    specifications and the corresponding environments in order to compute+    the interface of the module.+-}+module Exports (exportInterface) where++import           Data.List         (nub)+import qualified Data.Map   as Map (foldrWithKey, toList)+import           Data.Maybe        (catMaybes)+import qualified Data.Set   as Set ( Set, empty, insert, deleteMin, fromList+                                   , member, toList )++import Curry.Base.Position+import Curry.Base.Ident+import Curry.Syntax++import Base.CurryKinds (fromKind')+import Base.CurryTypes (fromQualType, fromQualPredSet, fromQualPredType)+import Base.Messages+import Base.Types++import Env.Class+import Env.OpPrec          (OpPrecEnv, PrecInfo (..), OpPrec (..), qualLookupP)+import Env.Instance+import Env.TypeConstructor ( TCEnv, TypeInfo (..), tcKind, clsKind+                           , qualLookupTypeInfo )+import Env.Value           (ValueEnv, ValueInfo (..), qualLookupValue)++import CompilerEnv++import Base.Kinds++-- ---------------------------------------------------------------------------+-- Computation of the interface+-- ---------------------------------------------------------------------------++-- After checking that the interface is not ambiguous, the compiler+-- generates the interface's declarations from the list of exported+-- functions and values. In order to make the interface more stable+-- against private changes in the module, we remove the hidden data+-- constructors of a data type in the interface when they occur+-- right-most in the declaration. In addition, newtypes whose constructor+-- is not exported are transformed into (abstract) data types.+--+-- If a type is imported from another module, its name is qualified with+-- the name of the module where it is defined. The same applies to an+-- exported function.++exportInterface :: CompilerEnv -> Module a -> Interface+exportInterface env (Module _ m (Just (Exporting _ es)) _ _) =+  exportInterface' m es (opPrecEnv env) (tyConsEnv env) (valueEnv env)+    (classEnv env) (instEnv env)+exportInterface _   (Module _ _ Nothing                 _ _) =+  internalError "Exports.exportInterface: no export specification"++exportInterface' :: ModuleIdent -> [Export] -> OpPrecEnv -> TCEnv -> ValueEnv+                 -> ClassEnv -> InstEnv -> Interface+exportInterface' m es pEnv tcEnv vEnv clsEnv inEnv = Interface m imports decls'+  where+  tvs     = filter (`notElem` tcs) identSupply+  tcs     = catMaybes $ map (localIdent m) $ definedTypes decls'+  imports = map (IImportDecl NoPos) $ usedModules decls'+  precs   = foldr (infixDecl m pEnv) [] es+  types   = foldr (typeDecl m tcEnv clsEnv tvs) [] es+  values  = foldr (valueDecl m vEnv tvs) [] es+  insts   = Map.foldrWithKey (instDecl m tcEnv tvs) [] inEnv+  decls   = precs ++ types ++ values ++ insts+  decls'  = closeInterface m tcEnv clsEnv inEnv tvs Set.empty decls++infixDecl :: ModuleIdent -> OpPrecEnv -> Export -> [IDecl] -> [IDecl]+infixDecl m pEnv (Export             f) ds = iInfixDecl m pEnv f ds+infixDecl m pEnv (ExportTypeWith tc cs) ds =+  foldr (iInfixDecl m pEnv . qualifyLike tc) ds cs+infixDecl _ _ _ _ = internalError "Exports.infixDecl: no pattern match"++iInfixDecl :: ModuleIdent -> OpPrecEnv -> QualIdent -> [IDecl] -> [IDecl]+iInfixDecl m pEnv op ds = case qualLookupP op pEnv of+  []                        -> ds+  [PrecInfo _ (OpPrec f p)] -> IInfixDecl NoPos f p (qualUnqualify m op) : ds+  _                         -> internalError "Exports.infixDecl"++-- Data types and renaming types whose constructors and field labels are+-- not exported are exported as abstract types, i.e., their constructors+-- do not appear in the interface. If only some constructors or field+-- labels of a type are not exported all constructors appear in the+-- interface, but a pragma marks the constructors and field labels which+-- are not exported as hidden to prevent their use in user code.++typeDecl :: ModuleIdent -> TCEnv -> ClassEnv -> [Ident] -> Export -> [IDecl]+         -> [IDecl]+typeDecl _ _     _      _   (Export             _) ds = ds+typeDecl m tcEnv clsEnv tvs (ExportTypeWith tc xs) ds =+  case qualLookupTypeInfo tc tcEnv of+    [DataType tc' k cs]+      | null xs   -> iTypeDecl IDataDecl m tvs tc' k []  [] : ds+      | otherwise -> iTypeDecl IDataDecl m tvs tc' k cs' hs : ds+      where hs    = filter (`notElem` xs) (csIds ++ ls)+            cs'   = map (constrDecl m n tvs) cs+            ls    = nub (concatMap recordLabels cs')+            csIds = map constrIdent cs+            n = kindArity k+    [RenamingType tc' k c]+      | null xs   -> iTypeDecl IDataDecl    m tvs tc' k [] [] : ds+      | otherwise -> iTypeDecl INewtypeDecl m tvs tc' k nc hs : ds+      where hs  = filter (`notElem` xs) (cId : ls)+            nc  = newConstrDecl m tvs c+            ls  = nrecordLabels nc+            cId = constrIdent c+    [AliasType tc' k n ty] -> ITypeDecl NoPos tc'' k' tvs' ty' : ds+      where tc'' = qualUnqualify m tc'+            k'   = fromKind' k n+            tvs' = take n tvs+            ty'  = fromQualType m tvs' ty+    [TypeClass qcls k ms] -> IClassDecl NoPos cx qcls' k' tv ms' hs : ds+      where qcls' = qualUnqualify m qcls+            cx    = [ Constraint (qualUnqualify m scls) (VariableType tv)+                    | scls <- superClasses qcls clsEnv ]+            k'    = fromKind' k 0+            tv    = head tvs+            ms'   = map (methodDecl m tvs) ms+            hs    = filter (`notElem` xs) (map methodName ms)+    _ -> internalError "Exports.typeDecl"+typeDecl _ _ _ _ _ _ = internalError "Exports.typeDecl: no pattern match"++iTypeDecl+  :: (Position -> QualIdent -> Maybe KindExpr -> [Ident] -> a -> [Ident] -> IDecl)+  -> ModuleIdent -> [Ident] -> QualIdent -> Kind -> a -> [Ident] -> IDecl+iTypeDecl f m tvs tc k x hs = f NoPos (qualUnqualify m tc) k' (take n tvs) x hs+  where n  = kindArity k+        k' = fromKind' k n++constrDecl :: ModuleIdent -> Int -> [Ident] -> DataConstr -> ConstrDecl+constrDecl m n tvs (DataConstr c n' ps [ty1, ty2])+  | isInfixOp c = ConOpDecl NoPos evs cx ty1' c ty2'+  where evs          = take n' $ drop n tvs+        cx           = fromQualPredSet m tvs ps+        [ty1', ty2'] = map (fromQualType m tvs) [ty1, ty2]+constrDecl m n tvs (DataConstr c n' ps tys) = ConstrDecl NoPos evs cx c tys'+  where evs  = take n' $ drop n tvs+        cx   = fromQualPredSet m tvs ps+        tys' = map (fromQualType m tvs) tys+constrDecl m n tvs (RecordConstr c n' ps ls tys) = RecordDecl NoPos evs cx c fs+  where+    evs  = take n' $ drop n tvs+    cx   = fromQualPredSet m tvs ps+    tys' = map (fromQualType m tvs) tys+    fs   = zipWith (FieldDecl NoPos . return) ls tys'++newConstrDecl :: ModuleIdent -> [Ident] -> DataConstr -> NewConstrDecl+newConstrDecl m tvs (DataConstr c _ _ tys)+  = NewConstrDecl NoPos c (fromQualType m tvs (head tys))+newConstrDecl m tvs (RecordConstr c _ _ ls tys)+  = NewRecordDecl NoPos c (head ls, fromQualType m tvs (head tys))++-- When exporting a class method, we have to remove the implicit class context.+-- Due to the sorting of the predicate set, this is fortunatly very easy. The+-- implicit class context is always the minimum element as the class variable+-- is assigned the index 0 and no other constraints on it are allowed.++methodDecl :: ModuleIdent -> [Ident] -> ClassMethod -> IMethodDecl+methodDecl m tvs (ClassMethod f a (PredType ps ty)) = IMethodDecl NoPos f a $+  fromQualPredType m tvs $ PredType (Set.deleteMin ps) ty++valueDecl :: ModuleIdent -> ValueEnv -> [Ident] -> Export -> [IDecl] -> [IDecl]+valueDecl m vEnv tvs (Export      f) ds = case qualLookupValue f vEnv of+  [Value _ cm a (ForAll _ pty)] ->+    IFunctionDecl NoPos (qualUnqualify m f)+      (if cm then Just (head tvs) else Nothing) a (fromQualPredType m tvs pty) : ds+  _ -> internalError $ "Exports.valueDecl: " ++ show f+valueDecl _ _ _ (ExportTypeWith _ _) ds = ds+valueDecl _ _ _ _ _ = internalError "Exports.valueDecl: no pattern match"++instDecl :: ModuleIdent -> TCEnv -> [Ident] -> InstIdent -> InstInfo -> [IDecl]+         -> [IDecl]+instDecl m tcEnv tvs ident@(cls, tc) info@(m', _, _) ds+  | qidModule cls /= Just m' && qidModule tc /= Just m' =+    iInstDecl m tcEnv tvs ident info : ds+  | otherwise = ds++iInstDecl :: ModuleIdent -> TCEnv -> [Ident] -> InstIdent -> InstInfo -> IDecl+iInstDecl m tcEnv tvs (cls, tc) (m', ps, is) =+  IInstanceDecl NoPos cx (qualUnqualify m cls) ty is mm+  where pty = PredType ps $ applyType (TypeConstructor tc) $+                map TypeVariable [0 .. n-1]+        QualTypeExpr cx ty = fromQualPredType m tvs pty+        n = kindArity (tcKind m tc tcEnv) - kindArity (clsKind m cls tcEnv)+        mm = if m == m' then Nothing else Just m'++-- The compiler determines the list of imported modules from the set of+-- module qualifiers that are used in the interface. Careful readers+-- probably will have noticed that the functions above carefully strip+-- the module prefix from all entities that are defined in the current+-- module. Note that the list of modules returned from+-- 'usedModules' is not necessarily a subset of the modules that+-- were imported into the current module. This will happen when an+-- imported module re-exports entities from another module. E.g., given+-- the three modules+--+-- @+-- module A where { data A = A; }+-- module B(A(..)) where { import A; }+-- module C where { import B; x = A; }+-- @+--+-- the interface for module @C@ will import module @A@ but not module @B@.++usedModules :: [IDecl] -> [ModuleIdent]+usedModules ds = nub' (modules ds [])+  where nub' = Set.toList . Set.fromList++class HasModule a where+  modules :: a -> [ModuleIdent] -> [ModuleIdent]++instance HasModule a => HasModule (Maybe a) where+  modules = maybe id modules++instance HasModule a => HasModule [a] where+  modules xs ms = foldr modules ms xs++instance HasModule IDecl where+  modules (IInfixDecl            _ _ _ op) = modules op+  modules (HidingDataDecl        _ tc _ _) = modules tc+  modules (IDataDecl        _ tc _ _ cs _) = modules tc . modules cs+  modules (INewtypeDecl     _ tc _ _ nc _) = modules tc . modules nc+  modules (ITypeDecl          _ tc _ _ ty) = modules tc . modules ty+  modules (IFunctionDecl      _ f _ _ qty) = modules f . modules qty+  modules (HidingClassDecl   _ cx cls _ _) = modules cx . modules cls+  modules (IClassDecl   _ cx cls _ _ ms _) =+    modules cx . modules cls . modules ms+  modules (IInstanceDecl _ cx cls ty _ mm) =+    modules cx . modules cls . modules ty . modules mm++instance HasModule ConstrDecl where+  modules (ConstrDecl    _ _ cx _ tys) = modules cx . modules tys+  modules (ConOpDecl _ _ cx ty1 _ ty2) = modules cx . modules ty1 . modules ty2+  modules (RecordDecl     _ _ cx _ fs) = modules cx . modules fs++instance HasModule FieldDecl where+  modules (FieldDecl _ _ ty) = modules ty++instance HasModule NewConstrDecl where+  modules (NewConstrDecl _ _      ty) = modules ty+  modules (NewRecordDecl _ _ (_, ty)) = modules ty++instance HasModule IMethodDecl where+  modules (IMethodDecl _ _ _ qty) = modules qty++instance HasModule Constraint where+  modules (Constraint cls ty) = modules cls . modules ty++instance HasModule TypeExpr where+  modules (ConstructorType tc) = modules tc+  modules (ApplyType  ty1 ty2) = modules ty1 . modules ty2+  modules (VariableType     _) = id+  modules (TupleType      tys) = modules tys+  modules (ListType        ty) = modules ty+  modules (ArrowType  ty1 ty2) = modules ty1 . modules ty2+  modules (ParenType       ty) = modules ty+  modules (ForallType    _ ty) = modules ty++instance HasModule QualTypeExpr where+  modules (QualTypeExpr cx ty) = modules cx . modules ty++instance HasModule QualIdent where+  modules = modules . qidModule++instance HasModule ModuleIdent where+  modules = (:)++-- After the interface declarations have been computed, the compiler+-- eventually must add hidden (data) type and class declarations to the+-- interface for all those types and classs which were used in the interface+-- but not exported from the current module, so that these type constructors+-- can always be distinguished from type variables. Besides hidden type and+-- class declarations, the compiler also adds instance declarations to the+-- interface. Since class and instance declarations added to an interface can+-- require the inclusion of further classes by their respective contexts,+-- closing an interface is implemented as a fix-point computation which+-- starts from the initial interface.++data IInfo = IOther | IType QualIdent | IClass QualIdent | IInst InstIdent+  deriving (Eq, Ord)++iInfo :: IDecl -> IInfo+iInfo (IInfixDecl           _ _ _ _) = IOther+iInfo (HidingDataDecl      _ tc _ _) = IType tc+iInfo (IDataDecl       _ tc _ _ _ _) = IType tc+iInfo (INewtypeDecl    _ tc _ _ _ _) = IType tc+iInfo (ITypeDecl          _ _ _ _ _) = IOther+iInfo (HidingClassDecl  _ _ cls _ _) = IClass cls+iInfo (IClassDecl   _ _ cls _ _ _ _) = IClass cls+iInfo (IInstanceDecl _ _ cls ty _ _) = IInst (cls, typeConstr ty)+iInfo (IFunctionDecl      _ _ _ _ _) = IOther++closeInterface :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> [Ident]+               -> Set.Set IInfo -> [IDecl] -> [IDecl]+closeInterface _ _ _ _ _ _ [] = []+closeInterface m tcEnv clsEnv inEnv tvs is (d:ds)+  | i == IOther       =+    d : closeInterface m tcEnv clsEnv inEnv tvs is (ds ++ ds')+  | i `Set.member` is = closeInterface m tcEnv clsEnv inEnv tvs is ds+  | otherwise         =+    d : closeInterface m tcEnv clsEnv inEnv tvs (Set.insert i is) (ds ++ ds')+  where i   = iInfo d+        ds' = hiddenTypes m tcEnv clsEnv tvs d +++                instances m tcEnv inEnv tvs is i++hiddenTypes :: ModuleIdent -> TCEnv -> ClassEnv -> [Ident] -> IDecl -> [IDecl]+hiddenTypes m tcEnv clsEnv tvs d =+  map hiddenTypeDecl $ filter (not . isPrimTypeId) (usedTypes d [])+  where hiddenTypeDecl tc = case qualLookupTypeInfo (qualQualify m tc) tcEnv of+          [DataType       _ k _] -> hidingDataDecl k+          [RenamingType   _ k _] -> hidingDataDecl k+          [TypeClass    cls k _] -> hidingClassDecl k $ superClasses cls clsEnv+          _                      ->+            internalError $ "Exports.hiddenTypeDecl: " ++ show tc+          where hidingDataDecl k =+                  let n = kindArity k+                      k' = fromKind' k n+                  in  HidingDataDecl NoPos tc k' $ take n tvs+                hidingClassDecl k sclss =+                  let cx = [ Constraint (qualUnqualify m scls) (VariableType tv)+                           | scls <- sclss ]+                      tv = head tvs+                      k' = fromKind' k 0+                  in  HidingClassDecl NoPos cx tc k' tv++instances :: ModuleIdent -> TCEnv -> InstEnv -> [Ident] -> Set.Set IInfo+          -> IInfo -> [IDecl]+instances _ _ _ _ _ IOther = []+instances m tcEnv inEnv tvs is (IType tc) =+  [ iInstDecl m tcEnv tvs ident info+  | (ident@(cls, tc'), info@(m', _, _)) <- Map.toList inEnv,+    qualQualify m tc == tc',+    if qidModule cls == Just m' then Set.member (IClass (qualUnqualify m cls)) is+                                else qidModule tc' == Just m' ]+instances m tcEnv inEnv tvs is (IClass cls) =+  [ iInstDecl m tcEnv tvs ident info+  | (ident@(cls', tc), info@(m', _, _)) <- Map.toList inEnv,+    qualQualify m cls == cls',+    qidModule cls' == Just m',+    m /= m' || isPrimTypeId tc+            || qidModule tc /= Just m+            || Set.member (IType (qualUnqualify m tc)) is ]+instances _ _ _ _ _ (IInst _) = []++definedTypes :: [IDecl] -> [QualIdent]+definedTypes ds = foldr definedType [] ds+  where+  definedType :: IDecl -> [QualIdent] -> [QualIdent]+  definedType (HidingDataDecl     _ tc _ _) tcs = tc : tcs+  definedType (IDataDecl      _ tc _ _ _ _) tcs = tc : tcs+  definedType (INewtypeDecl   _ tc _ _ _ _) tcs = tc : tcs+  definedType (ITypeDecl      _ tc _ _ _  ) tcs = tc : tcs+  definedType (HidingClassDecl _ _ cls _ _) tcs = cls : tcs+  definedType (IClassDecl  _ _ cls _ _ _ _) tcs = cls : tcs+  definedType _                             tcs = tcs++class HasType a where+  usedTypes :: a -> [QualIdent] -> [QualIdent]++instance HasType a => HasType (Maybe a) where+  usedTypes = maybe id usedTypes++instance HasType a => HasType [a] where+  usedTypes xs tcs = foldr usedTypes tcs xs++instance HasType IDecl where+  usedTypes (IInfixDecl            _ _ _ _) = id+  usedTypes (HidingDataDecl        _ _ _ _) = id+  usedTypes (IDataDecl        _ _ _ _ cs _) = usedTypes cs+  usedTypes (INewtypeDecl     _ _ _ _ nc _) = usedTypes nc+  usedTypes (ITypeDecl          _ _ _ _ ty) = usedTypes ty+  usedTypes (IFunctionDecl     _ _ _ _ qty) = usedTypes qty+  usedTypes (HidingClassDecl    _ cx _ _ _) = usedTypes cx+  usedTypes (IClassDecl    _ cx _ _ _ ms _) = usedTypes cx . usedTypes ms+  usedTypes (IInstanceDecl _ cx cls ty _ _) =+    usedTypes cx . (cls :) . usedTypes ty++instance HasType ConstrDecl where+  usedTypes (ConstrDecl    _ _ cx _ tys) = usedTypes cx . usedTypes tys+  usedTypes (ConOpDecl _ _ cx ty1 _ ty2) =+    usedTypes cx . usedTypes ty1 . usedTypes ty2+  usedTypes (RecordDecl     _ _ cx _ fs) = usedTypes cx . usedTypes fs++instance HasType FieldDecl where+  usedTypes (FieldDecl _ _ ty) = usedTypes ty++instance HasType NewConstrDecl where+  usedTypes (NewConstrDecl      _ _ ty) = usedTypes ty+  usedTypes (NewRecordDecl _ _ (_, ty)) = usedTypes ty++instance HasType IMethodDecl where+  usedTypes (IMethodDecl _ _ _ qty) = usedTypes qty++instance HasType Constraint where+  usedTypes (Constraint cls ty) = (cls :) . usedTypes ty++instance HasType TypeExpr where+  usedTypes (ConstructorType tc) = (tc :)+  usedTypes (ApplyType ty1 ty2) = usedTypes ty1 . usedTypes ty2+  usedTypes (VariableType     _) = id+  usedTypes (TupleType      tys) = usedTypes tys+  usedTypes (ListType        ty) = usedTypes ty+  usedTypes (ArrowType  ty1 ty2) = usedTypes ty1 . usedTypes ty2+  usedTypes (ParenType       ty) = usedTypes ty+  usedTypes (ForallType    _ ty) = usedTypes ty++instance HasType QualTypeExpr where+  usedTypes (QualTypeExpr cx ty) = usedTypes cx . usedTypes ty
− src/Exports.lhs
@@ -1,463 +0,0 @@--% $Id: Exports.lhs,v 1.32 2004/02/13 19:23:57 wlux Exp $-%-% Copyright (c) 2000-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Exports.lhs}-\section{Creating Interfaces}-This section describes how the exported interface of a compiled module-is computed.-\begin{verbatim}--> module Exports(expandInterface,exportInterface) where--> import Data.List-> import Data.Maybe-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Syntax-> import Types-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base-> import TopEnv--\end{verbatim}-The interface of a module is computed in two steps. The function-\texttt{expandInterface} checks the export specifications of the-module and expands them into a list containing all exported types and-functions, combining multiple exports for the same entity. The-expanded export specifications refer to the original names of all-entities. The function \texttt{exportInterface} uses the expanded-specifications and the corresponding environments in order to compute-to the interface of the module.-\begin{verbatim}--> expandInterface :: Module -> TCEnv -> ValueEnv -> Module-> expandInterface (Module m es ds) tcEnv tyEnv =->     --error (show es')->   case findDouble [unqualify tc | ExportTypeWith tc _ <- es'] of->     Nothing ->->       case findDouble ([c | ExportTypeWith _ cs <- es', c <- cs] ++->                    [unqualify f | Export f <- es']) of->         Nothing -> Module m (Just (Exporting NoPos es')) ds->         Just v -> errorAt' (ambiguousExportValue v)->     Just tc -> errorAt' (ambiguousExportType tc) ->   where ms = Set.fromList [fromMaybe m asM | ImportDecl _ m _ asM _ <- ds]->         es' = joinExports $->               maybe (expandLocalModule tcEnv tyEnv)->                     (expandSpecs ms m tcEnv tyEnv)->                     es--\end{verbatim}-While checking all export specifications, the compiler expands-specifications of the form \verb|T(..)| into-\texttt{T($C_1,\dots,C_n$)}, where $C_1,\dots,C_n$ are the data-constructors or the record labels of type \texttt{T}, and replaces -an export specification-\verb|module M| by specifications for all entities which are defined-in module \texttt{M} and imported into the current module with their-unqualified name. In order to distinguish exported type constructors-from exported functions, the former are translated into the equivalent-form \verb|T()|. Note that the export specification \texttt{x} may-export a type constructor \texttt{x} \emph{and} a global function-\texttt{x} at the same time.--\em{Note:} This frontend allows redeclaration and export of imported-identifiers.-\begin{verbatim}--> expandSpecs :: Set.Set ModuleIdent -> ModuleIdent -> TCEnv -> ValueEnv->             -> ExportSpec -> [Export]-> expandSpecs ms m tcEnv tyEnv (Exporting _ es) =->   concat (map (expandExport ms m tcEnv tyEnv) es)--> expandExport :: Set.Set ModuleIdent -> ModuleIdent -> TCEnv->              -> ValueEnv -> Export -> [Export]-> expandExport _ m tcEnv tyEnv (Export x) = expandThing m tcEnv tyEnv x-> expandExport _ m tcEnv _ (ExportTypeWith tc cs) =->   expandTypeWith m tcEnv tc cs-> expandExport _ m tcEnv tyEnv (ExportTypeAll tc) = ->   expandTypeAll m tyEnv tcEnv tc-> expandExport ms m tcEnv tyEnv (ExportModule m')->   | m == m' = (if m `Set.member` ms then expandModule tcEnv tyEnv m else [])->               ++ expandLocalModule tcEnv tyEnv->   | m' `Set.member` ms = expandModule tcEnv tyEnv m'->   | otherwise = errorAt' (moduleNotImported m')--> expandThing :: ModuleIdent -> TCEnv -> ValueEnv -> QualIdent->                -> [Export]-> expandThing m tcEnv tyEnv tc =->   case qualLookupTC tc tcEnv of->     [] -> expandThing' m tyEnv tc Nothing->     [t] -> expandThing' m tyEnv tc (Just [ExportTypeWith (origName t) []])->     _ -> errorAt' (ambiguousType tc)--> expandThing' :: ModuleIdent -> ValueEnv -> QualIdent->              -> Maybe [Export] -> [Export]-> expandThing' m tyEnv f tcExport =->   case (qualLookupValue f tyEnv) of->     [] -> fromMaybe (errorAt' (undefinedEntity f)) tcExport->     [Value f' _] -> Export f' : fromMaybe [] tcExport->     [_] -> fromMaybe (errorAt' (exportDataConstr f)) tcExport->     vs -> case (qualLookupValue (qualQualify m f) tyEnv) of->             [] -> fromMaybe (errorAt' (undefinedEntity f)) tcExport->             [Value f'' _] -> Export f'' : fromMaybe [] tcExport->             [_] -> fromMaybe (errorAt' (exportDataConstr f)) tcExport->             _   -> errorAt' (ambiguousName f)--> expandTypeWith :: ModuleIdent -> TCEnv -> QualIdent -> [Ident] ->	 -> [Export]-> expandTypeWith m tcEnv tc cs =->   case qualLookupTC tc tcEnv of->     [] -> errorAt' (undefinedType tc)->     [t]->       | isDataType t -> [ExportTypeWith (origName t)->                            (map (checkConstr (constrs t)) (nub cs))]->       | isRecordType t -> [ExportTypeWith (origName t)->                            (map (checkLabel (labels t)) (nub cs))]->       | otherwise -> errorAt' (nonDataType tc)->     _ -> errorAt' (ambiguousType tc)->   where checkConstr cs c->           | c `elem` cs = c->           | otherwise = errorAt' (undefinedDataConstr tc c)->         checkLabel ls l->	    | l' `elem` ls = l'->           | otherwise = errorAt' (undefinedLabel tc l)->	   where l' = renameLabel l--> expandTypeAll :: ModuleIdent -> ValueEnv -> TCEnv -> QualIdent ->	-> [Export]-> expandTypeAll m tyEnv tcEnv tc =->   case qualLookupTC tc tcEnv of->     [] -> errorAt' (undefinedType tc)->     [t]->       | isDataType t -> [exportType tyEnv t]->       | isRecordType t -> exportRecord m t->       | otherwise -> errorAt' (nonDataType tc)->     _ -> errorAt' (ambiguousType tc)--> expandLocalModule :: TCEnv -> ValueEnv -> [Export]-> expandLocalModule tcEnv tyEnv =->   [exportType tyEnv t | (_,t) <- localBindings tcEnv] ++->   [Export f' | (f,Value f' _) <- localBindings tyEnv, f == unRenameIdent f]--> expandModule :: TCEnv -> ValueEnv -> ModuleIdent -> [Export]-> expandModule tcEnv tyEnv m =->   [exportType tyEnv t | (_,t) <- moduleImports m tcEnv] ++->   [Export f | (_,Value f _) <- moduleImports m tyEnv]--> exportType :: ValueEnv -> TypeInfo -> Export-> exportType tyEnv t ->   | isRecordType t -- = ExportTypeWith (origName t) (labels t)->     = let ls = labels t->           r  = origName t->       in  case (lookupValue (head ls) tyEnv) of->             [Label _ r' _] -> if r == r' then ExportTypeWith r ls->		                   else ExportTypeWith r []->             _ -> internalError "exportType"->   | otherwise = ExportTypeWith (origName t) (constrs t)--> exportRecord :: ModuleIdent -> TypeInfo -> [Export]-> exportRecord m t = [ExportTypeWith (origName t) (labels t)]--\end{verbatim}-The expanded list of exported entities may contain duplicates. These-are removed by the function \texttt{joinExports}.-\begin{verbatim}--> joinExports :: [Export] -> [Export]-> joinExports es =->   [ExportTypeWith tc cs | (tc,cs) <- Map.toList (foldr joinType Map.empty es)] ++->   [Export f | f <- Set.toList (foldr joinFun Set.empty es)]--> joinType :: Export -> Map.Map QualIdent [Ident] -> Map.Map QualIdent [Ident]-> joinType (Export _) tcs = tcs-> joinType (ExportTypeWith tc cs) tcs =->   Map.insertWith union tc cs tcs--> joinFun :: Export -> Set.Set QualIdent -> Set.Set QualIdent-> joinFun (Export f) fs = f `Set.insert` fs-> joinFun (ExportTypeWith _ _) fs = fs--\end{verbatim}-After checking that the interface is not ambiguous, the compiler-generates the interface's declarations from the list of exported-functions and values. In order to make the interface more stable-against private changes in the module, we remove the hidden data-constructors of a data type in the interface when they occur-right-most in the declaration. In addition, newtypes whose constructor-is not exported are transformed into (abstract) data types.--If a type is imported from another module, its name is qualified with-the name of the module where it is defined. The same applies to an-exported function.-\begin{verbatim}--> exportInterface :: Module -> PEnv -> TCEnv -> ValueEnv -> Interface-> exportInterface (Module m (Just (Exporting _ es)) _) pEnv tcEnv tyEnv =->   Interface m (imports ++ precs ++ hidden ++ ds)->   where imports = map (IImportDecl NoPos) (usedModules ds)->         precs = foldr (infixDecl m pEnv) [] es->         hidden = map (hiddenTypeDecl m tcEnv) (hiddenTypes ds)->         ds = foldr (typeDecl m tcEnv) (foldr (funDecl m tyEnv) [] es) es-> exportInterface (Module _ Nothing _) _ _ _ = internalError "exportInterface"--> infixDecl :: ModuleIdent -> PEnv -> Export -> [IDecl] -> [IDecl]-> infixDecl m pEnv (Export f) ds = iInfixDecl m pEnv f ds-> infixDecl m pEnv (ExportTypeWith tc cs) ds =->   foldr (iInfixDecl m pEnv . qualifyLike (qualidMod tc)) ds cs->   where qualifyLike = maybe qualify qualifyWith--> iInfixDecl :: ModuleIdent -> PEnv -> QualIdent -> [IDecl] -> [IDecl]-> iInfixDecl m pEnv op ds =->   case qualLookupP op pEnv of->     [] -> ds->     [PrecInfo _ (OpPrec fix pr)] ->->       IInfixDecl NoPos fix pr (qualUnqualify m op) : ds->     _ -> internalError "infixDecl"--> typeDecl :: ModuleIdent -> TCEnv -> Export -> [IDecl] -> [IDecl]-> typeDecl _ _ (Export _) ds = ds-> typeDecl m tcEnv (ExportTypeWith tc cs) ds =->   case qualLookupTC tc tcEnv of->     [DataType tc n cs'] ->->       iTypeDecl IDataDecl m tc n->          (constrDecls m (drop n nameSupply) cs cs') : ds->     [RenamingType tc n (Data c n' ty)]->       | c `elem` cs ->->           iTypeDecl INewtypeDecl m tc n (NewConstrDecl NoPos tvs c ty') : ds->       | otherwise -> iTypeDecl IDataDecl m tc n [] : ds->       where tvs = take n' (drop n nameSupply)->             ty' = fromQualType m ty->     [AliasType tc n ty] ->->       case ty of ->	  TypeRecord fs _ ->->           let ty' = TypeRecord (filter (\ (l,_) -> elem l cs) fs) Nothing->           in  iTypeDecl ITypeDecl m tc n (fromQualType m ty') : ds->         _ -> iTypeDecl ITypeDecl m tc n (fromQualType m ty) : ds->     _ -> internalError "typeDecl"--> iTypeDecl :: (Position -> QualIdent -> [Ident] -> a -> IDecl)->            -> ModuleIdent -> QualIdent -> Int -> a -> IDecl-> iTypeDecl f m tc n = f NoPos (qualUnqualify m tc) (take n nameSupply)--> constrDecls :: ModuleIdent -> [Ident] -> [Ident] -> [Maybe (Data [Type])]->             -> [Maybe ConstrDecl]-> constrDecls m tvs cs = clean . map (>>= constrDecl m tvs)->   where clean = reverse . dropWhile isNothing . reverse->         constrDecl m tvs (Data c n tys)->           | c `elem` cs =->               Just (iConstrDecl (take n tvs) c (map (fromQualType m) tys))->           | otherwise = Nothing--> iConstrDecl :: [Ident] -> Ident -> [TypeExpr] -> ConstrDecl-> iConstrDecl tvs op [ty1,ty2]->   | isInfixOp op = ConOpDecl NoPos tvs ty1 op ty2-> iConstrDecl tvs c tys = ConstrDecl NoPos tvs c tys--> funDecl :: ModuleIdent -> ValueEnv -> Export -> [IDecl] -> [IDecl]-> funDecl m tyEnv (Export f) ds =->   case qualLookupValue f tyEnv of->     [Value _ (ForAll _ ty)] ->->       IFunctionDecl NoPos (qualUnqualify m f) (arrowArity ty) ->		  (fromQualType m ty) : ds->     _ -> internalError ("funDecl: " ++ show f)-> funDecl _ _ (ExportTypeWith _ _) ds = ds---\end{verbatim}-The compiler determines the list of imported modules from the set of-module qualifiers that are used in the interface. Careful readers-probably will have noticed that the functions above carefully strip-the module prefix from all entities that are defined in the current-module. Note that the list of modules returned from-\texttt{usedModules} is not necessarily a subset of the modules that-were imported into the current module. This will happen when an-imported module re-exports entities from another module. E.g., given-the three modules-\begin{verbatim}-module A where { data A = A; }-module B(A(..)) where { import A; }-module C where { import B; x = A; }-\end{verbatim}-the interface for module \texttt{C} will import module \texttt{A} but-not module \texttt{B}.-\begin{verbatim}--> usedModules :: [IDecl] -> [ModuleIdent]-> usedModules ds = nub (catMaybes (map qualidMod (foldr identsDecl [] ds)))->   where nub = Set.toList . Set.fromList--> identsDecl :: IDecl -> [QualIdent] -> [QualIdent]-> identsDecl (IDataDecl _ tc _ cs) xs =->   tc : foldr identsConstrDecl xs (catMaybes cs)-> identsDecl (INewtypeDecl _ tc _ nc) xs = tc : identsNewConstrDecl nc xs-> identsDecl (ITypeDecl _ tc _ ty) xs = tc : identsType ty xs-> identsDecl (IFunctionDecl _ f _ ty) xs = f : identsType ty xs--> identsConstrDecl :: ConstrDecl -> [QualIdent] -> [QualIdent]-> identsConstrDecl (ConstrDecl _ _ _ tys) xs = foldr identsType xs tys-> identsConstrDecl (ConOpDecl _ _ ty1 _ ty2) xs =->   identsType ty1 (identsType ty2 xs)--> identsNewConstrDecl :: NewConstrDecl -> [QualIdent] -> [QualIdent]-> identsNewConstrDecl (NewConstrDecl _ _ _ ty) xs = identsType ty xs--> identsType :: TypeExpr -> [QualIdent] -> [QualIdent]-> identsType (ConstructorType tc tys) xs = tc : foldr identsType xs tys-> identsType (VariableType _) xs = xs-> identsType (TupleType tys) xs = foldr identsType xs tys-> identsType (ListType ty) xs = identsType ty xs-> identsType (ArrowType ty1 ty2) xs = identsType ty1 (identsType ty2 xs)-> identsType (RecordType fs rty) xs =->   foldr identsType (maybe xs (\ty -> identsType ty xs) rty) (map snd fs)--\end{verbatim}-After the interface declarations have been computed, the compiler-eventually must add hidden (data) type declarations to the interface-for all those types which were used in the interface but not exported-from the current module, so that these type constructors can always be-distinguished from type variables.-\begin{verbatim}--> hiddenTypeDecl :: ModuleIdent -> TCEnv -> QualIdent -> IDecl-> hiddenTypeDecl m tcEnv tc =->   case qualLookupTC (qualQualify m tc) tcEnv of->     [DataType _ n _] -> hidingDataDecl tc n->     [RenamingType _ n _] -> hidingDataDecl tc n->     _ ->  internalError "hiddenTypeDecl"->   where hidingDataDecl tc n =->           HidingDataDecl NoPos (unqualify tc) (take n nameSupply)--> hiddenTypes :: [IDecl] -> [QualIdent]-> hiddenTypes ds = [tc | tc <- Set.toList tcs, not (isQualified tc)]->   where tcs = foldr Set.delete (Set.fromList (usedTypes ds))->                     (definedTypes ds)--> usedTypes :: [IDecl] -> [QualIdent]-> usedTypes ds = foldr usedTypesDecl [] ds--> usedTypesDecl :: IDecl -> [QualIdent] -> [QualIdent]-> usedTypesDecl (IDataDecl _ _ _ cs) tcs =->   foldr usedTypesConstrDecl tcs (catMaybes cs)-> usedTypesDecl (INewtypeDecl _ _ _ nc) tcs = usedTypesNewConstrDecl nc tcs-> usedTypesDecl (ITypeDecl _ _ _ ty) tcs = usedTypesType ty tcs-> usedTypesDecl (IFunctionDecl _ _ _ ty) tcs = usedTypesType ty tcs--> usedTypesConstrDecl :: ConstrDecl -> [QualIdent] -> [QualIdent]-> usedTypesConstrDecl (ConstrDecl _ _ _ tys) tcs = foldr usedTypesType tcs tys-> usedTypesConstrDecl (ConOpDecl _ _ ty1 _ ty2) tcs =->   usedTypesType ty1 (usedTypesType ty2 tcs)--> usedTypesNewConstrDecl :: NewConstrDecl -> [QualIdent] -> [QualIdent]-> usedTypesNewConstrDecl (NewConstrDecl _ _ _ ty) tcs = usedTypesType ty tcs--> usedTypesType :: TypeExpr -> [QualIdent] -> [QualIdent]-> usedTypesType (ConstructorType tc tys) tcs = tc : foldr usedTypesType tcs tys-> usedTypesType (VariableType _) tcs = tcs-> usedTypesType (TupleType tys) tcs = foldr usedTypesType tcs tys-> usedTypesType (ListType ty) tcs = usedTypesType ty tcs-> usedTypesType (ArrowType ty1 ty2) tcs =->   usedTypesType ty1 (usedTypesType ty2 tcs)-> usedTypesType (RecordType fs rty) tcs =->   foldr usedTypesType ->         (maybe tcs (\ty -> usedTypesType ty tcs) rty) ->         (map snd fs)--> definedTypes :: [IDecl] -> [QualIdent]-> definedTypes ds = foldr definedType [] ds--> definedType :: IDecl -> [QualIdent] -> [QualIdent]-> definedType (IDataDecl _ tc _ _) tcs = tc : tcs-> definedType (INewtypeDecl _ tc _ _) tcs = tc : tcs-> definedType (ITypeDecl _ tc _ _) tcs = tc : tcs-> definedType (IFunctionDecl _ _ _ _)  tcs = tcs--\end{verbatim}-Auxiliary definitions-\begin{verbatim}---> isDataType :: TypeInfo -> Bool-> isDataType (DataType _ _ _) = True-> isDataType (RenamingType _ _ _) = True-> isDataType (AliasType _ _ _) = False--> isRecordType :: TypeInfo -> Bool-> isRecordType (AliasType _ _ (TypeRecord _ _)) = True-> isRecordType _ = False--> constrs :: TypeInfo -> [Ident]-> constrs (DataType _ _ cs) = [c | Just (Data c _ _) <- cs]-> constrs (RenamingType _ _ (Data c _ _)) = [c]-> constrs (AliasType _ _ _) = []--> labels :: TypeInfo -> [Ident]-> labels (AliasType _ _ (TypeRecord fs _)) = map fst fs-> labels _ = []--\end{verbatim}-Error messages-\begin{verbatim}--> undefinedEntity :: QualIdent -> (Position,String)-> undefinedEntity x =->   (positionOfQualIdent x,->    "Entity " ++ qualName x ++ " in export list is not defined")--> undefinedType :: QualIdent -> (Position,String)-> undefinedType tc = ->   (positionOfQualIdent tc,->    "Type " ++ qualName tc ++ " in export list is not defined")--> moduleNotImported :: ModuleIdent -> (Position,String)-> moduleNotImported m = ->   (positionOfModuleIdent m,->    "Module " ++ moduleName m ++ " not imported")--> ambiguousExportType :: Ident -> (Position,String)-> ambiguousExportType x = ->   (positionOfIdent x,->    "Ambiguous export of type " ++ name x)--> ambiguousExportValue :: Ident -> (Position,String)-> ambiguousExportValue x = ->   (positionOfIdent x,->    "Ambiguous export of " ++ name x)--> ambiguousType :: QualIdent -> (Position,String)-> ambiguousType tc = ->   (positionOfQualIdent tc,->    "Ambiguous type " ++ qualName tc)--> ambiguousName :: QualIdent -> (Position,String)-> ambiguousName x = ->   (positionOfQualIdent x,->    "Ambiguous name " ++ qualName x)--> exportDataConstr :: QualIdent -> (Position,String)-> exportDataConstr c = ->   (positionOfQualIdent c,->    "Data constructor " ++ qualName c ++ " in export list")--> nonDataType :: QualIdent -> (Position,String)-> nonDataType tc = ->   (positionOfQualIdent tc,->    qualName tc ++ " is not a data type")--> undefinedDataConstr :: QualIdent -> Ident -> (Position,String)-> undefinedDataConstr tc c =->   (positionOfIdent c,    ->    name c ++ " is not a data constructor of type " ++ qualName tc)--> undefinedLabel :: QualIdent -> Ident -> (Position,String)-> undefinedLabel r l =->   (positionOfIdent l,    ->    name l ++ " is not a label of the record " ++ qualName r)--\end{verbatim}
+ src/Files/CymakePath.hs view
@@ -0,0 +1,32 @@+{- |+    Module      :  $Header$+    Description :  File pathes+    Copyright   :  (c) 2011, Björn Peemöller (bjp@informatik.uni-kiel.de)+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module contains functions to obtain the version number and path+    of the front end binary.+-}+module Files.CymakePath (getCymake, cymakeGreeting, cymakeVersion) where++import Data.Version (showVersion)+import System.FilePath ((</>))+import Paths_curry_frontend++-- | Show a greeting of the current front end+cymakeGreeting :: String+cymakeGreeting = "This is the Curry front end, version " ++ cymakeVersion++-- | Retrieve the version number of cymake+cymakeVersion :: String+cymakeVersion = showVersion version++-- | Retrieve the location of the front end executable+getCymake :: IO String+getCymake = do+  cymakeDir <- getBinDir+  return $ cymakeDir </> "curry-frontend"
− src/GenAbstractCurry.hs
@@ -1,1041 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- GenAbstractCurry - Generates an AbstractCurry program term---                    (type 'CurryProg')------ July 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module GenAbstractCurry (genTypedAbstract, -			 genUntypedAbstract) where--import qualified Data.Map as Map-import qualified Data.Set as Set-import Data.Maybe-import Data.List-import Data.Char--import Curry.Syntax-import Curry.Syntax.Utils-import Curry.AbstractCurry--import Base-import Types-import Curry.Base.Ident-import Curry.Base.Position-import TopEnv-------------------------------------------------------------------------------------- Generates standard (type infered) AbstractCurry code from a CurrySyntax--- module. The function needs the type environment 'tyEnv' to determin the--- infered function types.-genTypedAbstract :: ValueEnv -> TCEnv -> Module -> CurryProg-genTypedAbstract tyEnv tcEnv mod-   = genAbstract (genAbstractEnv TypedAcy tyEnv tcEnv mod) mod----- Generates untyped AbstractCurry code from a CurrySyntax module. The type--- signature takes place in every function type annotation, if it exists, --- otherwise the dummy type "Prelude.untyped" is used.-genUntypedAbstract :: ValueEnv -> TCEnv -> Module -> CurryProg-genUntypedAbstract tyEnv tcEnv mod-   = genAbstract (genAbstractEnv UntypedAcy tyEnv tcEnv mod) mod--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Private...---- Generates an AbstractCurry program term from the syntax tree-genAbstract :: AbstractEnv -> Module -> CurryProg-genAbstract env (Module mid exp decls)-   = let partitions = foldl partitionDecl emptyPartitions decls-         modname    = moduleName mid -	 (imps, _)  -	     = mapfoldl genImportDecl env (reverse (importDecls partitions))-	 (types, _) -	     = mapfoldl genTypeDecl env (reverse (typeDecls partitions))-	 (_, funcs) -	     = Map.mapAccumWithKey (genFuncDecl False) -	                env -			(funcDecls partitions)-	 (ops, _)   -	     = mapfoldl genOpDecl env (reverse (opDecls partitions))-     in  CurryProg modname imps types (Map.elems funcs) ops--------------------------------------------------------------------------------------------------------------------------------------------------------------------- The following types and functions can be used to spread a list of--- CurrySyntax declarations into four parts: a list of imports, a list of--- type declarations (data types and type synonyms), a table of function--- declarations and a list of fixity declarations.----- Inserts a CurrySyntax top level declaration into a partition.--- Note: declarations are collected in reverse order.-partitionDecl :: Partitions -> Decl -> Partitions-partitionDecl partitions (TypeSig pos ids typeexpr)-   = partitionFuncDecls (\id -> TypeSig pos [id] typeexpr) partitions ids-partitionDecl partitions (EvalAnnot pos ids annot)-   = partitionFuncDecls (\id -> EvalAnnot pos [id] annot) partitions ids-partitionDecl partitions (FunctionDecl pos id equs)-   = partitionFuncDecls (const (FunctionDecl pos id equs)) partitions [id]-partitionDecl partitions (ExternalDecl pos conv name id typeexpr)-   = partitionFuncDecls (const (ExternalDecl pos conv name id typeexpr))-                     partitions-		     [id]-partitionDecl partitions (FlatExternalDecl pos ids)-   = partitionFuncDecls (\id -> FlatExternalDecl pos [id]) partitions ids-partitionDecl partitions (InfixDecl pos fix prec idents)-   = partitions {opDecls = map (\id -> (InfixDecl pos fix prec [id])) idents-		           ++ opDecls partitions }-partitionDecl partitions decl-   = case decl of-       ImportDecl _ _ _ _ _ -         -> partitions {importDecls = decl: importDecls partitions }-       DataDecl _ _ _ _     -         -> partitions {typeDecls = decl : typeDecls partitions }-       TypeDecl _ _ _ _     -         -> partitions {typeDecls = decl : typeDecls partitions }-       _ -> partitions------partitionFuncDecls :: (Ident -> Decl) -> Partitions -> [Ident] -> Partitions-partitionFuncDecls genDecl partitions ids-   = partitions {funcDecls = foldl partitionFuncDecl (funcDecls partitions) ids}- where-   partitionFuncDecl funcs' id-      = Map.insert id (genDecl id : fromMaybe [] (Map.lookup id funcs')) funcs'----- Data type for representing partitions of CurrySyntax declarations--- (according to the definition of the AbstractCurry program--- representation; type 'CurryProg').--- Since a complete function declaration usually consist of more than one--- declaration (e.g. rules, type signature etc.), it is necessary --- to collect them within an association list-data Partitions = Partitions {importDecls :: [Decl],-			      typeDecls   :: [Decl],-			      funcDecls   :: Map.Map Ident [Decl],-			      opDecls     :: [Decl]-			     } deriving Show---- Generates initial partitions.-emptyPartitions = Partitions {importDecls = [],-			      typeDecls   = [],-			      funcDecls   = Map.empty,-			      opDecls     = []-			     } ------------------------------------------------------------------------------------- The following functions convert CurrySyntax terms to AbstractCurry--- terms.-----genImportDecl :: AbstractEnv -> Decl -> (String, AbstractEnv)-genImportDecl env (ImportDecl _ mid _ _ _) = (moduleName mid, env)------genTypeDecl :: AbstractEnv -> Decl -> (CTypeDecl, AbstractEnv)-genTypeDecl env (DataDecl _ ident params cdecls)-   = let (idxs, env1)    = mapfoldl genTVarIndex env params-	 (cdecls', env2) = mapfoldl genConsDecl env1 cdecls-     in  (CType (genQName True env2 (qualifyWith (moduleId env) ident))-	        (genVisibility env2 ident)-	        (zip idxs (map name params))-	        cdecls',-	  resetScope env2)-genTypeDecl env (TypeDecl _ ident params typeexpr)-   = let (idxs, env1)      = mapfoldl genTVarIndex env params-	 (typeexpr', env2) = genTypeExpr env1 typeexpr-     in  (CTypeSyn (genQName True env2 (qualifyWith (moduleId env) ident))-	           (genVisibility env2 ident)-	           (zip idxs (map name params))-	           typeexpr',-	  resetScope env2)-genTypeDecl env (NewtypeDecl pos ident _ _)-   = errorAt pos "'newtype' declarations are not supported in AbstractCurry"-genTypeDecl env _-   = internalError "unexpected declaration"------genConsDecl :: AbstractEnv -> ConstrDecl -> (CConsDecl, AbstractEnv)-genConsDecl env (ConstrDecl _ _ ident params)-   = let (params', env') = mapfoldl genTypeExpr env params-     in  (CCons (genQName False env' (qualifyWith (moduleId env) ident))-	        (length params)-	        (genVisibility env' ident)-	        params',-	  env')-genConsDecl env (ConOpDecl pos ids ltype ident rtype)-   = genConsDecl env (ConstrDecl pos ids ident [ltype, rtype])------genTypeExpr :: AbstractEnv -> TypeExpr -> (CTypeExpr, AbstractEnv)-genTypeExpr env (ConstructorType qident targs)-   = let (targs', env') = mapfoldl genTypeExpr env targs-     in  (CTCons (genQName True env' qident) targs', env')-genTypeExpr env (VariableType ident)-   | isJust midx = (CTVar (fromJust midx, name ident), env)-   | otherwise   = (CTVar (idx, name ident), env')- where-   midx        = getTVarIndex env ident-   (idx, env') = genTVarIndex env ident-genTypeExpr env (TupleType targs)-   | len > 1   = genTypeExpr env (ConstructorType (qTupleId len) targs)-   | len == 0  = genTypeExpr env (ConstructorType qUnitId targs)-   | len == 1  = genTypeExpr env (head targs)- where len = length targs-genTypeExpr env (ListType typeexpr)-   = genTypeExpr env (ConstructorType qListId [typeexpr])-genTypeExpr env (ArrowType texpr1 texpr2)-   = let (texpr1', env1) = genTypeExpr env texpr1-	 (texpr2', env2) = genTypeExpr env1 texpr2-     in  (CFuncType texpr1' texpr2', env2)-genTypeExpr env (RecordType fss mr)-   = let fs = concatMap (\ (ls,typeexpr) -> map (\l -> (l,typeexpr)) ls) fss-         (ls,ts) = unzip fs-         (ts',env1) = mapfoldl genTypeExpr env ts-         ls' = map name ls-     in case mr of-           Nothing-             -> (CRecordType (zip ls' ts') Nothing, env1)-           Just tvar@(VariableType _)-             -> let (CTVar iname, env2) = genTypeExpr env1 tvar-                in  (CRecordType (zip ls' ts') (Just iname), env2)-           (Just r@(RecordType _ _))-             -> let (CRecordType fields rbase, env2) = genTypeExpr env1 r-		    fields' = foldr (uncurry insertEntry) -				    fields-			            (zip ls' ts')-		in  (CRecordType fields' rbase, env2)-           _ -> internalError "illegal record base"----- NOTE: every infix declaration must declare exactly one operator.-genOpDecl :: AbstractEnv -> Decl -> (COpDecl, AbstractEnv)-genOpDecl env (InfixDecl _ fix prec [ident])-   = (COp (genQName False env (qualifyWith (moduleId env) ident))-          (genFixity fix)-          (fromInteger prec),-      env)------genFixity :: Infix -> CFixity-genFixity InfixL = CInfixlOp-genFixity InfixR = CInfixrOp-genFixity Infix  = CInfixOp----- Generate an AbstractCurry function declaration from a list of CurrySyntax--- function declarations.--- NOTES: ---   - every declaration in 'decls' must declare exactly one function.---   - since infered types are internally represented in flat style,---     all type variables are renamed with generated symbols when---     generating typed AbstractCurry.-genFuncDecl :: Bool -> AbstractEnv -> Ident -> [Decl] -> (AbstractEnv, CFuncDecl)-genFuncDecl isLocal env ident decls-   | not (null decls)-     = let name          = genQName False env (qualify ident)-	   visibility    = genVisibility env ident-           evalannot     = maybe CFlex -	                         (\ (EvalAnnot _ _ ea) -> genEvalAnnot ea)-				 (find isEvalAnnot decls)-           (mtype, env1) = maybe (Nothing, env) -                                 (\ (t, env') -> (Just t, env'))-				 (genFuncType env decls)-	   (rules, env2) = maybe ([], env1)-			         (\ (FunctionDecl _ _ equs)-				  -> mapfoldl genRule env1 equs)-				 (find isFunctionDecl decls)-           mexternal     = fmap genExternal (find isExternal decls)-	   arity         = compArity mtype rules-           typeexpr      = fromMaybe (CTCons ("Prelude","untyped") []) mtype-           rule          = compRule evalannot rules mexternal-           env3          = if isLocal then env1 else resetScope env2-       in  (env3, CFunc name arity visibility typeexpr rule)-   | otherwise-     = internalError ("missing declaration for function \""-		      ++ show ident ++ "\"")- where-   genFuncType env decls-      | acytype == UntypedAcy-	= fmap (genTypeSig env) (find isTypeSig decls)-      | acytype == TypedAcy-	= fmap (genTypeExpr env) mftype-      | otherwise -	= Nothing-    where -    acytype = acyType env-    mftype  | isLocal   -	      = lookupType ident (typeEnv env)-	    | otherwise -	      = qualLookupType (qualifyWith (moduleId env) ident)-	                       (typeEnv env)--   genTypeSig env (TypeSig _ _ ts)          = genTypeExpr env ts-   genTypeSig env (ExternalDecl _ _ _ _ ts) = genTypeExpr env ts--   genExternal (ExternalDecl _ _ mname ident _)-      = CExternal (fromMaybe (name ident) mname)-   genExternal (FlatExternalDecl _ [ident])-      = CExternal (name ident)-   genExternal _-      = internalError "illegal external declaration occured"--   compArity mtypeexpr rules-      | not (null rules)-        = let (CRule patts _ _) = head rules in length patts-      | otherwise-        = maybe (internalError ("unable to compute arity for function \""-				++ show ident ++ "\""))-	        compArityFromType-		mtypeexpr--   compArityFromType (CTVar _)        = 0-   compArityFromType (CFuncType _ t2) = 1 + compArityFromType t2-   compArityFromType (CTCons _ _)     = 0--   compRule evalannot rules mexternal-      | not (null rules) = CRules evalannot rules-      | otherwise-	= fromMaybe (internalError ("missing rule for function \""-				    ++ show ident ++ "\""))-	            mexternal------genRule :: AbstractEnv -> Equation -> (CRule, AbstractEnv)-genRule env (Equation pos lhs rhs)-   = let (patts, env1)  = mapfoldl (genPattern pos)-			           (beginScope env) -				   (simplifyLhs lhs)-	 (locals, env2) = genLocalDecls env1 (simplifyRhsLocals rhs)-	 (crhss, env3)  = mapfoldl (genCrhs pos) env2 (simplifyRhsExpr rhs)-     in  (CRule patts crhss locals, endScope env3)------genCrhs :: Position -> AbstractEnv -> (Expression, Expression) -           -> ((CExpr, CExpr), AbstractEnv)-genCrhs pos env (cond, expr)-   = let (cond', env1) = genExpr pos env cond-	 (expr', env2) = genExpr pos env1 expr-     in  ((cond', expr'), env2)----- NOTE: guarded expressions and 'where' declarations in local pattern--- declarations are not supported in PAKCS-genLocalDecls :: AbstractEnv -> [Decl] -> ([CLocalDecl], AbstractEnv)-genLocalDecls env decls-   = genLocals (foldl genLocalIndex env decls)-               (funcDecls (foldl partitionDecl emptyPartitions decls))-	       decls- where-   genLocalIndex env (PatternDecl _ constr _)-      = genLocalPatternIndex env constr-   genLocalIndex env (ExtraVariables _ idents)-      = let (_, env') = mapfoldl genVarIndex env idents-	in  env'-   genLocalIndex env _-       = env--   genLocalPatternIndex env (VariablePattern ident)-      = snd (genVarIndex env ident)-   genLocalPatternIndex env (ConstructorPattern _ args)-      = foldl genLocalPatternIndex env args-   genLocalPatternIndex env (InfixPattern c1 _ c2)-      = foldl genLocalPatternIndex env [c1,c2]-   genLocalPatternIndex env (ParenPattern c)-      = genLocalPatternIndex env c-   genLocalPatternIndex env (TuplePattern _ args)-      = foldl genLocalPatternIndex env args-   genLocalPatternIndex env (ListPattern _ args)-      = foldl genLocalPatternIndex env args-   genLocalPatternIndex env (AsPattern ident c)-      = genLocalPatternIndex (snd (genVarIndex env ident)) c-   genLocalPatternIndex env (LazyPattern _ c)-      = genLocalPatternIndex env c-   genLocalPatternIndex env (RecordPattern fields mc)-      = let env' = foldl genLocalPatternIndex env (map fieldTerm fields)-        in  maybe env' (genLocalPatternIndex env') mc-   genLocalPatternIndex env _-      = env--   -- The association list 'fdecls' is necessary because function-   -- rules may not be together in the declaration list-   genLocals :: AbstractEnv -> Map.Map Ident [Decl] -> [Decl] -	        -> ([CLocalDecl], AbstractEnv)-   genLocals env _ [] = ([], env)-   genLocals env fdecls ((FunctionDecl _ ident _):decls)-      = let (funcdecl, env1) = genLocalFuncDecl (beginScope env) fdecls ident-	    (locals, env2)   = genLocals (endScope env1) fdecls decls-        in  (funcdecl:locals, env2)-   genLocals env fdecls ((ExternalDecl _ _ _ ident _):decls)-      = let (funcdecl, env1) = genLocalFuncDecl (beginScope env) fdecls ident-	    (locals, env2)   = genLocals (endScope env1) fdecls decls-        in  (funcdecl:locals, env2)-   genLocals env fdecls ((FlatExternalDecl pos idents):decls)-      | null idents = genLocals env fdecls decls-      | otherwise -        = let (funcdecl, env1) -		= genLocalFuncDecl (beginScope env) fdecls (head idents)-	      (locals, env2) -		= genLocals (endScope env1)-		            fdecls -			    (FlatExternalDecl pos (tail idents):decls)-          in  (funcdecl:locals, env2)-   genLocals env fdecls (PatternDecl pos constr rhs : decls)-      = let (patt, env1)    = genLocalPattern pos env constr-	    (plocals, env2) = genLocalDecls (beginScope env1) -			                    (simplifyRhsLocals rhs)-	    (expr, env3)    = genLocalPattRhs pos env2 (simplifyRhsExpr rhs)-	    (locals, env4)  = genLocals (endScope env3) fdecls decls-	in  (CLocalPat patt expr plocals:locals, env4)-   genLocals env fdecls ((ExtraVariables pos idents):decls)-      | null idents  = genLocals env fdecls decls-      | otherwise-        = let ident  = head idents-	      idx    = fromMaybe -		         (internalError ("cannot find index"-					 ++ " for free variable \""-					 ++ show ident ++ "\""))-		         (getVarIndex env ident)-	      decls' = ExtraVariables pos (tail idents) : decls-	      (locals, env') = genLocals env fdecls decls'-          in (CLocalVar (idx, name ident) : locals, env')-   genLocals env fdecls ((TypeSig _ _ _):decls)-      = genLocals env fdecls decls-   genLocals _ _ decl = internalError ("unexpected local declaration: \n"-				       ++ show (head decl))--   genLocalFuncDecl :: AbstractEnv -> Map.Map Ident [Decl] -> Ident -		       -> (CLocalDecl, AbstractEnv)-   genLocalFuncDecl env fdecls ident-      = let fdecl = fromMaybe -		      (internalError ("missing declaration" -				      ++ " for local function \""-				      ++ show ident ++ "\""))-		      (Map.lookup ident fdecls)-	    (_, funcdecl) = genFuncDecl True env ident fdecl-        in  (CLocalFunc funcdecl, env)--   genLocalPattern pos env (LiteralPattern lit)-      = case lit of-       String _ cs -         -> genLocalPattern pos env -                 (ListPattern [] (map (LiteralPattern . Char noRef) cs))-       _ -> (CPLit (genLiteral lit), env)-   genLocalPattern pos env (VariablePattern ident)-      = let idx = fromMaybe -		     (internalError ("cannot find index"-				    ++ " for pattern variable \""-				    ++ show ident ++ "\""))-		     (getVarIndex env ident)   -        in  (CPVar (idx, name ident), env)-   genLocalPattern pos env (ConstructorPattern qident args)-      = let (args', env') = mapfoldl (genLocalPattern pos) env args-	in (CPComb (genQName False env qident) args', env')-   genLocalPattern pos env (InfixPattern larg qident rarg)-      = genLocalPattern pos env (ConstructorPattern qident [larg, rarg])-   genLocalPattern pos env (ParenPattern patt)-      = genLocalPattern pos env patt-   genLocalPattern pos env (TuplePattern _ args)-      | len > 1  -        = genLocalPattern pos env (ConstructorPattern (qTupleId len) args)-      | len == 1-	= genLocalPattern pos env (head args)-      | len == 0-	= genLocalPattern pos env (ConstructorPattern qUnitId [])-    where len = length args-   genLocalPattern pos env (ListPattern _ args)-      = genLocalPattern pos env -	  (foldr (\p1 p2 -> ConstructorPattern qConsId [p1,p2])-	   (ConstructorPattern qNilId [])-	   args)-   genLocalPattern pos _ (NegativePattern _ _)-      = errorAt pos "negative patterns are not supported in AbstractCurry"-   genLocalPattern pos env (AsPattern ident cterm)-      = let (patt, env1) = genLocalPattern pos env cterm-	    idx          = fromMaybe -			      (internalError ("cannot find index"-					      ++ " for alias variable \""-					      ++ show ident ++ "\""))-			      (getVarIndex env1 ident)-        in  (CPAs (idx, name ident) patt, env1)-   genLocalPattern pos env (LazyPattern _ cterm)-      = let (patt, env') = genLocalPattern pos env cterm-        in  (CPLazy patt, env')-   genLocalPattern pos env (RecordPattern fields mr)-      = let (fields', env1) = mapfoldl (genField genLocalPattern) env fields-	    (mr', env2)-		= maybe (Nothing, env1)-		        (applyFst Just . genLocalPattern pos env1)-			mr-	in  (CPRecord fields' mr', env2)--   genLocalPattRhs pos env [(Variable qSuccessFunId, expr)]-      = genExpr pos env expr-   genLocalPattRhs pos _ _-      = errorAt pos ("guarded expressions in pattern declarations"-		     ++ " are not supported in AbstractCurry")------genExpr :: Position -> AbstractEnv -> Expression -> (CExpr, AbstractEnv)-genExpr pos env (Literal lit)-   = case lit of-       String _ cs -> genExpr pos env (List [] (map (Literal . Char noRef) cs))-       _           -> (CLit (genLiteral lit), env)-genExpr _ env (Variable qident)-   | isJust midx          = (CVar (fromJust midx, name ident), env)-   | qident == qSuccessId = (CSymbol (genQName False env qSuccessFunId), env)-   | otherwise            = (CSymbol (genQName False env qident), env)- where-   ident = unqualify qident-   midx  = getVarIndex env ident-genExpr _ env (Constructor qident)-   = (CSymbol (genQName False env qident), env)-genExpr pos env (Paren expr)-   = genExpr pos env expr-genExpr pos env (Typed expr _)-   = genExpr pos env expr-genExpr pos env (Tuple _ args)-   | len > 1-     = genExpr pos env (foldl Apply (Variable (qTupleId (length args))) args)-   | len == 1-     = genExpr pos env (head args)-   | len == 0-     = genExpr pos env (Variable qUnitId)- where len = length args-genExpr pos env (List _ args)-   = let cons = Constructor qConsId-	 nil  = Constructor qNilId-     in  genExpr pos env (foldr (Apply . Apply cons) nil args)-genExpr pos env (ListCompr _ expr stmts)-   = let (stmts', env1) = mapfoldl (genStatement pos) (beginScope env) stmts-	 (expr', env2)  = genExpr pos env1 expr-     in  (CListComp expr' stmts', endScope env2)-genExpr pos env (EnumFrom expr)-   = genExpr pos env (Apply (Variable qEnumFromId) expr)-genExpr pos env (EnumFromThen expr1 expr2)-   = genExpr pos env (Apply (Apply (Variable qEnumFromThenId) expr1) expr2)-genExpr pos env (EnumFromTo expr1 expr2)-   = genExpr pos env (Apply (Apply (Variable qEnumFromToId) expr1) expr2)-genExpr pos env (EnumFromThenTo expr1 expr2 expr3)-   = genExpr pos env (Apply (Apply (Apply (Variable qEnumFromThenToId) -				    expr1) expr2) expr3)-genExpr pos env (UnaryMinus _ expr)-   = genExpr pos env (Apply (Variable qNegateId) expr)-genExpr pos env (Apply expr1 expr2)-   = let (expr1', env1) = genExpr pos env expr1-	 (expr2', env2) = genExpr pos env1 expr2-     in  (CApply expr1' expr2', env2)-genExpr pos env (InfixApply expr1 op expr2)-   = genExpr pos env (Apply (Apply (opToExpr op) expr1) expr2)-genExpr pos env (LeftSection expr op)-   = let ident  = freshVar env "x"-	 patt   = VariablePattern ident-	 var    = Variable (qualify ident)-	 applic = Apply (Apply (opToExpr op) expr) var -     in  genExpr pos env (Lambda noRef [patt] applic)-genExpr pos env (RightSection op expr)-   = let ident  = freshVar env "x"-	 patt   = VariablePattern ident-	 var    = Variable (qualify ident)-	 applic = Apply (Apply (opToExpr op) var) expr -     in  genExpr pos env (Lambda noRef [patt] applic)-genExpr pos env (Lambda _ params expr)-   = let (params', env1) = mapfoldl (genPattern pos) (beginScope env) params-	 (expr', env2)   = genExpr pos env1 expr-     in  (CLambda params' expr', endScope env2)-genExpr pos env (Let decls expr)-   = let (decls', env1) = genLocalDecls (beginScope env) decls-	 (expr', env2)  = genExpr pos env1 expr-     in  (CLetDecl decls' expr', endScope env2)-genExpr pos env (Do stmts expr)-   = let (stmts', env1) = mapfoldl (genStatement pos) (beginScope env) stmts-	 (expr', env2)  = genExpr pos env1 expr-     in  (CDoExpr (stmts' ++ [CSExpr expr']), endScope env2)-genExpr pos env (IfThenElse _ expr1 expr2 expr3)-   = genExpr pos env (Apply (Apply (Apply (Variable qIfThenElseId)-				    expr1) expr2) expr3)-genExpr pos env (Case _ expr alts)-   = let (expr', env1) = genExpr pos env expr-	 (alts', env2) = mapfoldl genBranchExpr env1 alts-     in  (CCase expr' alts', env2)-genExpr pos env (RecordConstr fields)-   = let (fields', env1) = mapfoldl (genField genExpr) env fields-     in  (CRecConstr fields', env1)-genExpr pos env (RecordSelection expr label)-   = let (expr', env1) = genExpr pos env expr-     in  (CRecSelect expr' (name label), env1)-genExpr pos env (RecordUpdate fields expr)-   = let (fields', env1) = mapfoldl (genField genExpr) env fields-         (expr', env2)   = genExpr pos env1 expr-     in  (CRecUpdate fields' expr', env2)------genStatement :: Position -> AbstractEnv -> Statement -	        -> (CStatement, AbstractEnv)-genStatement pos env (StmtExpr _ expr)-   = let (expr', env') = genExpr pos env expr-     in  (CSExpr expr', env')-genStatement _ env (StmtDecl decls)-   = let (decls', env') = genLocalDecls env decls-     in  (CSLet decls', env')-genStatement pos env (StmtBind _ patt expr)-   = let (expr', env1) = genExpr pos env expr-	 (patt', env2) = genPattern pos env1 patt-     in  (CSPat patt' expr', env2)----- NOTE: guarded expressions and local declarations in case branches--- are not supported in PAKCS-genBranchExpr :: AbstractEnv -> Alt -> (CBranchExpr, AbstractEnv)-genBranchExpr env (Alt pos patt rhs)-   = let (patt', env1) = genPattern pos (beginScope env) patt-	 (expr', env2) = genBranchRhs pos env1 (simplifyRhsExpr rhs)-     in  (CBranch patt' expr', endScope env2)- where-   genBranchRhs pos env [(Variable qSuccessFunId, expr)]-      = genExpr pos env expr-   genBranchRhs pos _ _-      = errorAt pos ("guarded expressions in case alternatives"-		     ++ " are not supported in AbstractCurry")------genPattern :: Position -> AbstractEnv -> ConstrTerm -> (CPattern, AbstractEnv)-genPattern pos env (LiteralPattern lit)-   = case lit of-       String _ cs -         -> genPattern pos env (ListPattern [] (map (LiteralPattern . Char noRef) cs))-       _ -> (CPLit (genLiteral lit), env)-genPattern _ env (VariablePattern ident)-   = let (idx, env') = genVarIndex env ident-     in  (CPVar (idx, name ident), env')-genPattern pos env (ConstructorPattern qident args)-   = let (args', env') = mapfoldl (genPattern pos) env args-     in  (CPComb (genQName False env qident) args', env')-genPattern pos env (InfixPattern larg qident rarg)-   = genPattern pos env (ConstructorPattern qident [larg, rarg])-genPattern pos env (ParenPattern patt)-   = genPattern pos env patt-genPattern pos env (TuplePattern _ args)-   | len > 1-     = genPattern pos env (ConstructorPattern (qTupleId len) args)-   | len == 1-     = genPattern pos env (head args)-   | len == 0-     = genPattern pos env (ConstructorPattern qUnitId [])- where len = length args-genPattern pos env (ListPattern _ args)-   = genPattern pos env (foldr (\x1 x2 -> ConstructorPattern qConsId [x1, x2]) -		         (ConstructorPattern qNilId []) -		         args)-genPattern pos _ (NegativePattern _ _)-   = errorAt pos "negative patterns are not supported in AbstractCurry"-genPattern pos env (AsPattern ident cterm)-   = let (patt, env1) = genPattern pos env cterm-	 (idx, env2) = genVarIndex env1 ident-     in  (CPAs (idx, name ident) patt, env2)-genPattern pos env (LazyPattern _ cterm)-   = let (patt, env') = genPattern pos env cterm-     in  (CPLazy patt, env')-genPattern pos env (FunctionPattern qident cterms)-   = let (patts, env') = mapfoldl (genPattern pos) env cterms-     in  (CPFuncComb (genQName False env qident) patts, env')-genPattern pos env (InfixFuncPattern cterm1 qident cterm2)-   = genPattern pos env (FunctionPattern qident [cterm1, cterm2])-genPattern pos env (RecordPattern fields mr)-   = let (fields', env1) = mapfoldl (genField genPattern) env fields-         (mr', env2)     = maybe (Nothing, env1)-                                 (applyFst Just . genPattern pos env1)-				 mr-     in  (CPRecord fields' mr', env2)------genField :: (Position -> AbstractEnv -> a -> (b, AbstractEnv))-	 -> AbstractEnv -> Field a -> (CField b, AbstractEnv)-genField genTerm env (Field pos label term)-   = let (term',env1) = genTerm pos env term-     in  ((name label, term'), env1)-----genLiteral :: Literal -> CLiteral-genLiteral (Char _ c)  = CCharc c-genLiteral (Int _ i)   = CIntc i-genLiteral (Float _ f) = CFloatc f-genLiteral _           = internalError "unsupported literal"----- Notes: --- - Some prelude identifiers are not quialified. The first check ensures---   that they get a correct qualifier.--- - The test for unqualified identifiers is necessary to qualify---   them correctly in the untyped AbstractCurry representation.-genQName :: Bool -> AbstractEnv -> QualIdent -> QName-genQName isTypeCons env qident-   | isPreludeSymbol qident-     = genQualName (qualQualify preludeMIdent qident)-   | not (isQualified qident)-     = genQualName (getQualIdent (unqualify qident))-   | otherwise-     = genQualName qident- where-  genQualName qid-     = let (mmid, id) = (qualidMod qid, qualidId qid)-	   mid = maybe (moduleId env)-		       (\mid' -> fromMaybe mid' (Map.lookup mid' (imports env)))-		       mmid-       in  (moduleName mid, name id)--  getQualIdent id-     | isTypeCons = case (lookupTC id (tconsEnv env)) of-		      --[DataType qid _ _] -> qid-		      --[RenamingType qid _ _] -> qid-		      --[AliasType qid _ _] -> qid-		      [info] -> origName info-		      _ ->  qualifyWith (moduleId env) id-     | otherwise  = case (lookupValue id (typeEnv env)) of-		      --[DataConstructor qid _] -> qid-		      --[NewtypeConstructor qid _] -> qid-		      --[Value qid _] -> qid-		      [info] -> origName info-		      _ -> qualifyWith (moduleId env) id-		      ------genVisibility :: AbstractEnv -> Ident -> CVisibility-genVisibility env ident-   | isExported env ident = Public-   | otherwise            = Private------genEvalAnnot :: EvalAnnotation -> CEvalAnnot-genEvalAnnot EvalRigid  = CRigid-genEvalAnnot EvalChoice = CChoice------------------------------------------------------------------------------------- This part defines an environment containing all necessary information--- for generating the AbstractCurry representation of a CurrySyntax term.---- Data type for representing an AbstractCurry generator environment.------    moduleName  - name of the module---    typeEnv     - table of all known types---    exports     - table of all exported symbols from the module---    imports     - table of import aliases---    varIndex    - index counter for generating variable indices---    tvarIndex   - index counter for generating type variable indices---    varScope    - stack of variable tables---    tvarScope   - stack of type variable tables---    acyType     - type of AbstractCurry code to be generated-data AbstractEnv = AbstractEnv {moduleId   :: ModuleIdent,-				typeEnv    :: ValueEnv,-				tconsEnv   :: TCEnv,-				exports    :: Set.Set Ident,-				imports    :: Map.Map ModuleIdent ModuleIdent,-				varIndex   :: Int,-				tvarIndex  :: Int,-				varScope   :: [Map.Map Ident Int],-				tvarScope  :: [Map.Map Ident Int],-                                acyType    :: AbstractType-			       } deriving Show---- Data type representing the type of AbstractCurry code to be generated--- (typed infered or untyped (i.e. type signated))-data AbstractType = TypedAcy | UntypedAcy deriving (Eq, Show)----- Initializes the AbstractCurry generator environment.-genAbstractEnv :: AbstractType -> ValueEnv -> TCEnv -> Module -> AbstractEnv-genAbstractEnv absType tyEnv tcEnv (Module mid exps decls)-   = AbstractEnv -       {moduleId     = mid,-	typeEnv      = tyEnv,-	tconsEnv     = tcEnv,-	exports      = foldl (buildExportTable mid decls) Set.empty exps',-	imports      = foldl buildImportTable Map.empty decls,-	varIndex     = 0,-	tvarIndex    = 0,-	varScope     = [Map.empty],-	tvarScope    = [Map.empty],-        acyType      = absType-       }- where-   exps' = maybe (buildExports mid decls) (\ (Exporting _ es) -> es) exps----- Generates a list of exports for all specified top level declarations-buildExports :: ModuleIdent -> [Decl] -> [Export]-buildExports _ [] = []-buildExports mid (DataDecl _ ident _ _:ds) -   = ExportTypeAll (qualifyWith mid ident) : buildExports mid ds-buildExports mid ((NewtypeDecl _ ident _ _):ds)-   = ExportTypeAll (qualifyWith mid ident) : buildExports mid ds-buildExports mid ((TypeDecl _ ident _ _):ds)-   = Export (qualifyWith mid ident) : buildExports mid ds-buildExports mid ((FunctionDecl _ ident _):ds)-   = Export (qualifyWith mid ident) : buildExports mid ds-buildExports mid (ExternalDecl _ _ _ ident _ : ds)-   = Export (qualifyWith mid ident) : buildExports mid ds-buildExports mid (FlatExternalDecl _ idents : ds)-   = map (Export . qualifyWith mid) idents ++ buildExports mid ds-buildExports mid (_:ds) = buildExports mid ds----- Builds a table containing all exported (i.e. public) identifiers--- from a module.-buildExportTable :: ModuleIdent -> [Decl] -> Set.Set Ident -> Export -                 -> Set.Set Ident-buildExportTable mid _ exptab (Export qident)-   | isJust (localIdent mid qident)-     = insertExportedIdent exptab (unqualify qident)-   | otherwise = exptab-buildExportTable mid _ exptab (ExportTypeWith qident ids)-   | isJust (localIdent mid qident)-     = foldl insertExportedIdent -             (insertExportedIdent exptab (unqualify qident))-             ids-   | otherwise  = exptab-buildExportTable mid decls exptab (ExportTypeAll qident)-   | isJust ident'-     = foldl insertExportedIdent-             (insertExportedIdent exptab ident)-             (maybe [] getConstrIdents (find (isDataDeclOf ident) decls))-   | otherwise = exptab- where -   ident' = localIdent mid qident-   ident  = fromJust ident'-buildExportTable _ _ exptab (ExportModule _) = exptab-----insertExportedIdent :: Set.Set Ident -> Ident -> Set.Set Ident-insertExportedIdent env ident = Set.insert ident env-----getConstrIdents :: Decl -> [Ident]-getConstrIdents (DataDecl _ _ _ constrs)-   = map getConstrIdent constrs- where-   getConstrIdent (ConstrDecl _ _ ident _)  = ident-   getConstrIdent (ConOpDecl _ _ _ ident _) = ident----- Builds a table for dereferencing import aliases-buildImportTable :: Map.Map ModuleIdent ModuleIdent -> Decl-		    -> Map.Map ModuleIdent ModuleIdent-buildImportTable env (ImportDecl _ mid _ malias _)-   = Map.insert (fromMaybe mid malias) mid env-buildImportTable env _ = env----- Checks whether an identifier is exported or not.-isExported :: AbstractEnv -> Ident -> Bool-isExported env ident = Set.member ident (exports env)----- Generates an unique index for the  variable 'ident' and inserts it--- into the  variable table of the current scope.-genVarIndex :: AbstractEnv -> Ident -> (Int, AbstractEnv)-genVarIndex env ident -   = let idx   = varIndex env-         vtabs = varScope env-	 vtab  = head vtabs --if null vtabs then Map.empty else head vtabs-     in  (idx, env {varIndex = idx + 1,-		    varScope = Map.insert ident idx vtab : sureTail vtabs})---- Generates an unique index for the type variable 'ident' and inserts it--- into the type variable table of the current scope.-genTVarIndex :: AbstractEnv -> Ident -> (Int, AbstractEnv)-genTVarIndex env ident-   = let idx   = tvarIndex env-         vtabs = tvarScope env-	 vtab  = head vtabs --if null vtabs then Map.empty else head vtabs-     in  (idx, env {tvarIndex = idx + 1,-		    tvarScope = Map.insert ident idx vtab : sureTail vtabs })----- Looks up the unique index for the variable 'ident' in the--- variable table of the current scope.-getVarIndex :: AbstractEnv -> Ident -> Maybe Int-getVarIndex env ident = Map.lookup ident (head (varScope env))---- Looks up the unique index for the type variable 'ident' in the type--- variable table of the current scope.-getTVarIndex :: AbstractEnv -> Ident -> Maybe Int-getTVarIndex env ident = Map.lookup ident (head (tvarScope env))----- Generates an indentifier which doesn't occur in the variable table--- of the current scope.-freshVar :: AbstractEnv -> String -> Ident-freshVar env name = genFreshVar env name 0- where-   genFreshVar env name idx-      | isJust (getVarIndex env ident)-         = genFreshVar env name (idx + 1)-      | otherwise -         = ident-    where ident = mkIdent (name ++ show idx)---- Sets the index counter back to zero and deletes all stack entries.-resetScope :: AbstractEnv -> AbstractEnv-resetScope env = env {varIndex  = 0,-		      tvarIndex = 0,-		      varScope  = [Map.empty],-		      tvarScope = [Map.empty]}---- Starts a new scope, i.e. copies and pushes the variable table of the current --- scope onto the top of the stack-beginScope :: AbstractEnv -> AbstractEnv-beginScope env = env {varScope  = head vs :vs,-		      tvarScope = head tvs :tvs }- where- vs  = varScope env- tvs = tvarScope env---- End the current scope, i.e. pops and deletes the variable table of the--- current scope from the top of the stack.-endScope :: AbstractEnv -> AbstractEnv-endScope env = env {varScope  = if oneElement vs then vs else tail vs,-		    tvarScope = if oneElement tvs then tvs else tail tvs}- where- vs  = varScope env- tvs = tvarScope env------------------------------------------------------------------------------------- Miscellaneous...---- Some identifiers...-qEnumFromId       = qualifyWith preludeMIdent (mkIdent "enumFrom")-qEnumFromThenId   = qualifyWith preludeMIdent (mkIdent "enumFromThen")-qEnumFromToId     = qualifyWith preludeMIdent (mkIdent "enumFromTo")-qEnumFromThenToId = qualifyWith preludeMIdent (mkIdent "enumFromThenTo")-qNegateId         = qualifyWith preludeMIdent (mkIdent "negate")-qIfThenElseId     = qualifyWith preludeMIdent (mkIdent "if_then_else")-qSuccessFunId     = qualifyWith preludeMIdent (mkIdent "success")----- The following functions check whether a declaration is of a certain kind-isFunctionDecl :: Decl -> Bool-isFunctionDecl (FunctionDecl _ _ _) = True-isFunctionDecl _                    = False--isExternal :: Decl -> Bool-isExternal (ExternalDecl _ _ _ _ _) = True-isExternal (FlatExternalDecl _ _)   = True-isExternal _                        = False----- Checks, whether a declaration is the data declaration of 'ident'.-isDataDeclOf :: Ident -> Decl -> Bool-isDataDeclOf ident (DataDecl _ ident' _ _) -   = ident == ident'-isDataDeclOf _ _  -   = False----- Checks, whether a symbol is defined in the Prelude.-isPreludeSymbol :: QualIdent -> Bool-isPreludeSymbol qident-   = let (mmid, ident) = (qualidMod qident, qualidId qident)-     in  (isJust mmid && preludeMIdent == fromJust mmid)-         || elem ident [unitId, listId, nilId, consId]-	 || isTupleId ident----- Converts an infix operator to an expression-opToExpr :: InfixOp -> Expression-opToExpr (InfixOp qident)     = Variable qident-opToExpr (InfixConstr qident) = Constructor qident----- Looks up the type of a qualified symbol in the type environment and--- converts it to a CurrySyntax type term.-qualLookupType :: QualIdent -> ValueEnv -> Maybe TypeExpr-qualLookupType qident tyEnv-   = case (qualLookupValue qident tyEnv) of-       [Value _ ts] -> (\ (ForAll _ ty) -> Just (fromType ty)) ts-       _            -> Nothing---- Looks up the type of a symbol in the type environment and--- converts it to a CurrySyntax type term.-lookupType :: Ident -> ValueEnv -> Maybe TypeExpr-lookupType ident tyEnv-   = case (lookupValue ident tyEnv) of-       [Value _ ts] -> (\ (ForAll _ ty) -> Just (fromType ty)) ts-       _            -> Nothing----- The following functions transform left-hand-side and right-hand-side terms--- for a better handling-simplifyLhs :: Lhs -> [ConstrTerm]-simplifyLhs = snd . flatLhs--simplifyRhsExpr :: Rhs -> [(Expression, Expression)]-simplifyRhsExpr (SimpleRhs _ expr _) -   = [(Variable qSuccessId, expr)]-simplifyRhsExpr (GuardedRhs crhs _)  -   = map (\ (CondExpr _ cond expr) -> (cond, expr)) crhs--simplifyRhsLocals :: Rhs -> [Decl]-simplifyRhsLocals (SimpleRhs _ _ locals) = locals-simplifyRhsLocals (GuardedRhs _ locals)  = locals----- FIXME This mapfold is a twisted mapAccumL--- A combination of 'map' and 'foldl'. It maps a function to a list--- from left to right while updating the argument 'e' continously.-mapfoldl :: (a -> b -> (c,a)) -> a -> [b] -> ([c], a)-mapfoldl _ e []     = ([], e)-mapfoldl f e (x:xs) = let (x', e')   = f e x-                          (xs', e'') = mapfoldl f e' xs-                      in  (x':xs', e'')---- Inserts an element under a key into an association list-insertEntry :: Eq a => a -> b -> [(a,b)] -> [(a,b)]-insertEntry k e [] = [(k,e)]-insertEntry k e ((x,y):xys)-   | k == x    = (k,e):xys-   | otherwise = (x,y) : insertEntry k e xys----- Returns the list without the first element. If the list is empty, an--- empty list will be returned.-sureTail :: [a] -> [a]-sureTail []     = []-sureTail (_:xs) = xs----- Returns 'True', if a list contains exactly one element-oneElement :: [a] -> Bool-oneElement [_] = True-oneElement _   = False----- Applies 'f' on the first value in a tuple-applyFst :: (a -> c) -> (a,b) -> (c,b)-applyFst f (x,y) = (f x, y)-----------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/GenFlatCurry.hs
@@ -1,1153 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- GenFlatCurry - Generates FlatCurry program terms and FlatCurry interfaces---                (type 'FlatCurry.Prog')------ November 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module GenFlatCurry (genFlatCurry,-		     genFlatInterface) where---import Control.Monad.State-import Control.Monad-import Data.Maybe-import Data.List-import qualified Data.Map as Map---import Curry.Base.MessageMonad-import Curry.Base.Ident as Id--import qualified Curry.Syntax as CS--import Curry.ExtendedFlat.Type-import Curry.ExtendedFlat.TypeInference--import Curry.ExtendedFlat.EraseTypes--import Base--import qualified IL.Type as IL-import qualified IL.CurryToIL as IL--import TopEnv(topEnvMap)-import CurryEnv (CurryEnv)-import qualified CurryEnv-import ScopeEnv (ScopeEnv)-import qualified ScopeEnv-import Types-import CurryCompilerOpts-import PatchPrelude---import Debug.Trace-trace' _ x = x------------------------------------------------------------------------------------- transforms intermediate language code (IL) to FlatCurry code-genFlatCurry :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv -		-> ArityEnv -> IL.Module -> (Prog, [WarnMsg])-genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv mod-   = (prog', messages)- where (prog, messages) -           = run opts cEnv mEnv tyEnv tcEnv aEnv False (visitModule mod)-       prog' = -- eraseTypes $ -               adjustTypeInfo $ adjustTypeInfo $ patchPreludeFCY prog----- transforms intermediate language code (IL) to FlatCurry interfaces-genFlatInterface :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv-		 -> ArityEnv -> IL.Module -> (Prog, [WarnMsg])-genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv mod-   = (patchPreludeFCY intf, messages)- where (intf, messages) -	   = run opts cEnv mEnv tyEnv tcEnv aEnv True (visitModule mod)----------------------------------------------------------------------------------------------------------------------------------------------------------------------- The environment 'FlatEnv' is embedded in the monadic representation--- 'FlatState' which allows the usage of 'do' expressions.--type FlatState a = State FlatEnv a---- Data type for representing an environment which contains information needed--- for generating FlatCurry code.-data FlatEnv = FlatEnv{ moduleIdE     :: ModuleIdent,-			  functionIdE   :: (QualIdent, [(Ident, IL.Type)]),-			  compilerOptsE :: Options,-			  moduleEnvE    :: ModuleEnv,-			  arityEnvE     :: ArityEnv,-			  typeEnvE      :: ValueEnv,     -- types of defined values-			  tConsEnvE     :: TCEnv,-			  publicEnvE    :: Map.Map Ident IdentExport,-			  fixitiesE     :: [CS.IDecl],-			  typeSynonymsE :: [CS.IDecl],-			  importsE      :: [CS.IDecl],-			  exportsE      :: [CS.Export],-			  interfaceE    :: [CS.IDecl],-			  varIndexE     :: Int,-			  varIdsE       :: ScopeEnv Ident VarIndex,-			  tvarIndexE    :: Int,-			  messagesE     :: [WarnMsg],-			  genInterfaceE :: Bool,-                          localTypes    :: Map.Map QualIdent IL.Type,-                          constrTypes   :: Map.Map QualIdent IL.Type-			}--data IdentExport = NotConstr       -- function, type-constructor-                 | OnlyConstr      -- constructor-                 | NotOnlyConstr   -- constructor, function, type-constructor------- Runs a 'FlatState' action and returns the result-run :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv -    -> Bool -> FlatState a -> (a, [WarnMsg])-run opts cEnv mEnv tyEnv tcEnv aEnv genIntf f-   = (result, messagesE env)- where- (result, env) = runState f env0- env0 = FlatEnv{ moduleIdE     = CurryEnv.moduleId cEnv,-		 functionIdE   = (qualify (mkIdent ""), []),-		 compilerOptsE = opts,-		 moduleEnvE    = mEnv,-		 arityEnvE     = aEnv,-		 typeEnvE      = tyEnv,-		 tConsEnvE     = tcEnv,-		 publicEnvE    = genPubEnv (CurryEnv.moduleId cEnv)-		                 (CurryEnv.interface cEnv),-		 fixitiesE     = CurryEnv.infixDecls cEnv,-		 typeSynonymsE = CurryEnv.typeSynonyms cEnv,-		 importsE      = CurryEnv.imports cEnv,-		 exportsE      = CurryEnv.exports cEnv,-		 interfaceE    = CurryEnv.interface cEnv,-		 varIndexE     = 0,-		 varIdsE       = ScopeEnv.new,-		 tvarIndexE    =0,-		 messagesE      = [],-		 genInterfaceE = genIntf,-                 localTypes    = Map.empty,-                 constrTypes   = Map.fromList (getConstrTypes tcEnv)-	       }--getConstrTypes :: TCEnv -> [(QualIdent, IL.Type)]-getConstrTypes tcEnv = trace' (show tinfos) tinfos-    where tcList = Map.toList $ topEnvMap tcEnv-          tinfos = [ foo tqid conid argtypes targnum-                   | (_, (_, DataType tqid targnum dts):_) <- tcList-                   , Just (Data conid _ argtypes) <- dts]-          foo tqid conid argtypes targnum-              = let conname = QualIdent (qualidMod tqid) conid-                    resulttype = IL.TypeConstructor tqid (map IL.TypeVariable [0..targnum-1])-                    contype = foldr IL.TypeArrow resulttype (map ttrans argtypes)-                in (conname, contype)-              -----visitModule :: IL.Module -> FlatState Prog-visitModule (IL.Module mid imps decls) = do-  -- insert local decls into localDecls-  let ts = [ (qn, t) | IL.FunctionDecl qn _ t _ <- decls ]-  modify (\ s -> s {localTypes = Map.fromList ts})-  whenFlatCurry-       (do ops     <- genOpDecls-           datas   <- mapM visitDataDecl (filter isDataDecl decls)-	   types   <- genTypeSynonyms-	   records <- genRecordTypes-	   funcs   <- mapM visitFuncDecl (filter isFuncDecl decls)-	   mod     <- visitModuleIdent mid-	   imps'   <- imports-	   is      <- mapM visitModuleIdent -	                   (nub (imps ++ (map (\ (CS.IImportDecl _ mid) -					       -> mid) imps')))-           return (Prog mod is (records ++ types ++ datas) funcs ops))-       (do ops     <- genOpDecls-	   ds      <- filterM isPublicDataDecl decls-	   datas   <- mapM visitDataDecl ds-	   types   <- genTypeSynonyms-	   records <- genRecordTypes-	   fs      <- filterM isPublicFuncDecl decls-	   funcs   <- mapM visitFuncDecl fs-	   expimps <- getExportedImports-	   itypes  <- mapM visitTypeIDecl (filter isTypeIDecl expimps)-	   ifuncs  <- mapM visitFuncIDecl (filter isFuncIDecl expimps)-	   iops    <- mapM visitOpIDecl (filter isOpIDecl expimps)-	   mod     <- visitModuleIdent mid-	   imps'   <- imports-	   is      <- mapM visitModuleIdent -	                   (nub (imps ++ (map (\ (CS.IImportDecl _ mid) -					       -> mid) imps')))-	   return (Prog mod -		        is -		        (itypes ++ records ++ types ++ datas)-		        (ifuncs ++ funcs)-		        (iops ++ ops)))-----visitDataDecl :: IL.Decl -> FlatState TypeDecl-visitDataDecl (IL.DataDecl qident arity constrs)-   = do cdecls <- mapM visitConstrDecl constrs-	qname  <- visitQualTypeIdent qident-	vis    <- getVisibility False qident-	return (Type qname vis [0 .. (arity - 1)] (concat cdecls))-visitDataDecl _ = internalError "GenFlatCurry: no data declaration"-----visitConstrDecl :: IL.ConstrDecl [IL.Type] -> FlatState [ConsDecl]-visitConstrDecl (IL.ConstrDecl qident types)-   = do texprs <- mapM visitType types-	qname  <- visitQualIdent qident-	vis    <- getVisibility True qident-        genFint <- genInterface-        if genFint && vis == Private -          then return []-          else return [Cons qname (length types) vis texprs]-----visitType :: IL.Type -> FlatState TypeExpr-visitType (IL.TypeConstructor qident types)-   = do texprs <- mapM visitType types-	qname  <- visitQualTypeIdent qident-	if (qualName qident) == "Identity"-	   then return (head texprs)-	   else return (TCons qname texprs)-visitType (IL.TypeVariable index)-   = return (TVar (abs index))-visitType (IL.TypeArrow type1 type2)-   = do texpr1 <- visitType type1-	texpr2 <- visitType type2-	return (FuncType texpr1 texpr2)-----visitFuncDecl :: IL.Decl -> FlatState FuncDecl-visitFuncDecl (IL.FunctionDecl qident params typeexpr expression)-   = let argtypes = splitoffArgTypes typeexpr params -     in do setFunctionId (qident, argtypes)-           qname <- visitQualIdent qident-           whenFlatCurry (do is    <- mapM newVarIndex params-	                     texpr <- visitType typeexpr-	                     expr  <- visitExpression expression-	                     vis   <- getVisibility False qident-	                     clearVarIndices-	                     return (Func qname (length params) vis texpr (Rule is expr)))-                         (do texpr <- visitType typeexpr-	                     clearVarIndices-	                     return (Func qname (length params) Public texpr (Rule [] (Var $ mkIdx 0))))-visitFuncDecl (IL.ExternalDecl qident _ name typeexpr)-   = do setFunctionId (qident, [])-	texpr <- visitType typeexpr-	qname <- visitQualIdent qident-	vis   <- getVisibility False qident-	xname <- visitExternalName name-	return (Func qname (typeArity typeexpr) vis texpr (External xname))-visitFuncDecl (IL.NewtypeDecl _ _ _)-   = do mid <- moduleId -	error ("\"" ++ Id.moduleName mid -	       ++ "\": newtype declarations are not supported")-visitFuncDecl _ = internalError "GenFlatCurry: no function declaration"-----visitExpression :: IL.Expression -> FlatState Expr-visitExpression (IL.Literal literal)-   = liftM Lit (visitLiteral literal)-visitExpression (IL.Variable ident)-   = liftM Var (lookupVarIndex ident)-visitExpression (IL.Function qident _)-   = do arity_ <- lookupIdArity qident-        qname <- visitQualIdent qident-	maybe (internalError (funcArity qname))-	      (\arity -> genFuncCall qname arity [])-	      arity_-visitExpression (IL.Constructor qident arity)-   = do arity_ <- lookupIdArity qident-        qname <- visitQualIdent qident-	maybe (internalError (consArity qident))-	      (\arity -> genConsCall qname arity [])-	      arity_-visitExpression (IL.Apply e1 e2)-   = genFlatApplication e1 e2-visitExpression (IL.Case r evalannot expression alts)-   = do ea       <- visitEval evalannot-	expr     <- visitExpression expression-	branches <- mapM visitAlt alts-	return (Case r ea expr branches)-visitExpression (IL.Or expression1 expression2)-   = do expr1 <- visitExpression expression1-	expr2 <- visitExpression expression2-	checkOverlapping expr1 expr2-	return (Or expr1 expr2)-visitExpression (IL.Exist ident expression)-   = do index <- newVarIndex ident-	expr  <- visitExpression expression-	case expr of-	  Free is expr' -> return (Free (index:is) expr')-	  _             -> return (Free [index] expr)-visitExpression (IL.Let binding expression)-   = do beginScope-	newVarIndex (bindingIdent binding)-        bind <- visitBinding binding-	expr <- visitExpression expression-        -- is it correct that there is no endScope? (hsi)-        return (Let [bind] expr)-visitExpression (IL.Letrec bindings expression)-   = do beginScope-	mapM_ (newVarIndex . bindingIdent) bindings-	binds <- mapM visitBinding bindings-	expr  <- visitExpression expression-	endScope-	return (Let binds expr)------visitLiteral :: IL.Literal -> FlatState Literal-visitLiteral (IL.Char rs c)  = return (Charc rs c)-visitLiteral (IL.Int rs i)   = return (Intc rs i)-visitLiteral (IL.Float rs f) = return (Floatc rs f)-----visitAlt :: IL.Alt -> FlatState BranchExpr-visitAlt (IL.Alt cterm expression)-   = do patt <- visitConstrTerm cterm-	expr <- visitExpression expression-	return (Branch patt expr)-----visitConstrTerm :: IL.ConstrTerm -> FlatState Pattern-visitConstrTerm (IL.LiteralPattern literal)-   = do lit <- visitLiteral literal-	return (LPattern lit)-visitConstrTerm (IL.ConstructorPattern qident args)-   = do is    <- mapM newVarIndex args-	qname <- visitQualIdent qident-	return (Pattern qname is)-visitConstrTerm (IL.VariablePattern ident)-   = do mid <- moduleId-	error ("\"" ++ Id.moduleName mid -	       ++ "\": variable patterns are not supported")-----visitEval :: IL.Eval -> FlatState CaseType-visitEval IL.Rigid = return Rigid-visitEval IL.Flex  = return Flex-----visitBinding :: IL.Binding -> FlatState (VarIndex, Expr)-visitBinding (IL.Binding ident expression)-   = do index <- lookupVarIndex ident-	expr  <- visitExpression expression-	return (index, expr)---------------------------------------------------------------------------------------visitFuncIDecl :: CS.IDecl -> FlatState FuncDecl-visitFuncIDecl (CS.IFunctionDecl _ qident arity typeexpr)-   = do texpr <- visitType (fst (cs2ilType [] typeexpr))-	qname <- visitQualIdent qident-	return (Func qname arity Public texpr (Rule [] (Var $ mkIdx 0)))-visitFuncIDecl _ = internalError "GenFlatCurry: no function interface"-----visitTypeIDecl :: CS.IDecl -> FlatState TypeDecl-visitTypeIDecl (CS.IDataDecl _ qident params constrs_)-   = do let mid = fromMaybe (internalError "GenFlatCurry: no module name")-		            (qualidMod qident)-	    is  = [0 .. length params - 1]-	cdecls <- mapM (visitConstrIDecl mid (zip params is)) -		       (catMaybes constrs_)-	qname  <- visitQualTypeIdent qident-	return (Type qname Public is cdecls)-visitTypeIDecl (CS.ITypeDecl _ qident params typeexpr)-   = do let is = [0 .. (length params) - 1]-	texpr <- visitType (fst (cs2ilType (zip params is) typeexpr))-	qname <- visitQualTypeIdent qident-	return (TypeSyn qname Public is texpr)-visitTypeIDecl _ = internalError "GenFlatCurry: no type interface"-----visitConstrIDecl :: ModuleIdent -> [(Ident, Int)] -> CS.ConstrDecl -		    -> FlatState ConsDecl-visitConstrIDecl mid tis (CS.ConstrDecl _ _ ident typeexprs)-   = do texprs <- mapM (visitType . (fst . cs2ilType tis)) typeexprs-	qname  <- visitQualIdent (qualifyWith mid ident)-	return (Cons qname (length typeexprs) Public texprs)-visitConstrIDecl mid tis (CS.ConOpDecl pos ids type1 ident type2)-   = visitConstrIDecl mid tis (CS.ConstrDecl pos ids ident [type1,type2])-----visitOpIDecl :: CS.IDecl -> FlatState OpDecl-visitOpIDecl (CS.IInfixDecl _ fixity prec qident)-   = do let fix = case fixity of-	            CS.InfixL -> InfixlOp-		    CS.InfixR -> InfixrOp-		    _         -> InfixOp-        qname <- visitQualIdent qident-	return (Op qname fix prec)---------------------------------------------------------------------------------------visitModuleIdent :: ModuleIdent -> FlatState String-visitModuleIdent = return . Id.moduleName-----visitQualIdent :: QualIdent -> FlatState QName-visitQualIdent qident-   = do mid <- moduleId-	let (mmod, ident) = (qualidMod qident, qualidId qident)-	    mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident-		  = Id.moduleName preludeMIdent-		| otherwise-		  = maybe (Id.moduleName mid) Id.moduleName mmod-        ftype <- lookupIdType qident-	return (QName Nothing ftype mod $ name ident)---- This variant of visitQualIdent does not look up the type of the identifier,--- which is wise when the identifier is bound to a type, because looking up--- the type of a type via lookupIdType will get stuck in an endless loop. (hsi)-visitQualTypeIdent :: QualIdent -> FlatState QName-visitQualTypeIdent qident-   = do mid <- moduleId-	let (mmod, ident) = (qualidMod qident, qualidId qident)-	    mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident-		  = Id.moduleName preludeMIdent-		| otherwise-		  = maybe (Id.moduleName mid) Id.moduleName mmod-	return (QName Nothing Nothing mod $ name ident)-----visitExternalName :: String -> FlatState String-visitExternalName name -   = moduleId >>= \mid -> return (Id.moduleName mid ++ "." ++ name)-----------------------------------------------------------------------------------------------------------------------------------------------------------------------getVisibility :: Bool -> QualIdent -> FlatState Visibility-getVisibility isConstr qident-   = do public <- isPublic isConstr qident-	if public then return Public else return Private------getExportedImports :: FlatState [CS.IDecl]-getExportedImports-   = do mid  <- moduleId-	exps <- exports-	genExportedIDecls (Map.toList (getExpImports mid Map.empty exps))-----getExpImports :: ModuleIdent -> Map.Map ModuleIdent [CS.Export] -> [CS.Export]-		 -> Map.Map ModuleIdent [CS.Export]-getExpImports mident expenv [] = expenv-getExpImports mident expenv ((CS.Export qident):exps)-   = getExpImports mident -	           (bindExpImport mident qident (CS.Export qident) expenv) -		   exps-getExpImports mident expenv ((CS.ExportTypeWith qident idents):exps)-   = getExpImports mident -		   (bindExpImport mident -		                  qident -		                  (CS.ExportTypeWith qident idents) -		                  expenv)-		   exps-getExpImports mident expenv ((CS.ExportTypeAll qident):exps)-   = getExpImports mident -	 	   (bindExpImport mident qident (CS.ExportTypeAll qident) expenv) -		   exps-getExpImports mident expenv ((CS.ExportModule mident'):exps)-   = getExpImports mident (Map.insert mident' [] expenv) exps-----bindExpImport :: ModuleIdent -> QualIdent -> CS.Export -	         -> Map.Map ModuleIdent [CS.Export] -> Map.Map ModuleIdent [CS.Export]-bindExpImport mident qident export expenv-   | isJust (localIdent mident qident)-     = expenv-   | otherwise-     = let (Just mod) = qualidMod qident-       in  maybe (Map.insert mod [export] expenv)-	         (\es -> Map.insert mod (export:es) expenv) -		 (Map.lookup mod expenv)-----genExportedIDecls :: [(ModuleIdent,[CS.Export])] -> FlatState [CS.IDecl]-genExportedIDecls mes = genExpIDecls [] mes-----genExpIDecls :: [CS.IDecl] -> [(ModuleIdent,[CS.Export])] -> FlatState [CS.IDecl]-genExpIDecls idecls [] = return idecls-genExpIDecls idecls ((mid,exps):mes)-   = do intf_ <- lookupModuleIntf mid-	let idecls' = maybe idecls (p_genExpIDecls mid idecls exps) intf_-	genExpIDecls idecls' mes- where-   p_genExpIDecls mid idecls exps intf-      | null exps = (map (qualifyIDecl mid) intf) ++ idecls-      | otherwise = (filter (isExportedIDecl exps) -		            (map (qualifyIDecl mid) intf))-		    ++ idecls---- -isExportedIDecl :: [CS.Export] -> CS.IDecl -> Bool-isExportedIDecl exports (CS.IInfixDecl _ _ _ qident)-   = isExportedQualIdent qident exports-isExportedIDecl exports (CS.IDataDecl _ qident _ _)-   = isExportedQualIdent qident exports-isExportedIDecl exports (CS.ITypeDecl _ qident _ _)-   = isExportedQualIdent qident exports-isExportedIDecl exports (CS.IFunctionDecl _ qident _ _)-   = isExportedQualIdent qident exports-isExportedIDecl exports _-   = False-----isExportedQualIdent :: QualIdent -> [CS.Export] -> Bool-isExportedQualIdent qident [] = False-isExportedQualIdent qident ((CS.Export qident'):exps)-   = qident == qident' || isExportedQualIdent qident exps-isExportedQualIdent qident ((CS.ExportTypeWith qident' idents):exps)-   = qident == qident' || isExportedQualIdent qident exps-isExportedQualIdent qident ((CS.ExportTypeAll qident'):exps)-   = qident == qident' || isExportedQualIdent qident exps-isExportedQualIdent qident ((CS.ExportModule _):exps)-   = isExportedQualIdent qident exps-----qualifyIDecl :: ModuleIdent -> CS.IDecl -> CS.IDecl-qualifyIDecl mident (CS.IInfixDecl pos fix prec qident)-   = (CS.IInfixDecl pos fix prec (qualQualify mident qident))-qualifyIDecl mident (CS.IDataDecl pos qident idents cdecls)-   = (CS.IDataDecl pos (qualQualify mident qident) idents cdecls)-qualifyIDecl mident (CS.INewtypeDecl pos qident idents ncdecl)-   = (CS.INewtypeDecl pos (qualQualify mident qident) idents ncdecl)-qualifyIDecl mident (CS.ITypeDecl pos qident idents texpr)-   = (CS.ITypeDecl pos (qualQualify mident qident) idents texpr)-qualifyIDecl mident (CS.IFunctionDecl pos qident arity texpr)-   = (CS.IFunctionDecl pos (qualQualify mident qident) arity texpr)-qualifyIDecl _ idecl = idecl------typeArity :: IL.Type -> Int-typeArity (IL.TypeArrow _ t)       = 1 + (typeArity t)-typeArity (IL.TypeConstructor _ _) = 0-typeArity (IL.TypeVariable _)      = 0---------------------------------------------------------------------------------------genFlatApplication :: IL.Expression -> IL.Expression -> FlatState Expr-genFlatApplication e1 e2-   = genFlatApplic [e2] e1- where-   genFlatApplic args expression -      = case expression of-	  (IL.Apply expr1 expr2)    -	      -> genFlatApplic (expr2:args) expr1-	  (IL.Function qident _)-	      -> do arity_ <- lookupIdArity qident-                    qname <- visitQualIdent qident-		    maybe (internalError (funcArity qident))-			  (\arity -> genFuncCall qname arity args)-			  arity_-	  (IL.Constructor qident _)-	      -> do arity_ <- lookupIdArity qident-                    qname <- visitQualIdent qident-		    maybe (internalError (consArity qident))-			  (\arity -> genConsCall qname arity args)-			  arity_-	  _   -> do expr <- visitExpression expression-		    genApplicComb expr args-----genFuncCall :: QName -> Int -> [IL.Expression] -> FlatState Expr-genFuncCall qname arity args-   | arity > cnt -     = genComb qname args (FuncPartCall (arity - cnt))-   | arity < cnt -     = do let (funcargs, applicargs) = splitAt arity args-	  funccall <- genComb qname funcargs FuncCall-	  genApplicComb funccall applicargs-   | otherwise   -     = genComb qname args FuncCall- where cnt = length args-----genConsCall :: QName -> Int -> [IL.Expression] -> FlatState Expr-genConsCall qname arity args-   | arity > cnt -     = genComb qname args (ConsPartCall (arity - cnt))-   | arity < cnt-     = do let (funcargs, applicargs) = splitAt arity args-	  conscall <- genComb qname funcargs ConsCall-	  genApplicComb conscall applicargs-   | otherwise -     = genComb qname args ConsCall - where cnt = length args-----genComb :: QName -> [IL.Expression] -> CombType -> FlatState Expr-genComb qname args combtype-   = do exprs <- mapM visitExpression args-	return (Comb combtype qname exprs)-	 ----genApplicComb :: Expr -> [IL.Expression] -> FlatState Expr-genApplicComb expr [] = return expr-genApplicComb expr (e1:es)-   = do expr1 <- visitExpression e1-	qname <- visitQualIdent qidApply-	genApplicComb (Comb FuncCall qname [expr, expr1]) es- where- qidApply = qualifyWith preludeMIdent (mkIdent "apply")------genOpDecls :: FlatState [OpDecl]-genOpDecls = fixities >>= mapM genOpDecl-----genOpDecl :: CS.IDecl -> FlatState OpDecl-genOpDecl (CS.IInfixDecl _ fixity prec qident)-   = do qname <- visitQualIdent qident-	return (Op qname (p_genOpFixity fixity) prec)- where-   p_genOpFixity CS.InfixL = InfixlOp-   p_genOpFixity CS.InfixR = InfixrOp-   p_genOpFixity CS.Infix  = InfixOp-genOpDecl _ = internalError "GenFlatCurry: no infix interface"----- The intermediate language (IL) does not represent type synonyms--- (and also no record declarations). For this reason an interface--- representation of all type synonyms is generated (see "CurryEnv")--- from the abstract syntax representation of the Curry program.--- The function 'typeSynonyms' returns this list of type synonyms.-genTypeSynonyms ::  FlatState [TypeDecl]-genTypeSynonyms = typeSynonyms >>= mapM genTypeSynonym-----genTypeSynonym :: CS.IDecl -> FlatState TypeDecl-genTypeSynonym (CS.ITypeDecl _ qident params typeexpr)-   = do let is = [0 .. (length params) - 1]-        tyEnv <- gets typeEnvE-        tcEnv <- gets tConsEnvE-	let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr-	texpr <- visitType (fst (cs2ilType (zip params is) typeexpr'))-	qname <- visitQualTypeIdent qident-	vis   <- getVisibility False qident-	return (TypeSyn qname vis is texpr)-genTypeSynonym _ = internalError "GenFlatCurry: no type synonym interface"----- In order to provide an interface for record declarations, 'genRecordTypes'--- generates dummy data declarations representing records together--- with their typed labels. For the record declaration------      type Rec = {l_1 :: t_1,..., l_n :: t_n}------ the following data declaration will be generated:------      data Rec' = l_1' t_1 | ... | l_n' :: t_n------ Rec' and l_i' are unique idenfifiers which encode the original names--- Rec and l_i.--- When reading an interface file containing such declarations, it is--- now possible to reconstruct the original record declaration. Since--- usual FlatCurry code is used, these declaration should not have any--- effects on the behaviour of the Curry program. But to ensure correctness,--- these dummies should be generated for the interface file as well as for--- the corresponding FlatCurry file.-genRecordTypes :: FlatState [TypeDecl]-genRecordTypes = records >>= mapM genRecordType-----genRecordType :: CS.IDecl -> FlatState TypeDecl-genRecordType (CS.ITypeDecl _ qident params (CS.RecordType fields _))-   = do let is = [0 .. (length params) - 1]-	    (mod,ident) = (qualidMod qident, qualidId qident)-	qname <- visitQualIdent ((maybe qualify qualifyWith mod) -				 (recordExtId ident))-	labels <- mapM (genRecordLabel mod (zip params is)) fields-	return (Type qname Public is labels)-----genRecordLabel :: Maybe ModuleIdent -> [(Ident,Int)] -> ([Ident],CS.TypeExpr) -	       -> FlatState ConsDecl-genRecordLabel mod vis ([ident],typeexpr)-   = do tyEnv <- gets typeEnvE-        tcEnv <- gets tConsEnvE-	let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr-        texpr <- visitType (fst (cs2ilType vis typeexpr'))-	qname <- visitQualIdent ((maybe qualify qualifyWith mod) -				 (labelExtId ident))-	return (Cons qname 1 Public [texpr])-------------------------------------------------------------------------------------- FlatCurry provides no possibility of representing record types like--- {l_1::t_1, l_2::t_2, ..., l_n::t_n}. So they have to be transformed to--- to the corresponding type constructors which are defined in the record --- declarations. --- Unlike data declarations or function type annotations, type synonyms and--- record declarations are not generated from the intermediate language.--- So the transformation has only to be performed in these cases.-elimRecordTypes :: ValueEnv -> TCEnv -> CS.TypeExpr -> CS.TypeExpr-elimRecordTypes tyEnv tcEnv (CS.ConstructorType qid typeexprs)-   = CS.ConstructorType qid (map (elimRecordTypes tyEnv tcEnv) typeexprs)-elimRecordTypes tyEnv tcEnv (CS.VariableType id)-   = CS.VariableType id-elimRecordTypes tyEnv tcEnv (CS.TupleType typeexprs)-   = CS.TupleType (map (elimRecordTypes tyEnv tcEnv) typeexprs)-elimRecordTypes tyEnv tcEnv (CS.ListType typeexpr)-   = CS.ListType (elimRecordTypes tyEnv tcEnv typeexpr)-elimRecordTypes tyEnv tcEnv (CS.ArrowType typeexpr1 typeexpr2)-   = CS.ArrowType (elimRecordTypes tyEnv tcEnv typeexpr1)-                  (elimRecordTypes tyEnv tcEnv typeexpr2)-elimRecordTypes tyEnv tcEnv (CS.RecordType fss _)-   = let fs = flattenRecordTypeFields fss-     in  case (lookupValue (fst (head fs)) tyEnv) of-  	   [Label _ record _] ->-	     case (qualLookupTC record tcEnv) of-	       [AliasType _ n (TypeRecord fs' _)] ->-	         let ms = foldl (matchTypeVars fs) Map.empty fs'-		     types = map (\i -> maybe -			 	          (CS.VariableType -					     (mkIdent ("#tvar" ++ show i)))-				          (elimRecordTypes tyEnv tcEnv)-				          (Map.lookup i ms))-			         [0 .. n-1]-	         in  CS.ConstructorType record types-	       _ -> internalError ("GenFlatCurry.elimRecordTypes: "-		 		   ++ "no record type")-	   _ -> internalError ("GenFlatCurry.elimRecordTypes: "-			       ++ "no label")--matchTypeVars :: [(Ident,CS.TypeExpr)] -> Map.Map Int CS.TypeExpr-	      -> (Ident, Type) -> Map.Map Int CS.TypeExpr-matchTypeVars fs ms (l,ty)-   = maybe ms (match ms ty) (lookup l fs)-  where-  match ms (TypeVariable i) typeexpr = Map.insert i typeexpr ms-  match ms (TypeConstructor _ tys) (CS.ConstructorType _ typeexprs)-     = matchList ms tys typeexprs-  match ms (TypeConstructor _ tys) (CS.ListType typeexpr)-     = matchList ms tys [typeexpr]-  match ms (TypeConstructor _ tys) (CS.TupleType typeexprs)-     = matchList ms tys typeexprs-  match ms (TypeArrow ty1 ty2) (CS.ArrowType typeexpr1 typeexpr2)-     = matchList ms [ty1,ty2] [typeexpr1,typeexpr2]-  match ms (TypeRecord fs' _) (CS.RecordType fss _)-     = foldl (matchTypeVars (flattenRecordTypeFields fss)) ms fs'-  match ms ty typeexpr-     = internalError ("GenFlatCurry.matchTypeVars: "-		      ++ show ty ++ "\n" ++ show typeexpr)--  matchList ms tys-     = foldl (\ms' (ty,typeexpr) -> match ms' ty typeexpr) ms . zip tys---flattenRecordTypeFields :: [([Ident],CS.TypeExpr)] -> [(Ident,CS.TypeExpr)]-flattenRecordTypeFields-   = concatMap (\ (labels, typeexpr)-		-> map (\label -> (label,typeexpr)) labels)--------------------------------------------------------------------------------------checkOverlapping :: Expr -> Expr -> FlatState ()-checkOverlapping expr1 expr2-   = do opts <- compilerOpts-	unless (noOverlapWarn opts)-	       (checkOverlap expr1 expr2)- where- checkOverlap (Case _ _ _ _) _ -    = do qid <- functionId-	 genWarning (overlappingRules qid)- checkOverlap _ (Case _ _ _ _)-    = do qid <- functionId-	 genWarning (overlappingRules qid)- checkOverlap _ _ = return ()-------------------------------------------------------------------------------------- -cs2ilType :: [(Ident,Int)] -> CS.TypeExpr -> (IL.Type, [(Ident,Int)])-cs2ilType ids (CS.ConstructorType qident typeexprs)-   = let (ilTypeexprs, ids') = emap cs2ilType ids typeexprs-     in  (IL.TypeConstructor qident ilTypeexprs, ids')-cs2ilType ids (CS.VariableType ident)-   = let mid        = lookup ident ids-	 nid        | null ids  = 0-		    | otherwise = 1 + snd (head ids)-	 (id, ids') | isJust mid = (fromJust mid, ids)-		    | otherwise  = (nid, (ident, nid):ids)-     in  (IL.TypeVariable id, ids')-cs2ilType ids (CS.ArrowType type1 type2)-   = let (ilType1, ids')  = cs2ilType ids type1-	 (ilType2, ids'') = cs2ilType ids' type2-     in  (IL.TypeArrow ilType1 ilType2, ids'')-cs2ilType ids (CS.ListType typeexpr)-   = let (ilTypeexpr, ids') = cs2ilType ids typeexpr-     in  (IL.TypeConstructor (qualify listId) [ilTypeexpr], ids')-cs2ilType ids (CS.TupleType typeexprs)-   = case typeexprs of-       []  -> (IL.TypeConstructor qUnitId [], ids)-       [t] -> cs2ilType ids t-       _   -> let (ilTypeexprs, ids') = emap cs2ilType ids typeexprs-		  tuplen = length ilTypeexprs-	      in  (IL.TypeConstructor (qTupleId tuplen) ilTypeexprs,-		   ids')-cs2ilType _ typeexpr = internalError ("cs2ilType: " ++ show typeexpr)------------------------------------------------------------------------------------- Messages for internal errors and warnings--funcArity qid = "GenFlatCurry: missing arity for function \"" -		++ show qid ++ "\""--consArity qid = "GenFlatCurry: missing arity for constructor \""-		++ show qid ++ "\""--missingVarIndex id = "GenFlatCurry: missing index for \"" ++ show id ++ "\""---overlappingRules qid =  "function \""-		        ++ qualName qid -		        ++ "\" is non-deterministic due to non-trivial "-		        ++ "overlapping rules"-----------------------------------------------------------------------------------------------------------------------------------------------------------------------isDataDecl :: IL.Decl -> Bool-isDataDecl (IL.DataDecl _ _ _) = True-isDataDecl _                = False-----isFuncDecl :: IL.Decl -> Bool-isFuncDecl (IL.FunctionDecl _ _ _ _) = True-isFuncDecl (IL.ExternalDecl _ _ _ _) = True-isFuncDecl _                         = False-----isPublicDataDecl :: IL.Decl -> FlatState Bool-isPublicDataDecl (IL.DataDecl qident _ _ ) = isPublic False qident-isPublicDataDecl _                         = return False-----isPublicFuncDecl :: IL.Decl -> FlatState Bool-isPublicFuncDecl (IL.FunctionDecl qident _ _ _) = isPublic False qident-isPublicFuncDecl (IL.ExternalDecl qident _ _ _) = isPublic False qident-isPublicFuncDecl _                              = return False-----isTypeIDecl :: CS.IDecl -> Bool-isTypeIDecl (CS.IDataDecl _ _ _ _) = True-isTypeIDecl (CS.ITypeDecl _ _ _ _) = True-isTypeIDecl _                      = False-----isRecordIDecl :: CS.IDecl -> Bool-isRecordIDecl (CS.ITypeDecl _ _ _ (CS.RecordType (_:_) _)) = True-isRecordIDecl _                                            = False-----isFuncIDecl :: CS.IDecl -> Bool-isFuncIDecl (CS.IFunctionDecl _ _ _ _) = True-isFuncIDecl _                          = False-----isOpIDecl :: CS.IDecl -> Bool-isOpIDecl (CS.IInfixDecl _ _ _ _) = True-isOpIDecl _                       = False ------bindingIdent :: IL.Binding -> Ident-bindingIdent (IL.Binding ident _) = ident-------------------------------------------------------------------------------------------------------------------------------------------------------------------emap :: (e -> a -> (b,e)) -> e -> [a] -> ([b], e)-emap _ env []     = ([], env)-emap f env (x:xs) = let (x',env')    = f env x-			(xs', env'') = emap f env' xs-		    in  ((x':xs'), env'')----------------------------------------------------------------------------------------------------------------------------------------------------------------------moduleId :: FlatState ModuleIdent-moduleId = gets moduleIdE-----functionId :: FlatState QualIdent-functionId = gets (fst . functionIdE)-----setFunctionId :: (QualIdent, [(Ident, IL.Type)]) -> FlatState ()-setFunctionId qid = modify (\env -> env{ functionIdE = qid })-----compilerOpts :: FlatState Options-compilerOpts = gets compilerOptsE-----exports :: FlatState [CS.Export]-exports = gets exportsE-----imports :: FlatState [CS.IDecl]-imports = gets importsE-----records :: FlatState [CS.IDecl]-records = gets (filter isRecordIDecl . interfaceE)-----fixities :: FlatState [CS.IDecl]-fixities = gets fixitiesE-----typeSynonyms :: FlatState [CS.IDecl]-typeSynonyms = gets typeSynonymsE-----isPublic :: Bool -> QualIdent -> FlatState Bool-isPublic isConstr qid = gets (\env -> maybe False isP-                                      (Map.lookup (unqualify qid) -                                       (publicEnvE env)))-  where-    isP NotConstr = not isConstr-    isP OnlyConstr = isConstr-    isP NotOnlyConstr = True-----lookupModuleIntf :: ModuleIdent -> FlatState (Maybe [CS.IDecl])-lookupModuleIntf mid-   = gets (Map.lookup mid . moduleEnvE)-----lookupIdArity :: QualIdent -> FlatState (Maybe Int)-lookupIdArity qid-   = gets (lookupA qid . arityEnvE)- where- lookupA qid aEnv = case (qualLookupArity qid aEnv) of-		      [ArityInfo _ a]-		         -> Just a-		      [] -> case (lookupArity (unqualify qid) aEnv) of-			      [ArityInfo _ a] -> Just a-			      _               -> Nothing-		      _  -> Nothing----getTypeOf :: Ident -> FlatState (Maybe TypeExpr)-getTypeOf ident = do-    valEnv <- gets typeEnvE -    case lookupValue ident valEnv of -      Value _ (ForAll _ t) : _ -          -> do t <- visitType (ttrans t)-                trace' ("getTypeOf(" ++ show ident ++ ") = " ++ show t)$-                       return (Just t)-      DataConstructor _ (ForAllExist _ _ t):_ -          -> do t <- visitType (ttrans t)-                trace' ("getTypeOfDataCon(" ++ show ident ++ ") = " ++ show t)$-                       return (Just t)-      _   -> do (_,ats) <- gets functionIdE-                case lookup ident ats of-                  Just t -> liftM Just (visitType t)-                  Nothing -> trace' ("lookupValue did not return a value for index " ++ show ident)-                             (return Nothing)-ttrans :: Type -> IL.Type -ttrans (TypeConstructor i ts)-    = IL.TypeConstructor i (map ttrans ts)-ttrans (TypeVariable v)-    = IL.TypeVariable v-ttrans (TypeConstrained [] v)-    = IL.TypeVariable v-ttrans (TypeConstrained (v:_) i)-    = ttrans v-ttrans (TypeArrow f x) = IL.TypeArrow (ttrans f) (ttrans x)-ttrans s@(TypeSkolem _) = error $ "in ttrans: " ++ show s-ttrans s@(TypeRecord _ _) = error $ "in ttrans: " ++ show s------ Constructor (:) receives special treatment throughout the--- whole implementation. We won't depart from that for mere--- aesthetic reasons. (hsi)-lookupIdType :: QualIdent -> FlatState (Maybe TypeExpr)-lookupIdType (QualIdent Nothing (Ident _ "[]" _))-    = return (Just l0)-      where l0 = TCons (mkQName ("Prelude", "[]")) [TVar 0]-lookupIdType (QualIdent Nothing (Ident _ ":" _))-    = return (Just (FuncType (TVar 0) (FuncType (l0) (l0))))-      where l0 = TCons (mkQName ("Prelude", "[]")) [TVar 0]-lookupIdType (QualIdent Nothing (Ident _ "()" _))-    = return (Just l0)-      where l0 = TCons (mkQName ("Prelude", "()")) []-lookupIdType (QualIdent Nothing (Ident _ t@('(':',':r) _))-    = return (Just funtype)-      where tupleArity = length r + 1-            argTypes   = map TVar [1..tupleArity]-            contype    = TCons (mkQName ("Prelude", t)) argTypes-            funtype    = foldr FuncType contype argTypes-lookupIdType qid-   = do aEnv <- gets typeEnvE-        lt <- gets localTypes-        ct <- gets constrTypes-        case Map.lookup qid lt `mplus` Map.lookup qid ct of-          Just t -> trace' ("lookupIdType local " ++ show (qid, t)) $ liftM Just (visitType t)  -- local name or constructor-          Nothing -> case [ t | Value _ (ForAll _ t) <- qualLookupValue qid aEnv ] of -                       t : _ -> liftM Just (visitType (IL.translType t))  -- imported name-                       []    -> case qualidMod qid of-                                  Nothing -> trace' ("no type for "  ++ show qid) $ return Nothing  -- no known type-                                  Just _ -> lookupIdType qid {qualidMod = Nothing}--- ---- Generates a new index for a variable-newVarIndex :: Ident -> FlatState VarIndex-newVarIndex ident-   = do idx0 <- gets varIndexE-        ty <- getTypeOf ident-        let idx = idx0 + 1-            vid = VarIndex ty idx-        vids <- gets varIdsE-        modify (\env -> env{ varIndexE = idx,-			     varIdsE   = ScopeEnv.insert ident vid vids-			   })-        return vid-----lookupVarIndex :: Ident -> FlatState VarIndex-lookupVarIndex id-   = do index_ <- gets (ScopeEnv.lookup id . varIdsE)-        maybe (internalError (missingVarIndex id)) return index_-----clearVarIndices :: FlatState ()-clearVarIndices = modify (\env -> env { varIndexE = 0,-				        varIdsE = ScopeEnv.new -				      })-----genWarning :: String -> FlatState ()-genWarning msg-   = modify (\env -> env{ messagesE = warnMsg:(messagesE env) })-    where warnMsg = WarnMsg Nothing msg-----genInterface :: FlatState Bool-genInterface = gets genInterfaceE-----beginScope :: FlatState ()-beginScope = modify-	       (\env -> env { varIdsE  = ScopeEnv.beginScope (varIdsE env)-			    })-----endScope :: FlatState ()-endScope = modify-	     (\env -> env { varIdsE  = ScopeEnv.endScope (varIdsE env)-			  })-----whenFlatCurry :: FlatState a -> FlatState a -> FlatState a-whenFlatCurry genFlat genIntf -   = genInterface >>= (\intf -> if intf then genIntf else genFlat)-------------------------------------------------------------------------------------- Generates an evironment containing all public identifiers from the module--- Note: Currently the record functions (selection and update) for all public --- record labels are inserted into the environment, though they are not--- explicitly declared in the export specifications.-genPubEnv :: ModuleIdent -> [CS.IDecl] -> Map.Map Ident IdentExport-genPubEnv mid idecls = foldl (bindEnvIDecl mid) Map.empty idecls--bindIdentExport :: Ident -> Bool -> Map.Map Ident IdentExport -> Map.Map Ident IdentExport-bindIdentExport id isConstr env =-    maybe (Map.insert id (if isConstr then OnlyConstr else NotConstr) env)-          (\ ie -> Map.insert id (updateIdentExport ie isConstr) env)-          (Map.lookup id env)-  where-    updateIdentExport OnlyConstr True  = OnlyConstr-    updateIdentExport OnlyConstr False = NotOnlyConstr-    updateIdentExport NotConstr True   = NotOnlyConstr-    updateIdentExport NotConstr False  = NotConstr-    updateIdentExport NotOnlyConstr _  = NotOnlyConstr------bindEnvIDecl :: ModuleIdent -> Map.Map Ident IdentExport -> CS.IDecl -> Map.Map Ident IdentExport-bindEnvIDecl mid env (CS.IDataDecl _ qid _ mcdecls)-   = maybe env -           (\id -> foldl bindEnvConstrDecl-	                 (bindIdentExport id False env)-	                 (catMaybes mcdecls))-	   (localIdent mid qid)-bindEnvIDecl mid env (CS.INewtypeDecl _ qid _ ncdecl)-   = maybe env -           (\id -> bindEnvNewConstrDecl (bindIdentExport id False env) ncdecl)-	   (localIdent mid qid)-bindEnvIDecl mid env (CS.ITypeDecl _ qid _ texpr)-   = maybe env (\id -> bindEnvITypeDecl env id texpr) (localIdent mid qid)-bindEnvIDecl mid env (CS.IFunctionDecl _ qid _ _)-   = maybe env (\id -> bindIdentExport id False env) (localIdent mid qid)-bindEnvIDecl _ env _ = env-----bindEnvITypeDecl :: Map.Map Ident IdentExport -> Ident -> CS.TypeExpr-		    -> Map.Map Ident IdentExport-bindEnvITypeDecl env id (CS.RecordType fs _)-   = bindIdentExport id False (foldl (bindEnvRecordLabel id) env fs)-bindEnvITypeDecl env id texpr-   = bindIdentExport id False env-----bindEnvConstrDecl :: Map.Map Ident IdentExport -> CS.ConstrDecl -> Map.Map Ident IdentExport-bindEnvConstrDecl env (CS.ConstrDecl _ _ id _)  = bindIdentExport id True env-bindEnvConstrDecl env (CS.ConOpDecl _ _ _ id _) = bindIdentExport id True env-----bindEnvNewConstrDecl :: Map.Map Ident IdentExport -> CS.NewConstrDecl -> Map.Map Ident IdentExport-bindEnvNewConstrDecl env (CS.NewConstrDecl _ _ id _) = bindIdentExport id False env-----bindEnvRecordLabel :: Ident -> Map.Map Ident IdentExport -> ([Ident],CS.TypeExpr) -> Map.Map Ident IdentExport-bindEnvRecordLabel r env ([lab], _) = bindIdentExport (recSelectorId (qualify r) lab) False expo-    where -      expo = (bindIdentExport (recUpdateId (qualify r) lab) False env)---splitoffArgTypes :: IL.Type -> [Ident] -> [(Ident, IL.Type)]-splitoffArgTypes (IL.TypeArrow l r) (i:is) = (i, l):splitoffArgTypes r is-splitoffArgTypes _ [] = []-splitoffArgTypes _ _  = error "internal error in splitoffArgTypes"--
+ src/Generators.hs view
@@ -0,0 +1,51 @@+{- |+    Module      :  $Header$+    Description :  Code generators+    Copyright   :  (c) 2011        Björn Peemöller+                       2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module subsumes the different code generators.+-}+module Generators where++import qualified Curry.AbstractCurry              as AC   (CurryProg)+import qualified Curry.FlatCurry.Type             as FC   (Prog)+import qualified Curry.FlatCurry.Annotated.Type   as AFC  (AProg, TypeExpr)+import qualified Curry.Syntax                     as CS   (Module)++import qualified Generators.GenAbstractCurry      as GAC  (genAbstractCurry)+import qualified Generators.GenFlatCurry          as GFC  ( genFlatCurry+                                                          , genFlatInterface+                                                          )+import qualified Generators.GenTypedFlatCurry     as GTFC (genTypedFlatCurry)++import           Base.Types                          (Type, PredType)++import           CompilerEnv                         (CompilerEnv (..))+import qualified IL                                  (Module)++-- |Generate typed AbstractCurry+genTypedAbstractCurry :: CompilerEnv -> CS.Module PredType -> AC.CurryProg+genTypedAbstractCurry = GAC.genAbstractCurry False++-- |Generate untyped AbstractCurry+genUntypedAbstractCurry :: CompilerEnv -> CS.Module PredType -> AC.CurryProg+genUntypedAbstractCurry = GAC.genAbstractCurry True++-- |Generate typed FlatCurry+genTypedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module+                  -> AFC.AProg AFC.TypeExpr+genTypedFlatCurry = GTFC.genTypedFlatCurry++-- |Generate FlatCurry+genFlatCurry :: AFC.AProg a -> FC.Prog+genFlatCurry = GFC.genFlatCurry++-- |Generate a FlatCurry interface+genFlatInterface :: FC.Prog -> FC.Prog+genFlatInterface = GFC.genFlatInterface
+ src/Generators/GenAbstractCurry.hs view
@@ -0,0 +1,532 @@+{- |+    Module      :  $Header$+    Description :  Generation of AbstractCurry program terms+    Copyright   :  (c) 2005        Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2015        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module contains the generation of an 'AbstractCurry' program term+    for a given 'Curry' module.+-}+{-# LANGUAGE CPP #-}+module Generators.GenAbstractCurry (genAbstractCurry) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative          ((<$>), (<*>), pure)+#endif+import           Control.Monad.Extra+import qualified Control.Monad.State as S     (State, evalState, get, gets+                                              , modify, put, when)+import qualified Data.Map            as Map   (Map, empty, fromList, lookup+                                              , union)+import qualified Data.Maybe          as Maybe (fromJust, fromMaybe, listToMaybe)+import qualified Data.Set            as Set   (Set, empty, insert, member)+import qualified Data.Traversable    as T     (forM)++import Curry.AbstractCurry+import Curry.Base.Ident+import Curry.Syntax++import Base.CurryTypes (fromPredType, toType, toPredType)+import Base.Expr       (bv)+import Base.Messages   (internalError)+import Base.NestEnv+import Base.Types      (arrowArity, PredType, unpredType, TypeScheme (..))+import Base.TypeSubst++import Env.Value       (ValueEnv, ValueInfo (..), qualLookupValue)+import Env.OpPrec      (mkPrec)++import CompilerEnv++type GAC a = S.State AbstractEnv a++-- ---------------------------------------------------------------------------+-- Interface+-- ---------------------------------------------------------------------------++-- |Generate an AbstractCurry program term from the syntax tree+--  when uacy flag is set untype AbstractCurry is generated+genAbstractCurry :: Bool -> CompilerEnv -> Module PredType -> CurryProg+genAbstractCurry uacy env mdl+  = S.evalState (trModule mdl) (abstractEnv uacy env mdl)++-- ---------------------------------------------------------------------------+-- Conversion from Curry to AbstractCurry+-- ---------------------------------------------------------------------------++trModule :: Module PredType -> GAC CurryProg+trModule (Module _ mid _ is ds) = do+  CurryProg mid' is' <$> dflt' <*> cds' <*> ids' <*> ts' <*> fs' <*> os'+  where+  mid'  = moduleName mid+  is'   = map cvImportDecl is+  dflt' = Maybe.listToMaybe <$> concatMapM (withLocalEnv . trDefaultDecl) ds+  cds'  = concatMapM (withLocalEnv . trClassDecl) ds+  ids'  = concatMapM (withLocalEnv . trInstanceDecl) ds+  ts'   = concatMapM (withLocalEnv . trTypeDecl) ds+  fs'   = concatMapM (withLocalEnv . trFuncDecl True) ds+  os'   = concatMapM (withLocalEnv . trInfixDecl) ds++cvImportDecl :: ImportDecl -> String+cvImportDecl (ImportDecl _ mid _ _ _) = moduleName mid++trDefaultDecl :: Decl a -> GAC [CDefaultDecl]+trDefaultDecl (DefaultDecl _ tys) = (\tys' -> [CDefaultDecl tys'])+  <$> mapM trTypeExpr tys+trDefaultDecl _                   = return []++trClassDecl :: Decl PredType -> GAC [CClassDecl]+trClassDecl (ClassDecl _ cx cls tv ds) = do+  (\cls' v' cx' tv' ds' -> [CClass cls' v' cx' tv' ds'])+    <$> trGlobalIdent cls <*> getTypeVisibility cls <*> trContext cx+    <*> getTVarIndex tv <*> concatMapM (trClassMethodDecl sigs fs) ds+  where fs = [f | FunctionDecl _ _ f _ <- ds]+        sigs = signatures ds+trClassDecl _ = return []++-- We ignore type signatures for class methods with a given default+-- implementation as declarations for those are generated anyway.+-- For function declarations we use the equation's arity instead of+-- the one from the value environment or 0.+trClassMethodDecl :: [(Ident, QualTypeExpr)] -> [Ident] -> Decl PredType+                  -> GAC [CFuncDecl]+trClassMethodDecl sigs fs (TypeSig p [f] _) | f `notElem` fs =+  trClassMethodDecl sigs fs $ FunctionDecl p undefined f []+trClassMethodDecl sigs fs (TypeSig p (f:f':fs') qty) = do+  liftM2 (++) (trClassMethodDecl sigs fs $ TypeSig p [f] qty)+              (trClassMethodDecl sigs fs $ TypeSig p (f':fs') qty)+trClassMethodDecl sigs _ (FunctionDecl _ _ f eqs) =+  (\f' a v ty rs -> [CFunc f' a v ty rs]) <$> trGlobalIdent f+  <*> pure (maybe 0 eqnArity $ Maybe.listToMaybe eqs)+  <*> getVisibility (unRenameIdent f)+  <*> trQualTypeExpr (Maybe.fromJust $ lookup f sigs) <*> mapM trEquation eqs+trClassMethodDecl _ _ _ = return []++trInstanceDecl :: Decl PredType -> GAC [CInstanceDecl]+trInstanceDecl (InstanceDecl _ cx qcls ty ds) =+  (\qcls' cx' ty' ds' -> [CInstance qcls' cx' ty' ds']) <$> trQual qcls+  <*> trContext cx <*> trTypeExpr ty <*> mapM (trInstanceMethodDecl qcls ty) ds+trInstanceDecl _ = return []++-- Again, we use the equation's arity for function declarations instead of+-- the one from the value.+trInstanceMethodDecl :: QualIdent -> TypeExpr -> Decl PredType -> GAC CFuncDecl+trInstanceMethodDecl qcls ty (FunctionDecl _ _ f eqs) = do+  uacy <- S.gets untypedAcy+  qty <- if uacy+           then return $ QualTypeExpr [] $ ConstructorType prelUntyped+           else getQualType' (qualifyLike qcls $ unRenameIdent f)+  CFunc <$> trLocalIdent f <*> pure (eqnArity $ head eqs) <*> pure Public+        <*> trInstanceMethodType ty qty <*> mapM trEquation eqs+trInstanceMethodDecl _ _ _ = internalError "GenAbstractCurry.trInstanceMethodDecl"++-- Transforms a class method type into an instance method's type by replacing+-- the class variable with the given instance type. The implicit class context+-- is dropped in doing so.+trInstanceMethodType :: TypeExpr -> QualTypeExpr -> GAC CQualTypeExpr+trInstanceMethodType ity (QualTypeExpr cx ty) =+  trQualTypeExpr $ fromPredType identSupply $+    subst (bindSubst 0 (toType [] ity) idSubst) $+      toPredType (take 1 identSupply) $ QualTypeExpr (drop 1 cx) ty++trTypeDecl :: Decl a -> GAC [CTypeDecl]+trTypeDecl (DataDecl    _ t vs cs clss) =+  (\t' v vs' cs' clss' -> [CType t' v vs' cs' clss'])+  <$> trGlobalIdent t <*> getTypeVisibility t+  <*> mapM genTVarIndex vs <*> mapM trConsDecl cs+  <*> mapM trQual clss+trTypeDecl (TypeDecl    _ t vs ty) = (\t' v vs' ty' -> [CTypeSyn t' v vs' ty'])+  <$> trGlobalIdent t <*> getTypeVisibility t+  <*> mapM genTVarIndex vs <*> trTypeExpr ty+trTypeDecl (NewtypeDecl _ t vs nc clss) =+  (\t' v vs' nc' clss' -> [CNewType t' v vs' nc' clss'])+  <$> trGlobalIdent t <*> getTypeVisibility t+  <*> mapM genTVarIndex vs <*> trNewConsDecl nc+  <*> mapM trQual clss+trTypeDecl _                       = return []++trConsDecl :: ConstrDecl -> GAC CConsDecl+trConsDecl (ConstrDecl  _ vs cx c tys) = inNestedTScope $ CCons+  <$> mapM genTVarIndex vs <*> trContext cx <*> trGlobalIdent c+  <*> getVisibility c <*> mapM trTypeExpr tys+trConsDecl (ConOpDecl p vs cx ty1 op ty2) = inNestedTScope $ trConsDecl $+  ConstrDecl p vs cx op [ty1, ty2]+trConsDecl (RecordDecl   _ vs cx c fs) = inNestedTScope $ CRecord+  <$> mapM genTVarIndex vs <*> trContext cx <*> trGlobalIdent c+  <*> getVisibility c <*> concatMapM trFieldDecl fs++trFieldDecl :: FieldDecl -> GAC [CFieldDecl]+trFieldDecl (FieldDecl _ ls ty) = T.forM ls $ \l ->+  CField <$> trGlobalIdent l <*> getVisibility l <*> trTypeExpr ty++trNewConsDecl :: NewConstrDecl -> GAC CConsDecl+trNewConsDecl (NewConstrDecl _ nc      ty) = CCons [] (CContext [])+  <$> trGlobalIdent nc <*> getVisibility nc <*> ((:[]) <$> trTypeExpr ty)+trNewConsDecl (NewRecordDecl p nc (l, ty)) = CRecord [] (CContext [])+  <$> trGlobalIdent nc <*> getVisibility nc <*> trFieldDecl (FieldDecl p [l] ty)++trTypeExpr :: TypeExpr -> GAC CTypeExpr+trTypeExpr (ConstructorType q) = CTCons <$> trQual q+trTypeExpr (ApplyType ty1 ty2) = CTApply <$> trTypeExpr ty1 <*> trTypeExpr ty2+trTypeExpr (VariableType    v) = CTVar  <$> getTVarIndex v+trTypeExpr (TupleType     tys) =+  trTypeExpr $ foldl ApplyType (ConstructorType $ qTupleId $ length tys) tys+trTypeExpr (ListType       ty) =+  trTypeExpr $ ApplyType (ConstructorType qListId) ty+trTypeExpr (ArrowType ty1 ty2) = CFuncType <$> trTypeExpr ty1 <*> trTypeExpr ty2+trTypeExpr (ParenType      ty) = trTypeExpr ty+trTypeExpr (ForallType    _ _) = internalError "GenAbstractCurry.trTypeExpr"++trConstraint :: Constraint -> GAC CConstraint+trConstraint (Constraint q ty) = (,) <$> trQual q <*> trTypeExpr ty++trContext :: Context -> GAC CContext+trContext cx = CContext <$> mapM trConstraint cx++trQualTypeExpr :: QualTypeExpr -> GAC CQualTypeExpr+trQualTypeExpr (QualTypeExpr cx ty) =+  CQualType <$> trContext cx <*> trTypeExpr ty++trInfixDecl :: Decl a -> GAC [COpDecl]+trInfixDecl (InfixDecl _ fix mprec ops) = mapM trInfix (reverse ops)+  where+  trInfix op = COp <$> trGlobalIdent op <*> return (cvFixity fix)+                   <*> return (fromInteger (mkPrec mprec))+  cvFixity InfixL = CInfixlOp+  cvFixity InfixR = CInfixrOp+  cvFixity Infix  = CInfixOp+trInfixDecl _ = return []++trFuncDecl :: Bool -> Decl PredType -> GAC [CFuncDecl]+trFuncDecl global (FunctionDecl  _ pty f eqs)+  =   (\f' a v ty rs -> [CFunc f' a v ty rs])+  <$> trFuncName global f <*> pure (eqnArity $ head eqs) <*> getVisibility f+  <*> getQualType f pty <*> mapM trEquation eqs+trFuncDecl global (ExternalDecl         _ vs)+  =   T.forM vs $ \(Var pty f) -> CFunc+  <$> trFuncName global f <*> pure (arrowArity $ unpredType pty)+  <*> getVisibility f <*> getQualType f pty <*> return []+trFuncDecl _      _                           = return []++trFuncName :: Bool -> Ident -> GAC QName+trFuncName global = if global then trGlobalIdent else trLocalIdent++trEquation :: Equation PredType -> GAC CRule+trEquation (Equation _ lhs rhs) = inNestedScope+                                $ CRule <$> trLhs lhs <*> trRhs rhs++trLhs :: Lhs a -> GAC [CPattern]+trLhs = mapM trPat . snd . flatLhs++trRhs :: Rhs PredType -> GAC CRhs+trRhs (SimpleRhs _ e ds) = inNestedScope $ do+  mapM_ insertDeclLhs ds+  CSimpleRhs <$> trExpr e <*> concatMapM trLocalDecl ds+trRhs (GuardedRhs gs ds) = inNestedScope $ do+  mapM_ insertDeclLhs ds+  CGuardedRhs <$> mapM trCondExpr gs <*> concatMapM trLocalDecl ds++trCondExpr :: CondExpr PredType -> GAC (CExpr, CExpr)+trCondExpr (CondExpr _ g e) = (,) <$> trExpr g <*> trExpr e++trLocalDecls :: [Decl PredType] -> GAC [CLocalDecl]+trLocalDecls ds = do+  mapM_ insertDeclLhs ds+  concatMapM trLocalDecl ds++-- Insert all variables declared in local declarations+insertDeclLhs :: Decl a -> GAC ()+insertDeclLhs   (PatternDecl      _ p _) = mapM_ genVarIndex (bv p)+insertDeclLhs   (FreeDecl          _ vs) = mapM_ genVarIndex (map varIdent vs)+insertDeclLhs s@(TypeSig          _ _ _) = do+  uacy <- S.gets untypedAcy+  S.when uacy (insertSig s)+insertDeclLhs _                          = return ()++trLocalDecl :: Decl PredType -> GAC [CLocalDecl]+trLocalDecl f@(FunctionDecl    _ _ _ _) = map CLocalFunc <$> trFuncDecl False f+trLocalDecl f@(ExternalDecl        _ _) = map CLocalFunc <$> trFuncDecl False f+trLocalDecl (PatternDecl       _ p rhs) = (\p' rhs' -> [CLocalPat p' rhs'])+                                          <$> trPat p <*> trRhs rhs+trLocalDecl (FreeDecl             _ vs) = (\vs' -> [CLocalVars vs'])+                                          <$> mapM getVarIndex (map varIdent vs)+trLocalDecl _                           = return [] -- can not occur (types etc.)++insertSig :: Decl a -> GAC ()+insertSig (TypeSig _ fs qty) = do+  sigs <- S.gets typeSigs+  let lsigs = Map.fromList [(f, qty) | f <- fs]+  S.modify $ \env -> env { typeSigs = sigs `Map.union` lsigs }+insertSig _                 = return ()++trExpr :: Expression PredType -> GAC CExpr+trExpr (Literal       _ l) = return (CLit $ cvLiteral l)+trExpr (Variable      _ v)+  | isQualified v = CSymbol <$> trQual v+  | otherwise     = lookupVarIndex (unqualify v) >>= \mvi -> case mvi of+    Just vi -> return (CVar vi)+    _       -> CSymbol <$> trQual v+trExpr (Constructor   _ c) = CSymbol <$> trQual c+trExpr (Paren           e) = trExpr e+trExpr (Typed       e qty) = CTyped <$> trExpr e <*> trQualTypeExpr qty+trExpr (Record     _ c fs) = CRecConstr <$> trQual c+                                        <*> mapM (trField trExpr) fs+trExpr (RecordUpdate e fs) = CRecUpdate <$> trExpr e+                                        <*> mapM (trField trExpr) fs+trExpr (Tuple          es) =+  trExpr $ apply (Variable undefined $ qTupleId $ length es) es+trExpr (List         _ es) =+  trExpr $ foldr (Apply . Apply (Constructor undefined qConsId))+                 (Constructor undefined qNilId)+                 es+trExpr (ListCompr    e ds) = inNestedScope $ flip CListComp+                             <$> mapM trStatement ds <*> trExpr e+trExpr (EnumFrom              e) =+  trExpr $ apply (Variable undefined qEnumFromId) [e]+trExpr (EnumFromThen      e1 e2) =+  trExpr $ apply (Variable undefined qEnumFromThenId) [e1, e2]+trExpr (EnumFromTo        e1 e2) =+  trExpr $ apply (Variable undefined qEnumFromToId) [e1, e2]+trExpr (EnumFromThenTo e1 e2 e3) =+  trExpr $ apply (Variable undefined qEnumFromThenToId) [e1, e2, e3]+trExpr (UnaryMinus            e) =+  trExpr $ apply (Variable undefined qNegateId) [e]+trExpr (Apply             e1 e2) = CApply <$> trExpr e1 <*> trExpr e2+trExpr (InfixApply     e1 op e2) = trExpr $ apply (infixOp op) [e1, e2]+trExpr (LeftSection        e op) = trExpr $ apply (infixOp op) [e]+trExpr (RightSection       op e) =+  trExpr $ apply (Variable undefined qFlip) [infixOp op, e]+trExpr (Lambda             ps e) = inNestedScope $+                                   CLambda <$> mapM trPat ps <*> trExpr e+trExpr (Let                ds e) = inNestedScope $+                                   CLetDecl <$> trLocalDecls ds <*> trExpr e+trExpr (Do                 ss e) = inNestedScope $+                                   (\ss' e' -> CDoExpr (ss' ++ [CSExpr e']))+                                   <$> mapM trStatement ss <*> trExpr e+trExpr (IfThenElse     e1 e2 e3) =+  trExpr $ apply (Variable undefined qIfThenElseId) [e1, e2, e3]+trExpr (Case            ct e bs) = CCase (cvCaseType ct)+                                   <$> trExpr e <*> mapM trAlt bs++cvCaseType :: CaseType -> CCaseType+cvCaseType Flex  = CFlex+cvCaseType Rigid = CRigid++trStatement :: Statement PredType -> GAC CStatement+trStatement (StmtExpr   e) = CSExpr     <$> trExpr e+trStatement (StmtDecl  ds) = CSLet      <$> trLocalDecls ds+trStatement (StmtBind p e) = flip CSPat <$> trExpr e <*> trPat p++trAlt :: Alt PredType -> GAC (CPattern, CRhs)+trAlt (Alt _ p rhs) = inNestedScope $ (,) <$> trPat p <*> trRhs rhs++trPat :: Pattern a -> GAC CPattern+trPat (LiteralPattern         _ l) = return (CPLit $ cvLiteral l)+trPat (VariablePattern        _ v) = CPVar <$> getVarIndex v+trPat (ConstructorPattern  _ c ps) = CPComb <$> trQual c <*> mapM trPat ps+trPat (InfixPattern    a p1 op p2) = trPat $ ConstructorPattern a op [p1, p2]+trPat (ParenPattern             p) = trPat p+trPat (RecordPattern       _ c fs) = CPRecord <$> trQual c+                                              <*> mapM (trField trPat) fs+trPat (TuplePattern            ps) =+  trPat $ ConstructorPattern undefined (qTupleId $ length ps) ps+trPat (ListPattern           _ ps) = trPat $+  foldr (\x1 x2 -> ConstructorPattern undefined qConsId [x1, x2])+        (ConstructorPattern undefined qNilId [])+        ps+trPat (NegativePattern        a l) = trPat $ LiteralPattern a $ negateLiteral l+trPat (AsPattern              v p) = CPAs <$> getVarIndex v<*> trPat p+trPat (LazyPattern              p) = CPLazy <$> trPat p+trPat (FunctionPattern     _ f ps) = CPFuncComb <$> trQual f <*> mapM trPat ps+trPat (InfixFuncPattern a p1 f p2) = trPat (FunctionPattern a f [p1, p2])++trField :: (a -> GAC b) -> Field a -> GAC (CField b)+trField act (Field _ l x) = (,) <$> trQual l <*> act x++negateLiteral :: Literal -> Literal+negateLiteral (Int    i) = Int   (-i)+negateLiteral (Float  f) = Float (-f)+negateLiteral _          = internalError "GenAbstractCurry.negateLiteral"++cvLiteral :: Literal -> CLiteral+cvLiteral (Char   c) = CCharc   c+cvLiteral (Int    i) = CIntc    i+cvLiteral (Float  f) = CFloatc  f+cvLiteral (String s) = CStringc s++trQual :: QualIdent -> GAC QName+trQual qid+  | n `elem` [unitId, listId, nilId, consId] = return ("Prelude", idName n)+  | isTupleId n                              = return ("Prelude", idName n)+  | otherwise+  = return (maybe "" moduleName (qidModule qid), idName n)+  where n = qidIdent qid++trGlobalIdent :: Ident -> GAC QName+trGlobalIdent i = S.gets moduleId >>= \m -> return (moduleName m, idName i)++trLocalIdent :: Ident -> GAC QName+trLocalIdent i = return ("", idName i)++qFlip :: QualIdent+qFlip = qualifyWith preludeMIdent (mkIdent "flip")++qNegateId :: QualIdent+qNegateId = qualifyWith preludeMIdent (mkIdent "negate")++qIfThenElseId :: QualIdent+qIfThenElseId = qualifyWith preludeMIdent (mkIdent "if_then_else")++prelUntyped :: QualIdent+prelUntyped = qualifyWith preludeMIdent $ mkIdent "untyped"++-------------------------------------------------------------------------------+-- This part defines an environment containing all necessary information+-- for generating the AbstractCurry representation of a CurrySyntax term.++-- |Data type for representing an AbstractCurry generator environment+data AbstractEnv = AbstractEnv+  { moduleId   :: ModuleIdent                -- ^name of the module+  , typeEnv    :: ValueEnv                   -- ^known values+  , tyExports  :: Set.Set Ident              -- ^exported type symbols+  , valExports :: Set.Set Ident              -- ^exported value symbols+  , varIndex   :: Int                        -- ^counter for variable indices+  , tvarIndex  :: Int                        -- ^counter for type variable indices+  , varEnv     :: NestEnv Int                -- ^stack of variable tables+  , tvarEnv    :: NestEnv Int                -- ^stack of type variable tables+  , untypedAcy :: Bool                       -- ^flag to indicate whether untyped+                                             --  AbstractCurry is generated+  , typeSigs   :: Map.Map Ident QualTypeExpr -- ^map of user defined type signatures+  } deriving Show++-- |Initialize the AbstractCurry generator environment+abstractEnv :: Bool -> CompilerEnv -> Module a -> AbstractEnv+abstractEnv uacy env (Module _ mid es _ ds) = AbstractEnv+  { moduleId   = mid+  , typeEnv    = valueEnv env+  , tyExports  = foldr (buildTypeExports  mid) Set.empty es'+  , valExports = foldr (buildValueExports mid) Set.empty es'+  , varIndex   = 0+  , tvarIndex  = 0+  , varEnv     = globalEnv emptyTopEnv+  , tvarEnv    = globalEnv emptyTopEnv+  , untypedAcy = uacy+  , typeSigs   = if uacy+                  then Map.fromList $ signatures ds+                  else Map.empty+  }+  where es' = case es of+          Just (Exporting _ e) -> e+          _                    -> internalError "GenAbstractCurry.abstractEnv"++-- Builds a table containing all exported identifiers from a module.+buildTypeExports :: ModuleIdent -> Export -> Set.Set Ident -> Set.Set Ident+buildTypeExports mid (ExportTypeWith tc _)+  | isLocalIdent mid tc = Set.insert (unqualify tc)+buildTypeExports _   _  = id++-- Builds a table containing all exported identifiers from a module.+buildValueExports :: ModuleIdent -> Export -> Set.Set Ident -> Set.Set Ident+buildValueExports mid (Export             q)+  | isLocalIdent mid q  = Set.insert (unqualify q)+buildValueExports mid (ExportTypeWith tc cs)+  | isLocalIdent mid tc = flip (foldr Set.insert) cs+buildValueExports _   _  = id++-- Looks up the unique index for the variable 'ident' in the+-- variable table of the current scope.+lookupVarIndex :: Ident -> GAC (Maybe CVarIName)+lookupVarIndex i = S.gets $ \env -> case lookupNestEnv i $ varEnv env of+  [v] -> Just (v, idName i)+  _   -> Nothing++getVarIndex :: Ident -> GAC CVarIName+getVarIndex i = S.get >>= \env -> case lookupNestEnv i $ varEnv env of+  [v] -> return (v, idName i)+  _   -> genVarIndex i++-- Generates an unique index for the  variable 'ident' and inserts it+-- into the  variable table of the current scope.+genVarIndex :: Ident -> GAC CVarIName+genVarIndex i = do+  env <- S.get+  let idx = varIndex env+  S.put $ env { varIndex = idx + 1, varEnv = bindNestEnv i idx (varEnv env) }+  return (idx, idName i)++-- Looks up the unique index for the type variable 'ident' in the type+-- variable table of the current scope.+getTVarIndex :: Ident -> GAC CTVarIName+getTVarIndex i = S.get >>= \env -> case lookupNestEnv i $ tvarEnv env of+  [v] -> return (v, idName i)+  _   -> genTVarIndex i++-- Generates an unique index for the type variable 'ident' and inserts it+-- into the type variable table of the current scope.+genTVarIndex :: Ident -> GAC CTVarIName+genTVarIndex i = do+  env <- S.get+  let idx = tvarIndex env+  S.put $ env { tvarIndex = idx + 1, tvarEnv = bindNestEnv i idx (tvarEnv env) }+  return (idx, idName i)++withLocalEnv :: GAC a -> GAC a+withLocalEnv act = do+  old <- S.get+  res <- act+  S.put old+  return res++inNestedScope :: GAC a -> GAC a+inNestedScope act = do+  (vo, to) <- S.gets $ \e -> (varEnv e, tvarEnv e)+  S.modify $ \e -> e { varEnv = nestEnv $ vo, tvarEnv = globalEnv emptyTopEnv }+  res <- act+  S.modify $ \e -> e { varEnv = vo, tvarEnv = to }+  return res++inNestedTScope :: GAC a -> GAC a+inNestedTScope act = do+  (vo, to) <- S.gets $ \e -> (varEnv e, tvarEnv e)+  S.modify $ \e -> e { varEnv = globalEnv emptyTopEnv, tvarEnv = nestEnv $ to }+  res <- act+  S.modify $ \e -> e { varEnv = vo, tvarEnv = to }+  return res++getQualType :: Ident -> PredType -> GAC CQualTypeExpr+getQualType f pty = do+  uacy <- S.gets untypedAcy+  sigs <- S.gets typeSigs+  trQualTypeExpr $ case uacy of+    True  -> Maybe.fromMaybe (QualTypeExpr [] $ ConstructorType prelUntyped)+                             (Map.lookup f sigs)+    False -> fromPredType identSupply pty++getQualType' :: QualIdent -> GAC QualTypeExpr+getQualType' f = do+  m     <- S.gets moduleId+  tyEnv <- S.gets typeEnv+  return $ case qualLookupValue f tyEnv of+    [Value _ _ _ (ForAll _ pty)] -> fromPredType identSupply pty+    _                          -> case qualLookupValue (qualQualify m f) tyEnv of+      [Value _ _ _ (ForAll _ pty)] -> fromPredType identSupply pty+      _                          ->+        internalError $ "GenAbstractCurry.getQualType': " ++ show f++getTypeVisibility :: Ident -> GAC CVisibility+getTypeVisibility i = S.gets $ \env ->+  if Set.member i (tyExports env) then Public else Private++getVisibility :: Ident -> GAC CVisibility+getVisibility i = S.gets $ \env ->+  if Set.member i (valExports env) then Public else Private++signatures :: [Decl a] -> [(Ident, QualTypeExpr)]+signatures ds = [(f, qty) | TypeSig _ fs qty <- ds, f <- fs]
+ src/Generators/GenFlatCurry.hs view
@@ -0,0 +1,56 @@+{- |+    Module      :  $Header$+    Description :  Generation of FlatCurry program and interface terms+    Copyright   :  (c) 2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module contains the generation of a 'FlatCurry' program term or+    a 'FlatCurry' interface out of an 'Annotated FlatCurry' module.+-}+module Generators.GenFlatCurry (genFlatCurry, genFlatInterface) where++import Curry.FlatCurry.Goodies+import Curry.FlatCurry.Type+import Curry.FlatCurry.Annotated.Goodies+import Curry.FlatCurry.Annotated.Type++-- transforms annotated FlatCurry code to FlatCurry code+genFlatCurry :: AProg a -> Prog+genFlatCurry = trAProg+  (\name imps types funcs ops ->+    Prog name imps types (map genFlatFuncDecl funcs) ops)++genFlatFuncDecl :: AFuncDecl a -> FuncDecl+genFlatFuncDecl = trAFunc+  (\name arity vis ty rule -> Func name arity vis ty $ genFlatRule rule)++genFlatRule :: ARule a -> Rule+genFlatRule = trARule+  (\_ args e -> Rule (map fst args) $ genFlatExpr e)+  (const External)++genFlatExpr :: AExpr a -> Expr+genFlatExpr = trAExpr+  (const Var)+  (const Lit)+  (\_ ct name args -> Comb ct (fst name) args)+  (\_ bs e -> Let (map (\(v, e') -> (fst v, e')) bs) e)+  (\_ vs e -> Free (map fst vs) e)+  (\_ e1 e2 -> Or e1 e2)+  (\_ ct e bs -> Case ct e bs)+  (\pat e -> Branch (genFlatPattern pat) e)+  (\_ e ty -> Typed e ty)++genFlatPattern :: APattern a -> Pattern+genFlatPattern = trAPattern+  (\_ name args -> Pattern (fst name) $ map fst args)+  (const LPattern)++-- transforms a FlatCurry module to a FlatCurry interface+genFlatInterface :: Prog -> Prog+genFlatInterface =+  updProgFuncs $ map $ updFuncRule $ const $ Rule [] $ Var 0
+ src/Generators/GenTypedFlatCurry.hs view
@@ -0,0 +1,515 @@+{- |+    Module      :  $Header$+    Description :  Generation of typed FlatCurry program terms+    Copyright   :  (c) 2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module contains the generation of a typed 'FlatCurry' program term+    for a given module in the intermediate language.+-}+{-# LANGUAGE CPP #-}+module Generators.GenTypedFlatCurry (genTypedFlatCurry) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import           Control.Monad              ((<=<))+import           Control.Monad.Extra        (concatMapM)+import qualified Control.Monad.State as S   ( State, evalState, get, gets+                                            , modify, put )+import           Data.Function              (on)+import           Data.List                  (nub, sortBy)+import           Data.Maybe                 (fromMaybe)+import qualified Data.Map            as Map (Map, empty, insert, lookup)+import qualified Data.Set            as Set (Set, empty, insert, member)++import           Curry.Base.Ident+import           Curry.FlatCurry.Annotated.Goodies (typeName)+import           Curry.FlatCurry.Annotated.Type+import           Curry.FlatCurry.Annotated.Typing+import qualified Curry.Syntax as CS++import Base.CurryTypes     (toType)+import Base.Messages       (internalError)+import Base.NestEnv        ( NestEnv, emptyEnv, bindNestEnv, lookupNestEnv+                           , nestEnv, unnestEnv )+import Base.TypeExpansion+import Base.Types++import CompilerEnv+import Env.OpPrec          (mkPrec)+import Env.TypeConstructor (TCEnv)+import Env.Value           (ValueEnv, ValueInfo (..), qualLookupValue)++import qualified IL as IL+import Transformations     (transType)++-- transforms intermediate language code (IL) to typed FlatCurry code+genTypedFlatCurry :: CompilerEnv -> CS.Module Type -> IL.Module+                  -> AProg TypeExpr+genTypedFlatCurry env mdl il = patchPrelude $ run env mdl (trModule il)++-- -----------------------------------------------------------------------------+-- Addition of primitive types for lists and tuples to the Prelude+-- -----------------------------------------------------------------------------++patchPrelude :: AProg a -> AProg a+patchPrelude p@(AProg n _ ts fs os)+  | n == prelude = AProg n [] ts' fs os+  | otherwise    = p+  where ts' = sortBy (compare `on` typeName) pts+        pts = primTypes ++ ts++primTypes :: [TypeDecl]+primTypes =+  [ Type arrow Public [0, 1] []+  , Type unit Public [] [(Cons unit 0 Public [])]+  , Type nil Public [0] [ Cons nil  0 Public []+                        , Cons cons 2 Public [TVar 0, TCons nil [TVar 0]]+                        ]+  ] ++ map mkTupleType [2 .. maxTupleArity]+  where arrow = mkPreludeQName "(->)"+        unit  = mkPreludeQName "()"+        nil   = mkPreludeQName "[]"+        cons  = mkPreludeQName ":"++mkTupleType :: Int -> TypeDecl+mkTupleType arity = Type tuple Public [0 .. arity - 1]+  [Cons tuple arity Public (map TVar [0 .. arity - 1])]+  where tuple = mkPreludeQName $ '(' : replicate (arity - 1) ',' ++ ")"++mkPreludeQName :: String -> QName+mkPreludeQName n = (prelude, n)++prelude :: String+prelude = "Prelude"++-- |Maximal arity of tuples+maxTupleArity :: Int+maxTupleArity = 15++-- -----------------------------------------------------------------------------++-- The environment 'FlatEnv' is embedded in the monadic representation+-- 'FlatState' which allows the usage of 'do' expressions.+type FlatState a = S.State FlatEnv a++-- Data type for representing an environment which contains information needed+-- for generating FlatCurry code.+data FlatEnv = FlatEnv+  { modIdent     :: ModuleIdent      -- current module+  -- for visibility calculation+  , tyExports    :: Set.Set Ident    -- exported types+  , valExports   :: Set.Set Ident    -- exported values (functions + constructors)+  , tcEnv        :: TCEnv            -- type constructor environment+  , tyEnv        :: ValueEnv         -- type environment+  , fixities     :: [CS.IDecl]       -- fixity declarations+  , typeSynonyms :: [CS.Decl Type]   -- type synonyms+  , imports      :: [ModuleIdent]    -- module imports+  -- state for mapping identifiers to indexes+  , nextVar      :: Int              -- fresh variable index counter+  , varMap       :: NestEnv VarIndex -- map of identifier to variable index+  }++-- Runs a 'FlatState' action and returns the result+run :: CompilerEnv -> CS.Module Type -> FlatState a -> a+run env (CS.Module _ mid es is ds) act = S.evalState act env0+  where+  es'  = case es of Just (CS.Exporting _ e) -> e+                    _                       -> []+  env0 = FlatEnv+    { modIdent     = mid+     -- for visibility calculation+    , tyExports  = foldr (buildTypeExports  mid) Set.empty es'+    , valExports = foldr (buildValueExports mid) Set.empty es'+    -- This includes *all* imports, even unused ones+    , imports      = nub [ m | CS.ImportDecl _ m _ _ _ <- is ]+    -- Environment to retrieve the type of identifiers+    , tyEnv        = valueEnv env+    , tcEnv        = tyConsEnv env+    -- Fixity declarations+    , fixities     = [ CS.IInfixDecl p fix (mkPrec mPrec) (qualifyWith mid o)+                     | CS.InfixDecl p fix mPrec os <- ds, o <- os+                     ]+    -- Type synonyms in the module+    , typeSynonyms = [ d | d@CS.TypeDecl{} <- ds ]+    , nextVar      = 0+    , varMap       = emptyEnv+    }++-- Builds a table containing all exported identifiers from a module.+buildTypeExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident+buildTypeExports mid (CS.ExportTypeWith tc _)+  | isLocalIdent mid tc = Set.insert (unqualify tc)+buildTypeExports _   _  = id++-- Builds a table containing all exported identifiers from a module.+buildValueExports :: ModuleIdent -> CS.Export -> Set.Set Ident -> Set.Set Ident+buildValueExports mid (CS.Export             q)+  | isLocalIdent mid q  = Set.insert (unqualify q)+buildValueExports mid (CS.ExportTypeWith tc cs)+  | isLocalIdent mid tc = flip (foldr Set.insert) cs+buildValueExports _   _  = id++getModuleIdent :: FlatState ModuleIdent+getModuleIdent = S.gets modIdent++getArity :: QualIdent -> FlatState Int+getArity qid = S.gets tyEnv >>= \ env -> return $ case qualLookupValue qid env of+  [DataConstructor  _ a _ _] -> a+  [NewtypeConstructor _ _ _] -> 1+  [Value            _ _ a _] -> a+  [Label              _ _ _] -> 1+  _                          -> internalError+                                ("GenTypedFlatCurry.getArity: " ++ qualName qid)++getFixities :: FlatState [CS.IDecl]+getFixities = S.gets fixities++-- The function 'typeSynonyms' returns the list of type synonyms.+getTypeSynonyms :: FlatState [CS.Decl Type]+getTypeSynonyms = S.gets typeSynonyms++-- Retrieve imports+getImports :: [ModuleIdent] -> FlatState [String]+getImports imps = (nub . map moduleName . (imps ++)) <$> S.gets imports++-- -----------------------------------------------------------------------------+-- Stateful part, used for translation of rules and expressions+-- -----------------------------------------------------------------------------++-- resets var index and environment+withFreshEnv :: FlatState a -> FlatState a+withFreshEnv act = S.modify (\ s -> s { nextVar = 0, varMap = emptyEnv }) >> act++-- Execute an action in a nested variable mapping+inNestedEnv :: FlatState a -> FlatState a+inNestedEnv act = do+  S.modify $ \ s -> s { varMap = nestEnv   $ varMap s }+  res <- act+  S.modify $ \ s -> s { varMap = unnestEnv $ varMap s }+  return res++-- Generates a new variable index for an identifier+newVar :: IL.Type -> Ident -> FlatState (VarIndex, TypeExpr)+newVar ty i = do+  idx <- (+1) <$> S.gets nextVar+  S.modify $ \ s -> s { nextVar = idx, varMap = bindNestEnv i idx (varMap s) }+  ty' <- trType ty+  return (idx, ty')++-- Retrieve the variable index assigned to an identifier+getVarIndex :: Ident -> FlatState VarIndex+getVarIndex i = S.gets varMap >>= \ varEnv -> case lookupNestEnv i varEnv of+  [v] -> return v+  _   -> internalError $ "GenFlatCurry.getVarIndex: " ++ escName i++-- -----------------------------------------------------------------------------+-- Translation of an interface+-- -----------------------------------------------------------------------------++-- Translate an operator declaration+trIOpDecl :: CS.IDecl -> FlatState [OpDecl]+trIOpDecl (CS.IInfixDecl _ fix prec op)+  = (\op' -> [Op op' (cvFixity fix) prec]) <$> trQualIdent op+trIOpDecl _ = return []++-- -----------------------------------------------------------------------------+-- Translation of a module+-- -----------------------------------------------------------------------------++trModule :: IL.Module -> FlatState (AProg TypeExpr)+trModule (IL.Module mid is ds) = do+  is' <- getImports is+  sns <- getTypeSynonyms >>= concatMapM trTypeSynonym+  tds <- concatMapM trTypeDecl ds+  fds <- concatMapM (return . map runNormalization <=< trAFuncDecl) ds+  ops <- getFixities >>= concatMapM trIOpDecl+  return $ AProg (moduleName mid) is' (sns ++ tds) fds ops++-- Translate a type synonym+trTypeSynonym :: CS.Decl a -> FlatState [TypeDecl]+trTypeSynonym (CS.TypeDecl _ t tvs ty) = do+  m    <- getModuleIdent+  qid  <- flip qualifyWith t <$> getModuleIdent+  t'   <- trQualIdent qid+  vis  <- getTypeVisibility qid+  tEnv <- S.gets tcEnv+  ty'  <- trType (transType $ expandType m tEnv $ toType tvs ty)+  return [TypeSyn t' vis [0 .. length tvs - 1] ty']+trTypeSynonym _                        = return []++-- Translate a data declaration+-- For empty data declarations, an additional constructor is generated. This+-- is due to the fact that external data declarations are translated into data+-- declarations with zero constructors and without the additional constructor+-- empty data declarations could not be distinguished from external ones.+trTypeDecl :: IL.Decl -> FlatState [TypeDecl]+trTypeDecl (IL.DataDecl      qid a []) = do+  q'  <- trQualIdent qid+  vis <- getTypeVisibility qid+  c   <- trQualIdent $ qualify (mkIdent $ "_Constr#" ++ idName (unqualify qid))+  let tvs = [0 .. a - 1]+  return [Type q' vis tvs [Cons c 1 Private [TCons q' $ map TVar tvs]]]+trTypeDecl (IL.DataDecl      qid a cs) = do+  q'  <- trQualIdent qid+  vis <- getTypeVisibility qid+  cs' <- mapM trConstrDecl cs+  return [Type q' vis [0 .. a - 1] cs']+trTypeDecl (IL.ExternalDataDecl qid a) = do+  q'  <- trQualIdent qid+  vis <- getTypeVisibility qid+  return [Type q' vis [0 .. a - 1] []]+trTypeDecl _                           = return []++-- Translate a constructor declaration+trConstrDecl :: IL.ConstrDecl -> FlatState ConsDecl+trConstrDecl (IL.ConstrDecl qid tys) = flip Cons (length tys)+  <$> trQualIdent qid+  <*> getVisibility qid+  <*> mapM trType tys++-- Translate a type expression+trType :: IL.Type -> FlatState TypeExpr+trType (IL.TypeConstructor t tys) = TCons <$> trQualIdent t <*> mapM trType tys+trType (IL.TypeVariable      idx) = return $ TVar $ abs idx+trType (IL.TypeArrow     ty1 ty2) = FuncType <$> trType ty1 <*> trType ty2+trType (IL.TypeForall    idxs ty) = ForallType (map abs idxs) <$> trType ty++-- Convert a fixity+cvFixity :: CS.Infix -> Fixity+cvFixity CS.InfixL = InfixlOp+cvFixity CS.InfixR = InfixrOp+cvFixity CS.Infix  = InfixOp++-- -----------------------------------------------------------------------------+-- Function declarations+-- -----------------------------------------------------------------------------++-- Translate a function declaration+trAFuncDecl :: IL.Decl -> FlatState [AFuncDecl TypeExpr]+trAFuncDecl (IL.FunctionDecl f vs _ e) = do+  f'  <- trQualIdent f+  a   <- getArity f+  vis <- getVisibility f+  ty' <- trType ty+  r'  <- trARule ty vs e+  return [AFunc f' a vis ty' r']+  where ty = foldr IL.TypeArrow (IL.typeOf e) $ map fst vs+trAFuncDecl (IL.ExternalDecl     f ty) = do+  f'   <- trQualIdent f+  a    <- getArity f+  vis  <- getVisibility f+  ty'  <- trType ty+  r'   <- trAExternal ty f+  return [AFunc f' a vis ty' r']+trAFuncDecl _                           = return []++-- Translate a function rule.+-- Resets variable index so that for every rule variables start with index 1+trARule :: IL.Type -> [(IL.Type, Ident)] -> IL.Expression+        -> FlatState (ARule TypeExpr)+trARule ty vs e = withFreshEnv $ ARule <$> trType ty+                                    <*> mapM (uncurry newVar) vs+                                    <*> trAExpr e++trAExternal :: IL.Type -> QualIdent -> FlatState (ARule TypeExpr)+trAExternal ty f = flip AExternal (qualName f) <$> trType ty++-- Translate an expression+trAExpr :: IL.Expression -> FlatState (AExpr TypeExpr)+trAExpr (IL.Literal       ty l) = ALit <$> trType ty <*> trLiteral l+trAExpr (IL.Variable      ty v) = AVar <$> trType ty <*> getVarIndex v+trAExpr (IL.Function    ty f _) = genCall Fun ty f []+trAExpr (IL.Constructor ty c _) = genCall Con ty c []+trAExpr (IL.Apply        e1 e2) = trApply e1 e2+trAExpr c@(IL.Case      t e bs) = flip ACase (cvEval t) <$> trType (IL.typeOf c) <*> trAExpr e+                                  <*> mapM (inNestedEnv . trAlt) bs+trAExpr (IL.Or           e1 e2) = AOr <$> trType (IL.typeOf e1) <*> trAExpr e1 <*> trAExpr e2+trAExpr (IL.Exist          v e) = inNestedEnv $ do+  v' <- newVar (IL.typeOf e) v+  e' <- trAExpr e+  ty' <- trType (IL.typeOf e)+  return $ case e' of AFree ty'' vs e'' -> AFree ty'' (v' : vs) e''+                      _                 -> AFree ty'  (v' : []) e'+trAExpr (IL.Let (IL.Binding v b) e) = inNestedEnv $ do+  v' <- newVar (IL.typeOf b) v+  b' <- trAExpr b+  e' <- trAExpr e+  ty' <- trType $ IL.typeOf e+  return $ case e' of ALet ty'' bs e'' -> ALet ty'' ((v', b'):bs) e''+                      _                -> ALet ty'  ((v', b'):[]) e'+trAExpr (IL.Letrec   bs e) = inNestedEnv $ do+  let (vs, es) = unzip [ ((IL.typeOf b, v), b) | IL.Binding v b <- bs]+  ALet <$> trType (IL.typeOf e)+       <*> (zip <$> mapM (uncurry newVar) vs <*> mapM trAExpr es)+       <*> trAExpr e+trAExpr (IL.Typed e _) = ATyped <$> ty' <*> trAExpr e <*> ty'+  where ty' = trType $ IL.typeOf e++-- Translate a literal+trLiteral :: IL.Literal -> FlatState Literal+trLiteral (IL.Char  c) = return $ Charc  c+trLiteral (IL.Int   i) = return $ Intc   i+trLiteral (IL.Float f) = return $ Floatc f++-- Translate a higher-order application+trApply :: IL.Expression -> IL.Expression -> FlatState (AExpr TypeExpr)+trApply e1 e2 = genFlatApplic e1 [e2]+  where+  genFlatApplic e es = case e of+    IL.Apply        ea eb -> genFlatApplic ea (eb:es)+    IL.Function    ty f _ -> genCall Fun ty f es+    IL.Constructor ty c _ -> genCall Con ty c es+    _ -> do+      expr <- trAExpr e+      genApply expr es++-- Translate an alternative+trAlt :: IL.Alt -> FlatState (ABranchExpr TypeExpr)+trAlt (IL.Alt p e) = ABranch <$> trPat p <*> trAExpr e++-- Translate a pattern+trPat :: IL.ConstrTerm -> FlatState (APattern TypeExpr)+trPat (IL.LiteralPattern        ty l) = ALPattern <$> trType ty <*> trLiteral l+trPat (IL.ConstructorPattern ty c vs) = do+  qty <- trType $ foldr IL.TypeArrow ty $ map fst vs+  APattern  <$> trType ty <*> ((\q -> (q, qty)) <$> trQualIdent c) <*> mapM (uncurry newVar) vs+trPat (IL.VariablePattern        _ _) = internalError "GenTypedFlatCurry.trPat"++-- Convert a case type+cvEval :: IL.Eval -> CaseType+cvEval IL.Rigid = Rigid+cvEval IL.Flex  = Flex++data Call = Fun | Con++-- Generate a function or constructor call+genCall :: Call -> IL.Type -> QualIdent -> [IL.Expression]+        -> FlatState (AExpr TypeExpr)+genCall call ty f es = do+  f'    <- trQualIdent f+  arity <- getArity f+  case compare supplied arity of+    LT -> genAComb ty f' es (part call (arity - supplied))+    EQ -> genAComb ty f' es (full call)+    GT -> do+      let (es1, es2) = splitAt arity es+      funccall <- genAComb ty f' es1 (full call)+      genApply funccall es2+  where+  supplied = length es+  full Fun = FuncCall+  full Con = ConsCall+  part Fun = FuncPartCall+  part Con = ConsPartCall++genAComb :: IL.Type -> QName -> [IL.Expression] -> CombType -> FlatState (AExpr TypeExpr)+genAComb ty qid es ct = do+  ty' <- trType ty+  let ty'' = defunc ty' (length es)+  AComb ty'' ct (qid, ty') <$> mapM trAExpr es+  where+  defunc t               0 = t+  defunc (FuncType _ t2) n = defunc t2 (n - 1)+  defunc _               _ = internalError "GenTypedFlatCurry.genAComb.defunc"++genApply :: AExpr TypeExpr -> [IL.Expression] -> FlatState (AExpr TypeExpr)+genApply e es = do+  ap  <- trQualIdent $ qApplyId+  es' <- mapM trAExpr es+  return $ foldl (\e1 e2 -> let FuncType ty1 ty2 = typeOf e1 in AComb ty2 FuncCall (ap, FuncType (FuncType ty1 ty2) (FuncType ty1 ty2)) [e1, e2]) e es'++-- -----------------------------------------------------------------------------+-- Normalization+-- -----------------------------------------------------------------------------++runNormalization :: Normalize a => a -> a+runNormalization x = S.evalState (normalize x) (0, Map.empty)++type NormState a = S.State (Int, Map.Map Int Int) a++class Normalize a where+  normalize :: a -> NormState a++instance Normalize Int where+  normalize i = do+    (n, m) <- S.get+    case Map.lookup i m of+      Nothing -> do+        S.put (n + 1, Map.insert i n m)+        return n+      Just n' -> return n'++instance Normalize TypeExpr where+  normalize (TVar           i) = TVar <$> normalize i+  normalize (TCons      q tys) = TCons q <$> mapM normalize tys+  normalize (FuncType ty1 ty2) = FuncType <$> normalize ty1 <*> normalize ty2+  normalize (ForallType is ty) =+    ForallType <$> mapM normalize is <*> normalize ty++instance Normalize b => Normalize (a, b) where+  normalize (x, y) = ((,) x) <$> normalize y++instance Normalize a => Normalize (AFuncDecl a) where+  normalize (AFunc f a v ty r) = AFunc f a v <$> normalize ty <*> normalize r++instance Normalize a => Normalize (ARule a) where+  normalize (ARule     ty vs e) = ARule <$> normalize ty+                                        <*> mapM normalize vs+                                        <*> normalize e+  normalize (AExternal ty    s) = flip AExternal s <$> normalize ty++instance Normalize a => Normalize (AExpr a) where+  normalize (AVar  ty       v) = flip AVar  v  <$> normalize ty+  normalize (ALit  ty       l) = flip ALit  l  <$> normalize ty+  normalize (AComb ty ct f es) = flip AComb ct <$> normalize ty+                                               <*> normalize f+                                               <*> mapM normalize es+  normalize (ALet  ty    ds e) = ALet <$> normalize ty+                                      <*> mapM normalizeBinding ds+                                      <*> normalize e+    where normalizeBinding (v, b) = (,) <$> normalize v <*> normalize b+  normalize (AOr   ty     a b) = AOr <$> normalize ty <*> normalize a+                                     <*> normalize b+  normalize (ACase ty ct e bs) = flip ACase ct <$> normalize ty <*> normalize e+                                               <*> mapM normalize bs+  normalize (AFree  ty   vs e) = AFree <$> normalize ty <*> mapM normalize vs+                                       <*> normalize e+  normalize (ATyped ty  e ty') = ATyped <$> normalize ty <*> normalize e+                                        <*> normalize ty'++instance Normalize a => Normalize (ABranchExpr a) where+  normalize (ABranch p e) = ABranch <$> normalize p <*> normalize e++instance Normalize a => Normalize (APattern a) where+  normalize (APattern  ty c vs) = APattern <$> normalize ty <*> normalize c+                                           <*> mapM normalize vs+  normalize (ALPattern ty    l) = flip ALPattern l <$> normalize ty++-- -----------------------------------------------------------------------------+-- Helper functions+-- -----------------------------------------------------------------------------++trQualIdent :: QualIdent -> FlatState QName+trQualIdent qid = do+  mid <- getModuleIdent+  return $ (moduleName $ fromMaybe mid mid', idName i)+  where+  mid' | i `elem` [listId, consId, nilId, unitId] || isTupleId i+       = Just preludeMIdent+       | otherwise+       = qidModule qid+  i = qidIdent qid++getTypeVisibility :: QualIdent -> FlatState Visibility+getTypeVisibility i = S.gets $ \s ->+  if Set.member (unqualify i) (tyExports s) then Public else Private++getVisibility :: QualIdent -> FlatState Visibility+getVisibility i = S.gets $ \s ->+  if Set.member (unqualify i) (valExports s) then Public else Private
+ src/Html/CurryHtml.hs view
@@ -0,0 +1,185 @@+{- |+    Module      :  $Header$+    Description :  Generating HTML documentation+    Copyright   :  (c) 2011 - 2016, Björn Peemöller+                       2016       , Jan Tikovsky+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module defines a function for generating HTML documentation pages+    for Curry source modules.+-}+module Html.CurryHtml (source2html) where++import Control.Monad.Writer+import Data.List             (mapAccumL)+import Data.Maybe            (fromMaybe, isJust)+import Network.URI           (escapeURIString, isUnreserved)+import System.Directory      (copyFile, doesFileExist)+import System.FilePath       ((</>))++import Curry.Base.Ident      ( ModuleIdent (..), Ident (..), QualIdent (..)+                             , unqualify, moduleName)+import Curry.Base.Monad      (CYIO, failMessages)+import Curry.Base.Position   (Position)+import Curry.Base.Pretty     ((<+>), text, vcat)+import Curry.Files.Filenames (htmlName)+import Curry.Syntax          (Module (..), Token)++import Html.SyntaxColoring++import Base.Messages         (message)+import CompilerOpts          (Options (..))+import Paths_curry_frontend  (getDataFileName)++-- |'FilePath' of the CSS style file to be added to the documentation.+cssFile :: FilePath+cssFile = "currysource.css"++-- |Translate source file into HTML file with syntaxcoloring+source2html :: Options -> ModuleIdent -> [(Position, Token)] -> Module a+            -> CYIO ()+source2html opts mid toks mdl = do+  liftIO $ writeFile (outDir </> htmlName mid) doc+  updateCSSFile outDir+  where+  doc    = program2html mid (genProgram mdl toks)+  outDir = fromMaybe "." (optHtmlDir opts)++-- |Update the CSS file+updateCSSFile :: FilePath -> CYIO ()+updateCSSFile dir = do+  src <- liftIO $ getDataFileName cssFile+  let target = dir </> cssFile+  srcExists <- liftIO $ doesFileExist src+  if srcExists then liftIO $ copyFile src target+               else failMessages [message $ missingStyleFile src]+  where+  missingStyleFile f = vcat+    [ text "Could not copy CSS style file:"+    , text "File" <+> text ("`" ++ f ++ "'") <+> text "does not exist"+    ]++-- generates htmlcode with syntax highlighting+-- @param modulname+-- @param a program+-- @return HTMLcode+program2html :: ModuleIdent -> [Code] -> String+program2html m codes = unlines+  [ "<!DOCTYPE html>"+  , "<html>", "<head>"+  , "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />"+  , "<title>" ++ titleHtml ++ "</title>"+  , "<link rel=\"stylesheet\" type=\"text/css\" href=\"" ++ cssFile ++ "\"/>"+  , "</head>"+  , "<body>"+  , "<table><tbody><tr>"+  , "<td class=\"linenumbers\"><pre>" ++ lineHtml ++ "</pre></td>"+  , "<td class=\"sourcecode\"><pre>" ++ codeHtml ++ "</pre></td>"+  , "</tr></tbody></table>"+  , "</body>"+  , "</html>"+  ]+  where+  titleHtml = "Module " ++ moduleName m+  lineHtml  = unlines $ map show [1 .. length (lines codeHtml)]+  codeHtml  = concat $ snd $ mapAccumL (code2html m) [] codes++code2html :: ModuleIdent -> [QualIdent] -> Code -> ([QualIdent], String)+code2html m defs c+  | isCall c  = (defs, maybe tag (addEntityLink m tag) (getQualIdent c))+  | isDecl c  = case getQualIdent c of+      Just i | i `notElem` defs+        -> (i:defs, spanTag (code2class c) (escIdent i) (escCode c))+      _ -> (defs, tag)+  | otherwise = case c of+      ModuleName m' -> (defs, addModuleLink m m' tag)+      _             -> (defs, tag)+  where tag = spanTag (code2class c) "" (escCode c)++escCode :: Code -> String+escCode = htmlQuote . code2string++escIdent :: QualIdent -> String+escIdent = htmlQuote . idName . unqualify++spanTag :: String -> String -> String -> String+spanTag clV idV str+  | null clV && null idV = str+  | otherwise            = "<span" ++ codeclass ++ idValue ++ ">"+                           ++ str ++ "</span>"+  where+  codeclass = if null clV then "" else " class=\"" ++ clV ++ "\""+  idValue   = if null idV then "" else " id=\"" ++ idV ++ "\""++-- which code has which css class+-- @param code+-- @return css class of the code+code2class :: Code -> String+code2class (Space          _) = ""+code2class NewLine            = ""+code2class (Keyword        _) = "keyword"+code2class (Pragma         _) = "pragma"+code2class (Symbol         _) = "symbol"+code2class (TypeCons   _ _ _) = "type"+code2class (DataCons   _ _ _) = "cons"+code2class (Function   _ _ _) = "func"+code2class (Identifier _ _ _) = "ident"+code2class (ModuleName     _) = "module"+code2class (Commentary     _) = "comment"+code2class (NumberCode     _) = "number"+code2class (StringCode     _) = "string"+code2class (CharCode       _) = "char"++addModuleLink :: ModuleIdent -> ModuleIdent -> String -> String+addModuleLink m m' str+  = "<a href=\"" ++ makeRelativePath m m' ++ "\">" ++ str ++ "</a>"++addEntityLink :: ModuleIdent -> String -> QualIdent -> String+addEntityLink m str qid =+  "<a href=\"" ++ modPath ++ "#" ++ fragment  ++ "\">" ++ str ++ "</a>"+  where+  modPath       = maybe "" (makeRelativePath m) mmid+  fragment      = string2urlencoded (idName ident)+  (mmid, ident) = (qidModule qid, qidIdent qid)++makeRelativePath :: ModuleIdent -> ModuleIdent -> String+makeRelativePath cur new  | cur == new = ""+                          | otherwise  = htmlName new++isCall :: Code -> Bool+isCall (TypeCons   TypeExport _ _) = True+isCall (TypeCons   TypeImport _ _) = True+isCall (TypeCons   TypeRefer  _ _) = True+isCall (TypeCons   _          _ _) = False+isCall (Identifier _          _ _) = False+isCall c                       = not (isDecl c) && isJust (getQualIdent c)++isDecl :: Code -> Bool+isDecl (DataCons ConsDeclare _ _) = True+isDecl (Function FuncDeclare _ _) = True+isDecl (TypeCons TypeDeclare _ _) = True+isDecl _                          = False++-- Translates arbitrary strings into equivalent urlencoded string.+string2urlencoded :: String -> String+string2urlencoded = escapeURIString isUnreserved++htmlQuote :: String -> String+htmlQuote [] = []+htmlQuote (c : cs)+  | c == '<'  = "&lt;"    ++ htmlQuote cs+  | c == '>'  = "&gt;"    ++ htmlQuote cs+  | c == '&'  = "&amp;"   ++ htmlQuote cs+  | c == '"'  = "&quot;"  ++ htmlQuote cs+  | c == 'ä'  = "&auml;"  ++ htmlQuote cs+  | c == 'ö'  = "&ouml;"  ++ htmlQuote cs+  | c == 'ü'  = "&uuml;"  ++ htmlQuote cs+  | c == 'Ä'  = "&Auml;"  ++ htmlQuote cs+  | c == 'Ö'  = "&Ouml;"  ++ htmlQuote cs+  | c == 'Ü'  = "&Uuml;"  ++ htmlQuote cs+  | c == 'ß'  = "&szlig;" ++ htmlQuote cs+  | otherwise = c : htmlQuote cs
+ src/Html/SyntaxColoring.hs view
@@ -0,0 +1,582 @@+{- |+    Module      :  $Header$+    Description :  Split module into code fragments+    Copyright   :  (c) 2014 - 2016 Björn Peemöller+                       2016        Jan Tikovsky+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module arranges the tokens of the module into different code+    categories for HTML presentation. The parsed and qualified module+    is used to establish links between used identifiers and their definitions.++    The fully qualified module is traversed to generate a list of code elements.+    Code elements representing identifiers are distinguished by their kind+    (type constructor, data constructor, function, (type) variable).+    They include information about their usage (i.e., declaration, call etc.)+    and whether the identifier occurs fully qualified in+    the source code or not. Initially, all identifier codes are fully qualified.++    In a next step, the token stream of the given program and the code list are+    traversed sequentially (see `encodeToks`). The information in the token+    stream is used to:++      * add code elements for newlines, spaces and pragmas+      * update the qualification information of identifiers in the code list.+-}++module Html.SyntaxColoring+  ( Code (..), TypeUsage (..), ConsUsage (..)+  , IdentUsage (..), FuncUsage (..)+  , genProgram, code2string, getQualIdent+  ) where++import Data.Function (on)+import Data.List     (sortBy)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Syntax++import Base.Messages++-- |Type of codes which are distinguished for HTML output+-- the boolean flags indicate whether the corresponding identifier+-- occurs qualified in the source module+data Code+  = Keyword     String+  | Space       Int+  | NewLine+  | Pragma      String+  | TypeCons    TypeUsage  Bool QualIdent+  | DataCons    ConsUsage  Bool QualIdent+  | Function    FuncUsage  Bool QualIdent+  | Identifier  IdentUsage Bool QualIdent+  | ModuleName  ModuleIdent+  | Commentary  String+  | NumberCode  String+  | StringCode  String+  | CharCode    String+  | Symbol      String+    deriving Show++data TypeUsage+  = TypeDeclare+  | TypeRefer+  | TypeExport+  | TypeImport+    deriving Show++data ConsUsage+  = ConsDeclare+  | ConsPattern+  | ConsCall+  | ConsInfix+  | ConsExport+  | ConsImport+    deriving Show++data FuncUsage+  = FuncDeclare+  | FuncTypeSig+  | FuncCall+  | FuncInfix+  | FuncExport+  | FuncImport+    deriving Show++data IdentUsage+  = IdDeclare -- declare a (type) variable+  | IdRefer   -- refer to a (type) variable+  | IdUnknown -- unknown usage+    deriving Show++-- @param fully qualified module+-- @param lex-Result+-- @return code list+genProgram :: Module a -> [(Position, Token)] -> [Code]+genProgram m pts = encodeToks (first "") (filter validCode (idsModule m)) pts++-- predicate to remove identifier codes for primitives+-- because they do not form valid link targets+validCode :: Code -> Bool+validCode (TypeCons   _ _ t) = t `notElem` [qUnitId, qListId]         && not (isQTupleId t)+validCode (DataCons   _ _ c) = c `notElem` [qUnitId, qNilId, qConsId] && not (isQTupleId c)+validCode (Identifier _ _ i) = not $ isAnonId $ unqualify i+validCode _                  = True++-- @param code+-- @return qid if available+getQualIdent :: Code -> Maybe QualIdent+getQualIdent (DataCons   _ _ qid) = Just qid+getQualIdent (Function   _ _ qid) = Just qid+getQualIdent (Identifier _ _ qid) = Just qid+getQualIdent (TypeCons   _ _ qid) = Just qid+getQualIdent _                    = Nothing++encodeToks :: Position -> [Code] -> [(Position, Token)] -> [Code]+encodeToks _   _   []                     = []+encodeToks cur ids toks@((pos, tok) : ts)+  -- advance line+  | line cur   < line   pos = NewLine : encodeToks (nl cur) ids toks+  -- advance column+  | column cur < column pos = let d = column pos - column cur+                              in  Space d : encodeToks (incr cur d) ids toks+  -- pragma token+  | isPragmaToken tok       = let (ps, (end:rest)) = break (isPragmaEnd . snd) toks+                                  s = unwords $ map (showToken . snd) (ps ++ [end])+                              in  Pragma s : encodeToks (incr cur (length s)) ids rest+  -- identifier token+  | isIdentTok tok          = case ids of+    []     -> encodeTok tok : encodeToks newPos [] ts+    (i:is)+      | tokenStr == code2string i' -> i' : encodeToks newPos is ts+  -- the 'otherwise' case should never occur if the token stream and+  -- the qualified AST which was used to generate the code list correspond to+  -- the same module+      | otherwise                  -> encodeToks cur is toks+      where i' = setQualified (isQualIdentTok tok) i+  -- other token+  | otherwise               = encodeTok tok : encodeToks newPos ids ts+  where+  tokenStr = showToken tok+  newPos   = incr cur (length tokenStr)++setQualified :: Bool -> Code -> Code+setQualified b (DataCons   u _ c) = DataCons u b c+setQualified b (Function   u _ f) = Function u b f+setQualified b (Identifier u _ i) = Identifier u b i+setQualified b (TypeCons   u _ t) = TypeCons u b t+setQualified _ m@(ModuleName   _) = m+setQualified _ s@(Symbol       _) = s+setQualified _ c                  = internalError $ "Html.SyntaxColoring.setQualified: " ++ show c++code2string :: Code -> String+code2string (Keyword           s) = s+code2string (Space             i) = replicate i ' '+code2string NewLine               = "\n"+code2string (Pragma            s) = s+code2string (DataCons    _ b qid) = ident2string b qid+code2string (TypeCons    _ b qid) = ident2string b qid+code2string (Function    _ b qid) = ident2string b qid+code2string (Identifier  _ b qid) = ident2string b qid+code2string (ModuleName      mid) = moduleName mid+code2string (Commentary        s) = s+code2string (NumberCode        s) = s+code2string (StringCode        s) = s+code2string (CharCode          s) = s+code2string (Symbol            s) = s++ident2string :: Bool -> QualIdent -> String+ident2string False q = idName $ unqualify q+ident2string True  q = qualName q++encodeTok :: Token -> Code+encodeTok tok@(Token c _)+  | c `elem` numCategories          = NumberCode (showToken tok)+  | c == CharTok                    = CharCode   (showToken tok)+  | c == StringTok                  = StringCode (showToken tok)+  | c `elem` keywordCategories      = Keyword    (showToken tok)+  | c `elem` specialIdentCategories = Keyword    (showToken tok)+  | c `elem` punctuationCategories  = Symbol     (showToken tok)+  | c `elem` reservedOpsCategories  = Symbol     (showToken tok)+  | c `elem` commentCategories      = Commentary (showToken tok)+  | c `elem` identCategories        = Identifier IdUnknown False $ qualify $ mkIdent+                                      $ showToken tok+  | c `elem` whiteSpaceCategories   = Space 0+  | c `elem` pragmaCategories       = Pragma     (showToken tok)+  | otherwise                       = internalError $+    "SyntaxColoring.encodeTok: Unknown token " ++ showToken tok++numCategories :: [Category]+numCategories = [IntTok, FloatTok]++keywordCategories :: [Category]+keywordCategories =+  [ KW_case, KW_class, KW_data, KW_default, KW_deriving, KW_do, KW_else+  , KW_external, KW_fcase, KW_free, KW_if, KW_import, KW_in+  , KW_infix, KW_infixl, KW_infixr, KW_instance, KW_let, KW_module, KW_newtype+  , KW_of, KW_then, KW_type, KW_where+  ]++specialIdentCategories :: [Category]+specialIdentCategories =+  [ Id_as, Id_ccall, Id_forall, Id_hiding+  , Id_interface, Id_primitive, Id_qualified ]++punctuationCategories :: [Category]+punctuationCategories =+  [ LeftParen, RightParen, Semicolon, LeftBrace, RightBrace+  , LeftBracket, RightBracket, Comma, Underscore, Backquote ]++reservedOpsCategories :: [Category]+reservedOpsCategories =+  [ At, Colon, DotDot, DoubleArrow, DoubleColon, Equals, Backslash, Bar+  , LeftArrow, RightArrow, Tilde ]++commentCategories :: [Category]+commentCategories = [LineComment, NestedComment]++identCategories :: [Category]+identCategories = [Id, QId, Sym, QSym, SymDot, SymMinus, SymStar]++isPragmaToken :: Token -> Bool+isPragmaToken (Token c _) = c `elem` pragmaCategories++isPragmaEnd :: Token -> Bool+isPragmaEnd (Token c _) = c == PragmaEnd++isIdentTok :: Token -> Bool+isIdentTok (Token c _) = c `elem` identCategories++isQualIdentTok :: Token -> Bool+isQualIdentTok (Token c _) = c `elem` [QId, QSym]++whiteSpaceCategories :: [Category]+whiteSpaceCategories = [EOF, VSemicolon, VRightBrace]++pragmaCategories :: [Category]+pragmaCategories = [PragmaLanguage, PragmaOptions, PragmaEnd]++-- DECL Position++declPos :: Decl a -> Position+declPos (InfixDecl        p _ _ _    ) = p+declPos (DataDecl         p _ _ _ _  ) = p+declPos (ExternalDataDecl p _ _      ) = p+declPos (NewtypeDecl      p _ _ _ _  ) = p+declPos (TypeDecl         p _ _ _    ) = p+declPos (TypeSig          p _ _      ) = p+declPos (FunctionDecl     p _ _ _    ) = p+declPos (ExternalDecl     p _        ) = p+declPos (PatternDecl      p _ _      ) = p+declPos (FreeDecl         p _        ) = p+declPos (DefaultDecl      p _        ) = p+declPos (ClassDecl        p _ _ _ _  ) = p+declPos (InstanceDecl     p _ _ _ _  ) = p++cmpDecl :: Decl a -> Decl a -> Ordering+cmpDecl = compare `on` declPos++cmpImportDecl :: ImportDecl -> ImportDecl -> Ordering+cmpImportDecl = compare `on` (\ (ImportDecl p _ _ _ _) -> p)++-- -----------------------------------------------------------------------------+-- Extract all identifiers mentioned in the source code as a Code entity+-- in the order of their occurrence. The extracted information is then used+-- to enrich the identifier tokens with additional information, e.g., for+-- link generation.+-- -----------------------------------------------------------------------------++idsModule :: Module a -> [Code]+idsModule (Module _ mid es is ds) =+  let hdrCodes = ModuleName mid : idsExportSpec es+      impCodes = concatMap idsImportDecl (sortBy cmpImportDecl is)+      dclCodes = concatMap idsDecl       (sortBy cmpDecl ds)+  in  hdrCodes ++ impCodes ++ dclCodes++-- Exports++idsExportSpec ::  Maybe ExportSpec -> [Code]+idsExportSpec Nothing                 = []+idsExportSpec (Just (Exporting _ es)) = concatMap idsExport es++idsExport :: Export -> [Code]+idsExport (Export            qid) = [Function FuncExport False qid]+idsExport (ExportTypeWith qid cs) = TypeCons TypeExport False qid :+  map (DataCons ConsExport False . qualify) cs+idsExport (ExportTypeAll     qid) = [TypeCons TypeExport False qid]+idsExport (ExportModule      mid) = [ModuleName mid]++-- Imports++idsImportDecl :: ImportDecl -> [Code]+idsImportDecl (ImportDecl _ mid _ mAlias spec)+  = ModuleName mid : aliasCode ++ maybe [] (idsImportSpec mid) spec+  where aliasCode = maybe [] ((:[]) . ModuleName) mAlias++idsImportSpec :: ModuleIdent -> ImportSpec -> [Code]+idsImportSpec mid (Importing _ is) = concatMap (idsImport mid) is+idsImportSpec mid (Hiding    _ is) = concatMap (idsImport mid) is++idsImport :: ModuleIdent -> Import -> [Code]+idsImport mid (Import            i) =+  [Function FuncImport False $ qualifyWith mid i]+idsImport mid (ImportTypeWith t cs) =+  TypeCons TypeImport False (qualifyWith mid t) :+    map (DataCons ConsImport False . qualifyWith mid) cs+idsImport mid (ImportTypeAll     t) =+  [TypeCons TypeImport False $ qualifyWith mid t]++-- Declarations++idsDecl :: Decl a -> [Code]+idsDecl (InfixDecl        _ _ _ ops) =+  map (Function FuncInfix False . qualify) ops+idsDecl (DataDecl   _ d vs cds clss) =+  TypeCons TypeDeclare False (qualify d) :+    map (Identifier IdDeclare False . qualify) vs +++      concatMap idsConstrDecl cds ++ map (TypeCons TypeRefer False) clss+idsDecl (ExternalDataDecl    _ d vs) =+  TypeCons TypeDeclare False (qualify d) :+    map (Identifier IdDeclare False . qualify) vs+idsDecl (NewtypeDecl _ t vs nc clss) =+  TypeCons TypeDeclare False (qualify t) :+    map (Identifier IdDeclare False . qualify) vs ++ idsNewConstrDecl nc +++      map (TypeCons TypeRefer False) clss+idsDecl (TypeDecl         _ t vs ty) =+  TypeCons TypeDeclare False (qualify t) :+    map (Identifier IdDeclare False . qualify) vs ++ idsTypeExpr ty+idsDecl (TypeSig           _ fs qty) =+  map (Function FuncTypeSig False . qualify) fs ++ idsQualTypeExpr qty+idsDecl (FunctionDecl     _ _ _ eqs) = concatMap idsEquation eqs+idsDecl (ExternalDecl          _ fs) =+  map (Function FuncDeclare False . qualify . varIdent) fs+idsDecl (PatternDecl        _ p rhs) = idsPat p ++ idsRhs rhs+idsDecl (FreeDecl              _ vs) =+  map (Identifier IdDeclare False . qualify . varIdent) vs+idsDecl (DefaultDecl          _ tys) = concatMap idsTypeExpr tys+idsDecl (ClassDecl      _ cx c v ds) =+  idsContext cx ++ TypeCons TypeDeclare False (qualify c) :+    Identifier IdDeclare False (qualify v) : concatMap idsClassDecl ds+idsDecl (InstanceDecl  _ cx c ty ds) = idsContext cx +++  TypeCons TypeRefer False c : idsTypeExpr ty ++ concatMap idsInstanceDecl ds++idsConstrDecl :: ConstrDecl -> [Code]+idsConstrDecl (ConstrDecl     _ vs cx c tys) =+  map (Identifier IdDeclare False . qualify) vs ++ idsContext cx +++    DataCons ConsDeclare False (qualify c) : concatMap idsTypeExpr tys+idsConstrDecl (ConOpDecl _ vs cx ty1 op ty2) =+  map (Identifier IdDeclare False . qualify) vs ++ idsContext cx +++  idsTypeExpr ty1 ++ (DataCons ConsDeclare False $ qualify op) : idsTypeExpr ty2+idsConstrDecl (RecordDecl      _ vs cx c fs) =+  map (Identifier IdDeclare False . qualify) vs ++ idsContext cx +++    DataCons ConsDeclare False (qualify c) : concatMap idsFieldDecl fs++idsNewConstrDecl :: NewConstrDecl -> [Code]+idsNewConstrDecl (NewConstrDecl _ c     ty) =+  DataCons ConsDeclare False (qualify c) : idsTypeExpr ty+idsNewConstrDecl (NewRecordDecl _ c (l,ty)) =+  DataCons ConsDeclare False (qualify c) :+    (Function FuncDeclare False $ qualify l) : idsTypeExpr ty++idsClassDecl :: Decl a -> [Code]+idsClassDecl (TypeSig       _ fs qty) =+  map (Function FuncDeclare False . qualify) fs ++ idsQualTypeExpr qty+idsClassDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs+idsClassDecl _                        =+  internalError "SyntaxColoring.idsClassDecl"++idsInstanceDecl :: Decl a -> [Code]+idsInstanceDecl (FunctionDecl _ _ _ eqs) = concatMap idsEquation eqs+idsInstanceDecl _                        =+  internalError "SyntaxColoring.idsInstanceDecl"++idsQualTypeExpr :: QualTypeExpr -> [Code]+idsQualTypeExpr (QualTypeExpr cx ty) = idsContext cx ++ idsTypeExpr ty++idsContext :: Context -> [Code]+idsContext = concatMap idsConstraint++idsConstraint :: Constraint -> [Code]+idsConstraint (Constraint qcls ty) =+  TypeCons TypeRefer False qcls : idsTypeExpr ty++idsTypeExpr :: TypeExpr -> [Code]+idsTypeExpr (ConstructorType qid) = [TypeCons TypeRefer False qid]+idsTypeExpr (ApplyType   ty1 ty2) = concatMap idsTypeExpr [ty1, ty2]+idsTypeExpr (VariableType      v) = [Identifier IdRefer False (qualify v)]+idsTypeExpr (TupleType       tys) = concatMap idsTypeExpr tys+idsTypeExpr (ListType         ty) = idsTypeExpr ty+idsTypeExpr (ArrowType   ty1 ty2) = concatMap idsTypeExpr [ty1, ty2]+idsTypeExpr (ParenType        ty) = idsTypeExpr ty+idsTypeExpr (ForallType    vs ty) =+  map (Identifier IdDeclare False . qualify) vs ++ idsTypeExpr ty++idsFieldDecl :: FieldDecl -> [Code]+idsFieldDecl (FieldDecl _ ls ty) =+  map (Function FuncDeclare False . qualify . unRenameIdent) ls ++ idsTypeExpr ty++idsEquation :: Equation a -> [Code]+idsEquation (Equation _ lhs rhs) = idsLhs lhs ++ idsRhs rhs++idsLhs :: Lhs a -> [Code]+idsLhs (FunLhs    f ps) = Function FuncDeclare False (qualify f) : concatMap idsPat ps+idsLhs (OpLhs p1 op p2) = idsPat p1 ++ [Function FuncDeclare False $ qualify op]+                                    ++ idsPat p2+idsLhs (ApLhs   lhs ps) = idsLhs lhs ++ concatMap idsPat ps++idsRhs :: Rhs a -> [Code]+idsRhs (SimpleRhs _ e ds) = idsExpr e ++ concatMap idsDecl ds+idsRhs (GuardedRhs ce ds) = concatMap idsCondExpr ce ++ concatMap idsDecl ds++idsCondExpr :: CondExpr a -> [Code]+idsCondExpr (CondExpr _ e1 e2) = idsExpr e1 ++ idsExpr e2++idsPat :: Pattern a -> [Code]+idsPat (LiteralPattern          _ _) = []+idsPat (NegativePattern         _ _) = []+idsPat (VariablePattern         _ v) = [Identifier IdDeclare False (qualify v)]+idsPat (ConstructorPattern _ qid ps) =+  DataCons ConsPattern False qid : concatMap idsPat ps+idsPat (InfixPattern    _ p1 qid p2) =+  idsPat p1 ++ DataCons ConsPattern False qid : idsPat p2+idsPat (ParenPattern              p) = idsPat p+idsPat (RecordPattern      _ qid fs) =+  DataCons ConsPattern False qid : concatMap (idsField idsPat) fs+idsPat (TuplePattern            ps) = concatMap idsPat ps+idsPat (ListPattern            _ ps) = concatMap idsPat ps+idsPat (AsPattern               v p) =+  Identifier IdDeclare False (qualify v) : idsPat p+idsPat (LazyPattern               p) = idsPat p+idsPat (FunctionPattern    _ qid ps) =+  Function FuncCall False qid : concatMap idsPat ps+idsPat (InfixFuncPattern  _ p1 f p2) =+  idsPat p1 ++ Function FuncInfix False f : idsPat p2++idsExpr :: Expression a -> [Code]+idsExpr (Literal              _ _) = []+idsExpr (Variable           _ qid)+  | isQualified qid                = [Function FuncCall False qid]+  | hasGlobalScope (unqualify qid) = [Function FuncCall False qid]+  | otherwise                      = [Identifier IdRefer False qid]+idsExpr (Constructor        _ qid) = [DataCons ConsCall False qid]+idsExpr (Paren                  e) = idsExpr e+idsExpr (Typed              e qty) = idsExpr e ++ idsQualTypeExpr qty+idsExpr (Record          _ qid fs) =+  DataCons ConsCall False qid : concatMap (idsField idsExpr) fs+idsExpr (RecordUpdate        e fs) =+  idsExpr e ++ concatMap (idsField idsExpr) fs+idsExpr (Tuple                 es) = concatMap idsExpr es+idsExpr (List                _ es) = concatMap idsExpr es+idsExpr (ListCompr        e stmts) = idsExpr e ++ concatMap idsStmt stmts+idsExpr (EnumFrom               e) = idsExpr e+idsExpr (EnumFromThen       e1 e2) = concatMap idsExpr [e1, e2]+idsExpr (EnumFromTo         e1 e2) = concatMap idsExpr [e1, e2]+idsExpr (EnumFromThenTo  e1 e2 e3) = concatMap idsExpr [e1, e2, e3]+idsExpr (UnaryMinus             e) = Symbol "-" : idsExpr e+idsExpr (Apply              e1 e2) = idsExpr e1 ++ idsExpr e2+idsExpr (InfixApply      e1 op e2) = idsExpr e1 ++ idsInfix op ++ idsExpr e2+idsExpr (LeftSection         e op) = idsExpr e ++ idsInfix op+idsExpr (RightSection        op e) = idsInfix op ++ idsExpr e+idsExpr (Lambda              ps e) = concatMap idsPat ps ++ idsExpr e+idsExpr (Let                 ds e) = concatMap idsDecl ds ++ idsExpr e+idsExpr (Do               stmts e) = concatMap idsStmt stmts ++ idsExpr e+idsExpr (IfThenElse      e1 e2 e3) = concatMap idsExpr [e1, e2, e3]+idsExpr (Case            _ e alts) = idsExpr e ++ concatMap idsAlt alts++idsField :: (a -> [Code]) -> Field a -> [Code]+idsField f (Field _ l x) = Function FuncCall False l : f x++idsInfix :: InfixOp a -> [Code]+idsInfix (InfixOp     _ qid) = [Function FuncInfix False qid]+idsInfix (InfixConstr _ qid) = [DataCons ConsInfix False qid]++idsStmt :: Statement a -> [Code]+idsStmt (StmtExpr   e) = idsExpr e+idsStmt (StmtDecl  ds) = concatMap idsDecl ds+idsStmt (StmtBind p e) = idsPat p ++ idsExpr e++idsAlt :: Alt a -> [Code]+idsAlt (Alt _ p rhs) = idsPat p ++ idsRhs rhs++-- -----------------------------------------------------------------------------+-- Conversion from a token to a string+-- -----------------------------------------------------------------------------++showToken :: Token -> String+showToken (Token Id                 a) = showAttr a+showToken (Token QId                a) = showAttr a+showToken (Token Sym                a) = showAttr a+showToken (Token QSym               a) = showAttr a+showToken (Token IntTok             a) = showAttr a+showToken (Token FloatTok           a) = showAttr a+showToken (Token CharTok            a) = showAttr a+showToken (Token StringTok          a) = showAttr a+showToken (Token LeftParen          _) = "("+showToken (Token RightParen         _) = ")"+showToken (Token Semicolon          _) = ";"+showToken (Token LeftBrace          _) = "{"+showToken (Token RightBrace         _) = "}"+showToken (Token LeftBracket        _) = "["+showToken (Token RightBracket       _) = "]"+showToken (Token Comma              _) = ","+showToken (Token Underscore         _) = "_"+showToken (Token Backquote          _) = "`"+showToken (Token VSemicolon         _) = ""+showToken (Token VRightBrace        _) = ""+showToken (Token At                 _) = "@"+showToken (Token Colon              _) = ":"+showToken (Token DotDot             _) = ".."+showToken (Token DoubleArrow        _) = "=>"+showToken (Token DoubleColon        _) = "::"+showToken (Token Equals             _) = "="+showToken (Token Backslash          _) = "\\"+showToken (Token Bar                _) = "|"+showToken (Token LeftArrow          _) = "<-"+showToken (Token RightArrow         _) = "->"+showToken (Token Tilde              _) = "~"+showToken (Token SymDot             _) = "."+showToken (Token SymMinus           _) = "-"+showToken (Token SymStar            _) = "*"+showToken (Token KW_case            _) = "case"+showToken (Token KW_class           _) = "class"+showToken (Token KW_data            _) = "data"+showToken (Token KW_default         _) = "default"+showToken (Token KW_deriving        _) = "deriving"+showToken (Token KW_do              _) = "do"+showToken (Token KW_else            _) = "else"+showToken (Token KW_external        _) = "external"+showToken (Token KW_fcase           _) = "fcase"+showToken (Token KW_free            _) = "free"+showToken (Token KW_if              _) = "if"+showToken (Token KW_import          _) = "import"+showToken (Token KW_in              _) = "in"+showToken (Token KW_infix           _) = "infix"+showToken (Token KW_infixl          _) = "infixl"+showToken (Token KW_infixr          _) = "infixr"+showToken (Token KW_instance        _) = "instance"+showToken (Token KW_let             _) = "let"+showToken (Token KW_module          _) = "module"+showToken (Token KW_newtype         _) = "newtype"+showToken (Token KW_of              _) = "of"+showToken (Token KW_then            _) = "then"+showToken (Token KW_type            _) = "type"+showToken (Token KW_where           _) = "where"+showToken (Token Id_as              _) = "as"+showToken (Token Id_ccall           _) = "ccall"+showToken (Token Id_forall          _) = "forall"+showToken (Token Id_hiding          _) = "hiding"+showToken (Token Id_interface       _) = "interface"+showToken (Token Id_primitive       _) = "primitive"+showToken (Token Id_qualified       _) = "qualified"+showToken (Token EOF                _) = ""+showToken (Token PragmaHiding       _) = "{-# HIDING"+showToken (Token PragmaLanguage     _) = "{-# LANGUAGE"+showToken (Token PragmaOptions      a) = "{-# OPTIONS" ++ showAttr a+showToken (Token PragmaMethod       _) = "{-# METHOD"+showToken (Token PragmaModule       _) = "{-# MODULE"+showToken (Token PragmaEnd          _) = "#-}"+showToken (Token LineComment   (StringAttributes s _)) = s+showToken (Token LineComment   a                     ) = showAttr a+showToken (Token NestedComment (StringAttributes s _)) = s+showToken (Token NestedComment                      a) = showAttr a++showAttr :: Attributes -> [Char]+showAttr NoAttributes             = ""+showAttr (CharAttributes     c _) = show c+showAttr (IntAttributes      i _) = show i+showAttr (FloatAttributes    f _) = show f+showAttr (StringAttributes   s _) = show s+showAttr (IdentAttributes    m i)+  | null m    = idName   $                          (mkIdent i)+  | otherwise = qualName $ qualifyWith (mkMIdent m) (mkIdent i)+showAttr (OptionsAttributes mt s) = showTool mt ++ ' ' : s++showTool :: Maybe String -> String+showTool Nothing  = ""+showTool (Just t) = '_' : t
+ src/IL.hs view
@@ -0,0 +1,19 @@+{- |+    Module      :  $Header$+    Description :  Intermediate language+    Copyright   :  (c) 2014, Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module is a simple re-export of the definition of the AST of IL+    and the pretty-printing of IL modules.+-}+module IL ( module IL.Type, module IL.Typing, ppModule, showModule ) where++import IL.Pretty     (ppModule)+import IL.ShowModule (showModule)+import IL.Type+import IL.Typing
− src/IL/CurryToIL.lhs
@@ -1,598 +0,0 @@--% $Id: ILTrans.lhs,v 1.86 2004/02/13 19:23:58 wlux Exp $-%-% Copyright (c) 1999-2003, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{ILTrans.lhs}-\section{Translating Curry into the Intermediate Language}-After desugaring and lifting have been performed, the source code is-translated into the intermediate language. Besides translating from-source terms and expressions into intermediate language terms and-expressions this phase in particular has to implement the pattern-matching algorithm for equations and case expressions.--Because of name conflicts between the source and intermediate language-data structures, we can use only a qualified import for the-\texttt{IL} module.-\begin{verbatim}--> module IL.CurryToIL(ilTrans,ilTransIntf, translType) where--> import Data.Maybe-> import Data.List-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Types-> import Base-> import qualified IL.Type as IL-> import Utils----\end{verbatim}-\paragraph{Modules}-At the top-level, the compiler has to translate data type, newtype,-function, and external declarations. When translating a data type or-newtype declaration, we ignore the types in the declaration and lookup-the types of the constructors in the type environment instead because-these types are already fully expanded, i.e., they do not include any-alias types.-\begin{verbatim}--> ilTrans :: Bool -> ValueEnv -> TCEnv -> EvalEnv -> Module -> IL.Module-> ilTrans flat tyEnv tcEnv evEnv (Module m _ ds) = ->   IL.Module m (imports m ds') ds'->   where ds' = concatMap (translGlobalDecl flat m tyEnv tcEnv evEnv) ds--> translGlobalDecl :: Bool -> ModuleIdent -> ValueEnv -> TCEnv -> EvalEnv->                  -> Decl -> [IL.Decl]-> translGlobalDecl _ m tyEnv tcEnv _ (DataDecl _ tc tvs cs) =->   [translData m tyEnv tcEnv tc tvs cs]-> translGlobalDecl _ m tyEnv tcEnv _ (NewtypeDecl _ tc tvs nc) =->   [translNewtype m tyEnv tcEnv tc tvs nc]-> translGlobalDecl flat m tyEnv tcEnv evEnv (FunctionDecl pos f eqs) =->   [translFunction pos flat m tyEnv tcEnv evEnv f eqs]-> translGlobalDecl _ m tyEnv tcEnv _ (ExternalDecl _ cc ie f _) =->   [translExternal m tyEnv tcEnv f cc (fromJust ie)]-> translGlobalDecl _ _ _ _ _ _ = []--> translData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] -> [ConstrDecl]->            -> IL.Decl-> translData m tyEnv tcEnv tc tvs cs =->   IL.DataDecl (qualifyWith m tc) (length tvs)->               (map (translConstrDecl m tyEnv tcEnv) cs)--> translNewtype :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] ->	        -> NewConstrDecl -> IL.Decl-> translNewtype m tyEnv tcEnv tc tvs (NewConstrDecl _ _ c _) =->   IL.NewtypeDecl (qualifyWith m tc) (length tvs)->                  (IL.ConstrDecl c' (translType' m tyEnv tcEnv ty))->                  -- (IL.ConstrDecl c' (translType ty))->   where c' = qualifyWith m c->         TypeArrow ty _ = constrType tyEnv c'--> translConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> ConstrDecl->                  -> IL.ConstrDecl [IL.Type]-> translConstrDecl m tyEnv tcEnv d =->   IL.ConstrDecl c' (map (translType' m tyEnv tcEnv)->	                  (arrowArgs (constrType tyEnv c')))->   -- IL.ConstrDecl c' (map translType (arrowArgs (constrType tyEnv c')))->   where c' = qualifyWith m (constr d)->         constr (ConstrDecl _ _ c _) = c->         constr (ConOpDecl _ _ _ op _) = op--> translExternal :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> CallConv->                -> String -> IL.Decl-> translExternal m tyEnv tcEnv f cc ie =->   IL.ExternalDecl f' (callConv cc) ie ->                   (translType' m tyEnv tcEnv (varType tyEnv f'))->   -- IL.ExternalDecl f' (callConv cc) ie (translType (varType tyEnv f'))->   where f' = qualifyWith m f->         callConv CallConvPrimitive = IL.Primitive->         callConv CallConvCCall = IL.CCall--\end{verbatim}-\paragraph{Interfaces}-In order to generate code, the compiler also needs to know the tags-and arities of all imported data constructors. For that reason we-compile the data type declarations of all interfaces into the-intermediate language, too. In this case we do not lookup the-types in the environment because the types in the interfaces are-already fully expanded. Note that we do not translate data types-which are imported into the interface from some other module.-\begin{verbatim}--> ilTransIntf :: ValueEnv -> TCEnv -> Interface -> [IL.Decl]-> ilTransIntf tyEnv tcEnv (Interface m ds) = ->   foldr (translIntfDecl m tyEnv tcEnv) [] ds--> translIntfDecl :: ModuleIdent -> ValueEnv -> TCEnv -> IDecl -> [IL.Decl] ->	         -> [IL.Decl]-> translIntfDecl m tyEnv tcEnv (IDataDecl _ tc tvs cs) ds->   | not (isQualified tc) = ->     translIntfData m tyEnv tcEnv (unqualify tc) tvs cs : ds-> translIntfDecl _ _ _ _ ds = ds--> translIntfData :: ModuleIdent -> ValueEnv -> TCEnv -> Ident -> [Ident] ->	         -> [Maybe ConstrDecl] -> IL.Decl-> translIntfData m tyEnv tcEnv tc tvs cs =->   IL.DataDecl (qualifyWith m tc) (length tvs)->               (map (maybe hiddenConstr ->	                    (translIntfConstrDecl m tyEnv tcEnv tvs)) cs)->   where hiddenConstr = IL.ConstrDecl qAnonId []->         qAnonId = qualify anonId--> translIntfConstrDecl :: ModuleIdent -> ValueEnv -> TCEnv -> [Ident] ->                      -> ConstrDecl -> IL.ConstrDecl [IL.Type]-> translIntfConstrDecl m tyEnv tcEnv tvs (ConstrDecl _ _ c tys) =->   IL.ConstrDecl (qualifyWith m c) (map (translType' m tyEnv tcEnv)->			                 (toQualTypes m tvs tys))->   -- IL.ConstrDecl (qualifyWith m c) (map translType (toQualTypes m tvs tys))-> translIntfConstrDecl m tyEnv tcEnv tvs (ConOpDecl _ _ ty1 op ty2) =->   IL.ConstrDecl (qualifyWith m op)->                 (map (translType' m tyEnv tcEnv)->	               (toQualTypes m tvs [ty1,ty2]))->   -- IL.ConstrDecl (qualifyWith m op)->   --              (map translType (toQualTypes m tvs [ty1,ty2]))--\end{verbatim}-\paragraph{Types}-The type representation in the intermediate language is the same as-the internal representation except that it does not support-constrained type variables and skolem types. The former are fixed and-the later are replaced by fresh type constructors.--Due to possible occurrence of record types, it is necessary to transform-them back into their corresponding type constructors.-\begin{verbatim}--> translType' :: ModuleIdent -> ValueEnv -> TCEnv -> Type -> IL.Type-> translType' m tyEnv tcEnv ty =->   translType (elimRecordTypes m tyEnv tcEnv (maximum (0:(typeVars ty))) ty)--> translType :: Type -> IL.Type-> translType (TypeConstructor tc tys) =->   IL.TypeConstructor tc (map translType tys)-> translType (TypeVariable tv) = IL.TypeVariable tv-> translType (TypeConstrained tys _) = translType (head tys)-> translType (TypeArrow ty1 ty2) =->   IL.TypeArrow (translType ty1) (translType ty2)-> translType (TypeSkolem k) =->   IL.TypeConstructor (qualify (mkIdent ("_" ++ show k))) []--> elimRecordTypes :: ModuleIdent -> ValueEnv -> TCEnv -> Int -> Type -> Type-> elimRecordTypes m tyEnv tcEnv n (TypeConstructor t tys) =->   TypeConstructor t (map (elimRecordTypes m tyEnv tcEnv n) tys)-> elimRecordTypes m tyEnv tcEnv n (TypeVariable v) =->   TypeVariable v-> elimRecordTypes m tyEnv tcEnv n (TypeConstrained tys v) =->   TypeConstrained (map (elimRecordTypes m tyEnv tcEnv n) tys) v-> elimRecordTypes m tyEnv tcEnv n (TypeArrow t1 t2) =->   TypeArrow (elimRecordTypes m tyEnv tcEnv n t1)->             (elimRecordTypes m tyEnv tcEnv n t2)-> elimRecordTypes m tyEnv tcEnv n (TypeSkolem v) =->   TypeSkolem v-> elimRecordTypes m tyEnv tcEnv n (TypeRecord fs _)->   | null fs = internalError "elimRecordTypes: empty record type"->   | otherwise =->     case (lookupValue (fst (head fs)) tyEnv) of->       [Label _ r _] ->->         case (qualLookupTC r tcEnv) of->           [AliasType _ n' (TypeRecord fs' _)] ->->	      let is = [0 .. n'-1]->                 vs = foldl (matchTypeVars fs)->			     Map.empty->			     fs'->		  tys = map (\i -> maybe (TypeVariable (i+n))->			                 (elimRecordTypes m tyEnv tcEnv n)->		                         (Map.lookup i vs))->		            is ->	      in  TypeConstructor r tys->	    _ -> internalError "elimRecordTypes: no record type"->       _ -> internalError "elimRecordTypes: no label"--> matchTypeVars :: [(Ident,Type)] -> Map.Map Int Type -> (Ident,Type) ->	           -> Map.Map Int Type-> matchTypeVars fs vs (l,ty) =->   maybe vs (match vs ty) (lookup l fs)->   where->   match vs (TypeVariable i) ty' = Map.insert i ty' vs->   match vs (TypeConstructor _ tys) (TypeConstructor _ tys') =->     matchList vs tys tys'->   match vs (TypeConstrained tys _) (TypeConstrained tys' _) =->     matchList vs tys tys'->   match vs (TypeArrow ty1 ty2) (TypeArrow ty1' ty2') =->     matchList vs [ty1,ty2] [ty1',ty2']->   match vs (TypeSkolem _) (TypeSkolem _) = vs->   match vs (TypeRecord fs _) (TypeRecord fs' _) =->     foldl (matchTypeVars fs') vs fs->   match vs ty ty' = ->     internalError ("matchTypeVars: " ++ show ty ++ "\n" ++ show ty')->->   matchList vs tys tys' = ->     foldl (\vs' (ty,ty') -> match vs' ty ty') vs (zip tys tys')--\end{verbatim}-\paragraph{Functions}-Each function in the program is translated into a function of the-intermediate language. The arguments of the function are renamed such-that all variables occurring in the same position (in different-equations) have the same name. This is necessary in order to-facilitate the translation of pattern matching into a \texttt{case}-expression. We use the following simple convention here: The top-level-arguments of the function are named from left to right \texttt{\_1},-\texttt{\_2}, and so on. The names of nested arguments are constructed-by appending \texttt{\_1}, \texttt{\_2}, etc. from left to right to-the name that were assigned to a variable occurring at the position of-the constructor term.--Some special care is needed for the selector functions introduced by-the compiler in place of pattern bindings. In order to generate the-code for updating all pattern variables, the equality of names between-the pattern variables in the first argument of the selector function-and their repeated occurrences in the remaining arguments must be-preserved. This means that the second and following arguments of a-selector function have to be renamed according to the name mapping-computed for its first argument.--If an evaluation annotation is available for a function, it determines-the evaluation mode of the case expression. Otherwise, the function-uses flexible matching.-\begin{verbatim}--> type RenameEnv = Map.Map Ident Ident--> translFunction :: Position -> Bool -> ModuleIdent -> ValueEnv -> TCEnv->       -> EvalEnv -> Ident -> [Equation] -> IL.Decl-> translFunction pos flat m tyEnv tcEnv evEnv f eqs =->   -- - | f == mkIdent "fun" = error (show (translType' m tyEnv tcEnv ty))->   -- - | otherwise = ->     IL.FunctionDecl f' vs (translType' m tyEnv tcEnv ty) expr->    -- = IL.FunctionDecl f' vs (translType ty)->    --                  (match ev vs (map (translEquation tyEnv vs vs'') eqs))->   where f'  = qualifyWith m f->         ty  = varType tyEnv f'->         -- ty' = elimRecordType m tyEnv tcEnv (maximum (0:(typeVars ty))) ty->         ev' = Map.lookup f evEnv->         ev  = maybe (defaultMode ty) evalMode ev'->         vs  = if not flat && isFpSelectorId f then translArgs eqs vs' else vs'->         (vs',vs'') = splitAt (equationArity (head eqs)) ->                              (argNames (mkIdent ""))->         expr | ev' == Just EvalChoice->                = IL.Apply ->                    (IL.Function ->                       (qualifyWith preludeMIdent (mkIdent "commit"))->                       1)->                    (match (srcRefOf pos) IL.Rigid vs ->                       (map (translEquation tyEnv vs vs'') eqs))->              | otherwise->                =  match (srcRefOf pos) ev vs (map (translEquation tyEnv vs vs'') eqs)->         ---->         -- (vs',vs'') = splitAt (arrowArity ty) (argNames (mkIdent ""))--> evalMode :: EvalAnnotation -> IL.Eval-> evalMode EvalRigid = IL.Rigid-> evalMode EvalChoice = error "eval choice is not yet supported"--> defaultMode :: Type -> IL.Eval-> defaultMode _ = IL.Flex->-> --defaultMode ty = if isIO (arrowBase ty) then IL.Rigid else IL.Flex-> --  where TypeConstructor qIOId _ = ioType undefined-> --        isIO (TypeConstructor tc [_]) = tc == qIOId-> --        isIO _ = False--> translArgs :: [Equation] -> [Ident] -> [Ident]-> translArgs [Equation _ (FunLhs _ (t:ts)) _] (v:_) =->   v : map (translArg (bindRenameEnv v t Map.empty)) ts->   where translArg env (VariablePattern v) = fromJust (Map.lookup v env)--> translEquation :: ValueEnv -> [Ident] -> [Ident] -> Equation->                -> ([NestedTerm],IL.Expression)-> translEquation tyEnv vs vs' (Equation _ (FunLhs _ ts) rhs) =->   (zipWith translTerm vs ts,->    translRhs tyEnv vs' (foldr2 bindRenameEnv Map.empty vs ts) rhs)--> translRhs :: ValueEnv -> [Ident] -> RenameEnv -> Rhs -> IL.Expression-> translRhs tyEnv vs env (SimpleRhs _ e _) = translExpr tyEnv vs env e---> equationArity :: Equation -> Int-> equationArity (Equation _ lhs _) = p_equArity lhs->  where->    p_equArity (FunLhs _ ts) = length ts->    p_equArity (OpLhs _ _ _) = 2->    p_equArity _             = error "ILTrans - illegal equation"---\end{verbatim}-\paragraph{Pattern Matching}-The pattern matching code searches for the left-most inductive-argument position in the left hand sides of all rules defining an-equation. An inductive position is a position where all rules have a-constructor rooted term. If such a position is found, a \texttt{case}-expression is generated for the argument at that position. The-matching code is then computed recursively for all of the alternatives-independently. If no inductive position is found, the algorithm looks-for the left-most demanded argument position, i.e., a position where-at least one of the rules has a constructor rooted term. If such a-position is found, an \texttt{or} expression is generated with those-cases that have a variable at the argument position in one branch and-all other rules in the other branch. If there is no demanded position,-the pattern matching is finished and the compiler translates the right-hand sides of the remaining rules, eventually combining them using-\texttt{or} expressions.--Actually, the algorithm below combines the search for inductive and-demanded positions. The function \texttt{match} scans the argument-lists for the left-most demanded position. If this turns out to be-also an inductive position, the function \texttt{matchInductive} is-called in order to generate a \texttt{case} expression. Otherwise, the-function \texttt{optMatch} is called that tries to find an inductive-position in the remaining arguments. If one is found,-\texttt{matchInductive} is called, otherwise the function-\texttt{optMatch} uses the demanded argument position found by-\texttt{match}.-\begin{verbatim}--> data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show--> pattern (NestedTerm t _) = t-> arguments (NestedTerm _ ts) = ts--> translLiteral :: Literal -> IL.Literal-> translLiteral (Char p c) = IL.Char p c-> translLiteral (Int id i) = IL.Int (srcRefOf (positionOfIdent id)) i-> translLiteral (Float p f) = IL.Float p f-> translLiteral _ = internalError "translLiteral"--> translTerm :: Ident -> ConstrTerm -> NestedTerm-> translTerm _ (LiteralPattern l) =->   NestedTerm (IL.LiteralPattern (translLiteral l)) []-> translTerm v (VariablePattern _) = NestedTerm (IL.VariablePattern v) []-> translTerm v (ConstructorPattern c ts) =->   NestedTerm (IL.ConstructorPattern c (take (length ts) vs))->              (zipWith translTerm vs ts)->   where vs = argNames v-> translTerm v (AsPattern _ t) = translTerm v t-> translTerm _ _ = internalError "translTerm"--> bindRenameEnv :: Ident -> ConstrTerm -> RenameEnv -> RenameEnv-> bindRenameEnv _ (LiteralPattern _) env = env-> bindRenameEnv v (VariablePattern v') env = Map.insert v' v env-> bindRenameEnv v (ConstructorPattern _ ts) env =->   foldr2 bindRenameEnv env (argNames v) ts-> bindRenameEnv v (AsPattern v' t) env = Map.insert v' v (bindRenameEnv v t env)-> bindRenameEnv _ _ env = internalError "bindRenameEnv"--> argNames :: Ident -> [Ident]-> argNames v = [mkIdent (prefix ++ show i) | i <- [1..]]->   where prefix = name v ++ "_"--> type Match = ([NestedTerm],IL.Expression)-> type Match' = ([NestedTerm] -> [NestedTerm],[NestedTerm],IL.Expression)--> isDefaultPattern :: IL.ConstrTerm -> Bool-> isDefaultPattern (IL.VariablePattern _) = True-> isDefaultPattern _ = False--> isDefaultMatch :: (IL.ConstrTerm,a) -> Bool-> isDefaultMatch = isDefaultPattern . fst--> match :: SrcRef -> IL.Eval -> [Ident] -> [Match] -> IL.Expression-> match _   ev [] alts = foldl1 IL.Or (map snd alts)-> match pos ev (v:vs) alts->   | null vars = e1->   | null nonVars = e2->   | otherwise = optMatch pos ev (IL.Or e1 e2) (v:) vs (map skipArg alts)->   where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)->         e1 = matchInductive pos ev id v vs nonVars->         e2 = match pos ev vs (map snd vars)->         tagAlt (t:ts,e) = (pattern t,(arguments t ++ ts,e))->         skipArg (t:ts,e) = ((t:),ts,e)--> optMatch :: SrcRef -> IL.Eval -> IL.Expression -> ([Ident] -> [Ident]) ->    -> [Ident] ->[Match'] -> IL.Expression-> optMatch _ ev e prefix [] alts = e-> optMatch pos ev e prefix (v:vs) alts->   | null vars = matchInductive pos ev prefix v vs nonVars->   | otherwise = optMatch pos ev e (prefix . (v:)) vs (map skipArg alts)->   where (vars,nonVars) = partition isDefaultMatch (map tagAlt alts)->         tagAlt (prefix,t:ts,e) = (pattern t,(prefix (arguments t ++ ts),e))->         skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)--> matchInductive :: SrcRef -> IL.Eval -> ([Ident] -> [Ident]) -> Ident ->    -> [Ident] ->[(IL.ConstrTerm,Match)] -> IL.Expression-> matchInductive pos ev prefix v vs alts =->   IL.Case pos ev (IL.Variable v) (matchAlts ev prefix vs alts)--> matchAlts :: IL.Eval -> ([Ident] -> [Ident]) -> [Ident] ->->     [(IL.ConstrTerm,Match)] -> [IL.Alt]-> matchAlts ev prefix vs [] = []-> matchAlts ev prefix vs ((t,alt):alts) =->   IL.Alt t (match (srcRefOf t) ->                   ev (prefix (vars t ++ vs)) (alt : map snd same)) :->   matchAlts ev prefix vs others->   where (same,others) = partition ((t ==) . fst) alts ->         vars (IL.ConstructorPattern _ vs) = vs->         vars _ = []--\end{verbatim}-Matching in a \texttt{case}-expression works a little bit differently.-In this case, the alternatives are matched from the first to the last-alternative and the first matching alternative is chosen. All-remaining alternatives are discarded.--\ToDo{The case matching algorithm should use type information in order-to detect total matches and immediately discard all alternatives which-cannot be reached.}-\begin{verbatim}--> caseMatch :: SrcRef -> ([Ident] -> [Ident]) -> [Ident] -> [Match'] ->    -> IL.Expression-> caseMatch _ prefix [] alts = thd3 (head alts)-> caseMatch r prefix (v:vs) alts->   | isDefaultMatch (head alts') =->       caseMatch r (prefix . (v:)) vs (map skipArg alts)->   | otherwise =->       IL.Case r IL.Rigid (IL.Variable v) (caseMatchAlts prefix vs alts')->   where alts' = map tagAlt alts->         tagAlt (prefix,t:ts,e) = (pattern t,(prefix,arguments t ++ ts,e))->         skipArg (prefix,t:ts,e) = (prefix . (t:),ts,e)--> caseMatchAlts ::->     ([Ident] -> [Ident]) -> [Ident] -> [(IL.ConstrTerm,Match')] -> [IL.Alt]-> caseMatchAlts prefix vs alts = map caseAlt (ts ++ ts')->   where (ts',ts) = partition isDefaultPattern (nub (map fst alts))->         caseAlt t =->           IL.Alt t (caseMatch (srcRefOf t) id (prefix (vars t ++ vs))->                               (matchingCases t alts))->         matchingCases t =->           map (joinArgs (vars t)) . filter (matches t . fst)->         matches t t' = t == t' || isDefaultPattern t'->         joinArgs vs (IL.VariablePattern _,(prefix,ts,e)) =->            (id,prefix (map varPattern vs ++ ts),e)->         joinArgs _ (_,(prefix,ts,e)) = (id,prefix ts,e)->         varPattern v = NestedTerm (IL.VariablePattern v) []->         vars (IL.ConstructorPattern _ vs) = vs->         vars _ = []--\end{verbatim}-\paragraph{Expressions}-Note that the case matching algorithm assumes that the matched-expression is accessible through a variable. The translation of case-expressions therefore introduces a let binding for the scrutinized-expression and immediately throws it away after the matching -- except-if the matching algorithm has decided to use that variable in the-right hand sides of the case expression. This may happen, for-instance, if one of the alternatives contains an \texttt{@}-pattern.-\begin{verbatim}--> translExpr :: ValueEnv -> [Ident] -> RenameEnv -> Expression -> IL.Expression-> translExpr _ _ _ (Literal l) = IL.Literal (translLiteral l)-> translExpr tyEnv _ env (Variable v) =->   case lookupVar v env of->     Just v' -> IL.Variable v'->     Nothing -> IL.Function v (arrowArity (varType tyEnv v))->   where lookupVar v env->           | isQualified v = Nothing->           | otherwise = Map.lookup (unqualify v) env-> translExpr tyEnv _ _ (Constructor c) =->   IL.Constructor c (arrowArity (constrType tyEnv c))-> translExpr tyEnv vs env (Apply e1 e2) =->   IL.Apply (translExpr tyEnv vs env e1) (translExpr tyEnv vs env e2)-> translExpr tyEnv vs env (Let ds e) =->   case ds of->     [ExtraVariables _ vs] -> foldr IL.Exist e' vs->     [d] | all (`notElem` bv d) (qfv emptyMIdent d) ->->       IL.Let (translBinding env' d) e'->     _ -> IL.Letrec (map (translBinding env') ds) e'->   where e' = translExpr tyEnv vs env' e->         env' = foldr2 Map.insert env bvs bvs->         bvs = bv ds->         translBinding env (PatternDecl _ (VariablePattern v) rhs) =->           IL.Binding v (translRhs tyEnv vs env rhs)->         translBinding env p = error $ "unexpected binding: "++show p-> translExpr tyEnv ~(v:vs) env (Case r e alts) =->   case caseMatch r id [v] (map (translAlt v) alts) of->     IL.Case r mode (IL.Variable v') alts'->       | v == v' && v `notElem` fv alts' -> IL.Case r mode e' alts'->     e''->       | v `elem` fv e'' -> IL.Let (IL.Binding v e') e''->       | otherwise -> e''->   where e' = translExpr tyEnv vs env e->         translAlt v (Alt _ t rhs) =->           (id,->            [translTerm v t],->            translRhs tyEnv vs (bindRenameEnv v t env) rhs)-> translExpr _ _ _ _ = internalError "translExpr"--> instance Expr IL.Expression where->   fv (IL.Variable v) = [v]->   fv (IL.Apply e1 e2) = fv e1 ++ fv e2->   fv (IL.Case _ _ e alts) = fv e ++ fv alts->   fv (IL.Or e1 e2) = fv e1 ++ fv e2->   fv (IL.Exist v e) = filter (/= v) (fv e)->   fv (IL.Let (IL.Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)->   fv (IL.Letrec bds e) = filter (`notElem` vs) (fv es ++ fv e)->     where (vs,es) = unzip [(v,e) | IL.Binding v e <- bds]->   fv _ = []--> instance Expr IL.Alt where->   fv (IL.Alt (IL.ConstructorPattern _ vs) e) = filter (`notElem` vs) (fv e)->   fv (IL.Alt (IL.VariablePattern v) e) = filter (v /=) (fv e)->   fv (IL.Alt _ e) = fv e--\end{verbatim}-\paragraph{Auxiliary Definitions}-The functions \texttt{varType} and \texttt{constrType} return the type-of variables and constructors, respectively. The quantifiers are-stripped from the types.-\begin{verbatim}--> varType :: ValueEnv -> QualIdent -> Type-> varType tyEnv f =->   case qualLookupValue f tyEnv of->     [Value _ (ForAll _ ty)] -> ty->     _ -> internalError ("varType: " ++ show f)--> constrType :: ValueEnv -> QualIdent -> Type-> constrType tyEnv c =->   case qualLookupValue c tyEnv of->     [DataConstructor _ (ForAllExist _ _ ty)] -> ty->     [NewtypeConstructor _ (ForAllExist _ _ ty)] -> ty->     _ -> internalError ("constrType: " ++ show c)--\end{verbatim}-The list of import declarations in the intermediate language code is-determined by collecting all module qualifiers used in the current-module.-\begin{verbatim}--> imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]-> imports m = Set.toList . Set.delete m . Set.fromList . foldr modulesDecl []--> modulesDecl :: IL.Decl -> [ModuleIdent] -> [ModuleIdent]-> modulesDecl (IL.DataDecl _ _ cs) ms = foldr modulesConstrDecl ms cs->   where modulesConstrDecl (IL.ConstrDecl _ tys) ms = foldr modulesType ms tys-> modulesDecl (IL.NewtypeDecl _ _ (IL.ConstrDecl _ ty)) ms = modulesType ty ms-> modulesDecl (IL.FunctionDecl _ _ ty e) ms = modulesType ty (modulesExpr e ms)-> modulesDecl (IL.ExternalDecl _ _ _ ty) ms = modulesType ty ms--> modulesType :: IL.Type -> [ModuleIdent] -> [ModuleIdent]-> modulesType (IL.TypeConstructor tc tys) ms =->   modules tc (foldr modulesType ms tys)-> modulesType (IL.TypeVariable _) ms = ms-> modulesType (IL.TypeArrow ty1 ty2) ms = modulesType ty1 (modulesType ty2 ms)--> modulesExpr :: IL.Expression -> [ModuleIdent] -> [ModuleIdent]-> modulesExpr (IL.Function f _) ms = modules f ms-> modulesExpr (IL.Constructor c _) ms = modules c ms-> modulesExpr (IL.Apply e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)-> modulesExpr (IL.Case _ _ e as) ms = modulesExpr e (foldr modulesAlt ms as)->   where modulesAlt (IL.Alt t e) ms = modulesConstrTerm t (modulesExpr e ms)->         modulesConstrTerm (IL.ConstructorPattern c _) ms = modules c ms->         modulesConstrTerm _ ms = ms-> modulesExpr (IL.Or e1 e2) ms = modulesExpr e1 (modulesExpr e2 ms)-> modulesExpr (IL.Exist _ e) ms = modulesExpr e ms-> modulesExpr (IL.Let b e) ms = modulesBinding b (modulesExpr e ms)-> modulesExpr (IL.Letrec bs e) ms = foldr modulesBinding (modulesExpr e ms) bs-> modulesExpr _ ms = ms--> modulesBinding :: IL.Binding -> [ModuleIdent] -> [ModuleIdent]-> modulesBinding (IL.Binding _ e) = modulesExpr e--> modules :: QualIdent -> [ModuleIdent] -> [ModuleIdent]-> modules x ms = maybe ms (: ms) (qualidMod x)--\end{verbatim}-
+ src/IL/Pretty.hs view
@@ -0,0 +1,179 @@+{- |+    Module      :  $Header$+    Description :  Pretty printer for IL+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux+                                   Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2017        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module implements just another pretty printer, this time for the+   intermediate language. It was mainly adapted from the Curry pretty+   printer which, in turn, is based on Simon Marlow's pretty printer+   for Haskell.+-}++module IL.Pretty (ppModule) where++import Curry.Base.Ident+import Curry.Base.Pretty+import IL.Type++dataIndent :: Int+dataIndent = 2++bodyIndent :: Int+bodyIndent = 2++exprIndent :: Int+exprIndent = 2++caseIndent :: Int+caseIndent = 2++altIndent :: Int+altIndent = 2++orIndent :: Int+orIndent = 2++ppModule :: Module -> Doc+ppModule (Module m is ds) = sepByBlankLine+  [ppHeader m, vcat (map ppImport is), sepByBlankLine (map ppDecl ds)]++ppHeader :: ModuleIdent -> Doc+ppHeader m = text "module" <+> text (moduleName m) <+> text "where"++ppImport :: ModuleIdent -> Doc+ppImport m = text "import" <+> text (moduleName m)++ppDecl :: Decl -> Doc+ppDecl (DataDecl                   tc n cs) = sep $+  text "data" <+> ppTypeLhs tc n :+  map (nest dataIndent)+      (zipWith (<+>) (equals : repeat (char '|')) (map ppConstr cs))+ppDecl (ExternalDataDecl              tc n) =+  text "external data" <+> ppTypeLhs tc n+ppDecl (FunctionDecl             f vs ty e) = ppTypeSig f ty $$ sep+  [ ppQIdent f <+> hsep (map (ppIdent . snd) vs) <+> equals+  , nest bodyIndent (ppExpr 0 e)]+ppDecl (ExternalDecl f ty) = text "external" <+> ppTypeSig f ty++ppTypeLhs :: QualIdent -> Int -> Doc+ppTypeLhs tc n = ppQIdent tc <+> hsep (map text (take n typeVars))++ppConstr :: ConstrDecl -> Doc+ppConstr (ConstrDecl c tys) = ppQIdent c <+> fsep (map (ppType 2) tys)++ppTypeSig :: QualIdent -> Type -> Doc+ppTypeSig f ty = ppQIdent f <+> text "::" <+> ppType 0 ty++ppType :: Int -> Type -> Doc+ppType p (TypeConstructor tc tys)+  | isQTupleId tc                    = parens+    (fsep (punctuate comma (map (ppType 0) tys)))+  | tc == qListId && length tys == 1 = brackets (ppType 0 (head tys))+  | otherwise                        = parenIf (p > 1 && not (null tys))+    (ppQIdent tc <+> fsep (map (ppType 2) tys))+ppType _ (TypeVariable    n) = ppTypeVar n+ppType p (TypeArrow ty1 ty2) = parenIf (p > 0)+                               (fsep (ppArrow (TypeArrow ty1 ty2)))+  where+  ppArrow (TypeArrow ty1' ty2') = ppType 1 ty1' <+> text "->" : ppArrow ty2'+  ppArrow ty                    = [ppType 0 ty]+ppType p (TypeForall ns ty)+  | null ns   = ppType p ty+  | otherwise = parenIf (p > 0) $ ppQuantifiedTypeVars ns <+> ppType 0 ty++ppTypeVar :: Int -> Doc+ppTypeVar n+  | n >= 0    = text (typeVars !! n)+  | otherwise = text ('_':show (-n))++ppQuantifiedTypeVars :: [Int] -> Doc+ppQuantifiedTypeVars ns+  | null ns = empty+  | otherwise = text "forall" <+> hsep (map ppTypeVar ns) <+> char '.'++ppBinding :: Binding -> Doc+ppBinding (Binding v expr) = sep+  [ppIdent v <+> equals, nest bodyIndent (ppExpr 0 expr)]++ppAlt :: Alt -> Doc+ppAlt (Alt pat expr) = sep+  [ppConstrTerm pat <+> text "->", nest altIndent (ppExpr 0 expr)]++ppLiteral :: Literal -> Doc+ppLiteral (Char  c) = text (show c)+ppLiteral (Int   i) = integer i+ppLiteral (Float f) = double f++ppConstrTerm :: ConstrTerm -> Doc+ppConstrTerm (LiteralPattern     _                    l) = ppLiteral l+ppConstrTerm (ConstructorPattern _ c [(_, v1), (_, v2)])+  | isQInfixOp c = ppIdent v1 <+> ppQInfixOp c <+> ppIdent v2+ppConstrTerm (ConstructorPattern _ c                 vs)+  | isQTupleId c = parens $ fsep (punctuate comma $ map (ppIdent . snd) vs)+  | otherwise    = ppQIdent c <+> fsep (map (ppIdent . snd) vs)+ppConstrTerm (VariablePattern    _                    v) = ppIdent v++ppExpr :: Int -> Expression -> Doc+ppExpr _ (Literal       _ l) = ppLiteral l+ppExpr _ (Variable      _ v) = ppIdent v+ppExpr _ (Function    _ f _) = ppQIdent f+ppExpr _ (Constructor _ c _) = ppQIdent c+ppExpr p (Apply (Apply (Function    _ f _) e1) e2)+  | isQInfixOp f = ppInfixApp p e1 f e2+ppExpr p (Apply (Apply (Constructor _ c _) e1) e2)+  | isQInfixOp c = ppInfixApp p e1 c e2+ppExpr p (Apply       e1 e2) = parenIf (p > 2) $ sep+  [ppExpr 2 e1, nest exprIndent (ppExpr 3 e2)]+ppExpr p (Case    ev e alts) = parenIf (p > 0) $+  text "case" <+> ppEval ev <+> ppExpr 0 e <+> text "of"+  $$ nest caseIndent (vcat $ map ppAlt alts)+  where ppEval Rigid = text "rigid"+        ppEval Flex  = text "flex"+ppExpr p (Or          e1 e2) = parenIf (p > 0) $ sep+  [nest orIndent (ppExpr 0 e1), char '|', nest orIndent (ppExpr 0 e2)]+ppExpr p (Exist         v e) = parenIf (p > 0) $ sep+  [text "let" <+> ppIdent v <+> text "free" <+> text "in", ppExpr 0 e]+ppExpr p (Let           b e) = parenIf (p > 0) $ sep+  [text "let" <+> ppBinding b <+> text "in",ppExpr 0 e]+ppExpr p (Letrec       bs e) = parenIf (p > 0) $ sep+  [text "letrec" <+> vcat (map ppBinding bs) <+> text "in", ppExpr 0 e]+ppExpr p (Typed        e ty) = parenIf (p > 0) $ sep+  [ppExpr 0 e, text "::", ppType 0 ty]++ppInfixApp :: Int -> Expression -> QualIdent -> Expression -> Doc+ppInfixApp p e1 op e2 = parenIf (p > 1) $ sep+  [ppExpr 2 e1 <+> ppQInfixOp op, nest exprIndent (ppExpr 2 e2)]++ppIdent :: Ident -> Doc+ppIdent ident+  | isInfixOp ident = parens (ppName ident)+  | otherwise       = ppName ident++ppQIdent :: QualIdent -> Doc+ppQIdent ident+  | isQInfixOp ident = parens (ppQual ident)+  | otherwise        = ppQual ident++ppQInfixOp :: QualIdent -> Doc+ppQInfixOp op+  | isQInfixOp op = ppQual op+  | otherwise     = char '`' <> ppQual op <> char '`'++ppName :: Ident -> Doc+ppName x = text (idName x)++ppQual :: QualIdent -> Doc+ppQual x = text (qualName x)++typeVars :: [String]+typeVars = [mkTypeVar c i | i <- [0 .. ], c <- ['a' .. 'z']] where+  mkTypeVar :: Char -> Int -> String+  mkTypeVar c i = c : if i == 0 then [] else show i
− src/IL/Pretty.lhs
@@ -1,167 +0,0 @@-% $Id: ILPP.lhs,v 1.22 2003/10/28 05:43:43 wlux Exp $-%-% Copyright (c) 1999-2003 Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{ILPP.lhs}-\section{A pretty printer for the intermediate language}-This module implements just another pretty printer, this time for the-intermediate language. It was mainly adapted from the Curry pretty-printer (see sect.~\ref{sec:CurryPP}) which, in turn, is based on Simon-Marlow's pretty printer for Haskell.-\begin{verbatim}--> module IL.Pretty(ppModule)  where-> -> import Text.PrettyPrint.HughesPJ--> import Curry.Base.Ident-> import IL.Type--> default(Int,Double)--> dataIndent = 2-> bodyIndent = 2-> exprIndent = 2-> caseIndent = 2-> altIndent = 2--> ppModule :: Module -> Doc-> ppModule (Module m is ds) =->   vcat (text "module" <+> text (show m) <+> text "where" :->         map ppImport is ++ map ppDecl ds)--> ppImport :: ModuleIdent -> Doc-> ppImport m = text "import" <+> text (show m)--> ppDecl :: Decl -> Doc-> ppDecl (DataDecl tc n cs) =->   sep (text "data" <+> ppTypeLhs tc n :->        map (nest dataIndent)->            (zipWith (<+>) (equals : repeat (char '|')) (map ppConstr cs)))-> ppDecl (NewtypeDecl tc n (ConstrDecl c ty)) =->   sep [text "newtype" <+> ppTypeLhs tc n <+> equals,->        nest dataIndent (ppConstr (ConstrDecl c [ty]))]-> ppDecl (FunctionDecl f vs ty exp) =->   ppTypeSig f ty $$->   sep [ppQIdent f <+> hsep (map ppIdent vs) <+> equals,->        nest bodyIndent (ppExpr 0 exp)]-> ppDecl (ExternalDecl f cc ie ty) =->   sep [text "external" <+> ppCallConv cc <+> text (show ie),->        nest bodyIndent (ppTypeSig f ty)]->   where ppCallConv Primitive = text "primitive"->         ppCallConv CCall = text "ccall"--> ppTypeLhs :: QualIdent -> Int -> Doc-> ppTypeLhs tc n = ppQIdent tc <+> hsep (map text (take n typeVars))--> ppConstr :: ConstrDecl [Type] -> Doc-> ppConstr (ConstrDecl c tys) = ppQIdent c <+> fsep (map (ppType 2) tys)--> ppTypeSig :: QualIdent -> Type -> Doc-> ppTypeSig f ty = ppQIdent f <+> text "::" <+> ppType 0 ty--> ppType :: Int -> Type -> Doc-> ppType p (TypeConstructor tc tys)->   | isQTupleId tc = parens (fsep (punctuate comma (map (ppType 0) tys)))->   | unqualify tc == nilId = brackets (ppType 0 (head tys))->   | otherwise =->       ppParen (p > 1 && not (null tys))->               (ppQIdent tc <+> fsep (map (ppType 2) tys))-> ppType _ (TypeVariable n)->   | n >= 0 = text (typeVars !! n)->   | otherwise = text ('_':show (-n))-> ppType p (TypeArrow ty1 ty2) =->   ppParen (p > 0) (fsep (ppArrow (TypeArrow ty1 ty2)))->   where ppArrow (TypeArrow ty1 ty2) =->           ppType 1 ty1 <+> text "->" : ppArrow ty2->         ppArrow ty = [ppType 0 ty]--> ppBinding :: Binding -> Doc-> ppBinding (Binding v exp) =->   sep [ppIdent v <+> equals,nest bodyIndent (ppExpr 0 exp)]--> ppAlt :: Alt -> Doc-> ppAlt (Alt pat exp) =->   sep [ppConstrTerm pat <+> text "->",nest altIndent (ppExpr 0 exp)]--> ppLiteral :: Literal -> Doc-> ppLiteral (Char _ c) = text (show c)-> ppLiteral (Int _ i) = integer i-> ppLiteral (Float _ f) = double f--> ppConstrTerm :: ConstrTerm -> Doc-> ppConstrTerm (LiteralPattern l) = ppLiteral l-> ppConstrTerm (ConstructorPattern c [v1,v2])->   | isQInfixOp c = ppIdent v1 <+> ppQInfixOp c <+> ppIdent v2-> ppConstrTerm (ConstructorPattern c vs)->   | isQTupleId c = parens (fsep (punctuate comma (map ppIdent vs)))->   | otherwise = ppQIdent c <+> fsep (map ppIdent vs)-> ppConstrTerm (VariablePattern v) = ppIdent v--> ppExpr :: Int -> Expression -> Doc-> ppExpr p (Literal l) = ppLiteral l-> ppExpr p (Variable v) = ppIdent v-> ppExpr p (Function f _) = ppQIdent f-> ppExpr p (Constructor c _) = ppQIdent c-> ppExpr p (Apply (Apply (Function f _) e1) e2)->   | isQInfixOp f = ppInfixApp p e1 f e2-> ppExpr p (Apply (Apply (Constructor c _) e1) e2)->   | isQInfixOp c = ppInfixApp p e1 c e2-> ppExpr p (Apply e1 e2) =->   ppParen (p > 2) (sep [ppExpr 2 e1,nest exprIndent (ppExpr 3 e2)])-> ppExpr p (Case _ ev e alts) =->   ppParen (p > 0)->           (text "case" <+> ppEval ev <+> ppExpr 0 e <+> text "of" $$->            nest caseIndent (vcat (map ppAlt alts)))->   where ppEval Rigid = text "rigid"->         ppEval Flex = text "flex"-> ppExpr p (Or e1 e2) =->   ppParen (p > 0) (sep [ppExpr 0 e1,char '|' <+> ppExpr 0 e2])-> ppExpr p (Exist v e) =->   ppParen (p > 0)->           (sep [text "let" <+> ppIdent v <+> text "free" <+> text "in",->                 ppExpr 0 e])-> ppExpr p (Let b e) =->   ppParen (p > 0) (sep [text "let" <+> ppBinding b <+> text "in",ppExpr 0 e])-> ppExpr p (Letrec bs e) =->   ppParen (p > 0)->           (sep [text "letrec" <+> vcat (map ppBinding bs) <+> text "in",->                 ppExpr 0 e])--> ppInfixApp :: Int -> Expression -> QualIdent -> Expression -> Doc-> ppInfixApp p e1 op e2 =->   ppParen (p > 1)->           (sep [ppExpr 2 e1 <+> ppQInfixOp op,nest exprIndent (ppExpr 2 e2)])--> ppIdent :: Ident -> Doc-> ppIdent ident->   | isInfixOp ident = parens (ppName ident)->   | otherwise = ppName ident--> ppQIdent :: QualIdent -> Doc-> ppQIdent ident->   | isQInfixOp ident = parens (ppQual ident)->   | otherwise = ppQual ident--> ppQInfixOp :: QualIdent -> Doc-> ppQInfixOp op->   | isQInfixOp op = ppQual op->   | otherwise = char '`' <> ppQual op <> char '`'--> ppName :: Ident -> Doc-> ppName x = text (name x)--> ppQual :: QualIdent -> Doc-> ppQual x = text (qualName x)--> typeVars :: [String]-> typeVars = [mkTypeVar c i | i <- [0..], c <- ['a' .. 'z']]->   where mkTypeVar c i = c : if i == 0 then [] else show i--> ppParen :: Bool -> Doc -> Doc-> ppParen p = if p then parens else id--\end{verbatim}
− src/IL/Scope.hs
@@ -1,124 +0,0 @@-module IL.Scope (getModuleScope,-		insertDeclScope, insertConstrDeclScope,-		insertCallConvScope, insertTypeScope,-		insertLiteralScope, insertConstrTermScope,-		insertExprScope, insertAltScope,-		insertBindingScope) where--import Curry.Base.Ident--import IL.Type-import OldScopeEnv as ScopeEnv---------------------------------------------------------------------------------------getModuleScope :: Module -> ScopeEnv-getModuleScope (Module _ _ decls) = foldl insertDecl newScopeEnv decls------insertDeclScope :: ScopeEnv -> Decl -> ScopeEnv-insertDeclScope env (DataDecl _ _ _) = env-insertDeclScope env (NewtypeDecl _ _ _) = env-insertDeclScope env (FunctionDecl _ params _ _)-   = foldr ScopeEnv.insertIdent (ScopeEnv.beginScope env) params-insertDeclScope env (ExternalDecl _ _ _ _) = env------insertConstrDeclScope :: ScopeEnv -> ConstrDecl [Type] -> ScopeEnv-insertConstrDeclScope env _ = env------insertCallConvScope :: ScopeEnv -> CallConv -> ScopeEnv-insertCallConvScope env _ = env------insertTypeScope :: ScopeEnv -> Type -> ScopeEnv-insertTypeScope env _ = env------insertLiteralScope :: ScopeEnv -> Literal -> ScopeEnv-insertLiteralScope env _ = env------insertConstrTermScope :: ScopeEnv -> ConstrTerm -> ScopeEnv-insertConstrTermScope env _ = env------insertExprScope :: ScopeEnv -> Expression -> ScopeEnv-insertExprScope env (Literal _) = env-insertExprScope env (Variable _) = env-insertExprScope env (Function _ _) = env-insertExprScope env (Constructor _ _) = env-insertExprScope env (Apply _ _) = env-insertExprScope env (Case _ _ _ _) = env-insertExprScope env (Or _ _) = env-insertExprScope env (Exist ident _)-   = ScopeEnv.insertIdent ident (ScopeEnv.beginScope env)-insertExprScope env (Let bind _)-   = insertBinding (beginScope env) bind-insertExprScope env (Letrec binds _)-   = foldl insertBinding (beginScope env) binds------insertAltScope :: ScopeEnv -> Alt -> ScopeEnv-insertAltScope env (Alt cterm _)-   = insertConstrTerm (ScopeEnv.beginScope env) cterm------insertBindingScope :: ScopeEnv -> Binding -> ScopeEnv-insertBindingScope env _ = env-----------------------------------------------------------------------------------------------------------------------------------------------------------------------insertDecl :: ScopeEnv -> Decl -> ScopeEnv-insertDecl env (DataDecl qident _ cdecls)-   = foldl insertConstrDecl-	 (ScopeEnv.insertIdent (unqualify qident) env)-	 cdecls--insertDecl env (NewtypeDecl qident _ cdecl)-   = insertConstrDecl (ScopeEnv.insertIdent (unqualify qident) env) cdecl--insertDecl env (FunctionDecl qident _ _ _)-   = ScopeEnv.insertIdent (unqualify qident) env--insertDecl env (ExternalDecl qident _ _ _)-   = ScopeEnv.insertIdent (unqualify qident) env------insertConstrDecl :: ScopeEnv -> ConstrDecl a -> ScopeEnv-insertConstrDecl env (ConstrDecl qident _)-   = ScopeEnv.insertIdent (unqualify qident) env------insertConstrTerm :: ScopeEnv -> ConstrTerm -> ScopeEnv-insertConstrTerm env (LiteralPattern _) = env-insertConstrTerm env (ConstructorPattern _ params)-   = foldr ScopeEnv.insertIdent env params-insertConstrTerm env (VariablePattern ident)-   = ScopeEnv.insertIdent ident env------insertBinding :: ScopeEnv -> Binding -> ScopeEnv-insertBinding env (Binding ident _) = ScopeEnv.insertIdent ident env------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/IL/ShowModule.hs view
@@ -0,0 +1,248 @@+{- |+    Module      :  $Header$+    Description :  Custom Show implementation for IL+    Copyright   :  (c) 2015        Björn Peemöller+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   This module implements a generic show function comparable to the one+   obtained by @deriving Show@. However, the internal representation of+   identifiers is hidden to avoid syntactic clutter.+-}++module IL.ShowModule (showModule) where++import Curry.Base.Ident+import Curry.Base.Position++import IL.Type++-- |Show a IL module like by an devired 'Show' instance+showModule :: Module -> String+showModule m = showsModule m "\n"++showsModule :: Module -> ShowS+showsModule (Module mident imps decls)+  = showsString "Module "+  . showsModuleIdent mident . newline+  . showsList (\i -> showsModuleIdent i . newline) imps+  . showsList (\d -> showsDecl d . newline) decls++showsDecl :: Decl -> ShowS+showsDecl (DataDecl qident arity constrdecls)+  = showsString "(DataDecl "+  . showsQualIdent qident . space+  . shows arity . space+  . showsList showsConstrDecl constrdecls+  . showsString ")"+showsDecl (ExternalDataDecl qident arity)+  = showsString "(ExternalDataDecl "+  . showsQualIdent qident . space+  . shows arity+  . showsString ")"+showsDecl (FunctionDecl qident idents typ expr)+  = showsString "(FunctionDecl "+  . showsQualIdent qident . space+  . showsList (showsIdent . snd) idents . space+  . showsType typ . space+  . showsExpression expr+  . showsString ")"+showsDecl (ExternalDecl qident typ)+  = showsString "(ExternalDecl "+  . showsQualIdent qident . space+  . showsType typ+  . showsString ")"++showsConstrDecl :: ConstrDecl -> ShowS+showsConstrDecl (ConstrDecl qident tys)+  = showsString "(ConstrDecl "+  . showsQualIdent qident . space+  . showsList showsType tys+  . showsString ")"++showsType :: Type -> ShowS+showsType (TypeConstructor qident types)+  = showsString "(TypeConstructor "+  . showsQualIdent qident . space+  . showsList showsType types+  . showsString ")"+showsType (TypeVariable int)+  = showsString "(TypeVariable "+  . shows int+  . showsString ")"+showsType (TypeArrow type1 type2)+  = showsString "(TypeArrow "+  . showsType type1 . space+  . showsType type2+  . showsString ")"+showsType (TypeForall ints typ)+  = showsString "(TypeForall "+  . showsList shows ints . space+  . showsType typ+  . showsString ")"++showsLiteral :: Literal -> ShowS+showsLiteral (Char c)+  = showsString "(Char "+  . shows c+  . showsString ")"+showsLiteral (Int n)+  = showsString "(Int "+  . shows n+  . showsString ")"+showsLiteral (Float x)+  = showsString "(Float "+  . shows x+  . showsString ")"++showsConstrTerm :: ConstrTerm -> ShowS+showsConstrTerm (LiteralPattern ty lit)+  = showsString "(LiteralPattern "+  . showsType ty+  . showsLiteral lit+  . showsString ")"+showsConstrTerm (ConstructorPattern ty qident idents)+  = showsString "(ConstructorPattern "+  . showsType ty+  . showsQualIdent qident . space+  . showsList (showsIdent . snd) idents+  . showsString ")"+showsConstrTerm (VariablePattern ty ident)+  = showsString "(VariablePattern "+  . showsType ty+  . showsIdent ident+  . showsString ")"++showsExpression :: Expression -> ShowS+showsExpression (Literal ty lit)+  = showsString "(Literal "+  . showsType ty+  . showsLiteral lit+  . showsString ")"+showsExpression (Variable ty ident)+  = showsString "(Variable "+  . showsType ty+  . showsIdent ident+  . showsString ")"+showsExpression (Function ty qident int)+  = showsString "(Function "+  . showsType ty+  . showsQualIdent qident . space+  . shows int+  . showsString ")"+showsExpression (Constructor ty qident int)+  = showsString "(Constructor "+  . showsType ty+  . showsQualIdent qident . space+  . shows int+  . showsString ")"+showsExpression (Apply exp1 exp2)+  = showsString "(Apply "+  . showsExpression exp1 . space+  . showsExpression exp2+  . showsString ")"+showsExpression (Case eval expr alts)+  = showsString "(Case "+  . showsEval eval . space+  . showsExpression expr . space+  . showsList showsAlt alts+  . showsString ")"+showsExpression (Or exp1 exp2)+  = showsString "(Or "+  . showsExpression exp1 . space+  . showsExpression exp2+  . showsString ")"+showsExpression (Exist ident expr)+  = showsString "(Exist "+  . showsIdent ident . space+  . showsExpression expr+  . showsString ")"+showsExpression (Let bind expr)+  = showsString "(Let "+  . showsBinding bind . space+  . showsExpression expr+  . showsString ")"+showsExpression (Letrec binds expr)+  = showsString "(Letrec "+  . showsList showsBinding binds . space+  . showsExpression expr+  . showsString ")"+showsExpression (Typed expr typ)+  = showsString "(Typed "+  . showsExpression expr . space+  . showsType typ+  . showsString ")"++showsEval :: Eval -> ShowS+showsEval Rigid = showsString "Rigid"+showsEval Flex  = showsString "Flex"++showsAlt :: Alt -> ShowS+showsAlt (Alt constr expr)+  = showsString "(Alt "+  . showsConstrTerm constr . space+  . showsExpression expr+  . showsString ")"++showsBinding :: Binding -> ShowS+showsBinding (Binding ident expr)+  = showsString "(Binding "+  . showsIdent ident . space+  . showsExpression expr+  . showsString ")"++showsPosition :: Position -> ShowS+showsPosition Position { line = l, column = c } = showsPair shows shows (l, c)+showsPosition _ = showsString "(0,0)"++showsString :: String -> ShowS+showsString = (++)++space :: ShowS+space = showsString " "++newline :: ShowS+newline = showsString "\n"++showsMaybe :: (a -> ShowS) -> Maybe a -> ShowS+showsMaybe shs = maybe (showsString "Nothing")+                       (\x -> showsString "(Just " . shs x . showsString ")")++showsList :: (a -> ShowS) -> [a] -> ShowS+showsList _   [] = showsString "[]"+showsList shs (x:xs)+  = showsString "["+  . foldl (\sys y -> sys . showsString "," . shs y) (shs x) xs+  . showsString "]"++showsPair :: (a -> ShowS) -> (b -> ShowS) -> (a,b) -> ShowS+showsPair sa sb (a,b)+  = showsString "(" . sa a . showsString "," . sb b . showsString ")"++showsIdent :: Ident -> ShowS+showsIdent (Ident p x n)+  = showsString "(Ident " . showsPosition p . space+  . shows x . space . shows n . showsString ")"++showsQualIdent :: QualIdent -> ShowS+showsQualIdent (QualIdent mident ident)+  = showsString "(QualIdent "+  . showsMaybe showsModuleIdent mident+  . space+  . showsIdent ident+  . showsString ")"++showsModuleIdent :: ModuleIdent -> ShowS+showsModuleIdent (ModuleIdent pos ss)+  = showsString "(ModuleIdent "+  . showsPosition pos . space+  . showsList (showsQuotes showsString) ss+  . showsString ")"++showsQuotes :: (a -> ShowS) -> a -> ShowS+showsQuotes sa a+  = showsString "\"" . sa a . showsString "\""
+ src/IL/Type.hs view
@@ -0,0 +1,140 @@+{- |+    Module      :  $Header$+    Description :  Definition of the intermediate language (IL)+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux+                                   Martin Engelke+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   The module 'IL' defines the intermediate language which will be+   compiled into abstract machine code. The intermediate language removes+   a lot of syntactic sugar from the Curry source language.  Top-level+   declarations are restricted to data type and function definitions. A+   newtype definition serves mainly as a hint to the backend that it must+   provide an auxiliary function for partial applications of the+   constructor (Newtype constructors must not occur in patterns+   and may be used in expressions only as partial applications.).++   Type declarations use a de-Bruijn indexing scheme (starting at 0) for+   type variables. In the type of a function, all type variables are+   numbered in the order of their occurence from left to right, i.e., a+   type '(Int -> b) -> (a,b) -> c -> (a,c)' is translated into the+   type (using integer numbers to denote the type variables)+   '(Int -> 0) -> (1,0) -> 2 -> (1,2)'.++   Pattern matching in an equation is handled via flexible and rigid+   'Case' expressions. Overlapping rules are translated with the+   help of 'Or' expressions. The intermediate language has three+   kinds of binding expressions, 'Exist' expressions introduce a+   new logical variable, 'Let' expression support a single+   non-recursive variable binding, and 'Letrec' expressions+   introduce multiple variables with recursive initializer expressions.+   The intermediate language explicitly distinguishes (local) variables+   and (global) functions in expressions.++   Note: this modified version uses haskell type 'Integer'+   instead of 'Int' for representing integer values. This provides+   an unlimited range of integer constants in Curry programs.+-}++module IL.Type+  ( -- * Data types+    Module (..), Decl (..), ConstrDecl (..), Type (..), Literal (..)+  , ConstrTerm (..), Expression (..), Eval (..), Alt (..), Binding (..)+  ) where++import Curry.Base.Ident++import Base.Expr++data Module = Module ModuleIdent [ModuleIdent] [Decl]+    deriving (Eq, Show)++data Decl+  = DataDecl         QualIdent Int [ConstrDecl]+  | ExternalDataDecl QualIdent Int+  | FunctionDecl     QualIdent [(Type, Ident)] Type Expression+  | ExternalDecl     QualIdent Type+    deriving (Eq, Show)++data ConstrDecl = ConstrDecl QualIdent [Type]+    deriving (Eq, Show)++data Type+  = TypeConstructor QualIdent [Type]+  | TypeVariable    Int+  | TypeArrow       Type Type+  | TypeForall      [Int] Type+    deriving (Eq, Show)++data Literal+  = Char  Char+  | Int   Integer+  | Float Double+    deriving (Eq, Show)++data ConstrTerm+    -- |literal patterns+  = LiteralPattern Type Literal+    -- |constructors+  | ConstructorPattern Type QualIdent [(Type, Ident)]+    -- |default+  | VariablePattern Type Ident+  deriving (Eq, Show)++data Expression+    -- |literal constants+  = Literal Type Literal+    -- |variables+  | Variable Type Ident+    -- |functions+  | Function Type QualIdent Int+    -- |constructors+  | Constructor Type QualIdent Int+    -- |applications+  | Apply Expression Expression+    -- |case expressions+  | Case Eval Expression [Alt]+    -- |non-deterministic or+  | Or Expression Expression+    -- |exist binding (introduction of a free variable)+  | Exist Ident Expression+    -- |let binding+  | Let Binding Expression+    -- |letrec binding+  | Letrec [Binding] Expression+    -- |typed expression+  | Typed Expression Type+  deriving (Eq, Show)++data Eval+  = Rigid+  | Flex+    deriving (Eq, Show)++data Alt = Alt ConstrTerm Expression+    deriving (Eq, Show)++data Binding = Binding Ident Expression+    deriving (Eq, Show)++instance Expr Expression where+  fv (Variable          _ v) = [v]+  fv (Apply           e1 e2) = fv e1 ++ fv e2+  fv (Case         _ e alts) = fv e  ++ fv alts+  fv (Or              e1 e2) = fv e1 ++ fv e2+  fv (Exist             v e) = filter (/= v) (fv e)+  fv (Let (Binding v e1) e2) = fv e1 ++ filter (/= v) (fv e2)+  fv (Letrec          bds e) = filter (`notElem` vs) (fv es ++ fv e)+    where (vs, es) = unzip [(v, e') | Binding v e' <- bds]+  fv (Typed             e _) = fv e+  fv _                       = []++instance Expr Alt where+  fv (Alt (ConstructorPattern _ _ vs) e) = filter (`notElem` map snd vs) (fv e)+  fv (Alt (VariablePattern       _ v) e) = filter (v /=) (fv e)+  fv (Alt _                           e) = fv e
− src/IL/Type.lhs
@@ -1,112 +0,0 @@-> {-# LANGUAGE DeriveDataTypeable #-}--% $Id: IL.lhs,v 1.18 2003/10/28 05:43:38 wlux Exp $-%-% Copyright (c) 1999-2003 Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{IL.lhs}-\section{The intermediate language}-The module \texttt{IL} defines the intermediate language which will be-compiled into abstract machine code. The intermediate language removes-a lot of syntactic sugar from the Curry source language.  Top-level-declarations are restricted to data type and function definitions. A-newtype definition serves mainly as a hint to the backend that it must-provide an auxiliary function for partial applications of the-constructor. \textbf{Newtype constructors must not occur in patterns-and may be used in expressions only as partial applications.}--Type declarations use a de-Bruijn indexing scheme (starting at 0) for-type variables. In the type of a function, all type variables are-numbered in the order of their occurence from left to right, i.e., a-type \texttt{(Int -> b) -> (a,b) -> c -> (a,c)} is translated into the-type (using integer numbers to denote the type variables)-\texttt{(Int -> 0) -> (1,0) -> 2 -> (1,2)}.--Pattern matching in an equation is handled via flexible and rigid-\texttt{Case} expressions. Overlapping rules are translated with the-help of \texttt{Or} expressions. The intermediate language has three-kinds of binding expressions, \texttt{Exist} expressions introduce a-new logical variable, \texttt{Let} expression support a single-non-recursive variable binding, and \texttt{Letrec} expressions-introduce multiple variables with recursive initializer expressions.-The intermediate language explicitly distinguishes (local) variables-and (global) functions in expressions.--\em{Note:} this modified version uses haskell type \texttt{Integer}-instead of \texttt{Int} for representing integer values. This provides-an unlimited range of integer constants in Curry programs.-\begin{verbatim}--> module IL.Type where--> import Data.Generics-> import Curry.Base.Ident-> import Curry.Base.Position (SrcRef(..))--> data Module = Module ModuleIdent [ModuleIdent] [Decl] deriving (Eq,Show)--> data Decl = ->     DataDecl QualIdent Int [ConstrDecl [Type]]->   | NewtypeDecl QualIdent Int (ConstrDecl Type)->   | FunctionDecl QualIdent [Ident] Type Expression->   | ExternalDecl QualIdent CallConv String Type->   deriving (Eq,Show)--> data ConstrDecl a = ConstrDecl QualIdent a deriving (Eq,Show)-> data CallConv = Primitive | CCall deriving (Eq,Show)--> data Type =->     TypeConstructor QualIdent [Type]->   | TypeVariable Int->   | TypeArrow Type Type->   deriving (Eq,Show, Typeable, Data)--> data Literal = Char SrcRef Char | Int SrcRef Integer | Float SrcRef Double deriving (Eq,Show)--> data ConstrTerm =->   -- literal patterns->     LiteralPattern Literal->   -- constructors->   | ConstructorPattern QualIdent [Ident]->   -- default->   | VariablePattern Ident->   deriving (Eq,Show)--> data Expression =->   -- literal constants->     Literal Literal->   -- variables, functions, constructors->   | Variable Ident | Function QualIdent Int | Constructor QualIdent Int->   -- applications->   | Apply Expression Expression->   -- case expressions->   | Case SrcRef Eval Expression [Alt]->   -- non-determinisismic or->   | Or Expression Expression->   -- binding forms->   | Exist Ident Expression->   | Let Binding Expression->   | Letrec [Binding] Expression->   deriving (Eq,Show)--> data Eval = Rigid | Flex deriving (Eq,Show)-> data Alt = Alt ConstrTerm Expression deriving (Eq,Show)-> data Binding = Binding Ident Expression deriving (Eq,Show)--\end{verbatim}--> instance SrcRefOf ConstrTerm where->   srcRefOf (LiteralPattern l) = srcRefOf l->   srcRefOf (ConstructorPattern i _) = srcRefOf i->   srcRefOf (VariablePattern i) = srcRefOf i---> instance SrcRefOf Literal where->   srcRefOf (Char s _)   = s->   srcRefOf (Int s _)    = s->   srcRefOf (Float s _)  = s  --
+ src/IL/Typing.hs view
@@ -0,0 +1,44 @@+{- |+    Module      :  $Header$+    Description :  TODO+    Copyright   :  (c)        2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   TODO+-}++module IL.Typing (Typeable(..)) where++import Base.Messages (internalError)++import IL.Type++class Typeable a where+  typeOf :: a -> Type++instance Typeable ConstrTerm where+  typeOf (LiteralPattern ty _) = ty+  typeOf (ConstructorPattern ty _ _) = ty+  typeOf (VariablePattern ty _) = ty++instance Typeable Expression where+  typeOf (Literal ty _) = ty+  typeOf (Variable ty _) = ty+  typeOf (Function ty _ _) = ty+  typeOf (Constructor ty _ _) = ty+  typeOf (Apply e _) = case typeOf e of+    TypeArrow _ ty -> ty+    _ -> internalError "IL.Typing.typeOf: application"+  typeOf (Case _ _ as) = typeOf $ head as+  typeOf (Or e _) = typeOf e+  typeOf (Exist _ e) = typeOf e+  typeOf (Let _ e) = typeOf e+  typeOf (Letrec _ e) = typeOf e+  typeOf (Typed e _) = typeOf e++instance Typeable Alt where+  typeOf (Alt _ e) = typeOf e
− src/IL/XML.lhs
@@ -1,518 +0,0 @@--% $Id: ILxml.lhs,v 1.0 2001/06/19 12:19:18 rafa Exp $-%-% $Log: ILxml.lhs,v $-%-% Revision 1.1  2001/06/19 12:19:18  rafa-% Pretty printer in XML for the intermediate language added.-%-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{ILxml.lhs}-\section{A pretty printer in XML for the intermediate language}-This module implements just another pretty printer, this time in XML and for-the intermediate language. It was mainly adapted from the Curry pretty-printer (see sect.~\ref{sec:CurryPP}), which in turn is based on Simon-Marlow's pretty printer for Haskell. The format of the output intends to be-similar to that of Flat-Curry XML representation.-\begin{verbatim}--> module IL.XML(module IL.XML) where--> import Text.PrettyPrint.HughesPJ-> import Data.Maybe--> import Curry.Base.Ident-> import qualified Curry.Syntax as CS--> import IL.Type-> import CurryEnv----> -- identation level-> level::Int-> level = 3--> xmlModule :: CurryEnv -> Module -> Doc-> xmlModule cEnv m = text "<prog>" $$ nest level (xmlBody cEnv m) ->	                           $$ text "</prog>"--> xmlBody :: CurryEnv -> Module -> Doc-> xmlBody cEnv (Module name imports decls) =->                   xmlElement "module"      xmlModuleDecl      moduleDecl   $$->                   xmlElement "import"      xmlImportDecl      importDecl   $$->                   xmlElement "types"       xmlTypeDecl        typeDecl     $$->                   xmlElement "functions"   xmlFunctionDecl    functionDecl $$->                   xmlElement "operators"   xmlOperatorDecl    operatorDecl $$->                   xmlElement "translation" xmlTranslationDecl translationDecl->               where->                 moduleDecl      = [name]->                 importDecl      = imports->                 operatorDecl    = infixDecls cEnv->                 translationDecl = foldl (qualIDeclId (moduleId cEnv))->			                  [] ->				          (interface cEnv)->                 (functionDecl,typeDecl) = splitDecls decls--> -- =========================================================================--> xmlModuleDecl :: ModuleIdent -> Doc-> xmlModuleDecl name = xmlModuleIdent name--> -- =========================================================================--> xmlImportDecl :: ModuleIdent -> Doc-> xmlImportDecl name = xmlElement "module" xmlModuleDecl  [name]---> -- =========================================================================-> --            T Y P E S-> -- =========================================================================--> xmlTypeDecl :: Decl -> Doc-> xmlTypeDecl (DataDecl tc arity cs) =->   beginType                                  $$->   nest level (xmlTypeParams arity)           $$->   xmlLines xmlConstructor cs                 $$->   endType->  where->   beginType = text "<type name=\"" <> (xmlQualIdent tc) <> text "\">"->   endType   = text "</type>"--> xmlTypeParams :: Int -> Doc-> xmlTypeParams n = xmlElement "params" xmlTypeVar [0..(n-1)]--> xmlConstructor :: ConstrDecl [Type] -> Doc-> xmlConstructor (ConstrDecl ident []) = xmlConstructorBegin ident 0-> xmlConstructor (ConstrDecl ident l)  =->   xmlConstructorBegin ident (length l) $$->   xmlLines xmlType l $$->   xmlConstructorEnd->  where->   xmlConstructorEnd = text "</cons>"--> xmlConstructorBegin :: QualIdent -> Int -> Doc-> xmlConstructorBegin ident n = xmlHeadingWithArity "cons" ident n (n==0)--> xmlHeadingWithArity :: String -> QualIdent -> Int -> Bool -> Doc-> xmlHeadingWithArity tagName ident n single =->   if single->   then prefix<>text "/>"->   else prefix<> text ">"->   where->     prefix = text ("<"++tagName++" name=\"") <> name <> text "\" " <> arity->     arity  = text "arity=\"" <> xmlInt n <> text "\""->     name   = xmlQualIdent ident---> xmlType :: Type -> Doc-> xmlType (TypeConstructor ident []) = xmlTypeConsBegin ident True-> xmlType (TypeConstructor ident l)  = xmlTypeConsBegin ident False $$->                                      xmlLines xmlType l           $$->                                      xmlTypeConsEnd->                                      where->                                        xmlTypeConsEnd = text "</tcons>"--> xmlType (TypeVariable n) = xmlTypeVar n-> xmlType (TypeArrow  a b) = xmlTypeFun a b--> xmlTypeConsBegin :: QualIdent -> Bool -> Doc-> xmlTypeConsBegin ident single =->   if single->   then prefix <> text "/>"->   else prefix <> text ">"->   where->     name   = xmlQualIdent ident->     prefix = text "<tcons name=\"" <> name <> text "\""--> xmlTypeVar :: Int -> Doc-> xmlTypeVar n = text "<tvar>"<> xmlInt n <> text "</tvar>"--> xmlTypeFun :: Type -> Type -> Doc-> xmlTypeFun a b =  xmlElement "functype" xmlType  [a,b]---> -- =========================================================================-> --            F U N C T I O N S-> -- =========================================================================--> xmlFunctionDecl :: Decl -> Doc-> xmlFunctionDecl (NewtypeDecl tc arity (ConstrDecl ident ty)) =->   xmlFunctionDecl (FunctionDecl ident [arg] ftype (Variable arg))->   where->    arg = mkIdent "_1"->    ftype = TypeArrow ty (TypeConstructor tc (map TypeVariable [0..arity-1]))--> xmlFunctionDecl (FunctionDecl ident largs fType expr) =->    heading $$ nest level (xmlRule largs expr) $$ end->  where->    heading = xmlBeginFunction ident (length largs) fType->    end     = text "</func>"--> xmlFunctionDecl (ExternalDecl ident callConv internalName fType) =->    heading $$ external $$ end->  where->    heading  = xmlBeginFunction ident (xmlFunctionArity fType) fType->    external = text ("<external>"->                     ++ xmlFormat internalName->                     ++ "</external>")->    end      = text "</func>"--> xmlBeginFunction :: QualIdent -> Int -> Type -> Doc-> xmlBeginFunction ident n fType =->    heading $$ typeDecls->    where->      heading   = xmlHeadingWithArity "func" ident n False->      typeDecls = nest level (xmlType fType)--> xmlEndFunction ::  Doc-> xmlEndFunction  = text "</func>"--> xmlFunctionArity :: Type -> Int-> xmlFunctionArity (TypeConstructor ident l) = 0-> xmlFunctionArity (TypeVariable n)          = 0-> xmlFunctionArity (TypeArrow  a b)          = 1 + (xmlFunctionArity b)--> xmlRule :: [Ident] -> Expression -> Doc-> xmlRule lArgs e = text "<rule>"               $$->                   nest level (xmlLhs lArgs)   $$->                   nest level (xmlRhs lArgs e) $$->                   text "</rule>"--> xmlLhs :: [Ident] -> Doc-> xmlLhs l  = xmlElement "lhs" xmlVar [0..((length l)-1)]--> xmlRhs :: [Ident] -> Expression -> Doc-> xmlRhs l e = text "<rhs>"  $$ nest level rhs $$ text "</rhs>"->              where->                varDicc    = xmlBuildDicc l->                (rhs, _) = xmlExpr varDicc e--> -- =========================================================================--> -- =========================================================================-> --            E X P R E S S I O N S-> -- =========================================================================--> xmlExpr :: [(Int,Ident)] -> Expression -> (Doc,[(Int,Ident)])-> xmlExpr d (Literal lit)  = (xmlLiteral (xmlLit lit),d)-> xmlExpr d (Variable ident)  = xmlExprVar d ident-> xmlExpr d (Function ident arity)    = (xmlSingleApp ident arity True,d)-> xmlExpr d (Constructor ident arity) = (xmlSingleApp ident arity False,d)-> xmlExpr d exp@(Apply e1 e2)         = xmlApply  d exp (xmlAppArgs exp)-> xmlExpr d (Case _ eval expr alt)      = xmlCase   d eval expr alt-> xmlExpr d (Or expr1 expr2)          = xmlOr     d expr1 expr2-> xmlExpr d (Exist ident expr)        = xmlFree   d ident expr-> xmlExpr d (Let binding expr)        = xmlLet    d binding expr-> xmlExpr d (Letrec lBinding expr)    = xmlLetrec d lBinding expr->   --error "Recursive let bindings not supported in FlatCurry"--> -- =========================================================================--> xmlSingleApp :: QualIdent -> Int -> Bool -> Doc-> xmlSingleApp ident arity isFunction =->    if arity>0->    then xmlCombHeading identDoc (text "PartCall") True->    else xmlCombHeading identDoc (text totalApp) True->    where->       identDoc = xmlQualIdent ident->       totalApp = if isFunction then "FuncCall" else "ConsCall"---> xmlCombHeading :: Doc -> Doc -> Bool -> Doc-> xmlCombHeading name cType single =->     if single->     then prefix <> text " />"->     else prefix <> text ">"->     where->       prefix = text "<comb type=\""<>cType<>text "\" name=\""<>name<>text "\""--> -- =========================================================================--> xmlExprVar :: [(Int,Ident)] -> Ident -> (Doc,[(Int,Ident)])-> xmlExprVar d ident =->    if isNew->    then (xmlVar newVar, (newVar,ident):d)->    else (xmlVar var, d)->    where->       var    = xmlLookUp ident d->       isNew  = var == -1->       newVar = xmlNewVar d--> -- =========================================================================---> xmlApply :: [(Int,Ident)] -> Expression -> (Expression,[Expression]) ->->              (Doc,[(Int,Ident)])--> xmlApply d exp ((Function ident arity),lExp) =->   xmlApplyFunctor d ident arity lExp True--> xmlApply d exp ((Constructor ident arity),lExp) =->   xmlApplyFunctor d ident arity lExp False--> xmlApply d (Apply expr1 expr2) e' =->   (text "<apply>" $$ nest level e1 $$ nest level e2 $$ text "</apply>", d2)->     where->        (e1,d1) = xmlExpr d  expr1->        (e2,d2) = xmlExpr d1 expr2--> xmlApplyFunctor ::[(Int,Ident)] -> QualIdent -> Int -> [Expression] ->->                     Bool -> (Doc,[(Int,Ident)])-> xmlApplyFunctor d ident arity lArgs isFunction =->    xmlCombApply d (xmlQualIdent ident)  (text cTypeS) n lArgs->    where->       n     = length (lArgs)->       cTypeS = if n==arity->               then if isFunction->                    then "FuncCall"->                    else "ConsCall"->               else "PartCall"---> xmlCombApply :: [(Int,Ident)] -> Doc -> Doc -> Int ->->                                 [Expression] -> (Doc,[(Int,Ident)])-> xmlCombApply d name cType 0 lArgs =->    (xmlCombHeading name cType True,d)-> xmlCombApply d name cType n lArgs =->    (xmlCombHeading name cType False $$ xmlLines id lDocs$$ text "</comb>", d1)->    where->      (lDocs,d1) = xmlMapDicc d xmlExpr lArgs---> xmlAppArgs :: Expression -> (Expression,[Expression])-> xmlAppArgs (Apply e1 e2) = (e,lArgs++[e2])->                            where->                                (e,lArgs) = (xmlAppArgs e1)-> xmlAppArgs e             = (e,[])-> -- =========================================================================---> -- =========================================================================--> xmlCase :: [(Int,Ident)] -> Eval -> Expression -> [Alt] -> (Doc,[(Int,Ident)])-> xmlCase d eval expr lAlt =->   (heading $$ nest level e1 $$ xmlLines id lDocs$$ end,d2)->   where->     sEval      = if eval==Rigid then "\"Rigid\"" else "\"Flex\""->     heading    = text "<case type=" <> text sEval <> text ">"->     end        = text "</case>"->     (e1,_)    = xmlExpr d expr->     (lDocs,d2) = xmlMapDicc d xmlBranch  lAlt--> xmlOr :: [(Int,Ident)] -> Expression -> Expression -> (Doc,[(Int,Ident)])-> xmlOr d  expr1 expr2 =->    (text "<or>" $$ nest level e1 $$ nest level e2 $$  text "</or>",d2)->    where->      (e1,d1) = xmlExpr d expr1->      (e2,d2) = xmlExpr d1 expr2---> xmlBranch :: [(Int,Ident)] -> Alt -> (Doc,[(Int,Ident)])-> xmlBranch d (Alt pattern expr) =->    (text "<branch>" $$ nest level e1 $$ nest level e2 $$ text "</branch>",d2)->    where->      (e1,d1) = xmlPattern d pattern->      (e2,d2) = xmlExpr d1 expr---> xmlPattern :: [(Int,Ident)] -> ConstrTerm -> (Doc,[(Int,Ident)])-> xmlPattern d (LiteralPattern lit) = (xmlLitPattern (xmlLit lit),d)-> xmlPattern d (ConstructorPattern ident lArgs) = xmlConsPattern d ident  lArgs-> xmlPattern d (VariablePattern _) = error "Variable patterns not allowed in Flat Curry"--> xmlConsPattern :: [(Int,Ident)] -> QualIdent -> [Ident] -> (Doc,[(Int,Ident)])-> xmlConsPattern d ident lArgs =->    (heading $$ xmlLines id lDocs $$ end,d2)->    where->      heading    = text "<pattern name=\""<> (xmlQualIdent ident) <>->                   text "\"" <> endh->      endh       = if (length lArgs)>0 then text ">" else text "/>"->      end        = if (length lArgs)>0 then text "</pattern>" else empty->      (lDocs,d2) = xmlMapDicc d xmlExprVar lArgs--> -- =========================================================================---> xmlFree :: [(Int,Ident)] -> Ident -> Expression -> (Doc,[(Int,Ident)])-> xmlFree d ident exp =->  (text "<freevars>" $$ nest level v $$ nest level e $$ text "</freevars>",d2)->                    where->                       (v,d1) = xmlExprVar d  ident->                       (e,d2) = xmlExpr d1 exp---> -- =========================================================================--> xmlLet :: [(Int,Ident)] -> Binding -> Expression -> (Doc,[(Int,Ident)])-> xmlLet d binding exp =->   (text "<let>" $$ nest level b $$ nest level e $$ text "</let>", d2)->   where->    (b,d1) = xmlBinding d binding->    (e,d2) = xmlExpr d1 exp--> xmlBinding :: [(Int,Ident)] -> Binding -> (Doc,[(Int,Ident)])-> xmlBinding d  (Binding ident exp) =->    (text "<binding>" $$ nest level v $$ nest level e $$ text "</binding>",d2)->    where->       (v,_)  = xmlExprVar d ident->       (e,d2) = xmlExpr d exp--> -- =========================================================================--> xmlLetrec :: [(Int,Ident)] -> [Binding] -> Expression -> (Doc,[(Int,Ident)])-> xmlLetrec d lB exp =->   (text "<letrec>" $$ xmlLines id b $$ nest level e $$ text "</letrec>",d2)->   where->     (b,d1) = xmlMapDicc d xmlBinding lB->     (e,d2) = xmlExpr d1 exp--> -- =========================================================================---> -- =========================================================================-> --            A U X I L I A R Y  F U N C T I O N S-> -- =========================================================================--> splitDecls :: [Decl] -> ([Decl],[Decl])-> splitDecls []     = ([],[])-> splitDecls (x:xs) = case x of->                      DataDecl     _ _ _   -> (functionDecl,x:typeDecl)->                      NewtypeDecl  _ _ _   -> (x:functionDecl,typeDecl)->                      FunctionDecl _ _ _ _ -> (x:functionDecl,typeDecl)->                      ExternalDecl _ _ _ _   -> (x:functionDecl,typeDecl)->                   where->                       (functionDecl,typeDecl) = splitDecls xs-----> xmlElement :: Eq a => String -> (a -> Doc) -> [a] -> Doc-> xmlElement name f []     = text ("<"++name++" />")-> xmlElement name f lDecls = beginElement $$ xmlLines f lDecls $$ endElement->                            where->                                beginElement = text ("<"++name++">")->                                endElement   = text ("</"++name++">")->--> xmlLines :: (a -> Doc) -> [a] -> Doc-> xmlLines f = (nest level).vcat.(map f)---> xmlMapDicc::[(Int,Ident)] -> ([(Int,Ident)] -> a -> (Doc,[(Int,Ident)])) ->->              [a] -> ([Doc],[(Int,Ident)])-> xmlMapDicc d f lArgs = foldl newArg ([],d) lArgs->                             where->                               newArg (l,d)  e = (l++[v'],d')->                                                 where (v',d') = f d e->---> -- The dictionary identifies var names with integers-> -- it will be ordered starting at the greatest integer-> xmlBuildDicc :: [Ident] -> [(Int,Ident)]-> xmlBuildDicc l = reverse (zip [0..((length l)-1)] l)--> -- looks for a ident in the dictorionary. If it appears returns its-> -- associated value. Otherwise, -1 is returned-> xmlLookUp :: Ident -> [(Int,Ident)] -> Int-> xmlLookUp ident []          = -1-> xmlLookUp ident ((n,name):xs) = if ident==name->                                 then n->                                 else xmlLookUp ident xs--> -- generates a integer corresponding to a new var-> xmlNewVar :: [(Int,Ident)] -> Int-> xmlNewVar []             = 0-> xmlNewVar ((n,ident):xs) = n+1--> xmlVar :: Int -> Doc-> xmlVar n = text "<var>" <> xmlInt n <> text "</var>"--> xmlLiteral :: Doc -> Doc-> xmlLiteral d =   text "<lit>" $$ nest level d $$ text "</lit>"--> xmlLitPattern :: Doc -> Doc-> xmlLitPattern d =   text "<lpattern>" $$ nest level d $$ text "</lpattern>"---> xmlLit :: Literal -> Doc-> xmlLit (Char _ c) = text "<charc>" <>  xmlInt (fromEnum c) <> text "</charc>"-> xmlLit (Int _ n) = text "<intc>" <>  xmlInteger n <> text "</intc>"-> xmlLit (Float _ n) = text "<floatc>" <>  xmlFloat n <> text "</floatc>"--> xmlOperatorDecl :: CS.IDecl -> Doc-> xmlOperatorDecl (CS.IInfixDecl _ fixity prec qident) =->     text "<op fixity=\"" <> xmlFixity fixity ->     <> text "\" prec=\"" <> xmlInteger prec <> text "\">"->     <> xmlIdent (unqualify qident)->     <> text "</op>"--> xmlFixity :: CS.Infix -> Doc-> xmlFixity CS.InfixL = text "InfixlOp"-> xmlFixity CS.InfixR = text "InfixrOp"-> xmlFixity CS.Infix  = text "InfixOp"---> xmlTranslationDecl :: QualIdent -> Doc-> xmlTranslationDecl expId =->       text "<trans>" ->    $$ nest level (   text "<name>"    <> xmlIdent (unqualify expId) <> text "</name>"->                   $$ text "<intname>" <> xmlQualIdent expId         <> text "</intname>")->    $$ text "</trans>"---> xmlIdent :: Ident -> Doc-> xmlIdent ident = text (xmlFormat (name ident))--> xmlInt :: Int -> Doc-> xmlInt n = text (show n)--> xmlInteger :: Integer -> Doc-> xmlInteger n = text (show n)--> xmlFloat :: Double -> Doc-> xmlFloat n = text (show n)--> xmlQualIdent :: QualIdent -> Doc-> xmlQualIdent ident = text (xmlFormat (qualName ident))--> xmlModuleIdent:: ModuleIdent -> Doc-> xmlModuleIdent name = text (xmlFormat (moduleName name))--> xmlFormat :: String -> String-> xmlFormat []       = []-> xmlFormat ('>':xs) = "&gt;"++xmlFormat xs-> xmlFormat ('<':xs) = "&lt;"++xmlFormat xs-> xmlFormat ('&':xs) = "&amp;"++xmlFormat xs-> xmlFormat (x:xs)   = x:(xmlFormat xs)--> -- =========================================================================--> qualIDeclId :: ModuleIdent -> [QualIdent] -> CS.IDecl -> [QualIdent]-> qualIDeclId mid qids (CS.IDataDecl _ qid _ mcdecls)->    = foldl (qualConstrDeclId mid) (qid:qids) (catMaybes mcdecls)-> qualIDeclId mid qids (CS.INewtypeDecl _ qid _ ncdecl)->    = qualNewConstrDeclId mid (qid:qids) ncdecl-> qualIDeclId mid qids (CS.ITypeDecl _ qid _ _)->    = qid:qids-> qualIDeclId mid qids (CS.IFunctionDecl _ qid _ _)->    = qid:qids-> qualIDeclId mid qids _ = qids--> qualConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.ConstrDecl ->	              -> [QualIdent]-> qualConstrDeclId mid qids (CS.ConstrDecl _ _ id _)->    = (qualifyWith mid id):qids-> qualConstrDeclId mid qids (CS.ConOpDecl _ _ _ id _)->    = (qualifyWith mid id):qids--> qualNewConstrDeclId :: ModuleIdent -> [QualIdent] -> CS.NewConstrDecl ->	                 -> [QualIdent]-> qualNewConstrDeclId mid qids (CS.NewConstrDecl _ _ id _)->    = (qualifyWith mid id):qids---\end{verbatim}
+ src/Imports.hs view
@@ -0,0 +1,397 @@+{- |+    Module      :  $Header$+    Description :  Importing interface declarations+    Copyright   :  (c) 2000 - 2003 Wolfgang Lux+                       2011        Björn Peemöller+                       2016        Jan Tikovsky+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module provides the function 'importModules' to bring the imported+    entities into the module's scope, and the function 'qualifyEnv' to+    qualify the environment prior to computing the export interface.+-}+module Imports (importInterfaces, importModules, qualifyEnv) where++import           Data.List                  (nubBy)+import qualified Data.Map            as Map+import           Data.Maybe                 (catMaybes, fromMaybe, isJust)+import qualified Data.Set            as Set++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Syntax++import Base.CurryKinds (toKind')+import Base.CurryTypes ( toQualType, toQualTypes, toQualPredSet, toQualPredType+                       , toConstrType, toMethodType )++import Base.Kinds+import Base.Messages+import Base.TopEnv+import Base.Types+import Base.TypeSubst++import Env.Class+import Env.Instance+import Env.Interface+import Env.ModuleAlias (importAliases, initAliasEnv)+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++import CompilerEnv++importModules :: Monad m => Module a -> InterfaceEnv -> [ImportDecl]+              -> CYT m CompilerEnv+importModules mdl@(Module _ mid _ _ _) iEnv expImps+  = ok $ foldl importModule initEnv expImps+  where+    initEnv = (initCompilerEnv mid)+      { aliasEnv     = importAliases expImps -- import module aliases+      , interfaceEnv = iEnv                  -- imported interfaces+      , extensions   = knownExtensions mdl+      }+    importModule env (ImportDecl _ m q asM is) =+      case Map.lookup m iEnv of+        Just intf -> importInterface (fromMaybe m asM) q is intf env+        Nothing   -> internalError $ "Imports.importModules: no interface for "+                                     ++ show m++-- |The function 'importInterfaces' brings the declarations of all+-- imported interfaces into scope for the current 'Interface'.+importInterfaces :: Interface -> InterfaceEnv -> CompilerEnv+importInterfaces (Interface m is _) iEnv+  = importUnifyData $ foldl importModule initEnv is+  where+    initEnv = (initCompilerEnv m) { aliasEnv = initAliasEnv, interfaceEnv = iEnv }+    importModule env (IImportDecl _ i) = case Map.lookup i iEnv of+      Just intf -> importInterfaceIntf intf env+      Nothing   -> internalError $ "Imports.importInterfaces: no interface for "+                                   ++ show m++-- ---------------------------------------------------------------------------+-- Importing an interface into the module+-- ---------------------------------------------------------------------------++-- Four kinds of environments are computed from the interface:+--+-- 1. The operator precedences+-- 2. The type constructors+-- 3. The types of the data constructors and functions (values)+-- 4. The instances+--+-- Note that the original names of all entities defined in the imported module+-- are qualified appropriately. The same is true for type expressions.++-- When an interface is imported, the compiler first transforms the+-- interface into these environments. If an import specification is+-- present, the environments are restricted to only those entities which+-- are included in the specification or not hidden by it, respectively.+-- The resulting environments are then imported into the current module+-- using either a qualified import (if the module is imported qualified)+-- or both a qualified and an unqualified import (non-qualified import).+-- Regardless of the type of import, all instance declarations are always+-- imported into the current module.++importInterface :: ModuleIdent -> Bool -> Maybe ImportSpec -> Interface+                -> CompilerEnv -> CompilerEnv+importInterface m q is (Interface mid _ ds) env = env'+  where+  env' = env+    { opPrecEnv = importEntities (precs  mid) m q vs id              ds $ opPrecEnv env+    , tyConsEnv = importEntities (types  mid) m q ts (importData vs) ds $ tyConsEnv env+    , valueEnv  = importEntities (values mid) m q vs id              ds $ valueEnv  env+    , classEnv  = importClasses   mid                                ds $ classEnv  env+    , instEnv   = importInstances mid                                ds $ instEnv   env+    }+  ts = isVisible addType  is+  vs = isVisible addValue is++addType :: Import -> [Ident] -> [Ident]+addType (Import            _) tcs = tcs+addType (ImportTypeWith tc _) tcs = tc : tcs+addType (ImportTypeAll     _) _   = internalError "Imports.addType"++addValue :: Import -> [Ident] -> [Ident]+addValue (Import            f) fs = f : fs+addValue (ImportTypeWith _ cs) fs = cs ++ fs+addValue (ImportTypeAll     _) _  = internalError "Imports.addValue"++isVisible :: (Import -> [Ident] -> [Ident]) -> Maybe ImportSpec+          -> Ident -> Bool+isVisible _   Nothing                 = const True+isVisible add (Just (Importing _ xs)) = (`Set.member`    Set.fromList (foldr add [] xs))+isVisible add (Just (Hiding    _ xs)) = (`Set.notMember` Set.fromList (foldr add [] xs))++importEntities :: Entity a => (IDecl -> [a]) -> ModuleIdent -> Bool+               -> (Ident -> Bool) -> (a -> a) -> [IDecl] -> TopEnv a -> TopEnv a+importEntities ents m q isVisible' f ds env =+  foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env+        [ (x, f y) | y <- concatMap ents ds+        , let x = unqualify (origName y), isVisible' x+        ]+  where importUnqual m' x y = importTopEnv m' x y . qualImportTopEnv m' x y++importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo+importData isVisible' (DataType tc k cs) =+  DataType tc k $ catMaybes $ map (importConstr isVisible') cs+importData isVisible' (RenamingType tc k nc) =+  maybe (DataType tc k []) (RenamingType tc k) (importConstr isVisible' nc)+importData _ (AliasType tc k n ty) = AliasType tc k n ty+importData isVisible' (TypeClass qcls k ms) =+  TypeClass qcls k $ catMaybes $ map (importMethod isVisible') ms+importData _ (TypeVar _) = internalError "Imports.importData: type variable"++importConstr :: (Ident -> Bool) -> DataConstr -> Maybe DataConstr+importConstr isVisible' dc+  | isVisible' (constrIdent dc) = Just dc+  | otherwise                   = Nothing++importMethod :: (Ident -> Bool) -> ClassMethod -> Maybe ClassMethod+importMethod isVisible' mthd+  | isVisible' (methodName mthd) = Just mthd+  | otherwise                    = Nothing++importClasses :: ModuleIdent -> [IDecl] -> ClassEnv -> ClassEnv+importClasses m = flip $ foldr (bindClass m)++bindClass :: ModuleIdent -> IDecl -> ClassEnv -> ClassEnv+bindClass m (HidingClassDecl p cx cls k tv) =+  bindClass m (IClassDecl p cx cls k tv [] [])+bindClass m (IClassDecl _ cx cls _ _ ds _) =+  bindClassInfo (qualQualify m cls) (sclss, ms)+  where sclss = map (\(Constraint scls _) -> qualQualify m scls) cx+        ms = map (\d -> (imethod d, isJust $ imethodArity d)) ds+bindClass _ _ = id++importInstances :: ModuleIdent -> [IDecl] -> InstEnv -> InstEnv+importInstances m = flip $ foldr (bindInstance m)++bindInstance :: ModuleIdent -> IDecl -> InstEnv -> InstEnv+bindInstance m (IInstanceDecl _ cx qcls ty is mm) = bindInstInfo+  (qualQualify m qcls, qualifyTC m $ typeConstr ty) (fromMaybe m mm, ps, is)+  where PredType ps _ = toQualPredType m [] $ QualTypeExpr cx ty+bindInstance _ _ = id++-- ---------------------------------------------------------------------------+-- Building the initial environment+-- ---------------------------------------------------------------------------++-- In a first step, the four export environments are initialized from+-- the interface's declarations.++-- operator precedences+precs :: ModuleIdent -> IDecl -> [PrecInfo]+precs m (IInfixDecl _ fix prec op) = [PrecInfo (qualQualify m op) (OpPrec fix prec)]+precs _ _                          = []++hiddenTypes :: ModuleIdent -> IDecl -> [TypeInfo]+hiddenTypes m (HidingDataDecl     _ tc k tvs) = [typeCon DataType m tc k tvs []]+hiddenTypes m (HidingClassDecl  _ _ qcls k _) = [typeCls m qcls k []]+hiddenTypes m d                               = types m d++-- type constructors and type classes+types :: ModuleIdent -> IDecl -> [TypeInfo]+types m (IDataDecl _ tc k tvs cs _) =+  [typeCon DataType m tc k tvs (map mkData cs)]+  where+    mkData (ConstrDecl _ evs cx c tys) =+      DataConstr c (length evs) (toQualPredSet m tvs' cx)+        (toQualTypes m tvs' tys)+      where tvs' = tvs ++ evs+    mkData (ConOpDecl _ evs cx ty1 c ty2) =+      DataConstr c (length evs) (toQualPredSet m tvs' cx)+        (toQualTypes m tvs' [ty1, ty2])+      where tvs' = tvs ++ evs+    mkData (RecordDecl _ evs cx c fs) =+      RecordConstr c (length evs) (toQualPredSet m tvs' cx) labels+        (toQualTypes m tvs' tys)+      where tvs' = tvs ++ evs+            (labels, tys) = unzip [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]+types m (INewtypeDecl _ tc k tvs nc _) =+  [typeCon RenamingType m tc k tvs (mkData nc)]+  where+    mkData (NewConstrDecl _ c ty) =+      DataConstr c 0 emptyPredSet [toQualType m tvs ty]+    mkData (NewRecordDecl _ c (l, ty)) =+      RecordConstr c 0 emptyPredSet [l] [toQualType m tvs ty]+types m (ITypeDecl _ tc k tvs ty) =+  [typeCon aliasType m tc k tvs (toQualType m tvs ty)]+  where+    aliasType tc' k' = AliasType tc' k' (length tvs)+types m (IClassDecl _ _ qcls k tv ds _) =+  [typeCls m qcls k (map mkMethod ds)]+  where+    mkMethod (IMethodDecl _ f a qty) = ClassMethod f a $+      qualifyPredType m $ normalize 1 $ toMethodType qcls tv qty+types _ _ = []++-- type constructors+typeCon :: (QualIdent -> Kind -> a) -> ModuleIdent -> QualIdent+        -> Maybe KindExpr -> [Ident] -> a+typeCon f m tc k tvs = f (qualQualify m tc) (toKind' k (length tvs))++-- type classes+typeCls :: ModuleIdent -> QualIdent -> Maybe KindExpr -> [ClassMethod]+        -> TypeInfo+typeCls m qcls k ms = TypeClass (qualQualify m qcls) (toKind' k 0) ms++-- data constructors, record labels, functions and class methods+values :: ModuleIdent -> IDecl -> [ValueInfo]+values m (IDataDecl _ tc _ tvs cs hs) =+  map (dataConstr m tc' tvs)+      (filter ((\con -> con `notElem` hs || isHiddenButNeeded con)+              . constrId) cs) +++  map (recLabel m tc' tvs ty') (nubBy sameLabel clabels)+  where tc' = qualQualify m tc+        ty' = constrType tc' tvs+        labels   = [ (l, lty) | RecordDecl _ _ _ _ fs <- cs+                   , FieldDecl _ ls lty <- fs, l <- ls, l `notElem` hs+                   ]+        clabels  = [(l, constr l, ty) | (l, ty) <- labels]+        constr l = [constrId c | c <- cs, l `elem` recordLabels c]+        -- hidden constructors needed for record updates with visible labels+        hiddenCs = [c | (l, _) <- labels, c <- constr l, c `elem` hs]+        isHiddenButNeeded = flip elem hiddenCs+        sameLabel (l1,_,_) (l2,_,_) = l1 == l2+values m (INewtypeDecl _ tc _ tvs nc hs) =+  map (newConstr m tc' tvs) [nc | nconstrId nc `notElem` hs] +++  case nc of+    NewConstrDecl _ _ _        -> []+    NewRecordDecl _ c (l, lty) ->+      [recLabel m tc' tvs ty' (l, [c], lty) | l `notElem` hs]+  where tc' = qualQualify m tc+        ty' = constrType tc' tvs+values m (IFunctionDecl _ f Nothing a qty) =+  [Value (qualQualify m f) False a (typeScheme (toQualPredType m [] qty))]+values m (IFunctionDecl _ f (Just tv) _ qty) =+  [Value (qualQualify m f) True 0 (typeScheme (toQualPredType m [tv] qty))]+values m (IClassDecl _ _ qcls _ tv ds hs) =+  map (classMethod m qcls' tv) (filter ((`notElem` hs) . imethod) ds)+  where qcls' = qualQualify m qcls+values _ _                        = []++dataConstr :: ModuleIdent -> QualIdent -> [Ident] -> ConstrDecl -> ValueInfo+dataConstr m tc tvs (ConstrDecl _ evs cx c tys) =+  DataConstructor (qualifyLike tc c) a labels $+    constrType' m tc tvs evs cx tys+  where a      = length tys+        labels = replicate a anonId+dataConstr m tc tvs (ConOpDecl _ evs cx ty1 op ty2) =+  DataConstructor (qualifyLike tc op) 2 [anonId, anonId] $+    constrType' m tc tvs evs cx [ty1, ty2]+dataConstr m tc tvs (RecordDecl _ evs cx c fs) =+  DataConstructor (qualifyLike tc c) a labels $+    constrType' m tc tvs evs cx tys+  where fields        = [(l, ty) | FieldDecl _ ls ty <- fs, l <- ls]+        (labels, tys) = unzip fields+        a             = length labels++newConstr :: ModuleIdent -> QualIdent -> [Ident] -> NewConstrDecl -> ValueInfo+newConstr m tc tvs (NewConstrDecl _ c ty1) =+  NewtypeConstructor (qualifyLike tc c) anonId $+  constrType' m tc tvs [] [] [ty1]+newConstr m tc tvs (NewRecordDecl _ c (l, ty1)) =+  NewtypeConstructor (qualifyLike tc c) l $+  constrType' m tc tvs [] [] [ty1]++recLabel :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr+           -> (Ident, [Ident], TypeExpr) -> ValueInfo+recLabel m tc tvs ty0 (l, cs, lty) = Label ql qcs tySc+  where ql   = qualifyLike tc l+        qcs  = map (qualifyLike tc) cs+        tySc = polyType (toQualType m tvs (ArrowType ty0 lty))++constrType' :: ModuleIdent -> QualIdent -> [Ident] -> [Ident] -> Context+            -> [TypeExpr] -> ExistTypeScheme+constrType' m tc tvs evs cx tys = ForAllExist (length tvs) (length evs) pty+  where tvs' = tvs ++ evs+        pty  = qualifyPredType m $ toConstrType tc tvs' cx tys++constrType :: QualIdent -> [Ident] -> TypeExpr+constrType tc tvs = foldl ApplyType (ConstructorType tc) $ map VariableType tvs++-- We always enter class methods with an arity of 0 into the value environment+-- because there may be different implementations with different arities.++classMethod :: ModuleIdent -> QualIdent -> Ident -> IMethodDecl -> ValueInfo+classMethod m qcls tv (IMethodDecl _ f _ qty) =+  Value (qualifyLike qcls f) True 0 $+    typeScheme $ qualifyPredType m $ toMethodType qcls tv qty++-- ---------------------------------------------------------------------------++-- After all modules have been imported, the compiler has to ensure that+-- all references to a data type use the same list of constructors.++importUnifyData :: CompilerEnv -> CompilerEnv+importUnifyData cEnv = cEnv { tyConsEnv = importUnifyData' $ tyConsEnv cEnv }++importUnifyData' :: TCEnv -> TCEnv+importUnifyData' tcEnv = fmap (setInfo allTyCons) tcEnv+  where+  setInfo tcs t   = case Map.lookup (origName t) tcs of+                         Nothing -> error "Imports.importUnifyData'"+                         Just ty -> ty+  allTyCons       = foldr (mergeData . snd) Map.empty $ allImports tcEnv+  mergeData t tcs =+    Map.insert tc (maybe t (sureMerge t) $ Map.lookup tc tcs) tcs+    where tc = origName t+  sureMerge x y = case merge x y of+                       Nothing -> error "Imports.importUnifyData'.sureMerge"+                       Just z  -> z++-- ---------------------------------------------------------------------------++-- |+qualifyEnv :: CompilerEnv -> CompilerEnv+qualifyEnv env = qualifyLocal env+               $ foldl (flip importInterfaceIntf) initEnv+               $ Map.elems+               $ interfaceEnv env+  where initEnv = initCompilerEnv $ moduleIdent env++qualifyLocal :: CompilerEnv -> CompilerEnv -> CompilerEnv+qualifyLocal currentEnv initEnv = currentEnv+  { opPrecEnv = foldr bindQual   pEnv  $ localBindings $ opPrecEnv currentEnv+  , tyConsEnv = foldr bindQual   tcEnv $ localBindings $ tyConsEnv currentEnv+  , valueEnv  = foldr bindGlobal tyEnv $ localBindings $ valueEnv  currentEnv+  , classEnv  = Map.unionWith mergeClassInfo clsEnv $ classEnv currentEnv+  , instEnv   = Map.union                    iEnv   $ instEnv  currentEnv+  }+  where+    pEnv   = opPrecEnv initEnv+    tcEnv  = tyConsEnv initEnv+    tyEnv  = valueEnv  initEnv+    clsEnv = classEnv  initEnv+    iEnv   = instEnv   initEnv+    bindQual   (_, y) = qualBindTopEnv (origName y) y+    bindGlobal (x, y)+      | hasGlobalScope x = bindQual (x, y)+      | otherwise        = bindTopEnv x y++-- Importing an interface into another interface is somewhat simpler+-- because all entities are imported into the environment. In addition,+-- only a qualified import is necessary. Note that the hidden data types+-- are imported as well because they may be used in type expressions in+-- an interface.++importInterfaceIntf :: Interface -> CompilerEnv -> CompilerEnv+importInterfaceIntf (Interface m _ ds) env = env+  { opPrecEnv = importEntitiesIntf m (precs  m)       ds $ opPrecEnv env+  , tyConsEnv = importEntitiesIntf m (hiddenTypes  m) ds $ tyConsEnv env+  , valueEnv  = importEntitiesIntf m (values m)       ds $ valueEnv  env+  , classEnv  = importClasses      m                  ds $ classEnv  env+  , instEnv   = importInstances    m                  ds $ instEnv   env+  }++importEntitiesIntf :: Entity a => ModuleIdent -> (IDecl -> [a]) -> [IDecl]+                    -> TopEnv a -> TopEnv a+importEntitiesIntf m ents ds env = foldr importEntity env (concatMap ents ds)+  where importEntity x = qualImportTopEnv (fromMaybe m (qidModule (origName x)))+                                          (unqualify (origName x)) x
− src/Imports.lhs
@@ -1,379 +0,0 @@--% $Id: Imports.lhs,v 1.25 2004/02/13 19:24:00 wlux Exp $-%-% Copyright (c) 2000-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Imports.lhs}-\section{Importing interfaces}-This module provides a few functions which can be used to import-interfaces into the current module.-\begin{verbatim}--> module Imports(importInterface,importInterfaceIntf,importUnifyData) where--> import Data.Maybe-> import qualified Data.Set as Set-> import qualified Data.Map as Map--> import Curry.Syntax-> import Types-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base-> import TopEnv---\end{verbatim}-Four kinds of environments are computed from the interface, one-containing the operator precedences, another for the type-constructors, the third containing the types of the data-constructors and functions, and the last contains the arity for each-function and constructor. Note that the original names of all-entities defined in the imported module are qualified appropriately.-The same is true for type expressions.-\begin{verbatim}--> type ExpPEnv = Map.Map Ident PrecInfo-> type ExpTCEnv = Map.Map Ident TypeInfo-> type ExpValueEnv = Map.Map Ident ValueInfo-> type ExpArityEnv = Map.Map Ident ArityInfo--\end{verbatim}-When an interface is imported, the compiler first transforms the-interface into these environments. If an import specification is-present, the environments are restricted to only those entities which-are included in the specification or not hidden by it, respectively.-The resulting environments are then imported into the current module-using either a qualified import or both a qualified and an unqualified-import.-\begin{verbatim}--> importInterface :: Position -> ModuleIdent -> Bool -> Maybe ImportSpec->                 -> Interface -> PEnv -> TCEnv -> ValueEnv -> ArityEnv->                 -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> importInterface p m q is i pEnv tcEnv tyEnv aEnv =->   (importEntities m q vs id mPEnv pEnv,->    importEntities m q ts (importData vs) mTCEnv tcEnv,->    importEntities m q vs id mTyEnv tyEnv,->    importEntities m q as id mAEnv aEnv)->   where mPEnv  = intfEnv bindPrec i->         mTCEnv = intfEnv bindTC i->         mTyEnv = intfEnv bindTy i->         mAEnv  = intfEnv bindA i->         is' = maybe [] (expandSpecs m mTCEnv mTyEnv) is->         ts  = isVisible is (Set.fromList (foldr addType [] is'))->         vs  = isVisible is (Set.fromList (foldr addValue [] is'))->         as  = isVisible is (Set.fromList (foldr addArity [] is'))--> isVisible :: Maybe ImportSpec -> Set.Set Ident -> Ident -> Bool-> isVisible (Just (Importing _ _)) xs = (`Set.member` xs)-> isVisible (Just (Hiding _ _)) xs = (`Set.notMember` xs)-> isVisible _ _ = const True--> importEntities :: Entity a => ModuleIdent -> Bool -> (Ident -> Bool)->                -> (a -> a) -> Map.Map Ident a -> TopEnv a -> TopEnv a-> importEntities m q isVisible f mEnv env =->   foldr (uncurry (if q then qualImportTopEnv m else importUnqual m)) env->         [(x,f y) | (x,y) <- Map.toList mEnv, isVisible x]->   where importUnqual m x y = importTopEnv m x y . qualImportTopEnv m x y--> importData :: (Ident -> Bool) -> TypeInfo -> TypeInfo-> importData isVisible (DataType tc n cs) =->   DataType tc n (map (>>= importConstr isVisible) cs)-> importData isVisible (RenamingType tc n nc) =->   maybe (DataType tc n []) (RenamingType tc n) (importConstr isVisible nc)-> importData isVisible (AliasType tc  n ty) = AliasType tc n ty--> importConstr :: (Ident -> Bool) -> Data a -> Maybe (Data a)-> importConstr isVisible (Data c n tys)->   | isVisible c = Just (Data c n tys)->   | otherwise = Nothing--\end{verbatim}-Importing an interface into another interface is somewhat simpler-because all entities are imported into the environment. In addition,-only a qualified import is necessary. Note that the hidden data types-are imported as well because they may be used in type expressions in-an interface.-\begin{verbatim}--> importInterfaceIntf :: Interface -> PEnv -> TCEnv -> ValueEnv -> ArityEnv->                     -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> importInterfaceIntf i pEnv tcEnv tyEnv aEnv =->   (importEntities m True (const True) id (intfEnv bindPrec i) pEnv,->    importEntities m True (const True) id (intfEnv bindTCHidden i) tcEnv,->    importEntities m True (const True) id (intfEnv bindTy i) tyEnv,->    importEntities m True (const True) id (intfEnv bindA i) aEnv)->   where Interface m _ = i--\end{verbatim}-In a first step, the three export environments are initialized from-the interface's declarations. This step also qualifies the names of-all entities defined in (but not imported into) the interface with its-module name.  -\begin{verbatim}--> intfEnv :: (ModuleIdent -> IDecl -> Map.Map Ident a -> Map.Map Ident a)->         -> Interface -> Map.Map Ident a-> intfEnv bind (Interface m ds) = foldr (bind m) Map.empty ds--> bindPrec :: ModuleIdent -> IDecl -> ExpPEnv -> ExpPEnv-> bindPrec m (IInfixDecl _ fix p op) =->   Map.insert (unqualify op) (PrecInfo (qualQualify m op) (OpPrec fix p))-> bindPrec _ _ = id--> bindTC :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv-> bindTC m (IDataDecl _ tc tvs cs) mTCEnv ->   | isJust (Map.lookup (unqualify tc) mTCEnv) =->     mTCEnv->   | otherwise =->     bindType DataType m tc tvs (map (fmap mkData) cs) mTCEnv->   where mkData (ConstrDecl _ evs c tys) =->           Data c (length evs) (toQualTypes m tvs tys)->         mkData (ConOpDecl _ evs ty1 c ty2) =->           Data c (length evs) (toQualTypes m tvs [ty1,ty2])-> bindTC m (INewtypeDecl _ tc tvs (NewConstrDecl _ evs c ty)) mTCEnv =->   bindType RenamingType m tc tvs ->	 (Data c (length evs) (toQualType m tvs ty)) mTCEnv-> bindTC m (ITypeDecl _ tc tvs ty) mTCEnv->   | isRecordExtId tc' = ->     bindType AliasType m (qualify (fromRecordExtId tc')) tvs ->	   (toQualType m tvs ty) mTCEnv->   | otherwise =->     bindType AliasType m tc tvs (toQualType m tvs ty) mTCEnv->   where tc' = unqualify tc-> bindTC m _ mTCEnv = mTCEnv--> bindTCHidden :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv-> bindTCHidden m (HidingDataDecl _ tc tvs) =->   bindType DataType m (qualify tc) tvs []-> bindTCHidden m d = bindTC m d--> bindType :: (QualIdent -> Int -> a -> TypeInfo) -> ModuleIdent -> QualIdent->          -> [Ident] -> a -> ExpTCEnv -> ExpTCEnv-> bindType f m tc tvs =->   Map.insert (unqualify tc) . f (qualQualify m tc) (length tvs) --> bindTy :: ModuleIdent -> IDecl -> ExpValueEnv -> ExpValueEnv-> bindTy m (IDataDecl _ tc tvs cs) =->   flip (foldr (bindConstr m tc' tvs (constrType tc' tvs))) (catMaybes cs)->   where tc' = qualQualify m tc-> bindTy m (INewtypeDecl _ tc tvs nc) =->   bindNewConstr m tc' tvs (constrType tc' tvs) nc->   where tc' = qualQualify m tc-> --bindTy m (ITypeDecl _ r tvs (RecordType fs _)) =-> --  flip (foldr (bindRecLabel m r')) fs-> --  where r' = qualifyWith m (fromRecordExtId (unqualify r))-> bindTy m (IFunctionDecl _ f _ ty) =->   Map.insert (unqualify f)->           (Value (qualQualify m f) (polyType (toQualType m [] ty)))-> bindTy m _ = id--> bindConstr :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr -> ConstrDecl->            -> ExpValueEnv -> ExpValueEnv-> bindConstr m tc tvs ty0 (ConstrDecl _ evs c tys) =->   bindValue DataConstructor m tc tvs c evs (foldr ArrowType ty0 tys)-> bindConstr m tc tvs ty0 (ConOpDecl _ evs ty1 op ty2) =->   bindValue DataConstructor m tc tvs op evs->             (ArrowType ty1 (ArrowType ty2 ty0))--> bindNewConstr :: ModuleIdent -> QualIdent -> [Ident] -> TypeExpr->               -> NewConstrDecl -> ExpValueEnv -> ExpValueEnv-> bindNewConstr m tc tvs ty0 (NewConstrDecl _ evs c ty1) =->   bindValue NewtypeConstructor m tc tvs c evs (ArrowType ty1 ty0)--> --bindRecLabel :: ModuleIdent -> QualIdent -> ([Ident],TypeExpr)-> --      -> ExpValueEnv -> ExpValueEnv-> --bindRecLabel m r ([l],ty) =-> --  Map.insert l (Label (qualify l) r (polyType (toQualType m [] ty)))--> bindValue :: (QualIdent -> ExistTypeScheme -> ValueInfo) -> ModuleIdent->           -> QualIdent -> [Ident] -> Ident -> [Ident] -> TypeExpr->           -> ExpValueEnv -> ExpValueEnv-> bindValue f m tc tvs c evs ty = Map.insert c (f (qualifyLike tc c) sigma)->   where sigma = ForAllExist (length tvs) (length evs) (toQualType m tvs ty)->         qualifyLike x = maybe qualify qualifyWith (qualidMod x)--> bindA :: ModuleIdent -> IDecl -> ExpArityEnv -> ExpArityEnv-> bindA m (IDataDecl _ _ _ cs) expAEnv->    = foldr (bindConstrA m) expAEnv (catMaybes cs)-> bindA m (IFunctionDecl _ f a _) expAEnv->    = Map.insert (unqualify f) (ArityInfo (qualQualify m f) a) expAEnv-> bindA _ _ expAEnv = expAEnv--> bindConstrA :: ModuleIdent -> ConstrDecl -> ExpArityEnv -> ExpArityEnv-> bindConstrA m (ConstrDecl _ _ c tys) expAEnv->    = Map.insert c (ArityInfo (qualifyWith m c) (length tys)) expAEnv-> bindConstrA m (ConOpDecl _ _ _ c _) expAEnv->    = Map.insert c (ArityInfo (qualifyWith m c) 2) expAEnv--\end{verbatim}-After the environments have been initialized, the optional import-specifications can be checked. There are two kinds of import-specifications, a ``normal'' one, which names the entities that shall-be imported, and a hiding specification, which lists those entities-that shall not be imported.--There is a subtle difference between both kinds of-specifications. While it is not allowed to list a data constructor-outside of its type in a ``normal'' specification, it is allowed to-hide a data constructor explicitly. E.g., if module \texttt{A} exports-the data type \texttt{T} with constructor \texttt{C}, the data-constructor can be imported with one of the two specifications-\begin{verbatim}-import A(T(C))-import A(T(..))-\end{verbatim}-but can be hidden in three different ways:-\begin{verbatim}-import A hiding(C)-import A hiding(T(C))-import A hiding(T(..))-\end{verbatim}--The functions \texttt{expandImport} and \texttt{expandHiding} check-that all entities in an import specification are actually exported-from the module. In addition, all imports of type constructors are-changed into a \texttt{T()} specification and explicit imports for the-data constructors are added.-\begin{verbatim}--> expandSpecs :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> ImportSpec->             -> [Import]-> expandSpecs m tcEnv tyEnv (Importing _ is) =->   concat (map (expandImport m tcEnv tyEnv) is)-> expandSpecs m tcEnv tyEnv (Hiding _ is) =->   concat (map (expandHiding m tcEnv tyEnv) is)--> expandImport :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Import->              -> [Import]-> expandImport m tcEnv tyEnv (Import x) = expandThing m tcEnv tyEnv x-> expandImport m tcEnv tyEnv (ImportTypeWith tc cs) =->   [expandTypeWith m tcEnv tc cs]-> expandImport m tcEnv tyEnv (ImportTypeAll tc) =->   [expandTypeAll m tcEnv tc]--> expandHiding :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Import->              -> [Import]-> expandHiding m tcEnv tyEnv (Import x) = expandHide m tcEnv tyEnv x-> expandHiding m tcEnv tyEnv (ImportTypeWith tc cs) =->   [expandTypeWith m tcEnv tc cs]-> expandHiding m tcEnv tyEnv (ImportTypeAll tc) =->   [expandTypeAll m tcEnv tc]--> expandThing :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Ident->             -> [Import]-> expandThing m tcEnv tyEnv tc =->   case Map.lookup tc tcEnv of->     Just _ -> expandThing' m tyEnv tc (Just [ImportTypeWith tc []])->     Nothing -> expandThing' m tyEnv tc Nothing--> expandThing' :: ModuleIdent -> ExpValueEnv -> Ident->              -> Maybe [Import] -> [Import]-> expandThing' m tyEnv f tcImport =->   case Map.lookup f tyEnv of->     Just v->       | isConstr v -> maybe (errorAt' (importDataConstr m f)) id tcImport->       | otherwise -> Import f : maybe [] id tcImport->     Nothing -> maybe (errorAt' (undefinedEntity m f)) id tcImport->   where isConstr (DataConstructor _ _) = True->         isConstr (NewtypeConstructor _ _) = True->         isConstr (Value _ _) = False--> expandHide :: ModuleIdent -> ExpTCEnv -> ExpValueEnv -> Ident->            -> [Import]-> expandHide m tcEnv tyEnv tc =->   case Map.lookup tc tcEnv of->     Just _ -> expandHide' m tyEnv tc (Just [ImportTypeWith tc []])->     Nothing -> expandHide' m tyEnv tc Nothing--> expandHide' :: ModuleIdent -> ExpValueEnv -> Ident->             -> Maybe [Import] -> [Import]-> expandHide' m tyEnv f tcImport =->   case Map.lookup f tyEnv of->     Just _ -> Import f : maybe [] id tcImport->     Nothing -> maybe (errorAt' (undefinedEntity m f)) id tcImport--> expandTypeWith ::  ModuleIdent -> ExpTCEnv -> Ident -> [Ident]->                -> Import-> expandTypeWith m tcEnv tc cs =->   case Map.lookup tc tcEnv of->     Just (DataType _ _ cs') ->->       ImportTypeWith tc (map (checkConstr [c | Just (Data c _ _) <- cs']) cs)->     Just (RenamingType _ _ (Data c _ _)) ->->       ImportTypeWith tc (map (checkConstr [c]) cs)->     Just _ -> errorAt' (nonDataType m tc)->     Nothing -> errorAt' (undefinedEntity m tc)->   where checkConstr cs c->           | c `elem` cs = c->           | otherwise = errorAt' (undefinedDataConstr m tc c)--> expandTypeAll :: ModuleIdent -> ExpTCEnv -> Ident -> Import-> expandTypeAll m tcEnv tc =->   case Map.lookup tc tcEnv of->     Just (DataType _ _ cs) -> ImportTypeWith tc [c | Just (Data c _ _) <- cs]->     Just (RenamingType _ _ (Data c _ _)) -> ImportTypeWith tc [c]->     Just _ -> errorAt' (nonDataType m tc)->     Nothing -> errorAt' (undefinedEntity m tc)--\end{verbatim}-After all modules have been imported, the compiler has to ensure that-all references to a data type use the same list of constructors.-\begin{verbatim}--> importUnifyData :: TCEnv -> TCEnv-> importUnifyData tcEnv =->   fmap (setInfo (foldr (mergeData . snd) Map.empty (allImports tcEnv))) tcEnv->   where setInfo tcs t = fromJust (Map.lookup (origName t) tcs)->         mergeData t tcs =->           Map.insert tc (maybe t (fromJust . merge t) (Map.lookup tc tcs)) tcs->           where tc = origName t--\end{verbatim}-Auxiliary functions:-\begin{verbatim}--> addType :: Import -> [Ident] -> [Ident]-> addType (Import _) tcs = tcs-> addType (ImportTypeWith tc _) tcs = tc : tcs-> addType (ImportTypeAll _) _ = internalError "types"--> addValue :: Import -> [Ident] -> [Ident]-> addValue (Import f) fs = f : fs-> addValue (ImportTypeWith _ cs) fs = cs ++ fs-> addValue (ImportTypeAll _) _ = internalError "values"--> addArity :: Import -> [Ident] -> [Ident]-> addArity (Import f) ids = f:ids-> addArity (ImportTypeWith _ cs) ids = cs ++ ids-> addArity (ImportTypeAll _) _ = internalError "arities"--> constrType :: QualIdent -> [Ident] -> TypeExpr-> constrType tc tvs = ConstructorType tc (map VariableType tvs)--\end{verbatim}-Error messages:-\begin{verbatim}--> undefinedEntity :: ModuleIdent -> Ident -> (Position,String)-> undefinedEntity m x =->  (positionOfIdent x,->   "Module " ++ moduleName m ++ " does not export " ++ name x)--> undefinedDataConstr :: ModuleIdent -> Ident -> Ident -> (Position,String)-> undefinedDataConstr m tc c =->  (positionOfIdent c,   ->   name c ++ " is not a data constructor of type " ++ name tc)--> nonDataType :: ModuleIdent -> Ident -> (Position,String)-> nonDataType m tc = ->  (positionOfIdent tc,->   name tc ++ " is not a data type")--> importDataConstr :: ModuleIdent -> Ident -> (Position,String)-> importDataConstr m c = ->  (positionOfIdent c,->   "Explicit import for data constructor " ++ name c)--\end{verbatim}
− src/InterfaceCheck.hs
@@ -1,142 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- InterfaceCheck - Checks the equality of the interfaces of two FlatCurry ---                  programs ------ January 2006,--- Martin Engelke (men@informatik.uni-kiel.de)----module InterfaceCheck where--import Data.List--import Curry.ExtendedFlat.Type--------------------------------------------------------------------------------------- Checks whether the interfaces of two FlatCurry programs are equal -interfaceCheck :: Prog -> Prog -> Bool-interfaceCheck (Prog m1 is1 ts1 fs1 os1) (Prog m2 is2 ts2 fs2 os2)-   = m1 == m2 -     && sort is1 == sort is2-     && checkTypeDecls ts1 ts2-     && checkFuncDecls fs1 fs2-     && checkOpDecls os1 os2-----------------------------------------------------------------------------------------------------------------------------------------------------------------------checkTypeDecls :: [TypeDecl] -> [TypeDecl] -> Bool-checkTypeDecls ts1 [] = null ts1-checkTypeDecls ts1 ((Type qname vis2 is2 cs2):ts2')-   = let (mt,ts1') = extract (isDataType qname) ts1-     in  maybe False -               (\ (Type _ vis1 is1 cs1) -		-> vis1 == vis2 -		   && is1 == is2 -		   && checkConsDecls cs1 cs2-		   && checkTypeDecls ts1' ts2')-	       mt-checkTypeDecls ts1 ((TypeSyn qname vis2 is2 texpr2):ts2')-   = let (mt,ts1') = extract (isTypeSyn qname) ts1-     in  maybe False-	       (\ (TypeSyn _ vis1 is1 texpr1)-		-> vis1 == vis2-		   && is1 == is2-		   && texpr1 == texpr2-		   && checkTypeDecls ts1' ts2')-	       mt-----checkConsDecls :: [ConsDecl] -> [ConsDecl] -> Bool-checkConsDecls cs1 [] = null cs1-checkConsDecls cs1 ((Cons qname arity2 vis2 texprs2):cs2')-   = let (mc,cs1') = extract (isCons qname) cs1-     in  maybe False-	       (\ (Cons _ arity1 vis1 texprs1)-		-> arity1 == arity2-		   && vis1 == vis2-		   && texprs1 == texprs2-		   && checkConsDecls cs1' cs2')-	       mc-----checkFuncDecls :: [FuncDecl] -> [FuncDecl] -> Bool-checkFuncDecls fs1 [] = null fs1-checkFuncDecls fs1 ((Func qname arity2 vis2 texpr2 rule2):fs2')-   = let (mf,fs1') = extract (isFunc qname) fs1-     in  maybe False-	       (\ (Func _ arity1 vis1 texpr1 rule1)-		-> arity1 == arity2-		   && vis1 == vis2-		   && texpr1 == texpr2-		   && checkRule rule1 rule2-		   && checkFuncDecls fs1' fs2')-	       mf-----checkRule :: Rule -> Rule -> Bool-checkRule (Rule _ _)   (Rule _ _)   = True-checkRule (External _) (External _) = True-checkRule _            _            = False-----checkOpDecls :: [OpDecl] -> [OpDecl] -> Bool-checkOpDecls os1 [] = null os1-checkOpDecls os1 ((Op qname fix2 prec2):os2')-   = let (mo,os1') = extract (isOp qname) os1-     in  maybe False-	       (\ (Op _ fix1 prec1)-		-> prec1 == prec2-		   && fix1 == fix2-		   && checkOpDecls os1' os2')-	       mo---------------------------------------------------------------------------------------isDataType :: QName -> TypeDecl -> Bool-isDataType qname (Type qname' _ _ _) = qname == qname'-isDataType _     _                   = False-----isTypeSyn :: QName -> TypeDecl -> Bool-isTypeSyn qname (TypeSyn qname' _ _ _) = qname == qname'-isTypeSyn _     _                      = False-----isCons :: QName -> ConsDecl -> Bool-isCons qname (Cons qname' _ _ _) = qname == qname'-----isFunc :: QName -> FuncDecl -> Bool-isFunc qname (Func qname' _ _ _ _) = qname == qname'-----isOp :: QName -> OpDecl -> Bool-isOp qname (Op qname' _ _) = qname == qname'---------------------------------------------------------------------------------------extract :: (a -> Bool) -> [a] -> (Maybe a, [a])-extract _ [] = (Nothing, [])-extract c (x:xs) | c x       = (Just x, xs)-		 | otherwise = let (res, xs') = extract c xs in (res, x:xs')--{---- Alternativ:-extract :: (a -> Bool) -> [a] -> (Maybe a, [a])-extract c xs = maybe (Nothing, xs) (\x -> (Just x, delete x xs)) (find c xs)--}------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ src/Interfaces.hs view
@@ -0,0 +1,144 @@+{- |+    Module      :  $Header$+    Description :  Loading interfaces+    Copyright   :  (c) 2000 - 2004, Wolfgang Lux+                       2011 - 2013, Björn Peemöller+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    The compiler maintains a global environment holding all (directly or+    indirectly) imported interface declarations for a module.++    This module contains a function to load *all* interface declarations+    declared by the (directly or indirectly) imported modules, regardless+    whether they are included by the import specification or not.++    The declarations are later brought into the scope of the module via the+    function 'importModules', see module "Imports".++    Interface files are updated by the Curry builder when necessary,+    see module "CurryBuilder".+-}+module Interfaces (loadInterfaces) where++import           Control.Monad               (unless)+import qualified Control.Monad.State    as S (StateT, execStateT, gets, modify)+import qualified Data.Map               as M (insert, member)++import           Curry.Base.Ident+import           Curry.Base.Monad+import           Curry.Base.Position+import           Curry.Base.Pretty+import           Curry.Files.PathUtils+import           Curry.Syntax++import Base.Messages+import Env.Interface++import Checks.InterfaceSyntaxCheck (intfSyntaxCheck)++-- Interface accumulating monad+type IntfLoader a = S.StateT LoaderState IO a++data LoaderState = LoaderState+  { iEnv   :: InterfaceEnv+  , spaths :: [FilePath]+  , errs   :: [Message]+  }++-- Report an error.+report :: [Message] -> IntfLoader ()+report msg = S.modify $ \ s -> s { errs = msg ++ errs s }++-- Check whether a module interface is already loaded.+loaded :: ModuleIdent -> IntfLoader Bool+loaded m = S.gets $ \ s -> m `M.member` iEnv s++-- Retrieve the search paths+searchPaths :: IntfLoader [FilePath]+searchPaths = S.gets spaths++-- Add an interface to the environment.+addInterface :: ModuleIdent -> Interface -> IntfLoader ()+addInterface m intf = S.modify $ \ s -> s { iEnv = M.insert m intf $ iEnv s }++-- |Load the interfaces needed by a given module.+-- This function returns an 'InterfaceEnv' containing the 'Interface's which+-- were successfully loaded.+loadInterfaces :: [FilePath] -- ^ 'FilePath's to search in for interfaces+               -> Module a   -- ^ 'Module' header with import declarations+               -> CYIO InterfaceEnv+loadInterfaces paths (Module _ m _ is _) = do+  res <- liftIO $ S.execStateT load (LoaderState initInterfaceEnv paths [])+  if null (errs res) then ok (iEnv res) else failMessages (reverse $ errs res)+  where load = mapM_ (loadInterface [m]) [(p, m') | ImportDecl p m' _ _ _ <- is]++-- |Load an interface into the given environment.+--+-- If an import declaration for a module is found, the compiler first+-- checks whether an import for the module is already pending.+-- In this case the module imports are cyclic which is not allowed in Curry.+-- Therefore, the import will be skipped and an error will be issued.+-- Otherwise, the compiler checks whether the module has already been imported.+-- If so, nothing needs to be done, otherwise the interface will be searched+-- for in the import paths and compiled.+loadInterface :: [ModuleIdent] -> (Position, ModuleIdent) -> IntfLoader ()+loadInterface ctxt imp@(p, m)+  | m `elem` ctxt = report [errCyclicImport p (m : takeWhile (/= m) ctxt)]+  | otherwise     = do+    isLoaded <- loaded m+    unless isLoaded $ do+      paths  <- searchPaths+      mbIntf <- liftIO $ lookupCurryInterface paths m+      case mbIntf of+        Nothing -> report [errInterfaceNotFound p m]+        Just fn -> compileInterface ctxt imp fn++-- |Compile an interface by recursively loading its dependencies.+--+-- After reading an interface, all imported interfaces are recursively+-- loaded and inserted into the interface's environment.+compileInterface :: [ModuleIdent] -> (Position, ModuleIdent) -> FilePath+                 -> IntfLoader ()+compileInterface ctxt (p, m) fn = do+  mbSrc <- liftIO $ readModule fn+  case mbSrc of+    Nothing  -> report [errInterfaceNotFound p m]+    Just src -> case runCYMIgnWarn (parseInterface fn src) of+      Left err -> report err+      Right intf@(Interface n is _) ->+        if m /= n+          then report [errWrongInterface (first fn) m n]+          else do+            let (intf', intfErrs) = intfSyntaxCheck intf+            mapM_ report [intfErrs]+            mapM_ (loadInterface (m : ctxt)) [ (q, i) | IImportDecl q i <- is ]+            addInterface m intf'++-- Error message for required interface that could not be found.+errInterfaceNotFound :: Position -> ModuleIdent -> Message+errInterfaceNotFound p m = posMessage p $+  text "Interface for module" <+> text (moduleName m) <+> text "not found"++-- Error message for an unexpected interface.+errWrongInterface :: Position -> ModuleIdent -> ModuleIdent -> Message+errWrongInterface p m n = posMessage p $+  text "Expected interface for" <+> text (moduleName m)+  <> comma <+> text "but found" <+> text (moduleName n)++-- Error message for a cyclic import.+errCyclicImport :: Position -> [ModuleIdent] -> Message+errCyclicImport _ []  = internalError "Interfaces.errCyclicImport: empty list"+errCyclicImport p [m] = posMessage p $+  text "Recursive import for module" <+> text (moduleName m)+errCyclicImport p ms  = posMessage p $+  text "Cyclic import dependency between modules"+  <+> hsep (punctuate comma (map text inits)) <+> text "and" <+> text lastm+  where+  (inits, lastm)         = splitLast $ map moduleName ms+  splitLast []           = internalError "Interfaces.splitLast: empty list"+  splitLast (x : [])     = ([]  , x)+  splitLast (x : y : ys) = (x : xs, z) where (xs, z) = splitLast (y : ys)
− src/KindCheck.lhs
@@ -1,320 +0,0 @@--% $Id: KindCheck.lhs,v 1.33 2004/02/13 19:24:04 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{KindCheck.lhs}-\section{Checking Type Definitions}-After the source file has been parsed and all modules have been-imported, the compiler first performs kind checking on all type-definitions and signatures. Because Curry currently does not support-type classes, kind checking is rather trivial. All types must be of-first order kind ($\star$), i.e., all type constructor applications-must be saturated.--During kind checking, this module will also disambiguate nullary-constructors and type variables which -- in contrast to Haskell -- is-not possible on purely syntactic criteria. In addition it is checked-that all type constructors and type variables occurring on the right-hand side of a type declaration are actually defined and no identifier-is defined more than once.-\begin{verbatim}--> module KindCheck(kindCheck) where--> import Data.Maybe--> import Curry.Syntax-> import Curry.Syntax.Utils(isTypeDecl)-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base hiding (bindArity)-> import TopEnv--\end{verbatim}-In order to check type constructor applications, the compiler-maintains an environment containing the kind information for all type-constructors. The function \texttt{kindCheck} first initializes this-environment by filtering out the arity of each type constructor from-the imported type environment. Next, the arities of all locally-defined type constructors are inserted into the environment, and,-finally, the declarations are checked within this environment.-\begin{verbatim}--> kindCheck :: ModuleIdent -> TCEnv -> [Decl] -> [Decl]-> kindCheck m tcEnv ds =->   case findDouble (map tconstr ds') of->     Nothing -> map (checkDecl m kEnv) ds->     Just tc -> errorAt' (duplicateType tc)->   where ds' = filter isTypeDecl ds->         kEnv = foldr (bindArity m) (fmap tcArity tcEnv) ds'--\end{verbatim}-The kind environment only needs to record the arity of each type constructor.-\begin{verbatim}--> type KindEnv = TopEnv Int--> bindArity :: ModuleIdent -> Decl -> KindEnv -> KindEnv-> bindArity m (DataDecl _ tc tvs _) = bindArity' m  tc tvs-> bindArity m (NewtypeDecl _ tc tvs _) = bindArity' m  tc tvs-> bindArity m (TypeDecl _ tc tvs _) = bindArity' m  tc tvs-> bindArity _ _ = id--> bindArity' :: ModuleIdent -> Ident -> [Ident]->            -> KindEnv -> KindEnv-> bindArity' m tc tvs ->   = bindTopEnv "KindCheck.bindArity'" tc n ->                . qualBindTopEnv "KindCheck.bindArity'" (qualifyWith m tc) n->   where n = length tvs--> lookupKind :: Ident -> KindEnv -> [Int]-> lookupKind = lookupTopEnv--> qualLookupKind :: QualIdent -> KindEnv -> [Int]-> qualLookupKind = qualLookupTopEnv--\end{verbatim}-When type declarations are checked, the compiler will allow anonymous-type variables on the left hand side of the declaration, but not on-the right hand side. Function and pattern declarations must be-traversed because they can contain local type signatures.-\begin{verbatim}--> checkDecl :: ModuleIdent -> KindEnv -> Decl -> Decl-> checkDecl m kEnv (DataDecl p tc tvs cs) =->   DataDecl p tc tvs' (map (checkConstrDecl m kEnv tvs') cs)->   where tvs' = checkTypeLhs kEnv tvs-> checkDecl m kEnv (NewtypeDecl p tc tvs nc) =->   NewtypeDecl p tc tvs' (checkNewConstrDecl m kEnv tvs' nc)->   where tvs' = checkTypeLhs kEnv tvs-> checkDecl m kEnv (TypeDecl p tc tvs ty) =->   TypeDecl p tc tvs' (checkClosedType m kEnv tvs' ty)->   where tvs' = checkTypeLhs kEnv tvs-> checkDecl m kEnv (TypeSig p vs ty) =->   TypeSig p vs (checkType m kEnv ty)-> checkDecl m kEnv (FunctionDecl p f eqs) =->   FunctionDecl p f (map (checkEquation m kEnv) eqs)-> checkDecl m kEnv (PatternDecl p t rhs) =->   PatternDecl p t (checkRhs m kEnv rhs)-> checkDecl m kEnv (ExternalDecl p cc ie f ty) =->   ExternalDecl p cc ie f (checkType m kEnv ty)-> checkDecl _ _ d = d--> checkTypeLhs :: KindEnv -> [Ident] -> [Ident]-> checkTypeLhs kEnv (tv:tvs)->   | tv == anonId = tv : checkTypeLhs kEnv tvs->   | isTypeConstr tv = errorAt' (noVariable tv)->   | tv `elem` tvs = errorAt' (nonLinear tv)->   | otherwise = tv : checkTypeLhs kEnv tvs->   where isTypeConstr tv = not (null (lookupKind tv kEnv))-> checkTypeLhs _ [] = []--> checkConstrDecl :: ModuleIdent -> KindEnv -> [Ident] -> ConstrDecl -> ConstrDecl-> checkConstrDecl m kEnv tvs (ConstrDecl p evs c tys) =->   ConstrDecl p evs' c (map (checkClosedType m kEnv tvs') tys)->   where evs' = checkTypeLhs kEnv evs->         tvs' = evs' ++ tvs-> checkConstrDecl m kEnv tvs (ConOpDecl p evs ty1 op ty2) =->   ConOpDecl p evs' (checkClosedType m kEnv tvs' ty1) op->             (checkClosedType m kEnv tvs' ty2)->   where evs' = checkTypeLhs kEnv evs->         tvs' = evs' ++ tvs--> checkNewConstrDecl :: ModuleIdent -> KindEnv -> [Ident] -> NewConstrDecl ->	     -> NewConstrDecl-> checkNewConstrDecl m kEnv tvs (NewConstrDecl p evs c ty) =->   NewConstrDecl p evs' c (checkClosedType m kEnv tvs' ty)->   where evs' = checkTypeLhs kEnv evs->         tvs' = evs' ++ tvs--\end{verbatim}-Checking expressions is rather straight forward. The compiler must-only traverse the structure of expressions in order to find local-declaration groups.-\begin{verbatim}--> checkEquation :: ModuleIdent -> KindEnv -> Equation -> Equation-> checkEquation m kEnv (Equation p lhs rhs) = ->     Equation p lhs (checkRhs m kEnv rhs)--> checkRhs :: ModuleIdent -> KindEnv -> Rhs -> Rhs-> checkRhs m kEnv (SimpleRhs p e ds) =->   SimpleRhs p (checkExpr m kEnv e) (map (checkDecl m kEnv) ds)-> checkRhs m kEnv (GuardedRhs es ds) =->   GuardedRhs (map (checkCondExpr m kEnv) es) (map (checkDecl m kEnv) ds)--> checkCondExpr :: ModuleIdent -> KindEnv -> CondExpr -> CondExpr-> checkCondExpr m kEnv (CondExpr p g e) =->   CondExpr p (checkExpr m kEnv g) (checkExpr m kEnv e)--> checkExpr :: ModuleIdent -> KindEnv -> Expression -> Expression-> checkExpr _ _ (Literal l) = Literal l-> checkExpr _ _ (Variable v) = Variable v-> checkExpr _ _ (Constructor c) = Constructor c-> checkExpr m kEnv (Paren e) = Paren (checkExpr m kEnv e)-> checkExpr m kEnv (Typed e ty) =->   Typed (checkExpr m kEnv e) (checkType m kEnv ty)-> checkExpr m kEnv (Tuple p es) = Tuple p (map (checkExpr m kEnv ) es)-> checkExpr m kEnv (List p es) = List p (map (checkExpr m kEnv ) es)-> checkExpr m kEnv (ListCompr p e qs) =->   ListCompr p (checkExpr m kEnv e) (map (checkStmt m kEnv ) qs)-> checkExpr m kEnv  (EnumFrom e) = EnumFrom (checkExpr m kEnv  e)-> checkExpr m kEnv  (EnumFromThen e1 e2) =->   EnumFromThen (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)-> checkExpr m kEnv  (EnumFromTo e1 e2) =->   EnumFromTo (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)-> checkExpr m kEnv  (EnumFromThenTo e1 e2 e3) =->   EnumFromThenTo (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)->                  (checkExpr m kEnv  e3)-> checkExpr m kEnv  (UnaryMinus op e) = UnaryMinus op (checkExpr m kEnv  e)-> checkExpr m kEnv  (Apply e1 e2) =->   Apply (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)-> checkExpr m kEnv  (InfixApply e1 op e2) =->   InfixApply (checkExpr m kEnv  e1) op (checkExpr m kEnv  e2)-> checkExpr m kEnv  (LeftSection e op) = LeftSection (checkExpr m kEnv  e) op-> checkExpr m kEnv  (RightSection op e) = RightSection op (checkExpr m kEnv  e)-> checkExpr m kEnv  (Lambda r ts e) = Lambda r ts (checkExpr m kEnv  e)-> checkExpr m kEnv  (Let ds e) =->   Let (map (checkDecl m kEnv) ds) (checkExpr m kEnv  e)-> checkExpr m kEnv  (Do sts e) =->   Do (map (checkStmt m kEnv ) sts) (checkExpr m kEnv  e)-> checkExpr m kEnv  (IfThenElse r e1 e2 e3) =->   IfThenElse r (checkExpr m kEnv  e1) (checkExpr m kEnv  e2)->              (checkExpr m kEnv  e3)-> checkExpr m kEnv  (Case r e alts) =->   Case r (checkExpr m kEnv  e) (map (checkAlt m kEnv) alts)-> checkExpr m kEnv  (RecordConstr fs) =->   RecordConstr (map (checkFieldExpr m kEnv) fs)-> checkExpr m kEnv  (RecordSelection e l) =->   RecordSelection (checkExpr m kEnv  e) l-> checkExpr m kEnv  (RecordUpdate fs e) =->   RecordUpdate (map (checkFieldExpr m kEnv) fs) (checkExpr m kEnv  e)--> checkStmt :: ModuleIdent -> KindEnv -> Statement -> Statement-> checkStmt m kEnv  (StmtExpr p e) = StmtExpr p (checkExpr m kEnv  e)-> checkStmt m kEnv  (StmtBind p t e) = StmtBind p t (checkExpr m kEnv  e)-> checkStmt m kEnv  (StmtDecl ds) = StmtDecl (map (checkDecl m kEnv) ds)--> checkAlt :: ModuleIdent -> KindEnv -> Alt -> Alt-> checkAlt m kEnv (Alt p t rhs) = Alt p t (checkRhs m kEnv rhs)--> checkFieldExpr :: ModuleIdent -> KindEnv -> Field Expression->	            -> Field Expression-> checkFieldExpr m kEnv (Field p l e) = Field p l (checkExpr m kEnv e)--\end{verbatim}-The parser cannot distinguish unqualified nullary type constructors-and type variables. Therefore, if the compiler finds an unbound-identifier in a position where a type variable is admissible, it will-interpret the identifier as such.-\begin{verbatim}--> checkClosedType :: ModuleIdent -> KindEnv -> [Ident] -> TypeExpr ->	  -> TypeExpr-> checkClosedType m kEnv tvs ty = checkClosed tvs (checkType m kEnv  ty)--> checkType :: ModuleIdent -> KindEnv -> TypeExpr -> TypeExpr-> checkType m kEnv (ConstructorType tc tys) =->   case qualLookupKind tc kEnv of->     []->       | not (isQualified tc) && null tys -> VariableType (unqualify tc)->       | otherwise -> errorAt' (undefinedType tc)->     [n]->       | n == n' -> ConstructorType tc (map (checkType m kEnv ) tys)->       | otherwise -> errorAt' (wrongArity tc n n')->     _ -> case (qualLookupKind (qualQualify m tc) kEnv) of->            [n] ->               | n == n' -> ConstructorType tc (map (checkType m kEnv ) tys)->               | otherwise -> errorAt' (wrongArity tc n n')->            _ -> errorAt' (ambiguousType tc)->  where n' = length tys -> checkType m kEnv  (VariableType tv)->   | tv == anonId = VariableType tv->   | otherwise = checkType m kEnv  (ConstructorType (qualify tv) [])-> checkType m kEnv  (TupleType tys) =->   TupleType (map (checkType m kEnv ) tys)-> checkType m kEnv  (ListType ty) =->   ListType (checkType m kEnv  ty)-> checkType m kEnv  (ArrowType ty1 ty2) =->   ArrowType (checkType m kEnv  ty1) (checkType m kEnv  ty2)-> checkType m kEnv  (RecordType fs r) =->   RecordType (map (\ (ls,ty) -> (ls, checkType m kEnv  ty)) fs)->	       (maybe Nothing (Just . checkType m kEnv ) r)--> checkClosed :: [Ident] -> TypeExpr -> TypeExpr-> checkClosed tvs (ConstructorType tc tys) =->   ConstructorType tc (map (checkClosed tvs) tys)-> checkClosed tvs (VariableType tv)->   | tv == anonId || tv `notElem` tvs = errorAt' (unboundVariable tv)->   | otherwise = VariableType tv-> checkClosed tvs (TupleType tys) =->   TupleType (map (checkClosed tvs) tys)-> checkClosed tvs (ListType ty) =->   ListType (checkClosed tvs ty)-> checkClosed tvs (ArrowType ty1 ty2) =->   ArrowType (checkClosed tvs ty1) (checkClosed tvs ty2)-> checkClosed tvs (RecordType fs r) =->   RecordType (map (\ (ls,ty) -> (ls, checkClosed tvs ty)) fs)->	       (maybe Nothing (Just . checkClosed tvs) r)->       --\end{verbatim}-Auxiliary definitions-\begin{verbatim}--> tconstr :: Decl -> Ident-> tconstr (DataDecl p tc _ _) = tc-> tconstr (NewtypeDecl p tc _ _) = tc-> tconstr (TypeDecl p tc _ _) = tc-> tconstr _ = internalError "tconstr"--\end{verbatim}-Error messages:-\begin{verbatim}--> undefinedType :: QualIdent -> (Position,String)-> undefinedType tc = ->     (positionOfQualIdent tc,->      "Undefined type " ++ qualName tc)--> ambiguousType :: QualIdent -> (Position,String)-> ambiguousType tc = ->     (positionOfQualIdent tc,->      "Ambiguous type " ++ qualName tc)--> duplicateType :: Ident -> (Position,String)-> duplicateType tc = ->     (positionOfIdent tc,->      "More than one definition for type " ++ name tc)--> nonLinear :: Ident -> (Position,String)-> nonLinear tv =->  (positionOfIdent tv,      ->   "Type variable " ++ name tv ++->   " occurs more than once on left hand side of type declaration")--> noVariable :: Ident -> (Position,String)-> noVariable tv =->  (positionOfIdent tv,      ->   "Type constructor " ++ name tv ++->   " used in left hand side of type declaration")--> wrongArity :: QualIdent -> Int -> Int -> (Position,String)-> wrongArity tc arity argc =->  (positionOfQualIdent tc,      ->   "Type constructor " ++ qualName tc ++ " expects " ++ arguments arity ++->   " but is applied to " ++ show argc)->   where arguments 0 = "no arguments"->         arguments 1 = "1 argument"->         arguments n = show n ++ " arguments"--> unboundVariable :: Ident -> (Position,String)-> unboundVariable tv = ->     (positionOfIdent tv,->      "Unbound type variable " ++ name tv)--\end{verbatim}
− src/Lift.lhs
@@ -1,307 +0,0 @@--% $Id: Lift.lhs,v 1.23 2004/02/13 14:02:54 wlux Exp $-%-% Copyright (c) 2001-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Lift.lhs}-\section{Lifting Declarations}-After desugaring and simplifying the code, the compiler lifts all-local function declarations to the top-level keeping only local-variable declarations. The algorithm used here is similar to-Johnsson's~\cite{Johnsson87:Thesis} (see also chapter 6-of~\cite{PeytonJonesLester92:Book}). It consists of two phases, first-we abstract each local function declaration, adding its free variables-as initial parameters and update all calls to take these variables-into account. Then all local function declarations are collected and-lifted to the top-level.-\begin{verbatim}--> module Lift(lift) where--> import Control.Monad-> import qualified Control.Monad.State as S-> import Data.List-> import qualified Data.Map as Map-> import qualified Data.Set as Set--> import Curry.Syntax-> import Curry.Syntax.Utils-> import Types-> import Curry.Base.Ident-> import Base-> import TopEnv-> import SCC--> lift :: ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv,EvalEnv)-> lift tyEnv evEnv (Module m es ds) =->   (Module m es (concatMap liftFunDecl ds'),tyEnv',evEnv')->   where (ds',tyEnv',evEnv') =->           S.evalState (S.evalStateT (abstractModule m ds) tyEnv) evEnv--\end{verbatim}-\paragraph{Abstraction}-Besides adding the free variables to every (local) function, the-abstraction pass also has to update the type environment in order to-reflect the new types of the expanded functions. As usual we use a-state monad transformer in order to pass the type environment-through. The environment constructed in the abstraction phase maps-each local function declaration onto its replacement expression,-i.e. the function applied to its free variables.-\begin{verbatim}--> type AbstractState a = S.StateT ValueEnv (S.State EvalEnv) a-> type AbstractEnv = Map.Map Ident Expression--> abstractModule :: ModuleIdent -> [Decl]->                -> AbstractState ([Decl],ValueEnv,EvalEnv)-> abstractModule m ds =->   do->     ds' <- mapM (abstractDecl m "" [] Map.empty) ds->     tyEnv' <- S.get->     evEnv' <- S.lift S.get->     return (ds',tyEnv',evEnv')--> abstractDecl :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Decl->              -> AbstractState Decl-> abstractDecl m _ lvs env (FunctionDecl p f eqs) =->   liftM (FunctionDecl p f) (mapM (abstractEquation m lvs env) eqs)-> abstractDecl m pre lvs env (PatternDecl p t rhs) =->   liftM (PatternDecl p t) (abstractRhs m pre lvs env rhs)-> abstractDecl _ _ _ _ d = return d--> abstractEquation :: ModuleIdent -> [Ident] -> AbstractEnv -> Equation->                  -> AbstractState Equation-> abstractEquation m lvs env (Equation p lhs@(FunLhs f ts) rhs) =->   liftM (Equation p lhs)->         (abstractRhs m (name f ++ ".") (lvs ++ bv ts) env rhs)--> abstractRhs :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Rhs->             -> AbstractState Rhs-> abstractRhs m pre lvs env (SimpleRhs p e _) =->   liftM (flip (SimpleRhs p) []) (abstractExpr m pre lvs env e)--\end{verbatim}-Within a declaration group we have to split the list of declarations-into the function and value declarations. Only the function-declarations are affected by the abstraction algorithm; the value-declarations are left unchanged except for abstracting their right-hand sides.--The abstraction of a recursive declaration group is complicated by the-fact that not all functions need to call each in a recursive-declaration group. E.g., in the following example neither g nor h-call each other.-\begin{verbatim}-  f = g True-    where x = f 1-          f z = y + z-          y = g False-          g z = if z then x else 0-\end{verbatim}-Because of this fact, f and g can be abstracted separately by adding-only \texttt{y} to \texttt{f} and \texttt{x} to \texttt{g}. On the-other hand, in the following example-\begin{verbatim}-  f x y = g 4-    where g p = h p + x-          h q = k + y + q-          k = g x-\end{verbatim}-the local function \texttt{g} uses \texttt{h}, so the free variables-of \texttt{h} have to be added to \texttt{g} as well. However, because-\texttt{h} does not call \texttt{g} it is sufficient to add only-\texttt{k} and \texttt{y} (and not \texttt{x}) to its definition. We-handle this by computing the dependency graph between the functions-and splitting this graph into its strongly connected components. Each-component is then processed separately, adding the free variables in-the group to its functions.--We have to be careful with local declarations within desugared case-expressions. If some of the cases have guards, e.g.,-\begin{verbatim}-  case e of-    x | x < 1 -> 1-    x -> let double y = y * y in double x-\end{verbatim}-the desugarer at present may duplicate code. While there is no problem-with local variable declaration being duplicated, we must avoid to-lift local function declarations more than once. Therefore-\texttt{abstractFunDecls} transforms only those function declarations-that have not been lifted and discards the other declarations. Note-that it is easy to check whether a function has been lifted by-checking whether an entry for its untransformed name is still present-in the type environment.-\begin{verbatim}--> abstractDeclGroup :: ModuleIdent -> String -> [Ident] -> AbstractEnv->                   -> [Decl] -> Expression -> AbstractState Expression-> abstractDeclGroup m pre lvs env ds e =->   abstractFunDecls m pre (lvs ++ bv vds) env (scc bv (qfv m) fds) vds e->   where (fds,vds) = partition isFunDecl ds--> abstractFunDecls :: ModuleIdent -> String -> [Ident] -> AbstractEnv->                  -> [[Decl]] -> [Decl] -> Expression->                  -> AbstractState Expression-> abstractFunDecls m pre lvs env [] vds e =->   do->     vds' <- mapM (abstractDecl m pre lvs env) vds->     e' <- abstractExpr m pre lvs env e->     return (Let vds' e')-> abstractFunDecls m pre lvs env (fds:fdss) vds e =->   do->     fs' <- liftM (\tyEnv -> filter (not . isLifted tyEnv) fs) S.get->     S.modify (abstractFunTypes m pre fvs fs')->     S.lift (S.modify (abstractFunAnnots m pre fs'))->     fds' <- mapM (abstractFunDecl m pre fvs lvs env')->                  [d | d <- fds, any (`elem` fs') (bv d)]->     e' <- abstractFunDecls m pre lvs env' fdss vds e->     return (Let fds' e')->   where fs = bv fds->         fvs = filter (`elem` lvs) (Set.toList fvsRhs)->         env' = foldr (bindF (map mkVar fvs)) env fs->         fvsRhs = Set.unions->           [Set.fromList (maybe [v] (qfv m) (Map.lookup v env)) | v <- qfv m fds]->         bindF fvs f = Map.insert f (apply (mkFun m pre f) fvs)->         isLifted tyEnv f = null (lookupValue f tyEnv)--> abstractFunTypes :: ModuleIdent -> String -> [Ident] -> [Ident]->                  -> ValueEnv -> ValueEnv-> abstractFunTypes m pre fvs fs tyEnv = foldr abstractFunType tyEnv fs->   where tys = map (varType tyEnv) fvs->         abstractFunType f tyEnv =->           qualBindFun m (liftIdent pre f)->                         (foldr TypeArrow (varType tyEnv f) tys)->                         (unbindFun f tyEnv)--> abstractFunAnnots :: ModuleIdent -> String -> [Ident] -> EvalEnv -> EvalEnv-> abstractFunAnnots m pre fs evEnv = foldr abstractFunAnnot evEnv fs->   where abstractFunAnnot f evEnv =->           case Map.lookup f evEnv of->             Just ev -> Map.insert (liftIdent pre f) ev (Map.delete f evEnv)->             Nothing -> evEnv--> abstractFunDecl :: ModuleIdent -> String -> [Ident] -> [Ident]->                 -> AbstractEnv -> Decl -> AbstractState Decl-> abstractFunDecl m pre fvs lvs env (FunctionDecl p f eqs) =->   abstractDecl m pre lvs env (FunctionDecl p f' (map (addVars f') eqs))->   where f' = liftIdent pre f->         addVars f (Equation p (FunLhs _ ts) rhs) =->           Equation p (FunLhs f (map VariablePattern fvs ++ ts)) rhs-> abstractFunDecl m pre _ lvs env (ExternalDecl p cc ie f ty) =->   return (ExternalDecl p cc ie (liftIdent pre f) ty)--> abstractExpr :: ModuleIdent -> String -> [Ident] -> AbstractEnv->              -> Expression -> AbstractState Expression-> abstractExpr _ _ _ _ (Literal l) = return (Literal l)-> abstractExpr m pre lvs env (Variable v)->   | isQualified v = return (Variable v)->   | otherwise = maybe (return (Variable v)) (abstractExpr m pre lvs env)->                       (Map.lookup (unqualify v) env)-> abstractExpr _ _ _ _ (Constructor c) = return (Constructor c)-> abstractExpr m pre lvs env (Apply e1 e2) =->   do->     e1' <- abstractExpr m pre lvs env e1->     e2' <- abstractExpr m pre lvs env e2->     return (Apply e1' e2')-> abstractExpr m pre lvs env (Let ds e) = abstractDeclGroup m pre lvs env ds e-> abstractExpr m pre lvs env (Case r e alts) =->   do->     e' <- abstractExpr m pre lvs env e->     alts' <- mapM (abstractAlt m pre lvs env) alts->     return (Case r e' alts')-> abstractExpr m _ _ _ _ = internalError "abstractExpr"--> abstractAlt :: ModuleIdent -> String -> [Ident] -> AbstractEnv -> Alt->             -> AbstractState Alt-> abstractAlt m pre lvs env (Alt p t rhs) =->   liftM (Alt p t) (abstractRhs m pre (lvs ++ bv t) env rhs)--\end{verbatim}-\paragraph{Lifting}-After the abstraction pass, all local function declarations are lifted-to the top-level.-\begin{verbatim}--> liftFunDecl :: Decl -> [Decl]-> liftFunDecl (FunctionDecl p f eqs) = (FunctionDecl p f eqs' : concat dss')->   where (eqs',dss') = unzip (map liftEquation eqs)-> liftFunDecl d = [d]--> liftVarDecl :: Decl -> (Decl,[Decl])-> liftVarDecl (PatternDecl p t rhs) = (PatternDecl p t rhs',ds')->   where (rhs',ds') = liftRhs rhs-> liftVarDecl (ExtraVariables p vs) = (ExtraVariables p vs,[])--> liftEquation :: Equation -> (Equation,[Decl])-> liftEquation (Equation p lhs rhs) = (Equation p lhs rhs',ds')->   where (rhs',ds') = liftRhs rhs--> liftRhs :: Rhs -> (Rhs,[Decl])-> liftRhs (SimpleRhs p e _) = (SimpleRhs p e' [],ds')->   where (e',ds') = liftExpr e--> liftDeclGroup :: [Decl] -> ([Decl],[Decl])-> liftDeclGroup ds = (vds',concat (map liftFunDecl fds ++ dss'))->   where (fds,vds) = partition isFunDecl ds->         (vds',dss') = unzip (map liftVarDecl vds)--> liftExpr :: Expression -> (Expression,[Decl])-> liftExpr (Literal l) = (Literal l,[])-> liftExpr (Variable v) = (Variable v,[])-> liftExpr (Constructor c) = (Constructor c,[])-> liftExpr (Apply e1 e2) = (Apply e1' e2',ds' ++ ds'')->   where (e1',ds') = liftExpr e1->         (e2',ds'') = liftExpr e2-> liftExpr (Let ds e) = (mkLet ds' e',ds'' ++ ds''')->   where (ds',ds'') = liftDeclGroup ds->         (e',ds''') = liftExpr e->         mkLet ds e = if null ds then e else Let ds e-> liftExpr (Case r e alts) = (Case r e' alts',concat (ds':dss'))->   where (e',ds') = liftExpr e->         (alts',dss') = unzip (map liftAlt alts)-> liftExpr _ = internalError "liftExpr"--> liftAlt :: Alt -> (Alt,[Decl])-> liftAlt (Alt p t rhs) = (Alt p t rhs',ds')->   where (rhs',ds') = liftRhs rhs---\end{verbatim}-\paragraph{Auxiliary definitions}-\begin{verbatim}--> isFunDecl :: Decl -> Bool-> isFunDecl (FunctionDecl _ _ _) = True-> isFunDecl (ExternalDecl _ _ _ _ _) = True-> isFunDecl _ = False--> mkFun :: ModuleIdent -> String -> Ident -> Expression-> mkFun m pre f = Variable (qualifyWith m (liftIdent pre f))--> mkVar :: Ident -> Expression-> mkVar v = Variable (qualify v)--> apply :: Expression -> [Expression] -> Expression-> apply = foldl Apply--> qualBindFun :: ModuleIdent -> Ident -> Type -> ValueEnv -> ValueEnv-> qualBindFun m f ty ->   = qualBindTopEnv "Lift.qualBindFun" f' (Value f' (polyType ty))->   where f' = qualifyWith m f--> unbindFun :: Ident -> ValueEnv -> ValueEnv-> unbindFun = unbindTopEnv--> varType :: ValueEnv -> Ident -> Type-> varType tyEnv v =->   case lookupValue v tyEnv of->     [Value _ (ForAll _ ty)] -> ty->     _ -> internalError ("varType " ++ show v)--> liftIdent :: String -> Ident -> Ident-> liftIdent prefix x =->     renameIdent (mkIdent (prefix ++ (show x))) (uniqueId x)->    --renameIdent (mkIdent (prefix ++ name x ++ show (uniqueId x))) (uniqueId x)--\end{verbatim}
+ src/Modules.hs view
@@ -0,0 +1,409 @@+{- |+    Module      :  $Header$+    Description :  Compilation of a single module+    Copyright   :  (c) 1999 - 2004 Wolfgang Lux+                       2005        Martin Engelke+                       2007        Sebastian Fischer+                       2011 - 2015 Björn Peemöller+                       2016        Jan Tikovsky+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module controls the compilation of modules.+-}++module Modules+  ( compileModule, loadAndCheckModule, loadModule, checkModule+  , parseModule, checkModuleHeader+  ) where++import qualified Control.Exception as C   (catch, IOException)+import           Control.Monad            (liftM, unless, when)+import           Data.Char                (toUpper)+import qualified Data.Map          as Map (elems, lookup)+import           Data.Maybe               (fromMaybe)+import           System.Directory         (getTemporaryDirectory, removeFile)+import           System.Exit              (ExitCode (..))+import           System.FilePath          (normalise)+import           System.IO+   (IOMode (ReadMode), Handle, hClose, hGetContents, hPutStr, openFile+  , openTempFile)+import           System.Process           (system)++import Curry.Base.Ident+import Curry.Base.Monad+import Curry.Base.Position+import Curry.Base.Pretty+import Curry.Base.Span+import Curry.FlatCurry.InterfaceEquivalence (eqInterface)+import Curry.Files.Filenames+import Curry.Files.PathUtils+import Curry.Syntax.InterfaceEquivalence++import Base.Messages+import Base.Types++import Env.Interface++-- source representations+import qualified Curry.AbstractCurry as AC+import qualified Curry.FlatCurry     as FC+import qualified Curry.Syntax        as CS+import qualified IL                  as IL++import Checks+import CompilerEnv+import CompilerOpts+import CondCompile (condCompile)+import Exports+import Generators+import Html.CurryHtml (source2html)+import Imports+import Interfaces (loadInterfaces)+import TokenStream (showTokenStream)+import Transformations++-- The function 'compileModule' is the main entry-point of this+-- module for compiling a Curry source module. Depending on the command+-- line options, it will emit either FlatCurry code or AbstractCurry code+-- (typed, untyped or with type signatures) for the module.+-- Usually, the first step is to check the module.+-- Then the code is translated into the intermediate+-- language. If necessary, this phase will also update the module's+-- interface file. The resulting code then is written out+-- to the corresponding file.+-- The untyped  AbstractCurry representation is written+-- out directly after parsing and simple checking the source file.+-- The typed AbstractCurry code is written out after checking the module.+--+-- The compiler automatically loads the prelude when compiling any+-- module, except for the prelude itself, by adding an appropriate import+-- declaration to the module.+compileModule :: Options -> ModuleIdent -> FilePath -> CYIO ()+compileModule opts m fn = do+  mdl <- loadAndCheckModule opts m fn+  writeTokens opts (fst mdl)+  writeParsed opts mdl+  writeHtml   opts (qual mdl)+  mdl' <- expandExports opts mdl+  qmdl <- dumpWith opts CS.showModule CS.ppModule DumpQualified $ qual mdl'+  writeAbstractCurry opts qmdl+  -- generate interface file+  let intf = uncurry exportInterface qmdl+  writeInterface opts (fst mdl') intf+  when withFlat $ do+    ((env, il), mdl'') <- transModule opts qmdl+    writeFlat opts env (snd mdl'') il+  where+  withFlat = any (`elem` optTargetTypes opts) [TypedFlatCurry, FlatCurry]++loadAndCheckModule :: Options -> ModuleIdent -> FilePath+                   -> CYIO (CompEnv (CS.Module PredType))+loadAndCheckModule opts m fn = do+  ce <- loadModule opts m fn >>= checkModule opts+  warnMessages $ uncurry (warnCheck opts) ce+  return ce++-- ---------------------------------------------------------------------------+-- Loading a module+-- ---------------------------------------------------------------------------++loadModule :: Options -> ModuleIdent -> FilePath+           -> CYIO (CompEnv (CS.Module ()))+loadModule opts m fn = do+  -- parse and check module header+  (toks, mdl) <- parseModule opts m fn+  -- load the imported interfaces into an InterfaceEnv+  let paths = map (addCurrySubdir (optUseSubdir opts))+                  ("." : optImportPaths opts)+  iEnv   <- loadInterfaces paths mdl+  checkInterfaces opts iEnv+  is     <- importSyntaxCheck iEnv mdl+  -- add information of imported modules+  cEnv   <- importModules mdl iEnv is+  return (cEnv { filePath = fn, tokens = toks }, mdl)++parseModule :: Options -> ModuleIdent -> FilePath+            -> CYIO ([(Span, CS.Token)], CS.Module ())+parseModule opts m fn = do+  mbSrc <- liftIO $ readModule fn+  case mbSrc of+    Nothing  -> failMessages [message $ text $ "Missing file: " ++ fn]+    Just src -> do+      ul      <- liftCYM $ CS.unlit fn src+      prepd   <- preprocess (optPrepOpts opts) fn ul+      condC   <- condCompile (optCppOpts opts) fn prepd+      doDump ((optDebugOpts opts) { dbDumpEnv = False })+             (DumpCondCompiled, undefined, condC)+      -- We ignore the warnings issued by the lexer because+      -- they will be issued a second time during parsing.+      spanToks <- liftCYM $ silent $ CS.lexSource fn condC+      ast      <- liftCYM $ CS.parseModule fn condC+      checked  <- checkModuleHeader opts m fn ast+      return (spanToks, checked)++preprocess :: PrepOpts -> FilePath -> String -> CYIO String+preprocess opts fn src+  | not (ppPreprocess opts) = return src+  | otherwise               = do+    res <- liftIO $ withTempFile $ \ inFn inHdl -> do+      hPutStr inHdl src+      hClose inHdl+      withTempFile $ \ outFn outHdl -> do+        hClose outHdl+        ec <- system $ unwords $+          [ppCmd opts, normalise fn, inFn, outFn] ++ ppOpts opts+        case ec of+          ExitFailure x -> return $ Left [message $ text $+              "Preprocessor exited with exit code " ++ show x]+          ExitSuccess   -> Right `liftM` readFile outFn+    either failMessages ok res++withTempFile :: (FilePath -> Handle -> IO a) -> IO a+withTempFile act = do+  tmp       <- getTemporaryDirectory+  (fn, hdl) <- openTempFile tmp "cymake.curry"+  res       <- act fn hdl+  hClose hdl+  removeFile fn+  return res++checkModuleHeader :: Monad m => Options -> ModuleIdent -> FilePath+                  -> CS.Module () -> CYT m (CS.Module ())+checkModuleHeader opts m fn = checkModuleId m+                            . importPrelude opts+                            . CS.patchModuleId fn++-- |Check whether the 'ModuleIdent' and the 'FilePath' fit together+checkModuleId :: Monad m => ModuleIdent -> CS.Module () -> CYT m (CS.Module ())+checkModuleId mid m@(CS.Module _ mid' _ _ _)+  | mid == mid' = ok m+  | otherwise   = failMessages [errModuleFileMismatch mid']++-- An implicit import of the prelude is added to the declarations of+-- every module, except for the prelude itself, or when the import is disabled+-- by a compiler option. If no explicit import for the prelude is present,+-- the prelude is imported unqualified, otherwise a qualified import is added.++importPrelude :: Options -> CS.Module () -> CS.Module ()+importPrelude opts m@(CS.Module ps mid es is ds)+    -- the Prelude itself+  | mid == preludeMIdent          = m+    -- disabled by compiler option+  | noImpPrelude                  = m+    -- already imported+  | preludeMIdent `elem` imported = m+    -- let's add it!+  | otherwise                     = CS.Module ps mid es (preludeImp : is) ds+  where+  noImpPrelude = NoImplicitPrelude `elem` optExtensions opts+                 || m `CS.hasLanguageExtension` NoImplicitPrelude+  preludeImp   = CS.ImportDecl NoPos preludeMIdent+                  False   -- qualified?+                  Nothing -- no alias+                  Nothing -- no selection of types, functions, etc.+  imported     = [imp | (CS.ImportDecl _ imp _ _ _) <- is]++checkInterfaces :: Monad m => Options -> InterfaceEnv -> CYT m ()+checkInterfaces opts iEnv = mapM_ checkInterface (Map.elems iEnv)+  where+  checkInterface intf = do+    let env = importInterfaces intf iEnv+    interfaceCheck opts (env, intf)++importSyntaxCheck :: Monad m => InterfaceEnv -> CS.Module a -> CYT m [CS.ImportDecl]+importSyntaxCheck iEnv (CS.Module _ _ _ imps _) = mapM checkImportDecl imps+  where+  checkImportDecl (CS.ImportDecl p m q asM is) = case Map.lookup m iEnv of+    Just intf -> CS.ImportDecl p m q asM `liftM` importCheck intf is+    Nothing   -> internalError $ "Modules.importModules: no interface for "+                                    ++ show m++-- ---------------------------------------------------------------------------+-- Checking a module+-- ---------------------------------------------------------------------------++-- TODO: The order of the checks should be improved!+checkModule :: Options -> CompEnv (CS.Module ())+            -> CYIO (CompEnv (CS.Module PredType))+checkModule opts mdl = do+  _   <- dumpCS DumpParsed mdl+  exc <- extensionCheck  opts mdl >>= dumpCS DumpExtensionChecked+  tsc <- typeSyntaxCheck opts exc >>= dumpCS DumpTypeSyntaxChecked+  kc  <- kindCheck       opts tsc >>= dumpCS DumpKindChecked+  sc  <- syntaxCheck     opts kc  >>= dumpCS DumpSyntaxChecked+  pc  <- precCheck       opts sc  >>= dumpCS DumpPrecChecked+  dc  <- deriveCheck     opts pc  >>= dumpCS DumpDeriveChecked+  inc <- instanceCheck   opts dc  >>= dumpCS DumpInstanceChecked+  tc  <- typeCheck       opts inc >>= dumpCS DumpTypeChecked+  ec  <- exportCheck     opts tc  >>= dumpCS DumpExportChecked+  return ec+  where+  dumpCS :: (MonadIO m, Show a) => DumpLevel -> CompEnv (CS.Module a)+         -> m (CompEnv (CS.Module a))+  dumpCS = dumpWith opts CS.showModule CS.ppModule++-- ---------------------------------------------------------------------------+-- Translating a module+-- ---------------------------------------------------------------------------++transModule :: Options -> CompEnv (CS.Module PredType)+            -> CYIO (CompEnv IL.Module, CompEnv (CS.Module Type))+transModule opts mdl = do+  derived    <- dumpCS DumpDerived       $ derive         mdl+  desugared  <- dumpCS DumpDesugared     $ desugar        derived+  dicts      <- dumpCS DumpDictionaries  $ insertDicts    desugared+  newtypes   <- dumpCS DumpNewtypes      $ removeNewtypes dicts+  simplified <- dumpCS DumpSimplified    $ simplify       newtypes+  lifted     <- dumpCS DumpLifted        $ lift           simplified+  il         <- dumpIL DumpTranslated    $ ilTrans        lifted+  ilCaseComp <- dumpIL DumpCaseCompleted $ completeCase   il+  return (ilCaseComp, newtypes)+  where+  dumpCS :: Show a => DumpLevel -> CompEnv (CS.Module a)+         -> CYIO (CompEnv (CS.Module a))+  dumpCS = dumpWith opts CS.showModule CS.ppModule+  dumpIL = dumpWith opts IL.showModule IL.ppModule++-- ---------------------------------------------------------------------------+-- Writing output+-- ---------------------------------------------------------------------------++-- The functions \texttt{genFlat} and \texttt{genAbstract} generate+-- flat and abstract curry representations depending on the specified option.+-- If the interface of a modified Curry module did not change, the+-- corresponding file name will be returned within the result of 'genFlat'+-- (depending on the compiler flag "force") and other modules importing this+-- module won't be dependent on it any longer.++writeTokens :: Options -> CompilerEnv -> CYIO ()+writeTokens opts env = when tokTarget $ liftIO $+  writeModule (useSubDir $ tokensName (filePath env))+              (showTokenStream (tokens env))+  where+  tokTarget  = Tokens `elem` optTargetTypes opts+  useSubDir  = addCurrySubdirModule (optUseSubdir opts) (moduleIdent env)++-- |Output the parsed 'Module' on request+writeParsed :: Show a => Options -> CompEnv (CS.Module a) -> CYIO ()+writeParsed opts (env, mdl) = when srcTarget $ liftIO $+  writeModule (useSubDir $ sourceRepName (filePath env)) (CS.showModule mdl)+  where+  srcTarget  = Parsed `elem` optTargetTypes opts+  useSubDir  = addCurrySubdirModule (optUseSubdir opts) (moduleIdent env)++writeHtml :: Options -> CompEnv (CS.Module a) -> CYIO ()+writeHtml opts (env, mdl) = when htmlTarget $+  source2html opts (moduleIdent env) (map (\(sp, tok) -> (span2Pos sp, tok)) (tokens env)) mdl+  where htmlTarget = Html `elem` optTargetTypes opts++writeInterface :: Options -> CompilerEnv -> CS.Interface -> CYIO ()+writeInterface opts env intf@(CS.Interface m _ _)+  | optForce opts = outputInterface+  | otherwise     = do+      equal <- liftIO $ C.catch (matchInterface interfaceFile intf)+                        ignoreIOException+      unless equal outputInterface+  where+  ignoreIOException :: C.IOException -> IO Bool+  ignoreIOException _ = return False++  interfaceFile   = interfName (filePath env)+  outputInterface = liftIO $ writeModule+                    (addCurrySubdirModule (optUseSubdir opts) m interfaceFile)+                    (show $ CS.ppInterface intf)++matchInterface :: FilePath -> CS.Interface -> IO Bool+matchInterface ifn i = do+  hdl <- openFile ifn ReadMode+  src <- hGetContents hdl+  case runCYMIgnWarn (CS.parseInterface ifn src) of+    Left  _  -> hClose hdl >> return False+    Right i' -> return (i `intfEquiv` fixInterface i')++writeFlat :: Options -> CompilerEnv -> CS.Module Type -> IL.Module -> CYIO ()+writeFlat opts env mdl il = do+  (_, tfc) <- dumpWith opts show (FC.ppProg . genFlatCurry) DumpTypedFlatCurry (env, tfcyProg)+  when tfcyTarget $ liftIO $ FC.writeFlatCurry (useSubDir tfcyName) tfc+  when fcyTarget $ do+    (_, fc) <- dumpWith opts show FC.ppProg DumpFlatCurry (env, fcyProg)+    liftIO $ FC.writeFlatCurry (useSubDir fcyName) fc+  writeFlatIntf opts env fcyProg+  where+  tfcyName   = typedFlatName (filePath env)+  tfcyProg   = genTypedFlatCurry env mdl il+  tfcyTarget = TypedFlatCurry `elem` optTargetTypes opts+  fcyName    = flatName (filePath env)+  fcyProg    = genFlatCurry tfcyProg+  fcyTarget  = FlatCurry `elem` optTargetTypes opts+  useSubDir  = addCurrySubdirModule (optUseSubdir opts) (moduleIdent env)++writeFlatIntf :: Options -> CompilerEnv -> FC.Prog -> CYIO ()+writeFlatIntf opts env prog+  | not (optInterface opts) = return ()+  | optForce opts           = outputInterface+  | otherwise               = do+      mfint <- liftIO $ FC.readFlatInterface targetFile+      let oldInterface = fromMaybe emptyIntf mfint+      when (mfint == mfint) $ return () -- necessary to close file -- TODO+      unless (oldInterface `eqInterface` fint) $ outputInterface+  where+  targetFile      = flatIntName (filePath env)+  emptyIntf       = FC.Prog "" [] [] [] []+  fint            = genFlatInterface prog+  useSubDir       = addCurrySubdirModule (optUseSubdir opts) (moduleIdent env)+  outputInterface = liftIO $ FC.writeFlatCurry (useSubDir targetFile) fint++writeAbstractCurry :: Options -> CompEnv (CS.Module PredType) -> CYIO ()+writeAbstractCurry opts (env, mdl) = do+  when acyTarget  $ liftIO+                  $ AC.writeCurry (useSubDir $ acyName (filePath env))+                  $ genTypedAbstractCurry env mdl+  when uacyTarget $ liftIO+                  $ AC.writeCurry (useSubDir $ uacyName (filePath env))+                  $ genUntypedAbstractCurry env mdl+  where+  acyTarget  = AbstractCurry        `elem` optTargetTypes opts+  uacyTarget = UntypedAbstractCurry `elem` optTargetTypes opts+  useSubDir  = addCurrySubdirModule (optUseSubdir opts) (moduleIdent env)++type Dump = (DumpLevel, CompilerEnv, String)++dumpWith :: MonadIO m+         => Options -> (a -> String) -> (a -> Doc) -> DumpLevel+         -> CompEnv a -> m (CompEnv a)+dumpWith opts rawView view lvl res@(env, mdl) = do+  let str = if dbDumpRaw (optDebugOpts opts) then rawView mdl+                                             else show (view mdl)+  doDump (optDebugOpts opts) (lvl, env, str)+  return res++-- |Translate FlatCurry into the intermediate language 'IL'+-- |The 'dump' function writes the selected information to standard output.+doDump :: MonadIO m => DebugOpts -> Dump -> m ()+doDump opts (level, env, dump)+  = when (level `elem` dbDumpLevels opts) $ liftIO $ do+      putStrLn (heading (capitalize $ lookupHeader dumpLevel) '=')+      when (dbDumpEnv opts) $ do+        putStrLn (heading "Environment" '-')+        putStrLn (showCompilerEnv env (dbDumpAllBindings opts) (dbDumpSimple opts))+      putStrLn (heading "Source Code" '-')+      putStrLn dump+  where+  heading h s = '\n' : h ++ '\n' : replicate (length h) s+  lookupHeader []            = "Unknown dump level " ++ show level+  lookupHeader ((l,_,h):lhs)+    | level == l = h+    | otherwise  = lookupHeader lhs+  capitalize = unwords . map firstUpper . words+  firstUpper ""     = ""+  firstUpper (c:cs) = toUpper c : cs++errModuleFileMismatch :: ModuleIdent -> Message+errModuleFileMismatch mid = posMessage mid $ hsep $ map text+  [ "Module", moduleName mid, "must be in a file"+  , moduleName mid ++ ".(l)curry" ]
− src/Modules.lhs
@@ -1,700 +0,0 @@--% $Id: Modules.lhs,v 1.84 2004/02/10 17:46:07 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-% March 2007, extensions by Sebastian Fischer (sebf@informatik.uni-kiel.de)-%-\nwfilename{Modules.lhs}-\section{Modules}-This module controls the compilation of modules.--Since this version is only used as a frontend for PAKCS, some of the following -import declarations are commented out-\begin{verbatim}--> module Modules(compileModule,->                importPrelude, patchModuleId,->	         loadInterfaces, transModule,->	         simpleCheckModule, checkModule->	        ) where--> import Text.PrettyPrint.HughesPJ-> import Data.List-> import qualified Data.Map as Map-> import System.IO-> import Data.Maybe-> import Control.Monad--> import Curry.Base.MessageMonad-> import Curry.Base.Position as P-> import Curry.Base.Ident--> import Curry.Files.Filenames-> import Curry.Files.PathUtils--> import Curry.Syntax-> import Curry.Syntax.Utils(isImportDecl)-> import Curry.Syntax.Pretty(ppModule,ppIDecl)-> import Curry.Syntax.ShowModule(showModule)--> import Curry.ExtendedFlat.Type-> import qualified Curry.ExtendedFlat.Type as EF --> import qualified IL.Type as IL-> import IL.CurryToIL(ilTrans)-> import qualified IL.Pretty(ppModule)-> import IL.XML(xmlModule)--> import Base-> import Types-> import KindCheck(kindCheck)-> import SyntaxCheck(syntaxCheck)-> import PrecCheck(precCheck)-> import TypeCheck(typeCheck)-> import WarnCheck(warnCheck)-> import Arity-> import Imports(importInterface,importInterfaceIntf,importUnifyData)-> import Exports(expandInterface,exportInterface)-> import Eval(evalEnv)-> import Qual(qual)-> import Desugar(desugar)-> import Simplify(simplify)-> import Lift(lift)--> import GenFlatCurry (genFlatCurry,genFlatInterface)-> import qualified Curry.AbstractCurry as AC-> import GenAbstractCurry-> import InterfaceCheck-> import CurryEnv--> import CurryCompilerOpts(Options(..),Dump(..))-> import CaseCompletion---> import TypeSubst-> import TopEnv---\end{verbatim}-The function \texttt{compileModule} is the main entry-point of this-module for compiling a Curry source module. Depending on the command-line options it will emit either C code or FlatCurry code (standard -or in XML-representation) or AbtractCurry code (typed, untyped or with type-signatures) for the module. Usually the first step is to-check the module. Then the code is translated into the intermediate-language. If necessary, this phase will also update the module's-interface file. The resulting code then is either written out (in-FlatCurry or XML format) or translated further into C code.-The untyped  AbstractCurry representation is written-out directly after parsing and simple checking the source file. -The typed AbstractCurry code is written out after checking the module.--The compiler automatically loads the prelude when compiling any-module, except for the prelude itself, by adding an appropriate import-declaration to the module. --Since this modified version of the Muenster Curry Compiler is used-as a frontend for PAKCS, all functions for evaluating goals and generating C -code are obsolete and commented out.-\begin{verbatim}--> compileModule :: Options -> FilePath -> IO (Maybe FilePath)-> compileModule opts fn =->   do->     mod <- liftM (importPrelude fn . ok . parseModule likeFlat fn) (readModule fn)->     let m = patchModuleId fn mod->     checkModuleId fn m->     mEnv <- loadInterfaces (importPaths opts) m->     if uacy || src->        then ->          do (tyEnv, tcEnv, aEnv, m', intf, _) <- simpleCheckModule opts mEnv m->             if uacy then genAbstract opts fn tyEnv tcEnv m'->                     else do->                       let outputFile = maybe (sourceRepName fn)->                                              id ->                                              (output opts)->                           outputMod = showModule m'->                       writeModule (writeToSubdir opts) outputFile outputMod->                       return Nothing->        else->          do -- checkModule checks types, and then transModule introduces new->             -- functions (by lambda lifting in 'desugar'). Consequence: The->             -- type of the newly introduced functions are not inferred (hsi)->             (tyEnv, tcEnv, aEnv, m', intf, _) <- checkModule opts mEnv m->             let (il,aEnv',dumps) = transModule fcy False False ->			                         mEnv tyEnv tcEnv aEnv m'->             mapM_ (doDump opts) dumps->	      genCode opts fn mEnv tyEnv tcEnv aEnv' intf m' il->   where acy      = abstract opts->         uacy     = untypedAbstract opts->         fcy      = flat opts->         xml      = flatXml opts->         src      = parseOnly opts->         likeFlat = fcy || xml || acy || uacy || src->	  ->         genCode opts fn mEnv tyEnv tcEnv aEnv intf m il->            | fcy || xml = genFlat opts fn mEnv tyEnv tcEnv aEnv intf m il->            | acy        = genAbstract opts fn tyEnv tcEnv m->            | otherwise  = return Nothing--> loadInterfaces :: [FilePath] -> Module -> IO ModuleEnv-> loadInterfaces paths (Module m _ ds) =->   foldM (loadInterface paths [m]) Map.empty->         [(p,m) | ImportDecl p m _ _ _ <- ds]--> checkModuleId :: Monad m => FilePath -> Module -> m ()-> checkModuleId fn (Module mid _ _)->    | last (moduleQualifiers mid) == takeBaseName fn->      = return ()->    | otherwise->      = error ("module \"" ++ moduleName mid ->	        ++ "\" must be in a file \"" ++ moduleName mid->	        ++ ".curry\"")--> simpleCheckModule :: Options -> ModuleEnv -> Module ->	    -> IO (ValueEnv,TCEnv,ArityEnv,Module,Interface,[WarnMsg])-> simpleCheckModule opts mEnv (Module m es ds) =->   do unless (noWarn opts) (printMessages msgs)->      return (tyEnv'', tcEnv, aEnv'', modul, intf, msgs)->   where (impDs,topDs) = partition isImportDecl ds->         iEnv = foldr bindAlias initIEnv impDs->         (pEnv,tcEnv,tyEnv,aEnv) = importModules mEnv impDs->         msgs = warnCheck m tyEnv impDs topDs->	  withExt = withExtensions opts->         (pEnv',topDs') = precCheck m pEnv ->		           $ syntaxCheck withExt m iEnv aEnv tyEnv tcEnv->			   $ kindCheck m tcEnv topDs->         ds' = impDs ++ qual m tyEnv topDs'->         modul = (Module m es ds') --expandInterface (Module m es ds') tcEnv tyEnv->         (_,tcEnv'',tyEnv'',aEnv'') ->            = qualifyEnv mEnv pEnv' tcEnv tyEnv aEnv->         intf = exportInterface modul pEnv' tcEnv'' tyEnv''--> checkModule :: Options -> ModuleEnv -> Module ->      -> IO (ValueEnv,TCEnv,ArityEnv,Module,Interface,[WarnMsg])-> checkModule opts mEnv (Module m es ds) =->   do unless (noWarn opts) (printMessages msgs)->      when (m == mkMIdent ["field114..."])->           (error (show es))->      return (tyEnv''', tcEnv', aEnv'', modul, intf, msgs)->   where (impDs,topDs) = partition isImportDecl ds->         iEnv = foldr bindAlias initIEnv impDs->         (pEnv,tcEnvI,tyEnvI,aEnv) = importModules mEnv impDs->         tcEnv = if withExtensions opts->	             then fmap (expandRecordTC tcEnvI) tcEnvI->		     else tcEnvI->         lEnv = importLabels mEnv impDs->	  tyEnvL = addImportedLabels m lEnv tyEnvI->	  tyEnv = if withExtensions opts->	             then fmap (expandRecordTypes tcEnv) tyEnvL->		     else tyEnvI->         msgs = warnCheck m tyEnv impDs topDs->	  withExt = withExtensions opts->         -- fre: replaced the argument aEnv by aEnv'' in the->         --      expression below. This fixed a bug that occured->         --      when one imported a module qualified that->         --      exported a function from another module.->         --      However, there is now a cyclic dependecy ->         --      but tests didn't show any problems.->         (pEnv',topDs') = precCheck m pEnv ->		           $ syntaxCheck withExt m iEnv aEnv'' tyEnv tcEnv->			   $ kindCheck m tcEnv topDs->         (tcEnv',tyEnv') = typeCheck m tcEnv tyEnv topDs'->         ds' = impDs ++ qual m tyEnv' topDs'->         modul = expandInterface (Module m es ds') tcEnv' tyEnv'->         (pEnv'',tcEnv'',tyEnv'',aEnv'') ->            = qualifyEnv mEnv pEnv' tcEnv' tyEnv' aEnv->         tyEnvL' = addImportedLabels m lEnv tyEnv''->	  tyEnv''' = if withExtensions opts->	                then fmap (expandRecordTypes tcEnv'') tyEnvL'->		        else tyEnv''->         --tyEnv''' = addImportedLabels m lEnv tyEnv''->         intf = exportInterface modul pEnv'' tcEnv'' tyEnv'''--> transModule :: Bool -> Bool -> Bool -> ModuleEnv -> ValueEnv -> TCEnv->      -> ArityEnv -> Module -> (IL.Module,ArityEnv,[(Dump,Doc)])-> transModule flat debug trusted mEnv tyEnv tcEnv aEnv (Module m es ds) =->     (il',aEnv',dumps)->   where topDs = filter (not . isImportDecl) ds->         evEnv = evalEnv topDs->         (desugared,tyEnv') = desugar tyEnv tcEnv (Module m es topDs)->         (simplified,tyEnv'') = simplify flat tyEnv' evEnv desugared->         (lifted,tyEnv''',evEnv') = lift tyEnv'' evEnv simplified->         aEnv' = bindArities aEnv lifted->         il = ilTrans flat tyEnv''' tcEnv evEnv' lifted->         il' = completeCase mEnv il->         dumps = [(DumpRenamed,ppModule (Module m es ds)),->	           (DumpTypes,ppTypes m (localBindings tyEnv)),->	           (DumpDesugared,ppModule desugared),->                  (DumpSimplified,ppModule simplified),->                  (DumpLifted,ppModule lifted),->                  (DumpIL,IL.Pretty.ppModule il),->	           (DumpCase,IL.Pretty.ppModule il')->	          ]--> qualifyEnv :: ModuleEnv -> PEnv -> TCEnv -> ValueEnv -> ArityEnv->     -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> qualifyEnv mEnv pEnv tcEnv tyEnv aEnv =->   (foldr bindQual pEnv' (localBindings pEnv),->    foldr bindQual tcEnv' (localBindings tcEnv),->    foldr bindGlobal tyEnv' (localBindings tyEnv),->    foldr bindQual aEnv' (localBindings aEnv))->   where (pEnv',tcEnv',tyEnv',aEnv') =->           foldl importInterface initEnvs (Map.toList mEnv)->         importInterface (pEnv,tcEnv,tyEnv,aEnv) (m,ds) =->           importInterfaceIntf (Interface m ds) pEnv tcEnv tyEnv aEnv->         bindQual (_,y) = qualBindTopEnv "Modules.qualifyEnv" (origName y) y->         bindGlobal (x,y)->           | uniqueId x == 0 = bindQual (x,y)->           | otherwise = bindTopEnv "Modules.qualifyEnv" x y--> writeXML :: Bool -> Maybe FilePath -> FilePath -> CurryEnv -> IL.Module -> IO ()-> writeXML sub tfn sfn cEnv il = writeModule sub ofn (showln code)->   where ofn  = fromMaybe (xmlName sfn) tfn->         code = (xmlModule cEnv il)--> writeFlat :: Options -> Maybe FilePath -> FilePath -> CurryEnv -> ModuleEnv ->              -> ValueEnv -> TCEnv -> ArityEnv -> IL.Module -> IO Prog-> writeFlat opts tfn sfn cEnv mEnv tyEnv tcEnv aEnv il->   = writeFlatFile opts (genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv il)->                        (fromMaybe (flatName sfn) tfn)--> writeFlatFile :: Options -> (Prog, [WarnMsg]) -> String -> IO Prog-> writeFlatFile opts@Options{extendedFlat=ext,writeToSubdir=sub} (res,msgs) fname = do->         unless (noWarn opts) (printMessages msgs)->	  if ext then writeExtendedFlat sub fname res->                else writeFlatCurry sub fname res->         return res---> writeTypedAbs :: Bool -> Maybe FilePath -> FilePath -> ValueEnv -> TCEnv -> Module->	           -> IO ()-> writeTypedAbs sub tfn sfn tyEnv tcEnv mod->    = AC.writeCurry sub fname (genTypedAbstract tyEnv tcEnv mod)->  where fname = fromMaybe (acyName sfn) tfn--> writeUntypedAbs :: Bool -> Maybe FilePath -> FilePath -> ValueEnv -> TCEnv  ->	             -> Module -> IO ()-> writeUntypedAbs sub tfn sfn tyEnv tcEnv mod->    = AC.writeCurry sub fname (genUntypedAbstract tyEnv tcEnv mod)->  where fname = fromMaybe (uacyName sfn) tfn--> showln :: Show a => a -> String-> showln x = shows x "\n"--\end{verbatim}--The function \texttt{importModules} brings the declarations of all-imported modules into scope for the current module.-\begin{verbatim}--> importModules :: ModuleEnv -> [Decl] -> (PEnv,TCEnv,ValueEnv,ArityEnv)-> importModules mEnv ds = (pEnv,importUnifyData tcEnv,tyEnv,aEnv)->   where (pEnv,tcEnv,tyEnv,aEnv) = foldl importModule initEnvs ds->         importModule (pEnv,tcEnv,tyEnv,aEnv) (ImportDecl p m q asM is) =->           case Map.lookup m mEnv of->             Just ds -> importInterface p (fromMaybe m asM) q is->                                        (Interface m ds) pEnv tcEnv tyEnv aEnv->             Nothing -> internalError "importModule"->         importModule (pEnv,tcEnv,tyEnv,aEnv) _ = (pEnv,tcEnv,tyEnv,aEnv)--> initEnvs :: (PEnv,TCEnv,ValueEnv,ArityEnv)-> initEnvs = (initPEnv,initTCEnv,initDCEnv,initAEnv)--\end{verbatim}-Unlike unsual identifiers like in functions, types etc. identifiers-of labels are always represented unqualified within the whole context-of compilation. Since the common type environment (type \texttt{ValueEnv})-has some problems with handling imported unqualified identifiers, it is -necessary to add the type information for labels seperately. For this reason-the function \texttt{importLabels} generates an environment containing-all imported labels and the function \texttt{addImportedLabels} adds this-content to a type environment.-\begin{verbatim}--> importLabels :: ModuleEnv -> [Decl] -> LabelEnv-> importLabels mEnv ds = foldl importLabelTypes Map.empty ds->   where->   importLabelTypes lEnv (ImportDecl p m _ asM is) =->     case (Map.lookup m mEnv) of->       Just ds' -> foldl (importLabelType p (fromMaybe m asM) is) lEnv ds'->       Nothing -> internalError "importLabels"->   importLabelTypes lEnv _ = lEnv->		      ->   importLabelType p m is lEnv (ITypeDecl _ r _ (RecordType fs _)) =->     foldl (insertLabelType p m r' (getImportSpec r' is)) lEnv fs->     where r' = qualifyWith m (fromRecordExtId (unqualify r))->   importLabelType _ _ _ lEnv _ = lEnv->			   ->   insertLabelType p m r (Just (ImportTypeAll _)) lEnv ([l],ty) =->     bindLabelType l r (toType [] ty) lEnv->   insertLabelType p m r (Just (ImportTypeWith _ ls)) lEnv ([l],ty)->     | l `elem` ls = bindLabelType l r (toType [] ty) lEnv->     | otherwise   = lEnv->   insertLabelType _ _ _ _ lEnv _ = lEnv->			     ->   getImportSpec r (Just (Importing _ is')) =->     find (isImported (unqualify r)) is'->   getImportSpec r Nothing = Just (ImportTypeAll (unqualify r))->   getImportSpec r _ = Nothing->		->   isImported r (Import r') = r == r'->   isImported r (ImportTypeWith r' _) = r == r'->   isImported r (ImportTypeAll r') = r == r'--> addImportedLabels :: ModuleIdent -> LabelEnv -> ValueEnv -> ValueEnv-> addImportedLabels m lEnv tyEnv = ->   foldr addLabelType tyEnv (concatMap snd (Map.toList lEnv))->   where->   addLabelType (LabelType l r ty) tyEnv = ->     let m' = fromMaybe m (qualidMod r)->     in  importTopEnv m' l ->                      (Label (qualify l) (qualQualify m' r) (polyType ty)) ->	               tyEnv--\end{verbatim}-Fully expand all (imported) record types within the type constructor -environment and the type environment.-Note: the record types for the current module are expanded within the-type check.-\begin{verbatim}--> expandRecordTC :: TCEnv -> TypeInfo -> TypeInfo-> expandRecordTC tcEnv (DataType qid n args) =->   DataType qid n (map (maybe Nothing (Just . (expandData tcEnv))) args)-> expandRecordTC tcEnv (RenamingType qid n (Data id m ty)) =->   RenamingType qid n (Data id m (expandRecords tcEnv ty))-> expandRecordTC tcEnv (AliasType qid n ty) =->   AliasType qid n (expandRecords tcEnv ty)--> expandData :: TCEnv -> Data [Type] -> Data [Type]-> expandData tcEnv (Data id n tys) =->   Data id n (map (expandRecords tcEnv) tys)--> expandRecordTypes :: TCEnv -> ValueInfo -> ValueInfo-> expandRecordTypes tcEnv (DataConstructor qid (ForAllExist n m ty)) =->   DataConstructor qid (ForAllExist n m (expandRecords tcEnv ty))-> expandRecordTypes tcEnv (NewtypeConstructor qid (ForAllExist n m ty)) =->   NewtypeConstructor qid (ForAllExist n m (expandRecords tcEnv ty))-> expandRecordTypes tcEnv (Value qid (ForAll n ty)) =->   Value qid (ForAll n (expandRecords tcEnv ty))-> expandRecordTypes tcEnv (Label qid r (ForAll n ty)) =->   Label qid r (ForAll n (expandRecords tcEnv ty))--> expandRecords :: TCEnv -> Type -> Type-> expandRecords tcEnv (TypeConstructor qid tys) =->   case (qualLookupTC qid tcEnv) of->     [AliasType _ _ rty@(TypeRecord _ _)]->       -> expandRecords tcEnv ->            (expandAliasType (map (expandRecords tcEnv) tys) rty)->     _ -> TypeConstructor qid (map (expandRecords tcEnv) tys)-> expandRecords tcEnv (TypeConstrained tys v) =->   TypeConstrained (map (expandRecords tcEnv) tys) v-> expandRecords tcEnv (TypeArrow ty1 ty2) =->   TypeArrow (expandRecords tcEnv ty1) (expandRecords tcEnv ty2)-> expandRecords tcEnv (TypeRecord fs rv) =->   TypeRecord (map (\ (l,ty) -> (l,expandRecords tcEnv ty)) fs) rv-> expandRecords _ ty = ty--\end{verbatim}-An implicit import of the prelude is added to the declarations of-every module, except for the prelude itself. If no explicit import for-the prelude is present, the prelude is imported unqualified, otherwise-only a qualified import is added.-\begin{verbatim}--> importPrelude :: FilePath -> Module -> Module-> importPrelude fn (Module m es ds) =->   Module m es (if m == preludeMIdent then ds else ds')->   where ids = [decl | decl@(ImportDecl _ _ _ _ _) <- ds]->         ds' = ImportDecl (P.first fn) preludeMIdent->                          (preludeMIdent `elem` map importedModule ids)->                          Nothing Nothing : ds->         importedModule (ImportDecl _ m q asM is) = fromMaybe m asM--\end{verbatim}-If an import declaration for a module is found, the compiler first-checks whether an import for the module is already pending. In this-case the module imports are cyclic which is not allowed in Curry. The-compilation will therefore be aborted. Next, the compiler checks-whether the module has been imported already. If so, nothing needs to-be done, otherwise the interface will be searched in the import paths-and compiled.-\begin{verbatim}--> loadInterface :: [FilePath] -> [ModuleIdent] -> ModuleEnv ->->     (Position,ModuleIdent) -> IO ModuleEnv-> loadInterface paths ctxt mEnv (p,m)->   | m `elem` ctxt = errorAt p (cyclicImport m (takeWhile (/= m) ctxt))->   | isLoaded m mEnv = return mEnv->   | otherwise =->       lookupInterface paths m >>=->       maybe (errorAt p (interfaceNotFound m))->             (compileInterface paths ctxt mEnv m)->   where isLoaded m mEnv = maybe False (const True) (Map.lookup m mEnv)--\end{verbatim}-After reading an interface, all imported interfaces are recursively-loaded and entered into the interface's environment. There is no need-to check FlatCurry-Interfaces, since these files contain automaticaly-generated FlatCurry terms (type \texttt{Prog}).-\begin{verbatim}--> compileInterface :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> ModuleIdent->                  -> FilePath -> IO ModuleEnv-> compileInterface paths ctxt mEnv m fn =->   do->     mintf <- readFlatInterface fn->     let intf = fromMaybe (errorAt (P.first fn) (interfaceNotFound m)) mintf->         (Prog mod _ _ _ _) = intf->         m' = mkMIdent [mod]->     unless (m' == m) (errorAt (P.first fn) (wrongInterface m m'))->     mEnv' <- loadFlatInterfaces paths ctxt mEnv intf->     return (bindFlatInterface intf mEnv')--> --loadIntfInterfaces :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> Interface-> --                   -> IO ModuleEnv-> --loadIntfInterfaces paths ctxt mEnv (Interface m ds) =-> --  foldM (loadInterface paths (m:ctxt)) mEnv [(p,m) | IImportDecl p m <- ds]---> loadFlatInterfaces :: [FilePath] -> [ModuleIdent] -> ModuleEnv -> Prog->                    -> IO ModuleEnv-> loadFlatInterfaces paths ctxt mEnv (Prog m is _ _ _) =->   foldM (loadInterface paths ((mkMIdent [m]):ctxt)) ->         mEnv ->         (map (\i -> (p, mkMIdent [i])) is)->  where p = P.first m---Interface files are updated by the Curry builder when necessary.-(see module \texttt{CurryBuilder}).--\end{verbatim}-The \texttt{doDump} function writes the selected information to the-standard output.-\begin{verbatim}--> doDump :: Options -> (Dump,Doc) -> IO ()-> doDump opts (d,x) =->   when (d `elem` dump opts)->        (print (text hd $$ text (replicate (length hd) '=') $$ x))->   where hd = dumpHeader d--> dumpHeader :: Dump -> String-> dumpHeader DumpRenamed = "Module after renaming"-> dumpHeader DumpTypes = "Types"-> dumpHeader DumpDesugared = "Source code after desugaring"-> dumpHeader DumpSimplified = "Source code after simplification"-> dumpHeader DumpLifted = "Source code after lifting"-> dumpHeader DumpIL = "Intermediate code"-> dumpHeader DumpCase = "Intermediate code after case simplification"---\end{verbatim}-The functions \texttt{genFlat} and \texttt{genAbstract} generate-flat and abstract curry representations depending on the specified option.-If the interface of a modified Curry module did not change, the corresponding -file name will be returned within the result of \texttt{genFlat} (depending-on the compiler flag "force") and other modules importing this module won't-be dependent on it any longer.-\begin{verbatim}--> genFlat :: Options -> FilePath -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv ->            -> Interface -> Module -> IL.Module -> IO (Maybe FilePath)-> genFlat opts fname mEnv tyEnv tcEnv aEnv intf mod il->   | flat opts->     = do writeFlat opts Nothing fname cEnv mEnv tyEnv tcEnv aEnv il->          let (flatInterface,intMsgs) = genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv il->          if force opts->            then ->              do writeInterface flatInterface intMsgs->                 return Nothing->            else ->               do mfint <- readFlatInterface fintName->                  let flatIntf = fromMaybe emptyIntf mfint->                  if mfint == mfint  -- necessary to close the file 'fintName'->                        && not (interfaceCheck flatIntf flatInterface)->                     then ->                        do writeInterface flatInterface intMsgs->                           return Nothing->                     else return Nothing->   | flatXml opts->     = writeXML (writeToSubdir opts) (output opts) fname cEnv il >> ->       return Nothing->   | otherwise->     = internalError "@Modules.genFlat: illegal option"->  where->    fintName = flatIntName fname->    cEnv = curryEnv mEnv tcEnv intf mod->    emptyIntf = Prog "" [] [] [] []->    writeInterface intf msgs = do->          unless (noWarn opts) (printMessages msgs)->          writeFlatCurry (writeToSubdir opts) fintName intf---> genAbstract :: Options -> FilePath  -> ValueEnv -> TCEnv -> Module ->                -> IO (Maybe FilePath)-> genAbstract opts@Options{writeToSubdir=sub} fname tyEnv tcEnv mod->    | abstract opts->      = do writeTypedAbs sub Nothing fname tyEnv tcEnv mod ->           return Nothing->    | untypedAbstract opts->      = do writeUntypedAbs sub Nothing fname tyEnv tcEnv mod->           return Nothing->    | otherwise->      = internalError "@Modules.genAbstract: illegal option"--> printMessages :: [WarnMsg] -> IO ()-> printMessages []   = return ()-> printMessages msgs = hPutStrLn stderr $ unlines $ map showWarning msgs--\end{verbatim}-The function \texttt{ppTypes} is used for pretty-printing the types-from the type environment.-\begin{verbatim}--> ppTypes :: ModuleIdent -> [(Ident,ValueInfo)] -> Doc-> ppTypes m = vcat . map (ppIDecl . mkDecl) . filter (isValue . snd)->   where mkDecl (v,Value _ (ForAll _ ty)) =->           IFunctionDecl undefined (qualify v) (arrowArity ty) ->		      (fromQualType m ty)->         isValue (DataConstructor _ _) = False->         isValue (NewtypeConstructor _ _) = False->         isValue (Value _ _) = True->         isValue (Label _ _ _) = False---\end{verbatim}-A module which doesn't contain a \texttt{module ... where} declaration-obtains its filename as module identifier (unlike the definition in-Haskell and original MCC where a module obtains \texttt{main}).-\begin{verbatim}--> patchModuleId :: FilePath -> Module -> Module-> patchModuleId fn (Module mid mexports decls)->    | (moduleName mid) == "main"->      = Module (mkMIdent [takeBaseName fn]) mexports decls->    | otherwise->      = Module mid mexports decls---\end{verbatim}-Error functions.-\begin{verbatim}--> interfaceNotFound :: ModuleIdent -> String-> interfaceNotFound m = "Interface for module " ++ moduleName m ++ " not found"--> cyclicImport :: ModuleIdent -> [ModuleIdent] -> String-> cyclicImport m [] = "Recursive import for module " ++ moduleName m-> cyclicImport m ms =->   "Cyclic import dependency between modules " ++ moduleName m ++->     modules "" ms->   where modules comma [m] = comma ++ " and " ++ moduleName m->         modules _ (m:ms) = ", " ++ moduleName m ++ modules "," ms--> wrongInterface :: ModuleIdent -> ModuleIdent -> String-> wrongInterface m m' =->   "Expected interface for " ++ show m ++ " but found " ++ show m'--\end{verbatim}-----> bindFlatInterface :: Prog -> ModuleEnv -> ModuleEnv-> bindFlatInterface (Prog m imps ts fs os)->    = Map.insert (mkMIdent [m])->      ((map genIImportDecl imps)->       ++ (map genITypeDecl ts')->       ++ (map genIFuncDecl fs)->       ++ (map genIOpDecl os))->  where->  genIImportDecl :: String -> IDecl->  genIImportDecl imp = IImportDecl pos (mkMIdent [imp])->->  genITypeDecl :: TypeDecl -> IDecl->  genITypeDecl (Type qn _ is cs)->     | recordExt `isPrefixOf` localName qn->       = ITypeDecl pos->                   (genQualIdent qn)->	            (map (genVarIndexIdent "a") is)->	            (RecordType (map genLabeledType cs) Nothing)->     | otherwise->       = IDataDecl pos ->                   (genQualIdent qn) ->                   (map (genVarIndexIdent "a") is) ->                   (map (Just . genConstrDecl) cs)->  genITypeDecl (TypeSyn qn _ is t)->     = ITypeDecl pos->                 (genQualIdent qn)->                 (map (genVarIndexIdent "a") is)->                 (genTypeExpr t)->->  genIFuncDecl :: FuncDecl -> IDecl->  genIFuncDecl (Func qn a _ t _) ->     = IFunctionDecl pos (genQualIdent qn) a (genTypeExpr t)->->  genIOpDecl :: OpDecl -> IDecl->  genIOpDecl (Op qn f p) = IInfixDecl pos (genInfix f) p  (genQualIdent qn)->->  genConstrDecl :: ConsDecl -> ConstrDecl->  genConstrDecl (Cons qn _ _ ts)->     = ConstrDecl pos [] (mkIdent (localName qn)) (map genTypeExpr ts)->->  genLabeledType :: EF.ConsDecl -> ([Ident],Curry.Syntax.TypeExpr)->  genLabeledType (Cons qn _ _ [t])->     = ([renameLabel (fromLabelExtId (mkIdent $ localName qn))], genTypeExpr t)->->  genTypeExpr :: EF.TypeExpr -> Curry.Syntax.TypeExpr->  genTypeExpr (TVar i)->     = VariableType (genVarIndexIdent "a" i)->  genTypeExpr (FuncType t1 t2) ->     = ArrowType (genTypeExpr t1) (genTypeExpr t2)->  genTypeExpr (TCons qn ts) ->     = ConstructorType (genQualIdent qn) (map genTypeExpr ts)->->  genInfix :: EF.Fixity -> Infix->  genInfix EF.InfixOp  = Infix->  genInfix EF.InfixlOp = InfixL->  genInfix EF.InfixrOp = InfixR->->  genQualIdent :: EF.QName -> QualIdent->  genQualIdent EF.QName{modName=mod,localName=name} = ->    qualifyWith (mkMIdent [mod]) (mkIdent name)->->  genVarIndexIdent :: String -> Int -> Ident->  genVarIndexIdent v i = mkIdent (v ++ show i)->->  isSpecialPreludeType :: TypeDecl -> Bool->  isSpecialPreludeType (Type EF.QName{modName=mod,localName=name} _ _ _) ->     = (name == "[]" || name == "()") && mod == "Prelude"->  isSpecialPreludeType _ = False->->  pos = P.first m->  ts' = filter (not . isSpecialPreludeType) ts-----\end{verbatim}-The label environment is used to store information of labels.-Unlike unsual identifiers like in functions, types etc. identifiers-of labels are always represented unqualified. Since the common type -environment (type \texttt{ValueEnv}) has some problems with handling -imported unqualified identifiers, it is necessary to process the type -information for labels seperately.-\begin{verbatim}--> data LabelInfo = LabelType Ident QualIdent Type deriving Show--> type LabelEnv = Map.Map Ident [LabelInfo]--> bindLabelType :: Ident -> QualIdent -> Type -> LabelEnv -> LabelEnv-> bindLabelType l r ty = Map.insertWith (++) l [LabelType l r ty]-
− src/NestEnv.lhs
@@ -1,77 +0,0 @@--% $Id: NestEnv.lhs,v 1.11 2003/10/04 17:04:23 wlux Exp $-%-% Copyright (c) 1999-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{NestEnv.lhs}-\subsection{Nested Environments}-The \texttt{NestEnv} environment type extends top-level environments-(see section~\ref{sec:toplevel-env}) to manage nested scopes. Local-scopes allow only for a single, unambiguous definition.--As a matter of convenience, the module \texttt{TopEnv} is exported by-the module \texttt{NestEnv}.  Thus, only the latter needs to be-imported.-\begin{verbatim}--> module NestEnv(module TopEnv, NestEnv, bindNestEnv,qualBindNestEnv,->                lookupNestEnv,qualLookupNestEnv,->                toplevelEnv,globalEnv,nestEnv) where--> import qualified Data.Map as Map--> import Curry.Base.Ident--> import TopEnv---> data NestEnv a = GlobalEnv (TopEnv a) | LocalEnv (NestEnv a) (Map.Map Ident a)-> --                 deriving Show--> instance Functor NestEnv where->   fmap f (GlobalEnv env) = GlobalEnv (fmap f env)->   fmap f (LocalEnv genv env) = LocalEnv (fmap f genv) (fmap f env)--> bindNestEnv :: Ident -> a -> NestEnv a -> NestEnv a-> bindNestEnv x y (GlobalEnv env) ->   = GlobalEnv (bindTopEnv "NestEnv.bindNestEnv" x y env)-> bindNestEnv x y (LocalEnv genv env) =->   case Map.lookup x env of->     Just _ -> error "internal error: bindNestEnv"->     Nothing -> LocalEnv genv (Map.insert x y env)--> qualBindNestEnv :: QualIdent -> a -> NestEnv a -> NestEnv a-> qualBindNestEnv x y (GlobalEnv env) ->   = GlobalEnv (qualBindTopEnv "NestEnv.qualBindNestEnv" x y env)-> qualBindNestEnv x y (LocalEnv genv env)->   | isQualified x = error "internal error: qualBindNestEnv"->   | otherwise =->       case Map.lookup x' env of->         Just _ -> error "internal error: qualBindNestEnv"->         Nothing -> LocalEnv genv (Map.insert x' y env)->   where x' = unqualify x--> lookupNestEnv :: Ident -> NestEnv a -> [a]-> lookupNestEnv x (GlobalEnv env) = lookupTopEnv x env-> lookupNestEnv x (LocalEnv genv env) =->   case Map.lookup x env of->     Just y -> [y]->     Nothing -> lookupNestEnv x genv--> qualLookupNestEnv :: QualIdent -> NestEnv a -> [a]-> qualLookupNestEnv x env->   | isQualified x = qualLookupTopEnv x (toplevelEnv env)->   | otherwise = lookupNestEnv (unqualify x) env--> toplevelEnv :: NestEnv a -> TopEnv a-> toplevelEnv (GlobalEnv env) = env-> toplevelEnv (LocalEnv genv _) = toplevelEnv genv--> globalEnv :: TopEnv a -> NestEnv a-> globalEnv = GlobalEnv--> nestEnv :: NestEnv a -> NestEnv a-> nestEnv env = LocalEnv env Map.empty--\end{verbatim}
− src/OldScopeEnv.hs
@@ -1,165 +0,0 @@-module OldScopeEnv (ScopeEnv,-		    newScopeEnv,-		    insertIdent, getIdentLevel,-		    isVisible, isDeclared,-		    beginScope, endScope,-		    getLevel,-		    genIdent, genIdentList) where--import Data.Maybe-import qualified Data.Map as Map--import Curry.Base.Ident-------------------------------------------------------------------------------------- Type for representing an environment containing identifiers in several--- scope levels-type ScopeEnv = (IdEnv, [IdEnv], Int)------------------------------------------------------------------------------------- Generates a new instance of a scope table-newScopeEnv :: ScopeEnv-newScopeEnv = (Map.empty, [], 0)----- Inserts an identifier into the current level of the scope environment-insertIdent :: Ident -> ScopeEnv -> ScopeEnv-insertIdent ident (topleveltab, leveltabs, level)-   = case leveltabs of-       (lt:lts) -> (topleveltab, (insertId level ident lt):lts, level)-       []       -> ((insertId level ident topleveltab), [], 0)----- Returns the declaration level of an identifier if it exists-getIdentLevel :: Ident -> ScopeEnv -> Maybe Int-getIdentLevel ident (topleveltab, leveltabs, _)-   = case leveltabs of-       (lt:_) -> maybe (getIdLevel ident topleveltab) Just (getIdLevel ident lt)-       []     -> getIdLevel ident topleveltab----- Checks whether the specified identifier is visible in the current scope--- (i.e. checks whether the identifier occurs in the scope environment)-isVisible :: Ident -> ScopeEnv -> Bool-isVisible ident (topleveltab, leveltabs, _)-   = case leveltabs of-       (lt:_) -> idExists ident lt || idExists ident topleveltab-       []     -> idExists ident topleveltab----- Checks whether the specified identifier is declared in the--- current scope (i.e. checks whether the identifier occurs in the--- current level of the scope environment)-isDeclared :: Ident -> ScopeEnv -> Bool-isDeclared ident (topleveltab, leveltabs, level)-   = case leveltabs of-       (lt:_) -> maybe False ((==) level) (getIdLevel ident lt)-       []     -> maybe False ((==) 0) (getIdLevel ident topleveltab)----- Increases the level of the scope.-beginScope :: ScopeEnv -> ScopeEnv-beginScope (topleveltab, leveltabs, level)-   = case leveltabs of-       (lt:lts) -> (topleveltab, (lt:lt:lts), level + 1)-       []       -> (topleveltab, [Map.empty], 1)----- Decreases the level of the scope. Identifier from higher levels--- will be lost.-endScope :: ScopeEnv -> ScopeEnv-endScope (topleveltab, leveltabs, level)-   = case leveltabs of-       (_:lts) -> (topleveltab, lts, level - 1)-       []      -> (topleveltab, [], 0)----- Returns the level of the current scope. Top level is 0-getLevel :: ScopeEnv -> Int-getLevel (_, _, level) = level----- Generates a new identifier for the specified name. The new identifier is --- unique within the current scope. If no identifier can be generated for --- 'name' then 'Nothing' will be returned-genIdent :: String -> ScopeEnv -> Maybe Ident-genIdent name (topleveltab, leveltabs, _)-   = case leveltabs of-       (lt:_) -> genId name lt-       []     -> genId name topleveltab----- Generates a list of new identifiers where each identifier has--- the prefix 'name' followed by  an index (i.e. "var3" if 'name' was "var").--- All returned identifiers are unique within the current scope.-genIdentList :: Int -> String -> ScopeEnv -> [Ident]-genIdentList size name scopeenv = p_genIdentList size name scopeenv 0- where-   p_genIdentList s n env i-      | s == 0 -	= []-      | otherwise-	= maybe (p_genIdentList s n env (i + 1))-	        (\ident -> ident:(p_genIdentList (s - 1) -				                 n -				                 (insertIdent ident env) -				                 (i + 1)))-		(genIdent (n ++ (show i)) env)---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Private declarations...--type IdEnv = Map.Map IdRep Int--data IdRep = Name String | Index Int deriving (Eq, Ord)----------------------------------------------------------------------------------------insertId :: Int -> Ident -> IdEnv -> IdEnv-insertId level ident env-   = Map.insert (Name (name ident)) -             level -	     (Map.insert (Index (uniqueId ident)) level env)------idExists :: Ident -> IdEnv -> Bool-idExists ident env = indexExists (uniqueId ident) env------getIdLevel :: Ident -> IdEnv -> Maybe Int-getIdLevel ident env = Map.lookup (Index (uniqueId ident)) env------genId n env-   | nameExists n env = Nothing-   | otherwise        = Just (p_genId (mkIdent n) 0)- where-   p_genId ident index-      | indexExists index env = p_genId ident (index + 1)-      | otherwise             = renameIdent ident index------nameExists :: String -> IdEnv -> Bool-nameExists name env = isJust (Map.lookup (Name name) env)------indexExists :: Int -> IdEnv -> Bool-indexExists index env = isJust (Map.lookup (Index index) env)------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/PatchPrelude.hs
@@ -1,40 +0,0 @@-module PatchPrelude where---import Curry.ExtendedFlat.Type----- the prelude has to be extended by data declarations for list and tuples--prelude = "Prelude"--patchPreludeFCY :: Prog -> Prog-patchPreludeFCY (Prog name imports types funcs ops)-   | name == prelude-     = Prog name [] (prelude_types_fcy ++ types) funcs ops-   | otherwise-     = Prog name imports types funcs ops--prelude_types_fcy :: [TypeDecl]-prelude_types_fcy =-  let unit = mkQName (prelude,"()")-      nil  = mkQName (prelude,"[]") in-  [Type unit Public [] [(Cons unit 0 Public [])],-   Type nil Public [0] -        [Cons nil 0 Public [],-         Cons (mkQName (prelude,":")) 2 Public -              [TVar 0, TCons nil [TVar 0]]]] ++-  map tupleType [2..maxTupleArity]--tupleType ar = -  let tuplecons = mkQName (prelude,"("++take (ar-1) (repeat ',')++")") in-  Type tuplecons Public [0..ar-1]-       [Cons tuplecons ar Public (map TVar [0..ar-1])]---- Maximal arity of tuples:-maxTupleArity = 15-------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/PrecCheck.lhs
@@ -1,461 +0,0 @@--% $Id: PrecCheck.lhs,v 1.21 2004/02/15 22:10:34 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{PrecCheck.lhs}-\section{Checking Precedences of Infix Operators}-The parser does not know the relative precedences of infix operators-and therefore parses them as if they all associate to the right and-have the same precedence. After performing the definition checks,-the compiler is going to process the infix applications in the module-and rearrange infix applications according to the relative precedences-of the operators involved.-\begin{verbatim}--> module PrecCheck(precCheck) where--> import Data.List--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Base--\end{verbatim}-For each declaration group, including the module-level, the compiler-first checks that its fixity declarations contain no duplicates and-that there is a corresponding value or constructor declaration in that-group. The fixity declarations are then used for extending the-imported precedence environment.-\begin{verbatim}--> bindPrecs :: ModuleIdent -> [Decl] -> PEnv -> PEnv-> bindPrecs m ds pEnv =->   case findDouble ops of->     Nothing ->->       case [ op | op <- ops, op `notElem` bvs] of->         [] -> foldr bindPrec pEnv fixDs->         op : _ -> errorAt' (undefinedOperator op)->     Just op -> errorAt' (duplicatePrecedence op)->   where (fixDs,nonFixDs) = partition isInfixDecl ds->         bvs = concatMap boundValues nonFixDs->         ops = [ op | InfixDecl p _ _ ops <- fixDs, op <- ops]->         bindPrec (InfixDecl _ fix pr ops) pEnv->           | p == defaultP = pEnv->           | otherwise = foldr (flip (bindP m) p) pEnv ops->           where p = OpPrec fix pr--> boundValues :: Decl -> [Ident]-> boundValues (DataDecl _ _ _ cs) = map constr cs->   where constr (ConstrDecl _ _ c _) = c->         constr (ConOpDecl _ _ _ op _) = op-> boundValues (NewtypeDecl _ _ _ (NewConstrDecl _ _ c _)) = [c]-> boundValues (FunctionDecl _ f _) = [f]-> boundValues (ExternalDecl _ _ _ f _) = [f]-> boundValues (FlatExternalDecl _ fs) = fs-> boundValues (PatternDecl _ t _) = bv t-> boundValues (ExtraVariables _ vs) = vs-> boundValues _ = []--\end{verbatim}-With the help of the precedence environment, the compiler checks all-infix applications and sections in the program. This pass will modify-the parse tree such that for a nested infix application the operator-with the lowest precedence becomes the root and that two adjacent-operators with the same precedence will not have conflicting-associativities. Note that the top-level precedence environment has to-be returned because it is needed for constructing the module's-interface.-\begin{verbatim}--> precCheck :: ModuleIdent -> PEnv -> [Decl] -> (PEnv,[Decl])-> precCheck = checkDecls--> checkDecls :: ModuleIdent -> PEnv -> [Decl] -> (PEnv,[Decl])-> checkDecls m pEnv ds = pEnv' `seq` (pEnv',ds')->   where pEnv' = bindPrecs m ds pEnv->         ds' = map (checkDecl m pEnv') ds--> checkDecl :: ModuleIdent -> PEnv -> Decl -> Decl-> checkDecl m pEnv (FunctionDecl p f eqs) =->   FunctionDecl p f (map (checkEqn m pEnv) eqs)-> checkDecl m pEnv (PatternDecl p t rhs) =->   PatternDecl p (checkConstrTerm pEnv t) (checkRhs m pEnv rhs)-> checkDecl _ _ d = d--> checkEqn :: ModuleIdent -> PEnv -> Equation -> Equation-> checkEqn m pEnv (Equation p lhs rhs) =->   Equation p (checkLhs pEnv lhs) (checkRhs m pEnv rhs)--> checkLhs :: PEnv -> Lhs -> Lhs-> checkLhs pEnv (FunLhs f ts) = FunLhs f (map (checkConstrTerm pEnv) ts)-> checkLhs pEnv (OpLhs t1 op t2) = t1' `seq` t2' `seq` OpLhs t1' op t2'->   where t1' = checkOpL pEnv op (checkConstrTerm pEnv t1)->         t2' = checkOpR pEnv op (checkConstrTerm pEnv t2)-> checkLhs pEnv (ApLhs lhs ts) =->   ApLhs (checkLhs pEnv lhs) (map (checkConstrTerm pEnv) ts)--> checkConstrTerm :: PEnv -> ConstrTerm -> ConstrTerm-> checkConstrTerm _ (LiteralPattern l) = LiteralPattern l-> checkConstrTerm _ (NegativePattern op l) = NegativePattern op l-> checkConstrTerm _ (VariablePattern v) = VariablePattern v-> checkConstrTerm pEnv (ConstructorPattern c ts) =->   ConstructorPattern c (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (InfixPattern t1 op t2) =->   fixPrecT pEnv InfixPattern->	 (checkConstrTerm pEnv t1) op (checkConstrTerm pEnv t2)-> checkConstrTerm pEnv (ParenPattern t) =->   ParenPattern (checkConstrTerm pEnv t)-> checkConstrTerm pEnv (TuplePattern p ts) =->   TuplePattern p (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (ListPattern p ts) =->   ListPattern p (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (AsPattern v t) =->   AsPattern v (checkConstrTerm pEnv t)-> checkConstrTerm pEnv (LazyPattern p t) =->   LazyPattern p (checkConstrTerm pEnv t)-> checkConstrTerm pEnv (FunctionPattern f ts) =->   FunctionPattern f (map (checkConstrTerm pEnv) ts)-> checkConstrTerm pEnv (InfixFuncPattern t1 op t2) =->   fixPrecT pEnv InfixFuncPattern ->	 (checkConstrTerm pEnv t1) op (checkConstrTerm pEnv t2)-> checkConstrTerm pEnv (RecordPattern fs r) =->   RecordPattern (map (checkFieldPattern pEnv) fs)->	          (maybe Nothing (Just . checkConstrTerm pEnv) r)--> checkFieldPattern :: PEnv -> Field ConstrTerm -> Field ConstrTerm-> checkFieldPattern pEnv (Field p label patt) =->     Field p label (checkConstrTerm pEnv patt)--> checkRhs :: ModuleIdent -> PEnv -> Rhs -> Rhs-> checkRhs m pEnv (SimpleRhs p e ds) = SimpleRhs p (checkExpr m pEnv' e) ds'->   where (pEnv',ds') = checkDecls m pEnv ds-> checkRhs m pEnv (GuardedRhs es ds) =->   GuardedRhs (map (checkCondExpr m pEnv') es) ds'->   where (pEnv',ds') = checkDecls m pEnv ds--> checkCondExpr :: ModuleIdent -> PEnv -> CondExpr -> CondExpr-> checkCondExpr m pEnv (CondExpr p g e) =->   CondExpr p (checkExpr m pEnv g) (checkExpr m pEnv e)--> checkExpr :: ModuleIdent -> PEnv -> Expression -> Expression-> checkExpr _ _ (Literal l) = Literal l-> checkExpr _ _ (Variable v) = Variable v-> checkExpr _ _ (Constructor c) = Constructor c-> checkExpr m pEnv (Paren e) = Paren (checkExpr m  pEnv e)-> checkExpr m pEnv (Typed e ty) = Typed (checkExpr m  pEnv e) ty-> checkExpr m pEnv (Tuple p es) = Tuple p (map (checkExpr m  pEnv) es)-> checkExpr m pEnv (List p es) = List p (map (checkExpr m  pEnv) es)-> checkExpr m pEnv (ListCompr p e qs) = ListCompr p (checkExpr m  pEnv' e) qs'->   where (pEnv',qs') = mapAccumL (checkStmt m ) pEnv qs-> checkExpr m pEnv (EnumFrom e) = EnumFrom (checkExpr m pEnv e)-> checkExpr m pEnv (EnumFromThen e1 e2) =->   EnumFromThen (checkExpr m pEnv e1) (checkExpr m pEnv e2)-> checkExpr m pEnv (EnumFromTo e1 e2) =->   EnumFromTo (checkExpr m pEnv e1) (checkExpr m pEnv e2)-> checkExpr m pEnv (EnumFromThenTo e1 e2 e3) =->   EnumFromThenTo (checkExpr m pEnv e1)->                  (checkExpr m pEnv e2)->                  (checkExpr m pEnv e3)-> checkExpr m pEnv (UnaryMinus op e) = UnaryMinus op (checkExpr m pEnv e)-> checkExpr m pEnv (Apply e1 e2) =->   Apply (checkExpr m pEnv e1) (checkExpr m pEnv e2)-> checkExpr m pEnv (InfixApply e1 op e2) =->   fixPrec pEnv (checkExpr m pEnv e1) op (checkExpr m pEnv e2)-> checkExpr m pEnv (LeftSection e op) =->   checkLSection pEnv op (checkExpr m pEnv e)-> checkExpr m pEnv (RightSection op e) =->   checkRSection pEnv op (checkExpr m pEnv e)-> checkExpr m pEnv (Lambda r ts e) =->   Lambda r (map (checkConstrTerm pEnv) ts) (checkExpr m pEnv e)-> checkExpr m pEnv (Let ds e) = Let ds' (checkExpr m pEnv' e)->   where (pEnv',ds') = checkDecls m pEnv ds-> checkExpr m pEnv (Do sts e) = Do sts' (checkExpr m pEnv' e)->   where (pEnv',sts') = mapAccumL (checkStmt m ) pEnv sts-> checkExpr m pEnv (IfThenElse r e1 e2 e3) =->   IfThenElse r (checkExpr m pEnv e1)->              (checkExpr m pEnv e2)->              (checkExpr m pEnv e3)-> checkExpr m pEnv (Case r e alts) =->   Case r (checkExpr m pEnv e) (map (checkAlt m pEnv) alts)-> checkExpr m pEnv (RecordConstr fs) =->   RecordConstr (map (checkFieldExpr m pEnv) fs)-> checkExpr m pEnv (RecordSelection e label) =->   RecordSelection (checkExpr m pEnv e) label-> checkExpr m pEnv (RecordUpdate fs e) =->   RecordUpdate (map (checkFieldExpr m pEnv) fs) (checkExpr m pEnv e)--> checkFieldExpr :: ModuleIdent -> PEnv -> Field Expression -> Field Expression-> checkFieldExpr m pEnv (Field p label e) =->   Field p label (checkExpr m  pEnv e)--> checkStmt :: ModuleIdent -> PEnv -> Statement -> (PEnv,Statement)-> checkStmt m pEnv (StmtExpr p e) = (pEnv,StmtExpr p (checkExpr m pEnv e))-> checkStmt m pEnv (StmtDecl ds) = pEnv' `seq` (pEnv',StmtDecl ds')->   where (pEnv',ds') = checkDecls m pEnv ds-> checkStmt m pEnv (StmtBind p t e) =->   (pEnv,StmtBind p (checkConstrTerm pEnv t) (checkExpr m pEnv e))--> checkAlt :: ModuleIdent -> PEnv -> Alt -> Alt-> checkAlt m pEnv (Alt p t rhs) =->   Alt p (checkConstrTerm pEnv t) (checkRhs m pEnv rhs)--\end{verbatim}-The functions \texttt{fixPrec}, \texttt{fixUPrec}, and-\texttt{fixRPrec} check the relative precedences of adjacent infix-operators in nested infix applications and unary negations. The-expressions will be reordered such that the infix operator with the-lowest precedence becomes the root of the expression. \emph{The-functions rely on the fact that the parser constructs infix-applications in a right-associative fashion}, i.e., the left argument-of an infix application will never be an infix application. In-addition, a unary negation will never have an infix application as-its argument.--The function \texttt{fixPrec} checks whether the left argument of an-infix application is a unary negation and eventually reorders the-expression if the precedence of the infix operator is higher than that-of the negation. This will be done with the help of the function-\texttt{fixUPrec}. In any case, the function \texttt{fixRPrec} is used-for fixing the precedence of the infix operator and that of its right-argument. Note that both arguments already have been checked before-\texttt{fixPrec} is called.-\begin{verbatim}--> fixPrec :: PEnv -> Expression -> InfixOp -> Expression->         -> Expression-> fixPrec pEnv (UnaryMinus uop e1) op e2->   | pr < 6 || pr == 6 && fix == InfixL =->       fixRPrec pEnv (UnaryMinus uop e1) op e2->   | pr > 6 = fixUPrec pEnv uop e1 op e2->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)->   where OpPrec fix pr = opPrec op pEnv-> fixPrec pEnv e1 op e2 = fixRPrec pEnv e1 op e2--> fixUPrec :: PEnv -> Ident -> Expression -> InfixOp -> Expression->          -> Expression-> fixUPrec pEnv uop  _ op (UnaryMinus _ _) =->   errorAt' $ ambiguousParse "operator" (opName op) (qualify uop)-> fixUPrec pEnv uop e1 op1 (InfixApply e2 op2 e3)->   | pr2 < 6 || pr2 == 6 && fix2 == InfixL =->       InfixApply (fixUPrec pEnv uop e1 op1 e2) op2 e3->   | pr2 > 6 = UnaryMinus uop (fixRPrec pEnv e1 op1 (InfixApply e2 op2 e3))->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op2)->   where OpPrec fix2 pr2 = opPrec op2 pEnv-> fixUPrec _ uop e1 op e2 = UnaryMinus uop (InfixApply e1 op e2)--> fixRPrec :: PEnv -> Expression -> InfixOp -> Expression->          -> Expression-> fixRPrec pEnv e1 op (UnaryMinus uop e2)->   | pr < 6 = InfixApply e1 op (UnaryMinus uop e2)->   | otherwise =->       errorAt' $ ambiguousParse "operator" (opName op) (qualify uop)->   where OpPrec _ pr = opPrec op pEnv-> fixRPrec pEnv e1 op1 (InfixApply e2 op2 e3)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =->       InfixApply e1 op1 (InfixApply e2 op2 e3)->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =->       InfixApply (fixPrec pEnv e1 op1 e2) op2 e3->   | otherwise =->       errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)->   where OpPrec fix1 pr1 = opPrec op1 pEnv->         OpPrec fix2 pr2 = opPrec op2 pEnv-> fixRPrec _ e1 op e2 = InfixApply e1 op e2--\end{verbatim}-The functions \texttt{checkLSection} and \texttt{checkRSection} are-used for handling the precedences inside left and right sections.-These functions only need to check that an infix operator occurring in-the section has either a higher precedence than the section operator-or both operators have the same precedence and are both left-associative for a left section and right associative for a right-section, respectively.-\begin{verbatim}--> checkLSection :: PEnv -> InfixOp -> Expression -> Expression-> checkLSection pEnv op e@(UnaryMinus uop _)->   | pr < 6 || pr == 6 && fix == InfixL = LeftSection e op->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)->   where OpPrec fix pr = opPrec op pEnv-> checkLSection pEnv op1 e@(InfixApply _ op2 _)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =->       LeftSection e op1->   | otherwise =->       errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)->   where OpPrec fix1 pr1 = opPrec op1 pEnv->         OpPrec fix2 pr2 = opPrec op2 pEnv-> checkLSection _ op e = LeftSection e op--> checkRSection :: PEnv -> InfixOp -> Expression -> Expression-> checkRSection pEnv op e@(UnaryMinus uop _)->   | pr < 6 = RightSection op e->   | otherwise = errorAt' $ ambiguousParse "unary" (qualify uop) (opName op)->   where OpPrec _ pr = opPrec op pEnv-> checkRSection pEnv op1 e@(InfixApply _ op2 _)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =->       RightSection op1 e->   | otherwise =->       errorAt' $ ambiguousParse "operator" (opName op1) (opName op2)->   where OpPrec fix1 pr1 = opPrec op1 pEnv->         OpPrec fix2 pr2 = opPrec op2 pEnv-> checkRSection _ op e = RightSection op e--\end{verbatim}-The functions \texttt{fixPrecT} and \texttt{fixRPrecT} check the-relative precedences of adjacent infix operators in patterns. The-patterns will be reordered such that the infix operator with the-lowest precedence becomes the root of the term. \emph{The functions-rely on the fact that the parser constructs infix patterns in a-right-associative fashion}, i.e., the left argument of an infix pattern-will never be an infix pattern. The functions also check whether the-left and right arguments of an infix pattern are negative literals. In-this case, the negation must bind more tightly than the operator for-the pattern to be accepted.-\begin{verbatim}--> fixPrecT ::  PEnv ->             -> (ConstrTerm -> QualIdent -> ConstrTerm -> ConstrTerm)->	      -> ConstrTerm -> QualIdent -> ConstrTerm  ->             -> ConstrTerm-> fixPrecT pEnv infixpatt t1@(NegativePattern uop l) op t2->   | pr < 6 || pr == 6 && fix == InfixL ->     = fixRPrecT pEnv infixpatt t1 op t2->   | otherwise ->     = errorAt' $ invalidParse "unary" uop op->   where OpPrec fix pr = prec op pEnv-> fixPrecT pEnv infixpatt t1 op t2 ->   = fixRPrecT pEnv infixpatt t1 op t2--> fixRPrecT :: PEnv ->              -> (ConstrTerm -> QualIdent -> ConstrTerm -> ConstrTerm)->              -> ConstrTerm  -> QualIdent -> ConstrTerm->              -> ConstrTerm-> fixRPrecT pEnv infixpatt t1 op t2@(NegativePattern uop l)->   | pr < 6    = infixpatt t1 op t2->   | otherwise = errorAt' $ invalidParse "unary" uop op->   where OpPrec _ pr = prec op pEnv-> fixRPrecT pEnv infixpatt t1 op1 (InfixPattern t2 op2 t3)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR->     = infixpatt t1 op1 (InfixPattern t2 op2 t3)->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL->     = InfixPattern (fixPrecT pEnv infixpatt t1 op1 t2) op2 t3->   | otherwise ->     = errorAt' $ ambiguousParse "operator" op1 op2->   where OpPrec fix1 pr1 = prec op1 pEnv->         OpPrec fix2 pr2 = prec op2 pEnv-> fixRPrecT pEnv infixpatt t1 op1 (InfixFuncPattern t2 op2 t3)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR->     = infixpatt t1 op1 (InfixFuncPattern t2 op2 t3)->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL->     = InfixFuncPattern (fixPrecT pEnv infixpatt t1 op1 t2) op2 t3->   | otherwise ->     = errorAt' $ ambiguousParse "operator" op1 op2->   where OpPrec fix1 pr1 = prec op1 pEnv->         OpPrec fix2 pr2 = prec op2 pEnv-> fixRPrecT _ infixpatt t1 op t2 = infixpatt t1 op t2--> {-fixPrecT :: Position -> PEnv -> ConstrTerm -> QualIdent -> ConstrTerm->          -> ConstrTerm-> fixPrecT p pEnv t1@(NegativePattern uop l) op t2->   | pr < 6 || pr == 6 && fix == InfixL = fixRPrecT p pEnv t1 op t2->   | otherwise = errorAt p $ invalidParse "unary" uop op->   where OpPrec fix pr = prec op pEnv-> fixPrecT p pEnv t1 op t2 = fixRPrecT p pEnv t1 op t2-}--> {-fixRPrecT :: Position -> PEnv -> ConstrTerm -> QualIdent -> ConstrTerm->           -> ConstrTerm-> fixRPrecT p pEnv t1 op t2@(NegativePattern uop l)->   | pr < 6 = InfixPattern t1 op t2->   | otherwise = errorAt p $ invalidParse "unary" uop op->   where OpPrec _ pr = prec op pEnv-> fixRPrecT p pEnv t1 op1 (InfixPattern t2 op2 t3)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR =->       InfixPattern t1 op1 (InfixPattern t2 op2 t3)->   | pr1 > pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL =->       InfixPattern (fixPrecT p pEnv t1 op1 t2) op2 t3->   | otherwise = errorAt p $ ambiguousParse "operator" op1 op2->   where OpPrec fix1 pr1 = prec op1 pEnv->         OpPrec fix2 pr2 = prec op2 pEnv-> fixRPrecT _ _ t1 op t2 = InfixPattern t1 op t2-}--\end{verbatim}-The functions \texttt{checkOpL} and \texttt{checkOpR} check the left-and right arguments of an operator declaration. If they are infix-patterns they must bind more tightly than the operator, otherwise the-left-hand side of the declaration is invalid.-\begin{verbatim}--> checkOpL :: PEnv -> Ident -> ConstrTerm -> ConstrTerm-> checkOpL pEnv op t@(NegativePattern uop l)->   | pr < 6 || pr == 6 && fix == InfixL = t->   | otherwise = errorAt' $ invalidParse "unary" uop (qualify op)->   where OpPrec fix pr = prec (qualify op) pEnv-> checkOpL pEnv op1 t@(InfixPattern _ op2 _)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixL && fix2 == InfixL = t->   | otherwise = errorAt' $ invalidParse "operator" op1 op2->   where OpPrec fix1 pr1 = prec (qualify op1) pEnv->         OpPrec fix2 pr2 = prec op2 pEnv-> checkOpL _ _ t = t--> checkOpR :: PEnv -> Ident -> ConstrTerm -> ConstrTerm-> checkOpR pEnv op t@(NegativePattern uop l)->   | pr < 6 = t->   | otherwise = errorAt' $ invalidParse "unary" uop (qualify op)->   where OpPrec _ pr = prec (qualify op) pEnv-> checkOpR pEnv op1 t@(InfixPattern _ op2 _)->   | pr1 < pr2 || pr1 == pr2 && fix1 == InfixR && fix2 == InfixR = t->   | otherwise = errorAt' $ invalidParse "operator" op1 op2->   where OpPrec fix1 pr1 = prec (qualify op1) pEnv->         OpPrec fix2 pr2 = prec op2 pEnv-> checkOpR _ _ t = t--\end{verbatim}-The functions \texttt{opPrec} and \texttt{prec} return the fixity and-operator precedence of an entity. Even though precedence checking is-performed after the renaming phase, we have to be prepared to see-ambiguous identifiers here. This may happen while checking the root of-an operator definition that shadows an imported definition.-\begin{verbatim}--> opPrec :: InfixOp -> PEnv -> OpPrec-> opPrec op = prec (opName op)--> prec :: QualIdent -> PEnv -> OpPrec-> prec op env =->   case qualLookupP op env of->     [] -> defaultP->     PrecInfo _ p : _ -> p--\end{verbatim}-Error messages.-\begin{verbatim}--> undefinedOperator :: Ident -> (Position,String)-> undefinedOperator op = ->  (positionOfIdent op,->   "no definition for " ++ name op ++ " in this scope")--> duplicatePrecedence :: Ident -> (Position,String)-> duplicatePrecedence op = ->  (positionOfIdent op,->   "More than one fixity declaration for " ++ name op)--> invalidParse :: String -> Ident -> QualIdent -> (Position,String)-> invalidParse what op1 op2 =->  (positionOfIdent op1,->   "Invalid use of " ++ what ++ " " ++ name op1 ++ " with " ++ qualName op2 ++->   (showLine $ positionOfQualIdent op2))--> ambiguousParse :: String -> QualIdent -> QualIdent -> (Position,String)-> ambiguousParse what op1 op2 =->  (positionOfQualIdent op1,->   "Ambiguous use of " ++ what ++ " " ++ qualName op1 ++->   " with " ++ qualName op2 ++ (showLine $ positionOfQualIdent op2))--\end{verbatim}
− src/Qual.lhs
@@ -1,165 +0,0 @@--% $Id: Qual.lhs,v 1.18 2004/02/15 22:10:36 wlux Exp $-%-% Copyright (c) 2001-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Qual.lhs}-\section{Proper Qualification}-After checking the module and before starting the translation into the-intermediate language, the compiler properly qualifies all-constructors and (global) functions occurring in a pattern or-expression such that their module prefix matches the module of their-definition. This is done also for functions and constructors declared-in the current module. Only functions and variables declared in local-declarations groups as well as function arguments remain unchanged.--\em{Note:} The modified version also qualifies type constructors-\begin{verbatim}--> module Qual(qual) where--> import Curry.Base.Ident-> import Curry.Syntax--> import Base-> import TopEnv--> qual :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl]-> qual m tyEnv ds = map (qualDecl m tyEnv) ds--> qualDecl :: ModuleIdent -> ValueEnv -> Decl -> Decl-> qualDecl m tyEnv (FunctionDecl p f eqs) =->   FunctionDecl p f (map (qualEqn m tyEnv) eqs)-> qualDecl m tyEnv (PatternDecl p t rhs) =->   PatternDecl p (qualTerm m tyEnv t) (qualRhs m tyEnv rhs)-> qualDecl _ _ d = d--> qualEqn :: ModuleIdent -> ValueEnv -> Equation -> Equation-> qualEqn m tyEnv (Equation p lhs rhs) =->   Equation p (qualLhs m tyEnv lhs) (qualRhs m tyEnv rhs)--> qualLhs :: ModuleIdent -> ValueEnv -> Lhs -> Lhs-> qualLhs m tyEnv (FunLhs f ts) = FunLhs f (map (qualTerm m tyEnv) ts)-> qualLhs m tyEnv (OpLhs t1 op t2) =->   OpLhs (qualTerm m tyEnv t1) op (qualTerm m tyEnv t2)-> qualLhs m tyEnv (ApLhs lhs ts) =->   ApLhs (qualLhs m tyEnv lhs) (map (qualTerm m tyEnv) ts)--> qualTerm :: ModuleIdent -> ValueEnv -> ConstrTerm -> ConstrTerm-> qualTerm _ _ (LiteralPattern l) = LiteralPattern l-> qualTerm _ _ (NegativePattern op l) = NegativePattern op l-> qualTerm _ _ (VariablePattern v) = VariablePattern v-> qualTerm m tyEnv (ConstructorPattern c ts) =->   ConstructorPattern (qualIdent m tyEnv c) (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (InfixPattern t1 op t2) =->   InfixPattern (qualTerm m tyEnv t1) ->                (qualIdent m tyEnv op) ->                (qualTerm m tyEnv t2)-> qualTerm m tyEnv (ParenPattern t) = ParenPattern (qualTerm m tyEnv t)-> qualTerm m tyEnv (TuplePattern p ts) = TuplePattern p (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (ListPattern p ts) = ListPattern p (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (AsPattern v t) = AsPattern v (qualTerm m tyEnv t)-> qualTerm m tyEnv (LazyPattern p t) = LazyPattern p (qualTerm m tyEnv t)-> qualTerm m tyEnv (FunctionPattern f ts) =->   FunctionPattern (qualIdent m tyEnv f) (map (qualTerm m tyEnv) ts)-> qualTerm m tyEnv (InfixFuncPattern t1 op t2) =->   InfixFuncPattern (qualTerm m tyEnv t1) ->		     (qualIdent m tyEnv op) ->	             (qualTerm m tyEnv t2)-> qualTerm m tyEnv (RecordPattern fs rt) =->   RecordPattern (map (qualFieldPattern m tyEnv) fs)->	          (maybe Nothing (Just . qualTerm m tyEnv) rt)--> qualFieldPattern :: ModuleIdent -> ValueEnv -> Field ConstrTerm->	           -> Field ConstrTerm-> qualFieldPattern m tyEnv (Field p l t) = Field p l (qualTerm m tyEnv t)--> qualRhs :: ModuleIdent -> ValueEnv -> Rhs -> Rhs-> qualRhs m tyEnv (SimpleRhs p e ds) =->   SimpleRhs p (qualExpr m tyEnv e) (map (qualDecl m tyEnv) ds) -> qualRhs m tyEnv (GuardedRhs es ds) =->   GuardedRhs (map (qualCondExpr m tyEnv) es) (map (qualDecl m tyEnv) ds)--> qualCondExpr :: ModuleIdent -> ValueEnv -> CondExpr -> CondExpr-> qualCondExpr m tyEnv (CondExpr p g e) =->   CondExpr p (qualExpr m tyEnv g) (qualExpr m tyEnv e)--> qualExpr :: ModuleIdent -> ValueEnv -> Expression -> Expression-> qualExpr _ _ (Literal l) = Literal l-> qualExpr m tyEnv (Variable v) = Variable (qualIdent m tyEnv v)-> qualExpr m tyEnv (Constructor c) = Constructor (qualIdent m tyEnv c)-> qualExpr m tyEnv (Paren e) = Paren (qualExpr m tyEnv e)-> qualExpr m tyEnv (Typed e ty) = Typed (qualExpr m tyEnv e) ty-> qualExpr m tyEnv (Tuple p es) = Tuple p (map (qualExpr m tyEnv) es)-> qualExpr m tyEnv (List p es) = List p (map (qualExpr m tyEnv) es)-> qualExpr m tyEnv (ListCompr p e qs) =->   ListCompr p (qualExpr m tyEnv e) (map (qualStmt m tyEnv) qs)-> qualExpr m tyEnv (EnumFrom e) = EnumFrom (qualExpr m tyEnv e)-> qualExpr m tyEnv (EnumFromThen e1 e2) =->   EnumFromThen (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (EnumFromTo e1 e2) =->   EnumFromTo (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (EnumFromThenTo e1 e2 e3) =->   EnumFromThenTo (qualExpr m tyEnv e1) ->                  (qualExpr m tyEnv e2) ->                  (qualExpr m tyEnv e3)-> qualExpr m tyEnv (UnaryMinus op e) = UnaryMinus op (qualExpr m tyEnv e)-> qualExpr m tyEnv (Apply e1 e2) = ->   Apply (qualExpr m tyEnv e1) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (InfixApply e1 op e2) =->   InfixApply (qualExpr m tyEnv e1) (qualOp m tyEnv op) (qualExpr m tyEnv e2)-> qualExpr m tyEnv (LeftSection e op) =->   LeftSection (qualExpr m tyEnv e) (qualOp m tyEnv op)-> qualExpr m tyEnv (RightSection op e) =->   RightSection (qualOp m tyEnv op) (qualExpr m tyEnv e)-> qualExpr m tyEnv (Lambda r ts e) =->   Lambda r (map (qualTerm m tyEnv) ts) (qualExpr m tyEnv e)-> qualExpr m tyEnv (Let ds e) = ->   Let (map (qualDecl m tyEnv) ds) (qualExpr m tyEnv e)-> qualExpr m tyEnv (Do sts e) = ->   Do (map (qualStmt m tyEnv) sts) (qualExpr m tyEnv e)-> qualExpr m tyEnv (IfThenElse r e1 e2 e3) =->   IfThenElse r (qualExpr m tyEnv e1) ->              (qualExpr m tyEnv e2) ->              (qualExpr m tyEnv e3)-> qualExpr m tyEnv (Case r e alts) =->   Case r (qualExpr m tyEnv e) (map (qualAlt m tyEnv) alts)-> qualExpr m tyEnv (RecordConstr fs) =->   RecordConstr (map (qualFieldExpr m tyEnv) fs)-> qualExpr m tyEnv (RecordSelection e l) =->   RecordSelection (qualExpr m tyEnv e) l-> qualExpr m tyEnv (RecordUpdate fs e) =->   RecordUpdate (map (qualFieldExpr m tyEnv) fs) (qualExpr m tyEnv e)--> qualStmt :: ModuleIdent -> ValueEnv -> Statement -> Statement-> qualStmt m tyEnv (StmtExpr p e) = StmtExpr p (qualExpr m tyEnv e)-> qualStmt m tyEnv (StmtBind p t e) =->   StmtBind p (qualTerm m tyEnv t) (qualExpr m tyEnv e)-> qualStmt m tyEnv (StmtDecl ds) = StmtDecl (map (qualDecl m tyEnv) ds)--> qualAlt :: ModuleIdent -> ValueEnv -> Alt -> Alt-> qualAlt m tyEnv (Alt p t rhs) = ->   Alt p (qualTerm m tyEnv t) (qualRhs m tyEnv rhs)--> qualFieldExpr :: ModuleIdent -> ValueEnv -> Field Expression->	        -> Field Expression-> qualFieldExpr m tyEnv (Field p l e) = Field p l (qualExpr m tyEnv e)--> qualOp :: ModuleIdent -> ValueEnv -> InfixOp -> InfixOp-> qualOp m tyEnv (InfixOp op) = InfixOp (qualIdent m tyEnv op)-> qualOp m tyEnv (InfixConstr op) = InfixConstr (qualIdent m tyEnv op)--> qualIdent :: ModuleIdent -> ValueEnv -> QualIdent -> QualIdent-> qualIdent m tyEnv x->   | not (isQualified x) && uniqueId (unqualify x) /= 0 = x->   | otherwise =->       case (qualLookupValue x tyEnv) of->         [y] -> origName y->         vs  -> case (qualLookupValue (qualQualify m x) tyEnv) of->                  [y] -> origName y->                  _ -> qualQualify m x -- internalError ("qualIdent: " ++ show x)--\end{verbatim}
− src/SCC.lhs
@@ -1,60 +0,0 @@--% $Id: SCC.lhs,v 1.3 2003/04/30 21:29:06 wlux Exp $-%-% Copyright (c) 2000,2002-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{SCC.lhs}-\section{Computing strongly connected components}-At various places in the compiler we had to partition a list of-declarations into strongly connected components. The function-\texttt{scc} computes this relation in two steps. First, the list is-topologically sorted ``downwards'' using the \emph{defs} relation.-Then the resulting list is sorted ``upwards'' using the \emph{uses}-relation and partitioned into the connected components. Both relations-are computed within this module using the bound and free names of each-declaration.--In order to avoid useless recomputations, the code in the module first-decorates the declarations with their bound and free names and a-unique number. The latter is only used to provide a trivial ordering-so that the declarations can be used as set elements.-\begin{verbatim}--> module SCC(scc) where--> import qualified Data.Set as Set--> data Node a b = Node{ key::Int, bvs::[b], fvs::[b], node::a }--> instance Eq (Node a b) where->   n1 == n2 = key n1 == key n2-> instance Ord (Node b a) where->   n1 `compare` n2 = key n1 `compare` key n2--> scc :: Eq b => (a -> [b])              -- entities defined by node->             -> (a -> [b])              -- entities used by node->             -> [a]                     -- list of nodes->             -> [[a]]                   -- strongly connected components-> scc bvs fvs = map (map node) . tsort' . tsort . zipWith wrap [0..]->   where wrap i n = Node i (bvs n) (fvs n) n--> tsort :: Eq b => [Node a b] -> [Node a b]-> tsort xs = snd (dfs xs Set.empty [])->   where dfs [] marks stack = (marks,stack)->         dfs (x:xs) marks stack->           | x `Set.member` marks = dfs xs marks stack->           | otherwise = dfs xs marks' (x:stack')->           where (marks',stack') = dfs (defs x) (x `Set.insert` marks) stack->         defs x = filter (any (`elem` fvs x) . bvs) xs--> tsort' :: Eq b => [Node a b] -> [[Node a b]]-> tsort' xs = snd (dfs xs Set.empty [])->   where dfs [] marks stack = (marks,stack)->         dfs (x:xs) marks stack->           | x `Set.member` marks = dfs xs marks stack->           | otherwise = dfs xs marks' ((x:concat stack'):stack)->           where (marks',stack') = dfs (uses x) (x `Set.insert` marks) []->         uses x = filter (any (`elem` bvs x) . fvs) xs--\end{verbatim}
− src/ScopeEnv.hs
@@ -1,175 +0,0 @@---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ScopeEnv - provides functions and data types for dealing with nested---            scope environments to store data from nested scopes------ This module should be imported using "import qualified" to avoid name--- clashes------ November 2005,--- Martin Engelke (men@informatik.uni-kiel.de)----module ScopeEnv (ScopeEnv,-		 new, insert, update, modify, lookup, sureLookup,-		 level, exists, beginScope, endScope, endScopeUp,-		 toList, toLevelList, currentLevel) where--import qualified Data.Map as Map-import Prelude hiding (lookup)--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Data type for representing information in nested scopes.-data ScopeEnv a b = ScopeEnv Int (Map.Map a (b,Int)) [Map.Map a (b,Int)]-		    deriving Show--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Returns an empty scope environment-new :: Ord a => ScopeEnv a b-new = ScopeEnv 0 Map.empty []----- Inserts a value under a key into the environment of the current scope-insert :: Ord a => a -> b -> ScopeEnv a b -> ScopeEnv a b-insert key val env = modifySE insertLev env- where- insertLev lev local = Map.insert key (val,lev) local----- Updates the value stored under an existing key in the environment of --- the current scope-update :: Ord a => a -> b -> ScopeEnv a b -> ScopeEnv a b-update key val env = modifySE updateLev env- where- updateLev lev local = maybe local -		             (\ (_,lev') ->  Map.insert key (val,lev') local)-			     (Map.lookup key local)---- Modifies the value of an existing key by applying the function 'fun'--- in the environment of the current scope-modify :: Ord a => (b -> b) -> a -> ScopeEnv a b -> ScopeEnv a b-modify fun key env = modifySE modifyLev env- where- modifyLev lev local -    = maybe local-            (\ (val',lev') -> Map.insert key (fun val', lev') local)-	    (Map.lookup key local)----- Looks up the value which is stored under a key from the environment of--- the current scope-lookup :: Ord a => a -> ScopeEnv a b -> Maybe b-lookup key env = selectSE lookupLev env- where- lookupLev lev local = maybe Nothing (Just . fst) (Map.lookup key local)----- Similar to 'lookup', but returns an alternative value, if the key--- doesn't exist in the environment of the current scope-sureLookup :: Ord a => a -> b -> ScopeEnv a b -> b-sureLookup key alt env = maybe alt id (lookup key env)----- Returns the level of the last insertion of a key-level :: Ord a => a -> ScopeEnv a b -> Int-level key env = selectSE levelLev env- where- levelLev lev local = maybe (-1) snd (Map.lookup key local)----- Checks, whether a key exists in the environment of the current scope-exists :: Ord a => a -> ScopeEnv a b -> Bool-exists key env = selectSE existsLev env- where- existsLev lev local = maybe False (const True) (Map.lookup key local)----- Switches to the next scope (i.e. pushes the environment of the current--- scope onto the top of an scope stack and increments the level counter)-beginScope :: Ord a => ScopeEnv a b -> ScopeEnv a b-beginScope (ScopeEnv lev top [])-   = ScopeEnv (lev + 1) top [top]-beginScope (ScopeEnv lev top (local:locals))-   = ScopeEnv (lev + 1) top (local:local:locals)----- Switches to the previous scope (i.e. pops the environment from the top--- of the scope stack and decrements the level counter)-endScope :: Ord a => ScopeEnv a b -> ScopeEnv a b-endScope (ScopeEnv _ top [])-   = ScopeEnv 0 top []-endScope (ScopeEnv lev top (_:locals))-   = ScopeEnv (lev - 1) top locals----- Behaves like 'endScope' but additionally updates the environment of--- the previous scope by updating all keys with the corresponding values--- from the poped environment-endScopeUp :: Ord a => ScopeEnv a b -> ScopeEnv a b-endScopeUp (ScopeEnv _ top [])-   = ScopeEnv 0 top []-endScopeUp (ScopeEnv lev top (local:[]))-   = ScopeEnv 0 (foldr (updateSE local) top (Map.toList top)) []-endScopeUp (ScopeEnv lev top (local:local':locals))-   = ScopeEnv (lev - 1) -              top -	      ((foldr (updateSE local) local' (Map.toList local')):locals)----- Returns the environment of current scope as a (key,value) list-toList :: Ord a => ScopeEnv a b -> [(a,b)]-toList env = selectSE toListLev env- where- toListLev lev local = map (\ (key,(val,_)) -> (key,val)) (Map.toList local)----- Returns all (key,value) pairs from the environment of the current scope --- which has been inserted in the current level-toLevelList :: Ord a => ScopeEnv a b -> [(a,b)]-toLevelList env = selectSE toLevelListLev env- where- toLevelListLev lev local-    = map (\ (key,(val,_)) -> (key,val))-          (filter (\ (_,(_,lev')) -> lev' == lev) (Map.toList local))----- Returns the current level-currentLevel :: Ord a => ScopeEnv a b -> Int-currentLevel env = selectSE const env--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Privates...-----modifySE :: (Int -> Map.Map a (b,Int) -> Map.Map a (b,Int)) -> ScopeEnv a b -          -> ScopeEnv a b-modifySE f (ScopeEnv _ top []) -   = ScopeEnv 0 (f 0 top) []-modifySE f (ScopeEnv lev top (local:locals))-   = ScopeEnv lev top ((f lev local):locals)-----selectSE :: (Int -> Map.Map a (b,Int) -> c) -> ScopeEnv a b -> c-selectSE f (ScopeEnv _ top [])        = f 0 top-selectSE f (ScopeEnv lev _ (local:_)) = f lev local-----updateSE :: Ord a => Map.Map a (b,Int) -> (a,(b,Int)) ->  Map.Map a (b,Int) -          -> Map.Map a (b,Int)-updateSE local (key,(_,lev)) local'-   = maybe local' -           (\ (val',lev') -	    -> if lev == lev' then Map.insert key (val',lev) local' -                              else local')-	   (Map.lookup key local)-------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/Simplify.lhs
@@ -1,475 +0,0 @@-% $Id: Simplify.lhs,v 1.10 2004/02/13 14:02:58 wlux Exp $-%-% Copyright (c) 2003, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Simplify.lhs}-\section{Optimizing the Desugared Code}\label{sec:simplify}-After desugaring the source code, but before lifting local-declarations, the compiler performs a few simple optimizations to-improve the efficiency of the generated code. In addition, the-optimizer replaces pattern bindings with simple variable bindings and-selector functions.--Currently, the following optimizations are implemented:-\begin{itemize}-\item Remove unused declarations.-\item Inline simple constants.-\item Compute minimal binding groups.-\item Under certain conditions, inline local function definitions.-\end{itemize}-\begin{verbatim}--> module Simplify(simplify) where--> import Control.Monad.Reader as R-> import Control.Monad.State as S-> import qualified Data.Map as Map--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Types-> import Base-> import SCC-> import Typing---> type SimplifyState a = S.StateT ValueEnv (ReaderT EvalEnv (S.State Int)) a-> type InlineEnv = Map.Map Ident Expression-> type SimplifyFlags = Bool- -> flatFlag :: SimplifyFlags -> Bool-> flatFlag   x = x--> simplify :: SimplifyFlags -> ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv)-> simplify flags tyEnv evEnv m ->   = S.evalState (R.runReaderT (S.evalStateT (simplifyModule flags m) tyEnv) evEnv) 1--> simplifyModule :: SimplifyFlags -> Module -> SimplifyState (Module,ValueEnv)-> simplifyModule flat (Module m es ds) =->   do->     ds' <- mapM (simplifyDecl flat m Map.empty) ds->     tyEnv <- S.get->     return (Module m es ds',tyEnv)--> simplifyDecl :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Decl -> SimplifyState Decl-> simplifyDecl flat m env (FunctionDecl p f eqs) =->   liftM (FunctionDecl p f . concat) (mapM (simplifyEquation flat m env) eqs)-> simplifyDecl flat m env (PatternDecl p t rhs) =->   liftM (PatternDecl p t) (simplifyRhs flat m env rhs)-> simplifyDecl _ _ _ d = return d--\end{verbatim}-After simplifying the right hand side of an equation, the compiler-transforms declarations of the form-\begin{quote}\tt-  $f\;t_1\dots t_{k-k'}\;x_{k-k'+1}\dots x_{k}$ =-    let $f'\;t'_1\dots t'_{k'}$ = $e$ in-    $f'\;x_1\dots x_{k'}$-\end{quote}-into the equivalent definition-\begin{quote}\tt-  $f\;t_1\dots t_{k-k'}\;(x_{k-k'+1}$@$t'_1)\dots(x_k$@$t'_{k'})$ = $e$-\end{quote}-where the arities of $f$ and $f'$ are $k$ and $k'$, respectively, and-$x_{k-k'+1},\dots,x_{k}$ are variables. This optimization was-introduced in order to avoid an auxiliary function being generated for-definitions whose right-hand side is a $\lambda$-expression, e.g.,-\verb|f . g = \x -> f (g x)|. This declaration is transformed into-\verb|(.) f g x = let lambda x = f (g x) in lambda x| by desugaring-and in turn is optimized into \verb|(.) f g x = f (g x)|, here. The-transformation can obviously be generalized to the case where $f'$ is-defined by more than one equation. However, we must be careful not to-change the evaluation mode of arguments. Therefore, the transformation-is applied only if $f$ and $f'$ use them same evaluation mode or all-of the arguments $t'_1,\dots,t'_k$ are variables. Actually, the-transformation could be applied to the case where the arguments-$t_1,\dots,t_{k-k'}$ are all variables as well, but in this case the-evaluation mode of $f$ may have to be changed to match that of $f'$.--We have to be careful with this optimization in conjunction with-newtype constructors. It is possible that the local function is-applied only partially, e.g., for-\begin{verbatim}-  newtype ST s a = ST (s -> (a,s))-  returnST x = ST (\s -> (x,s))-\end{verbatim}-the desugared code is equivalent to-\begin{verbatim}-  returnST x = let lambda1 s = (x,s) in lambda1-\end{verbatim}-We must not ``optimize'' this into \texttt{returnST x s = (x,s)}-because the compiler assumes that \texttt{returnST} is a unary-function.--Note that this transformation is not strictly semantic preserving as-the evaluation order of arguments can be changed. This happens if $f$-is defined by more than one rule with overlapping patterns and the-local functions of each rule have disjoint patterns. As an example,-consider the function-\begin{verbatim}-  f (Just x) _ = let g (Left z)  = x + z in g-  f _ (Just y) = let h (Right z) = y + z in h-\end{verbatim}-The definition of \texttt{f} is non-deterministic because of the-overlapping patterns in the first and second argument. However, the-optimized definition-\begin{verbatim}-  f (Just x) _ (Left z)  = x + z-  f _ (Just y) (Right z) = y + z-\end{verbatim}-is deterministic. It will evaluate and match the third argument first,-whereas the original definition is going to evaluate the first or the-second argument first, depending on the non-deterministic branch-chosen. As such definitions are presumably rare, and the optimization-avoids a non-deterministic split of the computation, we put up with-the change of evaluation order.--This transformation is actually just a special case of inlining a-(local) function definition. We are unable to handle the general case-because it would require to represent the pattern matching code-explicitly in a Curry expression.-\begin{verbatim}--> simplifyEquation :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Equation->                  -> SimplifyState [Equation]-> simplifyEquation flat m env (Equation p lhs rhs) =->   do->     rhs' <- simplifyRhs flat m env rhs->     tyEnv <- S.get->     evEnv <- S.lift R.ask->     return (inlineFun flat m tyEnv evEnv p lhs rhs')--> inlineFun :: SimplifyFlags -> ModuleIdent -> ValueEnv -> EvalEnv -> Position -> Lhs -> Rhs->           -> [Equation]-> inlineFun flags m tyEnv evEnv p (FunLhs f ts)->           (SimpleRhs _ (Let [FunctionDecl _ f' eqs'] e) _)->   | True -- False -- inlining of functions is deactivated (hsi)->    && f' `notElem` qfv m eqs' && e' == Variable (qualify f') &&->     n == arrowArity (funType m tyEnv (qualify f')) &&->     (evMode evEnv f == evMode evEnv f' ||->      and [all isVarPattern ts | Equation _ (FunLhs _ ts) _ <- eqs']) =->     map (mergeEqns p f ts' vs') eqs'->   where n :: Int                      -- type signature necessary for nhc->         (n,vs',ts',e') = etaReduce 0 [] (reverse ts) e->         mergeEqns p f ts vs (Equation _ (FunLhs _ ts') rhs) =->           Equation p (FunLhs f (ts ++ zipWith AsPattern vs ts')) rhs->         etaReduce n vs (VariablePattern v : ts) (Apply e (Variable v'))->           | qualify v == v' = etaReduce (n+1) (v:vs) ts e->         etaReduce n vs ts e = (n,vs,reverse ts,e)-> inlineFun _ _ _ _ p lhs rhs = [Equation p lhs rhs]--> simplifyRhs :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Rhs -> SimplifyState Rhs-> simplifyRhs flat m env (SimpleRhs p e _) =->   do->     e' <- simplifyExpr flat m env e->     return (SimpleRhs p e' [])--\end{verbatim}-Variables that are bound to (simple) constants and aliases to other-variables are substituted. In terms of conventional compiler-technology these optimizations correspond to constant folding and copy-propagation, respectively. The transformation is applied recursively-to a substituted variable in order to handle chains of variable-definitions.--The bindings of a let expression are sorted topologically in-order to split them into minimal binding groups. In addition,-local declarations occurring on the right hand side of a pattern-declaration are lifted into the enclosing binding group using the-equivalence (modulo $\alpha$-conversion) of \texttt{let}-$x$~=~\texttt{let} \emph{decls} \texttt{in} $e_1$ \texttt{in} $e_2$-and \texttt{let} \emph{decls}\texttt{;} $x$~=~$e_1$ \texttt{in} $e_2$.-This transformation avoids the creation of some redundant lifted-functions in later phases of the compiler.-\begin{verbatim}--> simplifyExpr :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Expression->              -> SimplifyState Expression-> simplifyExpr _ _ _ (Literal l) = return (Literal l)-> simplifyExpr flat m env (Variable v)->   | isQualified v = return (Variable v)->   | otherwise = maybe (return (Variable v)) (simplifyExpr flat m env)->                       (Map.lookup (unqualify v) env)-> simplifyExpr _ _ _ (Constructor c) = return (Constructor c)-> simplifyExpr flags m env (Apply (Let ds e1) e2) ->   = simplifyExpr flags m env (Let ds (Apply e1 e2))-> simplifyExpr flags m env (Apply (Case r e1 alts) e2) ->   = simplifyExpr flags m env (Case r e1 (map (applyToAlt e2) alts))->   where applyToAlt e (Alt p t rhs) = Alt p t (applyRhs rhs e)->         applyRhs (SimpleRhs p e1 _) e2 = SimpleRhs p (Apply e1 e2) []-> simplifyExpr flat m env (Apply e1 e2) =->   do->     e1' <- simplifyExpr flat m env e1->     e2' <- simplifyExpr flat m env e2->     return (Apply e1' e2')-> simplifyExpr flags m env (Let ds e) =->   do->     tyEnv <- S.get->     dss' <- mapM (sharePatternRhs m tyEnv) ds->     simplifyLet flags m env->       (scc bv (qfv m) (foldr (hoistDecls flags) [] (concat dss'))) e-> simplifyExpr flat m env (Case r e alts) =->   do->     e' <- simplifyExpr flat m env e->     alts' <- mapM (simplifyAlt flat m env) alts->     return (Case r e' alts')-> --> simplifyAlt :: SimplifyFlags -> ModuleIdent -> InlineEnv -> Alt -> SimplifyState Alt-> simplifyAlt flat m env (Alt p t rhs) =->   liftM (Alt p t) (simplifyRhs flat m env rhs)--> hoistDecls :: SimplifyFlags -> Decl -> [Decl] -> [Decl]-> hoistDecls flags (PatternDecl p t (SimpleRhs p' (Let ds e) _)) ds' ->  = foldr (hoistDecls flags) ds' (PatternDecl p t (SimpleRhs p' e []) : ds)-> hoistDecls _ d ds = d : ds--\end{verbatim}-The declaration groups of a let expression are first processed from-outside to inside, simplifying the right hand sides and collecting-inlineable expressions on the fly. At present, only simple constants-and aliases to other variables are inlined. A constant is considered-simple if it is either a literal, a constructor, or a non-nullary-function. Note that it is not possible to define nullary functions in-local declarations in Curry. Thus, an unqualified name always refers-to either a variable or a non-nullary function.  Applications of-constructors and partial applications of functions to at least one-argument are not inlined because the compiler has to allocate space-for them, anyway. In order to prevent non-termination, recursive-binding groups are not processed.--With the list of inlineable expressions, the body of the let is-simplified and then the declaration groups are processed from inside-to outside to construct the simplified, nested let expression. In-doing so unused bindings are discarded. In addition, all pattern-bindings are replaced by simple variable declarations using selector-functions to access the pattern variables.-\begin{verbatim}--> simplifyLet :: SimplifyFlags -> ModuleIdent -> InlineEnv -> [[Decl]] -> Expression->             -> SimplifyState Expression-> simplifyLet flat m env [] e = simplifyExpr flat m env e-> simplifyLet flags m env (ds:dss) e =->   do->     ds' <- mapM (simplifyDecl flags m env) ds->     tyEnv <- S.get->     e' <- simplifyLet flags m (inlineVars flags m tyEnv ds' env) dss e->     dss'' <-->       mapM (expandPatternBindings flags m tyEnv (qfv m ds' ++ qfv m e')) ds'->     return (foldr (mkLet flags m) e' ->                   (scc bv (qfv m) (concat dss'')))--> inlineVars :: SimplifyFlags -> ModuleIdent -> ValueEnv -> [Decl] -> InlineEnv -> InlineEnv-> inlineVars flags m tyEnv [PatternDecl _ (VariablePattern v) (SimpleRhs _ e _)] env->   | canInline e = Map.insert v e env->   where->   canInline (Literal _) = True->   canInline (Constructor _) = True->   canInline _ = False -- inlining of variables is deactivated (hsi)->   canInline (Variable v')->       | isQualified v' = arrowArity (funType m tyEnv v') > 0->       | otherwise = v /= unqualify v'->   canInline _ = False-> inlineVars _ _ _ _ env = env--> mkLet :: SimplifyFlags -> ModuleIdent -> [Decl] -> Expression -> Expression-> mkLet flags m [ExtraVariables p vs] e->   | null vs' = e->   | otherwise = Let [ExtraVariables p vs'] e->   where vs' = filter (`elem` qfv m e) vs-> mkLet flags m [PatternDecl _ (VariablePattern v) (SimpleRhs _ e _)] (Variable v')->   | v' == qualify v && v `notElem` qfv m e = e-> mkLet flags m ds e->   | null (filter (`elem` qfv m e) (bv ds)) = e->   | otherwise = Let ds e--\end{verbatim}-\label{pattern-binding}-In order to implement lazy pattern matching in local declarations,-pattern declarations $t$~\texttt{=}~$e$ where $t$ is not a variable-are transformed into a list of declarations-$v_0$~\texttt{=}~$e$\texttt{;} $v_1$~\texttt{=}~$f_1$~$v_0$\texttt{;}-\dots{} $v_n$~\texttt{=}~$f_n$~$v_0$ where $v_0$ is a fresh variable,-$v_1,\dots,v_n$ are the variables occurring in $t$ and the auxiliary-functions $f_i$ are defined by $f_i$~$t$~\texttt{=}~$v_i$ (see also-appendix D.8 of the Curry report~\cite{Hanus:Report}). The bindings-$v_0$~\texttt{=}~$e$ are introduced before splitting the declaration-groups of the enclosing let expression (cf. the \texttt{Let} case in-\texttt{simplifyExpr} above) so that they are placed in their own-declaration group whenever possible. In particular, this ensures that-the new binding is discarded when the expression $e$ is itself a-variable.--Unfortunately, this transformation introduces a well-known space-leak~\cite{Wadler87:Leaks,Sparud93:Leaks} because the matched-expression cannot be garbage collected until all of the matched-variables have been evaluated. Consider the following function:-\begin{verbatim}-  f x | all (' ' ==) cs = c where (c:cs) = x-\end{verbatim}-One might expect the call \verb|f (replicate 10000 ' ')| to execute in-constant space because (the tail of) the long list of blanks is-consumed and discarded immediately by \texttt{all}. However, the-application of the selector function that extracts the head of the-list is not evaluated until after the guard has succeeded and thus-prevents the list from being garbage collected.--In order to avoid this space leak we use the approach-from~\cite{Sparud93:Leaks} and update all pattern variables when one-of the selector functions has been evaluated. Therefore all pattern-variables except for the matched one are passed as additional-arguments to each of the selector functions. Thus, each of these-variables occurs twice in the argument list of a selector function,-once in the first argument and also as one of the remaining arguments.-This duplication of names is used by the compiler to insert the code-that updates the variables when generating abstract machine code.--By its very nature, this transformation introduces cyclic variable-bindings. Since cyclic bindings are not supported by PAKCS, we revert-to a simpler translation when generating FlatCurry output.--We will add only those pattern variables as additional arguments which-are actually used in the code. This reduces the number of auxiliary-variables and can prevent the introduction of a recursive binding-group when only a single variable is used. It is also the reason for-performing this transformation here instead of in the \texttt{Desugar}-module. The selector functions are defined in a local declaration on-the right hand side of a projection declaration so that there is-exactly one declaration for each used variable.--Another problem of the translation scheme is the handling of pattern-variables with higher-order types, e.g.,-\begin{verbatim}-  strange :: [a->a] -> Maybe (a->a)-  strange xs = Just x-    where (x:_) = xs-\end{verbatim}-By reusing the types of the pattern variables, the selector function-\verb|f (x:_) = x| has type \texttt{[a->a] -> a -> a} and therefore-seems to be binary function. Thus, in the goal \verb|strange []| the-selector is only applied partially and not evaluated. Note that this-goal will fail without the type annotation. In order to ensure that a-selector function is always evaluated when the corresponding variable-is used, we assume that the projection declarations -- ignoring the-additional arguments to prevent the space leak -- are actually defined-by $f_i$~$t$~\texttt{= I}~$v_i$, using a private renaming type-\begin{verbatim}-  newtype Identity a = I a-\end{verbatim}-As newtype constructors are completely transparent to the compiler,-this does not change the generated code, but only the types of the-selector functions.-\begin{verbatim}--> sharePatternRhs :: ModuleIdent -> ValueEnv -> Decl -> SimplifyState [Decl]-> sharePatternRhs m tyEnv (PatternDecl p t rhs) =->   case t of->     VariablePattern _ -> return [PatternDecl p t rhs]->     _ -> ->       do->         v0 <- freshIdent m patternId (monoType (typeOf tyEnv t))->         let v = addRefId (srcRefOf p) v0->         return [PatternDecl p t (SimpleRhs p (mkVar v) []),->                 PatternDecl p (VariablePattern v) rhs]->   where patternId n = mkIdent ("_#pat" ++ show n)-> sharePatternRhs _ _ d = return [d]--> expandPatternBindings :: SimplifyFlags -> ModuleIdent -> ValueEnv -> [Ident] ->    -> Decl -> SimplifyState [Decl]->-> expandPatternBindings flags m tyEnv fvs (PatternDecl p t (SimpleRhs p' e _)) =->   case t of->     VariablePattern _ -> return [PatternDecl p t (SimpleRhs p' e [])]->     _->       | flatFlag flags ->->           do->             fs <- sequence (zipWith getId tys vs)->             return (zipWith (flatProjectionDecl p t e) fs vs)->       | otherwise ->->           do->             fs <- mapM (freshIdent m fpSelectorId . selectorType ty)->                        (shuffle tys)->             return (zipWith (projectionDecl p t e) fs (shuffle vs))->->       where getId t v = freshIdent m ->                            (\ i -> updIdentName ( ++'#':name v) (fpSelectorId i))->                            (flatSelectorType ty t)->             ->             vs = filter (`elem` fvs) (bv t)->             ty = typeOf tyEnv t->             tys = map (typeOf tyEnv) vs->             selectorType ty0 (ty:tys) =->               polyType (foldr TypeArrow (identityType ty) (ty0:tys))->->             selectorDecl p f t (v:vs) =->               funDecl p f (t:map VariablePattern vs) (mkVar v)->             projectionDecl p t e f (v:vs) =->               varDecl p v (Let [selectorDecl p f t (v:vs)]->                                (foldl applyVar (Apply (mkVar f) e) vs))->->             flatSelectorType ty0 ty =->               polyType (TypeArrow ty0 (identityType ty))->             flatSelectorDecl p f t v = funDecl p f [t] (mkVar v)->             flatProjectionDecl p t e f v =->               varDecl p v (Let [flatSelectorDecl p f t v] (Apply (mkVar f) e))->-> expandPatternBindings _ _ _ _ d = return [d]--\end{verbatim}-Auxiliary functions-\begin{verbatim}--> isVarPattern :: ConstrTerm -> Bool-> isVarPattern (VariablePattern _) = True-> isVarPattern (AsPattern _ t) = isVarPattern t-> isVarPattern (ConstructorPattern _ _) = False-> isVarPattern (LiteralPattern _) = False--> funType :: ModuleIdent -> ValueEnv -> QualIdent -> Type-> funType m tyEnv f =->   case (qualLookupValue f tyEnv) of->     [Value _ (ForAll _ ty)] -> ty->     vs -> case (qualLookupValue (qualQualify m f) tyEnv) of->             [Value _ (ForAll _ ty)] -> ty->             _ -> internalError ("funType " ++ show f)--> evMode :: EvalEnv -> Ident -> Maybe EvalAnnotation-> evMode evEnv f = Map.lookup f evEnv--> freshIdent :: ModuleIdent -> (Int -> Ident) -> TypeScheme->            -> SimplifyState Ident-> freshIdent m f ty =->   do->     x <- liftM f (S.lift (R.lift ( S.modify succ >> S.get)))->     S.modify (bindFun m x ty)->     return x--> shuffle :: [a] -> [[a]]-> shuffle xs = shuffle id xs->   where shuffle _ [] = []->         shuffle f (x:xs) = (x : f xs) : shuffle (f . (x:)) xs--> mkVar :: Ident -> Expression-> mkVar = Variable . qualify--> applyVar :: Expression -> Ident -> Expression-> applyVar e v = Apply e (mkVar v)--> varDecl :: Position -> Ident -> Expression -> Decl-> varDecl p v e = PatternDecl p (VariablePattern v) (SimpleRhs p e [])--> funDecl :: Position -> Ident -> [ConstrTerm] -> Expression -> Decl-> funDecl p f ts e =->   FunctionDecl p f [Equation p (FunLhs f ts) (SimpleRhs p e [])]--> identityType :: Type -> Type-> identityType = TypeConstructor qIdentityId . return->   where qIdentityId = qualify (mkIdent "Identity")--\end{verbatim}
− src/Subst.lhs
@@ -1,124 +0,0 @@-% Copyright (c) 2002, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Subst.lhs}-\section{Substitutions}-The module {\tt Subst} implements substitutions. A substitution-$\sigma = \left\{x_1\mapsto t_1,\dots,x_n\mapsto t_n\right\}$ is a-finite mapping from (finitely many) variables $x_1,\dots,x_n$ to-some kind of expression or term.--In order to implement substitutions efficiently composed-substitutions are marked with a boolean flag (see below).-\begin{verbatim}--> module Subst where--> import qualified Data.Map as Map--> data Subst a b = Subst Bool (Map.Map a b) deriving Show--> idSubst :: Ord a => Subst a b-> idSubst = Subst False Map.empty--> substToList :: Ord v => Subst v e -> [(v,e)]-> substToList (Subst _ sigma) = Map.toList sigma--> bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e-> bindSubst v e (Subst comp sigma) = Subst comp (Map.insert v e sigma)--> unbindSubst :: Ord v => v -> Subst v e -> Subst v e-> unbindSubst v (Subst comp sigma) = Subst comp (Map.delete v sigma)--\end{verbatim}-For any substitution we have the following definitions:-\begin{displaymath}-  \begin{array}{l}-    \sigma(x) = \left\{\begin{array}{ll}-        t_i&\mbox{if $x=x_i$}\\-        x&\mbox{otherwise}\end{array}\right. \\-    \mathop{{\mathcal D}om}(\sigma) = \left\{x_1,\dots,x_n\right\} \\-    \mathop{{\mathcal C}odom}(\sigma) = \left\{t_1,\dots,t_n\right\}-  \end{array}  -\end{displaymath}-Note that obviously the set of variables must be a subset of the set-of expressions. Also it is usually possible to extend the substitution-to a homomorphism on the codomain of the substitution. This is-captured by the following class declaration:-\begin{verbatim}--class Ord v => Subst v e where-  var :: v -> e-  subst :: Subst v e -> e -> e--\end{verbatim}-With the help of the injection \texttt{var}, we can then compute the-substitution for a variable $\sigma(v)$ and also the composition of-two substitutions-$(\sigma_1 \circ \sigma_2)(e) \mathop{:=} \sigma_1(\sigma_2(e))$. A-naive implementation of the composition were-\begin{verbatim}-  compose sigma sigma' =-    foldr (uncurry bindSubst) sigma (substToList (fmap (subst sigma) sigma'))-\end{verbatim}-However, such an implementation is very inefficient because the-number of substiutions applied to a variable increases in-$\mathcal{O}(n)$ of the number of compositions.--A more efficient implementation is to apply \texttt{subst} again to-the value substituted for a variable in-$\mathop{{\mathcal D}om}(\sigma)$. However, this is correct only as-long as the result of the substitution does not include any variables-which are in $\mathop{{\mathcal D}om}(\sigma)$. For instance, it is-impossible to implement simple variable renamings in this way.--Therefore we use the simple strategy to apply \texttt{subst} again-only in case of a substitution which was returned from \texttt{compose}.-\begin{verbatim}--substVar :: Subst v e => Subst v e -> v -> e-substVar (Subst comp sigma) v = maybe (var v) subst' (Map.lookup v sigma)-  where subst' = if comp then subst (Subst comp sigma) else id--> compose :: (Show v,Ord v,Show e) => Subst v e -> Subst v e -> Subst v e-> compose sigma sigma' =->   composed (foldr (uncurry bindSubst) sigma' (substToList sigma))->   where dom = domain sigma->         dom' = domain sigma'->         domain = map fst . substToList->         composed (Subst _ sigma) = Subst True sigma--\end{verbatim}-Unfortunately Haskell does not (yet) support multi-parameter type-classes. For that reason we have to define a separate class for each-kind of variable type for these functions. We implement-\texttt{substVar} as a function that takes the class functions as an-additional parameters. As an example for the use of this function the-module includes a class \texttt{IntSubst} for substitution whose-domain are integer numbers.-\begin{verbatim}--> substVar' :: Ord v => (v -> e) -> (Subst v e -> e -> e)->           -> Subst v e -> v -> e-> substVar' var subst (Subst comp sigma) v =->   maybe (var v) subst' (Map.lookup v sigma)->   where subst' = if comp then subst (Subst comp sigma) else id--> class IntSubst e where->   ivar :: Int -> e->   isubst :: Subst Int e -> e -> e--> isubstVar :: IntSubst e => Subst Int e -> Int -> e-> isubstVar = substVar' ivar isubst--\end{verbatim}-The function \texttt{restrictSubstTo} implements the restriction of a-substitution to a given subset of its domain.-\begin{verbatim}--> restrictSubstTo :: Ord v => [v] -> Subst v e -> Subst v e-> restrictSubstTo vs (Subst comp sigma) =->   foldr (uncurry bindSubst) (Subst comp Map.empty)->         (filter ((`elem` vs) . fst) (Map.toList sigma))--\end{verbatim}
− src/SyntaxCheck.lhs
@@ -1,1149 +0,0 @@--% $Id: SyntaxCheck.lhs,v 1.53 2004/02/15 22:10:37 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{SyntaxCheck.lhs}-\section{Syntax Checks}-After the type declarations have been checked, the compiler performs a-syntax check on the remaining declarations. This check disambiguates-nullary data constructors and variables which -- in contrast to-Haskell -- is not possible on purely syntactic criteria. In addition,-this pass checks for undefined as well as ambiguous variables and-constructors. In order to allow lifting of local definitions in-later phases, all local variables are renamed by adding a unique-key.\footnote{Actually, all variables defined in the same scope share-the same key.} Finally, all (adjacent) equations of a function are-merged into a single definition.-\begin{verbatim}--> module SyntaxCheck(syntaxCheck) where--> import Data.Maybe-> import Data.List-> import qualified Data.Map as Map-> import Control.Monad.State as S--> import Curry.Syntax-> import Curry.Syntax.Utils-> import Types-> import Curry.Base.Position-> import Curry.Base.Ident-> import Base-> import NestEnv-> import Utils--\end{verbatim}-The syntax checking proceeds as follows. First, the compiler extracts-information about all imported values and data constructors from the-imported (type) environments. Next, the data constructors defined in-the current module are entered into this environment. After this-all record labels are entered into the environment too. If a record-identifier is already assigned to a constructor, then an error will be-generated. Finally, all-declarations are checked within the resulting environment. In-addition, this process will also rename the local variables.-\begin{verbatim}--> syntaxCheck :: Bool -> ModuleIdent -> ImportEnv -> ArityEnv -> ValueEnv -> TCEnv -> [Decl] -> [Decl]-> syntaxCheck withExt m iEnv aEnv tyEnv tcEnv ds =->   case findDouble (concatMap constrs tds) of->     --Nothing -> tds ++ run (checkModule withExt m env vds)->     Nothing -> map (checkTypeDecl withExt m) tds->	        ++ run (checkModule withExt m env2 vds)->     Just c -> errorAt' (duplicateData c)->   where (tds,vds) = partition isTypeDecl ds->	  (rs, tds') = partition isRecordDecl tds->         env1 = foldr (bindTypes m) -- (bindConstrs m) ->	               (globalEnv (fmap (renameInfo tcEnv iEnv aEnv) tyEnv)) ->	               tds'->	  env2 = foldr (bindTypes m) env1 rs--\end{verbatim}-A global state transformer is used for generating fresh integer keys-by which the variables get renamed.-\begin{verbatim}--> type RenameState a = S.State Int a--> run :: RenameState a -> a-> run m = S.evalState m (globalKey + 1)--> newId :: RenameState Int-> newId = S.modify succ >> S.get--\end{verbatim}-\ToDo{Probably the state transformer should use an \texttt{Integer} -counter.}--A nested environment is used for recording information about the data-constructors and variables in the module. For every data constructor-its arity is saved. This is used for checking that all constructor-applications in patterns are saturated. For local variables the-environment records the new name of the variable after renaming.-Global variables are recorded with qualified identifiers in order-to distinguish multiply declared entities.--Currently records must explicitly be declared together with their labels.-When constructing or updating a record, it is necessary to compute -all its labels using just one of them. Thus for each label -the record identifier and all its labels are entered into the environment--\em{Note:} the function \texttt{qualLookupVar} has been extended to-allow the usage of the qualified list constructor \texttt{(prelude.:)}.-\begin{verbatim}--> type RenameEnv = NestEnv RenameInfo-> data RenameInfo = Constr Int ->                 | GlobalVar Int QualIdent ->                 | LocalVar Int Ident->	          | RecordLabel QualIdent [Ident]->	    deriving (Eq,Show)--> globalKey :: Int-> globalKey = uniqueId (mkIdent "")--> renameInfo :: TCEnv -> ImportEnv -> ArityEnv -> ValueInfo -> RenameInfo-> renameInfo tcEnv iEnv aEnv (DataConstructor _ (ForAllExist _ _ ty)) ->    = Constr (arrowArity ty)-> renameInfo tcEnv iEnv aEnv (NewtypeConstructor _ _) ->    = Constr 1-> renameInfo tcEnv iEnv aEnv (Value qid _)->    = let (mmid, id) = (qualidMod qid, qualidId qid)->          qid' = maybe qid ->	                (\mid -> maybe qid ->		                       (\mid' -> qualifyWith mid' id)->				       (lookupAlias mid iEnv))->		        mmid->      in case (lookupArity id aEnv) of->	    [ArityInfo _ arity] -> GlobalVar arity qid->           rs -> case (qualLookupArity qid' aEnv) of->	            [ArityInfo _ arity] -> GlobalVar arity qid->	            _ -> maybe (internalError "renameInfo: missing arity")->	                       (\ (ArityInfo _ arity) -> GlobalVar arity qid)->		               (find (\ (ArityInfo qid'' _) ->			              -> qid'' == qid) rs)-> renameInfo tcEnv iEnv aEnv (Label l r _)->    = case (qualLookupTC r tcEnv) of->        [AliasType _ _ (TypeRecord fs _)] ->->          RecordLabel r (map fst fs)->        _ -> internalError "renameInfo: no record"--\end{verbatim}-Since record types are currently translated into data types, it is-necessary to ensure that all identifiers for records and constructors-are different. Furthermore it is not allowed to declare a label more-than once.-\begin{verbatim}--> bindTypes :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv-> bindTypes m (DataDecl _ tc _ cs) env = foldr (bindConstr m) env cs-> bindTypes m (NewtypeDecl _ tc _ nc) env = bindNewConstr m nc env-> bindTypes m (TypeDecl _ t _ (RecordType fs r)) env =->    -- - | isJust r = internalError "bindTypes: illegal record declaration"->    -- - | null fs = errorAt (positionOfIdent t) emptyRecord->    -- - | otherwise =->      case (qualLookupVar (qualifyWith m t) env) of->        [] -> foldr (bindRecordLabel m t (concatMap fst fs)) env fs->        rs | any isConstr rs -> errorAt' (illegalRecordId t)->           | otherwise->             -> foldr (bindRecordLabel m t (concatMap fst fs)) env fs-> bindTypes _ _ env = env--> bindRecordLabel :: ModuleIdent -> Ident -> [Ident] ->	             -> ([Ident],TypeExpr) -> RenameEnv -> RenameEnv-> bindRecordLabel m t labels (ls,_) env = ->     foldr (\l -> case (lookupVar l env) of->                    [] -> bindGlobal m l->                             (RecordLabel (qualifyWith m t) labels)->                    _  -> errorAt' (duplicateDefinition l)->	    ) env ls--> --bindConstrs :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv-> --bindConstrs m (DataDecl _ tc _ cs) env = foldr (bindConstr m) env cs-> --bindConstrs m (NewtypeDecl _ tc _ nc) env = bindNewConstr m nc env-> --bindConstrs _ _ env = env--> bindConstr :: ModuleIdent -> ConstrDecl -> RenameEnv -> RenameEnv-> bindConstr m (ConstrDecl _ _ c tys) = bindGlobal m c (Constr (length tys))-> bindConstr m (ConOpDecl _ _ _ op _) = bindGlobal m op (Constr 2)--> bindNewConstr :: ModuleIdent -> NewConstrDecl -> RenameEnv -> RenameEnv-> bindNewConstr m (NewConstrDecl _ _ c _) = bindGlobal m c (Constr 1)--> bindFuncDecl :: ModuleIdent -> Decl -> RenameEnv -> RenameEnv-> bindFuncDecl m (FunctionDecl _ id equs) env->    | null equs = internalError "bindFuncDecl: missing equations"->    | otherwise = let (_,ts) = getFlatLhs (head equs)->		   in  bindGlobal m ->	                          id ->			          (GlobalVar (length ts) (qualifyWith m id))->	                          env-> bindFuncDecl m (ExternalDecl _ _ _ id texpr) env->    = bindGlobal m id (GlobalVar (typeArity texpr) (qualifyWith m id)) env-> bindFuncDecl m (TypeSig _ ids texpr) env->    = foldr bindTS env (map (qualifyWith m) ids)->  where->  bindTS qid env ->     | null (qualLookupVar qid env)->       = bindGlobal m (unqualify qid) (GlobalVar (typeArity texpr) qid) env->     | otherwise->       = env-> bindFuncDecl _ _ env = env--> bindVarDecl :: Decl -> RenameEnv -> RenameEnv-> bindVarDecl (FunctionDecl _ id equs) env->    | null equs ->      = internalError "bindFuncDecl: missing equations"->    | otherwise ->      = let (_,ts) = getFlatLhs (head equs)->	 in  bindLocal (unRenameIdent id) (LocalVar (length ts) id) env-> bindVarDecl (PatternDecl p t _) env->    = foldr bindVar env (bv t)-> bindVarDecl (ExtraVariables p vs) env->    = foldr bindVar env vs -> bindVarDecl _ env = env--> bindVar :: Ident -> RenameEnv -> RenameEnv-> bindVar v env->   | v' == anonId = env->   | otherwise = bindLocal v' (LocalVar 0 v) env->   where v' = unRenameIdent v--> bindGlobal :: ModuleIdent -> Ident -> RenameInfo -> RenameEnv -> RenameEnv-> bindGlobal m c r = bindNestEnv c r . qualBindNestEnv (qualifyWith m c) r--> bindLocal :: Ident -> RenameInfo -> RenameEnv -> RenameEnv-> bindLocal f r = bindNestEnv f r--> lookupVar :: Ident -> RenameEnv -> [RenameInfo]-> lookupVar v env = lookupNestEnv v env ++! lookupTupleConstr v--> qualLookupVar :: QualIdent -> RenameEnv -> [RenameInfo]-> qualLookupVar v env =->   qualLookupNestEnv v env->   ++! qualLookupListCons v env->   ++! lookupTupleConstr (unqualify v)--> qualLookupListCons :: QualIdent -> RenameEnv -> [RenameInfo]-> qualLookupListCons v env->    | (isJust mmid) && ((fromJust mmid) == preludeMIdent) && (ident == consId)->       = qualLookupNestEnv (qualify ident) env->    | otherwise = []->  where (mmid, ident) = (qualidMod v, qualidId v)--> lookupTupleConstr :: Ident -> [RenameInfo]-> lookupTupleConstr v->   | isTupleId v = [Constr (tupleArity v)]->   | otherwise = []--\end{verbatim}-When a module is checked, the global declaration group is checked. The-resulting renaming environment can be discarded. The same is true for-a goal. Note that all declarations in the goal must be considered as-local declarations.-\begin{verbatim}--> checkModule :: Bool -> ModuleIdent -> RenameEnv -> [Decl] -> RenameState [Decl]-> checkModule withExt m env ds = liftM snd (checkTopDecls withExt m env ds)--> checkTopDecls :: Bool -> ModuleIdent -> RenameEnv -> [Decl]->               -> RenameState (RenameEnv,[Decl])-> checkTopDecls withExt m env ds = ->   checkDeclGroup (bindFuncDecl m) withExt m globalKey env ds--> checkTypeDecl :: Bool -> ModuleIdent -> Decl -> Decl-> checkTypeDecl withExt m d@(TypeDecl p r tvs (RecordType fs rty))->   | not withExt = errorAt (positionOfIdent r) noRecordExt->   | isJust rty = internalError "checkTypeDecl - illegal record type"->   | null fs = errorAt (positionOfIdent r) emptyRecord->   | otherwise = TypeDecl p r tvs (RecordType fs Nothing)-> checkTypeDecl _ _ d = d--\end{verbatim}-Each declaration group opens a new scope and uses a distinct key-for renaming the variables in this scope. In a declaration group,-first the left hand sides of all declarations are checked, next the-compiler checks that there is a definition for every type signature-and evaluation annotation in this group. Finally, the right hand sides-are checked and adjacent equations for the same function are merged-into a single definition.--The function \texttt{checkDeclLhs} also handles the case where a-pattern declaration is recognized as a function declaration by the-parser. This happens, e.g., for the declaration \verb|where Just x = y|-because the parser cannot distinguish nullary constructors and-functions. Note that pattern declarations are not allowed on the-top-level.-\begin{verbatim}--> checkLocalDecls :: Bool -> ModuleIdent -> RenameEnv -> [Decl] ->                  -> RenameState (RenameEnv,[Decl])-> checkLocalDecls withExt m env ds =->   newId >>= \k -> checkDeclGroup bindVarDecl withExt m k (nestEnv env) ds--> checkDeclGroup :: (Decl -> RenameEnv -> RenameEnv) -> Bool -> ModuleIdent->                 -> Int -> RenameEnv -> [Decl] ->                 -> RenameState (RenameEnv,[Decl])-> checkDeclGroup bindDecl withExt m k env ds =->   mapM (checkDeclLhs withExt k m env) ds' >>=->   checkDecls bindDecl withExt m env . joinEquations->  where ds' = sortFuncDecls ds--> checkDeclLhs :: Bool -> Int -> ModuleIdent -> RenameEnv -> Decl -> RenameState Decl-> checkDeclLhs withExt k _ _ (InfixDecl p fix pr ops) =->   return (InfixDecl p fix pr (map (flip renameIdent k) ops))-> checkDeclLhs withExt k _ env (TypeSig p vs ty) =->   return (TypeSig p (map (checkVar "type signature" k env) vs) ty)-> checkDeclLhs withExt k _ env (EvalAnnot p fs ev) =->   return (EvalAnnot p (map (checkVar "evaluation annotation" k env) fs) ev)-> checkDeclLhs withExt k m env (FunctionDecl p _ eqs) = ->   checkEquationLhs withExt k m env p eqs-> checkDeclLhs withExt k _ env (ExternalDecl p cc ie f ty) =->   return (ExternalDecl p cc ie (checkVar "external declaration" k env f) ty)-> checkDeclLhs withExt k _ env (FlatExternalDecl p fs) =->   return (FlatExternalDecl p->             (map (checkVar "external declaration" k env) fs))-> checkDeclLhs withExt k m env (PatternDecl p t rhs) =->   do->     t' <- checkConstrTerm withExt k p m env t->     return (PatternDecl p t' rhs)-> checkDeclLhs withExt k _ env (ExtraVariables p vs) =->   return (ExtraVariables p->             (map (checkVar "free variables declaration" k env) vs))-> checkDeclLhs _ _ _ _ d = return d--> checkEquationLhs :: Bool -> Int -> ModuleIdent -> RenameEnv -> Position ->	           -> [Equation] -> RenameState Decl-> checkEquationLhs withExt k m env p [Equation p' lhs rhs] =->   either (return . funDecl) (checkDeclLhs withExt k m env . patDecl)->          (checkEqLhs m k env p' lhs)->   where funDecl (f,lhs) = FunctionDecl p f [Equation p' lhs rhs]->         patDecl t->           | k == globalKey = errorAt p noToplevelPattern->           | otherwise = PatternDecl p' t rhs-> checkEquationLhs _ _ _ _ _ _ = internalError "checkEquationLhs"--> checkEqLhs :: ModuleIdent -> Int -> RenameEnv -> Position -> Lhs->            -> Either (Ident,Lhs) ConstrTerm-> checkEqLhs m k env _ (FunLhs f ts)->   | isDataConstr f env->     = if k /= globalKey->       then Right (ConstructorPattern (qualify f) ts)->       else if null (qualLookupVar (qualifyWith m f) env)->            then Left (f',FunLhs f' ts)->	     else errorAt (positionOfIdent f) noToplevelPattern->   | otherwise = Left (f',FunLhs f' ts)->   where f' = renameIdent f k-> checkEqLhs m k env p (OpLhs t1 op t2)->   | isDataConstr op env ->     = if k /= globalKey->       then checkOpLhs k env (infixPattern t1 (qualify op)) t2->       else if null (qualLookupVar (qualifyWith m op) env)->            then Left (op',OpLhs t1 op' t2)->	     else errorAt p noToplevelPattern->   | otherwise = Left (op',OpLhs t1 op' t2)->   where op' = renameIdent op k->         infixPattern (InfixPattern t1 op1 t2) op2 t3 =->           InfixPattern t1 op1 (infixPattern t2 op2 t3)->         infixPattern t1 op t2 = InfixPattern t1 op t2-> checkEqLhs m k env p (ApLhs lhs ts) =->   case checkEqLhs m k env p lhs of->     Left (f',lhs') -> Left (f',ApLhs lhs' ts)->     Right _ -> errorAt' $ nonVariable "curried definition" f->   where (f,_) = flatLhs lhs--> checkOpLhs :: Int -> RenameEnv -> (ConstrTerm -> ConstrTerm) -> ConstrTerm->            -> Either (Ident,Lhs) ConstrTerm-> checkOpLhs k env f (InfixPattern t1 op t2)->   | isJust m || isDataConstr op' env =->       checkOpLhs k env (f . InfixPattern t1 op) t2->   | otherwise = Left (op'',OpLhs (f t1) op'' t2)->   where (m,op') = (qualidMod op, qualidId op)->         op'' = renameIdent op' k-> checkOpLhs _ _ f t = Right (f t)--> checkVar :: String -> Int -> RenameEnv -> Ident -> Ident-> checkVar what k env v ->   | False && isDataConstr v env = errorAt' (nonVariable what v)---------------->   | otherwise = renameIdent v k---> checkDecls :: (Decl -> RenameEnv -> RenameEnv) -> Bool -> ModuleIdent->	        -> RenameEnv -> [Decl] -> RenameState (RenameEnv,[Decl])-> checkDecls bindDecl withExt m env ds = ->   case findDouble bvs of->     Nothing ->->       case findDouble tys of->         Nothing ->->           case findDouble evs of->             Nothing ->->               case filter (`notElem` tys) fs' of->                 [] -> liftM ((,) env') ->		              (mapM (checkDeclRhs withExt bvs m env'') ds)->                 f : _ -> errorAt' (noTypeSig f)->             Just v -> errorAt' (duplicateEvalAnnot v)->         Just v -> errorAt' (duplicateTypeSig v)->     Just v -> errorAt' (duplicateDefinition v)->   where vds = filter isValueDecl ds->	  tds = filter isTypeSig ds->         bvs = concat (map vars vds)->         tys = concat (map vars tds)->         evs = concat (map vars (filter isEvalAnnot ds))->         fs' = [f | FlatExternalDecl _ fs <- ds, f <- fs]->         env' = foldr bindDecl env vds->         env'' = foldr bindDecl env' tds--> checkDeclRhs :: Bool -> [Ident] -> ModuleIdent -> RenameEnv -> Decl ->              -> RenameState Decl-> checkDeclRhs withExt bvs _ _ (TypeSig p vs ty) =->   return (TypeSig p (map (checkLocalVar bvs ) vs) ty)-> checkDeclRhs withExt bvs _ _ (EvalAnnot p vs ev) =->   return (EvalAnnot p (map (checkLocalVar bvs ) vs) ev)-> checkDeclRhs withExt _ m env (FunctionDecl p f eqs) =->   liftM (FunctionDecl p f) (mapM (checkEquation withExt m env) eqs)-> checkDeclRhs withExt _ m env (PatternDecl p t rhs) =->   liftM (PatternDecl p t) (checkRhs withExt m env rhs)-> checkDeclRhs _ _ _ _ d = return d--> checkLocalVar :: [Ident] -> Ident -> Ident-> checkLocalVar bvs v->   | v `elem` bvs = v->   | otherwise = errorAt' (noBody v)--> joinEquations :: [Decl] -> [Decl]-> joinEquations [] = []-> joinEquations (FunctionDecl p f eqs : FunctionDecl p' f' [eq] : ds)->   | f == f' =->       if arity (head eqs) == arity eq then->         joinEquations (FunctionDecl p f (eqs ++ [eq]) : ds)->       else->         errorAt' (differentArity f)->   where arity (Equation _ lhs _) = length $ snd $ flatLhs lhs-> joinEquations (d : ds) = d : joinEquations ds--> checkEquation :: Bool -> ModuleIdent -> RenameEnv -> Equation -> RenameState Equation-> checkEquation withExt m env (Equation p lhs rhs) =->   do->     (env',lhs') <- checkLhs withExt p m env lhs->     rhs' <- checkRhs withExt m env' rhs->     return (Equation p lhs' rhs')--> checkLhs :: Bool -> Position -> ModuleIdent -> RenameEnv -> Lhs ->             -> RenameState (RenameEnv,Lhs)-> checkLhs withExt p m env lhs =->   newId >>= \k ->->   checkLhsTerm withExt k p m env lhs >>=->   return . checkConstrTerms withExt (nestEnv env)--> checkLhsTerm :: Bool -> Int -> Position -> ModuleIdent -> RenameEnv -> Lhs ->                 -> RenameState Lhs-> checkLhsTerm withExt k p m env (FunLhs f ts) =->   do->     ts' <- mapM (checkConstrTerm withExt k p m env) ts->     return (FunLhs f ts')-> checkLhsTerm withExt k p m env (OpLhs t1 op t2) =->   let wrongCalls = concatMap (checkParenConstrTerm (Just (qualify op)))->                               [t1,t2] in->   if not (null wrongCalls)->     then errorAt (positionOfIdent op) ->                  (infixWithoutParens wrongCalls)->     else  do->       t1' <- checkConstrTerm withExt k p m env t1->       t2' <- checkConstrTerm withExt k p m env t2 ->       return (OpLhs t1' op t2')->-> checkLhsTerm withExt k p m env (ApLhs lhs ts) =->   do->     lhs' <- checkLhsTerm withExt k p m env lhs->     ts' <- mapM (checkConstrTerm withExt k p m env) ts->     return (ApLhs lhs' ts')--> checkArgs :: Bool -> Position -> ModuleIdent -> RenameEnv -> [ConstrTerm]->           -> RenameState (RenameEnv,[ConstrTerm])-> checkArgs withExt p m env ts =->   newId >>= \k ->->   mapM (checkConstrTerm withExt k p m env) ts >>=->   return . checkConstrTerms withExt (nestEnv env)--> checkConstrTerms :: QuantExpr t => Bool -> RenameEnv -> t->                  -> (RenameEnv,t)-> checkConstrTerms withExt env ts =->   case findDouble bvs of->     Nothing -> (foldr bindVar env bvs,ts)->     Just v -> errorAt' (duplicateVariable v)->   where bvs = bv ts--> checkConstrTerm :: Bool -> Int -> Position -> ModuleIdent -> RenameEnv->	             -> ConstrTerm -> RenameState ConstrTerm-> checkConstrTerm _ _ _ _ _ (LiteralPattern l) =->   liftM LiteralPattern (renameLiteral l)-> checkConstrTerm _ _ _ _ _ (NegativePattern op l) =->   liftM (NegativePattern op) (renameLiteral l)-> checkConstrTerm withExt k p m env (VariablePattern v)->   | v == anonId ->     = liftM (VariablePattern . renameIdent anonId) newId->   | otherwise ->     = checkConstrTerm withExt k p m env (ConstructorPattern (qualify v) [])-> checkConstrTerm withExt k p m env (ConstructorPattern c ts) =->   case qualLookupVar c env of->     [Constr n]->       | n == n' ->->           liftM (ConstructorPattern c) ->	          (mapM (checkConstrTerm withExt k p m env) ts)->       | otherwise -> errorAt' (wrongArity c n n')->       where n' = length ts->     [r]->       | null ts && not (isQualified c) ->->	    return (VariablePattern (renameIdent (varIdent r) k))->       | withExt ->->           do ts' <- mapM (checkConstrTerm withExt k p m env) ts->	       if n' > n->	          then let (ts1,ts2) = splitAt n ts'->	               in  return (genFuncPattAppl ->			             (FunctionPattern (qualVarIdent r) ->				                      ts1) ->	                             ts2)->	          else return (FunctionPattern (qualVarIdent r) ts')->       | otherwise -> errorAt (positionOfQualIdent c) noFuncPattExt  ->	where n = arity r->	      n' = length ts->     rs -> case (qualLookupVar (qualQualify m c) env) of->             []->               | null ts && not (isQualified c) ->->	            return (VariablePattern (renameIdent (unqualify c) k))->	        | null rs -> errorAt' (undefinedData c)->		| otherwise -> errorAt' (ambiguousData c)->             [Constr n]->               | n == n' ->->                   liftM (ConstructorPattern (qualQualify m c)) ->                         (mapM (checkConstrTerm withExt k p m env) ts)->               | otherwise -> errorAt' (wrongArity c n n')->               where n' = length ts->	      [r]->	        | null ts && not (isQualified c) ->->                   return (VariablePattern (renameIdent (varIdent r) k))->               | withExt ->->	            do ts' <- mapM (checkConstrTerm withExt k p m env) ts->	               if n' > n->	                  then let (ts1,ts2) = splitAt n ts'->	                       in  return ->			             (genFuncPattAppl ->			                (FunctionPattern (qualVarIdent r) ts1) ->	                                ts2)->	                  else return (FunctionPattern (qualVarIdent r) ts')->	        | otherwise -> errorAt (positionOfQualIdent c) noFuncPattExt->               where n = arity r->		      n' = length ts->             _ -> errorAt' (ambiguousData c)-> checkConstrTerm withExt k p m env (InfixPattern t1 op t2) =->   case (qualLookupVar op env) of->     [Constr n]->       | n == 2 ->->           do t1' <- checkConstrTerm withExt k p m env t1->	       t2' <- checkConstrTerm withExt k p m env t2->              return (InfixPattern t1' op t2') ->       | otherwise -> errorAt' (wrongArity op n 2)->     [r]->       | withExt ->->           do t1' <- checkConstrTerm withExt k p m env t1->	       t2' <- checkConstrTerm withExt k p m env t2->              return (InfixFuncPattern t1' op t2')->       | otherwise -> errorAt p noFuncPattExt    ->     rs -> case (qualLookupVar (qualQualify m op) env) of->             [] | null rs -> errorAt' (undefinedData op)->                | otherwise -> errorAt' (ambiguousData op)->             [Constr n]->               | n == 2 ->->                   do t1' <- checkConstrTerm withExt k p m env t1->	               t2' <- checkConstrTerm withExt k p m env t2->                      return (InfixPattern t1' (qualQualify m op) t2') ->               | otherwise -> errorAt' (wrongArity op n 2)->	      [r]->               | withExt ->->	            do t1' <- checkConstrTerm withExt k p m env t1->	               t2' <- checkConstrTerm withExt k p m env t2->		       return (InfixFuncPattern t1' (qualQualify m op) t2')->	        | otherwise -> errorAt p noFuncPattExt->             _ -> errorAt' (ambiguousData op)-> checkConstrTerm withExt k p m env (ParenPattern t) =->   liftM ParenPattern (checkConstrTerm withExt k p m env t)-> checkConstrTerm withExt k p m env (TuplePattern pos ts) =->   liftM (TuplePattern pos) (mapM (checkConstrTerm withExt k p m env) ts)-> checkConstrTerm withExt k p m env (ListPattern pos ts) =->   liftM (ListPattern pos) (mapM (checkConstrTerm withExt k p m env) ts)-> checkConstrTerm withExt k p m env (AsPattern v t) =->   liftM (AsPattern (checkVar "@ pattern" k env v))->         (checkConstrTerm withExt k p m env t)-> checkConstrTerm withExt k p m env (LazyPattern pos t) =->   liftM (LazyPattern pos) (checkConstrTerm withExt k p m env t)-> checkConstrTerm withExt k p m env (RecordPattern fs t)->   | not withExt = errorAt p noRecordExt->   | not (null fs) =->     let (Field _ label _) = head fs->     in  case (lookupVar label env) of->           [] -> errorAt' (undefinedLabel label)->           [RecordLabel r ls]->             | not (null duplicates) ->->	        errorAt' (duplicateLabel (head duplicates))->	      | isNothing t && not (null missings) ->->	        errorAt (positionOfIdent label) ->                       (missingLabel (head missings) r "record pattern")->             | maybe True ((==) (VariablePattern anonId)) t ->->	        do fs' <- mapM (checkFieldPatt withExt k m r env) fs->	           t'  <- maybe (return Nothing)->	                        (\t' -> checkConstrTerm withExt k p m env t'->			                >>= return . Just)->			        t->	           return (RecordPattern fs' t')->	      | otherwise -> errorAt p illegalRecordPatt->            where ls' = map fieldLabel fs->                  duplicates = maybeToList (dup ls')->		   missings = ls \\ ls'->	    [_] -> errorAt' (notALabel label)->	    _ -> errorAt' (duplicateDefinition label)->   | otherwise = errorAt p emptyRecord--> checkFieldPatt :: Bool -> Int -> ModuleIdent -> QualIdent -> RenameEnv->	            -> Field ConstrTerm -> RenameState (Field ConstrTerm)-> checkFieldPatt withExt k m r env (Field p l t)->    = case (lookupVar l env) of->        [] -> errorAt' (undefinedLabel l)->        [RecordLabel r' _]->          | r == r' -> do t' <- checkConstrTerm withExt k ->                                   (positionOfIdent l) m env t->		           return (Field p l t')->          | otherwise -> errorAt' (illegalLabel l r)->        [_] -> errorAt' (notALabel l)->	 _ -> errorAt' (duplicateDefinition l)--> checkRhs :: Bool -> ModuleIdent -> RenameEnv -> Rhs -> RenameState Rhs-> checkRhs withExt m env (SimpleRhs p e ds) =->   do->     (env',ds') <- checkLocalDecls withExt m env ds->     e' <- checkExpr withExt p m env' e->     return (SimpleRhs p e' ds')-> checkRhs withExt m env (GuardedRhs es ds) =->   do->     (env',ds') <- checkLocalDecls withExt m env ds->     es' <- mapM (checkCondExpr withExt m env') es->     return (GuardedRhs es' ds')--> checkCondExpr :: Bool -> ModuleIdent -> RenameEnv -> CondExpr -> RenameState CondExpr-> checkCondExpr withExt m env (CondExpr p g e) =->   do->     g' <- checkExpr withExt p m env g->     e' <- checkExpr withExt p m env e->     return (CondExpr p g' e')--> checkExpr :: Bool -> Position -> ModuleIdent -> RenameEnv -> Expression ->           -> RenameState Expression-> checkExpr _ _ _ _ (Literal l) = liftM Literal (renameLiteral l)-> checkExpr withExt _ m env (Variable v) =->   case (qualLookupVar v env) of->     [] ->  errorAt' (undefinedVariable v)->     [Constr _] -> return (Constructor v)->     [GlobalVar _ _] -> return (Variable v)->     [LocalVar _ v'] -> return (Variable (qualify v'))->     rs -> case (qualLookupVar (qualQualify m v) env) of->             [] -> errorAt' (ambiguousIdent rs v)->             [Constr _] -> return (Constructor v)->             [GlobalVar _ _] -> return (Variable v)->             [LocalVar _ v'] -> return (Variable (qualify v'))->             rs' -> errorAt' (ambiguousIdent rs' v)-> checkExpr withExt p m env (Constructor c) = ->   checkExpr withExt p m env (Variable c)-> checkExpr withExt p m env (Paren e) = ->   liftM Paren (checkExpr withExt p m env e)-> checkExpr withExt p m env (Typed e ty) = ->   liftM (flip Typed ty) (checkExpr withExt p m env e)-> checkExpr withExt p m env (Tuple pos es) = ->   liftM (Tuple pos) (mapM (checkExpr withExt p m env) es)-> checkExpr withExt p m env (List pos es) = ->   liftM (List pos) (mapM (checkExpr withExt p m env) es)-> checkExpr withExt p m env (ListCompr pos e qs) =->   do->     (env',qs') <- mapAccumM (checkStatement withExt p m) env qs->     e' <- checkExpr withExt p m env' e->     return (ListCompr pos e' qs')-> checkExpr withExt p m env (EnumFrom e) = ->   liftM EnumFrom (checkExpr withExt p m env e)-> checkExpr withExt p m env (EnumFromThen e1 e2) =->   do->     e1' <- checkExpr withExt p m env e1->     e2' <- checkExpr withExt p m env e2->     return (EnumFromThen e1' e2')-> checkExpr withExt p m env (EnumFromTo e1 e2) =->   do->     e1' <- checkExpr withExt p m env e1->     e2' <- checkExpr withExt p m env e2->     return (EnumFromTo e1' e2')-> checkExpr withExt p m env (EnumFromThenTo e1 e2 e3) =->   do->     e1' <- checkExpr withExt p m env e1->     e2' <- checkExpr withExt p m env e2->     e3' <- checkExpr withExt p m env e3->     return (EnumFromThenTo e1' e2' e3')-> checkExpr withExt p m env (UnaryMinus op e) = ->   liftM (UnaryMinus op) (checkExpr withExt p m env e)-> checkExpr withExt p m env (Apply e1 e2) =->   do->     e1' <- checkExpr withExt p m env e1->     e2' <- checkExpr withExt p m env e2->     return (Apply e1' e2')-> checkExpr withExt p m env (InfixApply e1 op e2) =->   do->     e1' <- checkExpr withExt p m env e1->     e2' <- checkExpr withExt p m env e2->     return (InfixApply e1' (checkOp m env op) e2')-> checkExpr withExt p m env (LeftSection e op) =->   liftM (flip LeftSection (checkOp m env op)) (checkExpr withExt p m env e)-> checkExpr withExt p m env (RightSection op e) =->   liftM (RightSection (checkOp m env op)) (checkExpr withExt p m env e)-> checkExpr withExt p m env (Lambda r ts e) =->   do->     (env',ts') <- checkArgs withExt p m env ts->     e' <- checkExpr withExt p m env' e->     return (Lambda r ts' e')-> checkExpr withExt p m env (Let ds e) =->   do->     (env',ds') <- checkLocalDecls withExt m env ds->     e' <- checkExpr withExt p m env' e->     return (Let ds' e')-> checkExpr withExt p m env (Do sts e) =->   do->     (env',sts') <- mapAccumM (checkStatement withExt p m) env sts->     e' <- checkExpr withExt p m env' e->     return (Do sts' e')-> checkExpr withExt p m env (IfThenElse r e1 e2 e3) =->   do->     e1' <- checkExpr withExt p m env e1->     e2' <- checkExpr withExt p m env e2->     e3' <- checkExpr withExt p m env e3->     return (IfThenElse r e1' e2' e3')-> checkExpr withExt p m env (Case r e alts) =->   do->     e' <- checkExpr withExt p m env e->     alts' <- mapM (checkAlt withExt m env) alts->     return (Case r e' alts')-> checkExpr withExt p m env (RecordConstr fs)->   | not withExt = errorAt p noRecordExt->   | not (null fs) = ->     let (Field _ label _) = head fs->     in  case (lookupVar label env) of->           [] -> errorAt' (undefinedLabel label)->	    [RecordLabel r ls]->              | not (null duplicates) ->->                errorAt' (duplicateLabel (head duplicates))->              | not (null missings) ->->	         errorAt (positionOfIdent label) ->                        (missingLabel (head missings) r "record construction")->	       | otherwise ->->	         do fs' <- mapM (checkFieldExpr withExt m r env) fs->	            return (RecordConstr fs')->	      where ls' = map fieldLabel fs->	            duplicates = maybeToList (dup ls')->		    missings = ls \\ ls'->           [_] -> errorAt' (notALabel label)->	    _ -> errorAt' (duplicateDefinition label)->   | otherwise = errorAt p emptyRecord-> checkExpr withExt p m env (RecordSelection e l)->   | not withExt = errorAt p noRecordExt->   | otherwise =->     case (lookupVar l env) of->       [] -> errorAt' (undefinedLabel l)->       [RecordLabel r ls] ->->         do e' <- checkExpr withExt p m env e->            return (RecordSelection e' l)->       [_] -> errorAt' (notALabel l)->       _ -> errorAt' (duplicateDefinition l)-> checkExpr withExt p m env (RecordUpdate fs e)->   | not withExt = errorAt p noRecordExt->   | not (null fs) =->     let (Field _ label _) = head fs->     in  case (lookupVar label env) of->           [] -> errorAt' (undefinedLabel label)->	    [RecordLabel r ls]->             | not (null duplicates) ->->	        errorAt' (duplicateLabel (head duplicates))->	      | otherwise ->->	        do fs' <- mapM (checkFieldExpr withExt m r env) fs->	           e' <- checkExpr withExt (positionOfIdent label) m env e->	           return (RecordUpdate fs' e')->	      where duplicates = maybeToList (dup (map fieldLabel fs))->	    [_] -> errorAt' (notALabel label)->	    _ -> errorAt' (duplicateDefinition label)->   | otherwise = errorAt p emptyRecord--> checkStatement :: Bool -> Position -> ModuleIdent -> RenameEnv -> Statement->                -> RenameState (RenameEnv,Statement)-> checkStatement withExt p m env (StmtExpr pos e) =->   do->     e' <- checkExpr withExt p m env e->     return (env,StmtExpr pos e')-> checkStatement withExt p m env (StmtBind pos t e) =->   do->     e' <- checkExpr withExt p m env e->     (env',[t']) <- checkArgs withExt p m env [t]->     return (env',StmtBind pos t' e')-> checkStatement withExt _ m env (StmtDecl ds) =->   do->     (env',ds') <- checkLocalDecls withExt m env ds->     return (env',StmtDecl ds')--> checkAlt :: Bool -> ModuleIdent -> RenameEnv -> Alt -> RenameState Alt-> checkAlt withExt m env (Alt p t rhs) =->   do->     (env',[t']) <- checkArgs withExt p m env [t]->     rhs' <- checkRhs withExt m env' rhs->     return (Alt p t' rhs')--> checkFieldExpr :: Bool -> ModuleIdent -> QualIdent -> RenameEnv ->	            -> Field Expression -> RenameState (Field Expression)-> checkFieldExpr withExt m r env (Field p l e)->    = case (lookupVar l env) of->        [] -> errorAt' (undefinedLabel l)->        [RecordLabel r' _]->          | r == r' -> do e' <- checkExpr withExt (positionOfIdent l) m env e->		           return (Field p l e')->          | otherwise -> errorAt' (illegalLabel l r)->        [_] -> errorAt' (notALabel l)->	 _ -> errorAt' (duplicateDefinition l)---> checkOp :: ModuleIdent -> RenameEnv -> InfixOp -> InfixOp-> checkOp m env op =->   case (qualLookupVar v env) of->     [] -> errorAt' (undefinedVariable v)->     [Constr _] -> InfixConstr v->     [GlobalVar _ _] -> InfixOp v->     [LocalVar _ v'] -> InfixOp (qualify v')->     rs -> case (qualLookupVar (qualQualify m v) env) of->             [] -> errorAt' (ambiguousIdent rs v)->             [Constr _] -> InfixConstr v->             [GlobalVar _ _] -> InfixOp v->             [LocalVar _ v'] -> InfixOp (qualify v')->             rs' -> errorAt' (ambiguousIdent rs' v)->   where v = opName op--\end{verbatim}-Auxiliary definitions.-\begin{verbatim}--> constrs :: Decl -> [Ident]-> constrs (DataDecl _ _ _ cs) = map constr cs->   where constr (ConstrDecl _ _ c _) = c->         constr (ConOpDecl _ _ _ op _) = op-> constrs (NewtypeDecl _ _ _ (NewConstrDecl _ _ c _)) = [c]-> constrs _ = []--> vars :: Decl -> [Ident]-> vars (TypeSig p fs _) = fs-> vars (EvalAnnot p fs _) = fs-> vars (FunctionDecl p f _) = [f]-> vars (ExternalDecl p _ _ f _) = [f]-> vars (FlatExternalDecl p fs) = fs-> vars (PatternDecl p t _) = (bv t)-> vars (ExtraVariables p vs) = vs-> vars _ = []--> renameLiteral :: Literal -> RenameState Literal-> renameLiteral (Int v i) = liftM (flip Int i . renameIdent v) newId-> renameLiteral l = return l---Since the compiler expects all rules of the same function to be together,-it is necessary to sort the list of declarations.--> sortFuncDecls :: [Decl] -> [Decl]-> sortFuncDecls decls = sortFD Map.empty [] decls->  where->  sortFD env res [] = reverse res->  sortFD env res (decl:decls)->     = case decl of->	  FunctionDecl _ ident _->	     | isJust (Map.lookup ident env)->	       -> sortFD env (insertBy cmpFuncDecl decl res) decls->	     | otherwise->              -> sortFD (Map.insert ident () env) (decl:res) decls->	  _    -> sortFD env (decl:res) decls--> cmpFuncDecl :: Decl -> Decl -> Ordering-> cmpFuncDecl (FunctionDecl _ id1 _) (FunctionDecl _ id2 _)->    | id1 == id2 = EQ->    | otherwise  = GT-> cmpFuncDecl decl1 decl2 = GT--cmpPos :: Position -> Position -> Ordering-cmpPos p1 p2 | lp1 < lp2  = LT-             | lp1 == lp2 = EQ-             | otherwise  = GT- where lp1 = line p1-       lp2 = line p2---\end{verbatim}-Due to the lack of a capitalization convention in Curry, it is-possible that an identifier may ambiguously refer to a data-constructor and a function provided that both are imported from some-other module. When checking whether an identifier denotes a-constructor there are two options with regard to ambiguous-identifiers:-\begin{enumerate}-\item Handle the identifier as a data constructor if at least one of-  the imported names is a data constructor.-\item Handle the identifier as a data constructor only if all imported-  entities are data constructors.-\end{enumerate}-We choose the first possibility here because in the second case a-redefinition of a constructor can magically become possible if a-function with the same name is imported. It seems better to warn-the user about the fact that the identifier is ambiguous.-\begin{verbatim}--> isDataConstr :: Ident -> RenameEnv -> Bool-> isDataConstr v = any isConstr . lookupVar v . globalEnv . toplevelEnv--> isConstr :: RenameInfo -> Bool-> isConstr (Constr _) = True-> isConstr (GlobalVar _ _) = False-> isConstr (LocalVar _ _) = False-> isConstr (RecordLabel _ _) = False--> varIdent :: RenameInfo -> Ident-> varIdent (GlobalVar _ v) = unqualify v-> varIdent (LocalVar _ v) =  v-> varIdent _ = internalError "not a variable"--> qualVarIdent :: RenameInfo -> QualIdent-> qualVarIdent (GlobalVar _ v) = v-> qualVarIdent (LocalVar _ v) = qualify v-> qualVarIdent _ = internalError "not a qualified variable"--> arity :: RenameInfo -> Int-> arity (Constr n) = n-> arity (GlobalVar n _) = n-> arity (LocalVar n _) = n-> arity (RecordLabel _ ls) = length ls--\end{verbatim}-Unlike expressions, constructor terms have no possibility to represent-over-applications in function patterns. Therefore it is necessary to-transform them to nested-function patterns using the prelude function \texttt{apply}. E.g. the-the function pattern \texttt{(id id 10)} is transformed to-\texttt{(apply (id id) 10)}-\begin{verbatim}--> genFuncPattAppl :: ConstrTerm -> [ConstrTerm] -> ConstrTerm-> genFuncPattAppl term [] = term-> genFuncPattAppl term (t:ts) ->    = FunctionPattern qApplyId [genFuncPattAppl term ts, t]->  where->  qApplyId = qualifyWith preludeMIdent (mkIdent "apply")--\end{verbatim}-Miscellaneous functions.-\begin{verbatim}--> typeArity :: TypeExpr -> Int-> typeArity (ArrowType _ t2) = 1 + typeArity t2-> typeArity _                = 0--> getFlatLhs :: Equation -> (Ident,[ConstrTerm])-> getFlatLhs (Equation  _ lhs _) = flatLhs lhs--> dup :: Eq a => [a] -> Maybe a-> dup [] = Nothing-> dup (x:xs) | elem x xs = Just x->            | otherwise = dup xs--\end{verbatim}-Error messages.-\begin{verbatim}--> undefinedVariable :: QualIdent -> (Position,String)-> undefinedVariable v = ->     (positionOfQualIdent v,->      qualName v ++ " is undefined")--> undefinedData :: QualIdent -> (Position,String)-> undefinedData c =  ->     (positionOfQualIdent c,->      "Undefined data constructor " ++ qualName c)--> undefinedLabel :: Ident -> (Position,String)-> undefinedLabel l =   ->     (positionOfIdent l,->      "Undefined record label `" ++ name l ++ "`")--> ambiguousIdent :: [RenameInfo] -> QualIdent -> (Position,String)-> ambiguousIdent rs->   | any isConstr rs = ambiguousData->   | otherwise = ambiguousVariable--> ambiguousVariable :: QualIdent -> (Position,String)-> ambiguousVariable v =  ->     (positionOfQualIdent v,->      "Ambiguous variable " ++ qualName v)--> ambiguousData :: QualIdent -> (Position,String)-> ambiguousData c =  ->     (positionOfQualIdent c,->      "Ambiguous data constructor " ++ qualName c)--> duplicateDefinition :: Ident -> (Position,String)-> duplicateDefinition v =->     (positionOfIdent v,->      "More than one definition for `" ++ name v ++ "`")--> duplicateVariable :: Ident -> (Position,String)-> duplicateVariable v = ->     (positionOfIdent v,->      name v ++ " occurs more than once in pattern")--> duplicateData :: Ident -> (Position,String)-> duplicateData c = ->     (positionOfIdent c,->      "More than one definition for data constructor `"->	            ++ name c ++ "`")--> duplicateTypeSig :: Ident -> (Position,String)-> duplicateTypeSig v =  ->     (positionOfIdent v,->      "More than one type signature for `" ++ name v ++ "`")--> duplicateEvalAnnot :: Ident -> (Position,String)-> duplicateEvalAnnot v =   ->     (positionOfIdent v,->      "More than one eval annotation for `" ++ name v ++ "`")--> duplicateLabel :: Ident -> (Position,String)-> duplicateLabel l =   ->     (positionOfIdent l,->      "Multiple occurrence of record label `" ++ name l ++ "`")--> missingLabel :: Ident -> QualIdent -> String -> String -> missingLabel l r what = ->     "Missing label `" ++ name l ->     ++ "` in the " ++ what ++ " of `" ->     ++ name (unqualify r) ++ "`" --qualName r---> illegalLabel :: Ident -> QualIdent -> (Position,String)-> illegalLabel l r =   ->     (positionOfIdent l,->      "Label `" ++ name l ++ "` is not defined in record `" ->	     ++ name (unqualify r) ++ "`") --qualName r--> illegalRecordId :: Ident -> (Position,String)-> illegalRecordId r = ->    (positionOfIdent r,->     "Record identifier `" ++ name r ->	      ++ "` already assigned to a data constructor")--> nonVariable :: String -> Ident -> (Position,String)-> nonVariable what c = ->  (positionOfIdent c,     ->   "Data constructor `" ++ name c ++ "` in left hand side of " ++ what)--> noBody :: Ident -> (Position,String)-> noBody v = ->  (positionOfIdent v,     ->   "No body for `" ++ name v ++ "`")--> noTypeSig :: Ident -> (Position,String)-> noTypeSig f = ->  (positionOfIdent f,     ->   "No type signature for external function `" ++ name f ++ "`")--> noToplevelPattern :: String-> noToplevelPattern = "Pattern declaration not allowed at top-level"--> notALabel :: Ident -> (Position,String)-> notALabel l =  ->  (positionOfIdent l,     ->   "`" ++ name l ++ "` is not a record label")--> emptyRecord :: String-> emptyRecord = "empty records are not allowed"--> differentArity :: Ident -> (Position,String)-> differentArity f =   ->  (positionOfIdent f,     ->   "Equations for `" ++ name f ++ "` have different arities")--> wrongArity :: QualIdent -> Int -> Int -> (Position,String)-> wrongArity c arity argc =  ->  (positionOfQualIdent c,    ->   "Data constructor " ++ qualName c ++ " expects " ++ arguments arity ++->   " but is applied to " ++ show argc)->   where arguments 0 = "no arguments"->         arguments 1 = "1 argument"->         arguments n = show n ++ " arguments"--> illegalRecordPatt :: String-> illegalRecordPatt = "Expexting `_` after `|` in the record pattern"--> noFuncPattExt :: String-> noFuncPattExt = "function patterns are not supported in standard curry"->	        ++ extMessage--> noRecordExt :: String-> noRecordExt = "records are not supported in standard curry"->             ++ extMessage--> extMessage :: String-> extMessage = "\n(Use flag -e to enable extended curry)"--> infixWithoutParens :: [(QualIdent,QualIdent)] -> String-> infixWithoutParens calls =->     "Missing parens in infix patterns: \n" ++->     unlines (map (\(q1,q2) -> show q1 ++ " " ++ ->                               showLine (positionOfQualIdent q1) ++ ->                               "calls " ++ show q2 ++ " " ++ ->                               showLine (positionOfQualIdent q2)) calls)--\end{verbatim}--checkParen -@param Aufrufende InfixFunktion-@param ConstrTerm-@return Liste mit fehlerhaften Funktionsaufrufen-\begin{verbatim}--> checkParenConstrTerm :: (Maybe QualIdent) -> ConstrTerm -> [(QualIdent,QualIdent)]-> checkParenConstrTerm _ (LiteralPattern _) = []-> checkParenConstrTerm _ (NegativePattern _ _) = []-> checkParenConstrTerm _ (VariablePattern _) = []-> checkParenConstrTerm _ (ConstructorPattern qualIdent constrTerms) =->     concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm mCaller (InfixPattern constrTerm1 qualIdent constrTerm2) =->     maybe [] (\c -> [(c,qualIdent)]) mCaller ++->     checkParenConstrTerm Nothing constrTerm1 ++->     checkParenConstrTerm Nothing constrTerm2-> checkParenConstrTerm _ (ParenPattern constrTerm) =->     checkParenConstrTerm Nothing constrTerm-> checkParenConstrTerm _ (TuplePattern _ constrTerms) =->     concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm _ (ListPattern _ constrTerms) =->     concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm mCaller (AsPattern _ constrTerm) =->     checkParenConstrTerm mCaller constrTerm-> checkParenConstrTerm mCaller (LazyPattern _ constrTerm) =->     checkParenConstrTerm mCaller constrTerm-> checkParenConstrTerm _ (FunctionPattern _ constrTerms) =->     concatMap (checkParenConstrTerm Nothing) constrTerms-> checkParenConstrTerm mCaller (InfixFuncPattern constrTerm1 qualIdent constrTerm2) =->     maybe [] (\c -> [(c,qualIdent)]) mCaller ++->     checkParenConstrTerm Nothing constrTerm1 ++->     checkParenConstrTerm Nothing constrTerm2-> checkParenConstrTerm _ (RecordPattern fieldConstrTerms mConstrTerm) =  ->     maybe [] (checkParenConstrTerm Nothing) mConstrTerm ++->     concatMap (\(Field _ _ constrTerm) -> checkParenConstrTerm Nothing constrTerm) ->               fieldConstrTerms--\end{verbatim}
− src/SyntaxColoring.hs
@@ -1,800 +0,0 @@-module SyntaxColoring (Program,Code(..),TypeKind(..),ConstructorKind(..),-                       IdentifierKind(..),FunctionKind(..), genProgram,-                       code2string,getQualIdent, position2code,-                       area2codes) where--import Debug.Trace-import Data.Function(on)--import Data.Maybe-import Data.Either-import Data.List-import Data.Char hiding(Space)--import Curry.Base.Position-import Curry.Base.Ident-import Curry.Base.MessageMonad-import Curry.Syntax -import Curry.Syntax.Lexer----debug = False -- mergen von Token und Codes--trace' s x = if debug then trace s x else x---debug' = False -- messages--trace'' s x = if debug' then trace s x else x--type Program = [(Int,Int,Code)] --data Code =  Keyword String-           | Space Int-           | NewLine-           | ConstructorName  ConstructorKind QualIdent-           | TypeConstructor  TypeKind QualIdent-           | Function FunctionKind QualIdent-           | ModuleName ModuleIdent-           | Commentary String-           | NumberCode String-           | StringCode String-           | CharCode String-           | Symbol String-           | Identifier IdentifierKind QualIdent-           | CodeWarning [WarnMsg] Code-           | NotParsed String-             deriving Show-           -data TypeKind = TypeDecla-              | TypeUse-              | TypeExport deriving Show          --data ConstructorKind = ConstrPattern-                     | ConstrCall-                     | ConstrDecla-                     | OtherConstrKind deriving Show-                     -data IdentifierKind = IdDecl-                    | IdOccur-                    | UnknownId  deriving Show         -                      -data FunctionKind = InfixFunction-                  | TypSig-                  | FunDecl-                  | FunctionCall-                  | OtherFunctionKind deriving Show      -                  -                  -     -        ---- @param plaintext---- @param list with parse-Results with descending quality  e.g. [typingParse,fullParse,parse]                                        ---- @param lex-Result---- @return program-genProgram :: String -> [MsgMonad Module] -> MsgMonad [(Position,Token)] -> Program       -genProgram plainText parseResults m-    = case runMsg m of-        (Left e, msgs) -> buildMessagesIntoPlainText (e : msgs) plainText-        (Right posNtokList, mess) -            -> let messages = (prepareMessages (concatMap getMessages parseResults ++ mess))-                   mergedMessages = (mergeMessages' (trace' ("Messages: " ++ show messages) messages) posNtokList)-                   (nameList,codes) = catIdentifiers parseResults-               in tokenNcodes2codes nameList 1 1 mergedMessages codes--    ---- @param Program---- @param line---- @param col---- @return Code at this Position                  -position2code :: Program -> Int -> Int -> Maybe Code                 -position2code []  _ _ = Nothing-position2code [_] _ _ = Nothing-position2code ((l,c,code):xs@((_,c2,_):_)) line col-     | line == l && col >= c && col < c2 = Just code-     | l > line = Nothing-     | otherwise = position2code xs line col-     -area2codes :: Program -> Position -> Position -> [Code]     -area2codes [] _ _ = []-area2codes xxs@((l,c,code):xs) p1@Position{file=file} p2 -     | p1 > p2 = area2codes xxs p2 p1-     | posEnd >= p1 && posBegin <= p2  = code : area2codes xs p1 p2-     | posBegin > p2 = []-     | otherwise = area2codes xs p1 p2-   where-      posBegin = Position file l c noRef-      posEnd   = Position file l (c + length (code2string code)) noRef-                  -  ---- @param code---- @return qualIdent if available                   -getQualIdent :: Code -> Maybe QualIdent-getQualIdent (ConstructorName _ qualIdent) = Just qualIdent-getQualIdent (Function _ qualIdent) = Just qualIdent-getQualIdent (Identifier _ qualIdent) = Just qualIdent                      -getQualIdent (TypeConstructor _ qualIdent) = Just qualIdent-getQualIdent  _ = Nothing                  -                  -                    --- DEBUGGING----------- wird bald nicht mehr gebraucht--setMessagePosition :: WarnMsg -> WarnMsg-setMessagePosition m@(WarnMsg (Just p) _) = trace'' ("pos:" ++ show p ++ ":" ++ show m) m-setMessagePosition (WarnMsg _ m) = -        let mes@(WarnMsg pos _) =  (WarnMsg (getPositionFromString m) m) in-        trace'' ("pos:" ++ show pos ++ ":" ++ show mes) mes--getPositionFromString :: String -> Maybe Position-getPositionFromString message =-     if line > 0 && col > 0 -          then Just Position{file=file,line=line,column=col,astRef=noRef}-          else Nothing-  where-      file = takeWhile (/= '"') (tail (dropWhile (/= '"') message))-      line = readInt (takeWhile (/= '.') (drop 7 (dropWhile (/= ',') message)))-      col = readInt (takeWhile (/= ':') (tail (dropWhile (/= '.') (drop 7 (dropWhile (/= ',') message)))))-      -     -readInt :: String -> Int -readInt s = -      let onlyNum = filter isDigit s in-      if null onlyNum-         then 0-         else read onlyNum :: Int---- ---------------------------  ---- ----------------------------flatCode :: Code -> Code-flatCode (CodeWarning _ code) = code-flatCode code = code-             --                 --- ----------Message---------------------------------------                  -                  --getMessages :: MsgMonad a -> [WarnMsg]-getMessages = snd . runMsg --(Result mess _) = mess--- getMessages (Failure mess) = mess--lessMessage :: WarnMsg -> WarnMsg -> Bool-lessMessage (WarnMsg mPos1 _) (WarnMsg mPos2 _) = mPos1 < mPos2--nubMessages :: [WarnMsg] -> [WarnMsg] -nubMessages = nubBy eqMessage--eqMessage :: WarnMsg -> WarnMsg -> Bool-eqMessage (WarnMsg p1 s1) (WarnMsg p2 s2) = (p1 == p2) && (s1 == s2)--prepareMessages :: [WarnMsg] -> [WarnMsg]   -prepareMessages = qsort lessMessage . map setMessagePosition . nubMessages---buildMessagesIntoPlainText :: [WarnMsg] -> String -> Program-buildMessagesIntoPlainText messages text = -    buildMessagesIntoPlainText' messages (lines text) [] 1- where-    buildMessagesIntoPlainText' :: [WarnMsg] -> [String] -> [String] -> Int -> Program-    buildMessagesIntoPlainText' _ [] [] _ = -          []-    buildMessagesIntoPlainText' _ [] postStrs line = -          [(line,1,NotParsed (unlines postStrs))]    -    buildMessagesIntoPlainText' [] preStrs postStrs line = -          [(line,1,NotParsed (unlines (preStrs ++ postStrs)))]  -            -    buildMessagesIntoPlainText' messages (str:preStrs) postStrs ln = -          let (pre,post) = partition isLeq messages in-          if null pre -             then buildMessagesIntoPlainText' post preStrs (postStrs ++ [str]) (ln + 1)-             else (ln,1,NotParsed (unlines postStrs)) : -                  (ln,1,CodeWarning pre (NotParsed str)) :-                  (ln,1,NewLine) :-                  buildMessagesIntoPlainText' post preStrs [] (ln + 1)-      where -         isLeq (WarnMsg (Just p) _) = line p <= ln -         isLeq _ = True-                -        -        --     ---- @param parse-Modules  [typingParse,fullParse,parse] -catIdentifiers :: [MsgMonad Module] -> ([(ModuleIdent,ModuleIdent)],[Code])-catIdentifiers = catIds . rights_sc . map (fst . runMsg)-    where -      catIds [] = ([],[])-      catIds [m] =-          catIdentifiers' m Nothing-      catIds rs@(m:y:ys) =  -          catIdentifiers' (last rs) (Just m)-    --- not in base befoer base4--rights_sc  xs = [ x | Right x <- xs]----- @param parse-Module---- @param Maybe betterParse-Module    -catIdentifiers' :: Module -> Maybe Module -> ([(ModuleIdent,ModuleIdent)],[Code])-catIdentifiers' (Module moduleIdent maybeExportSpec decls)-                Nothing =-      let codes = (concatMap decl2codes (qsort lessDecl decls)) in-      (concatMap renamedImports decls,      -      ModuleName moduleIdent :-       maybe [] exportSpec2codes maybeExportSpec ++ codes)-catIdentifiers' (Module moduleIdent maybeExportSpec1 _)-                (Just (Module _ maybeExportSpec2 decls)) =-      let codes = (concatMap decl2codes (qsort lessDecl decls)) in-      (concatMap renamedImports decls,-      replaceFunctionCalls $ -        map (addModuleIdent moduleIdent)-          ([ModuleName moduleIdent] ++-           mergeExports2codes  -              (maybe [] (\(Exporting _ i) -> i)  maybeExportSpec1)-              (maybe [] (\(Exporting _ i) -> i)  maybeExportSpec2) ++-           codes))     -  -     -renamedImports :: Decl -> [(ModuleIdent,ModuleIdent)]-renamedImports decl =-    case decl of-        (ImportDecl _ oldName _ (Just newName) _) -> [(oldName,newName)]-        _ -> []-   -                      -replaceFunctionCalls :: [Code] -> [Code]                  -replaceFunctionCalls codes = map (idOccur2functionCall qualIdents) codes-   where-      qualIdents = findFunctionDecls codes-                                              --findFunctionDecls :: [Code] -> [QualIdent]-findFunctionDecls  =  mapMaybe getQualIdent . -                      filter isFunctionDecl .                       -                      map flatCode                   --isFunctionDecl  :: Code -> Bool-isFunctionDecl  (Function FunDecl _)  = True-isFunctionDecl  _ = False  --idOccur2functionCall :: [QualIdent] -> Code -> Code-idOccur2functionCall qualIdents ide@(Identifier IdOccur qualIdent)  -   | isQualified qualIdent = Function FunctionCall qualIdent-   | elem qualIdent qualIdents = Function FunctionCall qualIdent-   | otherwise = ide-idOccur2functionCall qualIdents (CodeWarning mess code) =-       CodeWarning mess (idOccur2functionCall qualIdents code)-idOccur2functionCall _ code = code-  --addModuleIdent :: ModuleIdent -> Code -> Code-addModuleIdent moduleIdent c@(Function x qualIdent) -    | uniqueId (unqualify qualIdent) == 0 =-        Function x (qualQualify moduleIdent qualIdent)-    | otherwise = c-addModuleIdent moduleIdent cn@(ConstructorName x qualIdent) -    | not $ isQualified qualIdent =-        ConstructorName x (qualQualify moduleIdent qualIdent)-    | otherwise = cn       -addModuleIdent moduleIdent tc@(TypeConstructor TypeDecla qualIdent) -    | not $ isQualified qualIdent =-        TypeConstructor TypeDecla (qualQualify moduleIdent qualIdent)-    | otherwise = tc         -addModuleIdent moduleIdent (CodeWarning mess code) =-    CodeWarning mess (addModuleIdent moduleIdent code)-addModuleIdent _ c = c-                        --- ------------------------------------------mergeMessages' :: [WarnMsg] -> [(Position,Token)] -> [([WarnMsg],Position,Token)]-mergeMessages' _ [] = []-mergeMessages' [] ((p,t):ps) = ([],p,t) : mergeMessages' [] ps-mergeMessages' mss@(m@(WarnMsg mPos x):ms) ((p,t):ps)  -    | mPos <= Just p = trace' (show mPos ++ " <= " ++ show (Just p) ++ " Message: " ++ x) ([m],p,t) : mergeMessages' ms ps -    | otherwise = ([],p,t) : mergeMessages' mss ps---tokenNcodes2codes :: [(ModuleIdent,ModuleIdent)] -> Int -> Int -> [([WarnMsg],Position,Token)] -> [Code] -> [(Int,Int,Code)]-tokenNcodes2codes _ _ _ [] _ = []          -tokenNcodes2codes nameList currLine currCol toks@((messages,pos@Position{line=line,column=col},token):ts) codes -    | currLine < line = -           trace' " NewLine: "-           ((currLine,currCol,NewLine) :-           tokenNcodes2codes nameList (currLine + 1) 1 toks codes)-    | currCol < col =  -           trace' (" Space " ++ show (col - currCol))-           ((currLine,currCol,Space (col - currCol)) :         -           tokenNcodes2codes nameList currLine col toks codes)-    | isTokenIdentifier token && null codes =    -           trace' ("empty Code-List, Token: " ++ show (line,col) ++ show token)-           (addMessage [(currLine,currCol,NotParsed tokenStr)] ++ tokenNcodes2codes nameList newLine newCol ts codes)-    | not (isTokenIdentifier token) = -           trace' (" Token ist kein Identifier: " ++ tokenStr ) -           (addMessage [(currLine,currCol,token2code token)] ++ tokenNcodes2codes nameList newLine newCol ts codes) -    | tokenStr == code2string (head codes) =-           trace' (" Code wird genommen: " ++ show (head codes) )-           (addMessage [(currLine,currCol,head codes)] ++ tokenNcodes2codes nameList newLine newCol ts (tail codes)) -    | tokenStr == code2qualString (renameModuleIdents nameList (head codes)) =-           let mIdent = maybe Nothing rename (getModuleIdent (head codes)) -               lenMod = maybe 0 (length . moduleName) mIdent-               startPos = maybe currCol (const (currCol + lenMod + 1)) mIdent-               symbol = [(currLine,currCol + lenMod,Symbol ".")]               -               prefix = maybe [] -                              ( (: symbol) . -                                ( \i -> (currLine,-                                         currCol,-                                         ModuleName i))) -                              mIdent in-           trace' (" Code wird genommen: " ++ show (head codes) )-           (addMessage (prefix ++ [(currCol,startPos,head codes)]) ++ tokenNcodes2codes nameList newLine newCol ts (tail codes))           -    | elem tokenStr (codeQualifiers (head codes)) =-           trace' (" Token: "++ tokenStr ++" ist Modulname von: " ++ show (head codes) )-           (addMessage [(currLine,currCol,ModuleName (mkMIdent [tokenStr]))] ++ -                    tokenNcodes2codes nameList newLine newCol ts codes)                  -    | otherwise = -           trace' (" Token: "++ -                   tokenStr ++-                   ",Code faellt weg:" ++ -                   code2string (head codes) ++ -                   "|" ++ -                   code2qualString (head codes))-           (tokenNcodes2codes nameList currLine currCol toks (tail codes))-  where-      tokenStr = token2string token            -      newLine  = (currLine + length (lines tokenStr)) - 1 -      newCol   = currCol + length tokenStr   --      rename mid = Just $ fromMaybe mid (lookup mid nameList)--      addMessage [] = []-      addMessage ((l,c,code):cs)-         | null messages = (l,c,code):cs-         | otherwise = trace' ("Warning bei code: " ++ show codes ++ ":" ++ show messages) -                              ((l,c,CodeWarning messages code): addMessage cs)-      -      -renameModuleIdents :: [(ModuleIdent,ModuleIdent)] -> Code -> Code-renameModuleIdents nameList c =-    case c of-        Function x qualIdent -> Function x (rename qualIdent (qualidMod qualIdent))-        Identifier x qualIdent -> Identifier x (rename qualIdent (qualidMod qualIdent))-        _ -> c-  where-    rename x (Nothing) = x-    rename x (Just m) = maybe x (\ m' -> qualifyWith m' (qualidId x)) (lookup m nameList)-           -{--codeWithoutUniqueID ::  Code -> String-codeWithoutUniqueID code = maybe (code2string code) (name . unqualify) $ getQualIdent code-     --codeUnqualify :: Code -> Code-codeUnqualify code = maybe code (setQualIdent code . qualify . unqualify)  $ getQualIdent code  --}  -          -codeQualifiers :: Code -> [String]-codeQualifiers = maybe [] moduleQualifiers . getModuleIdent--getModuleIdent :: Code -> Maybe ModuleIdent-getModuleIdent (ConstructorName _ qualIdent) = qualidMod qualIdent-getModuleIdent (Function _ qualIdent) = qualidMod qualIdent-getModuleIdent (ModuleName moduleIdent) = Just moduleIdent-getModuleIdent (Identifier _ qualIdent) = qualidMod qualIdent                     -getModuleIdent (TypeConstructor _ qualIdent) = qualidMod qualIdent-getModuleIdent _ = Nothing---  -{--setQualIdent :: Code -> QualIdent -> Code-setQualIdent (Keyword str) _ = (Keyword str)-setQualIdent (Space i) _ = (Space i)-setQualIdent NewLine _ = NewLine-setQualIdent (ConstructorName kind _) qualIdent = (ConstructorName kind qualIdent)-setQualIdent (Function kind _) qualIdent = (Function kind qualIdent)-setQualIdent (ModuleName moduleIdent) _ = (ModuleName moduleIdent)-setQualIdent (Commentary str) _ = (Commentary str)-setQualIdent (NumberCode str) _ = (NumberCode str)-setQualIdent (Symbol str) _ = (Symbol str)-setQualIdent (Identifier kind _) qualIdent = (Identifier kind qualIdent)                      -setQualIdent (TypeConstructor kind _) qualIdent = (TypeConstructor kind qualIdent)-setQualIdent (StringCode str) _ = (StringCode str)                                 -setQualIdent (CharCode str) _ = (CharCode str)             --}-                  -code2string (Keyword str) = str-code2string (Space i)= concat (replicate i " ")-code2string NewLine = "\n"-code2string (ConstructorName _ qualIdent) = name $ unqualify qualIdent-code2string (Function _ qualIdent) = name $ unqualify qualIdent-code2string (ModuleName moduleIdent) = moduleName moduleIdent-code2string (Commentary str) = str-code2string (NumberCode str) = str-code2string (Symbol str) = str-code2string (Identifier _ qualIdent) = name $ unqualify qualIdent                      -code2string (TypeConstructor _ qualIdent) = name $ unqualify qualIdent-code2string (StringCode str) = str                                 -code2string (CharCode str) = str-code2string (NotParsed str) = str-code2string _ = "" -- error / warning- -code2qualString (ConstructorName _ qualIdent) = qualName qualIdent-code2qualString (Function _ qualIdent) = qualName qualIdent-code2qualString (Identifier _ qualIdent) = qualName qualIdent                      -code2qualString (TypeConstructor _ qualIdent) = qualName qualIdent-code2qualString x = code2string x----token2code :: Token -> Code-token2code tok@(Token cat _)-    | elem cat [IntTok,FloatTok,IntegerTok]-         = NumberCode (token2string tok)-    | elem cat [KW_case,KW_choice,KW_data,KW_do,KW_else,KW_eval,KW_external,-                KW_free,KW_if,KW_import,KW_in,KW_infix,KW_infixl,KW_infixr,-                KW_let,KW_module,KW_newtype,KW_of,KW_rigid,KW_then,KW_type,-                KW_where,Id_as,Id_ccall,Id_forall,Id_hiding,Id_interface,Id_primitive,-                Id_qualified]-         =  Keyword (token2string tok)-    | elem cat [LeftParen,RightParen,Semicolon,LeftBrace,RightBrace,LeftBracket,-                RightBracket,Comma,Underscore,Backquote,-                At,Colon,DotDot,DoubleColon,Equals,Backslash,Bar,LeftArrow,RightArrow,-                Tilde]-         = Symbol (token2string tok)-    | elem cat [LineComment, NestedComment]-         = Commentary (token2string tok)-    | isTokenIdentifier tok-         = Identifier UnknownId $ qualify $ mkIdent $ token2string tok-    | cat == StringTok -         = StringCode (token2string tok)-    | cat == CharTok-         = CharCode (token2string tok)          -    | elem cat [EOF,VSemicolon,VRightBrace] = Space 0 -    -isTokenIdentifier :: Token -> Bool-isTokenIdentifier (Token cat _) = -  elem cat [Id,QId,Sym,QSym,Sym_Dot,Sym_Minus,Sym_MinusDot]-    --- DECL Position--getPosition :: Decl -> Position-getPosition (ImportDecl pos _ _ _ _) = pos     -getPosition (InfixDecl pos _ _ _) = pos     -getPosition (DataDecl pos _ _ _) = pos     -getPosition (NewtypeDecl pos _ _ _) = pos-getPosition (TypeDecl pos _ _ _) = pos   -getPosition (TypeSig pos _ _) = pos    -getPosition (EvalAnnot pos _ _) = pos-getPosition (FunctionDecl pos _ _) = pos    -getPosition (ExternalDecl pos _ _ _ _) = pos-getPosition (FlatExternalDecl pos _) = pos    -getPosition (PatternDecl pos _ _) = pos    -getPosition (ExtraVariables pos _) = pos-             --lessDecl :: Decl -> Decl -> Bool-lessDecl = (<) `on` getPosition--qsort _ []     = []-qsort less (x:xs) = qsort less [y | y <- xs, less y x] ++ [x] ++ qsort less [y | y <- xs, not $ less y x]------ DECL TO CODE -------------------------------------------------------------------- ----exportSpec2codes ::  ExportSpec -> [Code]-exportSpec2codes (Exporting _ exports) = concatMap (export2codes [])  exports----- @param parse-Exports---- @param betterParse-Exports-mergeExports2codes :: [Export] -> [Export]  -> [Code]-mergeExports2codes [] _ = []-mergeExports2codes (e:es) xs = concatMap (export2codes xs)  (e:es)---export2codes :: [Export] -> Export -> [Code]-export2codes exports e@(Export qualIdent) -    | length (filter checkDouble exports) /= 1 =      -       [Identifier UnknownId qualIdent]-    | otherwise =-       let [export] = (filter checkDouble exports) in-       export2c export     -  where    -    checkDouble (ExportTypeWith q _) = eqQualIdent qualIdent q-    checkDouble (Export q) = eqQualIdent qualIdent q-    checkDouble _ = False-    -    eqQualIdent q1 q2 -      | q1 == q2 = True-      | not (isQualified q1) = unqualify q1 == unqualify q2-      | otherwise = False-      -    export2c (Export qualIdent) = -         [Function OtherFunctionKind qualIdent]-    export2c _ = -         [TypeConstructor TypeExport qualIdent]-         -    -    -       -export2codes _ (ExportTypeWith qualIdent idents) = -     TypeConstructor TypeExport qualIdent : map (Function OtherFunctionKind . qualify) idents-export2codes _ (ExportTypeAll  qualIdent) = -     [TypeConstructor TypeExport qualIdent]  -export2codes _ (ExportModule moduleIdent) = -     [ModuleName moduleIdent]--decl2codes :: Decl -> [Code]            -decl2codes (ImportDecl _ moduleIdent xQualified mModuleIdent importSpec) = -     [ModuleName moduleIdent] ++-     maybe [] ((:[]) . ModuleName) mModuleIdent ++-     maybe [] (importSpec2codes moduleIdent)  importSpec-decl2codes (InfixDecl _ _ _ idents) =-     map (Function InfixFunction . qualify) idents-decl2codes (DataDecl _ ident idents constrDecls) =-     TypeConstructor TypeDecla (qualify ident) : -     map (Identifier UnknownId . qualify) idents ++-     concatMap constrDecl2codes constrDecls-decl2codes (NewtypeDecl xPosition xIdent yIdents xNewConstrDecl) =-     []-decl2codes (TypeDecl _ ident idents typeExpr) =-     TypeConstructor TypeDecla (qualify ident) : -     map (Identifier UnknownId . qualify) idents ++ -     typeExpr2codes typeExpr-decl2codes (TypeSig _ idents typeExpr) =-     map (Function TypSig . qualify) idents ++ typeExpr2codes typeExpr   -decl2codes (EvalAnnot xPosition idents xEvalAnnotation) =-     map (Function FunDecl . qualify) idents-decl2codes (FunctionDecl _ _ equations) =-     concatMap equation2codes equations  -decl2codes (ExternalDecl xPosition xCallConv xString xIdent xTypeExpr) =-     []-decl2codes (FlatExternalDecl _ idents) =-     map (Function FunDecl . qualify) idents   -decl2codes (PatternDecl xPosition constrTerm rhs) =-     constrTerm2codes constrTerm ++ rhs2codes rhs-decl2codes (ExtraVariables _ idents) =-     map (Identifier IdDecl . qualify) idents-  -equation2codes :: Equation -> [Code]-equation2codes (Equation _ lhs rhs) =-     lhs2codes lhs ++ rhs2codes rhs-     -lhs2codes :: Lhs -> [Code]-lhs2codes (FunLhs ident constrTerms) =-    Function FunDecl (qualify ident) : concatMap constrTerm2codes constrTerms-lhs2codes (OpLhs constrTerm1 ident constrTerm2) =-    constrTerm2codes constrTerm1 ++ [Function FunDecl $ qualify ident] ++ constrTerm2codes constrTerm2-lhs2codes (ApLhs lhs constrTerms) =-    lhs2codes lhs ++ concatMap constrTerm2codes constrTerms     --rhs2codes :: Rhs -> [Code]-rhs2codes (SimpleRhs _ expression decls) =-    expression2codes expression ++ concatMap decl2codes decls-rhs2codes (GuardedRhs condExprs decls) =-    concatMap condExpr2codes condExprs ++ concatMap decl2codes decls-    -condExpr2codes :: CondExpr -> [Code]-condExpr2codes (CondExpr _ expression1 expression2) =   -   expression2codes expression1 ++ expression2codes expression2    -    -constrTerm2codes :: ConstrTerm -> [Code]-constrTerm2codes (LiteralPattern literal) = []-constrTerm2codes (NegativePattern ident literal) = []-constrTerm2codes (VariablePattern ident) = [Identifier IdDecl (qualify ident)]-constrTerm2codes (ConstructorPattern qualIdent constrTerms) =-    ConstructorName ConstrPattern qualIdent : concatMap constrTerm2codes constrTerms-constrTerm2codes (InfixPattern constrTerm1 qualIdent constrTerm2) =-    constrTerm2codes constrTerm1 ++ [ConstructorName ConstrPattern qualIdent] ++ constrTerm2codes constrTerm2-constrTerm2codes (ParenPattern constrTerm) = constrTerm2codes constrTerm-constrTerm2codes (TuplePattern _ constrTerms) = concatMap constrTerm2codes constrTerms-constrTerm2codes (ListPattern _ constrTerms) = concatMap constrTerm2codes constrTerms-constrTerm2codes (AsPattern ident constrTerm) =-    Function OtherFunctionKind (qualify ident) : constrTerm2codes constrTerm-constrTerm2codes (LazyPattern _ constrTerm) = constrTerm2codes constrTerm-constrTerm2codes (FunctionPattern qualIdent constrTerms) = -    Function OtherFunctionKind qualIdent : concatMap constrTerm2codes constrTerms-constrTerm2codes (InfixFuncPattern constrTerm1 qualIdent constrTerm2) =-    constrTerm2codes constrTerm1 ++ [Function InfixFunction qualIdent] ++ constrTerm2codes constrTerm2-   -expression2codes :: Expression -> [Code]-expression2codes (Literal literal) = []-expression2codes (Variable qualIdent) = -    [Identifier IdOccur qualIdent]-expression2codes (Constructor qualIdent) = -    [ConstructorName ConstrCall qualIdent]-expression2codes (Paren expression) = -    expression2codes expression-expression2codes (Typed expression typeExpr) = -    expression2codes expression ++ typeExpr2codes typeExpr-expression2codes (Tuple _ expressions) = -    concatMap expression2codes expressions-expression2codes (List _ expressions) = -    concatMap expression2codes expressions-expression2codes (ListCompr _ expression statements) = -    expression2codes expression ++ concatMap statement2codes statements-expression2codes (EnumFrom expression) = -    expression2codes expression-expression2codes (EnumFromThen expression1 expression2) = -    expression2codes expression1 ++ expression2codes expression2-expression2codes (EnumFromTo expression1 expression2) = -    expression2codes expression1 ++ expression2codes expression2-expression2codes (EnumFromThenTo expression1 expression2 expression3) = -    expression2codes expression1 ++ -    expression2codes expression2 ++ -    expression2codes expression3-expression2codes (UnaryMinus ident expression) = -    Symbol (name ident) : expression2codes expression -expression2codes (Apply expression1 expression2) = -    expression2codes expression1 ++ expression2codes expression2-expression2codes (InfixApply expression1 infixOp expression2) = -    expression2codes expression1 ++ infixOp2codes infixOp ++ expression2codes expression2-expression2codes (LeftSection expression infixOp) = -    expression2codes expression ++ infixOp2codes infixOp-expression2codes (RightSection infixOp expression) = -    infixOp2codes infixOp ++ expression2codes expression-expression2codes (Lambda _ constrTerms expression) = -    concatMap constrTerm2codes constrTerms ++ expression2codes expression-expression2codes (Let decls expression) = -    concatMap decl2codes decls ++ expression2codes expression-expression2codes (Do statements expression) = -    concatMap statement2codes statements ++ expression2codes expression-expression2codes (IfThenElse _ expression1 expression2 expression3) = -    expression2codes expression1 ++ expression2codes expression2 ++ expression2codes expression3-expression2codes (Case _ expression alts) = -    expression2codes expression ++ concatMap alt2codes alts-    -infixOp2codes :: InfixOp -> [Code]-infixOp2codes (InfixOp qualIdent) = [Function InfixFunction qualIdent]-infixOp2codes (InfixConstr qualIdent) = [ConstructorName OtherConstrKind qualIdent]---statement2codes :: Statement -> [Code] -statement2codes (StmtExpr _ expression) =-    expression2codes expression-statement2codes (StmtDecl decls) =-    concatMap decl2codes decls-statement2codes (StmtBind _ constrTerm expression) =-     constrTerm2codes constrTerm ++ expression2codes expression---alt2codes :: Alt -> [Code]-alt2codes (Alt _ constrTerm rhs) =-    constrTerm2codes constrTerm ++ rhs2codes rhs-         -constrDecl2codes :: ConstrDecl -> [Code]-constrDecl2codes (ConstrDecl _ idents ident typeExprs) =-    ConstructorName ConstrDecla (qualify ident) : concatMap typeExpr2codes typeExprs-constrDecl2codes (ConOpDecl _ idents typeExpr1 ident typeExpr2) =   -    typeExpr2codes typeExpr1 ++ [ConstructorName ConstrDecla $ qualify ident] ++ typeExpr2codes typeExpr2--         -importSpec2codes :: ModuleIdent -> ImportSpec -> [Code]-importSpec2codes moduleIdent (Importing _ imports) = concatMap (import2codes moduleIdent) imports-importSpec2codes moduleIdent (Hiding _ imports) = concatMap (import2codes moduleIdent) imports--import2codes :: ModuleIdent -> Import -> [Code]-import2codes moduleIdent (Import ident) =-     [Function OtherFunctionKind $ qualifyWith moduleIdent ident]  -import2codes moduleIdent (ImportTypeWith ident idents) = -     ConstructorName OtherConstrKind (qualifyWith moduleIdent ident) :-     map (Function OtherFunctionKind . qualifyWith moduleIdent) idents-import2codes moduleIdent (ImportTypeAll  ident) = -     [ConstructorName OtherConstrKind $ qualifyWith moduleIdent ident]  -     -typeExpr2codes :: TypeExpr -> [Code]     -typeExpr2codes (ConstructorType qualIdent typeExprs) = -    TypeConstructor TypeUse qualIdent : concatMap typeExpr2codes typeExprs-typeExpr2codes (VariableType ident) = -    [Identifier IdOccur (qualify ident)]-typeExpr2codes (TupleType typeExprs) = -    concatMap typeExpr2codes typeExprs-typeExpr2codes (ListType typeExpr) = -    typeExpr2codes typeExpr-typeExpr2codes (ArrowType typeExpr1 typeExpr2) = -    typeExpr2codes typeExpr1 ++ typeExpr2codes typeExpr2---- TOKEN TO STRING --------------------------------------------------------------token2string (Token Id a) = attributes2string a-token2string (Token QId a) = attributes2string a-token2string (Token Sym a) = attributes2string a-token2string (Token QSym a) = attributes2string a-token2string (Token IntTok a) = attributes2string a-token2string (Token FloatTok a) = attributes2string a-token2string (Token CharTok a) = attributes2string a-token2string (Token IntegerTok a) = attributes2string a-token2string (Token StringTok a) = attributes2string a-token2string (Token LeftParen _) = "("-token2string (Token RightParen _) = ")"-token2string (Token Semicolon _) = ";"-token2string (Token LeftBrace _) = "{"-token2string (Token RightBrace _) = "}"-token2string (Token LeftBracket _) = "["-token2string (Token RightBracket _) = "]"-token2string (Token Comma _) = ","-token2string (Token Underscore _) = "_"-token2string (Token Backquote _) = "`"-token2string (Token VSemicolon _) = ""-token2string (Token VRightBrace _) = ""-token2string (Token At _) = "@"-token2string (Token Colon _) = ":"-token2string (Token DotDot _) = ".."-token2string (Token DoubleColon _) = "::"-token2string (Token Equals _) = "="-token2string (Token Backslash _) = "\\"-token2string (Token Bar _) = "|"-token2string (Token LeftArrow _) = "<-"-token2string (Token RightArrow _) = "->"-token2string (Token Tilde _) = "~"-token2string (Token Sym_Dot _) = "."-token2string (Token Sym_Minus _) = "-"-token2string (Token Sym_MinusDot _) = "-."-token2string (Token KW_case _) = "case"-token2string (Token KW_choice _) = "choice"-token2string (Token KW_data _) = "data"-token2string (Token KW_do _) = "do"-token2string (Token KW_else _) = "else"-token2string (Token KW_eval _) = "eval"-token2string (Token KW_external _) = "external"-token2string (Token KW_free _) = "free"-token2string (Token KW_if _) = "if"-token2string (Token KW_import _) = "import"-token2string (Token KW_in _) = "in"-token2string (Token KW_infix _) = "infix"-token2string (Token KW_infixl _) = "infixl"-token2string (Token KW_infixr _) = "infixr"-token2string (Token KW_let _) = "let"-token2string (Token KW_module _) = "module"-token2string (Token KW_newtype _) = "newtype"-token2string (Token KW_of _) = "of"-token2string (Token KW_rigid _) = "rigid"-token2string (Token KW_then _) = "then"-token2string (Token KW_type _) = "type"-token2string (Token KW_where _) = "where"-token2string (Token Id_as _) = "as"-token2string (Token Id_ccall _) = "ccall"-token2string (Token Id_forall _) = "forall"-token2string (Token Id_hiding _) = "hiding"-token2string (Token Id_interface _) = "interface"-token2string (Token Id_primitive _) = "primitive"-token2string (Token Id_qualified _) = "qualified"-token2string (Token EOF _) = ""-token2string (Token LineComment (StringAttributes sval _)) = sval-token2string (Token NestedComment (StringAttributes sval _)) = sval--attributes2string NoAttributes = ""-attributes2string (CharAttributes cval _) = showCh cval -attributes2string (IntAttributes ival _) = show ival-attributes2string (FloatAttributes fval _) = show fval-attributes2string (IntegerAttributes intval _) = show intval-attributes2string (StringAttributes sval _) = showSt sval -attributes2string (IdentAttributes mIdent ident) =concat (intersperse "." (mIdent ++ [ident])) ---showCh c    -   | c == '\\' = "'\\\\'"-   | elem c ('\127' : ['\001' .. '\031']) = show c-   | otherwise = toString c-  where-    toString c = '\'' : c : "'"--showSt = addQuotes . concatMap toGoodChar -   where-      addQuotes x = "\"" ++ x ++ "\""--toGoodChar c     -   | c == '\\' = "\\\\"-   | elem c ('\127' : ['\001' .. '\031']) = justShow c-   | c == '"' = "\\\""-   | otherwise = c : "" - where-     justShow = init . tail . show
+ src/TokenStream.hs view
@@ -0,0 +1,142 @@+{- |+    Module      :  $Header$+    Description :  Generating List of Tokens and Spans+    Copyright   :  (c) 2015 - 2016, Katharina Rahf+                       2015 - 2016, Björn Peemöller+                       2015 - 2016, Jan Tikovsky++    This module defines a function for writing the list of tokens+    and spans of a Curry source module into a separate file.+-}++module TokenStream (showTokenStream) where++import Data.List             (intercalate)++import Curry.Base.Position   (Position (..))+import Curry.Base.Span       (Span (..))+import Curry.Syntax          (Token (..), Category (..), Attributes (..))++-- |Show a list of 'Span' and 'Token' tuples.+-- The list is split into one tuple on each line to increase readability.+showTokenStream :: [(Span, Token)] -> String+showTokenStream [] = "[]\n"+showTokenStream ts = "[ " ++ intercalate "\n, " (map showST filteredTs) ++ "\n]\n"+  where filteredTs     = filter (not . isVirtual) ts+        showST (sp, t) = "(" ++ showSpan sp ++ ", " ++ showToken t ++ ")"++isVirtual :: (Span, Token) -> Bool+isVirtual (_, Token cat _) = cat `elem` [EOF, VRightBrace, VSemicolon]++-- show 'span' as "((startLine, startColumn), (endLine, endColumn))"+showSpan :: Span -> String+showSpan sp = "(" ++ showPos (start sp) ++ ", " ++ showPos (end sp) ++ ")"++-- show 'Position' as "(line, column)"+showPos :: Position -> String+showPos p = "(" ++ show (line p) ++ ", " ++ show (column p) ++ ")"++-- |Show tokens and their value if needed+showToken :: Token -> String+-- literals+showToken (Token CharTok        a) = "CharTok"   +++ showAttributes a+showToken (Token IntTok         a) = "IntTok"    +++ showAttributes a+showToken (Token FloatTok       a) = "FloatTok"  +++ showAttributes a+showToken (Token StringTok      a) = "StringTok" +++ showAttributes a+-- identifiers+showToken (Token Id             a) = "Id"        +++ showAttributes a+showToken (Token QId            a) = "QId"       +++ showAttributes a+showToken (Token Sym            a) = "Sym"       +++ showAttributes a+showToken (Token QSym           a) = "QSym"      +++ showAttributes a+-- punctuation symbols+showToken (Token LeftParen      _) = "LeftParen"+showToken (Token RightParen     _) = "RightParen"+showToken (Token Semicolon      _) = "Semicolon"+showToken (Token LeftBrace      _) = "LeftBrace"+showToken (Token RightBrace     _) = "RightBrace"+showToken (Token LeftBracket    _) = "LeftBracket"+showToken (Token RightBracket   _) = "RightBracket"+showToken (Token Comma          _) = "Comma"+showToken (Token Underscore     _) = "Underscore"+showToken (Token Backquote      _) = "Backquote"+-- layout+showToken (Token VSemicolon     _) = "VSemicolon"+showToken (Token VRightBrace    _) = "VRightBrace"+-- reserved keywords+showToken (Token KW_case        _) = "KW_case"+showToken (Token KW_class       _) = "KW_class"+showToken (Token KW_data        _) = "KW_data"+showToken (Token KW_default     _) = "KW_default"+showToken (Token KW_deriving    _) = "KW_deriving"+showToken (Token KW_do          _) = "KW_do"+showToken (Token KW_else        _) = "KW_else"+showToken (Token KW_external    _) = "KW_external"+showToken (Token KW_fcase       _) = "KW_fcase"+showToken (Token KW_free        _) = "KW_free"+showToken (Token KW_if          _) = "KW_if"+showToken (Token KW_import      _) = "KW_import"+showToken (Token KW_in          _) = "KW_in"+showToken (Token KW_infix       _) = "KW_infix"+showToken (Token KW_infixl      _) = "KW_infixl"+showToken (Token KW_infixr      _) = "KW_infixr"+showToken (Token KW_instance    _) = "KW_instance"+showToken (Token KW_let         _) = "KW_let"+showToken (Token KW_module      _) = "KW_module"+showToken (Token KW_newtype     _) = "KW_newtype"+showToken (Token KW_of          _) = "KW_of"+showToken (Token KW_then        _) = "KW_then"+showToken (Token KW_type        _) = "KW_type"+showToken (Token KW_where       _) = "KW_where"+-- reserved operators+showToken (Token At             _) = "At"+showToken (Token Colon          _) = "Colon"+showToken (Token DotDot         _) = "DotDot"+showToken (Token DoubleColon    _) = "DoubleColon"+showToken (Token Equals         _) = "Equals"+showToken (Token Backslash      _) = "Backslash"+showToken (Token Bar            _) = "Bar"+showToken (Token LeftArrow      _) = "LeftArrow"+showToken (Token RightArrow     _) = "RightArrow"+showToken (Token Tilde          _) = "Tilde"+showToken (Token DoubleArrow    _) = "DoubleArrow"+-- special identifiers+showToken (Token Id_as          _) = "Id_as"+showToken (Token Id_ccall       _) = "Id_ccall"+showToken (Token Id_forall      _) = "Id_forall"+showToken (Token Id_hiding      _) = "Id_hiding"+showToken (Token Id_interface   _) = "Id_interface"+showToken (Token Id_primitive   _) = "Id_primitive"+showToken (Token Id_qualified   _) = "Id_qualified"+-- special operators+showToken (Token SymDot         _) = "SymDot"+showToken (Token SymMinus       _) = "SymMinus"+-- special symbols+showToken (Token SymStar        _) = "SymStar"+-- pragmas+showToken (Token PragmaLanguage _) = "PragmaLanguage"+showToken (Token PragmaOptions  a) = "PragmaOptions" +++ showAttributes a+showToken (Token PragmaHiding   _) = "PragmaHiding"+showToken (Token PragmaMethod   _) = "PragmaMethod"+showToken (Token PragmaModule   _) = "PragmaModule"+showToken (Token PragmaEnd      _) = "PragmaEnd"+-- comments+showToken (Token LineComment    a) = "LineComment"   +++ showAttributes a+showToken (Token NestedComment  a) = "NestedComment" +++ showAttributes a+-- end-of-file token+showToken (Token EOF            _) = "EOF"++showAttributes :: Attributes -> String+showAttributes NoAttributes            = ""+showAttributes (CharAttributes    c _) = show c+showAttributes (IntAttributes     i _) = show i+showAttributes (FloatAttributes   f _) = show f+showAttributes (StringAttributes  s _) = show s+showAttributes (IdentAttributes   m i) = show $ intercalate "." (m ++ [i])+showAttributes (OptionsAttributes t a) = "(" ++ show t ++ ")" ++ ' ' : show a++-- Concatenate two 'String's with a smart space in between,+-- which is only added if both 'String's are non-empty+(+++) :: String -> String -> String+[] +++ t  = t+s  +++ [] = s+s  +++ t  = s ++ ' ' : t
− src/TopEnv.lhs
@@ -1,148 +0,0 @@--% $Id: TopEnv.lhs,v 1.20 2003/10/04 17:04:32 wlux Exp $-%-% Copyright (c) 1999-2003, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{TopEnv.lhs}-\subsection{Top-Level Environments}\label{sec:toplevel-env}-The module \texttt{TopEnv} implements environments for qualified and-possibly ambiguous identifiers. An identifier is ambiguous if two-different entities are imported under the same name or if a local-definition uses the same name as an imported entity. Following an idea-presented in \cite{DiatchkiJonesHallgren02:ModuleSystem}, an-identifier is associated with a list of entities in order to handle-ambiguous names properly.--In general, two entities are considered equal if the names of their-original definitions match.  However, in the case of algebraic data-types it is possible to hide some or all of their data constructors on-import and export, respectively. In this case we have to merge both-imports such that all data constructors which are visible through any-import path are visible in the current module. The class-\texttt{Entity} is used to handle this merge.--The code in this module ensures that the list of entities returned by-the functions \texttt{lookupTopEnv} and \texttt{qualLookupTopEnv}-contains exactly one element for each imported entity regardless of-how many times and from which module(s) it was imported. Thus, the-result of these function is a list with exactly one element if and-only if the identifier is unambiguous. The module names associated-with an imported entity identify the modules from which the entity was-imported.-\begin{verbatim}--> module TopEnv(TopEnv(..), Entity(..), emptyTopEnv,->               predefTopEnv,qualImportTopEnv,importTopEnv,->               bindTopEnv,qualBindTopEnv,rebindTopEnv,qualRebindTopEnv,->               unbindTopEnv,lookupTopEnv,qualLookupTopEnv,->               allImports,moduleImports,localBindings->              ) where--> import Data.Maybe-> import qualified Data.Map as Map-> import Control.Arrow(second)-> import Curry.Base.Ident---> data Source = Local | Import [ModuleIdent] deriving (Eq,Show)--> class Entity a where->  origName :: a -> QualIdent->  merge    :: a -> a -> Maybe a->  merge x y->    | origName x == origName y = Just x->    | otherwise = Nothing--> newtype TopEnv a = TopEnv { topEnvMap :: Map.Map QualIdent [(Source,a)] ->                           } deriving Show--> instance Functor TopEnv where->   fmap f (TopEnv env) = TopEnv (fmap (map (second f)) env)--> entities :: QualIdent -> Map.Map QualIdent [(Source,a)] -> [(Source,a)]-> entities x env = fromMaybe [] (Map.lookup x env)--> emptyTopEnv :: TopEnv a-> emptyTopEnv = TopEnv Map.empty--> predefTopEnv :: Entity a => QualIdent -> a -> TopEnv a -> TopEnv a-> predefTopEnv x y (TopEnv env) =->   case Map.lookup x env of->     Just _ -> error "internal error: predefTopEnv"->     Nothing -> TopEnv (Map.insert x [(Import [],y)] env)--> importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a -> TopEnv a-> importTopEnv m x y (TopEnv env) =->   TopEnv (Map.insert x' (mergeImport m y (entities x' env)) env)->   where x' = qualify x--> qualImportTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a->                  -> TopEnv a-> qualImportTopEnv m x y (TopEnv env) =->   TopEnv (Map.insert x' (mergeImport m y (entities x' env)) env)->   where x' = qualifyWith m x--> mergeImport :: Entity a => ModuleIdent -> a -> [(Source,a)] -> [(Source,a)]-> mergeImport m x [] = [(Import [m],x)]-> mergeImport m x ((Local,x') : xs) = (Local,x') : mergeImport m x xs-> mergeImport m x ((Import ms,x') : xs) =->   case merge x x' of->     Just x'' -> (Import (m:ms),x'') : xs->     Nothing -> (Import ms,x') : mergeImport m x xs--> bindTopEnv :: String -> Ident -> a -> TopEnv a -> TopEnv a-> bindTopEnv fun x y env = qualBindTopEnv fun (qualify x) y env--> qualBindTopEnv :: String -> QualIdent -> a -> TopEnv a -> TopEnv a-> qualBindTopEnv fun x y (TopEnv env) =->   TopEnv (Map.insert x (bindLocal y (entities x env)) env)->   where bindLocal y ys->           | null [y' | (Local,y') <- ys] = (Local,y) : ys->           | otherwise = error ("internal error: \"qualBindTopEnv " ->		                 ++ show x ++ "\" failed in function \""->			         ++ fun ++ "\"")--> rebindTopEnv :: Ident -> a -> TopEnv a -> TopEnv a-> rebindTopEnv = qualRebindTopEnv . qualify--> qualRebindTopEnv :: QualIdent -> a -> TopEnv a -> TopEnv a-> qualRebindTopEnv x y (TopEnv env) =->   TopEnv (Map.insert x (rebindLocal (entities x env)) env)->   where rebindLocal [] = error "internal error: qualRebindTopEnv"->         rebindLocal ((Local,_) : ys) = (Local,y) : ys->         rebindLocal ((Import ms,y) : ys) = (Import ms,y) : rebindLocal ys--> unbindTopEnv :: Ident -> TopEnv a -> TopEnv a-> unbindTopEnv x (TopEnv env) =->   TopEnv (Map.insert x' (unbindLocal (entities x' env)) env)->   where x' = qualify x->         unbindLocal [] = error "internal error: unbindTopEnv"->         unbindLocal ((Local,_) : ys) = ys->         unbindLocal ((Import ms,y) : ys) = (Import ms,y) : unbindLocal ys--> lookupTopEnv :: Ident -> TopEnv a -> [a]-> lookupTopEnv = qualLookupTopEnv . qualify--> qualLookupTopEnv :: QualIdent -> TopEnv a -> [a]-> qualLookupTopEnv x (TopEnv env) = map snd (entities x env)--> allImports :: TopEnv a -> [(QualIdent,a)]-> allImports (TopEnv env) =->   [(x,y) | (x,ys) <- Map.toList env, (Import _,y) <- ys]--> unqualBindings :: TopEnv a -> [(Ident,(Source,a))]-> unqualBindings (TopEnv env) =->   [(x',y) | (x,ys) <- takeWhile (not . isQualified . fst) (Map.toList env),->             let x' = unqualify x, y <- ys]--> moduleImports :: ModuleIdent -> TopEnv a -> [(Ident,a)]-> moduleImports m env =->   [(x,y) | (x,(Import ms,y)) <- unqualBindings env, m `elem` ms]--> localBindings :: TopEnv a -> [(Ident,a)]-> localBindings env = [(x,y) | (x,(Local,y)) <- unqualBindings env]--\end{verbatim}
+ src/Transformations.hs view
@@ -0,0 +1,86 @@+{- |+    Module      :  $Header$+    Description :  Code transformations+    Copyright   :  (c) 2011, Björn Peemöller (bjp@informatik.uni-kiel.de)+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module subsumes the different transformations of the source code.+-}+module Transformations where++import Curry.Syntax++import Base.Types++import Transformations.CaseCompletion as CC (completeCase)+import Transformations.CurryToIL      as IL (ilTrans, transType)+import Transformations.Derive         as DV (derive)+import Transformations.Desugar        as DS (desugar)+import Transformations.Dictionary     as DI (insertDicts)+import Transformations.Lift           as L  (lift)+import Transformations.Newtypes       as NT (removeNewtypes)+import Transformations.Qual           as Q  (qual)+import Transformations.Simplify       as S  (simplify)++import CompilerEnv+import Imports (qualifyEnv)+import qualified IL++-- |Fully qualify used constructors and functions.+qual :: CompEnv (Module a) -> CompEnv (Module a)+qual (env, mdl) = (qualifyEnv env, mdl')+  where mdl' = Q.qual (moduleIdent env) (tyConsEnv env) (valueEnv env) mdl++-- |Automatically derive instances.+derive :: CompEnv (Module PredType) -> CompEnv (Module PredType)+derive (env, mdl) = (env, mdl')+  where mdl' = DV.derive (tyConsEnv env) (valueEnv env) (instEnv env)+                         (opPrecEnv env) mdl++-- |Remove any syntactic sugar, changes the value environment.+desugar :: CompEnv (Module PredType) -> CompEnv (Module PredType)+desugar (env, mdl) = (env { valueEnv = tyEnv' }, mdl')+  where (mdl', tyEnv') = DS.desugar (extensions env) (valueEnv env)+                                    (tyConsEnv env) mdl++-- |Insert dictionaries, changes the type constructor and value environments.+insertDicts :: CompEnv (Module PredType) -> CompEnv (Module Type)+insertDicts (env, mdl) = (env { interfaceEnv = intfEnv'+                              , tyConsEnv = tcEnv'+                              , valueEnv = vEnv'+                              , opPrecEnv = pEnv' }, mdl')+  where (mdl', intfEnv', tcEnv', vEnv', pEnv') =+          DI.insertDicts (interfaceEnv env) (tyConsEnv env) (valueEnv env)+                         (classEnv env) (instEnv env) (opPrecEnv env) mdl++-- |Remove newtype constructors.+removeNewtypes :: CompEnv (Module Type) -> CompEnv (Module Type)+removeNewtypes (env, mdl) = (env, mdl')+  where mdl' = NT.removeNewtypes (valueEnv env) mdl++-- |Simplify the source code, changes the value environment.+simplify :: CompEnv (Module Type) -> CompEnv (Module Type)+simplify (env, mdl) = (env { valueEnv = tyEnv' }, mdl')+  where (mdl', tyEnv') = S.simplify (valueEnv env) mdl++-- |Lift local declarations, changes the value environment.+lift :: CompEnv (Module Type) -> CompEnv (Module Type)+lift (env, mdl) = (env { valueEnv = tyEnv' }, mdl')+  where (mdl', tyEnv') = L.lift (valueEnv env) mdl++-- |Translate into the intermediate language+ilTrans :: CompEnv (Module Type) -> CompEnv IL.Module+ilTrans (env, mdl) = (env, il)+  where il = IL.ilTrans (valueEnv env) mdl++-- |Translate a type into its representation in the intermediate language+transType :: Type -> IL.Type+transType = IL.transType++-- |Add missing case branches+completeCase :: CompEnv IL.Module -> CompEnv IL.Module+completeCase (env, mdl) = (env, CC.completeCase (interfaceEnv env) mdl)
+ src/Transformations/CaseCompletion.hs view
@@ -0,0 +1,453 @@+{- |+    Module      :  $Header$+    Description :  CaseCompletion+    Copyright   :  (c) 2005        Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2016        Jan Tikovsky+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    This module expands case branches with missing constructors.++    The MCC translates case expressions into the intermediate language+    representation (IL) without completing them (i.e. without generating+    case branches for missing contructors), because the intermediate language+    supports variable patterns for the fallback case.+    In contrast, the FlatCurry representation of patterns only allows+    literal and constructor patterns, which requires the expansion+    default branches to all missing constructors.++    This is only necessary for *rigid* case expressions, because any+    *flexible* case expression with more than one branch and a variable+    pattern is non-deterministic. In consequence, these overlapping patterns+    have already been eliminated in the pattern matching compilation+    process (see module CurryToIL).++    To summarize, this module expands all rigid case expressions.+-}+{-# LANGUAGE CPP #-}+module Transformations.CaseCompletion (completeCase) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import qualified Control.Monad.State as S   (State, evalState, gets, modify)+import           Data.List                  (find)+import           Data.Maybe                 (fromMaybe, listToMaybe)++import           Curry.Base.Ident+import qualified Curry.Syntax        as CS++import Base.CurryTypes                      (toType)+import Base.Expr+import Base.Messages                        (internalError)+import Base.Types                           ( boolType, charType, floatType+                                            , intType, listType+                                            )+import Base.Subst++import Env.Interface                        (InterfaceEnv, lookupInterface)++import Transformations.CurryToIL            (transType)+import Transformations.Dictionary           (qImplMethodId)++import IL++-- Completes case expressions by adding branches for missing constructors.+-- The interface environment 'iEnv' is needed to compute these constructors.+completeCase :: InterfaceEnv -> Module -> Module+completeCase iEnv mdl@(Module mid is ds) = Module mid is ds'+ where ds'= S.evalState (mapM ccDecl ds) (CCState mdl iEnv 0)++-- -----------------------------------------------------------------------------+-- Internally used state monad+-- -----------------------------------------------------------------------------++data CCState = CCState+  { modul        :: Module+  , interfaceEnv :: InterfaceEnv+  , nextId       :: Int+  }++type CCM a = S.State CCState a++getModule :: CCM Module+getModule = S.gets modul++getInterfaceEnv :: CCM InterfaceEnv+getInterfaceEnv = S.gets interfaceEnv++-- Create a fresh identifier+freshIdent :: CCM Ident+freshIdent = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return $ mkIdent $ "_#comp" ++ show nid++-- -----------------------------------------------------------------------------+-- The following functions traverse an IL term searching for case expressions+-- -----------------------------------------------------------------------------++ccDecl :: Decl -> CCM Decl+ccDecl dd@(DataDecl        _ _ _) = return dd+ccDecl edd@(ExternalDataDecl _ _) = return edd+ccDecl (FunctionDecl qid vs ty e) = FunctionDecl qid vs ty <$> ccExpr e+ccDecl ed@(ExternalDecl      _ _) = return ed++ccExpr :: Expression -> CCM Expression+ccExpr l@(Literal       _ _) = return l+ccExpr v@(Variable      _ _) = return v+ccExpr f@(Function    _ _ _) = return f+ccExpr c@(Constructor _ _ _) = return c+ccExpr (Apply         e1 e2) = Apply <$> ccExpr e1 <*> ccExpr e2+ccExpr (Case        ea e bs) = do+  e'  <- ccExpr e+  bs' <- mapM ccAlt bs+  ccCase ea e' bs'+ccExpr (Or            e1 e2) = Or <$> ccExpr e1 <*> ccExpr e2+ccExpr (Exist           v e) = Exist v <$> ccExpr e+ccExpr (Let             b e) = Let <$> ccBinding b <*> ccExpr e+ccExpr (Letrec         bs e) = Letrec <$> mapM ccBinding bs <*> ccExpr e+ccExpr (Typed          e ty) = flip Typed ty <$> ccExpr e++ccAlt :: Alt -> CCM Alt+ccAlt (Alt p e) = Alt p <$> ccExpr e++ccBinding :: Binding -> CCM Binding+ccBinding (Binding v e) = Binding v <$> ccExpr e++-- ---------------------------------------------------------------------------+-- Functions for completing case alternatives+-- ---------------------------------------------------------------------------+ccCase :: Eval -> Expression -> [Alt] -> CCM Expression+-- flexible cases are not completed+ccCase Flex  e alts     = return $ Case Flex e alts+ccCase Rigid _ []       = internalError $ "CaseCompletion.ccCase: "+                                       ++ "empty alternative list"+ccCase Rigid e as@(Alt p _:_) = case p of+  ConstructorPattern _ _ _ -> completeConsAlts Rigid e as+  LiteralPattern     _ _   -> completeLitAlts  Rigid e as+  VariablePattern    _ _   -> completeVarAlts        e as++-- Completes a case alternative list which branches via constructor patterns+-- by adding alternatives. Thus, case expressions of the form+--     case <ce> of+--       <C_1> -> <expr_1>+--              :+--       <C_n> -> <expr_n>+--      [<var> -> <default_expr>]+-- are in general extended to+--     let x = <ce> in+--     let y = <default_expr>[<var>/x] in+--     case x of+--       <C_1>  -> <expr_1>+--               :+--       <C_n>  -> <expr_n>+--       <C'_1> -> y+--               :+--       <C'_m> -> y+-- where the C'_j are the complementary constructor patterns of the C_i,+-- @x@ and @y@ are fresh variables, and "default_expr" is the expression+-- from the first alternative containing a variable pattern. If there is no such+-- alternative, the default expression is set to the prelude function 'failed'.+-- In addition, there are a few optimizations performed to avoid the+-- construction of unnecessary let-bindings:+--   - If there are no complementary patterns, the expression remains unchanged.+--   - If there is only one complementary pattern,+--     the binding for @y@ is avoided (see @bindDefVar@).+--   - If the variable @<var>@ does not occur in the default expression,+--     the binding for @x@ is avoided (see @mkCase@).+completeConsAlts :: Eval -> Expression -> [Alt] -> CCM Expression+completeConsAlts ea ce alts = do+  mdl       <- getModule+  menv      <- getInterfaceEnv+  -- complementary constructor patterns+  complPats <- mapM genPat $ getComplConstrs mdl menv+               [ c | (Alt (ConstructorPattern _ c _) _) <- consAlts ]+  v <- freshIdent+  w <- freshIdent+  return $ case (complPats, defaultAlt v) of+            (_:_, Just e') -> bindDefVar v ce w e' complPats+            _              -> Case ea ce consAlts+  where+  -- existing contructor pattern alternatives+  consAlts = [ a | a@(Alt (ConstructorPattern _ _ _) _) <- alts ]++  -- unifier for data type and concrete pattern type+  dataTy  = let TypeConstructor qid tys = patTy+            in TypeConstructor qid $ map TypeVariable [0 .. length tys - 1]+  patTy   = let Alt pat _ = head consAlts in typeOf pat+  tySubst = matchType dataTy patTy idSubst++  -- generate a new constructor pattern+  genPat (qid, tys) = ConstructorPattern patTy qid <$>+    mapM (\ty' -> freshIdent >>= \v -> return (ty', v)) (subst tySubst tys)++  -- default alternative, if there is one+  defaultAlt v = listToMaybe [ replaceVar x (Variable ty v) e+                             | Alt (VariablePattern ty x) e <- alts ]++  -- create a binding for @v = e@ if needed+  bindDefVar v e w e' ps+    | v `elem` fv e' = mkBinding v e $ mkCase (Variable (typeOf e) v) w e' ps+    | otherwise      = mkCase e w e' ps++  -- create a binding for @w = e'@ if needed, and a case expression+  -- @case e of { consAlts ++ (ps -> w) }@+  mkCase e w e' ps = case ps of+    [p] -> Case ea e (consAlts ++ [Alt p e'])+    _   -> mkBinding w e'+         $ Case ea e (consAlts ++ [Alt p (Variable (typeOf e') w) | p <- ps])++-- If the alternatives' branches contain literal patterns, a complementary+-- constructor list cannot be generated because it would become potentially+-- infinite. Thus, function 'completeLitAlts' transforms case expressions like+--     case <ce> of+--       <lit_1> -> <expr_1>+--       <lit_2> -> <expr_2>+--                   :+--       <lit_n> -> <expr_n>+--      [<var>   -> <default_expr>]+-- to+--     let x = <ce> in+--     case (v == <lit_1>) of+--       True  -> <expr_1>+--       False -> case (x == <lit_2>) of+--                  True  -> <expr_2>+--                  False -> case ...+--                                 :+--                               -> case (x == <lit_n>) of+--                                    True  -> <expr_n>+--                                    False -> <default_expr>+-- If the default expression is missing, @failed@ is used instead.+completeLitAlts :: Eval -> Expression -> [Alt] -> CCM Expression+completeLitAlts ea ce alts = do+  x <- freshIdent+  return $ mkBinding x ce $ nestedCases x alts+  where+  nestedCases _ []              = failedExpr (typeOf $ head alts)+  nestedCases x (Alt p ae : as) = case p of+    LiteralPattern ty l  -> Case ea (Variable ty x `eqExpr` Literal ty l)+                          [ Alt truePatt  ae+                          , Alt falsePatt (nestedCases x as)+                          ]+    VariablePattern ty v -> replaceVar v (Variable ty x) ae+    _ -> internalError "CaseCompletion.completeLitAlts: illegal alternative"++-- For the unusual case of only one alternative containing a variable pattern,+-- it is necessary to tranform it to a 'let' term because FlatCurry does not+-- support variable patterns in case alternatives. So the case expression+--    case <ce> of+--      x -> <ae>+-- is transformed to+--      let x = <ce> in <ae>+completeVarAlts :: Expression -> [Alt] -> CCM Expression+completeVarAlts _  []             = internalError $+  "CaseCompletion.completeVarAlts: empty alternative list"+completeVarAlts ce (Alt p ae : _) = case p of+  VariablePattern _ x -> return $ mkBinding x ce ae+  _                   -> internalError $+    "CaseCompletion.completeVarAlts: variable pattern expected"++-- Smart constructor for non-recursive let-binding. @mkBinding v e e'@+-- evaluates to @e'[v/e]@ if @e@ is a variable, or @let v = e in e'@ otherwise.+mkBinding :: Ident -> Expression -> Expression -> Expression+mkBinding v e e' = case e of+  Variable _ _ -> replaceVar v e e'+  _            -> Let (Binding v e) e'++-- ---------------------------------------------------------------------------+-- This part of the module contains functions for replacing variables+-- with expressions. This is necessary in the case of having a default+-- alternative like+--      v -> <expr>+-- where the variable v occurs in the default expression <expr>. When+-- building additional alternatives for this default expression, the variable+-- must be replaced with the newly generated constructors.+replaceVar :: Ident -> Expression -> Expression -> Expression+replaceVar v e x@(Variable  _ w)+  | v == w    = e+  | otherwise = x+replaceVar v e (Apply     e1 e2)+  = Apply (replaceVar v e e1) (replaceVar v e e2)+replaceVar v e (Case   ev e' bs)+  = Case ev (replaceVar v e e') (map (replaceVarInAlt v e) bs)+replaceVar v e (Or        e1 e2)+  = Or (replaceVar v e e1) (replaceVar v e e2)+replaceVar v e (Exist      w e')+   | v == w                     = Exist w e'+   | otherwise                  = Exist w (replaceVar v e e')+replaceVar v e (Let        b e')+   | v `occursInBinding` b      = Let b e'+   | otherwise                  = Let (replaceVarInBinding v e b)+                                      (replaceVar v e e')+replaceVar v e (Letrec    bs e')+   | any (occursInBinding v) bs = Letrec bs e'+   | otherwise                  = Letrec (map (replaceVarInBinding v e) bs)+                                         (replaceVar v e e')+replaceVar _ _ e'               = e'++replaceVarInAlt :: Ident -> Expression -> Alt -> Alt+replaceVarInAlt v e (Alt p e')+  | v `occursInPattern` p = Alt p e'+  | otherwise             = Alt p (replaceVar v e e')++replaceVarInBinding :: Ident -> Expression -> Binding -> Binding+replaceVarInBinding v e (Binding w e')+  | v == w    = Binding w e'+  | otherwise = Binding w (replaceVar v e e')++occursInPattern :: Ident -> ConstrTerm -> Bool+occursInPattern v (VariablePattern       _ w) = v == w+occursInPattern v (ConstructorPattern _ _ vs) = v `elem` map snd vs+occursInPattern _ _                           = False++occursInBinding :: Ident -> Binding -> Bool+occursInBinding v (Binding w _) = v == w++-- ---------------------------------------------------------------------------+-- The following functions generate several IL expressions and patterns++failedExpr :: Type -> Expression+failedExpr ty = Function ty (qualifyWith preludeMIdent (mkIdent "failed")) 0++eqExpr :: Expression -> Expression -> Expression+eqExpr e1 e2 = Apply (Apply (Function eqTy eq 2) e1) e2+  where eq   = qImplMethodId preludeMIdent qEqId ty $ mkIdent "=="+        ty   = case e2 of+                 Literal _ l -> case l of+                                  Char  _ -> charType+                                  Int   _ -> intType+                                  Float _ -> floatType+                 _ -> internalError "CaseCompletion.eqExpr: no literal"+        ty'  = transType ty+        eqTy = TypeArrow ty' (TypeArrow ty' boolType')++truePatt :: ConstrTerm+truePatt = ConstructorPattern boolType' qTrueId []++falsePatt :: ConstrTerm+falsePatt = ConstructorPattern boolType' qFalseId []++boolType' :: Type+boolType' = transType boolType++-- ---------------------------------------------------------------------------+-- The following functions compute the missing constructors for generating+-- missing case alternatives++-- Computes the complementary constructors for a given list of constructors.+-- All specified constructors must be of the same type.+-- This functions uses the module environment 'menv', which contains all+-- imported constructors, except for the built-in list constructors.+-- TODO: Check if the list constructors are in the menv.+getComplConstrs :: Module -> InterfaceEnv -> [QualIdent] -> [(QualIdent, [Type])]+getComplConstrs _                 _    []+  = internalError "CaseCompletion.getComplConstrs: empty constructor list"+getComplConstrs (Module mid _ ds) menv cs@(c:_)+  -- built-in lists+  | c `elem` [qNilId, qConsId] = complementary cs+    [(qNilId, []), (qConsId, [TypeVariable 0, transType (listType boolType)])]+  -- current module+  | mid' == mid                = getCCFromDecls cs ds+  -- imported module+  | otherwise                  = maybe [] (getCCFromIDecls mid' cs)+                                          (lookupInterface mid' menv)+  where mid' = fromMaybe mid (qidModule c)++-- Find complementary constructors within the declarations of the+-- current module+getCCFromDecls :: [QualIdent] -> [Decl] -> [(QualIdent, [Type])]+getCCFromDecls cs ds = complementary cs cinfos+  where+  cinfos = map constrInfo+         $ maybe [] extractConstrDecls (find (`declares` head cs) ds)++  decl `declares` qid = case decl of+    DataDecl    _ _ cs' -> any (`declaresConstr` qid) cs'+    _                   -> False++  declaresConstr (ConstrDecl cid _) qid = cid == qid++  extractConstrDecls (DataDecl _ _ cs') = cs'+  extractConstrDecls _                  = []++  constrInfo (ConstrDecl cid tys) = (cid, tys)++-- Find complementary constructors within the module environment+getCCFromIDecls :: ModuleIdent -> [QualIdent] -> CS.Interface+                -> [(QualIdent, [Type])]+getCCFromIDecls mid cs (CS.Interface _ _ ds) = complementary cs cinfos+  where+  cinfos = map (uncurry constrInfo)+         $ maybe [] extractConstrDecls (find (`declares` head cs) ds)++  decl `declares` qid = case decl of+    CS.IDataDecl    _ _ _ _ cs' _ -> any (`declaresConstr` qid) cs'+    CS.INewtypeDecl _ _ _ _ nc  _ -> isNewConstrDecl qid nc+    _                             -> False++  declaresConstr (CS.ConstrDecl  _ _ _ cid _) qid = unqualify qid == cid+  declaresConstr (CS.ConOpDecl _ _ _ _ oid _) qid = unqualify qid == oid+  declaresConstr (CS.RecordDecl  _ _ _ cid _) qid = unqualify qid == cid++  isNewConstrDecl qid (CS.NewConstrDecl _ cid _) = unqualify qid == cid+  isNewConstrDecl qid (CS.NewRecordDecl _ cid _) = unqualify qid == cid++  extractConstrDecls (CS.IDataDecl _ _ _ vs cs' _) = zip (repeat vs) cs'+  extractConstrDecls _                             = []++  constrInfo vs (CS.ConstrDecl _ _ _ cid tys)     =+    (qualifyWith mid cid, map (transType' vs) tys)+  constrInfo vs (CS.ConOpDecl  _ _ _ ty1 oid ty2) =+    (qualifyWith mid oid, map (transType' vs) [ty1, ty2])+  constrInfo vs (CS.RecordDecl _ _ _ cid  fs)     =+    ( qualifyWith mid cid+    , [transType' vs ty | CS.FieldDecl _ ls ty <- fs, _ <- ls]+    )++  transType' vs = transType . toType vs++-- Compute complementary constructors+complementary :: [QualIdent] -> [(QualIdent, [Type])] -> [(QualIdent, [Type])]+complementary known others = filter ((`notElem` known) . fst) others++-- ---------------------------------------------------------------------------+-- The following section contains defintions to compute a type substitution+-- for generating the type annotations for missing case alternatives++type TypeSubst = Subst Int Type++class SubstType a where+  subst :: TypeSubst -> a -> a++instance SubstType a => SubstType [a] where+  subst sigma = map (subst sigma)++instance SubstType Type where+  subst sigma (TypeConstructor q tys) = TypeConstructor q $ subst sigma tys+  subst sigma (TypeVariable       tv) = substVar' TypeVariable subst sigma tv+  subst sigma (TypeArrow     ty1 ty2) = TypeArrow (subst sigma ty1) (subst sigma ty2)+  subst _     (TypeForall        _ _) =+    internalError "Transformations.CaseCompletion.SubstType.Type.subst"++matchType :: Type -> Type -> TypeSubst -> TypeSubst+matchType ty1 ty2 = fromMaybe noMatch (matchType' ty1 ty2)+  where+    noMatch = internalError $ "Transformations.CaseCompletion.matchType: " +++                                showsPrec 11 ty1 " " ++ showsPrec 11 ty2 ""++matchType' :: Type -> Type -> Maybe (TypeSubst -> TypeSubst)+matchType' (TypeVariable tv) ty+  | ty == TypeVariable tv = Just id+  | otherwise = Just (bindSubst tv ty)+matchType' (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2)+  | tc1 == tc2 = Just $ foldr (\(ty1, ty2) -> (matchType ty1 ty2 .)) id $ tys+  where tys = zip tys1 tys2+matchType' (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =+  Just (matchType ty11 ty21 . matchType ty12 ty22)+matchType' _ _ = Nothing
+ src/Transformations/CurryToIL.hs view
@@ -0,0 +1,548 @@+{- |+    Module      :  $Header$+    Description :  Translation of Curry into IL+    Copyright   :  (c) 1999 - 2003 Wolfgang Lux+                                   Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2015        Jan Tikovsky+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   After desugaring and lifting have been performed, the source code is+   translated into the intermediate language. Besides translating from+   source terms and expressions into intermediate language terms and+   expressions, this phase in particular has to implement the pattern+   matching algorithm for equations and case expressions.++   Because of name conflicts between the source and intermediate language+   data structures, we can use only a qualified import for the 'IL' module.+-}+{-# LANGUAGE CPP #-}+module Transformations.CurryToIL (ilTrans, transType) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif++import           Control.Monad.Extra         (concatMapM)+import qualified Control.Monad.Reader as R+import           Data.List                   (nub, partition)+import qualified Data.Map             as Map (Map, empty, insert, lookup)+import qualified Data.Set             as Set (Set, empty, insert, delete, toList)++import Curry.Base.Ident+import Curry.Syntax hiding (caseAlt)++import Base.CurryTypes (toType)+import Base.Expr+import Base.Messages (internalError)+import Base.Types+import Base.Typing+import Base.Utils (foldr2)++import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++import qualified IL as IL++ilTrans :: ValueEnv -> Module Type -> IL.Module+ilTrans vEnv (Module _ m _ _ ds) = IL.Module m (imports m ds') ds'+  where ds' = R.runReader (concatMapM trDecl ds) (TransEnv m vEnv)++-- -----------------------------------------------------------------------------+-- Computation of necessary imports+-- -----------------------------------------------------------------------------++-- The list of import declarations in the intermediate language code is+-- determined by collecting all module qualifiers used in the current module.++imports :: ModuleIdent -> [IL.Decl] -> [ModuleIdent]+imports m = Set.toList . Set.delete m . foldr mdlsDecl Set.empty++mdlsDecl :: IL.Decl -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsDecl (IL.DataDecl       _ _ cs) ms = foldr mdlsConstrsDecl ms cs+  where mdlsConstrsDecl (IL.ConstrDecl _ tys) ms' = foldr mdlsType ms' tys+mdlsDecl (IL.ExternalDataDecl  _ _) ms = ms+mdlsDecl (IL.FunctionDecl _ _ ty e) ms = mdlsType ty (mdlsExpr e ms)+mdlsDecl (IL.ExternalDecl     _ ty) ms = mdlsType ty ms++mdlsType :: IL.Type -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsType (IL.TypeConstructor tc tys) ms = modules tc (foldr mdlsType ms tys)+mdlsType (IL.TypeVariable         _) ms = ms+mdlsType (IL.TypeArrow      ty1 ty2) ms = mdlsType ty1 (mdlsType ty2 ms)+mdlsType (IL.TypeForall        _ ty) ms = mdlsType ty ms++mdlsExpr :: IL.Expression -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsExpr (IL.Function    _ f _) ms = modules f ms+mdlsExpr (IL.Constructor _ c _) ms = modules c ms+mdlsExpr (IL.Apply       e1 e2) ms = mdlsExpr e1 (mdlsExpr e2 ms)+mdlsExpr (IL.Case       _ e as) ms = mdlsExpr e (foldr mdlsAlt ms as)+  where+  mdlsAlt     (IL.Alt                 t e') = mdlsPattern t . mdlsExpr e'+  mdlsPattern (IL.ConstructorPattern _ c _) = modules c+  mdlsPattern _                             = id+mdlsExpr (IL.Or          e1 e2) ms = mdlsExpr e1 (mdlsExpr e2 ms)+mdlsExpr (IL.Exist         _ e) ms = mdlsExpr e ms+mdlsExpr (IL.Let           b e) ms = mdlsBinding b (mdlsExpr e ms)+mdlsExpr (IL.Letrec       bs e) ms = foldr mdlsBinding (mdlsExpr e ms) bs+mdlsExpr _                      ms = ms++mdlsBinding :: IL.Binding -> Set.Set ModuleIdent -> Set.Set ModuleIdent+mdlsBinding (IL.Binding _ e) = mdlsExpr e++modules :: QualIdent -> Set.Set ModuleIdent -> Set.Set ModuleIdent+modules x ms = maybe ms (`Set.insert` ms) (qidModule x)++-- -----------------------------------------------------------------------------+-- Internal reader monad+-- -----------------------------------------------------------------------------++data TransEnv = TransEnv+  { moduleIdent :: ModuleIdent+  , valueEnv    :: ValueEnv+  }++type TransM a = R.Reader TransEnv a++getValueEnv :: TransM ValueEnv+getValueEnv = R.asks valueEnv++trQualify :: Ident -> TransM QualIdent+trQualify i = flip qualifyWith i <$> R.asks moduleIdent++-- Return the type of a variable+varType :: QualIdent -> TransM Type+varType f = do+  tyEnv <- getValueEnv+  case qualLookupValue f tyEnv of+    [Value _ _ _ (ForAll _ (PredType _ ty))] -> return ty+    [Label _ _ (ForAll _ (PredType _ ty))] -> return ty+    _ -> internalError $ "CurryToIL.varType: " ++ show f++-- Return the type of a constructor+constrType :: QualIdent -> TransM Type+constrType c = do+  vEnv <- getValueEnv+  case qualLookupValue c vEnv of+    [DataConstructor  _ _ _ (ForAllExist _ _ (PredType _ ty))] -> return ty+    [NewtypeConstructor _ _ (ForAllExist _ _ (PredType _ ty))] -> return ty+    _ -> internalError $ "CurryToIL.constrType: " ++ show c++-- -----------------------------------------------------------------------------+-- Translation+-- -----------------------------------------------------------------------------++-- At the top-level, the compiler has to translate data type, newtype,+-- function, and external declarations. When translating a data type or+-- newtype declaration, we ignore the types in the declaration and lookup+-- the types of the constructors in the type environment instead because+-- these types are already fully expanded, i.e., they do not include any+-- alias types.++trDecl :: Decl Type -> TransM [IL.Decl]+trDecl (DataDecl     _ tc tvs cs _) = (:[]) <$> trData tc tvs cs+trDecl (ExternalDataDecl  _ tc tvs) = (:[]) <$> trExternalData tc tvs+trDecl (FunctionDecl    _ ty f eqs) = (:[]) <$> trFunction f ty eqs+trDecl (ExternalDecl          _ vs) = mapM trExternal vs+trDecl _                            = return []++trData :: Ident -> [Ident] -> [ConstrDecl] -> TransM IL.Decl+trData tc tvs cs = do+  tc' <- trQualify tc+  IL.DataDecl tc' (length tvs) <$> mapM trConstrDecl cs++trConstrDecl :: ConstrDecl -> TransM IL.ConstrDecl+trConstrDecl d = do+  c' <- trQualify (constr d)+  ty' <- arrowArgs <$> constrType c'+  return $ IL.ConstrDecl c' (map transType ty')+  where+  constr (ConstrDecl    _ _ _ c _) = c+  constr (ConOpDecl  _ _ _ _ op _) = op+  constr (RecordDecl    _ _ _ c _) = c++trExternalData :: Ident -> [Ident] -> TransM IL.Decl+trExternalData tc tvs = flip IL.ExternalDataDecl (length tvs) <$> trQualify tc++trExternal :: Var Type -> TransM IL.Decl+trExternal (Var ty f) = flip IL.ExternalDecl (transType ty) <$> trQualify f++-- The type representation in the intermediate language does not support+-- types with higher order kinds. Therefore, the type transformations has+-- to transform all types to first order terms. To that end, we assume the+-- existence of a type synonym 'type @ f a = f a'. In addition, the type+-- representation of the intermediate language does not support constrained+-- type variables and skolem types. The former are fixed and the later are+-- replaced by fresh type constructors.++transType :: Type -> IL.Type+transType ty = transType' ty []++transType' :: Type -> [IL.Type] -> IL.Type+transType' (TypeConstructor    tc) = IL.TypeConstructor tc+transType' (TypeApply     ty1 ty2) = transType' ty1 . (transType ty2 :)+transType' (TypeVariable       tv) = foldl applyType' (IL.TypeVariable tv)+transType' (TypeConstrained tys _) = transType' (head tys)+transType' (TypeSkolem          k) =+  foldl applyType' (IL.TypeConstructor (qualify (mkIdent ("_" ++ show k))) [])+transType' (TypeArrow     ty1 ty2) =+  foldl applyType' (IL.TypeArrow (transType ty1) (transType ty2))+transType' (TypeForall     tvs ty) =+  foldl applyType' (IL.TypeForall tvs (transType ty))++applyType' :: IL.Type -> IL.Type -> IL.Type+applyType' ty1 ty2 =+  IL.TypeConstructor (qualifyWith preludeMIdent (mkIdent "Apply")) [ty1, ty2]++-- Each function in the program is translated into a function of the+-- intermediate language. The arguments of the function are renamed such+-- that all variables occurring in the same position (in different+-- equations) have the same name. This is necessary in order to+-- facilitate the translation of pattern matching into a 'case' expression.+-- We use the following simple convention here: The top-level+-- arguments of the function are named from left to right '_1', '_2',+-- and so on. The names of nested arguments are constructed by appending+-- '_1', '_2', etc. from left to right to the name that were assigned+-- to a variable occurring at the position of the constructor term.++-- Some special care is needed for the selector functions introduced by+-- the compiler in place of pattern bindings. In order to generate the+-- code for updating all pattern variables, the equality of names between+-- the pattern variables in the first argument of the selector function+-- and their repeated occurrences in the remaining arguments must be+-- preserved. This means that the second and following arguments of a+-- selector function have to be renamed according to the name mapping+-- computed for its first argument.++trFunction :: Ident -> Type -> [Equation Type] -> TransM IL.Decl+trFunction f ty eqs = do+  f' <- trQualify f+  let ty' = transType ty+      vs' = zip (map (transType . typeOf) ts) vs+  alts <- mapM (trEquation vs ws) eqs+  return $ IL.FunctionDecl f' vs' ty' (flexMatch vs' alts)+  where+  -- vs are the variables needed for the function: _1, _2, etc.+  -- ws is an infinite list for introducing additional variables later+  Equation _ lhs _ = head eqs+  (_, ts) = flatLhs lhs+  (vs, ws) = splitAt (length ts) (argNames (mkIdent ""))++trEquation :: [Ident]       -- identifiers for the function's parameters+           -> [Ident]       -- infinite list of additional identifiers+           -> Equation Type -- equation to be translated+           -> TransM Match  -- nested constructor terms + translated RHS+trEquation vs vs' (Equation _ (FunLhs _ ts) rhs) = do+  -- construct renaming of variables inside constructor terms+  let patternRenaming = foldr2 bindRenameEnv Map.empty vs ts+  -- translate right-hand-side+  rhs' <- trRhs vs' patternRenaming rhs+  -- convert patterns+  return (zipWith trPattern vs ts, rhs')+trEquation _  _    _+  = internalError "Translation of non-FunLhs euqation not defined"++type RenameEnv = Map.Map Ident Ident++-- Construct a renaming of all variables inside the pattern to fresh identifiers+bindRenameEnv :: Ident -> Pattern a -> RenameEnv -> RenameEnv+bindRenameEnv _ (LiteralPattern        _ _) env = env+bindRenameEnv v (VariablePattern      _ v') env = Map.insert v' v env+bindRenameEnv v (ConstructorPattern _ _ ts) env+  = foldr2 bindRenameEnv env (argNames v) ts+bindRenameEnv v (AsPattern            v' t) env+  = Map.insert v' v (bindRenameEnv v t env)+bindRenameEnv _ _                           _+  = internalError "CurryToIL.bindRenameEnv"++trRhs :: [Ident] -> RenameEnv -> Rhs Type -> TransM IL.Expression+trRhs vs env (SimpleRhs _ e _) = trExpr vs env e+trRhs _  _   (GuardedRhs _  _) = internalError "CurryToIL.trRhs: GuardedRhs"++-- Note that the case matching algorithm assumes that the matched+-- expression is accessible through a variable. The translation of case+-- expressions therefore introduces a let binding for the scrutinized+-- expression and immediately throws it away after the matching -- except+-- if the matching algorithm has decided to use that variable in the+-- right hand sides of the case expression. This may happen, for+-- instance, if one of the alternatives contains an as-pattern.++trExpr :: [Ident] -> RenameEnv -> Expression Type -> TransM IL.Expression+trExpr _  _   (Literal     ty l) = return $ IL.Literal (transType ty) (trLiteral l)+trExpr _  env (Variable    ty v)+  | isQualified v = fun+  | otherwise     = case Map.lookup (unqualify v) env of+      Nothing -> fun+      Just v' -> return $ IL.Variable (transType ty) v' -- apply renaming+  where fun = (IL.Function (transType ty) v . arrowArity) <$> varType v+trExpr _  _   (Constructor ty c)+  = (IL.Constructor (transType ty) c . arrowArity) <$> constrType c+trExpr vs env (Apply     e1 e2)+  = IL.Apply <$> trExpr vs env e1 <*> trExpr vs env e2+trExpr vs env (Let        ds e) = do+  e' <- trExpr vs env' e+  case ds of+    [FreeDecl _ vs']+       -> return $ foldr IL.Exist e' $ map varIdent vs'+    [d] | all (`notElem` bv d) (qfv emptyMIdent d)+      -> flip IL.Let    e' <$>      trBinding d+    _ -> flip IL.Letrec e' <$> mapM trBinding ds+  where+  env' = foldr2 Map.insert env bvs bvs+  bvs  = bv ds+  trBinding (PatternDecl _ (VariablePattern _ v) rhs)+    = IL.Binding v <$> trRhs vs env' rhs+  trBinding p = error $ "unexpected binding: " ++ show p+trExpr (v:vs) env (Case ct e alts) = do+  -- the ident v is used for the case expression subject, as this could+  -- be referenced in the case alternatives by a variable pattern+  e' <- trExpr vs env e+  let matcher = if ct == Flex then flexMatch else rigidMatch+      ty'     = transType $ typeOf e+  expr <- matcher [(ty', v)] <$> mapM (trAlt (v:vs) env) alts+  return $ case expr of+    IL.Case mode (IL.Variable _ v') alts'+        -- subject is not referenced -> forget v and insert subject+      | v == v' && v `notElem` fv alts' -> IL.Case mode e' alts'+    _+        -- subject is referenced -> introduce binding for v as subject+      | v `elem` fv expr                -> IL.Let (IL.Binding v e') expr+      | otherwise                       -> expr+trExpr  vs env (Typed e (QualTypeExpr _ ty)) =+  flip IL.Typed ty' <$> trExpr vs env e+  where ty' = transType (toType [] ty)+trExpr _ _ _ = internalError "CurryToIL.trExpr"++trAlt :: [Ident] -> RenameEnv -> Alt Type -> TransM Match+trAlt ~(v:vs) env (Alt _ t rhs) = do+  rhs' <- trRhs vs (bindRenameEnv v t env) rhs+  return ([trPattern v t], rhs')++trLiteral :: Literal -> IL.Literal+trLiteral (Char  c) = IL.Char c+trLiteral (Int   i) = IL.Int i+trLiteral (Float f) = IL.Float f+trLiteral _         = internalError "CurryToIL.trLiteral"++-- -----------------------------------------------------------------------------+-- Translation of Patterns+-- -----------------------------------------------------------------------------++data NestedTerm = NestedTerm IL.ConstrTerm [NestedTerm] deriving Show++pattern :: NestedTerm -> IL.ConstrTerm+pattern (NestedTerm t _) = t++arguments :: NestedTerm -> [NestedTerm]+arguments (NestedTerm _ ts) = ts++trPattern :: Ident -> Pattern Type -> NestedTerm+trPattern _ (LiteralPattern        ty l)+  = NestedTerm (IL.LiteralPattern (transType ty) $ trLiteral l) []+trPattern v (VariablePattern       ty _)+  = NestedTerm (IL.VariablePattern (transType ty) v) []+trPattern v (ConstructorPattern ty c ts)+  = NestedTerm (IL.ConstructorPattern (transType ty) c vs')+               (zipWith trPattern vs ts)+  where vs  = argNames v+        vs' = zip (map (transType . typeOf) ts) vs+trPattern v (AsPattern              _ t) = trPattern v t+trPattern _ _                            = internalError "CurryToIL.trPattern"++argNames :: Ident -> [Ident]+argNames v = [mkIdent (prefix ++ show i) | i <- [1 :: Integer ..] ]+  where prefix = idName v ++ "_"++-- -----------------------------------------------------------------------------+-- Flexible Pattern Matching Algorithm+-- -----------------------------------------------------------------------------++-- The pattern matching code searches for the left-most inductive+-- argument position in the left hand sides of all rules defining an+-- equation. An inductive position is a position where all rules have a+-- constructor rooted term. If such a position is found, a flexible 'case'+-- expression is generated for the argument at that position. The+-- matching code is then computed recursively for all of the alternatives+-- independently. If no inductive position is found, the algorithm looks+-- for the left-most demanded argument position, i.e., a position where+-- at least one of the rules has a constructor rooted term. If such a+-- position is found, an 'or' expression is generated with those+-- cases that have a variable at the argument position in one branch and+-- all other rules in the other branch. If there is no demanded position,+-- the pattern matching is finished and the compiler translates the right+-- hand sides of the remaining rules, eventually combining them using+-- 'or' expressions.++-- Actually, the algorithm below combines the search for inductive and+-- demanded positions. The function 'flexMatch' scans the argument+-- lists for the left-most demanded position. If this turns out to be+-- also an inductive position, the function 'flexMatchInductive' is+-- called in order to generate a flexible 'case' expression. Otherwise, the+-- function 'optFlexMatch' is called that tries to find an inductive+-- position in the remaining arguments. If one is found,+-- 'flexMatchInductive' is called, otherwise the function+-- 'optFlexMatch' uses the demanded argument position found by 'flexMatch'.++-- a @Match@ is a list of patterns and the respective expression.+type Match  = ([NestedTerm], IL.Expression)+-- a @Match'@ is a @Match@ with skipped patterns during the search for an+-- inductive position.+type Match' = (FunList NestedTerm, [NestedTerm], IL.Expression)+-- Functional lists+type FunList a = [a] -> [a]++flexMatch :: [(IL.Type, Ident)] -- variables to be matched+          -> [Match]            -- alternatives+          -> IL.Expression      -- result expression+flexMatch []     alts = foldl1 IL.Or (map snd alts)+flexMatch (v:vs) alts+  | notDemanded = varExp+  | isInductive = conExp+  | otherwise   = optFlexMatch (IL.Or conExp varExp) (v:) vs (map skipPat alts)+  where+  isInductive        = null varAlts+  notDemanded        = null conAlts+  -- separate variable and constructor patterns+  (varAlts, conAlts) = partition isVarMatch (map tagAlt alts)+  -- match variables+  varExp             = flexMatch               vs (map snd  varAlts)+  -- match constructors+  conExp             = flexMatchInductive id v vs (map prep conAlts)+  prep (p, (ts, e))  = (p, (id, ts, e))++-- Search for the next inductive position+optFlexMatch :: IL.Expression            -- default expression+             -> FunList (IL.Type, Ident) -- skipped variables+             -> [(IL.Type, Ident)]       -- next variables+             -> [Match']                 -- alternatives+             -> IL.Expression+optFlexMatch def _      []     _    = def+optFlexMatch def prefix (v:vs) alts+  | isInductive = flexMatchInductive prefix v vs alts'+  | otherwise   = optFlexMatch def (prefix . (v:)) vs (map skipPat' alts)+  where+  isInductive   = not (any isVarMatch alts')+  alts'         = map tagAlt' alts++-- Generate a case expression matching the inductive position+flexMatchInductive :: FunList (IL.Type, Ident)  -- skipped variables+                   -> (IL.Type, Ident)          -- current variable+                   -> [(IL.Type, Ident)]        -- next variables+                   -> [(IL.ConstrTerm, Match')] -- alternatives+                   -> IL.Expression+flexMatchInductive prefix v vs as+  = IL.Case IL.Flex (uncurry IL.Variable v) (flexMatchAlts as)+  where+  -- create alternatives for the different constructors+  flexMatchAlts []              = []+  flexMatchAlts ((t, e) : alts) = IL.Alt t expr : flexMatchAlts others+    where+    -- match nested patterns for same constructors+    expr = flexMatch (prefix (vars t ++ vs)) (map expandVars (e : map snd same))+    expandVars (pref, ts1, e') = (pref ts1, e')+    -- split into same and other constructors+    (same, others) = partition ((t ==) . fst) alts++-- -----------------------------------------------------------------------------+-- Rigid Pattern Matching Algorithm+-- -----------------------------------------------------------------------------++-- Matching in a 'case'-expression works a little bit differently.+-- In this case, the alternatives are matched from the first to the last+-- alternative and the first matching alternative is chosen. All+-- remaining alternatives are discarded.++-- TODO: The case matching algorithm should use type information in order+-- to detect total matches and immediately discard all alternatives which+-- cannot be reached.++rigidMatch :: [(IL.Type, Ident)] -> [Match] -> IL.Expression+rigidMatch vs alts = rigidOptMatch (snd $ head alts) id vs (map prepare alts)+  where prepare (ts, e) = (id, ts, e)++rigidOptMatch :: IL.Expression            -- default expression+              -> FunList (IL.Type, Ident) -- variables to be matched next+              -> [(IL.Type, Ident)]       -- variables to be matched afterwards+              -> [Match']                 -- translated equations+              -> IL.Expression+-- if there are no variables left: return the default expression+rigidOptMatch def _      []       _    = def+rigidOptMatch def prefix (v : vs) alts+  | isDemanded = rigidMatchDemanded prefix v vs alts'+  | otherwise  = rigidOptMatch def (prefix . (v:)) vs (map skipPat' alts)+  where+  isDemanded   = not $ isVarMatch (head alts')+  alts'        = map tagAlt' alts++-- Generate a case expression matching the demanded position.+-- This algorithm constructs a branch for all contained patterns, where+-- the right-hand side then respects the order of the patterns.+-- Thus, the expression+--    case x of+--      []   -> []+--      ys   -> ys+--      y:ys -> [y]+-- gets translated to+--    case x of+--      []   -> []+--      y:ys -> x+--      x    -> x+rigidMatchDemanded :: FunList (IL.Type, Ident)  -- skipped variables+                   -> (IL.Type, Ident)          -- current variable+                   -> [(IL.Type, Ident)]        -- next variables+                   -> [(IL.ConstrTerm, Match')] -- alternatives+                   -> IL.Expression+rigidMatchDemanded prefix v vs alts = IL.Case IL.Rigid (uncurry IL.Variable v)+  $ map caseAlt (consPats ++ varPats)+  where+  -- N.B.: @varPats@ is either empty or a singleton list due to nub+  (varPats, consPats) = partition isVarPattern $ nub $ map fst alts+  caseAlt t           = IL.Alt t expr+    where+    expr = rigidMatch (prefix $ vars t ++ vs) (matchingCases alts)+    -- matchingCases selects the matching alternatives+    --  and recursively matches the remaining patterns+    matchingCases a = map (expandVars (vars t)) $ filter (matches . fst) a+    matches t' = t == t' || isVarPattern t'+    expandVars vs' (p, (pref, ts1, e)) = (pref ts2, e)+      where ts2 | isVarPattern p = map var2Pattern vs' ++ ts1+                | otherwise      = ts1+            var2Pattern v' = NestedTerm (uncurry IL.VariablePattern v') []++-- -----------------------------------------------------------------------------+-- Pattern Matching Auxiliaries+-- -----------------------------------------------------------------------------++isVarPattern :: IL.ConstrTerm -> Bool+isVarPattern (IL.VariablePattern _ _) = True+isVarPattern _                        = False++isVarMatch :: (IL.ConstrTerm, a) -> Bool+isVarMatch = isVarPattern . fst++vars :: IL.ConstrTerm -> [(IL.Type, Ident)]+vars (IL.ConstructorPattern _ _ vs) = vs+vars _                              = []++-- tagAlt extracts the structure of the first pattern+tagAlt :: Match -> (IL.ConstrTerm, Match)+tagAlt (t:ts, e) = (pattern t, (arguments t ++ ts, e))+tagAlt ([]  , _) = error "CurryToIL.tagAlt: empty pattern list"++-- skipPat skips the current pattern position for later matching+skipPat :: Match -> Match'+skipPat (t:ts, e) = ((t:), ts, e)+skipPat ([]  , _) = error "CurryToIL.skipPat: empty pattern list"++-- tagAlt' extracts the next pattern+tagAlt' :: Match' -> (IL.ConstrTerm, Match')+tagAlt' (pref, t:ts, e') = (pattern t, (pref, arguments t ++ ts, e'))+tagAlt' (_   , []  , _ ) = error "CurryToIL.tagAlt': empty pattern list"++-- skipPat' skips the current argument for later matching+skipPat' :: Match' -> Match'+skipPat' (pref, t:ts, e') = (pref . (t:), ts, e')+skipPat' (_   , []  , _ ) = error "CurryToIL.skipPat': empty pattern list"
+ src/Transformations/Derive.hs view
@@ -0,0 +1,637 @@+{- |+  Module      :  $Header$+  Description :  Deriving instances+  Copyright   :  (c) 2016        Finn Teegen+  License     :  BSD-3-clause++  Maintainer  :  bjp@informatik.uni-kiel.de+  Stability   :  experimental+  Portability :  portable++  TODO+-}+{-# LANGUAGE CPP #-}+module Transformations.Derive (derive) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative      ((<$>))+#endif+import qualified Control.Monad.State as S (State, evalState, gets, modify)+import           Data.List         (intercalate, intersperse)+import           Data.Maybe        (fromJust, isJust)+import qualified Data.Set   as Set (deleteMin, union)++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Syntax++import Base.CurryTypes (fromPredType)+import Base.Messages (internalError)+import Base.Types+import Base.TypeSubst (instanceType)+import Base.Typing (typeOf)+import Base.Utils (snd3, mapAccumM)++import Env.Instance+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++data DVState = DVState+  { moduleIdent :: ModuleIdent+  , tyConsEnv   :: TCEnv+  , valueEnv    :: ValueEnv+  , instEnv     :: InstEnv+  , opPrecEnv   :: OpPrecEnv+  , nextId      :: Integer+  }++type DVM = S.State DVState++derive :: TCEnv -> ValueEnv -> InstEnv -> OpPrecEnv -> Module PredType+       -> Module PredType+derive tcEnv vEnv inEnv pEnv (Module ps m es is ds) = Module ps m es is $+  ds ++ concat (S.evalState (mapM deriveInstances tds) initState)+  where tds = filter isTypeDecl ds+        initState = DVState m tcEnv vEnv inEnv pEnv 1++getModuleIdent :: DVM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTyConsEnv :: DVM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: DVM ValueEnv+getValueEnv = S.gets valueEnv++getInstEnv :: DVM InstEnv+getInstEnv = S.gets instEnv++getPrecEnv :: DVM OpPrecEnv+getPrecEnv = S.gets opPrecEnv++getNextId :: DVM Integer+getNextId = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return nid++-- TODO: Comment (here and below)++type ConstrInfo = (Int, QualIdent, Maybe [Ident], [Type])++-- An instance declaration is created for each type class of a deriving clause.+-- Newtype declaration are simply treated as data declarations.++deriveInstances :: Decl PredType -> DVM [Decl PredType]+deriveInstances (DataDecl    _ tc tvs _ clss) = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  let otc = qualifyWith m tc+      cis = constructors m otc tcEnv+  mapM (deriveInstance otc tvs cis) clss+deriveInstances (NewtypeDecl p tc tvs _ clss) =+  deriveInstances $ DataDecl p tc tvs [] clss+deriveInstances _                             = return []++deriveInstance :: QualIdent -> [Ident] -> [ConstrInfo] -> QualIdent+               -> DVM (Decl PredType)+deriveInstance tc tvs cis cls = do+  inEnv <- getInstEnv+  let ps = snd3 $ fromJust $ lookupInstInfo (cls, tc) inEnv+      ty = applyType (TypeConstructor tc) $+             take (length tvs) $ map TypeVariable [0 ..]+      QualTypeExpr cx inst = fromPredType tvs $ PredType ps ty+  ds <- deriveMethods cls ty cis ps+  return $ InstanceDecl NoPos cx cls inst ds++-- Note: The methods and arities of the generated instance declarations have to+-- correspond to the methods and arities entered previously into the instance+-- environment (see instance check).++deriveMethods :: QualIdent -> Type -> [ConstrInfo] -> PredSet+              -> DVM [Decl PredType]+deriveMethods cls+  | cls == qEqId      = deriveEqMethods+  | cls == qOrdId     = deriveOrdMethods+  | cls == qEnumId    = deriveEnumMethods+  | cls == qBoundedId = deriveBoundedMethods+  | cls == qReadId    = deriveReadMethods+  | cls == qShowId    = deriveShowMethods+  | otherwise         = internalError $ "Derive.deriveMethods: " ++ show cls++-- Binary Operators:++type BinOpExpr = Int+              -> [Expression PredType]+              -> Int+              -> [Expression PredType]+              -> Expression PredType++deriveBinOp :: QualIdent -> Ident -> BinOpExpr -> Type -> [ConstrInfo]+            -> PredSet -> DVM (Decl PredType)+deriveBinOp cls op expr ty cis ps = do+  pty <- getInstMethodType ps cls ty op+  eqs <- mapM (deriveBinOpEquation op expr ty) $ sequence [cis, cis]+  return $ FunctionDecl NoPos pty op eqs++deriveBinOpEquation :: Ident -> BinOpExpr -> Type -> [ConstrInfo]+                    -> DVM (Equation PredType)+deriveBinOpEquation op expr ty [(i1, c1, _, tys1), (i2, c2, _, tys2)] = do+  vs1 <- mapM (freshArgument . instType) tys1+  vs2 <- mapM (freshArgument . instType) tys2+  let pat1 = constrPattern pty c1 vs1+      pat2 = constrPattern pty c2 vs2+      es1 = map (uncurry mkVar) vs1+      es2 = map (uncurry mkVar) vs2+  return $ mkEquation NoPos op [pat1, pat2] $ expr i1 es1 i2 es2+  where pty = predType $ instType ty+deriveBinOpEquation _ _ _ _ = internalError "Derive.deriveBinOpEquation"++-- Equality:++deriveEqMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveEqMethods ty cis ps = sequence+  [deriveBinOp qEqId eqOpId eqOpExpr ty cis ps]++eqOpExpr :: BinOpExpr+eqOpExpr i1 es1 i2 es2+  | i1 == i2  = if null es1 then prelTrue+                            else foldl1 prelAnd $ zipWith prelEq es1 es2+  | otherwise = prelFalse++-- Ordering:++deriveOrdMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveOrdMethods ty cis ps = sequence+  [deriveBinOp qOrdId leqOpId leqOpExpr ty cis ps]++leqOpExpr :: BinOpExpr+leqOpExpr i1 es1 i2 es2+  | i1 < i2   = prelTrue+  | i1 > i2   = prelFalse+  | otherwise = if null es1 then prelTrue+                            else foldl1 prelOr $ map innerAnd [0 .. n - 1]+  where n = length es1+        innerAnd i = foldl1 prelAnd $ map (innerOp i) [0 .. i]+        innerOp i j | j == n - 1 = prelLeq (es1 !! j) (es2 !! j)+                    | j == i     = prelLt  (es1 !! j) (es2 !! j)+                    | otherwise  = prelEq  (es1 !! j) (es2 !! j)++-- Enumerations:++deriveEnumMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveEnumMethods ty cis ps = sequence+  [ deriveSuccOrPred succId ty cis (tail cis) ps+  , deriveSuccOrPred predId ty (tail cis) cis ps+  , deriveToEnum ty cis ps+  , deriveFromEnum ty cis ps+  , deriveEnumFrom ty (last cis) ps+  , deriveEnumFromThen ty (head cis) (last cis) ps+  ]++deriveSuccOrPred :: Ident -> Type -> [ConstrInfo] -> [ConstrInfo] -> PredSet+                 -> DVM (Decl PredType)+deriveSuccOrPred f ty cis1 cis2 ps = do+  pty <- getInstMethodType ps qEnumId ty f+  FunctionDecl NoPos pty f <$> if null eqs+                                 then do+                                        v <- freshArgument $ instType ty+                                        return [failedEquation f ty v]+                                 else return eqs+  where eqs = zipWith (succOrPredEquation f ty) cis1 cis2++succOrPredEquation :: Ident -> Type -> ConstrInfo -> ConstrInfo+                   -> Equation PredType+succOrPredEquation f ty (_, c1, _, _) (_, c2, _, _) =+  mkEquation NoPos f [ConstructorPattern pty c1 []] $ Constructor pty c2+  where pty = predType $ instType ty++failedEquation :: Ident -> Type -> (PredType, Ident) -> Equation PredType+failedEquation f ty v =+  mkEquation NoPos f [uncurry VariablePattern v] $ preludeFailed $ instType ty++deriveToEnum :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveToEnum ty cis ps = do+  pty <- getInstMethodType ps qEnumId ty toEnumId+  return $ FunctionDecl NoPos pty toEnumId eqs+  where eqs = zipWith (toEnumEquation ty) [0 ..] cis++toEnumEquation :: Type -> Integer -> ConstrInfo -> Equation PredType+toEnumEquation ty i (_, c, _, _) =+  mkEquation NoPos toEnumId [LiteralPattern (predType intType) (Int i)] $+    Constructor (predType $ instType ty) c++deriveFromEnum :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveFromEnum ty cis ps = do+  pty <- getInstMethodType ps qEnumId ty fromEnumId+  return $ FunctionDecl NoPos pty fromEnumId eqs+  where eqs = zipWith (fromEnumEquation ty) cis [0 ..]++fromEnumEquation :: Type -> ConstrInfo -> Integer -> Equation PredType+fromEnumEquation ty (_, c, _, _) i =+  mkEquation NoPos fromEnumId [ConstructorPattern pty c []] $+    Literal (predType intType) $ Int i+  where pty = predType $ instType ty++deriveEnumFrom :: Type -> ConstrInfo -> PredSet -> DVM (Decl PredType)+deriveEnumFrom ty (_, c, _, _) ps = do+  pty <- getInstMethodType ps qEnumId ty enumFromId+  v <- freshArgument $ instType ty+  return $ funDecl NoPos pty enumFromId [uncurry VariablePattern v] $+    enumFromExpr v c++enumFromExpr :: (PredType, Ident) -> QualIdent -> Expression PredType+enumFromExpr v c = prelEnumFromTo (uncurry mkVar v) $ Constructor (fst v) c++deriveEnumFromThen :: Type -> ConstrInfo -> ConstrInfo -> PredSet+                   -> DVM (Decl PredType)+deriveEnumFromThen ty (_, c1, _, _) (_, c2, _, _) ps = do+  pty <- getInstMethodType ps qEnumId ty enumFromId+  vs@[v1, v2] <- mapM (freshArgument . instType) $ replicate 2 ty+  return $ funDecl NoPos pty enumFromThenId (map (uncurry VariablePattern) vs) $+    enumFromThenExpr v1 v2 c1 c2++enumFromThenExpr :: (PredType, Ident) -> (PredType, Ident) -> QualIdent+                 -> QualIdent -> Expression PredType+enumFromThenExpr v1 v2 c1 c2 =+  prelEnumFromThenTo (uncurry mkVar v1) (uncurry mkVar v2) $ boundedExpr+  where boundedExpr = IfThenElse (prelLeq+                                   (prelFromEnum $ uncurry mkVar v1)+                                   (prelFromEnum $ uncurry mkVar v2))+                                 (Constructor (fst v1) c2)+                                 (Constructor (fst v1) c1)++-- Upper and Lower Bounds:++deriveBoundedMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveBoundedMethods ty cis ps = sequence+  [ deriveMaxOrMinBound qMaxBoundId ty (head cis) ps+  , deriveMaxOrMinBound qMinBoundId ty (last cis) ps+  ]++deriveMaxOrMinBound :: QualIdent -> Type -> ConstrInfo -> PredSet+                    -> DVM (Decl PredType)+deriveMaxOrMinBound f ty (_, c, _, tys) ps = do+  pty <- getInstMethodType ps qBoundedId ty $ unqualify f+  return $ funDecl NoPos pty (unqualify f) [] $ maxOrMinBoundExpr f c ty tys++maxOrMinBoundExpr :: QualIdent -> QualIdent -> Type -> [Type]+                  -> Expression PredType+maxOrMinBoundExpr f c ty tys =+  apply (Constructor pty c) $ map (flip Variable f . predType) instTys+  where instTy:instTys = map instType $ ty : tys+        pty = predType $ foldr TypeArrow instTy instTys++-- Read:++deriveReadMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveReadMethods ty cis ps = sequence [deriveReadsPrec ty cis ps]++deriveReadsPrec :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveReadsPrec ty cis ps = do+  pty <- getInstMethodType ps qReadId ty $ readsPrecId+  d <- freshArgument intType+  r <- freshArgument stringType+  let pats = map (uncurry VariablePattern) [d, r]+  funDecl NoPos pty readsPrecId pats <$>+    deriveReadsPrecExpr ty cis (uncurry mkVar d) (uncurry mkVar r)++deriveReadsPrecExpr :: Type -> [ConstrInfo] -> Expression PredType+                    -> Expression PredType -> DVM (Expression PredType)+deriveReadsPrecExpr ty cis d r = do+  es <- mapM (deriveReadsPrecReadParenExpr ty d) cis+  return $ foldr1 prelAppend $ map (flip Apply r) $ es++deriveReadsPrecReadParenExpr :: Type -> Expression PredType -> ConstrInfo+                             -> DVM (Expression PredType)+deriveReadsPrecReadParenExpr ty d ci@(_, c, _, _) = do+  pEnv <- getPrecEnv+  let p = precedence c pEnv+  e <- deriveReadsPrecLambdaExpr ty ci p+  return $ prelReadParen (readsPrecReadParenCondExpr ci d p) e++readsPrecReadParenCondExpr :: ConstrInfo -> Expression PredType -> Precedence+                           -> Expression PredType+readsPrecReadParenCondExpr (_, c, _, tys) d p+  | null tys                        = prelFalse+  | isQInfixOp c && length tys == 2 =+    prelLt (Literal predIntType $ Int p) d+  | otherwise                       =+    prelLt (Literal predIntType $ Int 10) d++deriveReadsPrecLambdaExpr :: Type -> ConstrInfo -> Precedence+                      -> DVM (Expression PredType)+deriveReadsPrecLambdaExpr ty (_, c, ls, tys) p = do+  r <- freshArgument stringType+  (stmts, vs, s) <- deriveReadsPrecStmts (unqualify c) (p + 1) r ls tys+  let pty = predType $ foldr TypeArrow (instType ty) $ map instType tys+      e = Tuple [ apply (Constructor pty c) $ map (uncurry mkVar) vs+                , uncurry mkVar s+                ]+  return $ Lambda [uncurry VariablePattern r] $ ListCompr e stmts++deriveReadsPrecStmts+  :: Ident -> Precedence -> (PredType, Ident) -> Maybe [Ident] -> [Type]+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecStmts c p r ls tys+  | null tys                       = deriveReadsPrecNullaryConstrStmts c r+  | isJust ls                      =+    deriveReadsPrecRecordConstrStmts c r (fromJust ls) tys+  | isInfixOp c && length tys == 2 = deriveReadsPrecInfixConstrStmts c p r tys+  | otherwise                      = deriveReadsPrecConstrStmts c r tys++deriveReadsPrecNullaryConstrStmts+  :: Ident -> (PredType, Ident)+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecNullaryConstrStmts c r = do+  (s, stmt) <- deriveReadsPrecLexStmt (idName c) r+  return ([stmt], [], s)++deriveReadsPrecRecordConstrStmts+  :: Ident -> (PredType, Ident) -> [Ident] -> [Type]+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecRecordConstrStmts c r ls tys = do+  (s, stmt1) <- deriveReadsPrecLexStmt (idName c) r+  (t, ress) <-+    mapAccumM deriveReadsPrecFieldStmts s $ zip3 ("{" : repeat ",") ls tys+  let (stmtss, vs) = unzip ress+  (u, stmt2) <- deriveReadsPrecLexStmt "}" t+  return (stmt1 : concat stmtss ++ [stmt2], vs, u)++deriveReadsPrecFieldStmts+  :: (PredType, Ident) -> (String, Ident, Type)+  -> DVM ((PredType, Ident), ([Statement PredType], (PredType, Ident)))+deriveReadsPrecFieldStmts r (pre, l, ty) = do+  (s, stmt1) <- deriveReadsPrecLexStmt pre r+  (t, stmt2) <- deriveReadsPrecLexStmt (idName l) s+  (u, stmt3) <- deriveReadsPrecLexStmt "=" t+  (w, (stmt4, v)) <- deriveReadsPrecReadsPrecStmt 0 u ty+  return (w, ([stmt1, stmt2, stmt3, stmt4], v))++deriveReadsPrecInfixConstrStmts+  :: Ident -> Precedence -> (PredType, Ident) -> [Type]+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecInfixConstrStmts c p r tys = do+  (s, (stmt1, v1)) <- deriveReadsPrecReadsPrecStmt (p + 1) r $ head tys+  (t, stmt2) <- deriveReadsPrecLexStmt (idName c) s+  (u, (stmt3, v2)) <- deriveReadsPrecReadsPrecStmt (p + 1) t $ head $ tail tys+  return ([stmt1, stmt2, stmt3], [v1, v2], u)++deriveReadsPrecConstrStmts+  :: Ident -> (PredType, Ident) -> [Type]+  -> DVM ([Statement PredType], [(PredType, Ident)], (PredType, Ident))+deriveReadsPrecConstrStmts c r tys = do+    (s, stmt) <- deriveReadsPrecLexStmt (idName c) r+    (t, ress) <- mapAccumM (deriveReadsPrecReadsPrecStmt 11) s tys+    let (stmts, vs) = unzip ress+    return (stmt : stmts, vs, t)++deriveReadsPrecLexStmt :: String -> (PredType, Ident)+                      -> DVM ((PredType, Ident), Statement PredType)+deriveReadsPrecLexStmt str r = do+  s <- freshArgument $ stringType+  let pat  = TuplePattern+               [ LiteralPattern predStringType $ String str+               , uncurry VariablePattern s+               ]+      stmt = StmtBind pat $ preludeLex $ uncurry mkVar r+  return (s, stmt)++deriveReadsPrecReadsPrecStmt  :: Precedence -> (PredType, Ident) -> Type+      -> DVM ((PredType, Ident), (Statement PredType, (PredType, Ident)))+deriveReadsPrecReadsPrecStmt p r ty = do+  v <- freshArgument $ instType ty+  s <- freshArgument $ stringType+  let pat  = TuplePattern $ map (uncurry VariablePattern) [v, s]+      stmt = StmtBind pat $ preludeReadsPrec (instType ty) p $+               uncurry mkVar r+  return (s, (stmt, v))++-- Show:++deriveShowMethods :: Type -> [ConstrInfo] -> PredSet -> DVM [Decl PredType]+deriveShowMethods ty cis ps = sequence [deriveShowsPrec ty cis ps]++deriveShowsPrec :: Type -> [ConstrInfo] -> PredSet -> DVM (Decl PredType)+deriveShowsPrec ty cis ps = do+  pty <- getInstMethodType ps qShowId ty $ showsPrecId+  eqs <- mapM (deriveShowsPrecEquation ty) cis+  return $ FunctionDecl NoPos pty showsPrecId eqs++deriveShowsPrecEquation :: Type -> ConstrInfo -> DVM (Equation PredType)+deriveShowsPrecEquation ty (_, c, ls, tys) = do+  d <- freshArgument intType+  vs <- mapM (freshArgument . instType) tys+  let pats = [uncurry VariablePattern d, constrPattern pty c vs]+  pEnv <- getPrecEnv+  return $ mkEquation NoPos showsPrecId pats $ showsPrecExpr (unqualify c)+    (precedence c pEnv) ls (uncurry mkVar d) $ map (uncurry mkVar) vs+  where pty = predType $ instType ty++showsPrecExpr :: Ident -> Precedence -> Maybe [Ident] -> Expression PredType+              -> [Expression PredType] -> Expression PredType+showsPrecExpr c p ls d vs+  | null vs                       = showsPrecNullaryConstrExpr c+  | isJust ls                     = showsPrecShowParenExpr d 10 $+    showsPrecRecordConstrExpr c (fromJust ls) vs+  | isInfixOp c && length vs == 2 = showsPrecShowParenExpr d p $+    showsPrecInfixConstrExpr c p vs+  | otherwise                     = showsPrecShowParenExpr d 10 $+    showsPrecConstrExpr c vs++showsPrecNullaryConstrExpr :: Ident -> Expression PredType+showsPrecNullaryConstrExpr c = preludeShowString $ showsConstr c ""++showsPrecShowParenExpr :: Expression PredType -> Precedence+                       -> Expression PredType -> Expression PredType+showsPrecShowParenExpr d p =+  prelShowParen $ prelLt (Literal predIntType $ Int p) d++showsPrecRecordConstrExpr :: Ident -> [Ident] -> [Expression PredType]+                          -> Expression PredType+showsPrecRecordConstrExpr c ls vs = foldr prelDot (preludeShowString "}") $+  (:) (preludeShowString $ showsConstr c " {") $+    intercalate [preludeShowString ", "] $ zipWith showsPrecFieldExpr ls vs++showsPrecFieldExpr :: Ident -> Expression PredType -> [Expression PredType]+showsPrecFieldExpr l v =+  [preludeShowString $ showsConstr l " = ", preludeShowsPrec 0 v]++showsPrecInfixConstrExpr :: Ident -> Precedence -> [Expression PredType]+                         -> Expression PredType+showsPrecInfixConstrExpr c p vs = foldr1 prelDot+  [ preludeShowsPrec (p + 1) $ head vs+  , preludeShowString $ ' ' : idName c ++ " "+  , preludeShowsPrec (p + 1) $ head $ tail vs+  ]++showsPrecConstrExpr :: Ident -> [Expression PredType] -> Expression PredType+showsPrecConstrExpr c vs = foldr1 prelDot $+  preludeShowString (showsConstr c " ") :+    intersperse (preludeShowString " ") (map (preludeShowsPrec 11) vs)++-- -----------------------------------------------------------------------------+-- Generating variables+-- -----------------------------------------------------------------------------++freshArgument :: Type -> DVM (PredType, Ident)+freshArgument = freshVar "_#arg"++freshVar :: String -> Type -> DVM (PredType, Ident)+freshVar name ty =+  ((,) (predType ty)) . mkIdent . (name ++) .  show <$> getNextId++-- -----------------------------------------------------------------------------+-- Auxiliary functions+-- -----------------------------------------------------------------------------++constructors :: ModuleIdent -> QualIdent -> TCEnv -> [ConstrInfo]+constructors m tc tcEnv =  zipWith (mkConstrInfo m) [1 ..] $+  case qualLookupTypeInfo tc tcEnv of+    [DataType     _ _ cs] -> cs+    [RenamingType _ _ nc] -> [nc]+    _                     -> internalError $ "Derive.constructors: " ++ show tc++mkConstrInfo :: ModuleIdent -> Int -> DataConstr -> ConstrInfo+mkConstrInfo m i (DataConstr   c _ _    tys) =+  (i, qualifyWith m c, Nothing, tys)+mkConstrInfo m i (RecordConstr c _ _ ls tys) =+  (i, qualifyWith m c, Just ls, tys)++showsConstr :: Ident -> ShowS+showsConstr c = showParen (isInfixOp c) $ showString $ idName c++precedence :: QualIdent -> OpPrecEnv -> Precedence+precedence op pEnv = case qualLookupP op pEnv of+  [] -> defaultPrecedence+  PrecInfo _ (OpPrec _ p) : _ -> p++instType :: Type -> Type+instType (TypeConstructor tc) = TypeConstructor tc+instType (TypeVariable    tv) = TypeVariable (-1 - tv)+instType (TypeApply  ty1 ty2) = TypeApply (instType ty1) (instType ty2)+instType (TypeArrow  ty1 ty2) = TypeArrow (instType ty1) (instType ty2)+instType ty = ty++-- Returns the type for a given instance's method of a given class. To this+-- end, the class method's type is stripped of its first predicate (which is+-- the implicit class constraint) and the class variable is replaced with the+-- instance's type. The remaining predicate set is then united with the+-- instance's predicate set.++getInstMethodType :: PredSet -> QualIdent -> Type -> Ident -> DVM PredType+getInstMethodType ps cls ty f = do+  vEnv <- getValueEnv+  return $ instMethodType vEnv ps cls ty f++instMethodType :: ValueEnv -> PredSet -> QualIdent -> Type -> Ident -> PredType+instMethodType vEnv ps cls ty f = PredType (ps `Set.union` ps'') ty''+  where PredType ps' ty' = case qualLookupValue (qualifyLike cls f) vEnv of+          [Value _ _ _ (ForAll _ pty)] -> pty+          _ -> internalError $ "Derive.instMethodType"+        PredType ps'' ty'' = instanceType ty $ PredType (Set.deleteMin ps') ty'++-- -----------------------------------------------------------------------------+-- Prelude entities+-- -----------------------------------------------------------------------------++prelTrue :: Expression PredType+prelTrue = Constructor predBoolType qTrueId++prelFalse :: Expression PredType+prelFalse = Constructor predBoolType qFalseId++prelAppend :: Expression PredType -> Expression PredType -> Expression PredType+prelAppend e1 e2 = foldl1 Apply [Variable pty qAppendOpId, e1, e2]+  where pty = predType $ foldr1 TypeArrow $ replicate 3 $ typeOf e1++prelDot :: Expression PredType -> Expression PredType -> Expression PredType+prelDot e1 e2 = foldl1 Apply [Variable pty qDotOpId, e1, e2]+  where ty1@(TypeArrow _    ty12) = typeOf e1+        ty2@(TypeArrow ty21 _   ) = typeOf e2+        pty = predType $ foldr1 TypeArrow [ty1, ty2, ty21, ty12]++prelAnd :: Expression PredType -> Expression PredType -> Expression PredType+prelAnd e1 e2 = foldl1 Apply [Variable pty qAndOpId, e1, e2]+  where pty = predType $ foldr1 TypeArrow $ replicate 3 boolType++prelEq :: Expression PredType -> Expression PredType -> Expression PredType+prelEq e1 e2 = foldl1 Apply [Variable pty qEqOpId, e1, e2]+  where ty = typeOf e1+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelLeq :: Expression PredType -> Expression PredType -> Expression PredType+prelLeq e1 e2 = foldl1 Apply [Variable pty qLeqOpId, e1, e2]+  where ty = typeOf e1+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelLt :: Expression PredType -> Expression PredType -> Expression PredType+prelLt e1 e2 = foldl1 Apply [Variable pty qLtOpId, e1, e2]+  where ty = typeOf e1+        pty = predType $ foldr1 TypeArrow [ty, ty, boolType]++prelOr :: Expression PredType -> Expression PredType -> Expression PredType+prelOr e1 e2 = foldl1 Apply [Variable pty qOrOpId, e1, e2]+  where pty = predType $ foldr1 TypeArrow $ replicate 3 boolType++prelFromEnum :: Expression PredType -> Expression PredType+prelFromEnum e = Apply (Variable pty qFromEnumId) e+  where pty = predType $ TypeArrow (typeOf e) intType++prelEnumFromTo :: Expression PredType -> Expression PredType+               -> Expression PredType+prelEnumFromTo e1 e2 = apply (Variable pty qEnumFromToId) [e1, e2]+  where ty = typeOf e1+        pty = predType $ foldr1 TypeArrow [ty, ty, listType ty]++prelEnumFromThenTo :: Expression PredType -> Expression PredType+                   -> Expression PredType -> Expression PredType+prelEnumFromThenTo e1 e2 e3 =+  apply (Variable pty qEnumFromThenToId) [e1, e2, e3]+  where ty = typeOf e1+        pty = predType $ foldr1 TypeArrow [ty, ty, ty, listType ty]++prelReadParen :: Expression PredType -> Expression PredType+              -> Expression PredType+prelReadParen e1 e2 = apply (Variable pty qReadParenId) [e1, e2]+  where ty = typeOf e2+        pty = predType $ foldr1 TypeArrow [boolType, ty, ty]++prelShowParen :: Expression PredType -> Expression PredType+              -> Expression PredType+prelShowParen e1 e2 = apply (Variable pty qShowParenId) [e1, e2]+  where pty = predType $ foldr1 TypeArrow [ boolType+                                          , TypeArrow stringType stringType+                                          , stringType, stringType+                                          ]++preludeLex :: Expression PredType -> Expression PredType+preludeLex e = Apply (Variable pty qLexId) e+  where pty = predType $ TypeArrow stringType $+                listType $ tupleType [stringType, stringType]++preludeReadsPrec :: Type -> Integer -> Expression PredType+                 -> Expression PredType+preludeReadsPrec ty p e = flip Apply e $+  Apply (Variable pty qReadsPrecId) $ Literal predIntType $ Int p+  where pty = predType $ foldr1 TypeArrow [ intType, stringType+                                          , listType $ tupleType [ ty+                                                                 , stringType+                                                                 ]+                                          ]++preludeShowsPrec :: Integer -> Expression PredType -> Expression PredType+preludeShowsPrec p e = flip Apply e $+  Apply (Variable pty qShowsPrecId) $ Literal predIntType $ Int p+  where pty = predType $ foldr1 TypeArrow [ intType, typeOf e+                                          , stringType, stringType+                                          ]++preludeShowString :: String -> Expression PredType+preludeShowString s = Apply (Variable pty qShowStringId) $+  Literal predStringType $ String s+  where pty = predType $ foldr1 TypeArrow $ replicate 3 stringType++preludeFailed :: Type -> Expression PredType+preludeFailed ty = Variable (predType ty) qFailedId
+ src/Transformations/Desugar.hs view
@@ -0,0 +1,1070 @@+{- |+  Module      :  $Header$+  Description :  Desugaring Curry Expressions+  Copyright   :  (c) 2001 - 2004 Wolfgang Lux+                                 Martin Engelke+                     2011 - 2015 Björn Peemöller+                     2015        Jan Tikovsky+                     2016 - 2017 Finn Teegen+  License     :  BSD-3-clause++  Maintainer  :  bjp@informatik.uni-kiel.de+  Stability   :  experimental+  Portability :  portable++  The desugaring pass removes all syntactic sugar from the module.+  In particular, the output of the desugarer will have the following+  properties.++  * No guarded right hand sides occur in equations, pattern declarations,+    and case alternatives. In addition, the declaration lists (`where`-blocks)+    of the right hand sides are empty; local declarations are transformed+    into let expressions.++  * Patterns in equations and case alternatives are composed only of+    - literals,+    - variables,+    - constructor applications, and+    - as patterns applied to literals or constructor applications.++  * Expressions are composed only of+    - literals,+    - variables,+    - constructors,+    - (binary) applications,+    - case expressions,+    - let expressions, and+    - expressions with a type signature.++  * Functional patterns are replaced by variables and are integrated+    in a guarded right hand side using the (=:<=) operator.++  * Records are transformed into ordinary data types by removing the fields.+    Record construction and pattern matching are represented using solely the+    record constructor. Record selections are represented using selector+    functions which are generated for each record declaration, and record+    updated are represented using case-expressions that perform the update.++  * The type environment will be extended by new function declarations for:+    - Record selections, and+    - Converted lambda expressions.++  As we are going to insert references to real prelude entities,+  all names must be properly qualified before calling this module.+-}+{-# LANGUAGE CPP #-}+module Transformations.Desugar (desugar) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import           Control.Arrow              (first, second)+import           Control.Monad              (liftM2)+import           Control.Monad.Extra        (concatMapM)+import qualified Control.Monad.State as S   (State, runState, gets, modify)+import           Data.Foldable              (foldrM)+import           Data.List                  ( (\\), elemIndex, nub, partition+                                            , tails )+import           Data.Maybe                 (fromMaybe)+import qualified Data.Set            as Set (Set, empty, member, insert)++import Curry.Base.Ident+import Curry.Base.Position hiding (first)+import Curry.Syntax++import Base.Expr+import Base.CurryTypes+import Base.Messages (internalError)+import Base.TypeExpansion+import Base.Types+import Base.TypeSubst+import Base.Typing+import Base.Utils (fst3, mapAccumM)++import Env.TypeConstructor (TCEnv, TypeInfo (..), qualLookupTypeInfo)+import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++-- The desugaring phase keeps only the type, function, and value+-- declarations of the module, i.e., type signatures are discarded.+-- While record declarations are transformed into ordinary data/newtype+-- declarations, the remaining type declarations are not desugared.+-- Since they cannot occur in local declaration groups, they are filtered+-- out separately. Actually, the transformation is slightly more general than+-- necessary as it allows value declarations at the top-level of a module.++desugar :: [KnownExtension] -> ValueEnv -> TCEnv -> Module PredType+        -> (Module PredType, ValueEnv)+desugar xs vEnv tcEnv (Module ps m es is ds)+  = (Module ps m es is ds', valueEnv s')+  where (ds', s') = S.runState (desugarModuleDecls ds)+                               (DesugarState m xs tcEnv vEnv 1)++-- ---------------------------------------------------------------------------+-- Desugaring monad and accessor functions+-- ---------------------------------------------------------------------------++-- New identifiers may be introduced while desugaring pattern declarations,+-- case and lambda-expressions, list comprehensions, and record selections+-- and updates. As usual, we use a state monad transformer for generating+-- unique names. In addition, the state is also used for passing through the+-- type environment, which must be augmented with the types of these new+-- variables.++data DesugarState = DesugarState+  { moduleIdent :: ModuleIdent      -- read-only+  , extensions  :: [KnownExtension] -- read-only+  , tyConsEnv   :: TCEnv            -- read-only+  , valueEnv    :: ValueEnv         -- will be extended+  , nextId      :: Integer          -- counter+  }++type DsM a = S.State DesugarState a++getModuleIdent :: DsM ModuleIdent+getModuleIdent = S.gets moduleIdent++checkNegativeLitsExtension :: DsM Bool+checkNegativeLitsExtension = S.gets (\s -> NegativeLiterals `elem` extensions s)++getTyConsEnv :: DsM TCEnv+getTyConsEnv = S.gets tyConsEnv++getValueEnv :: DsM ValueEnv+getValueEnv = S.gets valueEnv++getNextId :: DsM Integer+getNextId = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return nid++-- ---------------------------------------------------------------------------+-- Generation of fresh names+-- ---------------------------------------------------------------------------++-- Create a fresh variable ident for a given prefix with a monomorphic type+freshVar :: Typeable t => String -> t -> DsM (PredType, Ident)+freshVar prefix t = do+  v <- (mkIdent . (prefix ++) . show) <$> getNextId+  return (predType $ typeOf t, v)++-- ---------------------------------------------------------------------------+-- Desugaring+-- ---------------------------------------------------------------------------++desugarModuleDecls :: [Decl PredType] -> DsM [Decl PredType]+desugarModuleDecls ds = do+  ds'   <- concatMapM dsRecordDecl ds+  ds''  <- mapM dsClassAndInstanceDecl ds'+  ds''' <- dsDeclGroup ds''+  return $ filter (not . liftM2 (||) isValueDecl isTypeSig) ds'' ++ ds'''++-- -----------------------------------------------------------------------------+-- Desugaring of class and instance declarations+-- -----------------------------------------------------------------------------++dsClassAndInstanceDecl :: Decl PredType -> DsM (Decl PredType)+dsClassAndInstanceDecl (ClassDecl p cx cls tv ds) =+  ClassDecl p cx cls tv . (tds ++) <$> dsDeclGroup vds+  where (tds, vds) = partition isTypeSig ds+dsClassAndInstanceDecl (InstanceDecl p cx cls ty ds) =+  InstanceDecl p cx cls ty <$> dsDeclGroup ds+dsClassAndInstanceDecl d = return d++-- -----------------------------------------------------------------------------+-- Desugaring of type declarations: records+-- -----------------------------------------------------------------------------++-- As an extension to the Curry language, the compiler supports Haskell's+-- record syntax, which introduces field labels for data and renaming types.+-- Field labels can be used in constructor declarations, patterns,+-- and expressions. For further convenience, an implicit selector+-- function is introduced for each field label.++-- Generate selector functions for record labels and replace record+-- constructor declarations by ordinary constructor declarations.+dsRecordDecl :: Decl PredType -> DsM [Decl PredType]+dsRecordDecl (DataDecl p tc tvs cs clss) = do+  m <- getModuleIdent+  let qcs = map (qualifyWith m . constrId) cs+  selFuns <- mapM (genSelFun p qcs) (nub $ concatMap recordLabels cs)+  return $ DataDecl p tc tvs (map unlabelConstr cs) clss : selFuns+dsRecordDecl (NewtypeDecl p tc tvs nc clss) = do+  m <- getModuleIdent+  let qc = qualifyWith m (nconstrId nc)+  selFun <- mapM (genSelFun p [qc]) (nrecordLabels nc)+  return $ NewtypeDecl p tc tvs (unlabelNewConstr nc) clss : selFun+dsRecordDecl d = return [d]++-- Generate a selector function for a single record label+genSelFun :: Position -> [QualIdent] -> Ident -> DsM (Decl PredType)+genSelFun p qcs l = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  let ForAll _ pty = varType (qualifyWith m l) vEnv+  FunctionDecl p pty l <$> concatMapM (genSelEqn p l) qcs++-- Generate a selector equation for a label and a constructor if the label+-- is applicable, otherwise the empty list is returned.+genSelEqn :: Position -> Ident -> QualIdent -> DsM [Equation PredType]+genSelEqn p l qc = do+  vEnv <- getValueEnv+  let (ls, ty) = conType qc vEnv+      (tys, ty0) = arrowUnapply (instType ty)+  case elemIndex l ls of+    Just n  -> do+      vs <- mapM (freshVar "_#rec") tys+      let pat = constrPattern (predType ty0) qc vs+      return [mkEquation p l [pat] (uncurry mkVar (vs !! n))]+    Nothing -> return []++-- Remove any labels from a data constructor declaration+unlabelConstr :: ConstrDecl -> ConstrDecl+unlabelConstr (RecordDecl p evs cx c fs) = ConstrDecl p evs cx c tys+  where tys = [ty | FieldDecl _ ls ty <- fs, _ <- ls]+unlabelConstr c                          = c++-- Remove any labels from a newtype constructor declaration+unlabelNewConstr :: NewConstrDecl -> NewConstrDecl+unlabelNewConstr (NewRecordDecl p nc (_, ty)) = NewConstrDecl p nc ty+unlabelNewConstr c                            = c++-- -----------------------------------------------------------------------------+-- Desugaring of value declarations+-- -----------------------------------------------------------------------------++-- Within a declaration group, all type signatures are discarded. First,+-- the patterns occurring in the left hand sides of pattern declarations+-- and external declarations are desugared. Due to lazy patterns, the former+-- may add further declarations to the group that must be desugared as well.+dsDeclGroup :: [Decl PredType] -> DsM [Decl PredType]+dsDeclGroup ds = concatMapM dsDeclLhs (filter isValueDecl ds) >>= mapM dsDeclRhs++dsDeclLhs :: Decl PredType -> DsM [Decl PredType]+dsDeclLhs (PatternDecl p t rhs) = do+  (ds', t') <- dsPat p [] t+  dss'      <- mapM dsDeclLhs ds'+  return $ PatternDecl p t' rhs : concat dss'+dsDeclLhs d                     = return [d]++-- TODO: Check if obsolete and remove+-- After desugaring its right hand side, each equation is eta-expanded+-- by adding as many variables as necessary to the argument list and+-- applying the right hand side to those variables (Note: eta-expansion+-- is disabled in the version for PAKCS).+-- Furthermore every occurrence of a record type within the type of a function+-- is simplified to the corresponding type constructor from the record+-- declaration. This is possible because currently records must not be empty+-- and a record label belongs to only one record declaration.++-- Desugaring of the right-hand-side of declarations+dsDeclRhs :: Decl PredType -> DsM (Decl PredType)+dsDeclRhs (FunctionDecl p pty f eqs) =+  FunctionDecl p pty f <$> mapM dsEquation eqs+dsDeclRhs (PatternDecl      p t rhs) = PatternDecl p t <$> dsRhs p id rhs+dsDeclRhs d@(FreeDecl           _ _) = return d+dsDeclRhs d@(ExternalDecl       _ _) = return d+dsDeclRhs _                          =+  error "Desugar.dsDeclRhs: no pattern match"++-- Desugaring of an equation+dsEquation :: Equation PredType -> DsM (Equation PredType)+dsEquation (Equation p lhs rhs) = do+  (     cs1, ts1) <- dsNonLinearity         ts+  (ds1, cs2, ts2) <- dsFunctionalPatterns p ts1+  (ds2,      ts3) <- mapAccumM (dsPat p) [] ts2+  rhs'            <- dsRhs p (constrain cs2 . constrain cs1)+                             (addDecls (ds1 ++ ds2) rhs)+  return $ Equation p (FunLhs f ts3) rhs'+  where (f, ts) = flatLhs lhs++-- Constrain an expression by a list of constraints.+-- @constrain []  e  ==  e@+-- @constrain c_n e  ==  (c_1 & ... & c_n) &> e@+constrain :: [Expression PredType] -> Expression PredType -> Expression PredType+constrain cs e = if null cs then e else foldr1 (&) cs &> e++-- -----------------------------------------------------------------------------+-- Desugaring of right-hand sides+-- -----------------------------------------------------------------------------++-- A list of boolean guards is expanded into a nested if-then-else+-- expression, whereas a constraint guard is replaced by a case+-- expression. Note that if the guard type is 'Success' only a+-- single guard is allowed for each equation (This change was+-- introduced in version 0.8 of the Curry report.). We check for the+-- type 'Bool' of the guard because the guard's type defaults to+-- 'Success' if it is not restricted by the guard expression.++dsRhs :: Position -> (Expression PredType -> Expression PredType)+      -> Rhs PredType -> DsM (Rhs PredType)+dsRhs p f rhs =     expandRhs (prelFailed (typeOf rhs)) f rhs+                >>= dsExpr pRhs+                >>= return . simpleRhs pRhs+  where+  pRhs = fromMaybe p (getRhsPosition rhs)++expandRhs :: Expression PredType -> (Expression PredType -> Expression PredType)+          -> Rhs PredType -> DsM (Expression PredType)+expandRhs _  f (SimpleRhs _ e ds) = return $ Let ds (f e)+expandRhs e0 f (GuardedRhs es ds) = (Let ds . f) <$> expandGuards e0 es++expandGuards :: Expression PredType -> [CondExpr PredType]+             -> DsM (Expression PredType)+expandGuards e0 es =+  return $ if boolGuards es then foldr mkIfThenElse e0 es else mkCond es+  where+  mkIfThenElse (CondExpr _ g e) = IfThenElse g e+  mkCond [CondExpr _ g e] = g &> e+  mkCond _                = error "Desugar.expandGuards.mkCond: non-unary list"++boolGuards :: [CondExpr PredType] -> Bool+boolGuards []                    = False+boolGuards (CondExpr _ g _ : es) = not (null es) || typeOf g == boolType++-- Add additional declarations to a right-hand side+addDecls :: [Decl PredType] -> Rhs PredType -> Rhs PredType+addDecls ds (SimpleRhs p e ds') = SimpleRhs p e (ds ++ ds')+addDecls ds (GuardedRhs es ds') = GuardedRhs es (ds ++ ds')++getRhsPosition :: Rhs a -> Maybe Position+getRhsPosition (SimpleRhs p _ _) = Just p+getRhsPosition (GuardedRhs  _ _) = Nothing++-- -----------------------------------------------------------------------------+-- Desugaring of non-linear patterns+-- -----------------------------------------------------------------------------++-- The desugaring traverses a pattern in depth-first order and collects+-- all variables. If it encounters a variable which has been previously+-- introduced, the second occurrence is changed to a fresh variable+-- and a new pair (newvar, oldvar) is saved to generate constraints later.+-- Non-linear patterns inside single functional patterns are not desugared,+-- as this special case is handled later.+dsNonLinearity :: [Pattern PredType]+               -> DsM ([Expression PredType], [Pattern PredType])+dsNonLinearity ts = do+  ((_, cs), ts') <- mapAccumM dsNonLinear (Set.empty, []) ts+  return (reverse cs, ts')++type NonLinearEnv = (Set.Set Ident, [Expression PredType])++dsNonLinear :: NonLinearEnv -> Pattern PredType+            -> DsM (NonLinearEnv, Pattern PredType)+dsNonLinear env l@(LiteralPattern        _ _) = return (env, l)+dsNonLinear env n@(NegativePattern       _ _) = return (env, n)+dsNonLinear env t@(VariablePattern       _ v)+  | isAnonId v         = return (env, t)+  | v `Set.member` vis = do+    v' <- freshVar "_#nonlinear" t+    return ((vis, mkStrictEquality v v' : eqs), uncurry VariablePattern v')+  | otherwise          = return ((Set.insert v vis, eqs), t)+  where (vis, eqs) = env+dsNonLinear env (ConstructorPattern pty c ts) = second (ConstructorPattern pty c)+                                                <$> mapAccumM dsNonLinear env ts+dsNonLinear env (InfixPattern   pty t1 op t2) = do+  (env1, t1') <- dsNonLinear env  t1+  (env2, t2') <- dsNonLinear env1 t2+  return (env2, InfixPattern pty t1' op t2')+dsNonLinear env (ParenPattern            t) = second ParenPattern+                                              <$> dsNonLinear env t+dsNonLinear env (RecordPattern      pty c fs) =+  second (RecordPattern pty c) <$> mapAccumM (dsField dsNonLinear) env fs+dsNonLinear env (TuplePattern             ts) = second TuplePattern+                                                <$> mapAccumM dsNonLinear env ts+dsNonLinear env (ListPattern          pty ts) = second (ListPattern pty)+                                                <$> mapAccumM dsNonLinear env ts+dsNonLinear env (AsPattern               v t) = do+  let pty = predType $ typeOf t+  (env1, VariablePattern _ v') <- dsNonLinear env (VariablePattern pty v)+  (env2, t') <- dsNonLinear env1 t+  return (env2, AsPattern v' t')+dsNonLinear env (LazyPattern               t) = second LazyPattern+                                                <$> dsNonLinear env t+dsNonLinear env fp@(FunctionPattern    _ _ _) = dsNonLinearFuncPat env fp+dsNonLinear env fp@(InfixFuncPattern _ _ _ _) = dsNonLinearFuncPat env fp++dsNonLinearFuncPat :: NonLinearEnv -> Pattern PredType+                   -> DsM (NonLinearEnv, Pattern PredType)+dsNonLinearFuncPat (vis, eqs) fp = do+  let fpVars = map (\(v, _, pty) -> (pty, v)) $ patternVars fp+      vs     = filter ((`Set.member` vis) . snd) fpVars+  vs' <- mapM (freshVar "_#nonlinear" . uncurry VariablePattern) vs+  let vis' = foldr (Set.insert . snd) vis fpVars+      fp'  = substPat (zip (map snd vs) (map snd vs')) fp+  return ((vis', zipWith mkStrictEquality (map snd vs) vs' ++ eqs), fp')++mkStrictEquality :: Ident -> (PredType, Ident) -> Expression PredType+mkStrictEquality x (pty, y) = mkVar pty x =:= mkVar pty y++substPat :: [(Ident, Ident)] -> Pattern a -> Pattern a+substPat _ l@(LiteralPattern        _ _) = l+substPat _ n@(NegativePattern       _ _) = n+substPat s (VariablePattern         a v) = VariablePattern a+                                         $ fromMaybe v (lookup v s)+substPat s (ConstructorPattern   a c ps) = ConstructorPattern a c+                                         $ map (substPat s) ps+substPat s (InfixPattern     a p1 op p2) = InfixPattern a (substPat s p1) op+                                                        (substPat s p2)+substPat s (ParenPattern              p) = ParenPattern (substPat s p)+substPat s (RecordPattern        a c fs) = RecordPattern a c (map substField fs)+  where substField (Field pos l pat) = Field pos l (substPat s pat)+substPat s (TuplePattern             ps) = TuplePattern+                                         $ map (substPat s) ps+substPat s (ListPattern            a ps) = ListPattern a+                                         $ map (substPat s) ps+substPat s (AsPattern               v p) = AsPattern (fromMaybe v (lookup v s))+                                                     (substPat s p)+substPat s (LazyPattern               p) = LazyPattern (substPat s p)+substPat s (FunctionPattern      a f ps) = FunctionPattern a f+                                         $ map (substPat s) ps+substPat s (InfixFuncPattern a p1 op p2) = InfixFuncPattern a (substPat s p1) op+                                                            (substPat s p2)++-- -----------------------------------------------------------------------------+-- Desugaring of functional patterns+-- -----------------------------------------------------------------------------++-- Desugaring of functional patterns works in the following way:+--  1. The patterns are recursively traversed from left to right+--     to extract every functional pattern (note that functional patterns+--     can not be nested).+--     Each pattern is replaced by a fresh variable and a pair+--     (variable, functional pattern) is generated.+--  2. The variable-pattern pairs of the form @(v, p)@ are collected and+--     transformed into additional constraints of the form @p =:<= v@,+--     where the pattern @p@ is converted to the corresponding expression.+--     In addition, any variable occurring in @p@ is declared as a fresh+--     free variable.+--     Multiple constraints will later be combined using the @&>@-operator+--     such that the patterns are evaluated from left to right.++dsFunctionalPatterns+  :: Position -> [Pattern PredType]+  -> DsM ([Decl PredType], [Expression PredType], [Pattern PredType])+dsFunctionalPatterns p ts = do+  -- extract functional patterns+  (bs, ts') <- mapAccumM elimFP [] ts+  -- generate declarations of free variables and constraints+  let (ds, cs) = genFPExpr p (concatMap patternVars ts') (reverse bs)+  -- return (declarations, constraints, desugared patterns)+  return (ds, cs, ts')++type LazyBinding = (Pattern PredType, (PredType, Ident))++elimFP :: [LazyBinding] -> Pattern PredType+       -> DsM ([LazyBinding], Pattern PredType)+elimFP bs p@(LiteralPattern        _ _) = return (bs, p)+elimFP bs p@(NegativePattern       _ _) = return (bs, p)+elimFP bs p@(VariablePattern       _ _) = return (bs, p)+elimFP bs (ConstructorPattern pty c ts) = second (ConstructorPattern pty c)+                                          <$> mapAccumM elimFP bs ts+elimFP bs (InfixPattern   pty t1 op t2) = do+  (bs1, t1') <- elimFP bs  t1+  (bs2, t2') <- elimFP bs1 t2+  return (bs2, InfixPattern pty t1' op t2')+elimFP bs (ParenPattern              t) = second ParenPattern <$> elimFP bs t+elimFP bs (RecordPattern      pty c fs) = second (RecordPattern pty c)+                                          <$> mapAccumM (dsField elimFP) bs fs+elimFP bs (TuplePattern             ts) = second TuplePattern+                                          <$> mapAccumM elimFP bs ts+elimFP bs (ListPattern          pty ts) = second (ListPattern pty)+                                          <$> mapAccumM elimFP bs ts+elimFP bs (AsPattern               v t) = second (AsPattern   v) <$> elimFP bs t+elimFP bs (LazyPattern               t) = second LazyPattern <$> elimFP bs t+elimFP bs p@(FunctionPattern     _ _ _) = do+ (pty, v) <- freshVar "_#funpatt" p+ return ((p, (pty, v)) : bs, VariablePattern pty v)+elimFP bs p@(InfixFuncPattern  _ _ _ _) = do+ (pty, v) <- freshVar "_#funpatt" p+ return ((p, (pty, v)) : bs, VariablePattern pty v)++genFPExpr :: Position -> [(Ident, Int, PredType)] -> [LazyBinding]+          -> ([Decl PredType], [Expression PredType])+genFPExpr p vs bs+  | null bs   = ([]               , [])+  | null free = ([]               , cs)+  | otherwise = ([FreeDecl p (map (\(v, _, pty) -> Var pty v) free)], cs)+  where+  mkLB (t, (pty, v)) = let (t', es) = fp2Expr t+                       in  (t' =:<= mkVar pty v) : es+  cs   = concatMap mkLB bs+  free = nub $ filter (not . isAnonId . fst3) $+                 concatMap patternVars (map fst bs) \\ vs++fp2Expr :: Pattern PredType -> (Expression PredType, [Expression PredType])+fp2Expr (LiteralPattern          pty l) = (Literal pty l, [])+fp2Expr (NegativePattern         pty l) = (Literal pty (negateLiteral l), [])+fp2Expr (VariablePattern         pty v) = (mkVar pty v, [])+fp2Expr (ConstructorPattern   pty c ts) =+  let (ts', ess) = unzip $ map fp2Expr ts+      pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf ts+  in  (apply (Constructor pty' c) ts', concat ess)+fp2Expr (InfixPattern   pty t1 op t2) =+  let (t1', es1) = fp2Expr t1+      (t2', es2) = fp2Expr t2+      pty' = predType $ foldr TypeArrow (unpredType pty) [typeOf t1, typeOf t2]+  in  (InfixApply t1' (InfixConstr pty' op) t2', es1 ++ es2)+fp2Expr (ParenPattern                t) = first Paren (fp2Expr t)+fp2Expr (TuplePattern               ts) =+  let (ts', ess) = unzip $ map fp2Expr ts+  in  (Tuple ts', concat ess)+fp2Expr (ListPattern            pty ts) =+  let (ts', ess) = unzip $ map fp2Expr ts+  in  (List pty ts', concat ess)+fp2Expr (FunctionPattern      pty f ts) =+  let (ts', ess) = unzip $ map fp2Expr ts+      pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf ts+  in  (apply (Variable pty' f) ts', concat ess)+fp2Expr (InfixFuncPattern pty t1 op t2) =+  let (t1', es1) = fp2Expr t1+      (t2', es2) = fp2Expr t2+      pty' = predType $ foldr TypeArrow (unpredType pty) $ map typeOf [t1, t2]+  in  (InfixApply t1' (InfixOp pty' op) t2', es1 ++ es2)+fp2Expr (AsPattern                 v t) =+  let (t', es) = fp2Expr t+      pty = predType $ typeOf t+  in  (mkVar pty v, (t' =:<= mkVar pty v) : es)+fp2Expr (RecordPattern        pty c fs) =+  let (fs', ess) = unzip [ (Field p f e, es) | Field p f t <- fs+                                             , let (e, es) = fp2Expr t]+  in  (Record pty c fs', concat ess)+fp2Expr t                               = internalError $+  "Desugar.fp2Expr: Unexpected constructor term: " ++ show t++-- -----------------------------------------------------------------------------+-- Desugaring of ordinary patterns+-- -----------------------------------------------------------------------------++-- The transformation of patterns is straight forward except for lazy+-- patterns. A lazy pattern '~t' is replaced by a fresh+-- variable 'v' and a new local declaration 't = v' in the+-- scope of the pattern. In addition, as-patterns 'v@t' where+-- 't' is a variable or an as-pattern are replaced by 't' in combination+-- with a local declaration for 'v'.++-- Record patterns are transformed into normal constructor patterns by+-- rearranging fields in the order of the record's declaration, adding+-- fresh variables in place of omitted fields, and discarding the field+-- labels.++-- Note: By rearranging fields here we loose the ability to comply+-- strictly with the Haskell 98 pattern matching semantics, which matches+-- fields of a record pattern in the order of their occurrence in the+-- pattern. However, keep in mind that Haskell matches alternatives from+-- top to bottom and arguments within an equation or alternative from+-- left to right, which is not the case in Curry except for rigid case+-- expressions.++dsLiteralPat :: PredType -> Literal+             -> Either (Pattern PredType) (Pattern PredType)+dsLiteralPat pty c@(Char _) = Right (LiteralPattern pty c)+dsLiteralPat pty (Int i) =+  Right (LiteralPattern pty (fixLiteral (unpredType pty)))+  where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)+        fixLiteral ty+          | ty == floatType = Float $ fromInteger i+          | otherwise = Int i+dsLiteralPat pty f@(Float _) = Right (LiteralPattern pty f)+dsLiteralPat pty (String cs) =+  Left $ ListPattern pty $ map (LiteralPattern pty' . Char) cs+  where pty' = predType $ elemType $ unpredType pty++dsPat :: Position -> [Decl PredType] -> Pattern PredType+      -> DsM ([Decl PredType], Pattern PredType)+dsPat _ ds v@(VariablePattern     _ _) = return (ds, v)+dsPat p ds (LiteralPattern      pty l) =+  either (dsPat p ds) (return . (,) ds) (dsLiteralPat pty l)+dsPat p ds (NegativePattern     pty l) =+  dsPat p ds (LiteralPattern pty (negateLiteral l))+dsPat p ds (ConstructorPattern pty c ts) =+  second (ConstructorPattern pty c) <$> mapAccumM (dsPat p) ds ts+dsPat p ds (InfixPattern  pty t1 op t2) =+  dsPat p ds (ConstructorPattern pty op [t1, t2])+dsPat p ds (ParenPattern           t) = dsPat p ds t+dsPat p ds (RecordPattern   pty c fs) = do+  vEnv <- getValueEnv+  --TODO: Rework+  let (ls, tys) = argumentTypes (unpredType pty) c vEnv+      tsMap = map field2Tuple fs+      anonTs = map (flip VariablePattern anonId . predType) tys+      maybeTs = map (flip lookup tsMap) ls+      ts = zipWith fromMaybe anonTs maybeTs+  dsPat p ds (ConstructorPattern pty c ts)+dsPat p ds (TuplePattern          ts) =+  dsPat p ds (ConstructorPattern pty (qTupleId $ length ts) ts)+  where pty = predType (tupleType (map typeOf ts))+dsPat p ds (ListPattern       pty ts) =+  second (dsList cons nil) <$> mapAccumM (dsPat p) ds ts+  where nil = ConstructorPattern pty qNilId []+        cons t ts' = ConstructorPattern pty qConsId [t, ts']+dsPat p ds (AsPattern            v t) = dsAs p v <$> dsPat p ds t+dsPat p ds (LazyPattern            t) = dsLazy p ds t+dsPat p ds (FunctionPattern    pty f ts) = second (FunctionPattern pty f)+                                        <$> mapAccumM (dsPat p) ds ts+dsPat p ds (InfixFuncPattern pty t1 f t2) =+  dsPat p ds (FunctionPattern pty f [t1, t2])++dsAs :: Position -> Ident -> ([Decl PredType], Pattern PredType)+     -> ([Decl PredType], Pattern PredType)+dsAs p v (ds, t) = case t of+  VariablePattern pty v' -> (varDecl p pty v (mkVar pty v') : ds, t)+  AsPattern        v' t' -> (varDecl p pty' v (mkVar pty' v') : ds, t)+    where pty' = predType $ typeOf t'+  _                      -> (ds, AsPattern v t)++dsLazy :: Position -> [Decl PredType] -> Pattern PredType+       -> DsM ([Decl PredType], Pattern PredType)+dsLazy p ds t = case t of+  VariablePattern _ _ -> return (ds, t)+  ParenPattern   t' -> dsLazy p ds t'+  AsPattern    v t' -> dsAs p v <$> dsLazy p ds t'+  LazyPattern    t' -> dsLazy p ds t'+  _                 -> do+    (pty, v') <- freshVar "_#lazy" t+    return (patDecl p t (mkVar pty v') : ds, VariablePattern pty v')++{-+-- -----------------------------------------------------------------------------+-- Desugaring of expressions+-- -----------------------------------------------------------------------------++-- Record construction expressions are transformed into normal+-- constructor applications by rearranging fields in the order of the+-- record's declaration, passing `Prelude.unknown` in place of+-- omitted fields, and discarding the field labels. The transformation of+-- record update expressions is a bit more involved as we must match the+-- updated expression with all valid constructors of the expression's+-- type. As stipulated by the Haskell 98 Report, a record update+-- expression @e { l_1 = e_1, ..., l_k = e_k }@ succeeds only if @e@ reduces to+-- a value @C e'_1 ... e'_n@ such that @C@'s declaration contains all+-- field labels @l_1,...,l_k@. In contrast to Haskell, we do not report+-- an error if this is not the case, but call failed instead.+-}+dsExpr :: Position -> Expression PredType -> DsM (Expression PredType)+dsExpr p (Literal     pty l) =+  either (dsExpr p) return (dsLiteral pty l)+dsExpr _ var@(Variable pty v)+  | isAnonId (unqualify v)   = return $ prelUnknown $ unpredType pty+  | otherwise                = return var+dsExpr _ c@(Constructor _ _) = return c+dsExpr p (Paren           e) = dsExpr p e+dsExpr p (Typed       e qty) = Typed <$> dsExpr p e <*> dsQualTypeExpr qty+dsExpr p (Record   pty c fs) = do+  vEnv <- getValueEnv+  --TODO: Rework+  let (ls, tys) = argumentTypes (unpredType pty) c vEnv+      esMap = map field2Tuple fs+      unknownEs = map prelUnknown tys+      maybeEs = map (flip lookup esMap) ls+      es = zipWith fromMaybe unknownEs maybeEs+  dsExpr p (applyConstr pty c tys es)+dsExpr p (RecordUpdate e fs) = do+  alts  <- constructors tc >>= concatMapM updateAlt+  dsExpr p $ Case Flex e (map (uncurry (caseAlt p)) alts)+  where ty = typeOf e+        pty = predType ty+        tc = rootOfType (arrowBase ty)+        updateAlt (RecordConstr c _ _ ls _)+          | all (`elem` qls2) (map fieldLabel fs)= do+            let qc = qualifyLike tc c+            vEnv <- getValueEnv+            let (qls, tys) = argumentTypes ty qc vEnv+            vs <- mapM (freshVar "_#rec") tys+            let pat = constrPattern pty qc vs+                esMap = map field2Tuple fs+                originalEs = map (uncurry mkVar) vs+                maybeEs = map (flip lookup esMap) qls+                es = zipWith fromMaybe originalEs maybeEs+            return [(pat, applyConstr pty qc tys es)]+          where qls2 = map (qualifyLike tc) ls+        updateAlt _ = return []+dsExpr p (Tuple      es) = apply (Constructor pty $ qTupleId $ length es) <$> mapM (dsExpr p) es+  where pty = predType (foldr TypeArrow (tupleType tys) tys)+        tys = map typeOf es+dsExpr p (List   pty es) = dsList cons nil <$> mapM (dsExpr p) es+  where nil = Constructor pty qNilId+        cons = Apply . Apply (Constructor (predType $ consType $ elemType $ unpredType pty) qConsId)+dsExpr p (ListCompr          e qs) = dsListComp p e qs+dsExpr p (EnumFrom              e) = Apply (prelEnumFrom (typeOf e))+                                     <$> dsExpr p e+dsExpr p (EnumFromThen      e1 e2) = apply (prelEnumFromThen (typeOf e1))+                                     <$> mapM (dsExpr p) [e1, e2]+dsExpr p (EnumFromTo        e1 e2) = apply (prelEnumFromTo (typeOf e1))+                                     <$> mapM (dsExpr p) [e1, e2]+dsExpr p (EnumFromThenTo e1 e2 e3) = apply (prelEnumFromThenTo (typeOf e1))+                                     <$> mapM (dsExpr p) [e1, e2, e3]+dsExpr p (UnaryMinus            e) = do+  e' <- dsExpr p e+  negativeLitsEnabled <- checkNegativeLitsExtension+  return $ case e' of+    Literal pty l | negativeLitsEnabled -> Literal pty $ negateLiteral l+    _                                   -> Apply (prelNegate $ typeOf e') e'+dsExpr p (Apply e1 e2) = Apply <$> dsExpr p e1 <*> dsExpr p e2+dsExpr p (InfixApply e1 op e2) = do+  op' <- dsExpr p (infixOp op)+  e1' <- dsExpr p e1+  e2' <- dsExpr p e2+  return $ apply op' [e1', e2']+dsExpr p (LeftSection  e op) = Apply <$> dsExpr p (infixOp op) <*> dsExpr p e+dsExpr p (RightSection op e) = do+  op' <- dsExpr p (infixOp op)+  e'  <- dsExpr p e+  return $ apply (prelFlip ty1 ty2 ty3) [op', e']+  where TypeArrow ty1 (TypeArrow ty2 ty3) = typeOf (infixOp op)+dsExpr p expr@(Lambda ts e) = do+  (pty, f) <- freshVar "_#lambda" expr+  dsExpr p $ Let [funDecl NoPos pty f ts e] $ mkVar pty f+dsExpr p (Let ds e) = do+  ds' <- dsDeclGroup ds+  e'  <- dsExpr p e+  return (if null ds' then e' else Let ds' e')+dsExpr p (Do              sts e) = dsDo sts e >>= dsExpr p+dsExpr p (IfThenElse e1 e2 e3) = do+  e1' <- dsExpr p e1+  e2' <- dsExpr p e2+  e3' <- dsExpr p e3+  return $ Case Rigid e1' [caseAlt p truePat e2', caseAlt p falsePat e3']+dsExpr p (Case ct e alts) = dsCase p ct e alts++-- We ignore the context in the type signature of a typed expression, since+-- there should be no possibility to provide an non-empty context without+-- scoped type-variables.+-- TODO: Verify++dsQualTypeExpr :: QualTypeExpr -> DsM QualTypeExpr+dsQualTypeExpr (QualTypeExpr cx ty) = QualTypeExpr cx <$> dsTypeExpr ty++dsTypeExpr :: TypeExpr -> DsM TypeExpr+dsTypeExpr ty = do+  m <- getModuleIdent+  tcEnv <- getTyConsEnv+  return $ fromType (typeVariables ty) (expandType m tcEnv (toType [] ty))++-- -----------------------------------------------------------------------------+-- Desugaring of case expressions+-- -----------------------------------------------------------------------------++-- If an alternative in a case expression has boolean guards and all of+-- these guards return 'False', the enclosing case expression does+-- not fail but continues to match the remaining alternatives against the+-- selector expression. In order to implement this semantics, which is+-- compatible with Haskell, we expand an alternative with boolean guards+-- such that it evaluates a case expression with the remaining cases that+-- are compatible with the matched pattern when the guards fail.++dsCase :: Position -> CaseType -> Expression PredType -> [Alt PredType]+       -> DsM (Expression PredType)+dsCase p ct e alts+  | null alts = internalError "Desugar.dsCase: empty list of alternatives"+  | otherwise = do+    m  <- getModuleIdent+    e' <- dsExpr p e+    v  <- freshVar "_#case" e+    alts'  <- mapM dsAltLhs alts+    alts'' <- mapM (expandAlt v ct) (init (tails alts')) >>= mapM dsAltRhs+    return (mkCase m v e' alts'')+  where+  mkCase m (pty, v) e' bs+    | v `elem` qfv m bs = Let [varDecl p pty v e'] (Case ct (mkVar pty v) bs)+    | otherwise         = Case ct e' bs++dsAltLhs :: Alt PredType -> DsM (Alt PredType)+dsAltLhs (Alt p t rhs) = do+  (ds', t') <- dsPat p [] t+  return $ Alt p t' (addDecls ds' rhs)++dsAltRhs :: Alt PredType -> DsM (Alt PredType)+dsAltRhs (Alt p t rhs) = Alt p t <$> dsRhs p id rhs++expandAlt :: (PredType, Ident) -> CaseType -> [Alt PredType]+          -> DsM (Alt PredType)+expandAlt _ _  []                   = error "Desugar.expandAlt: empty list"+expandAlt v ct (Alt p t rhs : alts) = caseAlt p t <$> expandRhs e0 id rhs+  where+  e0 | ct == Flex || null compAlts = prelFailed (typeOf rhs)+     | otherwise = Case ct (uncurry mkVar v) compAlts+  compAlts = filter (isCompatible t . altPattern) alts+  altPattern (Alt _ t1 _) = t1++isCompatible :: Pattern a -> Pattern a -> Bool+isCompatible (VariablePattern _ _) _ = True+isCompatible _ (VariablePattern _ _) = True+isCompatible (AsPattern _ t1) t2 = isCompatible t1 t2+isCompatible t1 (AsPattern _ t2) = isCompatible t1 t2+isCompatible (ConstructorPattern _ c1 ts1) (ConstructorPattern _ c2 ts2)+  = and ((c1 == c2) : zipWith isCompatible ts1 ts2)+isCompatible (LiteralPattern _ l1) (LiteralPattern _ l2) = l1 == l2+isCompatible _ _ = False++-- -----------------------------------------------------------------------------+-- Desugaring of do-Notation+-- -----------------------------------------------------------------------------++-- The do-notation is desugared in the following way:+--+-- `dsDo([]         , e)` -> `e`+-- `dsDo(e'     ; ss, e)` -> `e' >>        dsDo(ss, e)`+-- `dsDo(p <- e'; ss, e)` -> `e' >>= \v -> case v of+--                                           p -> dsDo(ss, e)+--                                           _ -> fail "..."`+-- `dsDo(let ds ; ss, e)` -> `let ds in    dsDo(ss, e)`+dsDo :: [Statement PredType] -> Expression PredType -> DsM (Expression PredType)+dsDo sts e = foldrM dsStmt e sts++dsStmt :: Statement PredType -> Expression PredType -> DsM (Expression PredType)+dsStmt (StmtExpr   e1) e' =+  return $ apply (prelBind_ (typeOf e1) (typeOf e')) [e1, e']+dsStmt (StmtBind t e1) e' = do+  v <- freshVar "_#var" t+  let func = Lambda [uncurry VariablePattern v] $+               Case Rigid (uncurry mkVar v)+                 [ caseAlt NoPos t e'+                 , caseAlt NoPos (uncurry VariablePattern v)+                     (failedPatternMatch $ typeOf e')+                 ]+  return $ apply (prelBind (typeOf e1) (typeOf t) (typeOf e')) [e1, func]+  where failedPatternMatch ty =+          apply (prelFail ty)+            [Literal predStringType $ String "Pattern match failed!"]+dsStmt (StmtDecl   ds) e' = return $ Let ds e'++-- -----------------------------------------------------------------------------+-- Desugaring of List Comprehensions+-- -----------------------------------------------------------------------------++-- In general, a list comprehension of the form+-- '[e | t <- l, qs]'+-- is transformed into an expression 'foldr f [] l' where 'f'+-- is a new function defined as+--+--     f x xs =+--       case x of+--           t -> [e | qs] ++ xs+--           _ -> xs+--+-- Note that this translation evaluates the elements of 'l' rigidly,+-- whereas the translation given in the Curry report is flexible.+-- However, it does not seem very useful to have the comprehension+-- generate instances of 't' which do not contribute to the list.+-- TODO: Unfortunately, this is incorrect.++-- Actually, we generate slightly better code in a few special cases.+-- When 't' is a plain variable, the 'case' expression degenerates+-- into a let-binding and the auxiliary function thus becomes an alias+-- for '(++)'. Instead of 'foldr (++)' we use the+-- equivalent prelude function 'concatMap'. In addition, if the+-- remaining list comprehension in the body of the auxiliary function has+-- no qualifiers -- i.e., if it is equivalent to '[e]' -- we+-- avoid the construction of the singleton list by calling '(:)'+-- instead of '(++)' and 'map' in place of 'concatMap', respectively.++dsListComp :: Position -> Expression PredType -> [Statement PredType]+           -> DsM (Expression PredType)+dsListComp p e []     =+  dsExpr p (List (predType $ listType $ typeOf e) [e])+dsListComp p e (q:qs) = dsQual p q (ListCompr e qs)++dsQual :: Position -> Statement PredType -> Expression PredType+       -> DsM (Expression PredType)+dsQual p (StmtExpr   b) e =+  dsExpr p (IfThenElse b e (List (predType $ typeOf e) []))+dsQual p (StmtDecl  ds) e = dsExpr p (Let ds e)+dsQual p (StmtBind t l) e+  | isVariablePattern t = dsExpr p (qualExpr t e l)+  | otherwise = do+    v <- freshVar "_#var" t+    l' <- freshVar "_#var" e+    dsExpr p (apply (prelFoldr (typeOf t) (typeOf e))+      [foldFunct v l' e, List (predType $ typeOf e) [], l])+  where+  qualExpr v (ListCompr e1 []) l1+    = apply (prelMap (typeOf v) (typeOf e1)) [Lambda [v] e1, l1]+  qualExpr v e1                  l1+    = apply (prelConcatMap (typeOf v) (elemType $ typeOf e1)) [Lambda [v] e1, l1]+  foldFunct v l1 e1+    = Lambda (map (uncurry VariablePattern) [v, l1])+       (Case Rigid (uncurry mkVar v)+          [ caseAlt p t (append e1 (uncurry mkVar l1))+          , caseAlt p (uncurry VariablePattern v) (uncurry mkVar l1)])++  append (ListCompr e1 []) l1 = apply (prelCons (typeOf e1)) [e1, l1]+  append e1                l1 = apply (prelAppend (elemType $ typeOf e1)) [e1, l1]+  prelCons ty                 = Constructor (predType $ consType ty) $ qConsId++-- -----------------------------------------------------------------------------+-- Desugaring of Lists, labels, fields, and literals+-- -----------------------------------------------------------------------------++dsList :: (b -> b -> b) -> b -> [b] -> b+dsList = foldr++--dsLabel :: a -> [(QualIdent, a)] -> QualIdent -> a+--dsLabel def fs l = fromMaybe def (lookup l fs)++dsField :: (a -> b -> DsM (a, b)) -> a -> Field b -> DsM (a, Field b)+dsField ds z (Field p l x) = second (Field p l) <$> (ds z x)++dsLiteral :: PredType -> Literal+          -> Either (Expression PredType) (Expression PredType)+dsLiteral pty (Char c) = Right $ Literal pty $ Char c+dsLiteral pty (Int i) = Right $ fixLiteral (unpredType pty)+  where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)+        fixLiteral ty+          | ty == intType = Literal pty $ Int i+          | ty == floatType = Literal pty $ Float $ fromInteger i+          | otherwise = Apply (prelFromInt $ unpredType pty) $+                          Literal predIntType $ Int i+dsLiteral pty f@(Float _) = Right $ fixLiteral (unpredType pty)+  where fixLiteral (TypeConstrained tys _) = fixLiteral (head tys)+        fixLiteral ty+          | ty == floatType = Literal pty f+          | otherwise = Apply (prelFromFloat $ unpredType pty) $+                          Literal predFloatType f+dsLiteral pty (String cs) =+  Left $ List pty $ map (Literal pty' . Char) cs+  where pty' = predType $ elemType $ unpredType pty++negateLiteral :: Literal -> Literal+negateLiteral (Int i) = Int (-i)+negateLiteral (Float f) = Float (-f)+negateLiteral _ = internalError "Desugar.negateLiteral"++-- ---------------------------------------------------------------------------+-- Prelude entities+-- ---------------------------------------------------------------------------++preludeFun :: [Type] -> Type -> String -> Expression PredType+preludeFun tys ty = Variable (predType $ foldr TypeArrow ty tys) . preludeIdent++preludeIdent :: String -> QualIdent+preludeIdent = qualifyWith preludeMIdent . mkIdent++prelBind :: Type -> Type -> Type -> Expression PredType+prelBind ma a mb = preludeFun [ma, TypeArrow a mb] mb ">>="++prelBind_ :: Type -> Type -> Expression PredType+prelBind_ ma mb = preludeFun [ma, mb] mb ">>"++prelFlip :: Type -> Type -> Type -> Expression PredType+prelFlip a b c = preludeFun [TypeArrow a (TypeArrow b c), b, a] c "flip"++prelFromInt :: Type -> Expression PredType+prelFromInt a = preludeFun [intType] a "fromInt"++prelFromFloat :: Type -> Expression PredType+prelFromFloat a = preludeFun [floatType] a "fromFloat"++prelEnumFrom :: Type -> Expression PredType+prelEnumFrom a = preludeFun [a] (listType a) "enumFrom"++prelEnumFromTo :: Type -> Expression PredType+prelEnumFromTo a = preludeFun [a, a] (listType a) "enumFromTo"++prelEnumFromThen :: Type -> Expression PredType+prelEnumFromThen a = preludeFun [a, a] (listType a) "enumFromThen"++prelEnumFromThenTo :: Type -> Expression PredType+prelEnumFromThenTo a = preludeFun [a, a, a] (listType a) "enumFromThenTo"++prelNegate :: Type -> Expression PredType+prelNegate a = preludeFun [a] a "negate"++prelFail :: Type -> Expression PredType+prelFail ma = preludeFun [stringType] ma "fail"++prelFailed :: Type -> Expression PredType+prelFailed a = preludeFun [] a "failed"++prelUnknown :: Type -> Expression PredType+prelUnknown a = preludeFun [] a "unknown"++prelMap :: Type -> Type -> Expression PredType+prelMap a b = preludeFun [TypeArrow a b, listType a] (listType b) "map"++prelFoldr :: Type -> Type -> Expression PredType+prelFoldr a b =+  preludeFun [TypeArrow a (TypeArrow b b), b, listType a] b "foldr"++prelAppend :: Type -> Expression PredType+prelAppend a = preludeFun [listType a, listType a] (listType a) "++"++prelConcatMap :: Type -> Type -> Expression PredType+prelConcatMap a b =+  preludeFun [TypeArrow a (listType b), listType a] (listType b) "concatMap"++(=:<=) :: Expression PredType -> Expression PredType -> Expression PredType+e1 =:<= e2 = apply (preludeFun [typeOf e1, typeOf e2] boolType "=:<=") [e1, e2]++(=:=) :: Expression PredType -> Expression PredType -> Expression PredType+e1 =:= e2 = apply (preludeFun [typeOf e1, typeOf e2] boolType "=:=") [e1, e2]++(&>) :: Expression PredType -> Expression PredType -> Expression PredType+e1 &> e2 = apply (preludeFun [boolType, typeOf e2] (typeOf e2) "cond") [e1, e2]++(&) :: Expression PredType -> Expression PredType -> Expression PredType+e1 & e2 = apply (preludeFun [boolType, boolType] boolType "&") [e1, e2]++truePat :: Pattern PredType+truePat = ConstructorPattern predBoolType qTrueId []++falsePat :: Pattern PredType+falsePat = ConstructorPattern predBoolType qFalseId []++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++conType :: QualIdent -> ValueEnv -> ([Ident], ExistTypeScheme)+conType c vEnv = case qualLookupValue c vEnv of+  [DataConstructor _ _ ls ty] -> (ls , ty)+  [NewtypeConstructor _ l ty] -> ([l], ty)+  _                           -> internalError $ "Desguar.conType: " ++ show c++varType :: QualIdent -> ValueEnv -> TypeScheme+varType v vEnv = case qualLookupValue v vEnv of+  Value _ _ _ tySc : _ -> tySc+  Label _ _   tySc : _ -> tySc+  _                    -> internalError $ "Desugar.varType: " ++ show v++elemType :: Type -> Type+elemType (TypeApply (TypeConstructor tc) ty) | tc == qListId = ty+elemType ty = internalError $ "Base.Types.elemType " ++ show ty++applyConstr :: PredType -> QualIdent -> [Type] -> [Expression PredType]+            -> Expression PredType+applyConstr pty c tys =+  apply (Constructor (predType (foldr TypeArrow (unpredType pty) tys)) c)++-- The function 'instType' instantiates the universally quantified+-- type variables of a type scheme with fresh type variables. Since this+-- function is used only to instantiate the closed types of record+-- constructors (recall that no existentially quantified type+-- variables are allowed for records), the compiler can reuse the same+-- monomorphic type variables for every instantiated type.++instType :: ExistTypeScheme -> Type+instType (ForAllExist _ _ pty) = inst $ unpredType pty+  where inst (TypeConstructor     tc) = TypeConstructor tc+        inst (TypeApply      ty1 ty2) = TypeApply (inst ty1) (inst ty2)+        inst (TypeVariable        tv) = TypeVariable (-1 - tv)+        inst (TypeArrow      ty1 ty2) = TypeArrow (inst ty1) (inst ty2)+        inst ty                       = ty++-- Retrieve all constructors of a type+constructors :: QualIdent -> DsM [DataConstr]+constructors tc = getTyConsEnv >>= \tcEnv -> return $+  case qualLookupTypeInfo tc tcEnv of+    [DataType     _ _ cs] -> cs+    [RenamingType _ _ nc] -> [nc]+    _                     ->+      internalError $ "Transformations.Desugar.constructors: " ++ show tc++-- The function 'argumentTypes' returns the labels and the argument types+-- of a data constructor instantiated at a particular type.++argumentTypes :: Type -> QualIdent -> ValueEnv -> ([QualIdent], [Type])+argumentTypes ty c vEnv =+  (map (qualifyLike c) ls, map (subst (matchType ty0 ty idSubst)) tys)+  where (ls, ForAllExist _ _ (PredType _ ty')) = conType c vEnv+        (tys, ty0) = arrowUnapply ty'
+ src/Transformations/Dictionary.hs view
@@ -0,0 +1,1324 @@+{- |+  Module      :  $Header$+  Description :  Dictionary insertion+  Copyright   :  (c) 2016 - 2017 Finn Teegen+  License     :  BSD-3-clause++  Maintainer  :  bjp@informatik.uni-kiel.de+  Stability   :  experimental+  Portability :  portable++  TODO+-}++{-# LANGUAGE CPP #-}+module Transformations.Dictionary+  ( insertDicts+  , dictTypeId, qDictTypeId, dictConstrId, qDictConstrId+  , defaultMethodId, qDefaultMethodId, superDictStubId, qSuperDictStubId+  , instFunId, qInstFunId, implMethodId, qImplMethodId+  ) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative      ((<$>), (<*>))+import           Data.Traversable         (traverse)+#endif+import           Control.Monad.Extra      ( concatMapM, liftM, maybeM, when+                                          , zipWithM )+import qualified Control.Monad.State as S (State, runState, gets, modify)++import           Data.List         (inits, nub, partition, tails, zipWith4)+import qualified Data.Map   as Map ( Map, empty, insert, lookup, mapWithKey+                                   , toList )+import           Data.Maybe        (fromMaybe, isJust)+import qualified Data.Set   as Set ( deleteMin, fromList, null, size, toAscList+                                   , toList, union )++import Curry.Base.Ident+import Curry.Base.Position+import Curry.Syntax++import Base.CurryTypes+import Base.Expr+import Base.Kinds+import Base.Messages (internalError)+import Base.TopEnv+import Base.Types+import Base.TypeSubst+import Base.Typing++import Env.Class+import Env.Instance+import Env.Interface+import Env.OpPrec+import Env.TypeConstructor+import Env.Value++data DTState = DTState+  { moduleIdent :: ModuleIdent+  , tyConsEnv   :: TCEnv+  , valueEnv    :: ValueEnv+  , classEnv    :: ClassEnv+  , instEnv     :: InstEnv+  , opPrecEnv   :: OpPrecEnv+  , augmentEnv  :: AugmentEnv -- for augmenting nullary class methods+  , dictEnv     :: DictEnv    -- for dictionary insertion+  , specEnv     :: SpecEnv    -- for dictionary specialization+  , nextId      :: Integer+  }++type DTM = S.State DTState++insertDicts :: InterfaceEnv -> TCEnv -> ValueEnv -> ClassEnv -> InstEnv+            -> OpPrecEnv -> Module PredType+            -> (Module Type, InterfaceEnv, TCEnv, ValueEnv, OpPrecEnv)+insertDicts intfEnv tcEnv vEnv clsEnv inEnv pEnv mdl@(Module _ m _ _ _) =+  (mdl', intfEnv', tcEnv', vEnv', pEnv')+  where initState =+          DTState m tcEnv vEnv clsEnv inEnv pEnv emptyAugEnv emptyDictEnv emptySpEnv 1+        (mdl', tcEnv', vEnv', pEnv') =+          runDTM (augment mdl >>= dictTrans >>= specialize >>= cleanup) initState+        intfEnv' = dictTransInterfaces vEnv' clsEnv intfEnv++runDTM :: DTM a -> DTState -> (a, TCEnv, ValueEnv, OpPrecEnv)+runDTM dtm s =+  let (a, s') = S.runState dtm s in (a, tyConsEnv s', valueEnv s', opPrecEnv s')++getModuleIdent :: DTM ModuleIdent+getModuleIdent = S.gets moduleIdent++getTyConsEnv :: DTM TCEnv+getTyConsEnv = S.gets tyConsEnv++modifyTyConsEnv :: (TCEnv -> TCEnv) -> DTM ()+modifyTyConsEnv f = S.modify $ \s -> s { tyConsEnv = f $ tyConsEnv s }++getValueEnv :: DTM ValueEnv+getValueEnv = S.gets valueEnv++modifyValueEnv :: (ValueEnv -> ValueEnv) -> DTM ()+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }++withLocalValueEnv :: DTM a -> DTM a+withLocalValueEnv act = do+  oldEnv <- getValueEnv+  res <- act+  modifyValueEnv $ const oldEnv+  return res++getClassEnv :: DTM ClassEnv+getClassEnv = S.gets classEnv++getInstEnv :: DTM InstEnv+getInstEnv = S.gets instEnv++modifyInstEnv :: (InstEnv -> InstEnv) -> DTM ()+modifyInstEnv f = S.modify $ \s -> s { instEnv = f $ instEnv s }++getPrecEnv :: DTM OpPrecEnv+getPrecEnv = S.gets opPrecEnv++modifyPrecEnv :: (OpPrecEnv -> OpPrecEnv) -> DTM ()+modifyPrecEnv f = S.modify $ \s -> s { opPrecEnv = f $ opPrecEnv s }++getAugEnv :: DTM AugmentEnv+getAugEnv = S.gets augmentEnv++setAugEnv :: AugmentEnv -> DTM ()+setAugEnv augEnv = S.modify $ \s -> s { augmentEnv = augEnv }++getDictEnv :: DTM DictEnv+getDictEnv = S.gets dictEnv++modifyDictEnv :: (DictEnv -> DictEnv) -> DTM ()+modifyDictEnv f = S.modify $ \s -> s { dictEnv = f $ dictEnv s }++withLocalDictEnv :: DTM a -> DTM a+withLocalDictEnv act = do+  oldEnv <- getDictEnv+  res <- act+  modifyDictEnv $ const oldEnv+  return res++getSpEnv :: DTM SpecEnv+getSpEnv = S.gets specEnv++setSpEnv :: SpecEnv -> DTM ()+setSpEnv spEnv = S.modify $ \s -> s { specEnv = spEnv }++getNextId :: DTM Integer+getNextId = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return nid++-- -----------------------------------------------------------------------------+-- Augmenting nullary class methods+-- -----------------------------------------------------------------------------++-- To prevent unwanted sharing of non-determinism for nullary class methods+-- we augment them with an additional unit argument.++type AugmentEnv = [QualIdent]++emptyAugEnv :: AugmentEnv+emptyAugEnv = []++initAugEnv :: ValueEnv -> AugmentEnv+initAugEnv = foldr (bindValue . snd) emptyAugEnv . allBindings+  where bindValue (Value f True _ (ForAll _ (PredType _ ty)))+          | arrowArity ty == 0 = (f :)+        bindValue _ = id++isAugmented :: AugmentEnv -> QualIdent -> Bool+isAugmented = flip elem++augmentValues :: ValueEnv -> ValueEnv+augmentValues = fmap augmentValueInfo++augmentValueInfo :: ValueInfo -> ValueInfo+augmentValueInfo (Value f True a (ForAll n (PredType ps ty)))+  | arrowArity ty == 0 = Value f True a $ ForAll n $ PredType ps ty'+  where ty' = augmentType ty+augmentValueInfo vi = vi++augmentTypes :: TCEnv -> TCEnv+augmentTypes = fmap augmentTypeInfo++augmentTypeInfo :: TypeInfo -> TypeInfo+augmentTypeInfo (TypeClass cls k ms) =+  TypeClass cls k $ map augmentClassMethod ms+augmentTypeInfo ti = ti++augmentClassMethod :: ClassMethod -> ClassMethod+augmentClassMethod mthd@(ClassMethod f a (PredType ps ty))+  | arrowArity ty == 0 =+    ClassMethod f (Just $ fromMaybe 0 a + 1) $ PredType ps $ augmentType ty+  | otherwise = mthd++augmentInstances :: AugmentEnv -> InstEnv -> InstEnv+augmentInstances = Map.mapWithKey . augmentInstInfo++augmentInstInfo :: AugmentEnv -> InstIdent -> InstInfo -> InstInfo+augmentInstInfo augEnv (cls, _) (m, ps, is) =+  (m, ps, map (augmentInstImpl augEnv cls) is)++augmentInstImpl :: AugmentEnv -> QualIdent -> (Ident, Int) -> (Ident, Int)+augmentInstImpl augEnv cls (f, a)+  | isAugmented augEnv (qualifyLike cls f) = (f, a + 1)+  | otherwise = (f, a)++class Augment a where+  augment :: a PredType -> DTM (a PredType)++instance Augment Module where+  augment (Module ps m es is ds) = do+    augEnv <- initAugEnv <$> getValueEnv+    setAugEnv augEnv+    modifyValueEnv $ augmentValues+    modifyTyConsEnv $ augmentTypes+    modifyInstEnv $ augmentInstances augEnv+    Module ps m es is <$> mapM (augmentDecl Nothing) ds++-- The first parameter of the functions 'augmentDecl', 'augmentEquation' and+-- 'augmentLhs' determines whether we have to unrename the function identifiers+-- before checking if the function has to augmented or not. Furthermore, it+-- specifies the module unqualified identifiers have to be qualified with.+-- The unrenaming is necessary for both class and instance declarations as all+-- identifiers within these have been renamed during the syntax check, while the+-- qualifying is needed for function declarations within instance declarations+-- as the implemented class methods can originate from another module. If not+-- qualified properly, the lookup in the augmentation environment would fail.++-- Since type signatures remain only in class declarations due to desugaring,+-- we can always perform the unrenaming and it is safe to assume that all other+-- functions mentioned in a type signature have to be augmented as well if the+-- first one is affected.++augmentDecl :: Maybe ModuleIdent -> Decl PredType -> DTM (Decl PredType)+augmentDecl _  d@(TypeSig          p fs qty) = do+  m <- getModuleIdent+  augEnv <- getAugEnv+  return $ if isAugmented augEnv (qualifyWith m $ unRenameIdent $ head fs)+              then TypeSig p fs $ augmentQualTypeExpr qty+              else d+augmentDecl mm (FunctionDecl    p pty f eqs) = do+    eqs' <- mapM (augmentEquation mm) eqs+    m <- maybe getModuleIdent return mm+    augEnv <- getAugEnv+    if isAugmented augEnv (qualifyWith m $ unRenameIdentIf (isJust mm) f)+      then return $ FunctionDecl p (augmentPredType pty) f eqs'+      else return $ FunctionDecl p pty f eqs'+augmentDecl _  (PatternDecl         p t rhs) = PatternDecl p t <$> augment rhs+augmentDecl _  (ClassDecl    p cx cls tv ds) = do+  m <- getModuleIdent+  ClassDecl p cx cls tv <$> mapM (augmentDecl $ Just m) ds+augmentDecl _  (InstanceDecl p cx cls ty ds) =+  InstanceDecl p cx cls ty <$> mapM (augmentDecl $ qidModule cls) ds+augmentDecl _ d                             = return d++augmentEquation :: Maybe ModuleIdent -> Equation PredType+                -> DTM (Equation PredType)+augmentEquation mm (Equation p lhs rhs) =+  Equation p <$> augmentLhs mm lhs <*> augment rhs++augmentLhs :: Maybe ModuleIdent -> Lhs PredType -> DTM (Lhs PredType)+augmentLhs mm lhs@(FunLhs f ts) = do+    m <- maybe getModuleIdent return mm+    augEnv <- getAugEnv+    if isAugmented augEnv (qualifyWith m $ unRenameIdentIf (isJust mm) f)+      then return $ FunLhs f $ ConstructorPattern predUnitType qUnitId [] : ts+      else return lhs+augmentLhs _ lhs               =+  internalError $ "Dictionary.augmentLhs" ++ show lhs++instance Augment Rhs where+  augment (SimpleRhs p e []) = simpleRhs p <$> augment e+  augment rhs                =+    internalError $ "Dictionary.augment: " ++ show rhs++instance Augment Expression where+  augment l@(Literal     _ _) = return l+  augment v@(Variable pty v') = do+    augEnv <- getAugEnv+    return $ if isAugmented augEnv v'+               then apply (Variable (augmentPredType pty) v')+                      [Constructor predUnitType qUnitId]+               else v+  augment c@(Constructor _ _) = return c+  augment (Typed       e qty) = flip Typed qty <$> augment e+  augment (Apply       e1 e2) = Apply <$> augment e1 <*> augment e2+  augment (Lambda       ts e) = Lambda ts <$> augment e+  augment (Let          ds e) =+    Let <$> mapM (augmentDecl Nothing) ds <*> augment e+  augment (Case      ct e as) = Case ct <$> augment e <*> mapM augment as+  augment e                   = internalError $ "Dictionary.augment: " ++ show e++instance Augment Alt where+  augment (Alt p t rhs) = Alt p t <$> augment rhs++augmentPredType :: PredType -> PredType+augmentPredType (PredType ps ty) = PredType ps $ augmentType ty++augmentType :: Type -> Type+augmentType = TypeArrow unitType++augmentQualTypeExpr :: QualTypeExpr -> QualTypeExpr+augmentQualTypeExpr (QualTypeExpr cx ty) = QualTypeExpr cx $ augmentTypeExpr ty++augmentTypeExpr :: TypeExpr -> TypeExpr+augmentTypeExpr = ArrowType $ ConstructorType qUnitId++-- -----------------------------------------------------------------------------+-- Lifting class and instance declarations+-- -----------------------------------------------------------------------------++-- When we lift class and instance declarations, we can remove the optional+-- default declaration since it has already been considered during the type+-- check.++liftDecls :: Decl PredType -> DTM [Decl PredType]+liftDecls (DefaultDecl _ _) = return []+liftDecls (ClassDecl _ _ cls tv ds) = do+  m <- getModuleIdent+  liftClassDecls (qualifyWith m cls) tv ds+liftDecls (InstanceDecl _ cx cls ty ds) = do+  clsEnv <- getClassEnv+  let PredType ps ty' = toPredType [] $ QualTypeExpr cx ty+      ps' = minPredSet clsEnv ps+  liftInstanceDecls ps' cls ty' ds+liftDecls d = return [d]++liftClassDecls :: QualIdent -> Ident -> [Decl PredType] -> DTM [Decl PredType]+liftClassDecls cls tv ds = do+  dictDecl <- createClassDictDecl cls tv ods+  clsEnv <- getClassEnv+  let fs = classMethods cls clsEnv+  methodDecls <- mapM (createClassMethodDecl cls ms) fs+  return $ dictDecl : methodDecls+  where (vds, ods) = partition isValueDecl ds+        ms = methodMap vds++liftInstanceDecls :: PredSet -> QualIdent -> Type -> [Decl PredType]+                  -> DTM [Decl PredType]+liftInstanceDecls ps cls ty ds = do+  dictDecl <- createInstDictDecl ps cls ty+  clsEnv <- getClassEnv+  let fs = classMethods cls clsEnv+  methodDecls <- mapM (createInstMethodDecl ps cls ty ms) fs+  return $ dictDecl : methodDecls+  where ms = methodMap ds++-- Since not every class method needs to be implemented in a class or instance+-- declaration, we use a map to associate a class method identifier with its+-- implementation.++type MethodMap = [(Ident, Decl PredType)]++-- We have to unrename the method's identifiers here because the syntax check+-- has renamed them before.++methodMap :: [Decl PredType] -> MethodMap+methodMap ds = [(unRenameIdent f, d) | d@(FunctionDecl _ _ f _) <- ds]++createClassDictDecl :: QualIdent -> Ident -> [Decl a] -> DTM (Decl a)+createClassDictDecl cls tv ds = do+  c <- createClassDictConstrDecl cls tv ds+  return $ DataDecl NoPos (dictTypeId cls) [tv] [c] []++createClassDictConstrDecl :: QualIdent -> Ident -> [Decl a] -> DTM ConstrDecl+createClassDictConstrDecl cls tv ds = do+  clsEnv <- getClassEnv+  let sclss = superClasses cls clsEnv+      cx    = [Constraint scls (VariableType tv) | scls <- sclss]+      tvs   = tv : filter (unRenameIdent tv /=) identSupply+      mtys  = map (fromType tvs . generalizeMethodType . transformMethodPredType)+                [toMethodType cls tv qty | TypeSig _ fs qty <- ds, _ <- fs]+  return $ ConstrDecl NoPos [] cx (dictConstrId cls) mtys++classDictConstrPredType :: ValueEnv -> ClassEnv -> QualIdent -> PredType+classDictConstrPredType vEnv clsEnv cls = PredType ps $ foldr TypeArrow ty mtys+  where sclss = superClasses cls clsEnv+        ps    = Set.fromList [Pred scls (TypeVariable 0) | scls <- sclss]+        fs    = classMethods cls clsEnv+        mptys = map (classMethodType vEnv cls) fs+        ty    = dictType $ Pred cls $ TypeVariable 0+        mtys  = map (generalizeMethodType . transformMethodPredType) mptys++createInstDictDecl :: PredSet -> QualIdent -> Type -> DTM (Decl PredType)+createInstDictDecl ps cls ty = do+  pty <- PredType ps . arrowBase <$> getInstDictConstrType cls ty+  funDecl NoPos pty (instFunId cls ty) [] <$> createInstDictExpr cls ty++createInstDictExpr :: QualIdent -> Type -> DTM (Expression PredType)+createInstDictExpr cls ty = do+  ty' <- instType <$> getInstDictConstrType cls ty+  m <- getModuleIdent+  clsEnv <- getClassEnv+  let fs = map (qImplMethodId m cls ty) $ classMethods cls clsEnv+  return $ apply (Constructor (predType ty') (qDictConstrId cls))+             (zipWith (Variable . predType) (arrowArgs ty') fs)++getInstDictConstrType :: QualIdent -> Type -> DTM Type+getInstDictConstrType cls ty = do+  vEnv <- getValueEnv+  clsEnv <- getClassEnv+  return $ instanceType ty $ unpredType $ classDictConstrPredType vEnv clsEnv cls++createClassMethodDecl :: QualIdent -> MethodMap -> Ident -> DTM (Decl PredType)+createClassMethodDecl cls =+  createMethodDecl (defaultMethodId cls) (defaultClassMethodDecl cls)++defaultClassMethodDecl :: QualIdent -> Ident -> DTM (Decl PredType)+defaultClassMethodDecl cls f = do+  pty@(PredType _ ty) <- getClassMethodType cls f+  augEnv <- getAugEnv+  let pats = if isAugmented augEnv (qualifyLike cls f)+               then [ConstructorPattern predUnitType qUnitId []]+               else []+  return $ funDecl NoPos pty f pats $ preludeError (instType ty) $+    "No instance or default method for class operation " ++ escName f++getClassMethodType :: QualIdent -> Ident -> DTM PredType+getClassMethodType cls f = do+  vEnv <- getValueEnv+  return $ classMethodType vEnv cls f++classMethodType :: ValueEnv -> QualIdent -> Ident -> PredType+classMethodType vEnv cls f = pty+  where ForAll _ pty = funType (qualifyLike cls f) vEnv++createInstMethodDecl :: PredSet -> QualIdent -> Type -> MethodMap -> Ident+                     -> DTM (Decl PredType)+createInstMethodDecl ps cls ty =+  createMethodDecl (implMethodId cls ty) (defaultInstMethodDecl ps cls ty)++defaultInstMethodDecl :: PredSet -> QualIdent -> Type -> Ident+                      -> DTM (Decl PredType)+defaultInstMethodDecl ps cls ty f = do+  vEnv <- getValueEnv+  let pty@(PredType _ ty') = instMethodType vEnv ps cls ty f+  return $ funDecl NoPos pty f [] $+    Variable (predType $ instType ty') (qDefaultMethodId cls f)++-- Returns the type for a given instance's method of a given class. To this+-- end, the class method's type is stripped of its first predicate (which is+-- the implicit class constraint) and the class variable is replaced with the+-- instance's type. The remaining predicate set is then united with the+-- instance's predicate set.++instMethodType :: ValueEnv -> PredSet -> QualIdent -> Type -> Ident -> PredType+instMethodType vEnv ps cls ty f = PredType (ps `Set.union` ps'') ty''+  where PredType ps'  ty'  = classMethodType vEnv cls f+        PredType ps'' ty'' = instanceType ty $ PredType (Set.deleteMin ps') ty'++createMethodDecl :: (Ident -> Ident) -> (Ident -> DTM (Decl PredType))+                 -> MethodMap -> Ident -> DTM (Decl PredType)+createMethodDecl methodId defaultDecl ms f =+  liftM (renameDecl $ methodId f) $ maybe (defaultDecl f) return (lookup f ms)++-- We have to rename the left hand side of lifted function declarations+-- accordingly which is done by the function 'renameDecl'.++renameDecl :: Ident -> Decl a -> Decl a+renameDecl f (FunctionDecl p a _ eqs) = FunctionDecl p a f $ map renameEq eqs+  where renameEq (Equation p' lhs rhs) = Equation p' (renameLhs lhs) rhs+        renameLhs (FunLhs _ ts) = FunLhs f ts+        renameLhs _ = internalError "Dictionary.renameDecl.renameLhs"+renameDecl _ _ = internalError "Dictionary.renameDecl"++-- -----------------------------------------------------------------------------+-- Creating stub declarations+-- -----------------------------------------------------------------------------++-- For each class method f defined in the processed module we have to introduce+-- a stub method with the same name that selects the appropriate function from+-- the provided dictionary and applies the remaining arguments to it. We also+-- create a stub method for each super class selecting the corresponding super+-- class dictionary from the provided class dictionary.++createStubs :: Decl PredType -> DTM [Decl Type]+createStubs (ClassDecl _ _ cls _ _) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  clsEnv <- getClassEnv+  let ocls  = qualifyWith m cls+      sclss = superClasses ocls clsEnv+      fs    = classMethods ocls clsEnv+      dictConstrPty = classDictConstrPredType vEnv clsEnv ocls+      (superDictAndMethodTys, dictTy) =+        arrowUnapply $ transformPredType dictConstrPty+      (superDictTys, methodTys)       =+        splitAt (length sclss) superDictAndMethodTys+      (superStubTys, methodStubTys)   =+        splitAt (length sclss) $ map (TypeArrow dictTy) superDictAndMethodTys+  superDictVs <- mapM (freshVar "_#super" . instType) superDictTys+  methodVs <- mapM (freshVar "_#meth" . instType) methodTys+  methodDictTyss <- zipWithM (computeMethodDictTypes ocls) fs methodTys+  methodDictVss <- mapM (mapM $ freshVar "_#dict" . instType) methodDictTyss+  let patternVs   = superDictVs ++ methodVs+      pattern     = createDictPattern (instType dictTy) ocls patternVs+      superStubs  = zipWith3 (createSuperDictStubDecl pattern ocls)+                      superStubTys sclss superDictVs+      methodStubs = zipWith4 (createMethodStubDecl pattern)+                      methodStubTys fs methodVs methodDictVss+  return $ superStubs ++ methodStubs+createStubs _ = return []++-- Computes the additional dictionary arguments of a transformed method type+-- which correspond to the constraints of the original class method's type.++computeMethodDictTypes :: QualIdent -> Ident -> Type -> DTM [Type]+computeMethodDictTypes cls f ty = do+  PredType _ ty' <- getClassMethodType cls f+  return $ take (length tys - arrowArity ty') tys+  where tys = arrowArgs ty++createDictPattern :: a -> QualIdent -> [(a, Ident)] -> Pattern a+createDictPattern a cls = constrPattern a (qDictConstrId cls)++createSuperDictStubDecl :: Pattern a -> QualIdent -> a -> QualIdent+                        -> (a, Ident) -> Decl a+createSuperDictStubDecl t cls a super v =+  createStubDecl t a (superDictStubId cls super) v []++createMethodStubDecl :: Pattern a -> a -> Ident -> (a, Ident) -> [(a, Ident)]+                     -> Decl a+createMethodStubDecl = createStubDecl++createStubDecl :: Pattern a -> a -> Ident -> (a, Ident) -> [(a, Ident)]+               -> Decl a+createStubDecl t a f v us = FunctionDecl NoPos a f [createStubEquation t f v us]++createStubEquation :: Pattern a -> Ident -> (a, Ident) -> [(a, Ident)]+                   -> Equation a+createStubEquation t f v us =+  mkEquation NoPos f (t : map (uncurry VariablePattern) us) $+    apply (uncurry mkVar v) (map (uncurry mkVar) us)++superDictStubType :: QualIdent -> QualIdent -> Type -> Type+superDictStubType cls super ty =+  TypeArrow (dictType $ Pred cls ty) (dictType $ Pred super ty)++-- -----------------------------------------------------------------------------+-- Entering new bindings into the environments+-- -----------------------------------------------------------------------------++bindDictTypes :: ModuleIdent -> ClassEnv -> TCEnv -> TCEnv+bindDictTypes m clsEnv tcEnv =+  foldr (bindDictType m clsEnv) tcEnv (allEntities tcEnv)++bindDictType :: ModuleIdent -> ClassEnv -> TypeInfo -> TCEnv -> TCEnv+bindDictType m clsEnv (TypeClass cls k ms) = bindEntity m tc ti+  where ti    = DataType tc (KindArrow k KindStar) [c]+        tc    = qDictTypeId cls+        c     = DataConstr (dictConstrId cls) 0 ps tys+        sclss = superClasses cls clsEnv+        ps    = Set.fromList [Pred scls (TypeVariable 0) | scls <- sclss]+        tys   = map (generalizeMethodType . transformMethodPredType . methodType) ms+bindDictType _ _      _                    = id++bindClassDecls :: ModuleIdent -> TCEnv -> ClassEnv -> ValueEnv -> ValueEnv+bindClassDecls m tcEnv clsEnv =+  flip (foldr $ bindClassEntities m clsEnv) $ allEntities tcEnv++-- It is safe to use 'fromMaybe 0' in 'bindClassEntities', because the+-- augmentation has already replaced the 'Nothing' value for the arity+-- of a method's implementation with 'Just 1' (despite the fact that+-- maybe no default implementation has been provided) if the method has+-- been augmented.++bindClassEntities :: ModuleIdent -> ClassEnv -> TypeInfo -> ValueEnv -> ValueEnv+bindClassEntities m clsEnv (TypeClass cls _ ms) =+  bindClassDict m clsEnv cls . bindSuperStubs m cls sclss .+    bindDefaultMethods m cls fs+  where fs    = zip (map methodName ms) (map (fromMaybe 0 . methodArity) ms)+        sclss = superClasses cls clsEnv+bindClassEntities _ _ _ = id++bindClassDict :: ModuleIdent -> ClassEnv -> QualIdent -> ValueEnv -> ValueEnv+bindClassDict m clsEnv cls vEnv = bindEntity m c dc vEnv+  where c  = qDictConstrId cls+        dc = DataConstructor c a (replicate a anonId) tySc+        a  = Set.size ps + arrowArity ty+        pty@(PredType ps ty) = classDictConstrPredType vEnv clsEnv cls+        tySc = ForAllExist 1 0 pty++bindDefaultMethods :: ModuleIdent -> QualIdent -> [(Ident, Int)] -> ValueEnv+                   -> ValueEnv+bindDefaultMethods m = flip . foldr . bindDefaultMethod m++bindDefaultMethod :: ModuleIdent -> QualIdent -> (Ident, Int) -> ValueEnv+                  -> ValueEnv+bindDefaultMethod m cls (f, n) vEnv =+  bindMethod m (qDefaultMethodId cls f) n (classMethodType vEnv cls f) vEnv++bindSuperStubs :: ModuleIdent -> QualIdent -> [QualIdent] -> ValueEnv+               -> ValueEnv+bindSuperStubs m = flip . foldr . bindSuperStub m++bindSuperStub :: ModuleIdent -> QualIdent -> QualIdent -> ValueEnv -> ValueEnv+bindSuperStub m cls scls = bindEntity m f $ Value f False 1 $ polyType ty+  where f  = qSuperDictStubId cls scls+        ty = superDictStubType cls scls (TypeVariable 0)++bindInstDecls :: ModuleIdent -> TCEnv -> ClassEnv -> InstEnv -> ValueEnv+                  -> ValueEnv+bindInstDecls m tcEnv clsEnv =+  flip (foldr $ bindInstFuns m tcEnv clsEnv) . Map.toList++bindInstFuns :: ModuleIdent -> TCEnv -> ClassEnv -> (InstIdent, InstInfo)+             -> ValueEnv -> ValueEnv+bindInstFuns m tcEnv clsEnv ((cls, tc), (m', ps, is)) =+  bindInstDict m cls ty m' ps . bindInstMethods m clsEnv cls ty m' ps is+  where ty = applyType (TypeConstructor tc) (take n (map TypeVariable [0..]))+        n = kindArity (tcKind m tc tcEnv) - kindArity (clsKind m cls tcEnv)++bindInstDict :: ModuleIdent -> QualIdent -> Type -> ModuleIdent -> PredSet+             -> ValueEnv -> ValueEnv+bindInstDict m cls ty m' ps =+  bindMethod m (qInstFunId m' cls ty) 0 $ PredType ps $ dictType $ Pred cls ty++bindInstMethods :: ModuleIdent -> ClassEnv -> QualIdent -> Type -> ModuleIdent+                -> PredSet -> [(Ident, Int)] -> ValueEnv -> ValueEnv+bindInstMethods m clsEnv cls ty m' ps is =+  flip (foldr (bindInstMethod m cls ty m' ps is)) (classMethods cls clsEnv)++bindInstMethod :: ModuleIdent -> QualIdent -> Type -> ModuleIdent+               -> PredSet -> [(Ident, Int)] -> Ident -> ValueEnv -> ValueEnv+bindInstMethod m cls ty m' ps is f vEnv = bindMethod m f' a pty vEnv+  where f'  = qImplMethodId m' cls ty f+        a   = fromMaybe 0 $ lookup f is+        pty = instMethodType vEnv ps cls ty f++bindMethod :: ModuleIdent -> QualIdent -> Int -> PredType -> ValueEnv+           -> ValueEnv+bindMethod m f n pty = bindEntity m f $ Value f False n $ typeScheme pty++-- The function 'bindEntity' introduces a binding for an entity into a top-level+-- environment. Depending on whether the entity is defined in the current module+-- or not, either an unqualified and a qualified local binding or a qualified+-- import are added to the environment.++bindEntity :: Entity a => ModuleIdent -> QualIdent -> a -> TopEnv a+           -> TopEnv a+bindEntity m x = case qidModule (qualUnqualify m x) of+  Just m' | m /= m' -> qualImportTopEnv m' x'+  _                 -> qualBindTopEnv (qualifyWith m x')+  where x' = unqualify x++-- -----------------------------------------------------------------------------+-- Transforming the environments+-- -----------------------------------------------------------------------------++dictTransTypes :: TCEnv -> TCEnv+dictTransTypes = fmap dictTransTypeInfo++dictTransTypeInfo :: TypeInfo -> TypeInfo+dictTransTypeInfo (DataType tc k cs) =+  DataType tc k $ map dictTransDataConstr cs+dictTransTypeInfo (RenamingType tc k nc) =+  RenamingType tc k $ dictTransDataConstr nc+dictTransTypeInfo ti@(AliasType _ _ _ _) = ti+dictTransTypeInfo (TypeClass cls k ms) =+  TypeClass cls k $ map dictTransClassMethod ms+dictTransTypeInfo (TypeVar _) =+  internalError "Dictionary.dictTransTypeInfo: type variable"++dictTransDataConstr :: DataConstr -> DataConstr+dictTransDataConstr (DataConstr c n ps tys) =+  DataConstr c n emptyPredSet $ map dictType (Set.toAscList ps) ++ tys+dictTransDataConstr (RecordConstr c n ps _ tys) =+  dictTransDataConstr $ DataConstr c n ps tys++-- For the same reason as in 'bindClassEntities' it is safe to use 'fromMaybe 0'+-- in 'dictTransClassMethod'. Note that type classes are removed anyway in the+-- cleanup phase.++dictTransClassMethod :: ClassMethod -> ClassMethod+dictTransClassMethod (ClassMethod f a pty) = ClassMethod f a' $ predType ty+  where a' = Just $ fromMaybe 0 a + arrowArity ty - arrowArity (unpredType pty)+        ty = transformPredType pty++dictTransValues :: ValueEnv -> ValueEnv+dictTransValues = fmap dictTransValueInfo++dictTransValueInfo :: ValueInfo -> ValueInfo+dictTransValueInfo (DataConstructor c a ls (ForAllExist n n' pty)) =+  DataConstructor c a' ls' $ ForAllExist n n' $ predType ty+  where a'  = arrowArity ty+        ls' = replicate (a' - a) anonId ++ ls+        ty  = transformPredType pty+dictTransValueInfo (NewtypeConstructor c l (ForAllExist n n' pty)) =+  NewtypeConstructor c l (ForAllExist n n' (predType (unpredType pty)))+dictTransValueInfo (Value f cm a (ForAll n pty)) =+  Value f False a' $ ForAll n $ predType ty+  where a' = a + if cm then 1 else arrowArity ty - arrowArity (unpredType pty)+        ty = transformPredType pty+dictTransValueInfo (Label l cs (ForAll n pty)) =+  Label l cs $ ForAll n $ predType $ unpredType pty++-- -----------------------------------------------------------------------------+-- Adding exports+-- -----------------------------------------------------------------------------++addExports :: Maybe ExportSpec -> [Export] -> Maybe ExportSpec+addExports (Just (Exporting p es)) es' = Just $ Exporting p $ es ++ es'+addExports Nothing                 _   = internalError "Dictionary.addExports"++dictExports :: Decl a -> DTM [Export]+dictExports (ClassDecl _ _ cls _ _) = do+  m <- getModuleIdent+  clsEnv <- getClassEnv+  return $ classExports m clsEnv cls+dictExports (InstanceDecl _ _ cls ty _) = do+  m <- getModuleIdent+  clsEnv <- getClassEnv+  return $ instExports m clsEnv cls (toType [] ty)+dictExports _ = return []++classExports :: ModuleIdent -> ClassEnv -> Ident -> [Export]+classExports m clsEnv cls =+  ExportTypeWith (qDictTypeId qcls) [dictConstrId qcls] :+    map (Export . qSuperDictStubId qcls) (superClasses qcls clsEnv) +++      map (Export . qDefaultMethodId qcls) (classMethods qcls clsEnv)+  where qcls = qualifyWith m cls++instExports :: ModuleIdent -> ClassEnv -> QualIdent -> Type -> [Export]+instExports m clsEnv cls ty =+  Export (qInstFunId m cls ty) :+    map (Export . qImplMethodId m cls ty) (classMethods cls clsEnv)++-- -----------------------------------------------------------------------------+-- Transforming the module+-- -----------------------------------------------------------------------------++type DictEnv = [(Pred, Expression Type)]++emptyDictEnv :: DictEnv+emptyDictEnv = []++class DictTrans a where+  dictTrans :: a PredType -> DTM (a Type)++instance DictTrans Module where+  dictTrans (Module ps m es is ds) = do+    liftedDs <- concatMapM liftDecls ds+    stubDs <- concatMapM createStubs ds+    tcEnv <- getTyConsEnv+    clsEnv <- getClassEnv+    inEnv <- getInstEnv+    modifyValueEnv $ bindClassDecls m tcEnv clsEnv+    modifyValueEnv $ bindInstDecls m tcEnv clsEnv inEnv+    modifyTyConsEnv $ bindDictTypes m clsEnv+    transDs <- mapM dictTrans liftedDs+    modifyValueEnv $ dictTransValues+    modifyTyConsEnv $ dictTransTypes+    dictEs <- addExports es <$> concatMapM dictExports ds+    return $ Module ps m dictEs is $ transDs ++ stubDs++-- We use and transform the type from the type constructor environment for+-- transforming a constructor declaration as it contains the reduced and+-- restricted predicate set for each data constructor.++-- The pattern declaration case of the DictTrans Decl instance converts+-- variable declarations with an overloaded type into function declarations.+-- This is necessary so that the compiler can add the implicit dictionary+-- arguments to the declaration.++instance DictTrans Decl where+  dictTrans (InfixDecl      p fix prec ops) = return $ InfixDecl p fix prec ops+  dictTrans (DataDecl        p tc tvs cs _) = do+    m <- getModuleIdent+    tcEnv <- getTyConsEnv+    let DataType _ _ cs' = head $ qualLookupTypeInfo (qualifyWith m tc) tcEnv+    return $ DataDecl p tc tvs (zipWith (dictTransConstrDecl tvs) cs cs') []+  dictTrans (ExternalDataDecl     p tc tvs) = return $ ExternalDataDecl p tc tvs+  dictTrans (NewtypeDecl     p tc tvs nc _) =+    return $ NewtypeDecl p tc tvs nc []+  dictTrans (TypeDecl          p tc tvs ty) = return $ TypeDecl p tc tvs ty+  dictTrans (FunctionDecl p      pty f eqs) =+    FunctionDecl p (transformPredType pty) f <$> mapM dictTrans eqs+  dictTrans (PatternDecl           p t rhs) = case t of+    VariablePattern pty@(PredType ps _) v | not (Set.null ps) ->+      dictTrans $ FunctionDecl p pty v [Equation p (FunLhs v []) rhs]+    _ -> withLocalDictEnv $ PatternDecl p <$> dictTrans t <*> dictTrans rhs+  dictTrans d@(FreeDecl                _ _) = return $ fmap unpredType d+  dictTrans d@(ExternalDecl            _ _) = return $ fmap unpredType d+  dictTrans d                               =+    internalError $ "Dictionary.dictTrans: " ++ show d++dictTransConstrDecl :: [Ident] -> ConstrDecl -> DataConstr -> ConstrDecl+dictTransConstrDecl tvs (ConstrDecl p evs _ c tes) dc =+  ConstrDecl p evs [] c $ map (fromType $ tvs ++ evs ++ bvs) tys+  where DataConstr _ _ _ tys = dictTransDataConstr dc+        bvs = nub $ bv tes+dictTransConstrDecl tvs (ConOpDecl p evs cx ty1 op ty2) dc =+  dictTransConstrDecl tvs (ConstrDecl p evs cx op [ty1, ty2]) dc+dictTransConstrDecl _ d _ = internalError $ "Dictionary.dictTrans: " ++ show d++instance DictTrans Equation where+  dictTrans (Equation p (FunLhs f ts) rhs) = withLocalValueEnv $ do+    m <- getModuleIdent+    pls <- matchPredList (varType m f) $+             foldr (TypeArrow . typeOf) (typeOf rhs) ts+    ts' <- addDictArgs pls ts+    modifyValueEnv $ bindPatterns ts'+    Equation p (FunLhs f ts') <$> dictTrans rhs+  dictTrans eq                             =+    internalError $ "Dictionary.dictTrans: " ++ show eq++instance DictTrans Rhs where+  dictTrans (SimpleRhs p e []) = simpleRhs p <$> dictTrans e+  dictTrans rhs                =+    internalError $ "Dictionary.dictTrans: " ++ show rhs++instance DictTrans Pattern where+  dictTrans (LiteralPattern        pty l) =+    return $ LiteralPattern (unpredType pty) l+  dictTrans (VariablePattern       pty v) =+    return $ VariablePattern (unpredType pty) v+  dictTrans (ConstructorPattern pty c ts) = do+    pls <- matchPredList (conType c) $+             foldr (TypeArrow . typeOf) (unpredType pty) ts+    ConstructorPattern (unpredType pty) c <$> addDictArgs pls ts+  dictTrans (AsPattern               v t) = AsPattern v <$> dictTrans t+  dictTrans t                             =+    internalError $ "Dictionary.dictTrans: " ++ show t++instance DictTrans Expression where+  dictTrans (Literal     pty l) = return $ Literal (unpredType pty) l+  dictTrans (Variable    pty v) = do+    pls <- matchPredList (funType v) (unpredType pty)+    es <- mapM dictArg pls+    let ty = foldr (TypeArrow . typeOf) (unpredType pty) es+    return $ apply (Variable ty v) es+  dictTrans (Constructor pty c) = do+    pls <- matchPredList (conType c) (unpredType pty)+    es <- mapM dictArg pls+    let ty = foldr (TypeArrow . typeOf) (unpredType pty) es+    return $ apply (Constructor ty c) es+  dictTrans (Apply       e1 e2) =+    Apply <$> dictTrans e1 <*> dictTrans e2+  dictTrans (Typed       e qty) =+    Typed <$> dictTrans e <*> dictTransQualTypeExpr qty+  dictTrans (Lambda       ts e) = withLocalValueEnv $ withLocalDictEnv $ do+    ts' <- mapM dictTrans ts+    modifyValueEnv $ bindPatterns ts'+    Lambda ts' <$> dictTrans e+  dictTrans (Let          ds e) = withLocalValueEnv $ do+    modifyValueEnv $ bindDecls ds+    Let <$> mapM dictTrans ds <*> dictTrans e+  dictTrans (Case      ct e as) =+    Case ct <$> dictTrans e <*> mapM dictTrans as+  dictTrans e                   =+    internalError $ "Dictionary.dictTrans: " ++ show e++-- Just like before in desugaring, we ignore the context in the type signature+-- of a typed expression, since there should be no possibility to provide an+-- non-empty context without scoped type-variables.+-- TODO: Verify++dictTransQualTypeExpr :: QualTypeExpr -> DTM QualTypeExpr+dictTransQualTypeExpr (QualTypeExpr _ ty) = return $ QualTypeExpr [] ty++instance DictTrans Alt where+  dictTrans (Alt p t rhs) = withLocalValueEnv $ withLocalDictEnv $ do+    t' <- dictTrans t+    modifyValueEnv $ bindPattern t'+    Alt p t' <$> dictTrans rhs++addDictArgs :: [Pred] -> [Pattern PredType] -> DTM [Pattern Type]+addDictArgs pls ts = do+  dictVars <- mapM (freshVar "_#dict" . dictType) pls+  clsEnv <- getClassEnv+  modifyDictEnv $ (++) $ dicts clsEnv $ zip pls (map (uncurry mkVar) dictVars)+  (++) (map (uncurry VariablePattern) dictVars) <$> mapM dictTrans ts+  where dicts clsEnv vs+          | null vs = vs+          | otherwise = vs ++ dicts clsEnv (concatMap (superDicts clsEnv) vs)+        superDicts clsEnv (Pred cls ty, e) =+          map (superDict cls ty e) (superClasses cls clsEnv)+        superDict cls ty e scls =+          (Pred scls ty, Apply (superDictExpr cls scls ty) e)+        superDictExpr cls scls ty =+          Variable (superDictStubType cls scls ty) (qSuperDictStubId cls scls)++-- The function 'dictArg' constructs the dictionary argument for a predicate+-- from the predicates of a class method or an overloaded function. It checks+-- whether a dictionary for the predicate is available in the dictionary+-- environment, which is the case when the predicate's type is a type variable,+-- and uses 'instDict' otherwise in order to supply a new dictionary using the+-- appropriate instance dictionary construction function. If the corresponding+-- instance declaration has a non-empty context, the dictionary construction+-- function is applied to the dictionaries computed for the context instantiated+-- at the appropriate types.++dictArg :: Pred -> DTM (Expression Type)+dictArg p = maybeM (instDict p) return (lookup p <$> getDictEnv)++instDict :: Pred -> DTM (Expression Type)+instDict p = instPredList p >>= flip (uncurry instFunApp) p++instFunApp :: ModuleIdent -> [Pred] -> Pred -> DTM (Expression Type)+instFunApp m pls p@(Pred cls ty) = apply (Variable ty' f) <$> mapM dictArg pls+  where f   = qInstFunId m cls ty+        ty' = foldr1 TypeArrow $ map dictType $ pls ++ [p]++instPredList :: Pred -> DTM (ModuleIdent, [Pred])+instPredList (Pred cls ty) = case unapplyType True ty of+  (TypeConstructor tc, tys) -> do+    inEnv <- getInstEnv+    case lookupInstInfo (cls, tc) inEnv of+      Just (m, ps, _) -> return (m, expandAliasType tys $ Set.toAscList ps)+      Nothing -> internalError $ "Dictionary.instPredList: " ++ show (cls, tc)+  _ -> internalError $ "Dictionary.instPredList: " ++ show ty++-- When adding dictionary arguments on the left hand side of an equation and+-- in applications, respectively, the compiler must unify the function's type+-- with the concrete instance at which that type is used in order to determine+-- the correct context.++-- Polymorphic methods make things a little bit more complicated. When an+-- instance dictionary constructor is applied to an instance method, the+-- suffix of the instance method type's context that corresponds to the+-- additional constraints of the type class method must be discarded and+-- no dictionaries must be added for these constraints. Unfortunately, the+-- dictionary transformation has already been applied to the component types+-- of the dictionary constructor. Therefore, the function 'matchPredList'+-- tries to find a suffix of the context whose transformation matches the+-- initial arrows of the instance type.++matchPredList :: (ValueEnv -> TypeScheme) -> Type -> DTM [Pred]+matchPredList tySc ty2 = do+  ForAll _ (PredType ps ty1) <- tySc <$> getValueEnv+  return $ foldr (\(pls1, pls2) pls' ->+                   fromMaybe pls' $ qualMatch pls1 ty1 pls2 ty2)+                 (internalError $ "Dictionary.matchPredList: " ++ show ps)+                 (splits $ Set.toAscList ps)++qualMatch :: [Pred] -> Type -> [Pred] -> Type -> Maybe [Pred]+qualMatch pls1 ty1 pls2 ty2 = case predListMatch pls2 ty2 of+  Just ty2' -> Just $ subst (matchType ty1 ty2' idSubst) pls1+  Nothing -> Nothing++predListMatch :: [Pred] -> Type -> Maybe Type+predListMatch []     ty = Just ty+predListMatch (p:ps) ty = case ty of+  TypeForall _ ty'                                 -> predListMatch (p : ps) ty'+  TypeArrow ty1 ty2 | ty1 == dictType (instPred p) -> predListMatch ps ty2+  _                                                -> Nothing++splits :: [a] -> [([a], [a])]+splits xs = zip (inits xs) (tails xs)++-- -----------------------------------------------------------------------------+-- Optimizing method calls+-- -----------------------------------------------------------------------------++-- Whenever a type class method is applied at a known type, the compiler can+-- apply the type instance's implementation directly.++type SpecEnv = Map.Map (QualIdent, QualIdent) QualIdent++emptySpEnv :: SpecEnv+emptySpEnv = Map.empty++initSpEnv :: ClassEnv -> InstEnv -> SpecEnv+initSpEnv clsEnv = foldr (uncurry bindInstance) emptySpEnv . Map.toList+  where bindInstance (cls, tc) (m, _, _) =+          flip (foldr $ bindInstanceMethod m cls tc) $ classMethods cls clsEnv+        bindInstanceMethod m cls tc f = Map.insert (f', d) f''+          where f'  = qualifyLike cls f+                d   = qInstFunId m cls ty+                f'' = qImplMethodId m cls ty f+                ty  = TypeConstructor tc++class Specialize a where+  specialize :: a Type -> DTM (a Type)++instance Specialize Module where+  specialize (Module ps m es is ds) = do+    clsEnv <- getClassEnv+    inEnv <- getInstEnv+    setSpEnv $ initSpEnv clsEnv inEnv+    Module ps m es is <$> mapM specialize ds++instance Specialize Decl where+  specialize (FunctionDecl p ty f eqs) =+    FunctionDecl p ty f <$> mapM specialize eqs+  specialize (PatternDecl     p t rhs) = PatternDecl p t <$> specialize rhs+  specialize d                         = return d++instance Specialize Equation where+  specialize (Equation p lhs rhs) = Equation p lhs <$> specialize rhs++instance Specialize Rhs where+  specialize (SimpleRhs p e []) = simpleRhs p <$> specialize e+  specialize rhs                =+    internalError $ "Dictionary.specialize: " ++ show rhs++instance Specialize Expression where+  specialize e = specialize' e []++specialize' :: Expression Type -> [Expression Type] -> DTM (Expression Type)+specialize' l@(Literal     _ _) es = return $ apply l es+specialize' v@(Variable   _ v') es = do+  spEnv <- getSpEnv+  return $ case Map.lookup (v', f) spEnv of+    Just f' -> apply (Variable ty' f') $ es'' ++ es'+    Nothing -> apply v es+  where d:es' = es+        (Variable _ f, es'') = unapply d []+        ty' = foldr (TypeArrow . typeOf) (typeOf $ Apply v d) es''+specialize' c@(Constructor _ _) es = return $ apply c es+specialize' (Typed       e qty) es = do+  e' <- specialize e+  return $ apply (Typed e' qty) es+specialize' (Apply       e1 e2) es = do+  e2' <- specialize e2+  specialize' e1 $ e2' : es+specialize' (Lambda       ts e) es = do+  e' <- specialize e+  return $ apply (Lambda ts e') es+specialize' (Let          ds e) es = do+  ds' <- mapM specialize ds+  e' <- specialize e+  return $ apply (Let ds' e') es+specialize' (Case      ct e as) es = do+  e' <- specialize e+  as' <- mapM specialize as+  return $ apply (Case ct e' as') es+specialize' e                   _  =+  internalError $ "Dictionary.specialize': " ++ show e++instance Specialize Alt where+  specialize (Alt p t rhs) = Alt p t <$> specialize rhs++-- -----------------------------------------------------------------------------+-- Cleaning up+-- -----------------------------------------------------------------------------++-- After we have transformed the module we have to remove class exports from+-- the export list and type classes from the type constructor environment.+-- Furthermore, we may have to remove some infix declarations and operators+-- from the precedence environment as functions with class constraint have+-- been supplemented with addiontal dictionary arguments during the dictionary+-- transformation.++cleanup :: Module a -> DTM (Module a)+cleanup (Module ps m es is ds) = do+  cleanedEs <- traverse cleanupExportSpec es+  cleanedDs <- concatMapM cleanupInfixDecl ds+  cleanupTyConsEnv+  cleanupPrecEnv+  return $ Module ps m cleanedEs is cleanedDs++cleanupExportSpec :: ExportSpec -> DTM ExportSpec+cleanupExportSpec (Exporting p es) = Exporting p <$> concatMapM cleanupExport es++cleanupExport :: Export -> DTM [Export]+cleanupExport e@(Export             _) = return [e]+cleanupExport e@(ExportTypeWith tc cs) = do+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfo tc tcEnv of+    [TypeClass _ _ _] -> return $ map (Export . qualifyLike tc) cs+    _                 -> return [e]+cleanupExport e                        =+  internalError $ "Dictionary.cleanupExport: " ++ show e++cleanupInfixDecl :: Decl a -> DTM [Decl a]+cleanupInfixDecl (InfixDecl p fix pr ops) = do+  m <- getModuleIdent+  vEnv <- getValueEnv+  let opArity = arrowArity . rawType . flip opType vEnv . qualifyWith m+      ops' = filter ((== 2) . opArity) ops+  return [InfixDecl p fix pr ops' | not (null ops')]+cleanupInfixDecl d                        = return [d]++cleanupTyConsEnv :: DTM ()+cleanupTyConsEnv = getTyConsEnv >>= mapM_ (cleanupTyCons . fst) . allBindings++cleanupTyCons :: QualIdent -> DTM ()+cleanupTyCons tc = do+  tcEnv <- getTyConsEnv+  case qualLookupTypeInfo tc tcEnv of+    [TypeClass _ _ _] -> modifyTyConsEnv $ qualUnbindTopEnv tc+    _                 -> return ()++cleanupPrecEnv :: DTM ()+cleanupPrecEnv = getPrecEnv >>= mapM_ (cleanupOp . fst) . allBindings++cleanupOp :: QualIdent -> DTM ()+cleanupOp op = do+  opArity <- arrowArity . rawType . opType op <$> getValueEnv+  when (opArity /= 2) $ modifyPrecEnv $ qualUnbindTopEnv op++-- -----------------------------------------------------------------------------+-- Transforming interfaces+-- -----------------------------------------------------------------------------++-- The following functions expect an already transformed value environment.+-- The transformation of interface declarations with it is quite simple and+-- straightforward.++dictTransInterfaces :: ValueEnv -> ClassEnv -> InterfaceEnv -> InterfaceEnv+dictTransInterfaces vEnv clsEnv = fmap $ dictTransInterface vEnv clsEnv++dictTransInterface :: ValueEnv -> ClassEnv -> Interface -> Interface+dictTransInterface vEnv clsEnv (Interface m is ds) =+  Interface m is $ concatMap (dictTransIDecl m vEnv clsEnv) ds++dictTransIDecl :: ModuleIdent -> ValueEnv -> ClassEnv -> IDecl -> [IDecl]+dictTransIDecl m vEnv _      d@(IInfixDecl         _ _ _ op)+  | arrowArity (rawType $ opType (qualQualify m op) vEnv) /= 2 = []+  | otherwise = [d]+dictTransIDecl _ _    _      d@(HidingDataDecl      _ _ _ _) = [d]+dictTransIDecl m _    _      (IDataDecl    p tc k tvs cs hs) =+  [IDataDecl p tc k tvs (map (dictTransIConstrDecl m tvs) cs) hs]+dictTransIDecl _ _    _      d@(INewtypeDecl    _ _ _ _ _ _) = [d]+dictTransIDecl _ _    _      d@(ITypeDecl         _ _ _ _ _) = [d]+dictTransIDecl m vEnv _      (IFunctionDecl       _ f _ _ _) =+  [iFunctionDeclFromValue m vEnv (qualQualify m f)]+dictTransIDecl _ _    _      (HidingClassDecl  p _ cls k tv) =+  [HidingDataDecl p (qDictTypeId cls) (fmap (flip ArrowKind Star) k) [tv]]+dictTransIDecl m vEnv clsEnv (IClassDecl   p _ cls k _ _ hs) =+  dictDecl : defaults ++ methodStubs ++ superDictStubs+  where qcls  = qualQualify m cls+        sclss = superClasses qcls clsEnv+        ms    = classMethods qcls clsEnv+        dictDecl    = IDataDecl p (qDictTypeId cls)+                        (fmap (flip ArrowKind Star) k)+                        [head identSupply] [constrDecl] []+        constrDecl  = iConstrDeclFromDataConstructor m vEnv $ qDictConstrId qcls+        defaults    = map (iFunctionDeclFromValue m vEnv .+                            qDefaultMethodId qcls) ms+        methodStubs = map (iFunctionDeclFromValue m vEnv . qualifyLike qcls) $+                        filter (`notElem` hs) ms+        superDictStubs = map (iFunctionDeclFromValue m vEnv .+                               qSuperDictStubId qcls) sclss+dictTransIDecl m vEnv clsEnv (IInstanceDecl _ _ cls ty _ mm) =+  iFunctionDeclFromValue m vEnv (qInstFunId m' qcls ty') :+    map (iFunctionDeclFromValue m vEnv . qImplMethodId m' qcls ty') ms+  where m'   = fromMaybe m mm+        qcls = qualQualify m cls+        ty'  = toQualType m [] ty+        ms   = classMethods qcls clsEnv++dictTransIConstrDecl :: ModuleIdent -> [Ident] -> ConstrDecl -> ConstrDecl+dictTransIConstrDecl m tvs (ConstrDecl     p evs cx c tys) =+  ConstrDecl p evs [] c $ transformIContext m (tvs ++ evs) cx ++ tys+dictTransIConstrDecl m tvs (ConOpDecl p evs cx ty1 op ty2) =+  dictTransIConstrDecl m tvs (ConstrDecl p evs cx op [ty1, ty2])+dictTransIConstrDecl m tvs (RecordDecl      p evs cx c fs) =+  RecordDecl p evs [] c $+    map toFieldDecl (transformIContext m (tvs ++ evs) cx) ++ fs+  where toFieldDecl = FieldDecl NoPos [anonId]++transformIContext :: ModuleIdent -> [Ident] -> Context -> [TypeExpr]+transformIContext m tvs cx =+   map (fromQualType m tvs . dictType) (Set.toAscList $ toQualPredSet m tvs cx)++iFunctionDeclFromValue :: ModuleIdent -> ValueEnv -> QualIdent -> IDecl+iFunctionDeclFromValue m vEnv f = case qualLookupValue f vEnv of+  [Value _ _ a (ForAll _ pty)] ->+    IFunctionDecl NoPos (qualUnqualify m f) Nothing a $+      fromQualPredType m identSupply pty+  _ -> internalError $ "Dictionary.iFunctionDeclFromValue: " ++ show f++iConstrDeclFromDataConstructor :: ModuleIdent -> ValueEnv -> QualIdent+                               -> ConstrDecl+iConstrDeclFromDataConstructor m vEnv c = case qualLookupValue c vEnv of+  [DataConstructor _ _ _ (ForAllExist n n' pty)] ->+    ConstrDecl NoPos evs [] (unqualify c) tys+    where evs = take n' $ drop n identSupply+          tys = map (fromQualType m identSupply) $ arrowArgs $ unpredType pty+  _ -> internalError $ "Dictionary.iConstrDeclFromDataConstructor: " ++ show c++-- -----------------------------------------------------------------------------+-- Functions for naming newly created types, functions and parameters+-- -----------------------------------------------------------------------------++dictTypeId :: QualIdent -> Ident+dictTypeId cls = mkIdent $ "_Dict#" ++ idName (unqualify cls)++qDictTypeId :: QualIdent -> QualIdent+qDictTypeId cls = qualifyLike cls $ dictTypeId cls++dictConstrId :: QualIdent -> Ident+dictConstrId = dictTypeId++qDictConstrId :: QualIdent -> QualIdent+qDictConstrId cls = qualifyLike cls $ dictConstrId cls++defaultMethodId :: QualIdent -> Ident -> Ident+defaultMethodId cls f = mkIdent $ "_def#" ++ idName f ++ '#' : qualName cls++qDefaultMethodId :: QualIdent -> Ident -> QualIdent+qDefaultMethodId cls = qualifyLike cls . defaultMethodId cls++superDictStubId :: QualIdent -> QualIdent -> Ident+superDictStubId cls scls = mkIdent $+  "_super#" ++ qualName cls ++ '#' : qualName scls++qSuperDictStubId :: QualIdent -> QualIdent -> QualIdent+qSuperDictStubId cls = qualifyLike cls . superDictStubId cls++instFunId :: QualIdent -> Type -> Ident+instFunId cls ty = mkIdent $+  "_inst#" ++ qualName cls ++ '#' : qualName (rootOfType ty)++qInstFunId :: ModuleIdent -> QualIdent -> Type -> QualIdent+qInstFunId m cls = qualifyWith m . instFunId cls++implMethodId :: QualIdent -> Type -> Ident -> Ident+implMethodId cls ty f = mkIdent $+  "_impl#" ++ idName f ++ '#' : qualName cls ++ '#' : qualName (rootOfType ty)++qImplMethodId :: ModuleIdent -> QualIdent -> Type -> Ident -> QualIdent+qImplMethodId m cls ty = qualifyWith m . implMethodId cls ty++-- -----------------------------------------------------------------------------+-- Generating variables+-- -----------------------------------------------------------------------------++freshVar :: String -> Type -> DTM (Type, Ident)+freshVar name ty = ((,) ty) . mkIdent . (name ++) .  show <$> getNextId++-- -----------------------------------------------------------------------------+-- Auxiliary functions+-- -----------------------------------------------------------------------------++-- The function 'dictType' returns the type of the dictionary corresponding to+-- a particular C-T instance.++dictType :: Pred -> Type+dictType (Pred cls ty) = TypeApply (TypeConstructor $ qDictTypeId cls) ty++-- The function 'transformPredType' replaces each predicate with a new+-- dictionary type argument.++transformPredType :: PredType -> Type+transformPredType (PredType ps ty) =+  foldr (TypeArrow . dictType) ty $ Set.toList ps++-- The function 'transformMethodPredType' first deletes the implicit class+-- constraint and then transforms the resulting predicated type as above.++transformMethodPredType :: PredType -> Type+transformMethodPredType (PredType ps ty) =+  transformPredType $ PredType (Set.deleteMin ps) ty++-- The function 'generalizeMethodType' generalizes an already transformed+-- method type to a forall type by quantifying all occuring type variables+-- except for the class variable whose index is 0.+generalizeMethodType :: Type -> Type+generalizeMethodType ty+  | null tvs  = ty+  | otherwise = TypeForall tvs ty+  where tvs = nub $ filter (/= 0) $ typeVars ty++instTypeVar :: Int -> Int+instTypeVar tv = -1 - tv++instType :: Type -> Type+instType (TypeConstructor tc) = TypeConstructor tc+instType (TypeVariable    tv) = TypeVariable (instTypeVar tv)+instType (TypeApply  ty1 ty2) = TypeApply (instType ty1) (instType ty2)+instType (TypeArrow  ty1 ty2) = TypeArrow (instType ty1) (instType ty2)+instType (TypeForall  tvs ty) = TypeForall (map instTypeVar tvs) (instType ty)+instType ty = ty++instPred :: Pred -> Pred+instPred (Pred cls ty) = Pred cls (instType ty)++unRenameIdentIf :: Bool -> Ident -> Ident+unRenameIdentIf b = if b then unRenameIdent else id++-- The string for the error message for a class method's default method+-- implementation has to be constructed in its desugared form since the+-- desugaring has already taken place.++preludeError :: Type -> String -> Expression PredType+preludeError a =+  Apply (Variable (predType (TypeArrow stringType a)) qErrorId) . stringExpr++stringExpr :: String -> Expression PredType+stringExpr = foldr (consExpr . Literal (predType charType) . Char) nilExpr+  where+  nilExpr = Constructor (predType stringType) qNilId+  consExpr = Apply . Apply (Constructor (predType $ consType charType) qConsId)++-- The function 'varType' is able to lookup both local and global identifiers.+-- Since the environments have been qualified before, global declarations are+-- only visible under their original name whereas local declarations are always+-- entered unqualified.++varType :: ModuleIdent -> Ident -> ValueEnv -> TypeScheme+varType m v vEnv = case qualLookupValue (qualify v) vEnv of+  Value _ _ _ tySc : _ -> tySc+  Label _ _   tySc : _ -> tySc+  _ -> case qualLookupValue (qualifyWith m v) vEnv of+    Value _ _ _ tySc : _ -> tySc+    Label _ _   tySc : _ -> tySc+    _ -> internalError $ "Dictionary.varType: " ++ show v++conType :: QualIdent -> ValueEnv -> TypeScheme+conType c vEnv = case qualLookupValue c vEnv of+  [DataConstructor  _ _ _ (ForAllExist n _ pty)] -> ForAll n pty+  [NewtypeConstructor _ _ (ForAllExist n _ pty)] -> ForAll n pty+  _ -> internalError $ "Dictionary.conType: " ++ show c++funType :: QualIdent -> ValueEnv -> TypeScheme+funType f vEnv = case qualLookupValue f vEnv of+  [Value _ _ _ tySc] -> tySc+  [Label _ _   tySc] -> tySc+  _ -> internalError $ "Dictionary.funType " ++ show f++opType :: QualIdent -> ValueEnv -> TypeScheme+opType op vEnv = case qualLookupValue op vEnv of+  [DataConstructor  _ _ _ (ForAllExist n _ pty)] -> ForAll n pty+  [NewtypeConstructor _ _ (ForAllExist n _ pty)] -> ForAll n pty+  [Value _ _ _                             tySc] -> tySc+  [Label _ _                               tySc] -> tySc+  _ -> internalError $ "Dictionary.opType " ++ show op
+ src/Transformations/Lift.hs view
@@ -0,0 +1,443 @@+{- |+    Module      :  $Header$+    Description :  Lifting of lambda-expressions and local functions+    Copyright   :  (c) 2001 - 2003 Wolfgang Lux+                       2011 - 2015 Björn Peemöller+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   After desugaring and simplifying the code, the compiler lifts all local+   function declarations to the top-level keeping only local variable+   declarations. The algorithm used here is similar to Johnsson's, consisting+   of two phases. First, we abstract each local function declaration,+   adding its free variables as initial parameters and update all calls+   to take these variables into account. Second, all local function+   declarations are collected and lifted to the top-level.+-}+{-# LANGUAGE CPP #-}+module Transformations.Lift (lift) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import           Control.Arrow              (first)+import qualified Control.Monad.State as S   (State, runState, gets, modify)+import           Data.List+import qualified Data.Map            as Map (Map, empty, insert, lookup)+import           Data.Maybe                 (catMaybes, fromJust)+import qualified Data.Set            as Set (fromList, toList, unions)+import Curry.Base.Ident+import Curry.Syntax++import Base.AnnotExpr+import Base.Expr+import Base.Messages                        (internalError)+import Base.SCC+import Base.Types+import Base.TypeSubst+import Base.Typing+import Base.Utils++import Env.Value++lift :: ValueEnv -> Module Type -> (Module Type, ValueEnv)+lift vEnv (Module ps m es is ds) = (lifted, valueEnv s')+  where+  (ds', s') = S.runState (mapM (absDecl "" []) ds) initState+  initState = LiftState m vEnv Map.empty+  lifted    = Module ps m es is $ concatMap liftFunDecl ds'++-- -----------------------------------------------------------------------------+-- Abstraction+-- -----------------------------------------------------------------------------++-- Besides adding the free variables to every (local) function, the+-- abstraction pass also has to update the type environment in order to+-- reflect the new types of the abstracted functions. As usual, we use a+-- state monad transformer in order to pass the type environment+-- through. The environment constructed in the abstraction phase maps+-- each local function declaration onto its replacement expression,+-- i.e. the function applied to its free variables. In order to generate+-- correct type annotations for an inserted replacement expression, we also+-- save a function's original type. The original type is later unified with+-- the concrete type of the replaced expression to obtain a type substitution+-- which is then applied to the replacement expression.++type AbstractEnv = Map.Map Ident (Expression Type, Type)++data LiftState = LiftState+  { moduleIdent :: ModuleIdent+  , valueEnv    :: ValueEnv+  , abstractEnv :: AbstractEnv+  }++type LiftM a = S.State LiftState a++getModuleIdent :: LiftM ModuleIdent+getModuleIdent = S.gets moduleIdent++getValueEnv :: LiftM ValueEnv+getValueEnv = S.gets valueEnv++modifyValueEnv :: (ValueEnv -> ValueEnv) -> LiftM ()+modifyValueEnv f = S.modify $ \s -> s { valueEnv = f $ valueEnv s }++getAbstractEnv :: LiftM AbstractEnv+getAbstractEnv = S.gets abstractEnv++withLocalAbstractEnv :: AbstractEnv -> LiftM a -> LiftM a+withLocalAbstractEnv ae act = do+  old <- getAbstractEnv+  S.modify $ \s -> s { abstractEnv = ae }+  res <- act+  S.modify $ \s -> s { abstractEnv = old }+  return res++absDecl :: String -> [Ident] -> Decl Type -> LiftM (Decl Type)+absDecl _   lvs (FunctionDecl p ty f eqs) = FunctionDecl p ty f+                                            <$> mapM (absEquation lvs) eqs+absDecl pre lvs (PatternDecl     p t rhs) = PatternDecl p t+                                            <$> absRhs pre lvs rhs+absDecl _   _   d                         = return d++absEquation :: [Ident] -> Equation Type -> LiftM (Equation Type)+absEquation lvs (Equation p lhs@(FunLhs f ts) rhs) =+  Equation p lhs <$> absRhs (idName f ++ ".") lvs' rhs+  where lvs' = lvs ++ bv ts+absEquation _ _ = error "Lift.absEquation: no pattern match"++absRhs :: String -> [Ident] -> Rhs Type -> LiftM (Rhs Type)+absRhs pre lvs (SimpleRhs p e _) = simpleRhs p <$> absExpr pre lvs e+absRhs _   _   _                 = error "Lift.absRhs: no simple RHS"++-- Within a declaration group we have to split the list of declarations+-- into the function and value declarations. Only the function+-- declarations are affected by the abstraction algorithm; the value+-- declarations are left unchanged except for abstracting their right+-- hand sides.++-- The abstraction of a recursive declaration group is complicated by the+-- fact that not all functions need to call each in a recursive+-- declaration group. E.g., in the following example neither 'g' nor 'h'+-- call each other.+--+--   f = g True+--     where x = h 1+--           h z = y + z+--           y = g False+--           g z = if z then x else 0+--+-- Because of this fact, 'g' and 'h' can be abstracted separately by adding+-- only 'y' to 'h' and 'x' to 'g'. On the other hand, in the following example+--+--   f x y = g 4+--     where g p = h p + x+--           h q = k + y + q+--           k = g x+--+-- the local function 'g' uses 'h', so the free variables+-- of 'h' have to be added to 'g' as well. However, because+-- 'h' does not call 'g' it is sufficient to add only+-- 'k' and 'y' (and not 'x') to its definition. We handle this by computing+-- the dependency graph between the functions and splitting this graph into+-- its strongly connected components. Each component is then processed+-- separately, adding the free variables in the group to its functions.++-- We have to be careful with local declarations within desugared case+-- expressions. If some of the cases have guards, e.g.,+--+--   case e of+--     x | x < 1 -> 1+--     x -> let double y = y * y in double x+--+-- the desugarer at present may duplicate code. While there is no problem+-- with local variable declaration being duplicated, we must avoid to+-- lift local function declarations more than once. Therefore+-- 'absFunDecls' transforms only those function declarations+-- that have not been lifted and discards the other declarations. Note+-- that it is easy to check whether a function has been lifted by+-- checking whether an entry for its transformed name is present+-- in the value environment.++absDeclGroup :: String -> [Ident] -> [Decl Type] -> Expression Type+             -> LiftM (Expression Type)+absDeclGroup pre lvs ds e = do+  m <- getModuleIdent+  absFunDecls pre lvs' (scc bv (qfv m) fds) vds e+  where lvs' = lvs ++ bv vds+        (fds, vds) = partition isFunDecl ds++absFunDecls :: String -> [Ident] -> [[Decl Type]] -> [Decl Type]+            -> Expression Type -> LiftM (Expression Type)+absFunDecls pre lvs []         vds e = do+  vds' <- mapM (absDecl pre lvs) vds+  e' <- absExpr pre lvs e+  return (Let vds' e')+absFunDecls pre lvs (fds:fdss) vds e = do+  m <- getModuleIdent+  env <- getAbstractEnv+  vEnv <- getValueEnv+  let -- defined functions+      fs      = bv fds+      -- function types+      ftys    = map extractFty fds+      extractFty (FunctionDecl _ _ f ((Equation _ (FunLhs _ ts) rhs):_)) =+        (f, foldr TypeArrow (typeOf rhs) $ map typeOf ts)+      extractFty _                                                       =+        internalError "Lift.absFunDecls.extractFty"+      -- typed free variables on the right-hand sides+      fvsRhs  = Set.unions+                  [ Set.fromList (filter (not . isDummyType . fst)+                                         (maybe [(ty, v)]+                                                (qafv' ty)+                                                (Map.lookup v env)))+                  | (ty, v) <- concatMap (qafv m) fds ]+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+      -- !!! HACK: When calculating the typed free variables on the     !!!+      -- !!! right-hand side, we have to filter out the ones annotated  !!!+      -- !!! with dummy types (see below). Additionally, we have to be  !!!+      -- !!! careful when we calculate the typed free variables in a    !!!+      -- !!! replacement expression: We have to unify the original      !!!+      -- !!! function type with the instantiated function type in order !!!+      -- !!! to obtain a type substitution that can then be applied to  !!!+      -- !!! the typed free variables in the replacement expression.    !!!+      -- !!! This is analogous to the procedure when inserting a        !!!+      -- !!! replacement expression with a correct type annotation      !!!+      -- !!! (see 'absType' in 'absExpr' below).                        !!!+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+      qafv' ty (re, fty) =+        let unifier = matchType fty ty idSubst+        in  map (\(ty', v) -> (subst unifier ty', v)) $ qafv m re+      -- free variables that are local+      fvs     = filter ((`elem` lvs) . snd) (Set.toList fvsRhs)+      -- extended abstraction environment+      env'    = foldr bindF env fs+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+      -- !!! HACK: Since we do not know how to annotate the function    !!!+      -- !!! call within the replacement expression until the replace-  !!!                          !!!+      -- !!! ment expression is actually inserted (see 'absType' in     !!!+      -- !!! 'absExpr' below), we use a dummy type for this. In turn,   !!!+      -- !!! this dummy type has to be filtered out when calculating    !!!+      -- !!! the typed free variables on right-hand sides (see above).  !!!                                             !!!+      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+      bindF f =+        Map.insert f ( apply (mkFun m pre dummyType f) (map (uncurry mkVar) fvs)+                     , fromJust $ lookup f ftys )+      -- newly abstracted functions+      fs'     = filter (\f -> null $ lookupValue (liftIdent pre f) vEnv) fs+  withLocalAbstractEnv env' $ do+    -- add variables to functions+    fds' <- mapM (absFunDecl pre fvs lvs) [d | d <- fds, any (`elem` fs') (bv d)]+    -- abstract remaining declarations+    e'   <- absFunDecls pre lvs fdss vds e+    return (Let fds' e')++-- When the free variables of a function are abstracted, the type of the+-- function must be changed as well.++absFunDecl :: String -> [(Type, Ident)] -> [Ident] -> Decl Type+           -> LiftM (Decl Type)+absFunDecl pre fvs lvs (FunctionDecl p _ f eqs) = do+  m <- getModuleIdent+  FunctionDecl _ _ _ eqs'' <- absDecl pre lvs $ FunctionDecl p undefined f' eqs'+  modifyValueEnv $ bindGlobalInfo+    (\qf tySc -> Value qf False (eqnArity $ head eqs') tySc) m f' $ polyType ty''+  return $ FunctionDecl p ty'' f' eqs''+  where f' = liftIdent pre f+        ty' = foldr TypeArrow (typeOf rhs') (map typeOf ts')+          where Equation _ (FunLhs _ ts') rhs' = head eqs'+        ty'' = genType ty'+        eqs' = map addVars eqs+        genType ty''' = subst (foldr2 bindSubst idSubst tvs tvs') ty'''+          where tvs = nub (typeVars ty''')+                tvs' = map TypeVariable [0 ..]+        addVars (Equation p' (FunLhs _ ts) rhs) =+          Equation p' (FunLhs f' (map (uncurry VariablePattern) fvs ++ ts)) rhs+        addVars _ = error "Lift.absFunDecl.addVars: no pattern match"+absFunDecl pre _ _ (ExternalDecl p vs) = ExternalDecl p <$> mapM (absVar pre) vs+absFunDecl _ _ _ _ = error "Lift.absFunDecl: no pattern match"++absVar :: String -> Var Type -> LiftM (Var Type)+absVar pre (Var ty f) = do+  m <- getModuleIdent+  modifyValueEnv $ bindGlobalInfo+    (\qf tySc -> Value qf False (arrowArity ty) tySc) m f' $ polyType ty+  return $ Var ty f'+  where f' = liftIdent pre f++absExpr :: String -> [Ident] -> Expression Type -> LiftM (Expression Type)+absExpr _   _   l@(Literal     _ _) = return l+absExpr pre lvs var@(Variable ty v)+  | isQualified v = return var+  | otherwise     = do+    getAbstractEnv >>= \env -> case Map.lookup (unqualify v) env of+      Nothing       -> return var+      Just (e, fty) -> let unifier = matchType fty ty idSubst+                       in  absExpr pre lvs $ fmap (subst unifier) $ absType ty e+  where -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+        -- !!! HACK: When inserting the replacement expression for an     !!!+        -- !!! abstracted function, we have to unify the original         !!!+        -- !!! function type with the instantiated function type in order !!!+        -- !!! to obtain a type substitution that can then be applied to  !!!+        -- !!! the type annotations in the replacement expression.        !!!+        -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!+        absType ty' (Variable _ v') = Variable ty' v'+        absType ty' (Apply   e1 e2) =+          Apply (absType (TypeArrow (typeOf e2) ty') e1) e2+        absType _ _ = internalError "Lift.absExpr.absType"+absExpr _   _   c@(Constructor _ _) = return c+absExpr pre lvs (Apply       e1 e2) = Apply         <$> absExpr pre lvs e1+                                                    <*> absExpr pre lvs e2+absExpr pre lvs (Let          ds e) = absDeclGroup pre lvs ds e+absExpr pre lvs (Case      ct e bs) = Case ct       <$> absExpr pre lvs e+                                                    <*> mapM (absAlt pre lvs) bs+absExpr pre lvs (Typed        e ty) = flip Typed ty <$> absExpr pre lvs e+absExpr _   _   e                   = internalError $ "Lift.absExpr: " ++ show e++absAlt :: String -> [Ident] -> Alt Type -> LiftM (Alt Type)+absAlt pre lvs (Alt p t rhs) = Alt p t <$> absRhs pre lvs' rhs+  where lvs' = lvs ++ bv t++-- -----------------------------------------------------------------------------+-- Lifting+-- -----------------------------------------------------------------------------++-- After the abstraction pass, all local function declarations are lifted+-- to the top-level.++liftFunDecl :: Eq a => Decl a -> [Decl a]+liftFunDecl (FunctionDecl p a f eqs) =+  FunctionDecl p a f eqs' : map renameFunDecl (concat dss')+  where (eqs', dss') = unzip $ map liftEquation eqs+liftFunDecl d                        = [d]++liftVarDecl :: Eq a => Decl a -> (Decl a, [Decl a])+liftVarDecl (PatternDecl   p t rhs) = (PatternDecl p t rhs', ds')+  where (rhs', ds') = liftRhs rhs+liftVarDecl ex@(FreeDecl       _ _) = (ex, [])+liftVarDecl _ = error "Lift.liftVarDecl: no pattern match"++liftEquation :: Eq a => Equation a -> (Equation a, [Decl a])+liftEquation (Equation p lhs rhs) = (Equation p lhs rhs', ds')+  where (rhs', ds') = liftRhs rhs++liftRhs :: Eq a => Rhs a -> (Rhs a, [Decl a])+liftRhs (SimpleRhs p e _) = first (simpleRhs p) (liftExpr e)+liftRhs _                 = error "Lift.liftRhs: no pattern match"++liftDeclGroup :: Eq a => [Decl a] -> ([Decl a], [Decl a])+liftDeclGroup ds = (vds', concat (map liftFunDecl fds ++ dss'))+  where (fds , vds ) = partition isFunDecl ds+        (vds', dss') = unzip $ map liftVarDecl vds++liftExpr :: Eq a => Expression a -> (Expression a, [Decl a])+liftExpr l@(Literal     _ _) = (l, [])+liftExpr v@(Variable    _ _) = (v, [])+liftExpr c@(Constructor _ _) = (c, [])+liftExpr (Apply       e1 e2) = (Apply e1' e2', ds1 ++ ds2)+  where (e1', ds1) = liftExpr e1+        (e2', ds2) = liftExpr e2+liftExpr (Let          ds e) = (mkLet ds' e', ds1 ++ ds2)+  where (ds', ds1) = liftDeclGroup ds+        (e' , ds2) = liftExpr e+liftExpr (Case    ct e alts) = (Case ct e' alts', concat $ ds' : dss')+  where (e'   , ds' ) = liftExpr e+        (alts', dss') = unzip $ map liftAlt alts+liftExpr (Typed        e ty) = (Typed e' ty, ds) where (e', ds) = liftExpr e+liftExpr _ = internalError "Lift.liftExpr"++liftAlt :: Eq a => Alt a -> (Alt a, [Decl a])+liftAlt (Alt p t rhs) = (Alt p t rhs', ds') where (rhs', ds') = liftRhs rhs++-- -----------------------------------------------------------------------------+-- Renaming+-- -----------------------------------------------------------------------------++-- After all local function declarations have been lifted to top-level, we+-- may have to rename duplicate function arguments. Due to polymorphic let+-- declarations it could happen that an argument was added multiple times+-- instantiated with different types during the abstraction pass beforehand.++type RenameMap a = [((a, Ident), Ident)]++renameFunDecl :: Eq a => Decl a -> Decl a+renameFunDecl (FunctionDecl p a f eqs) =+  FunctionDecl p a f (map renameEquation eqs)+renameFunDecl d                        = d++renameEquation :: Eq a => Equation a -> Equation a+renameEquation (Equation p lhs rhs) = Equation p lhs' (renameRhs rm rhs)+  where (rm, lhs') = renameLhs lhs++renameLhs :: Eq a => Lhs a -> (RenameMap a, Lhs a)+renameLhs (FunLhs f ts) = (rm, FunLhs f ts')+  where (rm, ts') = foldr renamePattern ([], []) ts+renameLhs _             = error "Lift.renameLhs"++renamePattern :: Eq a => Pattern a -> (RenameMap a, [Pattern a])+              -> (RenameMap a, [Pattern a])+renamePattern (VariablePattern a v) (rm, ts)+  | v `elem` varPatNames ts =+    let v' = updIdentName (++ ("." ++ show (length rm))) v+    in  (((a, v), v') : rm, VariablePattern a v' : ts)+renamePattern t                     (rm, ts) = (rm, t : ts)++renameRhs :: Eq a => RenameMap a -> Rhs a -> Rhs a+renameRhs rm (SimpleRhs p e _) = simpleRhs p (renameExpr rm e)+renameRhs _  _                 = error "Lift.renameRhs"++renameExpr :: Eq a => RenameMap a -> Expression a -> Expression a+renameExpr _  l@(Literal     _ _) = l+renameExpr rm v@(Variable   a v')+  | isQualified v' = v+  | otherwise      = case lookup (a, unqualify v') rm of+                       Just v'' -> Variable a (qualify v'')+                       _        -> v+renameExpr _  c@(Constructor _ _) = c+renameExpr rm (Typed        e ty) = Typed (renameExpr rm e) ty+renameExpr rm (Apply       e1 e2) = Apply (renameExpr rm e1) (renameExpr rm e2)+renameExpr rm (Let          ds e) =+  Let (map (renameDecl rm) ds) (renameExpr rm e)+renameExpr rm (Case    ct e alts) =+  Case ct (renameExpr rm e) (map (renameAlt rm) alts)+renameExpr _  _                   = error "Lift.renameExpr"++renameDecl :: Eq a => RenameMap a -> Decl a -> Decl a+renameDecl rm (PatternDecl p t rhs) = PatternDecl p t (renameRhs rm rhs)+renameDecl _  d                     = d++renameAlt :: Eq a => RenameMap a -> Alt a -> Alt a+renameAlt rm (Alt p t rhs) = Alt p t (renameRhs rm rhs)++-- ---------------------------------------------------------------------------+-- Auxiliary definitions+-- ---------------------------------------------------------------------------++isFunDecl :: Decl a -> Bool+isFunDecl (FunctionDecl _ _ _ _) = True+isFunDecl (ExternalDecl _ _    ) = True+isFunDecl _                      = False++mkFun :: ModuleIdent -> String -> a -> Ident -> Expression a+mkFun m pre a = Variable a . qualifyWith m . liftIdent pre++liftIdent :: String -> Ident -> Ident+liftIdent prefix x = renameIdent (mkIdent $ prefix ++ showIdent x) $ idUnique x++varPatNames :: [Pattern a] -> [Ident]+varPatNames = catMaybes . map varPatName++varPatName :: Pattern a -> Maybe Ident+varPatName (VariablePattern _ i) = Just i+varPatName _                     = Nothing++dummyType :: Type+dummyType = TypeForall [] undefined++isDummyType :: Type -> Bool+isDummyType (TypeForall [] _) = True+isDummyType _                 = False
+ src/Transformations/Newtypes.hs view
@@ -0,0 +1,111 @@+{- |+  Module      :  $Header$+  Description :  Removing newtype constructors+  Copyright   :  (c) 2017        Finn Teegen+  License     :  BSD-3-clause++  Maintainer  :  fte@informatik.uni-kiel.de+  Stability   :  experimental+  Portability :  portable++  After inserting dictionaries, the compiler removes all occurences of+  newtype declarations. Applications 'N x' in patterns and expressions,+  where 'N' is a newtype constructor, are replaced by a 'x'. The newtype+  declarations are replaced by type synonyms and partial applications of+  newtype constructors are changed into calls to 'Prelude.id'.+-}+{-# LANGUAGE CPP #-}+module Transformations.Newtypes (removeNewtypes) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import qualified Control.Monad.Reader as R++import Curry.Base.Ident+import Curry.Syntax++import Base.Messages (internalError)+import Base.Types++import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++removeNewtypes :: ValueEnv -> Module Type -> Module Type+removeNewtypes vEnv mdl = R.runReader (nt mdl) vEnv++type NTM a = R.Reader ValueEnv a++class Show a => Newtypes a where+  nt :: a -> NTM a++instance Newtypes a => Newtypes [a] where+  nt = mapM nt++instance Show a => Newtypes (Module a) where+  nt (Module ps m es is ds) = Module ps m es is <$> mapM nt ds++instance Show a => Newtypes (Decl a) where+  nt d@(InfixDecl       _ _ _ _) = return d+  nt d@(DataDecl      _ _ _ _ _) = return d+  nt d@(ExternalDataDecl  _ _ _) = return d+  nt (NewtypeDecl p tc vs nc []) = return $ TypeDecl p tc vs $ nconstrType nc+  nt d@(TypeDecl        _ _ _ _) = return d+  nt (FunctionDecl    p a f eqs) = FunctionDecl p a f <$> nt eqs+  nt d@(ExternalDecl        _ _) = return d+  nt (PatternDecl       p t rhs) = PatternDecl p <$> nt t <*> nt rhs+  nt d@(FreeDecl            _ _) = return d+  nt d                           = internalError $+    "Newtypes.Newtypes.nt: unexpected declaration: " ++ show d++instance Show a => Newtypes (Equation a) where+  nt (Equation p lhs rhs) = Equation p <$> nt lhs <*> nt rhs++instance Show a => Newtypes (Lhs a) where+  nt (FunLhs f ts) = FunLhs f <$> nt ts+  nt lhs           = internalError $+    "Newtypes.Newtypes.nt: unexpected left-hand-side: " ++ show lhs++instance Show a => Newtypes (Rhs a) where+  nt (SimpleRhs p e []) = flip (SimpleRhs p) [] <$> nt e+  nt rhs                = internalError $+    "Newtypes.Newtypes.nt: unexpected right-hand-side: " ++ show rhs++instance Show a => Newtypes (Pattern a) where+  nt t@(LiteralPattern      _ _) = return t+  nt t@(VariablePattern     _ _) = return t+  nt (ConstructorPattern a c ts) = case ts of+    [t] -> do+      isNc <- isNewtypeConstr c+      if isNc then nt t+              else ConstructorPattern a c <$> ((: []) <$> nt t)+    _   -> ConstructorPattern a c <$> mapM nt ts+  nt (AsPattern             v t) = AsPattern v <$> nt t+  nt t                      = internalError $+    "Newtypes.Newtypes.nt: unexpected pattern: " ++ show t++instance Show a => Newtypes (Expression a) where+  nt e@(Literal   _ _) = return e+  nt e@(Variable  _ _) = return e+  nt (Constructor a c) = do+    isNc <- isNewtypeConstr c+    return $ if isNc then Variable a qIdId else Constructor a c+  nt (Apply     e1 e2) = case e1 of+    Constructor _ c -> do+      isNc <- isNewtypeConstr c+      if isNc then nt e2 else Apply <$> nt e1 <*> nt e2+    _ -> Apply <$> nt e1 <*> nt e2+  nt (Case    ct e as) = Case ct <$> nt e <*> mapM nt as+  nt (Let        ds e) = Let <$> nt ds <*> nt e+  nt (Typed     e qty) = flip Typed qty <$> nt e+  nt e                 = internalError $+    "Newtypes.Newtypes.nt: unexpected expression: " ++ show e++instance Show a => Newtypes (Alt a) where+  nt (Alt p t rhs) = Alt p <$> nt t <*> nt rhs++isNewtypeConstr :: QualIdent -> NTM Bool+isNewtypeConstr c = R.ask >>= \vEnv -> return $+  case qualLookupValue c vEnv of+    [NewtypeConstructor _ _ _] -> True+    [DataConstructor  _ _ _ _] -> False+    _ -> internalError $ "Newtypes.isNewtypeConstr: " ++ show c
+ src/Transformations/Qual.hs view
@@ -0,0 +1,238 @@+{- |+    Module      :  $Header$+    Description :  Proper Qualification+    Copyright   :  (c) 2001 - 2004 Wolfgang Lux+                       2005        Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2016 - 2017 Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++    After checking the module and before starting the translation into the+    intermediate language, the compiler properly qualifies all type+    constructors, data constructors and (global) functions+    occurring in a pattern or expression such that their module prefix+    matches the module of their definition.+    This is done also for functions and constructors declared+    in the current module.+    Only functions and variables declared in local declarations groups+    as well as function arguments remain unchanged.+-}+{-# LANGUAGE CPP #-}+module Transformations.Qual (qual) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative       ((<$>), (<*>), pure)+#endif+import qualified Control.Monad.Reader as R (Reader, asks, runReader)+import           Data.Traversable+import           Prelude hiding            (mapM)++import Curry.Base.Ident+import Curry.Syntax++import Base.TopEnv         (origName)++import Env.TypeConstructor (TCEnv   , qualLookupTypeInfo)+import Env.Value           (ValueEnv, qualLookupValue)++data QualEnv = QualEnv+  { moduleIdent :: ModuleIdent+  , tyConsEnv   :: TCEnv+  , valueEnv    :: ValueEnv+  }++type Qual a = a -> R.Reader QualEnv a++qual :: ModuleIdent -> TCEnv -> ValueEnv -> Module a -> Module a+qual m tcEnv tyEnv mdl = R.runReader (qModule mdl) (QualEnv m tcEnv tyEnv)++qModule :: Qual (Module a)+qModule (Module ps m es is ds) = do+  es' <- qExportSpec es+  ds' <- mapM qDecl  ds+  return (Module ps m es' is ds')++qExportSpec :: Qual (Maybe ExportSpec)+qExportSpec Nothing                 = return Nothing+qExportSpec (Just (Exporting p es)) = (Just . Exporting p) <$> mapM qExport es++qExport :: Qual Export+qExport (Export            x) = Export <$> qIdent x+qExport (ExportTypeWith t cs) = flip ExportTypeWith cs <$> qConstr t+qExport (ExportTypeAll     t) = ExportTypeAll <$> qConstr t+qExport m@(ExportModule    _) = return m++qDecl :: Qual (Decl a)+qDecl i@(InfixDecl          _ _ _ _) = return i+qDecl (DataDecl      p n vs cs clss) = DataDecl p n vs <$>+  mapM qConstrDecl cs <*> mapM qClass clss+qDecl e@(ExternalDataDecl     _ _ _) = return e+qDecl (NewtypeDecl   p n vs nc clss) = NewtypeDecl p n vs <$>+  qNewConstrDecl nc <*> mapM qClass clss+qDecl (TypeDecl           p n vs ty) = TypeDecl p n vs <$> qTypeExpr ty+qDecl (TypeSig             p fs qty) = TypeSig p fs <$> qQualTypeExpr qty+qDecl (FunctionDecl       a p f eqs) = FunctionDecl a p f <$> mapM qEquation eqs+qDecl e@(ExternalDecl           _ _) = return e+qDecl (PatternDecl          p t rhs) = PatternDecl p <$> qPattern t <*> qRhs rhs+qDecl vs@(FreeDecl              _ _) = return vs+qDecl (DefaultDecl            p tys) = DefaultDecl p <$> mapM qTypeExpr tys+qDecl (ClassDecl     p cx cls tv ds) = ClassDecl p <$>+  qContext cx <*> pure cls <*> pure tv <*> mapM qDecl ds+qDecl (InstanceDecl p cx qcls ty ds) = InstanceDecl p <$>+  qContext cx <*> qClass qcls <*> qTypeExpr ty <*> mapM qDecl ds++qConstrDecl :: Qual ConstrDecl+qConstrDecl (ConstrDecl p vs cx      n tys) =+  flip (ConstrDecl p vs) n <$> qContext cx <*> mapM qTypeExpr tys+qConstrDecl (ConOpDecl  p vs cx ty1 op ty2) =+  ConOpDecl p vs <$> qContext cx <*> qTypeExpr ty1 <*> pure op <*> qTypeExpr ty2+qConstrDecl (RecordDecl p vs cx       c fs) =+  flip (RecordDecl p vs) c <$> qContext cx <*> mapM qFieldDecl fs++qNewConstrDecl :: Qual NewConstrDecl+qNewConstrDecl (NewConstrDecl p n ty)+  = NewConstrDecl p n <$> qTypeExpr ty+qNewConstrDecl (NewRecordDecl p n (f, ty))+  = (\ty' -> NewRecordDecl p n (f, ty')) <$> qTypeExpr ty++qFieldDecl :: Qual FieldDecl+qFieldDecl (FieldDecl p fs ty) = FieldDecl p fs <$> qTypeExpr ty++qConstraint :: Qual Constraint+qConstraint (Constraint cls ty) = Constraint <$> qClass cls <*> qTypeExpr ty++qContext :: Qual Context+qContext = mapM qConstraint++qTypeExpr :: Qual TypeExpr+qTypeExpr (ConstructorType     c) = ConstructorType <$> qConstr c+qTypeExpr (ApplyType     ty1 ty2) = ApplyType <$> qTypeExpr ty1+                                              <*> qTypeExpr ty2+qTypeExpr v@(VariableType      _) = return v+qTypeExpr (TupleType         tys) = TupleType <$> mapM qTypeExpr tys+qTypeExpr (ListType           ty) = ListType  <$> qTypeExpr ty+qTypeExpr (ArrowType     ty1 ty2) = ArrowType <$> qTypeExpr ty1+                                              <*> qTypeExpr ty2+qTypeExpr (ParenType          ty) = ParenType <$> qTypeExpr ty+qTypeExpr (ForallType      vs ty) = ForallType vs <$> qTypeExpr ty++qQualTypeExpr :: Qual QualTypeExpr+qQualTypeExpr (QualTypeExpr cx ty) = QualTypeExpr <$> qContext cx+                                                  <*> qTypeExpr ty++qEquation :: Qual (Equation a)+qEquation (Equation p lhs rhs) = Equation p <$> qLhs lhs <*> qRhs rhs++qLhs :: Qual (Lhs a)+qLhs (FunLhs    f ts) = FunLhs f      <$> mapM qPattern ts+qLhs (OpLhs t1 op t2) = flip OpLhs op <$> qPattern t1 <*> qPattern t2+qLhs (ApLhs   lhs ts) = ApLhs         <$> qLhs lhs <*> mapM qPattern ts++qPattern :: Qual (Pattern a)+qPattern l@(LiteralPattern        _ _) = return l+qPattern n@(NegativePattern       _ _) = return n+qPattern v@(VariablePattern       _ _) = return v+qPattern (ConstructorPattern   a c ts) = ConstructorPattern a+                                         <$> qIdent c <*> mapM qPattern ts+qPattern (InfixPattern     a t1 op t2) = InfixPattern a <$> qPattern t1+                                                        <*> qIdent op+                                                        <*> qPattern t2+qPattern (ParenPattern              t) = ParenPattern <$> qPattern t+qPattern (RecordPattern        a c fs) = RecordPattern a <$> qIdent c+                                         <*> mapM (qField qPattern) fs+qPattern (TuplePattern             ts) = TuplePattern <$> mapM qPattern ts+qPattern (ListPattern            a ts) = ListPattern a <$> mapM qPattern ts+qPattern (AsPattern               v t) = AsPattern v <$> qPattern t+qPattern (LazyPattern               t) = LazyPattern <$> qPattern t+qPattern (FunctionPattern      a f ts) = FunctionPattern a <$> qIdent f+                                                           <*> mapM qPattern ts+qPattern (InfixFuncPattern a t1 op t2) = InfixFuncPattern a <$> qPattern t1+                                                            <*> qIdent op+                                                            <*> qPattern t2++qRhs :: Qual (Rhs a)+qRhs (SimpleRhs p e ds) = SimpleRhs p <$> qExpr e           <*> mapM qDecl ds+qRhs (GuardedRhs es ds) = GuardedRhs  <$> mapM qCondExpr es <*> mapM qDecl ds++qCondExpr :: Qual (CondExpr a)+qCondExpr (CondExpr p g e) = CondExpr p <$> qExpr g <*> qExpr e++qExpr :: Qual (Expression a)+qExpr l@(Literal           _ _) = return l+qExpr (Variable            a v) = Variable     a <$> qIdent v+qExpr (Constructor         a c) = Constructor  a <$> qIdent c+qExpr (Paren                 e) = Paren          <$> qExpr e+qExpr (Typed             e qty) = Typed          <$> qExpr e+                                                 <*> qQualTypeExpr qty+qExpr (Record           a c fs) =+  Record a <$> qIdent c <*> mapM (qField qExpr) fs+qExpr (RecordUpdate       e fs) = RecordUpdate   <$> qExpr e+                                                 <*> mapM (qField qExpr) fs+qExpr (Tuple                es) = Tuple          <$> mapM qExpr es+qExpr (List               a es) = List a         <$> mapM qExpr es+qExpr (ListCompr          e qs) = ListCompr      <$> qExpr e <*> mapM qStmt qs+qExpr (EnumFrom              e) = EnumFrom       <$> qExpr e+qExpr (EnumFromThen      e1 e2) = EnumFromThen   <$> qExpr e1 <*> qExpr e2+qExpr (EnumFromTo        e1 e2) = EnumFromTo     <$> qExpr e1 <*> qExpr e2+qExpr (EnumFromThenTo e1 e2 e3) = EnumFromThenTo <$> qExpr e1 <*> qExpr e2+                                                              <*> qExpr e3+qExpr (UnaryMinus            e) = UnaryMinus     <$> qExpr e+qExpr (Apply             e1 e2) = Apply          <$> qExpr e1 <*> qExpr e2+qExpr (InfixApply     e1 op e2) = InfixApply     <$> qExpr e1 <*> qInfixOp op+                                                              <*> qExpr e2+qExpr (LeftSection        e op) = LeftSection  <$> qExpr e <*> qInfixOp op+qExpr (RightSection       op e) = RightSection <$> qInfixOp op <*> qExpr e+qExpr (Lambda             ts e) = Lambda       <$> mapM qPattern ts <*> qExpr e+qExpr (Let                ds e) = Let <$> mapM qDecl ds  <*> qExpr e+qExpr (Do                sts e) = Do  <$> mapM qStmt sts <*> qExpr e+qExpr (IfThenElse     e1 e2 e3) = IfThenElse <$> qExpr e1 <*> qExpr e2+                                                          <*> qExpr e3+qExpr (Case            ct e as) = Case ct    <$> qExpr e <*> mapM qAlt as++qStmt :: Qual (Statement a)+qStmt (StmtExpr   e) = StmtExpr <$> qExpr e+qStmt (StmtBind t e) = StmtBind <$> qPattern t <*> qExpr e+qStmt (StmtDecl  ds) = StmtDecl <$> mapM qDecl ds++qAlt :: Qual (Alt a)+qAlt (Alt p t rhs) = Alt p <$> qPattern t <*> qRhs rhs++qField :: Qual a -> Qual (Field a)+qField q (Field p l x) = Field p <$> qIdent l <*> q x++qInfixOp :: Qual (InfixOp a)+qInfixOp (InfixOp     a op) = InfixOp     a <$> qIdent op+qInfixOp (InfixConstr a op) = InfixConstr a <$> qIdent op++qIdent :: Qual QualIdent+qIdent x | isQualified x                = x'+         | hasGlobalScope (unqualify x) = x'+         | otherwise                    = return x+  where+  x' = do+    m     <- R.asks moduleIdent+    tyEnv <- R.asks valueEnv+    return $ case qualLookupValue x tyEnv of+      [y] -> origName y+      _   -> case qualLookupValue qmx tyEnv of+        [y] -> origName y+        _   -> qmx+        where qmx = qualQualify m x++qConstr :: Qual QualIdent+qConstr x = do+  m     <- R.asks moduleIdent+  tcEnv <- R.asks tyConsEnv+  return $ case qualLookupTypeInfo x tcEnv of+    [y] -> origName y+    _   -> case qualLookupTypeInfo qmx tcEnv of+      [y] -> origName y+      _   -> qmx+      where qmx = qualQualify m x++qClass :: Qual QualIdent+qClass = qConstr
+ src/Transformations/Simplify.hs view
@@ -0,0 +1,344 @@+{- |+    Module      :  $Header$+    Description :  Optimizing the Desugared Code+    Copyright   :  (c) 2003        Wolfgang Lux+                                   Martin Engelke+                       2011 - 2015 Björn Peemöller+                       2016        Finn Teegen+    License     :  BSD-3-clause++    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable++   After desugaring the source code, but before lifting local+   declarations, the compiler performs a few simple optimizations to+   improve the efficiency of the generated code. In addition, the+   optimizer replaces pattern bindings with simple variable bindings and+   selector functions.++   Currently, the following optimizations are implemented:++     * Under certain conditions, inline local function definitions.+     * Remove unused declarations.+     * Compute minimal binding groups for let expressions.+     * Remove pattern bindings to constructor terms+     * Inline simple constants.+-}+{-# LANGUAGE CPP #-}+module Transformations.Simplify (simplify) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative        ((<$>), (<*>))+#endif+import           Control.Monad.Extra        (concatMapM)+import           Control.Monad.State as S   (State, runState, gets, modify)+import qualified Data.Map            as Map (Map, empty, insert, lookup)++import Curry.Base.Position+import Curry.Base.Ident+import Curry.Syntax++import Base.Expr+import Base.Messages (internalError)+import Base.SCC+import Base.Types+import Base.Typing+import Base.Utils++import Env.Value (ValueEnv, ValueInfo (..), qualLookupValue)++-- -----------------------------------------------------------------------------+-- Simplification+-- -----------------------------------------------------------------------------++simplify :: ValueEnv -> Module Type -> (Module Type, ValueEnv)+simplify vEnv mdl@(Module _ m _ _ _) = (mdl', valueEnv s')+  where (mdl', s') = S.runState (simModule mdl) (SimplifyState m vEnv 1)++-- -----------------------------------------------------------------------------+-- Internal state monad+-- -----------------------------------------------------------------------------++data SimplifyState = SimplifyState+  { moduleIdent :: ModuleIdent -- read-only!+  , valueEnv    :: ValueEnv    -- updated for new pattern selection functions+  , nextId      :: Int         -- counter+  }++type SIM = S.State SimplifyState++getModuleIdent :: SIM ModuleIdent+getModuleIdent = S.gets moduleIdent++getNextId :: SIM Int+getNextId = do+  nid <- S.gets nextId+  S.modify $ \s -> s { nextId = succ nid }+  return nid++getFunArity :: QualIdent -> SIM Int+getFunArity f = do+  vEnv <- getValueEnv+  return $ case qualLookupValue f vEnv of+    [Value _ _ a _] -> a+    [Label   _ _ _] -> 1+    _               -> internalError $ "Simplify.funType " ++ show f++getValueEnv :: SIM ValueEnv+getValueEnv = S.gets valueEnv++freshIdent :: (Int -> Ident) -> SIM Ident+freshIdent f = f <$> getNextId++-- -----------------------------------------------------------------------------+-- Simplification+-- -----------------------------------------------------------------------------++simModule :: Module Type -> SIM (Module Type)+simModule (Module ps m es is ds) = Module ps m es is+                                   <$> mapM (simDecl Map.empty) ds++-- Inline an expression for a variable+type InlineEnv = Map.Map Ident (Expression Type)++simDecl :: InlineEnv -> Decl Type -> SIM (Decl Type)+simDecl env (FunctionDecl p ty f eqs) = FunctionDecl p ty f+                                        <$> concatMapM (simEquation env) eqs+simDecl env (PatternDecl     p t rhs) = PatternDecl p t <$> simRhs env rhs+simDecl _   d                         = return d++simEquation :: InlineEnv -> Equation Type -> SIM [Equation Type]+simEquation env (Equation p lhs rhs) = do+  rhs'  <- simRhs env rhs+  inlineFun env p lhs rhs'++simRhs :: InlineEnv -> Rhs Type -> SIM (Rhs Type)+simRhs env (SimpleRhs p e _) = simpleRhs p <$> simExpr env e+simRhs _   (GuardedRhs  _ _) = error "Simplify.simRhs: guarded rhs"++-- -----------------------------------------------------------------------------+-- Inlining of Functions+-- -----------------------------------------------------------------------------++-- After simplifying the right hand side of an equation, the compiler+-- transforms declarations of the form+--+--   f t_1 ... t_{k-l} x_{k-l+1} ... x_k =+--     let g y_1 ... y_l = e+--     in  g x_{k-l+1} ... x_k+--+-- into the equivalent definition+--+--   f t_1 ... t_{k-l} x_{k-l+1} x_k = let y_1   = x_{k-l+1}+--                                              ...+--                                         y_l   = x_k+--                                     in  e+--+-- where the arities of 'f' and 'g' are 'k' and 'l', respectively, and+-- 'x_{k-l+1}, ... ,x_k' are variables. The transformation can obviously be+-- generalized to the case where 'g' is defined by more than one equation.+-- However, we must be careful not to change the evaluation mode of arguments.+-- Therefore, the transformation is applied only all of the arguments of 'g'+-- are variables.+--+-- This transformation is actually just a special case of inlining a+-- (local) function definition. We are unable to handle the general case+-- because it would require to represent the pattern matching code+-- explicitly in a Curry expression.++inlineFun :: InlineEnv -> Position -> Lhs Type -> Rhs Type+          -> SIM [Equation Type]+inlineFun env p lhs rhs = do+  m <- getModuleIdent+  case rhs of+    SimpleRhs _ (Let [FunctionDecl _ _ f' eqs'] e) _+      | -- @f'@ is not recursive+        f' `notElem` qfv m eqs'+        -- @f'@ does not perform any pattern matching+        && and [all isVariablePattern ts1 | Equation _ (FunLhs _ ts1) _ <- eqs']+      -> do+        let a = eqnArity $ head eqs'+            (n, vs', e') = etaReduce 0 [] (reverse (snd $ flatLhs lhs)) e+        if  -- the eta-reduced rhs of @f@ is a call to @f'@+            e' == Variable (typeOf e') (qualify f')+            -- @f'@ was fully applied before eta-reduction+            && n  == a+          then mapM (mergeEqns p vs') eqs'+          else return [Equation p lhs rhs]+    _ -> return [Equation p lhs rhs]+  where+  etaReduce n1 vs (VariablePattern ty v : ts1) (Apply e1 (Variable _ v'))+    | qualify v == v' = etaReduce (n1 + 1) ((ty, v) : vs) ts1 e1+  etaReduce n1 vs _ e1 = (n1, vs, e1)++  mergeEqns p1 vs (Equation _ (FunLhs _ ts2) (SimpleRhs p2 e _))+    = Equation p1 lhs <$> simRhs env (simpleRhs p2 (Let ds e))+      where+      ds = zipWith (\t v -> PatternDecl p2 t (simpleRhs p2 (uncurry mkVar v)))+                   ts2+                   vs+  mergeEqns _ _ _ = error "Simplify.inlineFun.mergeEqns: no pattern match"++-- -----------------------------------------------------------------------------+-- Simplification of Expressions+-- -----------------------------------------------------------------------------++-- Variables that are bound to (simple) constants and aliases to other+-- variables are substituted. In terms of conventional compiler technology,+-- these optimizations correspond to constant propagation and copy propagation,+-- respectively. The transformation is applied recursively to a substituted+-- variable in order to handle chains of variable definitions.++-- Applications of let-expressions and case-expressions to other expressions+-- are simplified according to the following rules:+--   (let ds in e_1)            e_2 -> let ds in (e1 e2)+--   (case e_1 of p'_n -> e'_n) e_2 -> case e_1 of p'_n -> (e'n e_2)++-- The bindings of a let expression are sorted topologically in+-- order to split them into minimal binding groups. In addition,+-- local declarations occurring on the right hand side of a pattern+-- declaration are lifted into the enclosing binding group using the+-- equivalence (modulo alpha-conversion) of 'let x = let ds in e_1 in e_2'+-- and 'let ds; x = e_1 in e_2'.+-- This transformation avoids the creation of some redundant lifted+-- functions in later phases of the compiler.++simExpr :: InlineEnv -> Expression Type -> SIM (Expression Type)+simExpr _   l@(Literal     _ _) = return l+simExpr _   c@(Constructor _ _) = return c+-- subsitution of variables+simExpr env v@(Variable   ty x)+  | isQualified x = return v+  | otherwise     =+    maybe (return v) (simExpr env . withType ty) (Map.lookup (unqualify x) env)+-- simplification of application+simExpr env (Apply       e1 e2) = case e1 of+  Let ds e'     -> simExpr env (Let ds (Apply e' e2))+  Case ct e' bs -> simExpr env (Case ct e' (map (applyToAlt e2) bs))+  _             -> Apply <$> simExpr env e1 <*> simExpr env e2+  where+  applyToAlt e (Alt       p t rhs) = Alt p t (applyToRhs e rhs)+  applyToRhs e (SimpleRhs p e1' _) = simpleRhs p (Apply e1' e)+  applyToRhs _ (GuardedRhs    _ _) = error "Simplify.simExpr.applyRhs: Guarded rhs"+-- simplification of declarations+simExpr env (Let          ds e) = do+  m   <- getModuleIdent+  dss <- mapM sharePatternRhs ds+  simplifyLet env (scc bv (qfv m) (foldr hoistDecls [] (concat dss))) e+simExpr env (Case      ct e bs) = Case ct <$> simExpr env e+                                          <*> mapM (simplifyAlt env) bs+simExpr env (Typed       e qty) = flip Typed qty <$> simExpr env e+simExpr _   _                   = error "Simplify.simExpr: no pattern match"++-- Simplify a case alternative+simplifyAlt :: InlineEnv -> Alt Type -> SIM (Alt Type)+simplifyAlt env (Alt p t rhs) = Alt p t <$> simRhs env rhs++-- Transform a pattern declaration @t = e@ into two declarations+-- @t = v, v = e@ whenever @t@ is not a variable. This is used to share+-- the expression @e@ using the fresh variable @v@.+sharePatternRhs :: Decl Type -> SIM [Decl Type]+--TODO: change to patterns instead of case+sharePatternRhs (PatternDecl p t rhs) = case t of+  VariablePattern _ _ -> return [PatternDecl p t rhs]+  _                   -> do+    let ty = typeOf t+    v  <- freshIdent patternId+    return [ PatternDecl p t                      (simpleRhs p (mkVar ty v))+           , PatternDecl p (VariablePattern ty v) rhs+           ]+  where patternId n = mkIdent ("_#pat" ++ show n)+sharePatternRhs d                     = return [d]++-- Lift up nested let declarations in pattern declarations, i.e., replace+-- @let p = let ds' in e'; ds in e@ by @let ds'; p = e'; ds in e@.+hoistDecls :: Decl a -> [Decl a] -> [Decl a]+hoistDecls (PatternDecl p t (SimpleRhs p' (Let ds' e) _)) ds+ = foldr hoistDecls ds (PatternDecl p t (simpleRhs p' e) : ds')+hoistDecls d ds = d : ds++-- The declaration groups of a let expression are first processed from+-- outside to inside, simplifying the right hand sides and collecting+-- inlineable expressions on the fly. At present, only simple constants+-- and aliases to other variables are inlined. A constant is considered+-- simple if it is either a literal, a constructor, or a non-nullary+-- function. Note that it is not possible to define nullary functions in+-- local declarations in Curry. Thus, an unqualified name always refers+-- to either a variable or a non-nullary function. Applications of+-- constructors and partial applications of functions to at least one+-- argument are not inlined because the compiler has to allocate space+-- for them, anyway. In order to prevent non-termination, recursive+-- binding groups are not processed for inlining.++-- With the list of inlineable expressions, the body of the let is+-- simplified and then the declaration groups are processed from inside+-- to outside to construct the simplified, nested let expression. In+-- doing so, unused bindings are discarded. In addition, all pattern+-- bindings are replaced by simple variable declarations using selector+-- functions to access the pattern variables.++simplifyLet :: InlineEnv -> [[Decl Type]] -> Expression Type+            -> SIM (Expression Type)+simplifyLet env []       e = simExpr env e+simplifyLet env (ds:dss) e = do+  m     <- getModuleIdent+  ds'   <- mapM (simDecl env) ds  -- simplify declarations+  env'  <- inlineVars env ds'     -- inline a simple variable binding+  e'    <- simplifyLet env' dss e -- simplify remaining bindings+  ds''  <- concatMapM (expandPatternBindings (qfv m ds' ++ qfv m e')) ds'+  return $ foldr (mkLet' m) e' (scc bv (qfv m) ds'')++inlineVars :: InlineEnv -> [Decl Type] -> SIM InlineEnv+inlineVars env ds = case ds of+  [PatternDecl _ (VariablePattern _ v) (SimpleRhs _ e _)] -> do+    allowed <- canInlineVar v e+    return $ if allowed then Map.insert v e env else env+  _ -> return env+  where+  canInlineVar _ (Literal     _ _) = return True+  canInlineVar _ (Constructor _ _) = return True+  canInlineVar v (Variable   _ v')+    | isQualified v'             = (> 0) <$> getFunArity v'+    | otherwise                  = return $ v /= unqualify v'+  canInlineVar _ _               = return False++mkLet' :: ModuleIdent -> [Decl Type] -> Expression Type -> Expression Type+mkLet' m [FreeDecl p vs] e+  | null vs'  = e+  | otherwise = Let [FreeDecl p vs'] e         -- remove unused free variables+  where vs' = filter ((`elem` qfv m e) . varIdent) vs+mkLet' m [PatternDecl _ (VariablePattern ty v) (SimpleRhs _ e _)] (Variable _ v')+  | v' == qualify v && v `notElem` qfv m e = withType ty e -- inline single binding+mkLet' m ds e+  | null (filter (`elem` qfv m e) (bv ds)) = e -- removed unused bindings+  | otherwise                              = Let ds e++-- In order to implement lazy pattern matching in local declarations,+-- pattern declarations 't = e' where 't' is not a variable+-- are transformed into a list of declarations+-- 'v_0 = e; v_1 = f_1 v_0; ...; v_n = f_n v_0' where 'v_0' is a fresh+-- variable, 'v_1,...,v_n' are the variables occurring in 't' and the+-- auxiliary functions 'f_i' are defined by 'f_i t = v_i' (see also+-- appendix D.8 of the Curry report). The bindings 'v_0 = e' are introduced+-- before splitting the declaration groups of the enclosing let expression+-- (cf. the 'Let' case in 'simExpr' above) so that they are placed in their own+-- declaration group whenever possible. In particular, this ensures that+-- the new binding is discarded when the expression 'e' is itself a variable.++-- fvs contains all variables used in the declarations and the body+-- of the let expression.+expandPatternBindings :: [Ident] -> Decl Type -> SIM [Decl Type]+expandPatternBindings fvs d@(PatternDecl p t (SimpleRhs _ e _)) = case t of+  VariablePattern _ _ -> return [d]+  _                   ->+    -- used variables+    mapM mkSelectorDecl (filter ((`elem` fvs) . fst3) (patternVars t))+  where+    pty = typeOf t -- type of pattern+    mkSelectorDecl (v, _, vty) = do+      let fty = TypeArrow pty vty+      f <- freshIdent (updIdentName (++ '#' : idName v) . fpSelectorId)+      return $ varDecl p vty v $+        Let [funDecl p fty f [t] (mkVar vty v)] (Apply (mkVar fty f) e)+expandPatternBindings _ d = return [d]
− src/TypeCheck.lhs
@@ -1,1331 +0,0 @@--% $Id: TypeCheck.lhs,v 1.90 2004/11/06 18:34:07 wlux Exp $-%-% Copyright (c) 1999-2004, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{TypeCheck.lhs}-\section{Type Checking Curry Programs}-This module implements the type checker of the Curry compiler. The-type checker is invoked after the syntactic correctness of the program-has been verified. Local variables have been renamed already. Thus the-compiler can maintain a flat type environment (which is necessary in-order to pass the type information to later phases of the compiler).-The type checker now checks the correct typing of all expressions and-also verifies that the type signatures given by the user match the-inferred types. The type checker uses algorithm-W~\cite{DamasMilner82:Principal} for inferring the types of-unannotated declarations, but allows for polymorphic recursion when a-type annotation is present.-\begin{verbatim}--> module TypeCheck(typeCheck) where--> import Text.PrettyPrint.HughesPJ-> import Control.Monad.State as S-> import Data.List-> import Data.Maybe-> import qualified Data.Map as Map-> import qualified Data.Set as Set--> import Curry.Base.Position-> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Pretty-> import Curry.Syntax.Utils---> import Base-> import Types-> import TopEnv-> import SCC-> import TypeSubst-> import Utils--> infixl 5 $-$--> ($-$) :: Doc -> Doc -> Doc-> x $-$ y = x $$ space $$ y--\end{verbatim}-Type checking proceeds as follows. First, the type constructor-environment is initialized by adding all types defined in the current-module. Next, the types of all data constructors and field labels-are entered into the type environment and then a type inference -for all function and value definitions is performed. -The type checker returns the resulting type-constructor and type environments.-\begin{verbatim}--> typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> [Decl] -> (TCEnv,ValueEnv)-> typeCheck m tcEnv tyEnv ds =->   run (tcDecls m tcEnv' Map.empty vds >>->        S.lift S.get >>= \theta -> S.get >>= \tyEnv' ->->        return (tcEnv',subst theta tyEnv'))->       (bindLabels m tcEnv' (bindConstrs m tcEnv' tyEnv))->   where (tds,vds) = partition isTypeDecl ds->         tcEnv' = bindTypes m tds tcEnv--\end{verbatim}--The type checker makes use of nested state monads in order to-maintain the type environment, the current substitution, and a counter-which is used for generating fresh type variables.-\begin{verbatim}--> type TcState a = S.StateT ValueEnv (S.StateT TypeSubst (S.State Int)) a--> run :: TcState a -> ValueEnv -> a-> run m tyEnv = S.evalState (S.evalStateT (S.evalStateT m tyEnv) idSubst) 0--\end{verbatim}-\paragraph{Defining Types}-Before type checking starts, the types defined in the local module-have to be entered into the type constructor environment. All type-synonyms occurring in the definitions are fully expanded and all type-constructors are qualified with the name of the module in which they-are defined. This is possible because Curry does not allow (mutually)-recursive type synonyms. In order to simplify the expansion of type-synonyms, the compiler first performs a dependency analysis on the-type definitions. This also makes it easy to identify (mutually)-recursive synonyms.--Note that \texttt{bindTC} is passed the \emph{final} type constructor-environment in order to handle the expansion of type synonyms. This-does not lead to a termination problem because \texttt{sortTypeDecls}-already has checked that there are no recursive type synonyms.--We have to be careful with existentially quantified type variables for-data constructors. An existentially quantified type variable may-shadow a universally quantified variable from the left hand side of-the type declaration. In order to avoid wrong indices being assigned-to these variables, we replace all shadowed variables in the left hand-side by \texttt{anonId} before passing them to \texttt{expandMonoType}-and \texttt{expandMonoTypes}, respectively.-\begin{verbatim}--> bindTypes :: ModuleIdent -> [Decl] -> TCEnv -> TCEnv-> bindTypes m ds tcEnv = tcEnv'->   where tcEnv' = foldr (bindTC m tcEnv') tcEnv (sortTypeDecls m ds)--> bindTC :: ModuleIdent -> TCEnv -> Decl -> TCEnv -> TCEnv-> bindTC m tcEnv (DataDecl _ tc tvs cs) =->   bindTypeInfo DataType m tc tvs (map (Just . mkData) cs)->   where mkData (ConstrDecl _ evs c tys) = Data c (length evs) tys'->           where tys' = expandMonoTypes m tcEnv (cleanTVars tvs evs) tys->         mkData (ConOpDecl _ evs ty1 op ty2) = Data op (length evs) tys'->           where tys' = expandMonoTypes m tcEnv (cleanTVars tvs evs) [ty1,ty2]-> bindTC m tcEnv (NewtypeDecl _ tc tvs (NewConstrDecl _ evs c ty)) =->   bindTypeInfo RenamingType m tc tvs (Data c (length evs) ty')->   where ty' = expandMonoType m tcEnv (cleanTVars tvs evs) ty-> bindTC m tcEnv (TypeDecl _ tc tvs ty) =->   bindTypeInfo AliasType m tc tvs (expandMonoType m tcEnv tvs ty)-> bindTC _ _ _ = id--> cleanTVars :: [Ident] -> [Ident] -> [Ident]-> cleanTVars tvs evs = [if tv `elem` evs then anonId else tv | tv <- tvs]--> sortTypeDecls :: ModuleIdent -> [Decl] -> [Decl]-> sortTypeDecls m = map (typeDecl m) . scc bound free->   where bound (DataDecl _ tc _ _) = [tc]->         bound (NewtypeDecl _ tc _ _) = [tc]->         bound (TypeDecl _ tc _ _) = [tc]->         free (DataDecl _ _ _ _) = []->         free (NewtypeDecl _ _ _ _) = []->         free (TypeDecl _ _ _ ty) = ft m ty []--> typeDecl :: ModuleIdent -> [Decl] -> Decl-> typeDecl _ [] = internalError "typeDecl"-> typeDecl _ [d@(DataDecl _ _ _ _)] = d-> typeDecl _ [d@(NewtypeDecl _ _ _ _)] = d-> typeDecl m [d@(TypeDecl p tc _ ty)]->   | tc `elem` ft m ty [] = errorAt' (recursiveTypes [tc])->   | otherwise = d-> typeDecl _ (TypeDecl p tc _ _ : ds) =->   errorAt' (recursiveTypes (tc : [tc' | TypeDecl _ tc' _ _ <- ds]))--> ft :: ModuleIdent -> TypeExpr -> [Ident] -> [Ident]-> ft m (ConstructorType tc tys) tcs =->   maybe id (:) (localIdent m tc) (foldr (ft m) tcs tys)-> ft _ (VariableType _) tcs = tcs-> ft m (TupleType tys) tcs = foldr (ft m) tcs tys-> ft m (ListType ty) tcs = ft m ty tcs-> ft m (ArrowType ty1 ty2) tcs = ft m ty1 $ ft m ty2 $ tcs-> ft m (RecordType fs rty) tcs = ->   foldr (ft m) (maybe tcs (\ty -> ft m ty tcs) rty) (map snd fs)--\end{verbatim}-\paragraph{Defining Data Constructors}-In the next step, the types of all data constructors are entered into-the type environment using the information just entered into the type-constructor environment. Thus, we can be sure that all type variables-have been properly renamed and all type synonyms are already expanded.-\begin{verbatim}--> bindConstrs :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv-> bindConstrs m tcEnv tyEnv =->   foldr (bindData . snd) tyEnv (localBindings tcEnv)->   where bindData (DataType tc n cs) tyEnv =->           foldr (bindConstr m n (constrType tc n)) tyEnv (catMaybes cs)->         bindData (RenamingType tc n (Data c n' ty)) tyEnv =->           bindGlobalInfo NewtypeConstructor m c->                          (ForAllExist n n' (TypeArrow ty (constrType tc n)))->                          tyEnv->         bindData (AliasType _ _ _) tyEnv = tyEnv->         bindConstr m n ty (Data c n' tys) =->           bindGlobalInfo DataConstructor m c->                          (ForAllExist n n' (foldr TypeArrow ty tys))->         constrType tc n = TypeConstructor tc (map TypeVariable [0..n-1])--\end{verbatim}-\paragraph{Defining Field Labels}-Records can only be declared as type aliases. So currently there is-nothing more to do than entering all typed record fields (labels) -which occur in record types on the right-hand-side of type aliases -into the type environment. Since we use the type constructor environment-again, we can be sure that all type variables-have been properly renamed and all type synonyms are already expanded.-\begin{verbatim}--> bindLabels :: ModuleIdent -> TCEnv -> ValueEnv -> ValueEnv-> bindLabels m tcEnv tyEnv =->   foldr (bindFieldLabels . snd) tyEnv (localBindings tcEnv)->   where bindFieldLabels (AliasType r _ (TypeRecord fs _)) tyEnv =->           foldr (bindField r) tyEnv fs->	  bindFieldLabels _ tyEnv = tyEnv->	  ->         bindField r (l,ty) tyEnv =->           case (lookupValue l tyEnv) of->             [] -> bindLabel l r (polyType ty) tyEnv ->             _  -> tyEnv--\end{verbatim}-\paragraph{Type Signatures}-The type checker collects type signatures in a flat environment. All-anonymous variables occurring in a signature are replaced by fresh-names. However, the type is not expanded so that the signature is-available for use in the error message that is printed when the-inferred type is less general than the signature.-\begin{verbatim}--> type SigEnv = Map.Map Ident TypeExpr--> bindTypeSig :: Ident -> TypeExpr -> SigEnv -> SigEnv-> bindTypeSig = Map.insert--> bindTypeSigs :: Decl -> SigEnv -> SigEnv-> bindTypeSigs (TypeSig _ vs ty) env =->   foldr (flip bindTypeSig (nameSigType ty)) env vs -> bindTypeSigs _ env = env--> lookupTypeSig :: Ident -> SigEnv -> Maybe TypeExpr-> lookupTypeSig = Map.lookup--> qualLookupTypeSig :: ModuleIdent -> QualIdent -> SigEnv -> Maybe TypeExpr-> qualLookupTypeSig m f sigs = localIdent m f >>= flip lookupTypeSig sigs--> nameSigType :: TypeExpr -> TypeExpr-> nameSigType ty = fst (nameType ty (filter (`notElem` fv ty) nameSupply))--> nameTypes :: [TypeExpr] -> [Ident] -> ([TypeExpr],[Ident])-> nameTypes (ty:tys) tvs = (ty':tys',tvs'')->   where (ty',tvs') = nameType ty tvs->         (tys',tvs'') = nameTypes tys tvs'-> nameTypes [] tvs = ([],tvs)--> nameType :: TypeExpr -> [Ident] -> (TypeExpr,[Ident])-> nameType (ConstructorType tc tys) tvs = (ConstructorType tc tys',tvs')->   where (tys',tvs') = nameTypes tys tvs-> nameType (VariableType tv) (tv':tvs)->   | tv == anonId = (VariableType tv',tvs)->   | otherwise = (VariableType tv,tv':tvs)-> nameType (TupleType tys) tvs = (TupleType tys',tvs')->   where (tys',tvs') = nameTypes tys tvs-> nameType (ListType ty) tvs = (ListType ty',tvs')->   where (ty',tvs') = nameType ty tvs-> nameType (ArrowType ty1 ty2) tvs = (ArrowType ty1' ty2',tvs'')->   where (ty1',tvs') = nameType ty1 tvs->         (ty2',tvs'') = nameType ty2 tvs'-> nameType (RecordType fs rty) tvs = ->   (RecordType (zip ls tys') (listToMaybe rty'), tvs)->   where (ls, tys) = unzip fs->         (tys', _) = nameTypes tys tvs->         (rty', _) = nameTypes (maybeToList rty) tvs-        -\end{verbatim}-\paragraph{Type Inference}-Before type checking a group of declarations, a dependency analysis is-performed and the declaration group is eventually transformed into-nested declaration groups which are checked separately. Within each-declaration group, first the left hand sides of all declarations are-typed. Next, the right hand sides of the declarations are typed in the-extended type environment. Finally, the types for the left and right-hand sides are unified and the types of all defined functions are-generalized. The generalization step will also check that the type-signatures given by the user match the inferred types.--Argument and result types of foreign functions using the-\texttt{ccall} calling convention are restricted to the basic types-\texttt{Bool}, \texttt{Char}, \texttt{Int}, and \texttt{Float}. In-addition, \texttt{IO}~$t$ is a legitimate result type when $t$ is-either one of the basic types or \texttt{()}.--\ToDo{Extend the set of legitimate types to match the types admitted-  by the Haskell Foreign Function Interface-  Addendum.~\cite{Chakravarty03:FFI}}-\begin{verbatim}--> tcDecls :: ModuleIdent -> TCEnv -> SigEnv -> [Decl] -> TcState ()-> tcDecls m tcEnv sigs ds =->   mapM_ (tcDeclGroup m tcEnv (foldr bindTypeSigs sigs ods))->         (scc bv (qfv m) vds)->   where (vds,ods) = partition isValueDecl ds--> tcDeclGroup :: ModuleIdent -> TCEnv -> SigEnv -> [Decl] -> TcState ()-> --tcDeclGroup m tcEnv _ [ForeignDecl p cc _ f ty] =-> --  tcForeignFunct m tcEnv p cc f ty-> tcDeclGroup m tcEnv _ [ExternalDecl _ _ _ f ty] =->   tcExternalFunct m tcEnv f ty-> tcDeclGroup m tcEnv sigs [FlatExternalDecl _ fs] =->   mapM_ (tcFlatExternalFunct m tcEnv sigs) fs-> tcDeclGroup m tcEnv sigs [ExtraVariables _ vs] =->   mapM_ (tcExtraVar m tcEnv sigs ) vs-> tcDeclGroup m tcEnv sigs ds =->   do->     tyEnv0 <- S.get->     tysLhs <- mapM (tcDeclLhs m tcEnv sigs) ds->     tysRhs <- mapM (tcDeclRhs m tcEnv tyEnv0 sigs) ds->     sequence_ (zipWith3 (unifyDecl m) ds tysLhs tysRhs)->     theta <- S.lift S.get->     mapM_ (genDecl m tcEnv sigs (fvEnv (subst theta tyEnv0)) theta) ds--> --tcForeignFunct :: ModuleIdent -> TCEnv -> Position -> CallConv -> Ident-> --               -> TypeExpr -> TcState ()-> --tcForeignFunct m tcEnv p cc f ty =-> --  S.modify (bindFun m f (checkForeignType cc (expandPolyType tcEnv ty)))-> --  where checkForeignType CallConvPrimitive ty = ty-> --        checkForeignType CallConvCCall (ForAll n ty) =-> --          ForAll n (checkCCallType ty)-> --        checkCCallType (TypeArrow ty1 ty2)-> --          | isCArgType ty1 = TypeArrow ty1 (checkCCallType ty2)-> --          | otherwise = errorAt p (invalidCType "argument" m ty1)-> --        checkCCallType ty-> --          | isCResultType ty = ty-> --          | otherwise = errorAt p (invalidCType "result" m ty)-> --        isCArgType (TypeConstructor tc []) = tc `elem` basicTypeId-> --        isCArgType _ = False-> --        isCResultType (TypeConstructor tc []) = tc `elem` basicTypeId-> --        isCResultType (TypeConstructor tc [ty]) =-> --          tc == qIOId && (ty == unitType || isCArgType ty)-> --        isCResultType _ = False-> --        basicTypeId = [qBoolId,qCharId,qIntId,qFloatId]--> tcExternalFunct :: ModuleIdent -> TCEnv -> Ident -> TypeExpr -> TcState ()-> tcExternalFunct m tcEnv  f ty =->   S.modify (bindFun m f (expandPolyType m tcEnv ty))--> tcFlatExternalFunct :: ModuleIdent -> TCEnv -> SigEnv -> Ident -> TcState ()-> tcFlatExternalFunct m tcEnv sigs f =->   typeOf f tcEnv sigs >>= S.modify . bindFun m f->   where typeOf f tcEnv sigs =->           case lookupTypeSig f sigs of->             Just ty -> return (expandPolyType m tcEnv ty)->             Nothing -> internalError "tcFlatExternalFunct"--> tcExtraVar :: ModuleIdent -> TCEnv -> SigEnv -> Ident->            -> TcState ()-> tcExtraVar m tcEnv sigs v =->   typeOf v tcEnv sigs >>= S.modify . bindFun m v . monoType->   where typeOf v tcEnv sigs =->           case lookupTypeSig v sigs of->             Just ty->               | n == 0 -> return ty'->               | otherwise -> errorAt' (polymorphicFreeVar v)->               where ForAll n ty' = expandPolyType m tcEnv ty->             Nothing -> freshTypeVar--> tcDeclLhs :: ModuleIdent -> TCEnv -> SigEnv -> Decl -> TcState Type-> tcDeclLhs m tcEnv sigs (FunctionDecl p f _) =->   tcConstrTerm m tcEnv sigs p (VariablePattern f)-> tcDeclLhs m tcEnv sigs (PatternDecl p t _) = tcConstrTerm m tcEnv sigs p t--> tcDeclRhs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Decl->           -> TcState Type-> tcDeclRhs m tcEnv tyEnv0 sigs (FunctionDecl _ f (eq:eqs)) =->   tcEquation m tcEnv tyEnv0 sigs eq >>= flip tcEqns eqs->   where tcEqns ty [] = return ty->         tcEqns ty (eq@(Equation p _ _):eqs) =->           tcEquation m tcEnv tyEnv0 sigs eq >>=->           unify p "equation" (ppDecl (FunctionDecl p f [eq])) m ty >>->           tcEqns ty eqs-> tcDeclRhs m tcEnv tyEnv0 sigs (PatternDecl _ _ rhs) =->   tcRhs m tcEnv tyEnv0 sigs rhs--> unifyDecl :: ModuleIdent -> Decl -> Type -> Type -> TcState ()-> unifyDecl m (FunctionDecl p f _) =->   unify p "function binding" (text "Function:" <+> ppIdent f) m-> unifyDecl m (PatternDecl p t _) =->   unify p "pattern binding" (ppConstrTerm 0 t) m--\end{verbatim}-In Curry we cannot generalize the types of let-bound variables because-they can refer to logic variables. Without this monomorphism-restriction unsound code like-\begin{verbatim}-bug = x =:= 1 & x =:= 'a'-  where x :: a-        x = fresh-fresh :: a-fresh = x where x free-\end{verbatim}-could be written. Note that \texttt{fresh} has the polymorphic type-$\forall\alpha.\alpha$. This is correct because \texttt{fresh} is a-function and therefore returns a different variable at each-invocation.--The code in \texttt{genVar} below also verifies that the inferred type-for a variable or function matches the type declared in a type-signature. As the declared type is already used for assigning an initial-type to a variable when it is used, the inferred type can only be more-specific. Therefore, if the inferred type does not match the type-signature the declared type must be too general.-\begin{verbatim}--> genDecl :: ModuleIdent -> TCEnv -> SigEnv -> Set.Set Int -> TypeSubst -> Decl->         -> TcState ()-> genDecl m tcEnv sigs lvs theta (FunctionDecl _ f _) =->   S.modify (genVar True m tcEnv sigs lvs theta f)-> genDecl m tcEnv sigs lvs theta (PatternDecl p t _) =->   mapM_ (S.modify . genVar False m tcEnv sigs lvs theta ) (bv t)--> genVar :: Bool -> ModuleIdent -> TCEnv -> SigEnv -> Set.Set Int -> TypeSubst->        -> Ident -> ValueEnv -> ValueEnv-> genVar poly m tcEnv sigs lvs theta v tyEnv =->   case lookupTypeSig v sigs of->     Just sigTy->       | cmpTypes sigma (expandPolyType m tcEnv sigTy) -> tyEnv'->       | otherwise -> errorAt (positionOfIdent v) ->                              (typeSigTooGeneral m what sigTy sigma)->     Nothing -> tyEnv'->   where what = text (if poly then "Function:" else "Variable:") <+> ppIdent v->         tyEnv' = rebindFun m v sigma tyEnv->         sigma = genType poly (subst theta (varType v tyEnv))->         genType poly (ForAll n ty)->           | n > 0 = internalError ("genVar: " ++ showLine (positionOfIdent v) ++ ->                                    show v ++ " :: " ++ show ty)->           | poly = gen lvs ty->           | otherwise = monoType ty->         cmpTypes (ForAll _ t1) (ForAll _ t2) = equTypes t1 t2--> tcEquation :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Equation->            -> TcState Type-> tcEquation m tcEnv tyEnv0 sigs (Equation p lhs rhs) =->   do->     tys <- mapM (tcConstrTerm m tcEnv sigs p) ts->     ty <- tcRhs m tcEnv tyEnv0 sigs rhs->     checkSkolems p m (text "Function: " <+> ppIdent f) tyEnv0->                  (foldr TypeArrow ty tys)->   where (f,ts) = flatLhs lhs--> tcLiteral :: ModuleIdent -> Literal -> TcState Type-> tcLiteral _ (Char _ _) = return charType-> tcLiteral m (Int v _)  = --return intType->   do->     ty <- freshConstrained [intType,floatType]->     S.modify (bindFun m v (monoType ty))->     return ty-> tcLiteral _ (Float _ _) = return floatType-> tcLiteral _ (String _ _) = return stringType--> tcConstrTerm :: ModuleIdent -> TCEnv -> SigEnv -> Position -> ConstrTerm->              -> TcState Type-> tcConstrTerm m tcEnv sigs _ (LiteralPattern l) = tcLiteral m l-> tcConstrTerm m tcEnv sigs _ (NegativePattern _ l) = tcLiteral m l-> tcConstrTerm m tcEnv sigs _ (VariablePattern v) =->   do ->     ty <- case lookupTypeSig v sigs of->             Just t -> inst (expandPolyType m tcEnv t)->             Nothing -> freshTypeVar->     S.modify (bindFun m v (monoType ty))->     return ty->   -> tcConstrTerm m tcEnv sigs p t@(ConstructorPattern c ts) =->   do->     tyEnv <- S.get->     ty <- skol (constrType m c tyEnv)->     unifyArgs (ppConstrTerm 0 t) ts ty->   where unifyArgs _ [] ty = return ty->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =->           tcConstrTerm m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           unifyArgs doc ts ty2->         unifyArgs _ _ _ = internalError "tcConstrTerm"-> tcConstrTerm m tcEnv sigs p t@(InfixPattern t1 op t2) =->   do->     tyEnv <- S.get->     ty <- skol (constrType m op tyEnv)->     unifyArgs (ppConstrTerm 0 t) [t1,t2] ty->   where unifyArgs _ [] ty = return ty->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =->           tcConstrTerm m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           unifyArgs doc ts ty2->         unifyArgs _ _ _ = internalError "tcConstrTerm"-> tcConstrTerm m tcEnv sigs p (ParenPattern t) = tcConstrTerm m tcEnv sigs p t-> tcConstrTerm m tcEnv sigs p (TuplePattern _ ts)->  | null ts = return unitType->  | otherwise = liftM tupleType $ mapM (tcConstrTerm m tcEnv sigs p) ts-> tcConstrTerm m tcEnv sigs p t@(ListPattern _ ts) =->   freshTypeVar >>= flip (tcElems (ppConstrTerm 0 t)) ts->   where tcElems _ ty [] = return (listType ty)->         tcElems doc ty (t:ts) =->           tcConstrTerm m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty >>->           tcElems doc ty ts-> tcConstrTerm m tcEnv sigs p t@(AsPattern v t') =->   do->     ty1 <- tcConstrTerm m tcEnv sigs p (VariablePattern v)->     ty2 <- tcConstrTerm m tcEnv sigs p t'->     unify p "pattern" (ppConstrTerm 0 t) m ty1 ty2->     return ty1-> tcConstrTerm m tcEnv sigs p (LazyPattern _ t) = tcConstrTerm m tcEnv sigs p t-> tcConstrTerm m tcEnv sigs p t@(FunctionPattern f ts) =->   do->     tyEnv <- S.get->     ty <- inst (funType m f tyEnv) --skol (constrType m c tyEnv)->     unifyArgs (ppConstrTerm 0 t) ts ty->   where unifyArgs _ [] ty = return ty->         unifyArgs doc (t:ts) ty@(TypeVariable _) =->           do (alpha,beta) <- tcArrow p "function pattern" doc m ty->	       ty' <- tcConstrTermFP m tcEnv sigs p t->	       unify p "function pattern"->	             (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->	             m ty' alpha->	       unifyArgs doc ts beta->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =->           tcConstrTermFP m tcEnv sigs p t >>=->           unify p "function pattern" ->	          (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           unifyArgs doc ts ty2->         unifyArgs _ _ ty = internalError ("tcConstrTerm: " ++ show ty)-> tcConstrTerm m tcEnv sigs p t@(InfixFuncPattern t1 op t2) =->   tcConstrTerm m tcEnv sigs p (FunctionPattern op [t1,t2])-> tcConstrTerm m tcEnv sigs p r@(RecordPattern fs rt)->   | isJust rt =->     do->       ty <- tcConstrTerm m tcEnv sigs p (fromJust rt)->       fts <- mapM (tcFieldPatt (tcConstrTerm m tcEnv sigs) m) fs->       alpha <- freshVar id->	let rty = TypeRecord fts (Just alpha)->	unify p "record pattern" (ppConstrTerm 0 r) m ty rty->       return rty->   | otherwise =->     do->       fts <- mapM (tcFieldPatt (tcConstrTerm m tcEnv sigs) m) fs->       return (TypeRecord fts Nothing)--\end{verbatim}-In contrast to usual patterns, the type checking routine for arguments of -function patterns \texttt{tcConstrTermFP} differs from \texttt{tcConstrTerm}-because of possibly multiple occurrences of variables.-\begin{verbatim}--> tcConstrTermFP :: ModuleIdent -> TCEnv -> SigEnv -> Position -> ConstrTerm->                   -> TcState Type-> tcConstrTermFP m tcEnv sigs p (LiteralPattern l) = tcLiteral m l-> tcConstrTermFP m tcEnv sigs p (NegativePattern _ l) = tcLiteral m l-> tcConstrTermFP m tcEnv sigs p (VariablePattern v) =->   do->     ty <- maybe freshTypeVar ->                 (inst . expandPolyType m tcEnv) ->                 (lookupTypeSig v sigs)->     tyEnv <- S.get->     ty' <- maybe (S.modify (bindFun m v (monoType ty)) >> return ty)->                  (\ (ForAll _ t) -> return t)->	           (sureVarType v tyEnv)->     return ty' -> tcConstrTermFP m tcEnv sigs p t@(ConstructorPattern c ts) =->   do->     tyEnv <- S.get->     ty <- skol (constrType m c tyEnv)->     unifyArgs (ppConstrTerm 0 t) ts ty->   where unifyArgs _ [] ty = return ty->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =->           tcConstrTermFP m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           unifyArgs doc ts ty2->         unifyArgs _ _ _ = internalError "tcConstrTermFP"-> tcConstrTermFP m tcEnv sigs p t@(InfixPattern t1 op t2) =->   do->     tyEnv <- S.get->     ty <- skol (constrType m op tyEnv)->     unifyArgs (ppConstrTerm 0 t) [t1,t2] ty->   where unifyArgs _ [] ty = return ty->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =->           tcConstrTermFP m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           unifyArgs doc ts ty2->         unifyArgs _ _ _ = internalError "tcConstrTermFP"-> tcConstrTermFP m tcEnv sigs p (ParenPattern t) = tcConstrTermFP m tcEnv sigs p t-> tcConstrTermFP m tcEnv sigs p (TuplePattern _ ts)->  | null ts = return unitType->  | otherwise = liftM tupleType $ mapM (tcConstrTermFP m tcEnv sigs p) ts-> tcConstrTermFP m tcEnv sigs p t@(ListPattern _ ts) =->   freshTypeVar >>= flip (tcElems (ppConstrTerm 0 t)) ts->   where tcElems _ ty [] = return (listType ty)->         tcElems doc ty (t:ts) =->           tcConstrTermFP m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty >>->           tcElems doc ty ts-> tcConstrTermFP m tcEnv sigs p t@(AsPattern v t') =->   do->     ty1 <- tcConstrTermFP m tcEnv sigs p (VariablePattern v)->     ty2 <- tcConstrTermFP m tcEnv sigs p t'->     unify p "pattern" (ppConstrTerm 0 t) m ty1 ty2->     return ty1-> tcConstrTermFP m tcEnv sigs p (LazyPattern _ t) = tcConstrTermFP m tcEnv sigs p t-> tcConstrTermFP m tcEnv sigs p t@(FunctionPattern f ts) =->   do->     tyEnv <- S.get->     ty <- inst (funType m f tyEnv) --skol (constrType m c tyEnv)->     unifyArgs (ppConstrTerm 0 t) ts ty->   where unifyArgs _ [] ty = return ty->         unifyArgs doc (t:ts) ty@(TypeVariable _) =->           do (alpha,beta) <- tcArrow p "function pattern" doc m ty->	       ty' <- tcConstrTermFP m tcEnv sigs p t->	       unify p "function pattern"->	             (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->	             m ty' alpha->	       unifyArgs doc ts beta->         unifyArgs doc (t:ts) (TypeArrow ty1 ty2) =->           tcConstrTermFP m tcEnv sigs p t >>=->           unify p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           unifyArgs doc ts ty2->         unifyArgs _ _ _ = internalError "tcConstrTermFP"-> tcConstrTermFP m tcEnv sigs p t@(InfixFuncPattern t1 op t2) =->   tcConstrTermFP m tcEnv sigs p (FunctionPattern op [t1,t2])-> tcConstrTermFP m tcEnv sigs p r@(RecordPattern fs rt)->   | isJust rt =->     do->       ty <- tcConstrTermFP m tcEnv sigs p (fromJust rt)->       fts <- mapM (tcFieldPatt (tcConstrTermFP m tcEnv sigs) m) fs->       alpha <- freshVar id->	let rty = TypeRecord fts (Just alpha)->	unify p "record pattern" (ppConstrTerm 0 r) m ty rty->       return rty->   | otherwise =->     do->       fts <- mapM (tcFieldPatt (tcConstrTermFP m tcEnv sigs) m) fs->       return (TypeRecord fts Nothing)--> tcFieldPatt :: (Position -> ConstrTerm -> TcState Type) -> ModuleIdent->             -> Field ConstrTerm -> TcState (Ident,Type)-> tcFieldPatt tcPatt m f@(Field _ l t) =->   do->     tyEnv <- S.get->     let p = positionOfIdent l->     lty <- maybe (freshTypeVar->	             >>= (\lty' ->->		           S.modify->		             (bindLabel l (qualifyWith m (mkIdent "#Rec"))->		                        (polyType lty'))->		           >> return lty'))->	           (\ (ForAll _ lty') -> return lty')->	           (sureLabelType l tyEnv)->     ty <- tcPatt p t->     unify p "record" (text "Field:" <+> ppFieldPatt f) m lty ty->     return (l,ty)--> tcRhs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> Rhs -> TcState Type-> tcRhs m tcEnv tyEnv0 sigs (SimpleRhs p e ds) =->   do->     tcDecls m tcEnv sigs ds->     ty <- tcExpr m tcEnv sigs p e->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty-> tcRhs m tcEnv tyEnv0 sigs (GuardedRhs es ds) =->   do->     tcDecls m tcEnv sigs ds->     tcCondExprs m tcEnv tyEnv0 sigs es--> tcCondExprs :: ModuleIdent -> TCEnv -> ValueEnv -> SigEnv -> [CondExpr]->             -> TcState Type-> tcCondExprs m tcEnv tyEnv0 sigs es =->   do->     gty <- if length es > 1 then return boolType->                             else freshConstrained [successType,boolType]->     ty <- freshTypeVar->     tcCondExprs' gty ty es->   where tcCondExprs' gty ty [] = return ty->         tcCondExprs' gty ty (e:es) =->           tcCondExpr gty ty e >> tcCondExprs' gty ty es->         tcCondExpr gty ty (CondExpr p g e) =->           tcExpr m tcEnv sigs p g >>=->           unify p "guard" (ppExpr 0 g) m gty >>->           tcExpr m tcEnv sigs p e >>=->           checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 >>=->           unify p "guarded expression" (ppExpr 0 e) m ty--> tcExpr :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Expression->        -> TcState Type-> tcExpr m _ _ _ (Literal l) = tcLiteral m l-> tcExpr m tcEnv sigs p (Variable v) =->   case qualLookupTypeSig m v sigs of->     Just ty -> inst (expandPolyType m tcEnv ty)->     Nothing -> S.get >>= inst . funType m v-> tcExpr m tcEnv sigs p (Constructor c) = S.get >>= instExist . constrType m c-> tcExpr m tcEnv sigs p (Typed e sig) =->   do->     tyEnv0 <- S.get->     ty <- tcExpr m tcEnv sigs p e->     inst sigma' >>=->       flip (unify p "explicitly typed expression" (ppExpr 0 e) m) ty->     theta <- S.lift S.get->     let sigma = gen (fvEnv (subst theta tyEnv0)) (subst theta ty)->     unless (sigma == sigma')->       (errorAt p (typeSigTooGeneral m (text "Expression:" <+> ppExpr 0 e)->                  sig' sigma))->     return ty->   where sig' = nameSigType sig->         sigma' = expandPolyType m tcEnv sig'-> tcExpr m tcEnv sigs p (Paren e) = tcExpr m tcEnv sigs p e-> tcExpr m tcEnv sigs p (Tuple _ es)->   | null es = return unitType->   | otherwise = liftM tupleType $ mapM (tcExpr m tcEnv sigs p) es-> tcExpr m tcEnv sigs p e@(List _ es) = freshTypeVar >>= tcElems (ppExpr 0 e) es->   where tcElems _ [] ty = return (listType ty)->         tcElems doc (e:es) ty =->           tcExpr m tcEnv sigs p e >>=->           unify p "expression" (doc $-$ text "Term:" <+> ppExpr 0 e)->                 m ty >>->           tcElems doc es ty-> tcExpr m tcEnv sigs p (ListCompr _ e qs) =->   do->     tyEnv0 <- S.get->     mapM_ (tcQual m tcEnv sigs p) qs->     ty <- tcExpr m tcEnv sigs p e->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 (listType ty)-> tcExpr m tcEnv sigs p e@(EnumFrom e1) =->   do->     ty1 <- tcExpr m tcEnv sigs p e1->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1->     return (listType intType)-> tcExpr m tcEnv sigs p e@(EnumFromThen e1 e2) =->   do->     ty1 <- tcExpr m tcEnv sigs p e1->     ty2 <- tcExpr m tcEnv sigs p e2->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2->     return (listType intType)-> tcExpr m tcEnv sigs p e@(EnumFromTo e1 e2) =->   do->     ty1 <- tcExpr m tcEnv sigs p e1->     ty2 <- tcExpr m tcEnv sigs p e2->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2->     return (listType intType)-> tcExpr m tcEnv sigs p e@(EnumFromThenTo e1 e2 e3) =->   do->     ty1 <- tcExpr m tcEnv sigs p e1->     ty2 <- tcExpr m tcEnv sigs p e2->     ty3 <- tcExpr m tcEnv sigs p e3->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1) m intType ty1->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2) m intType ty2->     unify p "arithmetic sequence"->           (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e3) m intType ty3->     return (listType intType)-> tcExpr m tcEnv sigs p e@(UnaryMinus op e1) =->   do->     opTy <- opType op->     ty1 <- tcExpr m tcEnv sigs p e1->     unify p "unary negation" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)->           m opTy ty1->     return ty1->   where opType op->           | op == minusId = freshConstrained [intType,floatType]->           | op == fminusId = return floatType->           | otherwise = internalError ("tcExpr unary " ++ name op)-> tcExpr m tcEnv sigs p e@(Apply e1 e2) =->   do->     ty1 <- tcExpr m tcEnv sigs p e1->     ty2 <- tcExpr m tcEnv sigs p e2->     (alpha,beta) <-->       tcArrow p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)->               m ty1->     unify p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2)->           m alpha ty2->     return beta-> tcExpr m tcEnv sigs p e@(InfixApply e1 op e2) =->   do->     opTy <- tcExpr m tcEnv sigs p (infixOp op)->     ty1 <- tcExpr m tcEnv sigs p e1->     ty2 <- tcExpr m tcEnv sigs p e2->     (alpha,beta,gamma) <-->       tcBinary p "infix application"->                (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) m opTy->     unify p "infix application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)->           m alpha ty1->     unify p "infix application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e2)->           m beta ty2->     return gamma-> tcExpr m tcEnv sigs p e@(LeftSection e1 op) =->   do->     opTy <- tcExpr m tcEnv sigs p (infixOp op)->     ty1 <- tcExpr m tcEnv sigs p e1->     (alpha,beta) <-->       tcArrow p "left section" (ppExpr 0 e $-$ text "Operator:" <+> ppOp op)->               m opTy->     unify p "left section" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)->           m alpha ty1->     return beta-> tcExpr m tcEnv sigs p e@(RightSection op e1) =->   do->     opTy <- tcExpr m tcEnv sigs p (infixOp op)->     ty1 <- tcExpr m tcEnv sigs p e1->     (alpha,beta,gamma) <-->       tcBinary p "right section"->                (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) m opTy->     unify p "right section" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)->           m beta ty1->     return (TypeArrow alpha gamma)-> tcExpr m tcEnv sigs p exp@(Lambda r ts e) =->   do->     tyEnv0 <- S.get->     tys <- mapM (tcConstrTerm m tcEnv sigs p) ts->     ty <- tcExpr m tcEnv sigs p e->     checkSkolems p m (text "Expression:" <+> ppExpr 0 exp) tyEnv0->                  (foldr TypeArrow ty tys)-> tcExpr m tcEnv sigs p (Let ds e) =->   do->     tyEnv0 <- S.get->     theta <- S.lift S.get->     tcDecls m tcEnv sigs ds->     ty <- tcExpr m tcEnv sigs p e->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty-> tcExpr m tcEnv sigs p (Do sts e) =->   do->     tyEnv0 <- S.get->     mapM_ (tcStmt m tcEnv sigs p) sts->     alpha <- freshTypeVar->     ty <- tcExpr m tcEnv sigs p e->     unify p "statement" (ppExpr 0 e) m (ioType alpha) ty->     checkSkolems p m (text "Expression:" <+> ppExpr 0 e) tyEnv0 ty-> tcExpr m tcEnv sigs p e@(IfThenElse _ e1 e2 e3) =->   do->     ty1 <- tcExpr m tcEnv sigs p e1->     unify p "expression" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)->           m boolType ty1->     ty2 <- tcExpr m tcEnv sigs p e2->     ty3 <- tcExpr m tcEnv sigs p e3->     unify p "expression" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e3)->           m ty2 ty3->     return ty3-> tcExpr m tcEnv sigs p (Case _ e alts) =->   do->     tyEnv0 <- S.get->     ty <- tcExpr m tcEnv sigs p e->     alpha <- freshTypeVar->     tcAlts tyEnv0 ty alpha alts->   where tcAlts tyEnv0 _ ty [] = return ty->         tcAlts tyEnv0 ty1 ty2 (alt:alts) =->           tcAlt (ppAlt alt) tyEnv0 ty1 ty2 alt >> tcAlts tyEnv0 ty1 ty2 alts->         tcAlt doc tyEnv0 ty1 ty2 (Alt p t rhs) =->           tcConstrTerm m tcEnv sigs p t >>=->           unify p "case pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t)->                 m ty1 >>->           tcRhs m tcEnv tyEnv0 sigs rhs >>=->           unify p "case branch" doc m ty2-> tcExpr m tcEnv sigs p (RecordConstr fs) =->   do ->     fts <- mapM (tcFieldExpr m tcEnv sigs equals) fs->     --when (1 == length fs)->     --     (error (show fs ++ "\n" ++ show fts))->     return (TypeRecord fts Nothing)-> tcExpr m tcEnv sigs p r@(RecordSelection e l) =->   do->     ty <- tcExpr m tcEnv sigs p e->     tyEnv <- S.get->     lty <- maybe (freshTypeVar ->	             >>= (\lty' -> ->		           S.modify ->		             (bindLabel l (qualifyWith m (mkIdent "#Rec"))->		                        (monoType lty'))->	                   >> return lty'))->                  (\ (ForAll _ lty') -> return lty')->	           (sureLabelType l tyEnv)->     alpha <- freshVar id->     let rty = TypeRecord [(l,lty)] (Just alpha)->     unify p "record selection" (ppExpr 0 r) m ty rty->     return lty-> tcExpr m tcEnv sigs p r@(RecordUpdate fs e) =->   do->     ty <- tcExpr m tcEnv sigs p e->     fts <- mapM (tcFieldExpr m tcEnv sigs (text ":=")) fs->     alpha <- freshVar id->     let rty = TypeRecord fts (Just alpha)->     unify p "record update" (ppExpr 0 r) m ty rty->     return ty--> tcQual :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Statement->        -> TcState ()-> tcQual m tcEnv sigs p (StmtExpr _ e) =->   do->     ty <- tcExpr m tcEnv sigs p e->     unify p "guard" (ppExpr 0 e) m boolType ty-> tcQual m tcEnv sigs p q@(StmtBind _ t e) =->   do->     ty1 <- tcConstrTerm m tcEnv sigs p t->     ty2 <- tcExpr m tcEnv sigs p e->     unify p "generator" (ppStmt q $-$ text "Term:" <+> ppExpr 0 e)->           m (listType ty1) ty2-> tcQual m tcEnv sigs p (StmtDecl ds) = tcDecls m tcEnv sigs ds--> tcStmt :: ModuleIdent -> TCEnv -> SigEnv -> Position -> Statement->        -> TcState ()-> tcStmt m tcEnv sigs p (StmtExpr _ e) =->   do->     alpha <- freshTypeVar->     ty <- tcExpr m tcEnv sigs p e->     unify p "statement" (ppExpr 0 e) m (ioType alpha) ty-> tcStmt m tcEnv sigs p st@(StmtBind _ t e) =->   do->     ty1 <- tcConstrTerm m tcEnv sigs p t->     ty2 <- tcExpr m tcEnv sigs p e->     unify p "statement" (ppStmt st $-$ text "Term:" <+> ppExpr 0 e)->           m (ioType ty1) ty2-> tcStmt m tcEnv sigs p (StmtDecl ds) = tcDecls m tcEnv sigs ds--> tcFieldExpr :: ModuleIdent -> TCEnv -> SigEnv -> Doc -> Field Expression->	      -> TcState (Ident,Type)-> tcFieldExpr m tcEnv sigs comb f@(Field _ l e) =->   do->     tyEnv <- S.get->     let p = positionOfIdent l->     lty <- maybe (freshTypeVar ->	             >>= (\lty' -> ->		           S.modify ->		             (bindLabel l (qualifyWith m (mkIdent "#Rec"))->		                          (monoType lty'))->	                   >> return lty'))->                  inst->	           (sureLabelType l tyEnv)->     ty <- tcExpr m tcEnv sigs p e->     unify p "record" (text "Field:" <+> ppFieldExpr comb f) m lty ty->     return (l,ty)--\end{verbatim}-The function \texttt{tcArrow} checks that its argument can be used as-an arrow type $\alpha\rightarrow\beta$ and returns the pair-$(\alpha,\beta)$. Similarly, the function \texttt{tcBinary} checks-that its argument can be used as an arrow type-$\alpha\rightarrow\beta\rightarrow\gamma$ and returns the triple-$(\alpha,\beta,\gamma)$.-\begin{verbatim}--> tcArrow :: Position -> String -> Doc -> ModuleIdent -> Type->         -> TcState (Type,Type)-> tcArrow p what doc m ty =->   do->     theta <- S.lift S.get->     unaryArrow (subst theta ty)->   where unaryArrow (TypeArrow ty1 ty2) = return (ty1,ty2)->         unaryArrow (TypeVariable tv) =->           do->             alpha <- freshTypeVar->             beta <- freshTypeVar->             S.lift (S.modify (bindVar tv (TypeArrow alpha beta)))->             return (alpha,beta)->         unaryArrow ty = errorAt p (nonFunctionType what doc m ty)--> tcBinary :: Position -> String -> Doc -> ModuleIdent -> Type->          -> TcState (Type,Type,Type)-> tcBinary p what doc m ty = tcArrow p what doc m ty >>= uncurry binaryArrow->   where binaryArrow ty1 (TypeArrow ty2 ty3) = return (ty1,ty2,ty3)->         binaryArrow ty1 (TypeVariable tv) =->           do->             beta <- freshTypeVar->             gamma <- freshTypeVar->             S.lift (S.modify (bindVar tv (TypeArrow beta gamma)))->             return (ty1,beta,gamma)->         binaryArrow ty1 ty2 =->           errorAt p (nonBinaryOp what doc m (TypeArrow ty1 ty2))--\end{verbatim}-\paragraph{Unification}-The unification uses Robinson's algorithm (cf., e.g., Chap.~9-of~\cite{PeytonJones87:Book}).-\begin{verbatim}--> unify :: Position -> String -> Doc -> ModuleIdent -> Type -> Type->       -> TcState ()-> unify p what doc m ty1 ty2 =->   S.lift $->   do->     theta <- S.get->     let ty1' = subst theta ty1->     let ty2' = subst theta ty2->     either (errorAt p . typeMismatch what doc m ty1' ty2')->            (S.modify . compose)->            (unifyTypes m ty1' ty2')--> unifyTypes :: ModuleIdent -> Type -> Type -> Either Doc TypeSubst-> unifyTypes _ (TypeVariable tv1) (TypeVariable tv2)->   | tv1 == tv2 = Right idSubst->   | otherwise = Right (bindSubst tv1 (TypeVariable tv2) idSubst)-> unifyTypes m (TypeVariable tv) ty->   | tv `elem` typeVars ty = Left (recursiveType m tv ty)->   | otherwise = Right (bindSubst tv ty idSubst)-> unifyTypes m ty (TypeVariable tv)->   | tv `elem` typeVars ty = Left (recursiveType m tv ty)->   | otherwise = Right (bindSubst tv ty idSubst)-> unifyTypes _ (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2)->   | tv1 == tv2 = Right idSubst->   | tys1 == tys2 = Right (bindSubst tv1 (TypeConstrained tys2 tv2) idSubst)-> unifyTypes m (TypeConstrained tys tv) ty =->   foldr (choose . unifyTypes m ty) (Left (incompatibleTypes m ty (head tys)))->         tys->   where choose (Left _) theta' = theta'->         choose (Right theta) _ = Right (bindSubst tv ty theta)-> unifyTypes m ty (TypeConstrained tys tv) =->   foldr (choose . unifyTypes m ty) (Left (incompatibleTypes m ty (head tys)))->         tys->   where choose (Left _) theta' = theta'->         choose (Right theta) _ = Right (bindSubst tv ty theta)-> unifyTypes m (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2)->   | tc1 == tc2 = unifyTypeLists m tys1 tys2-> unifyTypes m (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) =->   unifyTypeLists m [ty11,ty12] [ty21,ty22]-> unifyTypes _ (TypeSkolem k1) (TypeSkolem k2)->   | k1 == k2 = Right idSubst-> unifyTypes m (TypeRecord fs1 Nothing) tr2@(TypeRecord fs2 Nothing)->   | length fs1 == length fs2 = unifyTypedLabels m fs1 tr2-> unifyTypes m tr1@(TypeRecord fs1 Nothing) tr2@(TypeRecord fs2 (Just a2)) =->   either Left->          (\res -> either Left ->	                   (Right . compose res) ->                          (unifyTypes m (TypeVariable a2) tr1))->          (unifyTypedLabels m fs2 tr1)-> unifyTypes m tr1@(TypeRecord _ (Just _)) tr2@(TypeRecord _ Nothing) =->   unifyTypes m tr2 tr1-> unifyTypes m (TypeRecord fs1 (Just a1)) tr2@(TypeRecord fs2 (Just a2)) =->   let (fs1', rs1, rs2) = splitFields fs1 fs2->   in  either ->         Left->         (\res -> ->           either ->             Left ->	      (\res' -> Right (compose res res'))->	      (unifyTypeLists m [TypeVariable a1,->			         TypeRecord (fs1 ++ rs2) Nothing]->	                        [TypeVariable a2,->			         TypeRecord (fs2 ++ rs1) Nothing]))->         (unifyTypedLabels m fs1' tr2)->   where->   splitFields fs1 fs2 = split' [] [] fs2 fs1->   split' fs1' rs1 rs2 [] = (fs1',rs1,rs2)->   split' fs1' rs1 rs2 ((l,ty):fs1) =->     maybe (split' fs1' ((l,ty):rs1) rs2 fs1)->           (const (split' ((l,ty):fs1') rs1 (remove l rs2) fs1))->           (lookup l rs2)-> unifyTypes m ty1 ty2 = Left (incompatibleTypes m ty1 ty2)--> unifyTypeLists :: ModuleIdent -> [Type] -> [Type] -> Either Doc TypeSubst-> unifyTypeLists _ [] _ = Right idSubst-> unifyTypeLists _ _ [] = Right idSubst-> unifyTypeLists m (ty1:tys1) (ty2:tys2) =->   either Left (unifyTypesTheta m ty1 ty2) (unifyTypeLists m tys1 tys2)->   where unifyTypesTheta m ty1 ty2 theta =->           either Left (Right . flip compose theta)->                  (unifyTypes m (subst theta ty1) (subst theta ty2))--> unifyTypedLabels :: ModuleIdent -> [(Ident,Type)] -> Type ->	           -> Either Doc TypeSubst-> unifyTypedLabels m [] (TypeRecord _ _) = Right idSubst-> unifyTypedLabels m ((l,ty):fs1) tr@(TypeRecord fs2 _) =->   either Left->          (\r -> ->            maybe (Left (missingLabel m l tr))->                  (\ty' -> ->		     either (const (Left (incompatibleLabelTypes m l ty ty')))->	                    (Right . flip compose r)->	                    (unifyTypes m ty ty'))->                  (lookup l fs2))->          (unifyTypedLabels m fs1 tr)-> unifyTypedLabels _ _ _ = internalError "unifyTypedLabels"--\end{verbatim}-For each declaration group, the type checker has to ensure that no-skolem type escapes its scope.-\begin{verbatim}--> checkSkolems :: Position -> ModuleIdent -> Doc -> ValueEnv -> Type->              -> TcState Type-> checkSkolems p m what tyEnv ty =->   do->     theta <- S.lift S.get->     let ty' = subst theta ty->         fs = fsEnv (subst theta tyEnv)->     unless (all (`Set.member` fs) (typeSkolems ty'))->            (errorAt p (skolemEscapingScope m what ty'))->     --error (show ty ++ " ## " ++ show (subst theta ty))->     return ty'--\end{verbatim}-\paragraph{Instantiation and Generalization}-We use negative offsets for fresh type variables.-\begin{verbatim}--> fresh :: (Int -> a) -> TcState a-> fresh f = liftM f (S.lift (S.lift (S.modify succ >> S.get)))--> freshVar :: (Int -> a) -> TcState a-> freshVar f = fresh (\n -> f (- n - 1))--> freshTypeVar :: TcState Type-> freshTypeVar = freshVar TypeVariable--> freshConstrained :: [Type] -> TcState Type-> freshConstrained tys = freshVar (TypeConstrained tys)--> freshSkolem :: TcState Type-> freshSkolem = fresh TypeSkolem--> inst :: TypeScheme -> TcState Type-> inst (ForAll n ty) =->   do->     tys <- replicateM n freshTypeVar->     return (expandAliasType tys ty)--> instExist :: ExistTypeScheme -> TcState Type-> instExist (ForAllExist n n' ty) =->   do->     tys <- replicateM (n + n') freshTypeVar->     return (expandAliasType tys ty)--> skol :: ExistTypeScheme -> TcState Type-> skol (ForAllExist n n' ty) =->   do->     tys <- replicateM n freshTypeVar->     tys' <- replicateM n' freshSkolem->     return (expandAliasType (tys ++ tys') ty)--> gen :: Set.Set Int -> Type -> TypeScheme-> gen gvs ty =->   ForAll (length tvs) (subst (foldr2 bindSubst idSubst tvs tvs') ty)->   where tvs = [tv | tv <- nub (typeVars ty), tv `Set.notMember` gvs]->         tvs' = map TypeVariable [0..]--\end{verbatim}-\paragraph{Auxiliary Functions}-The functions \texttt{constrType}, \texttt{varType}, and-\texttt{funType} are used to retrieve the type of constructors,-pattern variables, and variables in expressions, respectively, from-the type environment. Because the syntactical correctness has already-been verified by the syntax checker, none of these functions should-fail.--Note that \texttt{varType} can handle ambiguous identifiers and-returns the first available type. This function is used for looking up-the type of an identifier on the left hand side of a rule where it-unambiguously refers to the local definition.-\begin{verbatim}--> constrType :: ModuleIdent -> QualIdent -> ValueEnv -> ExistTypeScheme-> constrType m c tyEnv =->   case qualLookupValue c tyEnv of->     [DataConstructor _ sigma] -> sigma->     [NewtypeConstructor _ sigma] -> sigma->     _ -> case (qualLookupValue (qualQualify m c) tyEnv) of->            [DataConstructor _ sigma] -> sigma->            [NewtypeConstructor _ sigma] -> sigma->            _ -> internalError ("constrType " ++ show c)--> varType :: Ident -> ValueEnv -> TypeScheme-> varType v tyEnv =->   case lookupValue v tyEnv of->     Value _ sigma : _ -> sigma->     _ -> internalError ("varType " ++ show v)--> sureVarType :: Ident -> ValueEnv -> Maybe TypeScheme-> sureVarType v tyEnv =->   case lookupValue v tyEnv of->     Value _ sigma : _ -> Just sigma->     _ -> Nothing--> funType :: ModuleIdent -> QualIdent -> ValueEnv -> TypeScheme-> funType m f tyEnv =->   case (qualLookupValue f tyEnv) of->     [Value _ sigma] -> sigma->     vs -> case (qualLookupValue (qualQualify m f) tyEnv) of->             [Value _ sigma] -> sigma->             _ -> internalError ("funType " ++ show f)--> sureLabelType :: Ident -> ValueEnv -> Maybe TypeScheme-> sureLabelType l tyEnv =->   case lookupValue l tyEnv of->     Label _ _ sigma : _ -> Just sigma->     _ -> Nothing---\end{verbatim}-The function \texttt{expandType} expands all type synonyms in a type-and also qualifies all type constructors with the name of the module-in which the type was defined.-\begin{verbatim}--> expandMonoType :: ModuleIdent -> TCEnv -> [Ident] -> TypeExpr -> Type-> expandMonoType m tcEnv tvs ty = expandType m tcEnv (toType tvs ty)--> expandMonoTypes :: ModuleIdent -> TCEnv -> [Ident] -> [TypeExpr] -> [Type]-> expandMonoTypes m tcEnv tvs tys = map (expandType m tcEnv) (toTypes tvs tys)--> expandPolyType :: ModuleIdent -> TCEnv -> TypeExpr -> TypeScheme-> expandPolyType m tcEnv ty = ->     polyType $ normalize $ expandMonoType m tcEnv [] ty--> expandType :: ModuleIdent -> TCEnv -> Type -> Type-> expandType m tcEnv (TypeConstructor tc tys) =->   case qualLookupTC tc tcEnv of->     [DataType tc' _ _] -> TypeConstructor tc' tys'->     [RenamingType tc' _ _] -> TypeConstructor tc' tys'->     [AliasType _ _ ty] -> expandAliasType tys' ty->     _ -> case (qualLookupTC (qualQualify m tc) tcEnv) of->            [DataType tc' _ _] -> TypeConstructor tc' tys'->            [RenamingType tc' _ _] -> TypeConstructor tc' tys'->            [AliasType _ _ ty] -> expandAliasType tys' ty->            _ -> internalError ("expandType " ++ show tc)->   where tys' = map (expandType m tcEnv) tys-> expandType _ _ (TypeVariable tv) = TypeVariable tv-> expandType _ _ (TypeConstrained tys tv) = TypeConstrained tys tv-> expandType m tcEnv (TypeArrow ty1 ty2) =->   TypeArrow (expandType m tcEnv ty1) (expandType m tcEnv ty2)-> expandType _ tcEnv (TypeSkolem k) = TypeSkolem k-> expandType m tcEnv (TypeRecord fs rv) =->   TypeRecord (map (\ (l,ty) -> (l, expandType m tcEnv ty)) fs) rv--\end{verbatim}-The functions \texttt{fvEnv} and \texttt{fsEnv} compute the set of-free type variables and free skolems of a type environment,-respectively. We ignore the types of data constructors here because we-know that they are closed.-\begin{verbatim}--> fvEnv :: ValueEnv -> Set.Set Int-> fvEnv tyEnv =->   Set.fromList [tv | ty <- localTypes tyEnv, tv <- typeVars ty, tv < 0]--> fsEnv :: ValueEnv -> Set.Set Int-> fsEnv tyEnv = Set.unions (map (Set.fromList . typeSkolems) (localTypes tyEnv))--> localTypes :: ValueEnv -> [Type]-> localTypes tyEnv = [ty | (_,Value _ (ForAll _ ty)) <- localBindings tyEnv]--\end{verbatim}-Miscellaneous functions.-\begin{verbatim}--> remove :: Eq a => a -> [(a,b)] -> [(a,b)]-> remove _ [] = []-> remove k ((k',e):kes) | k == k'   = kes->		        | otherwise = (k',e):(remove k kes) --\end{verbatim}-Error functions.-\begin{verbatim}--> recursiveTypes :: [Ident] -> (Position,String)-> recursiveTypes [tc] = ->     (positionOfIdent tc,->      "Recursive synonym type " ++ name tc)-> recursiveTypes (tc:tcs) =->  (positionOfIdent tc,->   "Recursive synonym types " ++ name tc ++ types "" tcs)->   where types comma [tc] = comma ++ " and " ++ name tc ++->                            showLine (positionOfIdent tc) ->         types _ (tc:tcs) = ", " ++ name tc ++ ->                            showLine (positionOfIdent tc) ++ ->                            types "," tcs--> polymorphicFreeVar :: Ident -> (Position,String)-> polymorphicFreeVar v =->  (positionOfIdent v,->   "Free variable " ++ name v ++ " has a polymorphic type")--> typeSigTooGeneral :: ModuleIdent -> Doc -> TypeExpr -> TypeScheme -> String-> typeSigTooGeneral m what ty sigma = show $->   vcat [text "Type signature too general", what,->         text "Inferred type:" <+> ppTypeScheme m sigma,->         text "Type signature:" <+> ppTypeExpr 0 ty]--> nonFunctionType :: String -> Doc -> ModuleIdent -> Type -> String-> nonFunctionType what doc m ty = show $->   vcat [text "Type error in" <+> text what, doc,->         text "Type:" <+> ppType m ty,->         text "Cannot be applied"]--> nonBinaryOp :: String -> Doc -> ModuleIdent -> Type -> String-> nonBinaryOp what doc m ty = show $->   vcat [text "Type error in" <+> text what, doc,->         text "Type:" <+> ppType m ty,->         text "Cannot be used as binary operator"]--> typeMismatch :: String -> Doc -> ModuleIdent -> Type -> Type -> Doc -> String-> typeMismatch what doc m ty1 ty2 reason = show $->   vcat [text "Type error in" <+> text what, doc,->         text "Inferred type:" <+> ppType m ty2,->         text "Expected type:" <+> ppType m ty1,->         reason]--> skolemEscapingScope :: ModuleIdent -> Doc -> Type -> String-> skolemEscapingScope m what ty = show $->   vcat [text "Existential type escapes out of its scope", what,->         text "Type:" <+> ppType m ty]--> recursiveType :: ModuleIdent -> Int -> Type -> Doc-> recursiveType m tv ty = incompatibleTypes m (TypeVariable tv) ty--> missingLabel :: ModuleIdent -> Ident -> Type -> Doc-> missingLabel m l rty =->   sep [text "Missing field for label" <+> ppIdent l,->        text "in the record type" <+> ppType m rty]--> incompatibleTypes :: ModuleIdent -> Type -> Type -> Doc-> incompatibleTypes m ty1 ty2 =->   sep [text "Types" <+> ppType m ty1,->        nest 2 (text "and" <+> ppType m ty2),->        text "are incompatible"]--> incompatibleLabelTypes :: ModuleIdent -> Ident -> Type -> Type -> Doc-> incompatibleLabelTypes m l ty1 ty2 =->   sep [text "Labeled types" <+> ppIdent l <> text "::" <> ppType m ty1,->        nest 10 (text "and" <+> ppIdent l <> text "::" <> ppType m ty2),->        text "are incompatible"]--\end{verbatim}---\end{verbatim}-The following functions implement pretty-printing for types.-\begin{verbatim}--> ppType :: ModuleIdent -> Type -> Doc-> ppType m = ppTypeExpr 0 . fromQualType m--> ppTypeScheme :: ModuleIdent -> TypeScheme -> Doc-> ppTypeScheme m (ForAll _ ty) = ppType m ty
− src/TypeSubst.lhs
@@ -1,104 +0,0 @@--% $Id: TypeSubst.lhs,v 1.2 2004/02/08 22:14:01 wlux Exp $-%-% Copyright (c) 2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{TypeSubst.lhs}-\section{Type Substitutions}-This module implements substitutions on types.-\begin{verbatim}--> module TypeSubst(module TypeSubst, idSubst,bindSubst,compose) where---> import Data.Maybe-> import Data.List--> import Types--> import Subst-> import Base-> import TopEnv--> type TypeSubst = Subst Int Type--> class SubstType a where->   subst :: TypeSubst -> a -> a--> bindVar :: Int -> Type -> TypeSubst -> TypeSubst-> bindVar tv ty = compose (bindSubst tv ty idSubst)--> substVar :: TypeSubst -> Int -> Type-> substVar = substVar' TypeVariable subst--> instance SubstType Type where->   subst sigma (TypeConstructor tc tys) =->     TypeConstructor tc (map (subst sigma) tys)->   subst sigma (TypeVariable tv) = substVar sigma tv->   subst sigma (TypeConstrained tys tv) =->     case substVar sigma tv of->       TypeVariable tv -> TypeConstrained tys tv->       ty -> ty->   subst sigma (TypeArrow ty1 ty2) =->     TypeArrow (subst sigma ty1) (subst sigma ty2)->   subst sigma (TypeSkolem k) = TypeSkolem k->   subst sigma (TypeRecord fs rv)->     | isJust rv =->       case substVar sigma (fromJust rv) of->         TypeVariable tv -> TypeRecord fs' (Just tv)->         ty -> ty->     | otherwise = TypeRecord fs' Nothing->    where fs' = map (\ (l,ty) -> (l, subst sigma ty)) fs--> instance SubstType TypeScheme where->   subst sigma (ForAll n ty) =->     ForAll n (subst (foldr unbindSubst sigma [0..n-1]) ty)--> instance SubstType ExistTypeScheme where->   subst sigma (ForAllExist n n' ty) =->     ForAllExist n n' (subst (foldr unbindSubst sigma [0..n+n'-1]) ty)--> instance SubstType ValueInfo where->   subst theta (DataConstructor c ty) = DataConstructor c ty->   subst theta (NewtypeConstructor c ty) = NewtypeConstructor c ty->   subst theta (Value v ty) = Value v (subst theta ty)->   subst theta (Label l r ty) = Label l r (subst theta ty)--> instance SubstType a => SubstType (TopEnv a) where->   subst = fmap . subst--\end{verbatim}-The function \texttt{expandAliasType} expands all occurrences of a-type synonym in a type. After the expansion we have to reassign the-type indices for all type variables. Otherwise, expanding a type-synonym like \verb|type Pair' a b = (b,a)| could break the invariant-that the universally quantified type variables are assigned indices in-the order of their occurrence. This is handled by the function-\texttt{normalize}.-\begin{verbatim}--> expandAliasType :: [Type] -> Type -> Type-> expandAliasType tys (TypeConstructor tc tys') =->   TypeConstructor tc (map (expandAliasType tys) tys')-> expandAliasType tys (TypeVariable n)->   | n >= 0 = tys !! n->   | otherwise = TypeVariable n-> expandAliasType _ (TypeConstrained tys n) = TypeConstrained tys n-> expandAliasType tys (TypeArrow ty1 ty2) =->   TypeArrow (expandAliasType tys ty1) (expandAliasType tys ty2)-> expandAliasType _ (TypeSkolem k) = TypeSkolem k-> expandAliasType tys (TypeRecord fs rv)->   | isJust rv =->     let (TypeVariable tv) = expandAliasType tys (TypeVariable (fromJust rv))->     in  TypeRecord fs' (Just tv)->   | otherwise =->     TypeRecord fs' Nothing->  where fs' = map (\ (l,ty) -> (l, expandAliasType tys ty)) fs--> normalize :: Type -> Type-> normalize ty = expandAliasType [TypeVariable (occur tv) | tv <- [0..]] ty->   where tvs = zip (nub (filter (>= 0) (typeVars ty))) [0..]->         occur tv = fromJust (lookup tv tvs)--\end{verbatim}
− src/Types.lhs
@@ -1,251 +0,0 @@-% $Id: Types.lhs,v 1.11 2004/02/08 22:14:02 wlux Exp $-%-% Copyright (c) 2002, Wolfgang Lux-% See LICENSE for the full license.-%-% Modified by Martin Engelke (men@informatik.uni-kiel.de)-%-\nwfilename{Types.lhs}-\section{Types}-This module modules provides the definitions for the internal -representation of types in the compiler.-\begin{verbatim}--> module Types where--> import Data.List-> import Data.Maybe--> import Curry.Base.Ident--\end{verbatim}-A type is either a type variable, an application of a type constructor-to a list of arguments, or an arrow type. The \texttt{TypeConstrained}-case is used for representing type variables that are restricted to a-particular set of types. At present, this is used for typing guard-expressions, which are restricted to be either of type \texttt{Bool}-or of type \texttt{Success}, and integer literals, which are-restricted to types \texttt{Int} and \texttt{Float}. If the type is-not restricted it defaults to the first type from the constraint list.-The case \texttt{TypeSkolem} is used for handling skolem types, which-result from the use of existentially quantified data constructors.--Type variables are represented with deBruijn style indices. Universally-quantified type variables are assigned indices in the order of their-occurrence in the type from left to right. This leads to a canonical-representation of types where $\alpha$-equivalence of two types-coincides with equality of the representation.--Note that even though \texttt{TypeConstrained} variables use indices-as well, these variables must never be quantified.-\begin{verbatim}--> data Type =->     TypeConstructor QualIdent [Type]->   | TypeVariable Int->   | TypeConstrained [Type] Int->   | TypeArrow Type Type->   | TypeSkolem Int->   | TypeRecord [(Ident,Type)] (Maybe Int)->   deriving (Show, Eq)--\end{verbatim}-The function \texttt{isArrowType} checks whether a type is a function-type $t_1 \rightarrow t_2 \rightarrow \dots \rightarrow t_n$ . The-function \texttt{arrowArity} computes the arity $n$ of a function type-and \texttt{arrowBase} returns the type $t_n$.-\begin{verbatim}--> isArrowType :: Type -> Bool-> isArrowType (TypeArrow _ _) = True-> isArrowType _ = False--> arrowArity :: Type -> Int-> arrowArity (TypeArrow _ ty) = 1 + arrowArity ty-> arrowArity _ = 0--> arrowArgs :: Type -> [Type]-> arrowArgs (TypeArrow ty1 ty2) = ty1 : arrowArgs ty2-> arrowArgs ty = []--> arrowBase :: Type -> Type-> arrowBase (TypeArrow _ ty) = arrowBase ty-> arrowBase ty = ty--\end{verbatim}-The functions \texttt{typeVars}, \texttt{typeConstrs},-\texttt{typeSkolems} return a list of all type variables, type-constructors, or skolems occurring in a type $t$, respectively. Note-that \texttt{TypeConstrained} variables are not included in the set of-type variables because they cannot be generalized.-\begin{verbatim}--> typeVars :: Type -> [Int]-> typeVars ty = vars ty []->   where vars (TypeConstructor _ tys) tvs = foldr vars tvs tys->         vars (TypeVariable tv) tvs = tv : tvs->         vars (TypeConstrained _ _) tvs = tvs->         vars (TypeArrow ty1 ty2) tvs = vars ty1 (vars ty2 tvs)->         vars (TypeSkolem _) tvs = tvs->         vars (TypeRecord fs rtv) tvs =->             foldr vars (maybe tvs (: tvs) rtv) (map snd fs)--> typeConstrs :: Type -> [QualIdent]-> typeConstrs ty = types ty []->   where types (TypeConstructor tc tys) tcs = tc : foldr types tcs tys->         types (TypeVariable _) tcs = tcs->         types (TypeConstrained _ _) tcs = tcs->         types (TypeArrow ty1 ty2) tcs = types ty1 (types ty2 tcs)->         types (TypeSkolem _) tcs = tcs->         types (TypeRecord fs _) tcs =->             foldr types tcs (map snd fs)--> typeSkolems :: Type -> [Int]-> typeSkolems ty = skolems ty []->   where skolems (TypeConstructor _ tys) sks = foldr skolems sks tys->         skolems (TypeVariable _) sks = sks->         skolems (TypeConstrained _ _) sks = sks->         skolems (TypeArrow ty1 ty2) sks = skolems ty1 (skolems ty2 sks)->         skolems (TypeSkolem k) sks = k : sks->         skolems (TypeRecord fs _) sks =->             foldr skolems sks (map snd fs)--> equTypes :: Type -> Type -> Bool-> equTypes t1 t2 = fst (equ [] t1 t2)->  where ->  equ is (TypeConstructor qid1 ts1) (TypeConstructor qid2 ts2)->     | qid1 == qid2 = equs is ts1 ts2->     | otherwise    = (False, is)->  equ is (TypeVariable i1) (TypeVariable i2)->     = maybe (True, (i1,i2):is) ->             (\ i2' -> (i2 == i2', is))->             (lookup i1 is)->  equ is (TypeConstrained ts1 i1) (TypeConstrained ts2 i2)->     = let (res, is') = equs is ts1 ts2->       in  maybe (res, (i1,i2):is')->                 (\ i2' -> (res && i2 == i2', is'))->                 (lookup i1 is')->  equ is (TypeArrow tf1 tt1) (TypeArrow tf2 tt2)->     = let (res1, is1) = equ is tf1 tf2->           (res2, is2) = equ is1 tt1 tt2->       in  (res1 && res2, is2)->  equ is (TypeSkolem i1) (TypeSkolem i2)->     = maybe (True, (i1,i2):is)->             (\ i2' -> (i2 == i2', is))->             (lookup i1 is)->  equ is (TypeRecord fs1 r1) (TypeRecord fs2 r2)->     | isJust r1 && isJust r2->       = let (res1, is1) = equ is (TypeVariable (fromJust r1))->		                   (TypeVariable (fromJust r2))->             (res2, is2) = equRecords is1 fs1 fs2->         in  (res1 && res2, is2)->     | isNothing r1 && isNothing r2 = equRecords is fs1 fs2->     | otherwise = (False, is)->  equ is _ _ = (False, is)->	->  equRecords is fs1 fs2 | length fs1 == length fs2 = equrec is fs1 fs2->		         | otherwise = (False, is)->    where->    equrec is [] fs2 = (True, is)->    equrec is ((l,t):fs1) fs2->       = let (res1, is1) = maybe (False,is) (equ is t) (lookup l fs2)->             (res2, is2) = equrec is1 fs1 fs2->         in  (res1 && res2, is2)->->  equs is [] [] = (True, is)->  equs is (t1:ts1) (t2:ts2)->     = let (res1, is1) = equ is t1 t2->           (res2, is2) = equs is1 ts1 ts2->       in  (res1 && res2, is2)--\end{verbatim}-We support two kinds of quantifications of types here, universally-quantified type schemes $\forall\overline{\alpha} .-\tau(\overline{\alpha})$ and universally and existentially quantified-type schemes $\forall\overline{\alpha} \exists\overline{\eta} .-\tau(\overline{\alpha},\overline{\eta})$.  In both, quantified type-variables are assigned ascending indices starting from 0. Therefore it-is sufficient to record the numbers of quantified type variables in-the \texttt{ForAll} and \texttt{ForAllExist} constructors. In case of-the latter, the first of the two numbers is the number of universally-quantified variables and the second the number of existentially-quantified variables.-\begin{verbatim}--> data TypeScheme = ForAll Int Type deriving (Show, Eq)-> data ExistTypeScheme = ForAllExist Int Int Type deriving (Show, Eq)--\end{verbatim}-The functions \texttt{monoType} and \texttt{polyType} translate a type-$\tau$ into a monomorphic type scheme $\forall.\tau$ and a polymorphic-type scheme $\forall\overline{\alpha}.\tau$ where $\overline{\alpha} =-\textrm{fv}(\tau)$, respectively. \texttt{polyType} assumes that all-universally quantified variables in the type are assigned indices-starting with 0 and does not renumber the variables.-\begin{verbatim}--> monoType, polyType :: Type -> TypeScheme-> monoType ty = ForAll 0 ty-> polyType ty = ForAll (maximum (-1 : typeVars ty) + 1) ty--\end{verbatim}-There are a few predefined types:-\begin{verbatim}--> unitType,boolType,charType,intType,floatType,stringType,successType :: Type-> unitType = primType unitId []-> boolType = primType boolId []-> charType = primType charId []-> intType = primType intId []-> floatType = primType floatId []-> stringType = listType charType-> successType = primType successId []--> listType,ioType :: Type -> Type-> listType ty = primType listId [ty]-> ioType ty = primType ioId [ty]--> tupleType :: [Type] -> Type-> tupleType tys = primType (tupleId (length tys)) tys--> primType :: Ident -> [Type] -> Type-> primType = TypeConstructor . qualifyWith preludeMIdent--> typeVar :: Int -> Type-> typeVar = TypeVariable--\end{verbatim}----> qualifyType :: ModuleIdent -> Type -> Type-> qualifyType m (TypeConstructor tc tys)->   | isTupleId tc' = tupleType tys'->   | tc' == unitId && n == 0 = unitType->   | tc' == listId && n == 1 = listType (head tys')->   | otherwise = TypeConstructor (qualQualify m tc) tys'->   where n = length tys'->         tc' = unqualify tc->         tys' = map (qualifyType m) tys-> qualifyType _ (TypeVariable tv) = TypeVariable tv-> qualifyType m (TypeConstrained tys tv) =->   TypeConstrained (map (qualifyType m) tys) tv-> qualifyType m (TypeArrow ty1 ty2) =->   TypeArrow (qualifyType m ty1) (qualifyType m ty2)-> qualifyType _ (TypeSkolem k) = TypeSkolem k-> qualifyType m (TypeRecord fs rty) =->   TypeRecord (map (\ (l,ty) -> (l, qualifyType m ty)) fs) rty---> unqualifyType :: ModuleIdent -> Type -> Type-> unqualifyType m (TypeConstructor tc tys) =->   TypeConstructor (qualUnqualify m tc) (map (unqualifyType m) tys)-> unqualifyType _ (TypeVariable tv) = TypeVariable tv-> unqualifyType m (TypeConstrained tys tv) =->   TypeConstrained (map (unqualifyType m) tys) tv-> unqualifyType m (TypeArrow ty1 ty2) =->   TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)-> unqualifyType m (TypeSkolem k) = TypeSkolem k-> unqualifyType m (TypeRecord fs rty) =->   TypeRecord (map (\ (l,ty) -> (l, unqualifyType m ty)) fs) rty-
− src/Typing.lhs
@@ -1,406 +0,0 @@--% $Id: Typing.lhs,v 1.7 2004/02/12 19:13:12 wlux Exp $-%-% Copyright (c) 2003-2006, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Typing.lhs}-\section{Computing the Type of Curry Expressions}-\begin{verbatim}--> module Typing(Typeable(..)) where--> import Data.Maybe-> import Control.Monad-> import Control.Monad.State as S--> import Curry.Base.Ident-> import Curry.Syntax-> import Curry.Syntax.Utils--> import Types-> import Base-> import TypeSubst-> import TopEnv-> import Utils---\end{verbatim}-During the transformation of Curry source code into the intermediate-language, the compiler has to recompute the types of expressions. This-is simpler than type checking because the types of all variables are-known. Yet, the compiler still must handle functions and constructors-with polymorphic types and instantiate their type schemes using fresh-type variables. Since all types computed by \texttt{typeOf} are-monomorphic, we can use type variables with non-negative offsets for-the instantiation of type schemes here without risk of name conflicts.-Using non-negative offsets also makes it easy to distinguish these-fresh variables from free type variables introduce during type-inference, which must be regarded as constants here.--However, using non-negative offsets for fresh type variables gives-rise to two problems when those types are entered back into the type-environment, e.g., while introducing auxiliary variables during-desugaring. The first is that those type variables now appear to be-universally quantified variables, but with indices greater than the-number of quantified type variables.\footnote{To be precise, this can-  happen only for auxiliary variables, which have monomorphic types,-  whereas auxiliary functions will be assigned polymorphic types and-  these type variables will be properly quantified. However, in this-  case the assigned types may be too general.} This results in an-internal error (``Prelude.!!: index too large'') whenever such a type-is instantiated. The second problem is that there may be inadvertent-name captures because \texttt{computeType} always uses indices-starting at 0 for the fresh type variables. In order to avoid these-problems, \texttt{computeType} renames all type variables with-non-negative offsets after the final type has been computed, using-negative indices below the one with the smallest value occurring in-the type environment. Computing the minimum index of all type-variables in the type environment seems prohibitively inefficient.-However, recall that, thanks to laziness, the minimum is computed only-when the final type contains any type variables with non-negative-indices. This happens, for instance, 36 times while compiling the-prelude (for 159 evaluated applications of \texttt{typeOf}) and only-twice while compiling the standard \texttt{IO} module (for 21-applications of \texttt{typeOf}).\footnote{These numbers were obtained-  for version 0.9.9.}--A careful reader will note that inadvertent name captures are still-possible if one computes the types of two or more auxiliary variables-before actually entering their types into the environment. Therefore,-make sure that you enter the types of these auxiliary variables-immediately into the type environment, unless you are sure that those-types cannot contain fresh type variables. One such case are the free-variables of a goal.--\ToDo{In the long run, this module should be made obsolete by adding-attributes to the abstract syntax tree -- e.g., along the lines of-Chap.~6 in~\cite{PeytonJonesLester92:Book} -- and returning an-abstract syntax tree attributed with type information together with-the type environment from type inference. This also would allow-getting rid of the identifiers in the representation of integer-literals, which are used in order to implement overloading of-integer constants.}--\ToDo{When computing the type of an expression with a type signature-make use of the annotation instead of recomputing its type. In order-to do this, we must either ensure that the types are properly-qualified and expanded or we need access to the type constructor-environment.}-\begin{verbatim}--> type TyState a = S.StateT TypeSubst (S.State Int) a--> run :: TyState a -> ValueEnv -> a-> run m tyEnv = S.evalState (S.evalStateT m idSubst) 0--> class Typeable a where->   typeOf :: ValueEnv -> a -> Type--> instance Typeable Ident where->   typeOf = computeType identType--> instance Typeable ConstrTerm where->   typeOf = computeType argType--> instance Typeable Expression where->   typeOf = computeType exprType--> instance Typeable Rhs where->   typeOf = computeType rhsType--> computeType f tyEnv x = normalize (run doComputeType tyEnv)->   where doComputeType =->           do->             ty <- f tyEnv x->             theta <- S.get->             return (fixTypeVars tyEnv (subst theta ty))--> fixTypeVars :: ValueEnv -> Type -> Type-> fixTypeVars tyEnv ty = subst (foldr2 bindSubst idSubst tvs tvs') ty->   where tvs = filter (>= 0) (typeVars ty)->         tvs' = map TypeVariable [n - 1,n - 2 ..]->         n = minimum (0 : concatMap typeVars tys)->         tys = [ty | (_,Value _ (ForAll _ ty)) <- localBindings tyEnv]--> identType :: ValueEnv -> Ident -> TyState Type-> identType tyEnv x = instUniv (varType x tyEnv)--> litType :: ValueEnv -> Literal -> TyState Type-> litType _ (Char _ _)    = return charType-> litType tyEnv (Int v _) = identType tyEnv v-> litType _ (Float _ _)   = return floatType-> litType _ (String _ _)  = return stringType--> argType :: ValueEnv -> ConstrTerm -> TyState Type-> argType tyEnv (LiteralPattern l) = litType tyEnv l-> argType tyEnv (NegativePattern _ l) = litType tyEnv l-> argType tyEnv (VariablePattern v) = identType tyEnv v-> argType tyEnv (ConstructorPattern c ts) =->   do->     ty <- instUnivExist (constrType c tyEnv)->     tys <- mapM (argType tyEnv) ts->     unifyList (init (flatten ty)) tys->     return (last (flatten ty))->   where flatten (TypeArrow ty1 ty2) = ty1 : flatten ty2->         flatten ty = [ty]-> argType tyEnv (InfixPattern t1 op t2) =->   argType tyEnv (ConstructorPattern op [t1,t2])-> argType tyEnv (ParenPattern t) = argType tyEnv t-> argType tyEnv (TuplePattern _ ts)->   | null ts = return unitType->   | otherwise = liftM tupleType $ mapM (argType tyEnv) ts-> argType tyEnv (ListPattern _ ts) = freshTypeVar >>= flip elemType ts->   where elemType ty [] = return (listType ty)->         elemType ty (t:ts) =->           argType tyEnv t >>= unify ty >> elemType ty ts-> argType tyEnv (AsPattern v _) = argType tyEnv (VariablePattern v)-> argType tyEnv (LazyPattern _ t) = argType tyEnv t-> argType tyEnv (FunctionPattern f ts) =->   do ->     ty <- instUniv (funType f tyEnv)->     tys <- mapM (argType tyEnv) ts->     unifyList (init (flatten ty)) tys->     return (last (flatten ty))->   where flatten (TypeArrow ty1 ty2) = ty1 : flatten ty2->         flatten ty = [ty]-> argType tyEnv (InfixFuncPattern t1 op t2) =->   argType tyEnv (FunctionPattern op [t1,t2])-> argType tyEnv (RecordPattern fs r)->   | isJust r =->     do->       tys <- mapM (fieldPattType tyEnv) fs->       rty <- argType tyEnv (fromJust r)->       (TypeVariable i) <- freshTypeVar->       unify rty (TypeRecord tys (Just i))->       return rty->   | otherwise =->     do->       tys <- mapM (fieldPattType tyEnv) fs->       return (TypeRecord tys Nothing)--> fieldPattType :: ValueEnv -> Field ConstrTerm -> TyState (Ident,Type)-> fieldPattType tyEnv (Field _ l t) =->   do->     lty <- instUniv (labelType l tyEnv)->     ty <- argType tyEnv t->     unify lty ty->     return (l,lty)--> exprType :: ValueEnv -> Expression -> TyState Type-> exprType tyEnv (Literal l) = litType tyEnv l-> exprType tyEnv (Variable v) = instUniv (funType v tyEnv)-> exprType tyEnv (Constructor c) = instUnivExist (constrType c tyEnv)-> exprType tyEnv (Typed e _) = exprType tyEnv e-> exprType tyEnv (Paren e) = exprType tyEnv e-> exprType tyEnv (Tuple _ es)->   | null es = return unitType->   | otherwise = liftM tupleType $ mapM (exprType tyEnv) es-> exprType tyEnv (List _ es) = freshTypeVar >>= flip elemType es->   where elemType ty [] = return (listType ty)->         elemType ty (e:es) =->           exprType tyEnv e >>= unify ty >> elemType ty es-> exprType tyEnv (ListCompr _ e _) = liftM listType $ exprType tyEnv e-> exprType tyEnv (EnumFrom _) = return (listType intType)-> exprType tyEnv (EnumFromThen _ _) = return (listType intType)-> exprType tyEnv (EnumFromTo _ _) = return (listType intType)-> exprType tyEnv (EnumFromThenTo _ _ _) = return (listType intType)-> exprType tyEnv (UnaryMinus _ e) = exprType tyEnv e-> exprType tyEnv (Apply e1 e2) =->   do->     (ty1,ty2) <- exprType tyEnv e1 >>= unifyArrow->     exprType tyEnv e2 >>= unify ty1->     return ty2-> exprType tyEnv (InfixApply e1 op e2) =->   do->     (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2->     exprType tyEnv e1 >>= unify ty1->     exprType tyEnv e2 >>= unify ty2->     return ty3-> exprType tyEnv (LeftSection e op) =->   do->     (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2->     exprType tyEnv e >>= unify ty1->     return (TypeArrow ty2 ty3)-> exprType tyEnv (RightSection op e) =->   do->     (ty1,ty2,ty3) <- exprType tyEnv (infixOp op) >>= unifyArrow2->     exprType tyEnv e >>= unify ty2->     return (TypeArrow ty1 ty3)-> exprType tyEnv (Lambda _ args e) =->   do->     tys <- mapM (argType tyEnv) args->     ty <- exprType tyEnv e->     return (foldr TypeArrow ty tys)-> exprType tyEnv (Let _ e) = exprType tyEnv e-> exprType tyEnv (Do _ e) = exprType tyEnv e-> exprType tyEnv (IfThenElse _ e1 e2 e3) =->   do->     exprType tyEnv e1 >>= unify boolType->     ty2 <- exprType tyEnv e2->     ty3 <- exprType tyEnv e3->     unify ty2 ty3->     return ty3-> exprType tyEnv (Case _ _ alts) = freshTypeVar >>= flip altType alts->   where altType ty [] = return ty->         altType ty (Alt _ _ rhs:alts) =->           rhsType tyEnv rhs >>= unify ty >> altType ty alts-> exprType tyEnv (RecordConstr fs) =->   do ->     tys <- mapM (fieldExprType tyEnv) fs->     return (TypeRecord tys Nothing)-> exprType tyEnv (RecordSelection r l) =->   do ->     lty <- instUniv (labelType l tyEnv)->     rty <- exprType tyEnv r->     (TypeVariable i) <- freshTypeVar->     unify rty (TypeRecord [(l,lty)] (Just i))->     return lty-> exprType tyEnv (RecordUpdate fs r) =->   do->     tys <- mapM (fieldExprType tyEnv) fs->     rty <- exprType tyEnv r->     (TypeVariable i) <- freshTypeVar->     unify rty (TypeRecord tys (Just i))->     return rty--> rhsType :: ValueEnv -> Rhs -> TyState Type-> rhsType tyEnv (SimpleRhs _ e _) = exprType tyEnv e-> rhsType tyEnv (GuardedRhs es _) = freshTypeVar >>= flip condExprType es->   where condExprType ty [] = return ty->         condExprType ty (CondExpr _ _ e:es) =->           exprType tyEnv e >>= unify ty >> condExprType ty es--> fieldExprType :: ValueEnv -> Field Expression -> TyState (Ident,Type)-> fieldExprType tyEnv (Field _ l e) =->   do->     lty <- instUniv (labelType l tyEnv)->     ty <- exprType tyEnv e->     unify lty ty->     return (l,lty)--\end{verbatim}-In order to avoid name conflicts with non-generalized type variables-in a type we instantiate quantified type variables using non-negative-offsets here.-\begin{verbatim}--> freshTypeVar :: TyState Type-> freshTypeVar = liftM TypeVariable $ S.lift (S.modify succ >> S.get)--> instType :: Int -> Type -> TyState Type-> instType n ty =->   do->     tys <- sequence (replicate n freshTypeVar)->     return (expandAliasType tys ty)--> instUniv :: TypeScheme -> TyState Type-> instUniv (ForAll n ty) = instType n ty--> instUnivExist :: ExistTypeScheme -> TyState Type-> instUnivExist (ForAllExist n n' ty) = instType (n + n') ty--\end{verbatim}-When unifying two types, the non-generalized variables, i.e.,-variables with negative offsets, must not be substituted. Otherwise,-the unification algorithm is identical to the one used by the type-checker.-\begin{verbatim}--> unify :: Type -> Type -> TyState ()-> unify ty1 ty2 =->   S.modify (\theta -> unifyTypes (subst theta ty1) (subst theta ty2) theta)--> unifyList :: [Type] -> [Type] -> TyState ()-> unifyList tys1 tys2 = sequence_ (zipWith unify tys1 tys2)--> unifyArrow :: Type -> TyState (Type,Type)-> unifyArrow ty =->   do->     theta <- S.get->     case subst theta ty of->       TypeVariable tv->         | tv >= 0 ->->             do->               ty1 <- freshTypeVar->               ty2 <- freshTypeVar->               S.modify (bindVar tv (TypeArrow ty1 ty2))->               return (ty1,ty2)->       TypeArrow ty1 ty2 -> return (ty1,ty2)->       ty' -> internalError ("unifyArrow (" ++ show ty' ++ ")")--> unifyArrow2 :: Type -> TyState (Type,Type,Type)-> unifyArrow2 ty =->   do->     (ty1,ty2) <- unifyArrow ty->     (ty21,ty22) <- unifyArrow ty2->     return (ty1,ty21,ty22)--> unifyTypes :: Type -> Type -> TypeSubst -> TypeSubst-> unifyTypes (TypeVariable tv1) (TypeVariable tv2) theta->   | tv1 == tv2 = theta-> unifyTypes (TypeVariable tv) ty theta->   | tv >= 0 = bindVar tv ty theta-> unifyTypes ty (TypeVariable tv) theta->   | tv >= 0 = bindVar tv ty theta-> unifyTypes (TypeConstructor tc1 tys1) (TypeConstructor tc2 tys2) theta->   | tc1 == tc2 = foldr2 unifyTypes theta tys1 tys2-> unifyTypes (TypeConstrained tys1 tv1) (TypeConstrained tys2 tv2) theta->   | tv1 == tv2 = theta-> unifyTypes (TypeArrow ty11 ty12) (TypeArrow ty21 ty22) theta =->   unifyTypes ty11 ty21 (unifyTypes ty12 ty22 theta)-> unifyTypes (TypeSkolem k1) (TypeSkolem k2) theta->   | k1 == k2 = theta-> unifyTypes (TypeRecord fs1 Nothing) (TypeRecord fs2 Nothing) theta->   | length fs1 == length fs2 = foldr (unifyTypedLabels fs1) theta fs2-> unifyTypes tr1@(TypeRecord fs1 Nothing) (TypeRecord fs2 (Just a2)) theta =->   unifyTypes (TypeVariable a2)->              tr1->              (foldr (unifyTypedLabels fs1) theta fs2)-> unifyTypes tr1@(TypeRecord _ (Just _)) tr2@(TypeRecord _ Nothing) theta =->   unifyTypes tr2 tr1 theta-> unifyTypes (TypeRecord fs1 (Just a1)) (TypeRecord fs2 (Just a2)) theta =->   unifyTypes (TypeVariable a1)->              (TypeVariable a2)->              (foldr (unifyTypedLabels fs1) theta fs2)-> unifyTypes ty1 ty2 _ =->   internalError ("unify: (" ++ show ty1 ++ ") (" ++ show ty2 ++ ")")--> unifyTypedLabels :: [(Ident,Type)] -> (Ident,Type) -> TypeSubst -> TypeSubst-> unifyTypedLabels fs1 (l,ty) theta =->   maybe theta (\ty1 -> unifyTypes ty1 ty theta) (lookup l fs1)--\end{verbatim}-The functions \texttt{constrType}, \texttt{varType}, and-\texttt{funType} are used for computing the type of constructors,-pattern variables, and variables.--\ToDo{These functions should be shared with the type checker.}-\begin{verbatim}--> constrType :: QualIdent -> ValueEnv -> ExistTypeScheme-> constrType c tyEnv =->   case qualLookupValue c tyEnv of->     [DataConstructor _ sigma] -> sigma->     [NewtypeConstructor _ sigma] -> sigma->     _ -> internalError ("constrType " ++ show c)--> varType :: Ident -> ValueEnv -> TypeScheme-> varType v tyEnv =->   case lookupValue v tyEnv of->     [Value _ sigma] -> sigma->     _ -> internalError ("varType " ++ show v)--> funType :: QualIdent -> ValueEnv -> TypeScheme-> funType f tyEnv =->   case qualLookupValue f tyEnv of->     [Value _ sigma] -> sigma->     _ -> internalError ("funType " ++ show f)--> labelType :: Ident -> ValueEnv -> TypeScheme-> labelType l tyEnv =->   case lookupValue l tyEnv of->     [Label _ _ sigma] -> sigma->     _ -> internalError ("labelType " ++ show l)--\end{verbatim}
− src/Utils.lhs
@@ -1,92 +0,0 @@-% $Id: Utils.lhs,v 1.4 2003/10/04 17:04:38 wlux Exp $-%-% Copyright (c) 2001-2003, Wolfgang Lux-% See LICENSE for the full license.-%-\nwfilename{Utils.lhs}-\section{Utility Functions}-The module \texttt{Utils} provides a few simple functions that are-commonly used in the compiler, but not implemented in the Haskell-\texttt{Prelude} or standard library.-\begin{verbatim}--> module Utils where--> infixr 5 ++!--\end{verbatim}-\paragraph{Triples}-The \texttt{Prelude} does not contain standard functions for-triples. We provide projection, (un-)currying, and mapping for triples-here.-\begin{verbatim}--> fst3 (x,_,_) = x-> snd3 (_,y,_) = y-> thd3 (_,_,z) = z--> apFst3 f (x,y,z) = (f x,y,z)-> apSnd3 f (x,y,z) = (x,f y,z)-> apThd3 f (x,y,z) = (x,y,f z)--> curry3 f x y z = f (x,y,z)-> uncurry3 f (x,y,z) = f x y z--\end{verbatim}-\paragraph{Lists}-The function \texttt{(++!)} is variant of the list concatenation-operator \texttt{(++)} that ignores the second argument if the first-is a non-empty list. When lists are used to encode non-determinism in-Haskell, this operator has the same effect as the cut operator in-Prolog, hence the \texttt{!} in the name.-\begin{verbatim}--> (++!) :: [a] -> [a] -> [a]-> xs ++! ys = if null xs then ys else xs--\end{verbatim}-\paragraph{Strict fold}-The function \texttt{foldl\_strict} is a strict version of-\texttt{foldl}, i.e., it evaluates the binary applications before-the recursion. This has the advantage that \texttt{foldl\_strict} does-not construct a large application which is then evaluated in the base-case of the recursion.-\begin{verbatim}--foldl_strict :: (a -> b -> a) -> a -> [b] -> a-foldl_strict = foldl'---\end{verbatim}-\paragraph{Folding with two lists}-Fold operations with two arguments lists can be defined using-\texttt{zip} and \texttt{foldl} or \texttt{foldr}, resp. Our-definitions are unfolded for efficiency reasons.-\begin{verbatim}--> foldl2 :: (a -> b -> c -> a) -> a -> [b] -> [c] -> a-> foldl2 f z []     _      = z-> foldl2 f z _      []     = z-> foldl2 f z (x:xs) (y:ys) = foldl2 f (f z x y) xs ys--> foldr2 :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c-> foldr2 f z []     _      = z-> foldr2 f z _      []     = z-> foldr2 f z (x:xs) (y:ys) = f x y (foldr2 f z xs ys)--\end{verbatim}-\paragraph{Monadic fold with an accumulator}-The function \texttt{mapAccumM} is a generalization of-\texttt{mapAccumL} to monads like \texttt{foldM} is for-\texttt{foldl}.-\begin{verbatim}--> mapAccumM :: Monad m => (a -> b -> m (a,c)) -> a -> [b] -> m (a,[c])-> mapAccumM _ s [] = return (s,[])-> mapAccumM f s (x:xs) =->   do->     (s',y) <- f s x->     (s'',ys) <- mapAccumM f s' xs->     return (s'',y:ys)--\end{verbatim}
− src/WarnCheck.hs
@@ -1,872 +0,0 @@-------------------------------------------------------------------------------------- WarnCheck - Searches for potentially irregular code and generates---             warning messages---                --- February 2006,--- Martin Engelke (men@informatik.uni-kiel.de)----module WarnCheck (warnCheck) where--import Control.Monad.State-import qualified Data.Map as Map-import Data.List--import Curry.Base.Ident-import Curry.Base.Position-import Curry.Base.MessageMonad-import Curry.Syntax--import Base (ValueEnv, ValueInfo(..), qualLookupValue)-import TopEnv-import qualified ScopeEnv-import ScopeEnv (ScopeEnv)-------------------------------------------------------------------------------------- Data type for representing the current state of generating warnings.--- The monadic representation of the state allows the usage of monadic --- syntax (do expression) for dealing easier and safer with its--- contents.--type CheckState = State CState--data CState = CState {messages  :: [WarnMsg],-		      scope     :: ScopeEnv QualIdent IdInfo,-		      values    :: ValueEnv,-		      moduleId  :: ModuleIdent }---- Runs a 'CheckState' action and returns the list of messages-run ::  CheckState a -> [WarnMsg]-run f-   = reverse (messages (execState f emptyState))--emptyState :: CState-emptyState = CState {messages  = [],-		     scope     = ScopeEnv.new,-		     values    = emptyTopEnv,-		     moduleId  = mkMIdent []-		    }------------------------------------------------------------------------------------- Find potentially incorrect code in a Curry program and generate--- the following warnings for:---    - unreferenced variables---    - shadowing variables---    - idle case alternatives---    - overlapping case alternatives---    - function rules which are not together-warnCheck :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl] -> [WarnMsg]-warnCheck mid vals imports decls-   = run (do addImportedValues vals-	     addModuleId mid-	     checkImports imports-	     foldM' insertDecl decls-	     foldM' (checkDecl mid) decls-             checkDeclOccurrences decls-	 )-----------------------------------------------------------------------------------------------------------------------------------------------------------------------checkDecl :: ModuleIdent -> Decl -> CheckState ()-checkDecl mid (DataDecl pos ident params cdecls)-   = do beginScope-	foldM' insertTypeVar params-	foldM' (checkConstrDecl mid) cdecls-	params' <- filterM isUnrefTypeVar params-	when (not (null params')) -	     (foldM' genWarning' (map unrefTypeVar params'))-	endScope-checkDecl mid (TypeDecl _ ident params texpr)-   = do beginScope-	foldM' insertTypeVar params-	checkTypeExpr mid texpr-	params' <- filterM isUnrefTypeVar params-	when (not (null params'))-	     (foldM' genWarning'  (map unrefTypeVar params'))-	endScope-checkDecl mid (FunctionDecl pos ident equs)-   = do beginScope-	foldM' (checkEquation mid) equs-	c <- isConsId ident-	idents' <- returnUnrefVars-	when (not (c || null idents')) -             (foldM' genWarning' (map unrefVar idents'))-	endScope-checkDecl mid (PatternDecl _ cterm rhs)-   = do checkConstrTerm mid cterm-	checkRhs mid rhs-checkDecl _ _ = return ()---- Checks locally declared identifiers (i.e. functions and logic variables)--- for shadowing-checkLocalDecl :: Decl -> CheckState ()-checkLocalDecl (FunctionDecl pos ident _)-   = do s <- isShadowingVar ident-	when s (genWarning' (shadowingVar ident))-checkLocalDecl (ExtraVariables pos idents)-   = do idents' <- filterM isShadowingVar idents-	when (not (null idents'))-	     (foldM' genWarning' (map shadowingVar idents'))-checkLocalDecl (PatternDecl _ constrTerm _)-   = checkConstrTerm (mkMIdent []) constrTerm-checkLocalDecl _ = return ()-----checkConstrDecl :: ModuleIdent -> ConstrDecl -> CheckState ()-checkConstrDecl mid (ConstrDecl _ _ ident texprs)-   = do visitId ident-	foldM' (checkTypeExpr mid) texprs-checkConstrDecl mid (ConOpDecl _ _ texpr1 ident texpr2)-   = do visitId ident-	checkTypeExpr mid texpr1-	checkTypeExpr mid texpr2---checkTypeExpr :: ModuleIdent -> TypeExpr -> CheckState ()-checkTypeExpr mid (ConstructorType qid texprs)-   = do maybe (return ()) visitTypeId (localIdent mid qid)-	foldM' (checkTypeExpr mid ) texprs-checkTypeExpr mid  (VariableType ident)-   = visitTypeId ident-checkTypeExpr mid  (TupleType texprs)-   = foldM' (checkTypeExpr mid ) texprs-checkTypeExpr mid  (ListType texpr)-   = checkTypeExpr mid  texpr-checkTypeExpr mid  (ArrowType texpr1 texpr2)-   = do checkTypeExpr mid  texpr1-	checkTypeExpr mid  texpr2-checkTypeExpr mid  (RecordType fields restr)-   = do foldM' (checkTypeExpr mid ) (map snd fields)-	maybe (return ()) (checkTypeExpr mid ) restr-----checkEquation :: ModuleIdent -> Equation -> CheckState ()-checkEquation mid (Equation _ lhs rhs)-   = do checkLhs mid lhs-	checkRhs mid rhs-----checkLhs :: ModuleIdent -> Lhs -> CheckState ()-checkLhs mid (FunLhs ident cterms)-   = do visitId ident-	foldM' (checkConstrTerm mid) cterms-	foldM' (insertConstrTerm False) cterms-checkLhs mid (OpLhs cterm1 ident cterm2)-   = checkLhs mid (FunLhs ident [cterm1, cterm2])-checkLhs mid (ApLhs lhs cterms)-   = do checkLhs mid lhs-	foldM' (checkConstrTerm mid ) cterms-	foldM' (insertConstrTerm False) cterms-----checkRhs :: ModuleIdent -> Rhs -> CheckState ()-checkRhs mid (SimpleRhs _ expr decls)-   = do beginScope  -- function arguments can be overwritten by local decls-	foldM' checkLocalDecl decls-	foldM' insertDecl decls-	foldM' (checkDecl mid) decls-	checkDeclOccurrences decls-	checkExpression mid expr-	idents' <- returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope-checkRhs mid (GuardedRhs cexprs decls)-   = do beginScope-	foldM' checkLocalDecl decls-	foldM' insertDecl decls-	foldM' (checkDecl mid) decls-	checkDeclOccurrences decls-	foldM' (checkCondExpr mid) cexprs-	idents' <- returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope------checkCondExpr :: ModuleIdent -> CondExpr -> CheckState ()-checkCondExpr mid (CondExpr _ cond expr)-   = do checkExpression mid cond-	checkExpression mid expr---- -checkConstrTerm :: ModuleIdent -> ConstrTerm -> CheckState ()-checkConstrTerm mid (VariablePattern ident)-   = do s <- isShadowingVar ident-	when s (genWarning' (shadowingVar ident))-checkConstrTerm mid (ConstructorPattern _ cterms)-   = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (InfixPattern cterm1 qident cterm2)-   = checkConstrTerm mid (ConstructorPattern qident [cterm1, cterm2])-checkConstrTerm mid (ParenPattern cterm)-   = checkConstrTerm mid cterm-checkConstrTerm mid (TuplePattern _ cterms)-   = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (ListPattern _ cterms)-   = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid (AsPattern ident cterm)-   = do s <- isShadowingVar ident-	when s (genWarning' (shadowingVar ident))-	checkConstrTerm mid cterm-checkConstrTerm mid (LazyPattern _ cterm)-   = checkConstrTerm mid cterm-checkConstrTerm mid (FunctionPattern _ cterms)-   = foldM' (checkConstrTerm mid ) cterms-checkConstrTerm mid  (InfixFuncPattern cterm1 qident cterm2)-   = checkConstrTerm mid  (FunctionPattern qident [cterm1, cterm2])-checkConstrTerm mid  (RecordPattern fields restr)-   = do foldM' (checkFieldPattern mid) fields-	maybe (return ()) (checkConstrTerm mid ) restr-checkConstrTerm _ _ = return ()-----checkExpression :: ModuleIdent -> Expression -> CheckState ()-checkExpression mid (Variable qident)-   = maybe (return ()) visitId (localIdent mid qident)-checkExpression mid (Paren expr)-   = checkExpression mid expr-checkExpression mid (Typed expr _)-   = checkExpression mid expr-checkExpression mid (Tuple _ exprs)-   = foldM' (checkExpression mid ) exprs-checkExpression mid (List _ exprs)-   = foldM' (checkExpression mid ) exprs-checkExpression mid (ListCompr _ expr stmts)-   = do beginScope-	foldM' (checkStatement mid ) stmts-	checkExpression mid expr-	idents' <- returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope-checkExpression mid  (EnumFrom expr)-   = checkExpression mid  expr-checkExpression mid  (EnumFromThen expr1 expr2)-   = foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid  (EnumFromTo expr1 expr2)-   = foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid  (EnumFromThenTo expr1 expr2 expr3)-   = foldM' (checkExpression mid ) [expr1, expr2, expr3]-checkExpression mid  (UnaryMinus _ expr)-   = checkExpression mid  expr-checkExpression mid  (Apply expr1 expr2)-   = foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid  (InfixApply expr1 op expr2)-   = do maybe (return ()) (visitId) (localIdent mid (opName op))-	foldM' (checkExpression mid ) [expr1, expr2]-checkExpression mid  (LeftSection expr _)-   = checkExpression mid  expr-checkExpression mid  (RightSection _ expr)-   = checkExpression mid  expr-checkExpression mid  (Lambda _ cterms expr)-   = do beginScope-	foldM' (checkConstrTerm mid ) cterms-	foldM' (insertConstrTerm False) cterms-	checkExpression mid expr-	idents' <- returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope-checkExpression mid  (Let decls expr)-   = do beginScope-	foldM' checkLocalDecl decls-	foldM' insertDecl decls-	foldM' (checkDecl mid) decls-	checkDeclOccurrences decls-	checkExpression mid  expr-	idents' <- returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope-checkExpression mid  (Do stmts expr)-   = do beginScope-	foldM' (checkStatement mid ) stmts-	checkExpression mid  expr-	idents' <- returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope-checkExpression mid  (IfThenElse _ expr1 expr2 expr3)-   = foldM' (checkExpression mid ) [expr1, expr2, expr3]-checkExpression mid  (Case _ expr alts)-   = do checkExpression mid  expr-	foldM' (checkAlt mid) alts-	checkCaseAlternatives mid alts-checkExpression mid (RecordConstr fields)-   = foldM' (checkFieldExpression mid) fields-checkExpression mid (RecordSelection expr ident)-   = checkExpression mid expr -- Hier auch "visitId ident" ?-checkExpression mid (RecordUpdate fields expr)-   = do foldM' (checkFieldExpression mid) fields-	checkExpression mid expr-checkExpression _ _  = return ()-----checkStatement :: ModuleIdent -> Statement -> CheckState ()-checkStatement mid (StmtExpr _ expr)-   = checkExpression mid expr-checkStatement mid (StmtDecl decls)-   = do foldM' checkLocalDecl decls-	foldM' insertDecl decls-	foldM' (checkDecl mid) decls-	checkDeclOccurrences decls-checkStatement mid (StmtBind _ cterm expr)-   = do checkConstrTerm mid cterm-	insertConstrTerm False cterm-	checkExpression mid expr-----checkAlt :: ModuleIdent -> Alt -> CheckState ()-checkAlt mid (Alt pos cterm rhs)-   = do beginScope -	checkConstrTerm mid  cterm-	insertConstrTerm False cterm-	checkRhs mid rhs-	idents' <-  returnUnrefVars-	when (not (null idents'))-	     (foldM' genWarning' (map unrefVar idents'))-	endScope-----checkFieldExpression :: ModuleIdent -> Field Expression -> CheckState ()-checkFieldExpression mid (Field _ ident expr)-   = checkExpression mid expr -- Hier auch "visitId ident" ?-----checkFieldPattern :: ModuleIdent -> Field ConstrTerm -> CheckState ()-checkFieldPattern mid (Field _ ident cterm)-   = checkConstrTerm mid  cterm---- Check for idle and overlapping case alternatives-checkCaseAlternatives :: ModuleIdent -> [Alt] -> CheckState ()-checkCaseAlternatives mid alts-   = do checkIdleAlts mid alts-	checkOverlappingAlts mid alts------- FIXME this looks buggy: is alts' required to be non-null or not? (hsi)-checkIdleAlts :: ModuleIdent -> [Alt] -> CheckState ()-checkIdleAlts mid alts-   = do alts' <- dropUnless' isVarAlt alts-	let idles = tail_ [] alts'-	    (Alt pos _ _) = head idles-	unless (null idles) (genWarning pos idleCaseAlts)- where- isVarAlt (Alt _ (VariablePattern id) _) -    = isVarId id- isVarAlt (Alt _ (ParenPattern (VariablePattern id)) _) -    = isVarId id- isVarAlt (Alt _ (AsPattern _ (VariablePattern id)) _)-    = isVarId id- isVarAlt _ = return False-----checkOverlappingAlts :: ModuleIdent -> [Alt] -> CheckState ()-checkOverlappingAlts mid [] = return ()-checkOverlappingAlts mid (alt:alts)-   = do (altsr, alts') <- partition' (equalAlts alt) alts-        mapM_ (\ (Alt pos _ _) -> genWarning pos overlappingCaseAlt) altsr-	checkOverlappingAlts mid alts'- where- equalAlts (Alt _ cterm1 _) (Alt _ cterm2 _) = equalConstrTerms cterm1 cterm2-- equalConstrTerms (LiteralPattern l1) (LiteralPattern l2)-    = return (l1 == l2)- equalConstrTerms (NegativePattern id1 l1) (NegativePattern id2 l2) -    = return (id1 == id2 && l1 == l2)- equalConstrTerms (VariablePattern id1) (VariablePattern id2)-    = do p <- isConsId id1 -	 return (p && id1 == id2)- equalConstrTerms (ConstructorPattern qid1 cs1)-		  (ConstructorPattern qid2 cs2)-    = if qid1 == qid2-      then all' (\ (c1,c2) -> equalConstrTerms c1 c2) (zip cs1 cs2)-      else return False- equalConstrTerms (InfixPattern lcs1 qid1 rcs1)-		  (InfixPattern lcs2 qid2 rcs2)-    = equalConstrTerms (ConstructorPattern qid1 [lcs1, rcs1])-                       (ConstructorPattern qid2 [lcs2, rcs2])- equalConstrTerms (ParenPattern cterm1) (ParenPattern cterm2)-    = equalConstrTerms cterm1 cterm2- equalConstrTerms (TuplePattern _ cs1) (TuplePattern _ cs2)-    = equalConstrTerms (ConstructorPattern (qTupleId 2) cs1)-                       (ConstructorPattern (qTupleId 2) cs2)- equalConstrTerms (ListPattern _ cs1) (ListPattern _ cs2)-    = cmpListM equalConstrTerms cs1 cs2- equalConstrTerms (AsPattern id1 cterm1) (AsPattern id2 cterm2)-    = equalConstrTerms cterm1 cterm2- equalConstrTerms (LazyPattern _ cterm1) (LazyPattern _ cterm2)-    = equalConstrTerms cterm1 cterm2- equalConstrTerms _ _ = return False----- Find function rules which are not together-checkDeclOccurrences :: [Decl] -> CheckState ()-checkDeclOccurrences decls = checkDO (mkIdent "") Map.empty decls- where- checkDO prevId env [] = return ()- checkDO prevId env ((FunctionDecl pos ident _):decls)-    = do c <- isConsId ident-	 if not (c || prevId == ident)-          then (maybe (checkDO ident (Map.insert ident pos env) decls)-	              (\pos' -> genWarning' (rulesNotTogether ident pos')-		                >> checkDO ident env decls)-	              (Map.lookup ident env))-	  else checkDO ident env decls- checkDO _ env (_:decls) -    = checkDO (mkIdent "") env decls----- check import declarations for multiply imported modules-checkImports :: [Decl] -> CheckState ()-checkImports imps = checkImps Map.empty imps- where- checkImps env [] = return ()- checkImps env ((ImportDecl pos mid _ _ spec):imps)-    | mid /= preludeMIdent-      = maybe (checkImps (Map.insert mid (fromImpSpec spec) env) imps)-              (\ishs -> checkImpSpec env pos mid ishs spec-	                >>= (\env' -> checkImps env' imps))-	      (Map.lookup mid env)-    | otherwise-      = checkImps env imps- checkImps env (_:imps) = checkImps env imps-- checkImpSpec env pos mid (is,hs) Nothing-    = genWarning' (multiplyImportedModule mid) >> return env- checkImpSpec env pos mid (is,hs) (Just (Importing _ is'))-    | null is && any (\i' -> notElem i' hs) is'-      = do genWarning' (multiplyImportedModule mid)-	   return (Map.insert mid (is',hs) env)-    | null iis-      = return (Map.insert mid (is' ++ is,hs) env)-    | otherwise-      = do foldM' genWarning'-		  (map ((multiplyImportedSymbol mid) . impName) iis)-	   return (Map.insert mid (unionBy cmpImport is' is,hs) env)-  where iis = intersectBy cmpImport is' is- checkImpSpec env pos mid (is,hs) (Just (Hiding _ hs'))-    | null ihs-      = return (Map.insert mid (is,hs' ++ hs) env)-    | otherwise-      = do foldM' genWarning' -		  (map ((multiplyHiddenSymbol mid) . impName) ihs)-	   return (Map.insert mid (is,unionBy cmpImport hs' hs) env)-  where ihs = intersectBy cmpImport hs' hs-- cmpImport (ImportTypeWith id1 cs1) (ImportTypeWith id2 cs2)-    = id1 == id2 && null (intersect cs1 cs2)- cmpImport i1 i2 = (impName i1) == (impName i2)-- impName (Import id)           = id- impName (ImportTypeAll id)    = id- impName (ImportTypeWith id _) = id-- fromImpSpec Nothing                 = ([],[])- fromImpSpec (Just (Importing _ is)) = (is,[])- fromImpSpec (Just (Hiding _ hs))    = ([],hs)------------------------------------------------------------------------------------- For detecting unreferenced variables, the following functions updates the --- current check state by adding identifiers occuring in declaration left hand --- sides.-----insertDecl :: Decl -> CheckState ()-insertDecl (DataDecl _ ident _ cdecls)-   = do insertTypeConsId ident-	foldM' insertConstrDecl cdecls-insertDecl (TypeDecl _ ident _ texpr)-   = do insertTypeConsId ident-	insertTypeExpr texpr-insertDecl (FunctionDecl _ ident _)-   = do c <- isConsId ident-	unless c (insertVar ident)-insertDecl (ExternalDecl _ _ _ ident _)-   = insertVar ident-insertDecl (FlatExternalDecl _ idents)-   = foldM' insertVar idents-insertDecl (PatternDecl _ cterm _)-   = insertConstrTerm False cterm-insertDecl (ExtraVariables _ idents)-   = foldM' insertVar idents-insertDecl _ = return ()-----insertTypeExpr :: TypeExpr -> CheckState ()-insertTypeExpr (VariableType _) = return ()-insertTypeExpr (ConstructorType _ texprs)-   = foldM' insertTypeExpr texprs-insertTypeExpr (TupleType texprs)-   = foldM' insertTypeExpr texprs-insertTypeExpr (ListType texpr)-   = insertTypeExpr texpr-insertTypeExpr (ArrowType texpr1 texpr2)-   = foldM' insertTypeExpr [texpr1,texpr2]-insertTypeExpr (RecordType fields restr)-   = do --foldM' insertVar (concatMap fst fields)-	maybe (return ()) insertTypeExpr restr-----insertConstrDecl :: ConstrDecl -> CheckState ()-insertConstrDecl (ConstrDecl _ _ ident _)-   = insertConsId ident-insertConstrDecl (ConOpDecl _ _ _ ident _)-   = insertConsId ident---- Notes: ---    - 'fp' indicates whether 'checkConstrTerm' deals with the arguments---      of a function pattern or not.---    - Since function patterns are not recognized before syntax check, it is---      necessary to determine, whether a constructor pattern represents a---      constructor or a function. -insertConstrTerm :: Bool -> ConstrTerm -> CheckState ()-insertConstrTerm fp (VariablePattern ident)-   | fp        = do c <- isConsId ident-		    v <- isVarId ident-		    unless c (if (name ident) /= "_" && v-			         then visitId ident-			         else insertVar ident)-   | otherwise = do c <- isConsId ident-	            unless c (insertVar ident)-insertConstrTerm fp (ConstructorPattern qident cterms)-   = do c <- isQualConsId qident-	if c then foldM' (insertConstrTerm fp) cterms-	     else foldM' (insertConstrTerm True) cterms-insertConstrTerm fp (InfixPattern cterm1 qident cterm2)-   = insertConstrTerm fp (ConstructorPattern qident [cterm1, cterm2])-insertConstrTerm fp (ParenPattern cterm)-   = insertConstrTerm fp cterm-insertConstrTerm fp (TuplePattern _ cterms)-   = foldM' (insertConstrTerm fp) cterms-insertConstrTerm fp (ListPattern _ cterms)-   = foldM' (insertConstrTerm fp) cterms-insertConstrTerm fp (AsPattern ident cterm)-   = do insertVar ident-	insertConstrTerm fp cterm-insertConstrTerm fp (LazyPattern _ cterm)-   = insertConstrTerm fp cterm-insertConstrTerm _ (FunctionPattern _ cterms)-   = foldM' (insertConstrTerm True) cterms-insertConstrTerm _ (InfixFuncPattern cterm1 qident cterm2)-   = insertConstrTerm True (FunctionPattern qident [cterm1, cterm2])-insertConstrTerm fp (RecordPattern fields restr)-   = do foldM' (insertFieldPattern fp) fields-	maybe (return ()) (insertConstrTerm fp) restr-insertConstrTerm _ _ = return ()-----insertFieldPattern :: Bool -> Field ConstrTerm -> CheckState ()-insertFieldPattern fp (Field _ _ cterm)-   = insertConstrTerm fp cterm--------------------------------------------------------------------------------------------------------------------------------------------------------------------- Data type for distinguishing identifiers as either (type) constructors or--- (type) variables (including functions).--- The Boolean flag in 'VarInfo' is used to mark variables when they are used --- within expressions.-data IdInfo = ConsInfo | VarInfo Bool deriving Show-----isVariable :: IdInfo -> Bool-isVariable (VarInfo _) = True-isVariable _           = False-----isConstructor :: IdInfo -> Bool-isConstructor ConsInfo = True-isConstructor _        = False-----variableVisited :: IdInfo -> Bool-variableVisited (VarInfo v) = v-variableVisited _           = True-----visitVariable :: IdInfo -> IdInfo-visitVariable info = case info of-		       VarInfo _ -> VarInfo True-		       _         -> info------modifyScope :: (ScopeEnv QualIdent IdInfo -> ScopeEnv QualIdent IdInfo)-	       -> CState -> CState-modifyScope f state = state{ scope = f (scope state) }------genWarning :: Position -> String -> CheckState ()-genWarning pos msg-   = modify (\state -> state{ messages = warnMsg:(messages state) })- where warnMsg = WarnMsg (Just pos) msg- -genWarning' :: (Position, String) -> CheckState ()-genWarning' (pos, msg)-   = modify (\state -> state{ messages = warnMsg:(messages state) })-    where warnMsg = WarnMsg (Just pos) msg -----insertVar :: Ident -> CheckState ()-insertVar id -   | isAnnonId id = return ()-   | otherwise-     = modify -         (\state -> modifyScope -	              (ScopeEnv.insert (commonId id) (VarInfo False)) state)-----insertTypeVar :: Ident -> CheckState ()-insertTypeVar id-   | isAnnonId id = return ()-   | otherwise    -     = modify -         (\state -> modifyScope -	              (ScopeEnv.insert (typeId id) (VarInfo False)) state)-----insertConsId :: Ident -> CheckState ()-insertConsId id-   = modify -       (\state -> modifyScope (ScopeEnv.insert (commonId id) ConsInfo) state)-----insertTypeConsId :: Ident -> CheckState ()-insertTypeConsId id-   = modify -       (\state -> modifyScope (ScopeEnv.insert (typeId id) ConsInfo) state)-----isVarId :: Ident -> CheckState Bool-isVarId id-   = gets (\state -> isVar state (commonId id))-----isConsId :: Ident -> CheckState Bool-isConsId id -   = gets (\state -> isCons state (qualify id))-----isQualConsId :: QualIdent -> CheckState Bool-isQualConsId qid-   = gets (\state -> isCons state qid)-----isShadowingVar :: Ident -> CheckState Bool-isShadowingVar id -   = gets (\state -> isShadowing state (commonId id))-----visitId :: Ident -> CheckState ()-visitId id -   = modify -       (\state -> modifyScope -	            (ScopeEnv.modify visitVariable (commonId id)) state)-----visitTypeId :: Ident -> CheckState ()-visitTypeId id -   = modify -       (\state -> modifyScope -	            (ScopeEnv.modify visitVariable (typeId id)) state)-----isUnrefTypeVar :: Ident -> CheckState Bool-isUnrefTypeVar id-   = gets (\state -> isUnref state (typeId id))-----returnUnrefVars :: CheckState [Ident]-returnUnrefVars -   = gets (\state -> -	   	    let ids    = map fst (ScopeEnv.toLevelList (scope state))-                        unrefs = filter (isUnref state) ids-	            in  map unqualify unrefs )-----addModuleId :: ModuleIdent -> CheckState ()-addModuleId mid = modify (\state -> state{ moduleId = mid })------withScope :: CheckState a -> CheckState ()-withScope m = beginScope >> m >> endScope-----beginScope :: CheckState ()-beginScope = modify (\state -> modifyScope ScopeEnv.beginScope state)-----endScope :: CheckState ()-endScope = modify (\state -> modifyScope ScopeEnv.endScopeUp state)----- Adds the content of a value environment to the state-addImportedValues :: ValueEnv -> CheckState ()-addImportedValues vals = modify (\state -> state{ values = vals })-----foldM' :: (a -> CheckState ()) -> [a] -> CheckState ()-foldM' f [] = return ()-foldM' f (x:xs) = f x >> foldM' f xs-----dropUnless' :: (a -> CheckState Bool) -> [a] -> CheckState [a]-dropUnless' mpred [] = return []-dropUnless' mpred (x:xs)-   = do p <- mpred x-	if p then return (x:xs) else dropUnless' mpred xs-----partition' :: (a -> CheckState Bool) -> [a] -> CheckState ([a],[a])-partition' mpred xs = part mpred [] [] xs- where- part mpred ts fs [] = return (reverse ts, reverse fs)- part mpred ts fs (x:xs)-   = do p <- mpred x-	if p then part mpred (x:ts) fs xs-	     else part mpred ts (x:fs) xs-----all' :: (a -> CheckState Bool) -> [a] -> CheckState Bool-all' mpred [] = return True-all' mpred (x:xs)-   = do p <- mpred x-	if p then all' mpred xs else return False----------------------------------------------------------------------------------------isShadowing :: CState -> QualIdent -> Bool-isShadowing state qid-   = let sc = scope state-     in  maybe False isVariable (ScopeEnv.lookup qid sc)-	 && ScopeEnv.level qid sc < ScopeEnv.currentLevel sc-----isUnref :: CState -> QualIdent -> Bool-isUnref state qid -   = let sc = scope state-     in  maybe False (not . variableVisited) (ScopeEnv.lookup qid sc)-         && ScopeEnv.level qid sc == ScopeEnv.currentLevel sc-----isVar :: CState -> QualIdent -> Bool-isVar state qid = maybe (isAnnonId (unqualify qid)) -	           isVariable -		   (ScopeEnv.lookup qid (scope state))-----isCons :: CState -> QualIdent -> Bool-isCons state qid = maybe (isImportedCons state qid)-		         isConstructor-			 (ScopeEnv.lookup qid (scope state))- where- isImportedCons state qid-    = case (qualLookupValue qid (values state)) of-        (DataConstructor _ _):_    -> True-        (NewtypeConstructor _ _):_ -> True-        _                          -> False------isAnnonId :: Ident -> Bool-isAnnonId id = (name id) == "_"----- Since type identifiers and normal identifiers (e.g. functions, variables--- or constructors) don't share the same namespace, it is necessary--- to distinguish them in the scope environment of the check state.--- For this reason type identifiers are annotated with 1 and normal--- identifiers are annotated with 0.----commonId :: Ident -> QualIdent-commonId id = qualify (unRenameIdent id)-----typeId :: Ident -> QualIdent-typeId id = qualify (renameIdent id 1)------------------------------------------------------------------------------------- Warnings...--unrefTypeVar :: Ident -> (Position, String)-unrefTypeVar id = -  (positionOfIdent id,-   "unreferenced type variable \"" ++ show id ++ "\"")--unrefVar :: Ident -> (Position, String)-unrefVar id = -  (positionOfIdent id,-   "unused declaration of variable \"" ++ show id ++ "\"")--shadowingVar :: Ident -> (Position, String)-shadowingVar id = -  (positionOfIdent id,-   "shadowing symbol \"" ++ show id ++ "\"")--idleCaseAlts :: String-idleCaseAlts = "idle case alternative(s)"--overlappingCaseAlt :: String-overlappingCaseAlt = "redundant overlapping case alternative"--rulesNotTogether :: Ident -> Position -> (Position, String)-rulesNotTogether id pos-  = (positionOfIdent id,-     "rules for function \"" ++ show id ++ "\" "    -     ++ "are not together "-     ++ "(first occurrence at " -     ++ show (line pos) ++ "." ++ show (column pos) ++ ")")--multiplyImportedModule :: ModuleIdent -> (Position, String)-multiplyImportedModule mid -  = (positionOfModuleIdent mid,-     "module \"" ++ show mid ++ "\" was imported more than once")--multiplyImportedSymbol :: ModuleIdent -> Ident -> (Position, String)-multiplyImportedSymbol mid ident-  = (positionOfIdent ident,-     "symbol \"" ++ show ident ++ "\" was imported from module \""-     ++ show mid ++ "\" more than once")--multiplyHiddenSymbol :: ModuleIdent -> Ident -> (Position, String)-multiplyHiddenSymbol mid ident-  = (positionOfIdent ident,-     "symbol \"" ++ show ident ++ "\" from module \"" ++ show mid-     ++ "\" was hidden more than once")------------------------------------------------------------------------------------- Miscellaneous---- safer versions of 'tail' and 'head'-tail_ :: [a] -> [a] -> [a]-tail_ alt []     = alt-tail_ _   (_:xs) = xs------cmpListM :: Monad m => (a -> a -> m Bool) -> [a] -> [a] -> m Bool-cmpListM cmpM []     []     = return True-cmpListM cmpM (x:xs) (y:ys) = do c <- cmpM x y-				 if c then cmpListM cmpM xs ys -				      else return False-cmpListM cmpM _      _      = return False------------------------------------------------------------------------------------------------------------------------------------------------------------------
− src/currydoc.css
@@ -1,34 +0,0 @@-/* Use monospace fonts for typewriter styles */-pre, tt, code { font-family: monospace }--/* Use always white background */-body { background: white; color: black }--/* Show hyperlinks without underscore */-a:visited, a:link, a:active { text-decoration: none }--.keyword { color:blue }-.constructorname_constrpattern { color : #FF00FF }-.constructorname_constrcall { color : #FF00FF }-.constructorname_constrdecla { color : #FF00FF }-.constructorname_otherconstrkind { color : #FF00FF }-.typeconstructor_typedecla  { color : #ff7f50 }-.typeconstructor_typeuse  { color : #ff7f50 }-.typeconstructor_typeexport  { color : #ff7f50 }-.function_infixfunction  { color : #800080 }-.function_typsig  { color : #800080 }-.function_fundecl  { color : #800080 }-.function_functioncall  { color : #800080 }-.function_otherfunctionkind  { color : #800080 }-.moduleName  { color : #800000 }-.commentary  { color : green }-.numberCode  { color : #008080 }-.stringCode  { color : #800000 }-.charCode  { color : #800000 }-.symbol  { color : #C0C0C0 }-.identifier_iddecl   { color : black }-.identifier_idoccur   { color : black }-.identifier_unknownid   { color : black }-.codeWarning  {font-weight: bold;font-style:italic; color : red }-.codeError  { font-style:italic; color : #a52a2a }-.notParsed  { font-style:italic; color : #C0C0C0 }
src/cymake.hs view
@@ -1,97 +1,57 @@--- -------------------------------------------------------------------------------- |--- cymake - The Curry builder------          Command line tool for generating Curry representations (e.g.---          FlatCurry, AbstractCurry) for a Curry source file including---          all imported modules.------ September 2005, Martin Engelke (men@informatik.uni-kiel.de)------ -----------------------------------------------------------------------------+{- |+    Module      :  $Header$+    Description :  Main module+    Copyright   :  (c) 2005        Martin Engelke+                       2011 - 2016 Björn Peemöller+    License     :  BSD-3-clause -module Main(main) where+    Maintainer  :  bjp@informatik.uni-kiel.de+    Stability   :  experimental+    Portability :  portable -import Data.List-import Data.Maybe-import System.Console.GetOpt-import System.Environment(getArgs, getProgName)-import System.Exit(ExitCode(..), exitWith)-import System.IO-import Control.Monad (unless)+    Command line tool for generating Curry representations (e.g. FlatCurry,+    AbstractCurry) for a Curry source file including all imported modules.+-}+module Main (main) where -import CurryBuilder(buildCurry)-import CurryCompilerOpts-import CurryHtml-import Curry.Files.CymakePath (cymakeVersion)+import Curry.Base.Monad (runCYIO) +import Base.Messages+import Files.CymakePath (cymakeGreeting, cymakeVersion) --- | The command line tool cymake+import CurryBuilder     (buildCurry)+import CompilerOpts     (Options (..), CymakeMode (..), getCompilerOpts, usage)++-- |The command line tool cymake main :: IO ()-main = do-  prog <- getProgName-  args <- getArgs-  cymake prog args+main = getCompilerOpts >>= cymake --- | Checks the command line arguments and invokes the curry builder-cymake :: String -> [String] -> IO ()-cymake prog args-  | elem Help opts = printUsage prog-  | null files     = badUsage prog ["no files"]-  | null errs'-    && not (elem Html opts) = do-      unless (noVerb options')-        (putStrLn $ "This is cymake, version " ++ cymakeVersion)-      mapM_ (buildCurry options') files-  | null errs'     = do-                     let importFiles = nub $ importPaths opts'-                         outputFile  = maybe "" id (output opts')-                     mapM_ (source2html importFiles outputFile) files-  | otherwise      = badUsage prog errs'-  where-  (opts, files, errs) = getOpt Permute options args-  opts'               = foldr selectOption defaultOpts opts-  options'            = if flat opts' || flatXml opts' || abstract opts'-                        || untypedAbstract opts' || parseOnly opts'-                          then  opts'-                          else  opts'{ flat = True }-  errs'               = errs ++ check options' files+-- |Invoke the curry builder w.r.t the command line arguments+cymake :: (String, Options, [String], [String]) -> IO ()+cymake (prog, opts, files, errs) = case optMode opts of+  ModeHelp             -> printUsage prog+  ModeVersion          -> printVersion+  ModeNumericVersion   -> printNumericVersion+  ModeMake | not (null errs) -> badUsage prog errs+           | null files      -> badUsage prog ["No input files"]+           | otherwise       -> runCYIO (mapM_ (buildCurry opts) files) >>=+                                either abortWithMessages continueWithMessages+  where continueWithMessages = warnOrAbort (optWarnOpts opts) . snd --- | Prints usage information of the command line tool.+-- |Print the usage information of the command line tool printUsage :: String -> IO ()-printUsage prog = do-  putStrLn (usageInfo header options)-  exitWith ExitSuccess-  where header = "usage: " ++ prog ++ " [OPTION] ... MODULE ..."---- | Prints errors-badUsage :: String -> [String] -> IO ()-badUsage prog errs = do-  putErrsLn $ map (\err -> prog ++ ": " ++ err) errs-  abortWith ["Try '" ++ prog ++ " -" ++ "-help' for more information"]---- | Checks options and files and return a list of error messages-check :: Options -> [String] -> [String]-check opts files-   | null files-     = ["no files"]-   | isJust (output opts) && length files > 1-     = ["cannot specify -o with multiple targets"]-   | otherwise-     = []---- | Prints an error message on 'stderr'-putErrLn :: String -> IO ()-putErrLn = hPutStrLn stderr+printUsage prog = putStrLn $ usage prog --- | Prints a list of error messages on 'stderr'-putErrsLn :: [String] -> IO ()-putErrsLn = mapM_ putErrLn+-- |Print the program version+printVersion :: IO ()+printVersion = putStrLn cymakeGreeting --- | Prints a list of error messages on 'stderr' and aborts the program with---   exit code 1-abortWith :: [String] -> IO a-abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)+-- |Print the numeric program version+printNumericVersion :: IO ()+printNumericVersion = putStrLn cymakeVersion --- -------------------------------------------------------------------------------- -----------------------------------------------------------------------------+-- |Print errors and abort execution on bad parameters+badUsage :: String -> [String] -> IO ()+badUsage prog errs = do+  putErrsLn $ map (\ err -> prog ++ ": " ++ err) errs+  abortWith ["Try '" ++ prog ++ " --help' for more information"]
+ test/TestFrontend.hs view
@@ -0,0 +1,317 @@+--------------------------------------------------------------------------------+-- Test Suite for the Curry Frontend+--------------------------------------------------------------------------------+--+-- This Test Suite supports three kinds of tests:+--+-- 1) tests which should pass+-- 2) tests which should pass with a specific warning+-- 3) tests which should fail yielding a specific error message+--+-- In order to add a test to this suite, proceed as follows:+--+-- 1) Store your test code in a file (please use descriptive names) and put it+--    in the corresponding subfolder (i.e. test/pass for passing tests,+--    test/fail for failing tests and test/warning for passing tests producing+--    warnings)+-- 2) Extend the corresponding test information list (there is one for each test+--    group at the end of this file) with the required information (i.e. name of+--    the Curry module to be tested and expected warning/failure message(s))+-- 3) Run 'cabal test'++{-# LANGUAGE CPP #-}+module TestFrontend (tests) where++#if __GLASGOW_HASKELL__ < 710+import           Control.Applicative    ((<$>))+#endif+import qualified Control.Exception as E (SomeException, catch)++import           Data.List              (isInfixOf, sort)+import           Distribution.TestSuite+import           System.FilePath        (FilePath, (</>), (<.>))++import           Curry.Base.Message     (Message, message, ppMessages, ppError)+import           Curry.Base.Monad       (CYIO, runCYIO)+import           Curry.Base.Pretty      (text)+import qualified CompilerOpts as CO     ( Options (..), WarnOpts (..)+                                        , WarnFlag (..), Verbosity (VerbQuiet)+                                        , defaultOptions, defaultWarnOpts)+import CurryBuilder                     (buildCurry)++tests :: IO [Test]+tests = return [passingTests, warningTests, failingTests]++runSecure :: CYIO a -> IO (Either [Message] (a, [Message]))+runSecure act = runCYIO act `E.catch` handler+  where handler e = return (Left [message $ text $ show (e :: E.SomeException)])++-- Execute a test by calling cymake+runTest :: CO.Options -> String -> [String] -> IO Progress+runTest opts test [] = passOrFail <$> runSecure (buildCurry opts' test)+ where+  wOpts         = CO.optWarnOpts opts+  wFlags        =   CO.WarnUnusedBindings+                  : CO.WarnUnusedGlobalBindings+                  : CO.wnWarnFlags wOpts+  opts'         = opts { CO.optForce    = True+                       , CO.optWarnOpts = wOpts { CO.wnWarnFlags = wFlags }+                       }+  passOrFail    = Finished . either fail pass+  fail msgs+    | null msgs = Pass+    | otherwise = Fail $ "An unexpected failure occurred: " ++ showMessages msgs+  pass _        = Pass+runTest opts test errorMsgs = catchE <$> runSecure (buildCurry opts' test)+ where+  wOpts         = CO.optWarnOpts opts+  wFlags        =   CO.WarnUnusedBindings+                  : CO.WarnUnusedGlobalBindings+                  : CO.wnWarnFlags wOpts+  opts'         = opts { CO.optForce    = True+                       , CO.optWarnOpts = wOpts { CO.wnWarnFlags = wFlags }+                       }+  catchE        = Finished . either pass fail+  pass msgs = let errorStr     = showMessages msgs+                  leftOverMsgs = filter (not . flip isInfixOf errorStr) errorMsgs+               in if null leftOverMsgs+                 then Pass+                 else Fail $ "Expected warnings/failures did not occur: " ++ unwords leftOverMsgs+  fail          = pass . snd++showMessages :: [Message] -> String+showMessages = show . ppMessages ppError . sort++-- group of tests which should pass+passingTests :: Test+passingTests = Group { groupName    = "Passing Tests"+                     , concurrently = False+                     , groupTests   = map (mkTest "test/pass/") passInfos+                     }++-- group of test which should fail yielding a specific error message+failingTests :: Test+failingTests = Group { groupName    = "Failing Tests"+                     , concurrently = False+                     , groupTests   = map (mkTest "test/fail/") failInfos+                     }++-- group of tests which should pass producing a specific warning message+warningTests :: Test+warningTests = Group { groupName    = "Warning Tests"+                     , concurrently = False+                     , groupTests   = map (mkTest "test/warning/") warnInfos+                     }++-- create a new test+mkTest :: FilePath -> TestInfo -> Test+mkTest path (testName, testTags, testOpts, mSetOpts, errorMsgs) =+  let file = path </> testName <.> "curry"+      opts = CO.defaultOptions { CO.optVerbosity   = CO.VerbQuiet+                               , CO.optImportPaths = [path]+                               }+      test = TestInstance+        { run       = runTest opts file errorMsgs+        , name      = testName+        , tags      = testTags+        , options   = testOpts+        , setOption = maybe (\_ _ -> Right test) id mSetOpts+        }+  in Test test++-- Information for a test instance:+-- * name of test+-- * tags to classify a test+-- * options+-- * function to set options+-- * optional warning/error message which should be thrown on execution of test+type TestInfo = (String, [String], [OptionDescr], Maybe SetOption, [String])++type SetOption = String -> String -> Either String TestInstance++--------------------------------------------------------------------------------+-- Definition of passing tests+--------------------------------------------------------------------------------++-- generate a simple passing test+mkPassTest :: String -> TestInfo+mkPassTest name = (name, [], [], Nothing, [])++-- To add a passing test to the test suite simply add the module name of the+-- test code to the following list+passInfos :: [TestInfo]+passInfos = map mkPassTest+  [ "AbstractCurryBug"+  , "ACVisibility"+  , "AnonymVar"+  , "CaseComplete"+  , "DefaultPrecedence"+  , "Dequeue"+  , "ExplicitLayout"+  , "FCase"+  , "FP_Lifting"+  , "FP_NonCyclic"+  , "FP_NonLinearity"+  , "FunctionalPatterns"+  , "HaskellRecords"+  , "Hierarchical"+  , "Infix"+  , "Inline"+  , "Lambda"+  , "Maybe"+  , "NegLit"+  , "Newtype1"+  , "Newtype2"+  , "NonLinearLHS"+  , "OperatorDefinition"+  , "PatDecl"+  , "Prelude"+  , "Pretty"+  , "RecordsPolymorphism"+  , "RecordTest1"+  , "RecordTest2"+  , "RecordTest3"+  , "ReexportTest"+  , "SelfExport"+  , "SpaceLeak"+  , "TyConsTest"+  , "TypedExpr"+  , "UntypedAcy"+  , "Unzip"+  ]++--------------------------------------------------------------------------------+-- Definition of failing tests+--------------------------------------------------------------------------------++-- generate a simple failing test+mkFailTest :: String -> [String] -> TestInfo+mkFailTest name errorMsgs = (name, [], [], Nothing, errorMsgs)++-- To add a failing test to the test suite simply add the module name of the+-- test code and the expected error message(s) to the following list+failInfos :: [TestInfo]+failInfos = map (uncurry mkFailTest)+  [ ("ErrorMultipleSignature", ["More than one type signature for `f'"])+  , ("ExportCheck/AmbiguousName", ["Ambiguous name `not'"])+  , ("ExportCheck/AmbiguousType", ["Ambiguous type `Bool'"])+  , ("ExportCheck/ModuleNotImported", ["Module `Foo' not imported"])+  , ("ExportCheck/MultipleName", ["Multiple exports of name `not'"])+  , ("ExportCheck/MultipleType", ["Multiple exports of type `Bool'"])+  , ("ExportCheck/NoDataType", ["`Foo' is not a data type"])+  , ("ExportCheck/OutsideTypeConstructor", ["Data constructor `False' outside type export in export list"])+  , ("ExportCheck/OutsideTypeLabel", ["Label `value' outside type export in export list"])+  , ("ExportCheck/UndefinedElement", ["`foo' is not a constructor or label of type `Bool'"])+  , ("ExportCheck/UndefinedName", ["Undefined name `foo' in export list"])+  , ("ExportCheck/UndefinedType", ["Undefined type or class `Foo' in export list"])+  , ("FP_Cyclic", ["Function `g' used in functional pattern depends on `f'  causing a cyclic dependency"])+  , ("FP_Restrictions",+      [ "Functional patterns are not supported inside a case expression"+      , "Functional patterns are not supported inside a case expression"+      , "Functional patterns are not supported inside a list comprehension"+      , "Functional patterns are not supported inside a do sequence"+      ]+    )+  , ("FP_NonGlobal", ["Function `f1' in functional pattern is not global"])+  , ("ImportError",+      [ "Module Prelude does not export foo"+      , "Module Prelude does not export bar"+      ]+    )+  , ("KindCheck",+      [ "Type variable a occurs more than once in left hand side of type declaration"+      , "Type variable b occurs more than once in left hand side of type declaration"+      ]+    )+  , ("MultipleArities", ["Equations for `test' have different arities"])+  , ("MultipleDefinitions",+      ["Multiple definitions for data/record constructor `Rec'"]+    )+  , ("MultiplePrecedence",+      ["More than one fixity declaration for `f'"]+    )+  , ("PatternRestrictions",+      [ "Lazy patterns are not supported inside a functional pattern"]+    )+  , ("PragmaError", ["Unknown language extension"])+  , ("PrecedenceRange", ["Precedence out of range"])+  , ("RecordLabelIDs", ["Multiple declarations of `RecordLabelIDs.id'"])+  , ("RecursiveTypeSyn", ["Mutually recursive synonym and/or renaming types A and B (line 12.6)"])+  , ("SyntaxError", ["Type error in application"])+  , ("TypedFreeVariables",+      ["Variable x has a polymorphic type", "Type error in equation"]+    )+  , ("TypeError1", ["Type error in explicitly typed expression"])+  , ("TypeError2", ["Missing instance for Prelude.Num Prelude.Bool"])+  ]++--------------------------------------------------------------------------------+-- Definition of warning tests+--------------------------------------------------------------------------------++-- To add a warning test to the test suite simply add the module name of the+-- test code and the expected warning message(s) to the following list+warnInfos :: [TestInfo]+warnInfos = map (uncurry mkFailTest)+  [+    ("AliasClash",+      [ "The module alias `AliasClash' overlaps with the current module name"+      , "Overlapping module aliases"+      , "Module List is imported more than once"+      ]+    )+  , ("Case1", ["Pattern matches are non-exhaustive", "In an equation for `h'"])+  , ("Case2",+      [ "An fcase expression is potentially non-deterministic due to overlapping rules"+      , "Pattern matches are non-exhaustive", "In an fcase alternative"+      , "In a case alternative", "In an equation for `fp'"+      , "Pattern matches are potentially unreachable"+      , "Function `fp' is potentially non-deterministic due to overlapping rules"+      , "Pattern matches are non-exhaustive"+      ]+    )+  , ("CaseModeH",+      [ "Wrong case mode in symbol `B' due to selected case mode `haskell`, try renaming to b instead"+      , "Wrong case mode in symbol `B' due to selected case mode `haskell`, try renaming to b instead"+      , "Wrong case mode in symbol `Xs' due to selected case mode `haskell`, try renaming to xs instead"+      , "Wrong case mode in symbol `c' due to selected case mode `haskell`, try renaming to C instead"+      , "Wrong case mode in symbol `f' due to selected case mode `haskell`, try renaming to F instead"+      ]+    )+  , ("CaseModeP",+      [ "Wrong case mode in symbol `a' due to selected case mode `prolog`, try renaming to A instead"+      , "Wrong case mode in symbol `a' due to selected case mode `prolog`, try renaming to A instead"+      , "Wrong case mode in symbol `mf' due to selected case mode `prolog`, try renaming to Mf instead"+      , "Wrong case mode in symbol `E' due to selected case mode `prolog`, try renaming to e instead"+      ]+    )+  , ("CheckSignature",+      [ "Top-level binding with no type signature: hw"+      , "Top-level binding with no type signature: f"+      , "Unused declaration of variable `answer'"+      ]+    )+  , ("NonExhaustivePattern",+      [ "Pattern matches are non-exhaustive", "In a case alternative"+      , "In an equation for `test2'", "In an equation for `and'"+      , "In an equation for `plus'", "In an equation for `len2'"+      , "In an equation for `tuple'", "In an equation for `tuple2'"+      , "In an equation for `g'", "In an equation for `rec'"]+    )+  , ("OverlappingPatterns",+      [ "Pattern matches are potentially unreachable", "In a case alternative"+      , "An fcase expression is potentially non-deterministic due to overlapping rules"+      , "Function `i' is potentially non-deterministic due to overlapping rules"+      , "Function `j' is potentially non-deterministic due to overlapping rules"+      , "Function `k' is potentially non-deterministic due to overlapping rules"+      ]+    )+  , ("ShadowingSymbols",+      [ "Unused declaration of variable `x'", "Shadowing symbol `x'"])+  , ("TabCharacter",+      [ "Tab character"])+  , ("UnexportedFunction",+      [ "Unused declaration of variable `q'"+      , "Unused declaration of variable `g'" ]+    )+  ]