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 +296/−0
- LICENSE +1/−0
- curry-frontend.cabal +147/−53
- data/currysource.css +41/−0
- src/Arity.hs +0/−133
- src/Base.lhs +0/−557
- src/Base/AnnotExpr.hs +123/−0
- src/Base/CurryKinds.hs +45/−0
- src/Base/CurryTypes.hs +215/−0
- src/Base/Expr.hs +211/−0
- src/Base/KindSubst.hs +48/−0
- src/Base/Kinds.hs +55/−0
- src/Base/Messages.hs +78/−0
- src/Base/NestEnv.hs +120/−0
- src/Base/PrettyKinds.hs +22/−0
- src/Base/PrettyTypes.hs +54/−0
- src/Base/SCC.hs +62/−0
- src/Base/Subst.hs +127/−0
- src/Base/TopEnv.hs +181/−0
- src/Base/TypeExpansion.hs +113/−0
- src/Base/TypeSubst.hs +143/−0
- src/Base/Types.hs +511/−0
- src/Base/Typing.hs +192/−0
- src/Base/Utils.hs +94/−0
- src/CaseCompletion.hs +0/−662
- src/Checks.hs +162/−0
- src/Checks/DeriveCheck.hs +108/−0
- src/Checks/ExportCheck.hs +482/−0
- src/Checks/ExtensionCheck.hs +72/−0
- src/Checks/ImportSyntaxCheck.hs +278/−0
- src/Checks/InstanceCheck.hs +356/−0
- src/Checks/InterfaceCheck.hs +315/−0
- src/Checks/InterfaceSyntaxCheck.hs +356/−0
- src/Checks/KindCheck.hs +765/−0
- src/Checks/PrecCheck.hs +497/−0
- src/Checks/SyntaxCheck.hs +1391/−0
- src/Checks/TypeCheck.hs +1811/−0
- src/Checks/TypeSyntaxCheck.hs +686/−0
- src/Checks/WarnCheck.hs +1483/−0
- src/CompilerEnv.hs +117/−0
- src/CompilerOpts.hs +588/−0
- src/CondCompile.hs +26/−0
- src/Curry/Files/CymakePath.hs +0/−15
- src/Curry/Syntax.hs +0/−43
- src/Curry/Syntax/Frontend.hs +0/−202
- src/Curry/Syntax/LLParseComb.lhs +0/−288
- src/Curry/Syntax/LexComb.lhs +0/−104
- src/Curry/Syntax/Lexer.lhs +0/−630
- src/Curry/Syntax/Parser.lhs +0/−806
- src/Curry/Syntax/Pretty.lhs +0/−368
- src/Curry/Syntax/ShowModule.hs +0/−499
- src/Curry/Syntax/Type.lhs +0/−315
- src/Curry/Syntax/Unlit.hs +0/−61
- src/Curry/Syntax/Utils.hs +0/−257
- src/CurryBuilder.hs +205/−172
- src/CurryCompilerOpts.hs +0/−166
- src/CurryDeps.hs +187/−0
- src/CurryDeps.lhs +0/−144
- src/CurryEnv.hs +0/−181
- src/CurryHtml.hs +0/−190
- src/Desugar.lhs +0/−843
- src/Env/Class.hs +76/−0
- src/Env/Instance.hs +50/−0
- src/Env/Interface.hs +31/−0
- src/Env/ModuleAlias.hs +41/−0
- src/Env/OpPrec.hs +111/−0
- src/Env/Type.hs +70/−0
- src/Env/TypeConstructor.hs +217/−0
- src/Env/Value.hs +203/−0
- src/Eval.lhs +0/−96
- src/Exports.hs +425/−0
- src/Exports.lhs +0/−463
- src/Files/CymakePath.hs +32/−0
- src/GenAbstractCurry.hs +0/−1041
- src/GenFlatCurry.hs +0/−1153
- src/Generators.hs +51/−0
- src/Generators/GenAbstractCurry.hs +532/−0
- src/Generators/GenFlatCurry.hs +56/−0
- src/Generators/GenTypedFlatCurry.hs +515/−0
- src/Html/CurryHtml.hs +185/−0
- src/Html/SyntaxColoring.hs +582/−0
- src/IL.hs +19/−0
- src/IL/CurryToIL.lhs +0/−598
- src/IL/Pretty.hs +179/−0
- src/IL/Pretty.lhs +0/−167
- src/IL/Scope.hs +0/−124
- src/IL/ShowModule.hs +248/−0
- src/IL/Type.hs +140/−0
- src/IL/Type.lhs +0/−112
- src/IL/Typing.hs +44/−0
- src/IL/XML.lhs +0/−518
- src/Imports.hs +397/−0
- src/Imports.lhs +0/−379
- src/InterfaceCheck.hs +0/−142
- src/Interfaces.hs +144/−0
- src/KindCheck.lhs +0/−320
- src/Lift.lhs +0/−307
- src/Modules.hs +409/−0
- src/Modules.lhs +0/−700
- src/NestEnv.lhs +0/−77
- src/OldScopeEnv.hs +0/−165
- src/PatchPrelude.hs +0/−40
- src/PrecCheck.lhs +0/−461
- src/Qual.lhs +0/−165
- src/SCC.lhs +0/−60
- src/ScopeEnv.hs +0/−175
- src/Simplify.lhs +0/−475
- src/Subst.lhs +0/−124
- src/SyntaxCheck.lhs +0/−1149
- src/SyntaxColoring.hs +0/−800
- src/TokenStream.hs +142/−0
- src/TopEnv.lhs +0/−148
- src/Transformations.hs +86/−0
- src/Transformations/CaseCompletion.hs +453/−0
- src/Transformations/CurryToIL.hs +548/−0
- src/Transformations/Derive.hs +637/−0
- src/Transformations/Desugar.hs +1070/−0
- src/Transformations/Dictionary.hs +1324/−0
- src/Transformations/Lift.hs +443/−0
- src/Transformations/Newtypes.hs +111/−0
- src/Transformations/Qual.hs +238/−0
- src/Transformations/Simplify.hs +344/−0
- src/TypeCheck.lhs +0/−1331
- src/TypeSubst.lhs +0/−104
- src/Types.lhs +0/−251
- src/Typing.lhs +0/−406
- src/Utils.lhs +0/−92
- src/WarnCheck.hs +0/−872
- src/currydoc.css +0/−34
- src/cymake.hs +45/−85
- test/TestFrontend.hs +317/−0
+ 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><</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=='<' = "<" ++ htmlQuote cs- | c=='>' = ">" ++ htmlQuote cs- | c=='&' = "&" ++ htmlQuote cs- | c=='"' = """ ++ htmlQuote cs- | c=='\228' = "ä" ++ htmlQuote cs- | c=='\246' = "ö" ++ htmlQuote cs- | c=='\252' = "ü" ++ htmlQuote cs- | c=='\196' = "Ä" ++ htmlQuote cs- | c=='\214' = "Ö" ++ htmlQuote cs- | c=='\220' = "Ü" ++ htmlQuote cs- | c=='\223' = "ß"++ 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 == '<' = "<" ++ htmlQuote cs+ | c == '>' = ">" ++ htmlQuote cs+ | c == '&' = "&" ++ htmlQuote cs+ | c == '"' = """ ++ htmlQuote cs+ | c == 'ä' = "ä" ++ htmlQuote cs+ | c == 'ö' = "ö" ++ htmlQuote cs+ | c == 'ü' = "ü" ++ htmlQuote cs+ | c == 'Ä' = "Ä" ++ htmlQuote cs+ | c == 'Ö' = "Ö" ++ htmlQuote cs+ | c == 'Ü' = "Ü" ++ htmlQuote cs+ | c == 'ß' = "ß" ++ 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) = ">"++xmlFormat xs-> xmlFormat ('<':xs) = "<"++xmlFormat xs-> xmlFormat ('&':xs) = "&"++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'" ]+ )+ ]