curry-frontend (empty) → 0.1
raw patch · 70 files changed
+24067/−0 lines, 70 filesdep +basedep +directorydep +filepathsetup-changed
Dependencies added: base, directory, filepath, mtl, old-time
Files
- LICENSE +27/−0
- Setup.hs +2/−0
- curry-frontend.cabal +44/−0
- src/AbstractCurry.hs +282/−0
- src/Arity.hs +132/−0
- src/Base.lhs +956/−0
- src/CaseCompletion.hs +661/−0
- src/Combined.lhs +299/−0
- src/CompilerResults.hs +24/−0
- src/CurryBuilder.hs +204/−0
- src/CurryCompilerOpts.hs +167/−0
- src/CurryDeps.lhs +417/−0
- src/CurryEnv.hs +182/−0
- src/CurryHtml.hs +158/−0
- src/CurryLexer.lhs +629/−0
- src/CurryPP.lhs +369/−0
- src/CurryParser.lhs +818/−0
- src/CurrySubdir.hs +90/−0
- src/CurrySyntax.lhs +323/−0
- src/Desugar.lhs +917/−0
- src/Env.lhs +57/−0
- src/Error.lhs +42/−0
- src/Eval.lhs +96/−0
- src/Exports.lhs +460/−0
- src/ExtendedFlat.hs +513/−0
- src/Frontend.hs +262/−0
- src/GenAbstractCurry.hs +1108/−0
- src/GenFlatCurry.hs +1140/−0
- src/GetOpt.hs +194/−0
- src/IL.lhs +108/−0
- src/ILPP.lhs +166/−0
- src/ILScope.hs +124/−0
- src/ILTrans.lhs +594/−0
- src/ILxml.lhs +518/−0
- src/Ident.lhs +415/−0
- src/Imports.lhs +380/−0
- src/InterfaceCheck.hs +142/−0
- src/KindCheck.lhs +322/−0
- src/LLParseComb.lhs +292/−0
- src/LexComb.lhs +102/−0
- src/Lift.lhs +317/−0
- src/Map.lhs +225/−0
- src/Message.hs +74/−0
- src/Modules.lhs +799/−0
- src/NestEnv.lhs +73/−0
- src/OldScopeEnv.hs +170/−0
- src/PatchPrelude.hs +40/−0
- src/PathUtils.lhs +60/−0
- src/Position.lhs +95/−0
- src/PrecCheck.lhs +462/−0
- src/Pretty.lhs +905/−0
- src/Qual.lhs +166/−0
- src/SCC.lhs +59/−0
- src/ScopeEnv.hs +176/−0
- src/Set.lhs +91/−0
- src/ShowCurrySyntax.hs +493/−0
- src/Simplify.lhs +466/−0
- src/Subst.lhs +127/−0
- src/SyntaxCheck.lhs +1183/−0
- src/SyntaxColoring.hs +873/−0
- src/TopEnv.lhs +146/−0
- src/TypeCheck.lhs +1346/−0
- src/TypeSubst.lhs +102/−0
- src/Types.lhs +217/−0
- src/Typing.lhs +401/−0
- src/Unlit.lhs +110/−0
- src/Utils.lhs +101/−0
- src/WarnCheck.hs +910/−0
- src/currydoc.css +34/−0
- src/cymake.hs +110/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 1998-2004, Wolfgang Lux+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++1. Redistributions of source code must retain the above copyright+notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+notice, this list of conditions and the following disclaimer in the+documentation and/or other materials provided with the distribution.+3. None of the names of the copyright holders and contributors may be+used to endorse or promote products derived from this software without+specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ curry-frontend.cabal view
@@ -0,0 +1,44 @@+Name: curry-frontend+Version: 0.1+Cabal-Version: >= 1.6+Synopsis: A compiler for the functional logic language Curry to several intermediate language formats.+Description: The Curry Frontend consists of the executable program "cymake".+ It is used by various backends to compile Curry programs to + an internal representation. + The code is a stripped-down version of an early version of+ the Muenster Curry Compiler + (<http://danae.uni-muenster.de/~lux/curry/>)+Category: Language+License: OtherLicense+License-File: LICENSE+Author: Wolfgang Lux, Martin Engelke, Bernd Brassel, Holger Siegel+Maintainer: Michael Hanus+Bug-Reports: mailto:mh@informatik.uni-kiel.de+Homepage: http://curry-language.org+Build-Type: Simple+Stability: experimental++Extra-Source-Files: src/currydoc.css+ ++Executable cymake+ hs-source-dirs: src+ Main-is: cymake.hs+ Build-Depends: base >= 3 && < 4, mtl, old-time, directory, filepath+ Other-Modules: AbstractCurry, CurryBuilder, Env, IL, Message+ CurryCompilerOpts, Error, Modules, Subst, Arity+ CurryDeps, Eval, ILPP, NestEnv, SyntaxCheck, Base+ Exports, ILScope, SyntaxColoring, CurryEnv+ ExtendedFlat, ILTrans, OldScopeEnv, CurryHtml+ ILxml, PatchPrelude, TopEnv, CaseCompletion+ CurryLexer, Imports, PathUtils, TypeCheck+ CurryParser, InterfaceCheck, Position+ Types, CurryPP, Frontend, PrecCheck+ TypeSubst, CurrySubdir, GenAbstractCurry+ Pretty, Typing, Combined, CurrySyntax+ GenFlatCurry, KindCheck, Qual, Unlit, CompilerResults+ LexComb, SCC, Utils, GetOpt+ Lift, ScopeEnv, WarnCheck+ LLParseComb, Set, Desugar, Ident, ShowCurrySyntax+ Map, Simplify+
+ src/AbstractCurry.hs view
@@ -0,0 +1,282 @@+------------------------------------------------------------------------------+--- Library to support meta-programming in Curry.+---+--- This library contains a definition for representing Curry programs+--- in Curry (type "CurryProg") and an I/O action to read Curry programs and+--- transform them into this abstract representation (function "readCurry").+---+--- Note this defines a slightly new format for AbstractCurry+--- in comparison to the first proposal of 2003.+---+--- Assumption: an abstract Curry program is stored in file prog.acy+--- and translated with the parser by "parsecurry -acy prog".+---+--- @author Michael Hanus+--- @version April 2004+---+--- Version for Haskell (slightly modified):+--- July 2005, Martin Engelke (men@informatik.uni-kiel.de)+---+------------------------------------------------------------------------------++module AbstractCurry (CurryProg(..), QName, CLabel, CVisibility(..),+ CTVarIName, CTypeDecl(..), CConsDecl(..), CTypeExpr(..),+ COpDecl(..), CFixity(..), CVarIName,+ CFuncDecl(..), CRules(..), CEvalAnnot(..),+ CRule(..), CLocalDecl(..), CExpr(..), CStatement(..),+ CPattern(..), CBranchExpr(..), CLiteral(..),+ CField,+ readCurry, writeCurry) where++import Data.List(intersperse)++import PathUtils (writeModule,readModule)+++------------------------------------------------------------------------------+-- Definition of data types for representing abstract Curry programs:+-- ==================================================================++--- Data type for representing a Curry module in the intermediate form.+--- A value of this data type has the form+--- <CODE>+--- (CProg modname imports typedecls functions opdecls)+--- </CODE>+--- where modname: name of this module,+--- imports: list of modules names that are imported,+--- typedecls, opdecls, functions: see below++data CurryProg = CurryProg String [String] [CTypeDecl] [CFuncDecl] [COpDecl]+ deriving (Read, Show)++--- The data type for representing qualified names.+--- In AbstractCurry all names are qualified to avoid name clashes.+--- The first component is the module name and the second component the+--- unqualified name as it occurs in the source program.+type QName = (String,String)++--- Type for representing label identifiers+type CLabel = String++-- Data type to specify the visibility of various entities.++data CVisibility = Public -- exported entity+ | Private -- private entity+ deriving (Read, Show, Eq)+++--- The data type for representing type variables.+--- They are represented by (i,n) where i is a type variable index+--- which is unique inside a function and n is a name (if possible,+--- the name written in the source program).+type CTVarIName = (Int,String)++--- Data type for representing definitions of algebraic data types+--- and type synonyms.+--- <PRE>+--- A data type definition of the form+---+--- data t x1...xn = ...| c t1....tkc |...+---+--- is represented by the Curry term+---+--- (CType t v [i1,...,in] [...(CCons c kc v [t1,...,tkc])...])+---+--- where each ij is the index of the type variable xj+---+--- Note: the type variable indices are unique inside each type declaration+--- and are usually numbered from 0+---+--- Thus, a data type declaration consists of the name of the data type,+--- a list of type parameters and a list of constructor declarations.+--- </PRE>++data CTypeDecl = CType QName CVisibility [CTVarIName] [CConsDecl]+ | CTypeSyn QName CVisibility [CTVarIName] CTypeExpr+ deriving (Read, Show)+++--- A constructor declaration consists of the name and arity of the+--- constructor and a list of the argument types of the constructor.++data CConsDecl = CCons QName Int CVisibility [CTypeExpr]+ deriving (Read, Show)+++--- Data type for type expressions.+--- A type expression is either a type variable, a function type,+--- or a type constructor application.+---+--- Note: the names of the predefined type constructors are+--- "Int", "Float", "Bool", "Char", "IO", "Success",+--- "()" (unit type), "(,...,)" (tuple types), "[]" (list type)++data CTypeExpr =+ CTVar CTVarIName -- type variable+ | CFuncType CTypeExpr CTypeExpr -- function type t1->t2+ | CTCons QName [CTypeExpr] -- type constructor application+ | CRecordType [CField CTypeExpr] -- record type (extended Curry)+ (Maybe CTVarIName)+ deriving (Read, Show) +++--- Data type for operator declarations.+--- An operator declaration "fix p n" in Curry corresponds to the+--- AbstractCurry term (COp n fix p).++data COpDecl = COp QName CFixity Integer deriving (Read, Show)++data CFixity = CInfixOp -- non-associative infix operator+ | CInfixlOp -- left-associative infix operator+ | CInfixrOp -- right-associative infix operator+ deriving (Read, Show, Eq)+++--- Data types for representing object variables.+--- Object variables occurring in expressions are represented by (Var i)+--- where i is a variable index.++type CVarIName = (Int,String)+++--- Data type for representing function declarations.+--- <PRE>+--- A function declaration in FlatCurry is a term of the form+---+--- (CFunc name arity visibility type (CRules eval [CRule rule1,...,rulek]))+---+--- and represents the function "name" with definition+---+--- name :: type+--- rule1+--- ...+--- rulek+---+--- Note: the variable indices are unique inside each rule+---+--- External functions are represented as (CFunc name arity type (CExternal s))+--- where s is the external name associated to this function.+---+--- Thus, a function declaration consists of the name, arity, type, and+--- a list of rules.+--- </PRE>++data CFuncDecl = CFunc QName Int CVisibility CTypeExpr CRules+ deriving (Read, Show)+++--- A rule is either a list of formal parameters together with an expression+--- (i.e., a rule in flat form), a list of general program rules with+--- an evaluation annotation, or it is externally defined++data CRules = CRules CEvalAnnot [CRule]+ | CExternal String+ deriving (Read, Show)++--- Data type for classifying evaluation annotations for functions.+--- They can be either flexible (default), rigid, or choice.++data CEvalAnnot = CFlex | CRigid | CChoice deriving (Read, Show, Eq)++--- The most general form of a rule. It consists of a list of patterns+--- (left-hand side), a list of guards ("success" if not present in the+--- source text) with their corresponding right-hand sides, and+--- a list of local declarations.+data CRule = CRule [CPattern] [(CExpr,CExpr)] [CLocalDecl]+ deriving (Read, Show)++--- Data type for representing local (let/where) declarations+data CLocalDecl =+ CLocalFunc CFuncDecl -- local function declaration+ | CLocalPat CPattern CExpr [CLocalDecl] -- local pattern declaration+ | CLocalVar CVarIName -- local free variable declaration+ deriving (Read, Show)++--- Data type for representing Curry expressions.++data CExpr =+ CVar CVarIName -- variable (unique index / name)+ | CLit CLiteral -- literal (Integer/Float/Char constant)+ | CSymbol QName -- a defined symbol with module and name+ | CApply CExpr CExpr -- application (e1 e2)+ | CLambda [CPattern] CExpr -- lambda abstraction+ | CLetDecl [CLocalDecl] CExpr -- local let declarations+ | CDoExpr [CStatement] -- do expression+ | CListComp CExpr [CStatement] -- list comprehension+ | CCase CExpr [CBranchExpr] -- case expression+ | CRecConstr [CField CExpr] -- record construction (extended Curry)+ | CRecSelect CExpr CLabel -- field selection (extended Curry)+ | CRecUpdate [CField CExpr] CExpr -- record update (extended Curry)+ deriving (Read, Show)++--- Data type for representing statements in do expressions and+--- list comprehensions.++data CStatement = CSExpr CExpr -- an expression (I/O action or boolean)+ | CSPat CPattern CExpr -- a pattern definition+ | CSLet [CLocalDecl] -- a local let declaration+ deriving (Read, Show)++--- Data type for representing pattern expressions.++data CPattern =+ CPVar CVarIName -- pattern variable (unique index / name)+ | CPLit CLiteral -- literal (Integer/Float/Char constant)+ | CPComb QName [CPattern] -- application (m.c e1 ... en) of n-ary+ -- constructor m.c (CPComb (m,c) [e1,...,en])+ | CPAs CVarIName CPattern -- as-pattern (extended Curry)+ | CPFuncComb QName [CPattern] -- function pattern (extended Curry)+ | CPLazy CPattern -- lazy pattern (extended Curry) + | CPRecord [CField CPattern] -- record pattern (extended curry)+ (Maybe CPattern)+ deriving (Read, Show) ++--- Data type for representing branches in case expressions.++data CBranchExpr = CBranch CPattern CExpr deriving (Read, Show)++--- Data type for representing literals occurring in an expression.+--- It is either an integer, a float, or a character constant.+--- Note: the constructor definition of 'CIntc' differs from the original+--- PAKCS definition. It uses Haskell type 'Integer' instead of 'Int'+--- to provide an unlimited range of integer numbers. Furthermore+--- float values are represented with Haskell type 'Double' instead of+--- 'Float'.++data CLiteral = CIntc Integer+ | CFloatc Double+ | CCharc Char+ deriving (Read, Show, Eq)++--- Type for representing labeled fields++type CField a = (CLabel,a)++------------------------------------------------------------------------------+------------------------------------------------------------------------------++-- Reads an AbstractCurry file and returns the corresponding AbstractCurry+-- program term (type 'CurryProg')+readCurry :: String -> IO CurryProg+readCurry filename+ = do file <- readModule filename+ let prog = (read file) :: CurryProg+ return prog++-- Writes an AbstractCurry program term into a file+writeCurry :: String -> CurryProg -> IO ()+writeCurry filename prog + = catch (writeModule filename (showCurry prog)) (\e -> ioError e)++-- Shows an AbstractCurry program in a more nicely way.+showCurry :: CurryProg -> String+showCurry (CurryProg mname imps types funcs ops) =+ "CurryProg "++show mname++"\n "+++ show imps ++"\n ["+++ concat (intersperse ",\n " (map (\t->show t) types)) ++"]\n ["+++ concat (intersperse ",\n " (map (\f->show f) funcs)) ++"]\n "+++ show ops ++"\n"+ ++------------------------------------------------------------------------------+------------------------------------------------------------------------------
+ src/Arity.hs view
@@ -0,0 +1,132 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 Base+import CurrySyntax+import Ident+++-------------------------------------------------------------------------------++-- 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 view
@@ -0,0 +1,956 @@+% $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 \texttt{Base} provides common definitions for the various +phases of the compiler.+\begin{verbatim}++> module Base(module Base,module Ident,module Position,module Types,+> module CurrySyntax) where++> import Data.List+> import Control.Monad+> import Data.Maybe++> import Ident +> import Position+> import Types+> import CurrySyntax+> import CurryPP+> import Pretty+> import ExtendedFlat hiding (SrcRef, Fixity(..), TypeExpr, Expr(..))+> import Env+> import TopEnv+> import Map+> import Set+> import Utils+++> import qualified ExtendedFlat as EF ++\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] -> TypeExpr -> Type+> toQualType m tvs ty = qualifyType m (toType tvs ty)++> toQualTypes :: ModuleIdent -> [Ident] -> [TypeExpr] -> [Type]+> toQualTypes m tvs tys = map (qualifyType m) (toTypes tvs tys)++> toType :: [Ident] -> TypeExpr -> Type+> toType tvs ty = toType' (fromListFM (zip (tvs ++ tvs') [0..])) ty+> where tvs' = [tv | tv <- nub (fv ty), tv `notElem` tvs]++> toTypes :: [Ident] -> [TypeExpr] -> [Type]+> toTypes tvs tys = map (toType' (fromListFM (zip (tvs ++ tvs') [0..]))) tys+> where tvs' = [tv | tv <- nub (concatMap fv tys), tv `notElem` tvs]++> toType' :: FM Ident Int -> TypeExpr -> Type+> toType' tvs (ConstructorType tc tys) =+> TypeConstructor tc (map (toType' tvs) tys)+> toType' tvs (VariableType tv) =+> maybe (internalError ("toType " ++ show tv)) TypeVariable (lookupFM tv tvs)+> toType' tvs (TupleType tys)+> | null tys = TypeConstructor (qualify unitId) []+> | otherwise = TypeConstructor (qualify (tupleId (length tys'))) tys'+> where tys' = map (toType' tvs) tys+> toType' tvs (ListType ty) = TypeConstructor (qualify listId) [toType' tvs ty]+> toType' tvs (ArrowType ty1 ty2) =+> TypeArrow (toType' tvs ty1) (toType' tvs ty2)+> toType' tvs (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)++> 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++> fromQualType :: ModuleIdent -> Type -> TypeExpr+> fromQualType m ty = fromType (unqualifyType m ty)++> fromType :: Type -> TypeExpr+> fromType (TypeConstructor tc tys)+> | isTupleId c = TupleType tys'+> | c == listId && length tys == 1 = ListType (head tys')+> | c == unitId && null tys = TupleType []+> | otherwise = ConstructorType tc tys'+> where c = unqualify tc+> tys' = map (fromType) tys+> fromType (TypeVariable tv) =+> VariableType (if tv >= 0 then nameSupply !! tv+> else mkIdent ('_' : show (-tv)))+> fromType (TypeConstrained tys _) = fromType (head tys)+> fromType (TypeArrow ty1 ty2) = ArrowType (fromType ty1) (fromType ty2)+> fromType (TypeSkolem k) = VariableType (mkIdent ("_?" ++ show k))+> fromType (TypeRecord fs rty) = +> RecordType (map (\ (l,ty) -> ([l], fromType ty)) fs)+> (maybe Nothing (Just . fromType . TypeVariable) 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++\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++\end{verbatim}+\paragraph{Interfaces}+The compiler maintains a global environment holding all (directly or+indirectly) imported interfaces.++The function \texttt{bindFlatInterfac} 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 = Env ModuleIdent [IDecl]++> bindModule :: Interface -> ModuleEnv -> ModuleEnv+> bindModule (Interface m ds) = bindEnv m ds++> bindFlatInterface :: Prog -> ModuleEnv -> ModuleEnv+> bindFlatInterface (Prog m imps ts fs os)+> = bindModule (Interface (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],CurrySyntax.TypeExpr)+> genLabeledType (Cons qn _ _ [t])+> = ([renameLabel (fromLabelExtId (mkIdent $ localName qn))], genTypeExpr t)+>+> genTypeExpr :: EF.TypeExpr -> CurrySyntax.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 :: QName -> QualIdent+> genQualIdent 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 QName{modName=mod,localName=name} _ _ _) +> = (name == "[]" || name == "()") && mod == "Prelude"+> isSpecialPreludeType _ = False+>+> pos = first m+> ts' = filter (not . isSpecialPreludeType) ts++> lookupModule :: ModuleIdent -> ModuleEnv -> Maybe [IDecl]+> lookupModule = lookupEnv++\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 = Env Ident [LabelInfo]++> bindLabelType :: Ident -> QualIdent -> Type -> LabelEnv -> LabelEnv+> bindLabelType l r ty lEnv =+> maybe (bindEnv l [LabelType l r ty] lEnv)+> (\ls -> bindEnv l ((LabelType l r ty):ls) lEnv)+> (lookupEnv l lEnv)++> lookupLabelType :: Ident -> LabelEnv -> [LabelInfo]+> lookupLabelType l lEnv = fromMaybe [] (lookupEnv l lEnv)++> initLabelEnv :: LabelEnv+> initLabelEnv = emptyEnv+++\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) = splitQualIdent 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) = splitQualIdent qid++> lookupTupleArity :: Ident -> [ArityInfo]+> lookupTupleArity id +> | isTupleId id +> = [ArityInfo (qualifyWith preludeMIdent id) (tupleArity id)]+> | otherwise+> = []++\end{verbatim}+\paragraph{Module alias}+\begin{verbatim}++> type ImportEnv = Env ModuleIdent ModuleIdent++> bindAlias :: Decl -> ImportEnv -> ImportEnv+> bindAlias (ImportDecl _ mid _ mmid _) iEnv+> = bindEnv mid (fromMaybe mid mmid) iEnv++> lookupAlias :: ModuleIdent -> ImportEnv -> Maybe ModuleIdent+> lookupAlias = lookupEnv++> sureLookupAlias :: ModuleIdent -> ImportEnv -> ModuleIdent+> sureLookupAlias m iEnv = fromMaybe m (lookupAlias m iEnv)+++\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 Infix Integer deriving Eq++> instance Show OpPrec where+> showsPrec _ (OpPrec fix p) = showString (assoc fix) . shows p+> where assoc InfixL = "left "+> assoc InfixR = "right "+> assoc Infix = "non-assoc "++> defaultP :: OpPrec+> defaultP = OpPrec 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 = Env Ident EvalAnnotation++> bindEval :: Ident -> EvalAnnotation -> EvalEnv -> EvalEnv+> bindEval = bindEnv++> lookupEval :: Ident -> EvalEnv -> Maybe EvalAnnotation+> lookupEval f evEnv = lookupEnv f evEnv++\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 InfixR 5)) emptyTopEnv++> initTCEnv :: TCEnv+> initTCEnv = foldr (uncurry predefTC) emptyTopEnv predefTypes+> where a = typeVar 0+> predefTC (TypeConstructor tc tys) cs =+> predefTopEnv (qualify (unqualify tc))+> (DataType tc (length tys) (map Just cs))++> initDCEnv :: ValueEnv+> initDCEnv =+> foldr (uncurry predefDC) emptyTopEnv+> [(c,constrType (polyType ty) n' tys)+> | (ty,cs) <- predefTypes, Data c n' tys <- cs]+> where primTypes = map snd (moduleImports preludeMIdent initTCEnv)+> 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) aEnv+> = bindArity preludeMIdent id (length ts) aEnv++> initIEnv :: ImportEnv+> initIEnv = emptyEnv++> 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{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.+\begin{verbatim}++> 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 (`notElemSet` fromListSet (bv e))++\end{verbatim}+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.+\begin{verbatim}++> 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)++\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.}++Here is a list of predicates identifying various kinds of+declarations.+\begin{verbatim}++> isImportDecl, isInfixDecl, isTypeDecl :: Decl -> Bool+> isTypeSig, isEvalAnnot, isExtraVariables, 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+> isExtraVariables (ExtraVariables _ _) = True+> isExtraVariables _ = False+> isValueDecl (FunctionDecl _ _ _) = True+> isValueDecl (ExternalDecl _ _ _ _ _) = True+> isValueDecl (FlatExternalDecl _ _) = True+> isValueDecl (PatternDecl _ _ _) = True+> isValueDecl (ExtraVariables _ _) = True+> isValueDecl _ = False+> isRecordDecl (TypeDecl _ _ _ (RecordType _ _)) = True+> isRecordDecl _ = False++> isIImportDecl :: IDecl -> Bool+> isIImportDecl (IImportDecl _ _) = True+> isIImportDecl _ = False++\end{verbatim}+The function \texttt{infixOp} converts an infix operator into an+expression.+\begin{verbatim}++> infixOp :: InfixOp -> Expression+> infixOp (InfixOp op) = Variable op+> infixOp (InfixConstr op) = Constructor op++\end{verbatim}+The function \texttt{linear} 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}++> data Linear a = Linear | NonLinear a++> linear :: Eq a => [a] -> Linear a+> linear (x:xs)+> | x `elem` xs = NonLinear x+> | otherwise = linear xs+> linear [] = Linear++\end{verbatim}+In order to give precise error messages on duplicate definitions of+identifiers, the compiler pairs identifiers with their position in the+source file when passing them to the function above. However, the+position must be ignored when comparing two such pairs.+\begin{verbatim}++> data PIdent = PIdent Position Ident++> instance Eq PIdent where+> PIdent _ x == PIdent _ y = x == y++\end{verbatim}+++++
+ src/CaseCompletion.hs view
@@ -0,0 +1,661 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 qualified CurrySyntax+import Base (ModuleEnv, lookupModule)+import IL+import Ident+import Position (SrcRef)+import OldScopeEnv as ScopeEnv+import ILScope++++-------------------------------------------------------------------------------++-- 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', msgs',_) = 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', msgs1, senv1) = visitExpr mod menv msgs (insertExprScope senv expr) expr+ (alts', msgs2, 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', msgs1, 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 = ScopeEnv.genIdentList arity "x" senv3+ senv4 = foldr ScopeEnv.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+ (mmid', _) = splitQualIdent cons+ mid' = maybe mid id mmid'+++-- 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] -> [CurrySyntax.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+ CurrySyntax.IDataDecl _ _ _ cdecls+ -> any (p_isIConstrDecl qident) + (map fromJust (filter isJust cdecls))+ CurrySyntax.INewtypeDecl _ _ _ ncdecl + -> p_isINewConstrDecl qident ncdecl+ _ -> False++ p_isIConstrDecl qident (CurrySyntax.ConstrDecl _ _ ident _)+ = (unqualify qident) == ident+ p_isIConstrDecl qident (CurrySyntax.ConOpDecl _ _ _ ident _)+ = (unqualify qident) == ident++ p_isINewConstrDecl qident (CurrySyntax.NewConstrDecl _ _ ident _)+ = (unqualify qident) == ident++ p_extractIConstrDecls idecl+ = case idecl of+ CurrySyntax.IDataDecl _ _ _ cdecls + -> map fromJust (filter isJust cdecls)+ _ -> []++ p_getIConstrDeclInfo mid (CurrySyntax.ConstrDecl _ _ ident types)+ = (qualifyWith mid ident, length types)+ p_getIConstrDeclInfo mid (CurrySyntax.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/Combined.lhs view
@@ -0,0 +1,299 @@+% -*- LaTeX -*-+% $Id: Combined.lhs,v 1.16 2003/05/07 22:38:37 wlux Exp $+%+% Copyright (c) 1998-2003, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{Combined.lhs}+\section{Combined monads}\label{sec:combined-monads}+In this section we introduce combined monads which are parameterized+by another monads. This technique has been explored+in~\cite{KingWadler93:Combining} and very extensively+in~\cite{LiangHudakJones95:ModInterp}. The monad transformers used in+this report are mostly copied from the latter. Some restrictions were+necessary because Haskell~98 does not support multi-parameter type+classes. Especially, we cannot define generic lift operations because+they have to be parameterized over two monad classes. In addition, we+cannot define generic state and environment monad classes.+\begin{verbatim}++> module Combined where++> import Control.Monad+> import Data.IORef++> import Error++\end{verbatim}+\subsection{Identity monad}+The identity monad only serves as a base monad if no other monad --+usually either \texttt{[]} or \texttt{IO} -- can be used. It allows to+derive the usual -- i.e. unparameterized -- state and environment+monads.++Unfortunately, we cannot define \texttt{Id} as a \texttt{newtype}+because of a bug in the nhc compiler.+\begin{verbatim}++> -- newtype Id a = Id a+> data Id a = Id a++> unId :: Id a -> a+> unId (Id x) = x++> instance Functor Id where+> fmap f (Id x) = Id (f x)++> instance Monad Id where+> return x = Id x+> Id x >>= k = k x++> callId :: Id a -> a+> callId = unId++\end{verbatim}+\subsection{State transformers}+The state transformer monad is defined as usual, except that the+result of the state transformer function is itself a monad. The+unparameterized version is defined by using the identity monad+\texttt{Id} for the base monad.+\begin{verbatim}++> newtype StateT s m a = StateT (s -> m (a,s))+> type St s a = StateT s Id a++> unStateT :: StateT s m a -> (s -> m (a,s))+> unStateT (StateT st) = st++> instance Functor f => Functor (StateT s f) where+> fmap f (StateT st) = StateT (fmap (\(x,s') -> (f x,s')) . st)++> instance Monad m => Monad (StateT s m) where+> return x = StateT (\s -> return (x,s))+> StateT st >>= f = StateT (\s -> st s >>= \(x,s') -> unStateT (f x) s')+> fail msg = StateT (const (fail msg))++> instance MonadPlus m => MonadPlus (StateT s m) where+> mzero = StateT (const mzero)+> StateT st `mplus` StateT st' = StateT (\s -> st s `mplus` st' s)++> liftSt :: Monad m => m a -> StateT s m a+> liftSt m = StateT (\s -> m >>= \x -> return (x,s))++> callSt :: Monad m => StateT s m a -> s -> m a+> callSt (StateT st) s = st s >>= return . fst++> runSt :: St s a -> s -> a+> runSt st = callId . callSt st++\end{verbatim}+In addition to the standard monad functions, state monads should+provide means to fetch and change the state. With multi-parameter type+classes, one could use the following class:+\begin{verbatim}++class Monad m => StateMonad s m where+ update :: (s -> s) -> m s+ fetch :: m s+ change :: s -> m s++ fetch = update id+ change = update . const++instance Monad m => StateMonad s (StateT s m) where+ update f = StateT (\s -> return (s,f s))++\end{verbatim}+Unfortunately multi-parameter type classes are not available in+Haskell~98. Therefore we define the corresponding instance functions+for each state monad class separately. Here are the functions for the+state transformers.+\begin{verbatim}++> updateSt :: Monad m => (s -> s) -> StateT s m s+> updateSt f = StateT (\s -> return (s,f s))++> updateSt_ :: Monad m => (s -> s) -> StateT s m ()+> updateSt_ f = StateT (\s -> return ((),f s))++> fetchSt :: Monad m => StateT s m s+> fetchSt = updateSt id++> changeSt :: Monad m => s -> StateT s m s+> changeSt = updateSt . const++\end{verbatim}+Currying and uncurrying for state monads has been implemented+in~\cite{Fokker95:JPEG}. Here we extend this implementation to the+parametric monad classes.+\begin{verbatim}++> stCurry :: Monad m => StateT (s,t) m a -> t -> StateT s m (t,a)+> stCurry (StateT st) t =+> StateT (\s -> st (s,t) >>= \(x,(s',t')) -> return ((t',x),s'))++> stUncurry :: Monad m => (t -> StateT s m (t,a)) -> StateT (s,t) m a+> stUncurry f =+> StateT (\(s,t) -> let (StateT st) = f t+> in st s >>= \((t',x),s') -> return (x,(s',t')))++\end{verbatim}+\subsection{Environment monad}+A variant of the state transformer monad is the environment monad+which is also known as (state) reader monad.+\begin{verbatim}++> data ReaderT r m a = ReaderT (r -> m a)+> type Rt r a = ReaderT r Id a++> unReaderT :: ReaderT r m a -> (r -> m a)+> unReaderT (ReaderT rt) = rt++> instance Functor f => Functor (ReaderT r f) where+> fmap f (ReaderT rt) = ReaderT (fmap f . rt)++> instance Monad m => Monad (ReaderT r m) where+> return x = ReaderT (\_ -> return x)+> ReaderT rt >>= f = ReaderT (\r -> rt r >>= \x -> unReaderT (f x) r)+> fail msg = ReaderT (const (fail msg))++> instance MonadPlus m => MonadPlus (ReaderT r m) where+> mzero = ReaderT (\_ -> mzero)+> ReaderT rt `mplus` ReaderT rt' = ReaderT (\r -> rt r `mplus` rt' r)++> liftRt :: Monad m => m a -> ReaderT r m a+> liftRt m = ReaderT (\_ -> m)++> callRt :: ReaderT r m a -> r -> m a+> callRt (ReaderT rt) r = rt r++> runRt :: Rt r a -> r -> a+> runRt rt = callId . callRt rt++\end{verbatim}+Similar to the state monad class, an environment monad class which+provides functions to access the current state and to run an+environment monad in a given state could be defined as follows:+\begin{verbatim}++class Monad m => EnvMonad r m where+ env :: m r+ putEnv :: r -> m a -> m a++instance Monad m => EnvMonad r (ReaderT r m) where+ env = ReaderT return+ putEnv r (ReaderT rt) = ReaderT (\_ -> rt r)++\end{verbatim}+Again, this requires multi-parameter type classes; thus we define the+appropriate instance functions for the type \texttt{ReaderT} instead.+\begin{verbatim}++> envRt :: Monad m => ReaderT r m r+> envRt = ReaderT return ++> putEnvRt :: Monad m => r -> ReaderT r m a -> ReaderT r m a+> putEnvRt r (ReaderT rt) = ReaderT (\_ -> rt r)++\end{verbatim}+Currying can also be applied to state reader monads.+\begin{verbatim}++> rtCurry :: Monad m => ReaderT (r,t) m a -> t -> ReaderT r m a+> rtCurry (ReaderT rt) t = ReaderT (\r -> rt (r,t))++> rtUncurry :: Monad m => (t -> ReaderT r m a) -> ReaderT (r,t) m a+> rtUncurry f = ReaderT (\(r,t) -> let (ReaderT rt) = f t in rt r)++\end{verbatim}+A state reader transformer can be transformed trivially into a state+transformer monad. This is handled by the combinator \texttt{ro}.+\begin{verbatim}++> ro :: Monad m => ReaderT r m a -> StateT r m a+> ro (ReaderT rt) = StateT (\s -> rt s >>= \x -> return (x,s))++\end{verbatim}+\subsection{Error monad}+Another useful monad defined in~\cite{LiangHudakJones95:ModInterp} is+the error monad.+\begin{verbatim}++> data ErrorT m a = ErrorT (m (Error a))++> unErrorT :: ErrorT m a -> m (Error a)+> unErrorT (ErrorT m) = m++> instance Functor f => Functor (ErrorT f) where+> fmap f (ErrorT m) = ErrorT (fmap (fmap f) m)++> instance Monad m => Monad (ErrorT m) where+> return = ErrorT . return . Ok+> fail = ErrorT . return . Error+> ErrorT m >>= f = ErrorT (m >>= k)+> where k (Ok x) = unErrorT (f x)+> k (Error msg) = return (Error msg)++> instance MonadPlus m => MonadPlus (ErrorT m) where+> mzero = ErrorT mzero+> ErrorT m `mplus` ErrorT m' = ErrorT (m `mplus` m')++> liftErr :: Monad m => m a -> ErrorT m a+> liftErr = ErrorT . liftM Ok++> callErr :: ErrorT m a -> m (Error a)+> callErr = unErrorT++\end{verbatim}+\subsection{Mutable variables}+All major Haskell implementations provide some kind of mutable state+variables. In order to be able to lift these operations to the+combined monads approach, we define a class for handling these+references. Currently this is restricted to the use of mutable+variables in the \texttt{IO} monad.\footnote{We use the interface+provided by Hugs and ghc and provide compatibility implementations for+hbc and nhc that adapt the respective implementations to the one used+here. See appendix~\ref{sec:hbc-ioexts} and~\ref{sec:nhc-ioexts} for+details.}+\begin{verbatim}++> type Ref a = IORef a++> class Monad m => RefMonad m where+> newRef :: a -> m (Ref a)+> readRef :: Ref a -> m a+> writeRef :: Ref a -> a -> m ()++> instance RefMonad IO where+> newRef = newIORef+> readRef = readIORef+> writeRef = writeIORef++\end{verbatim}+\subsection{Lifting operations}+In order to use the operations of one the classes defined above in+another monad, the appropriate \texttt{lift}\dots{} combinators have+to be applied. The following instance declarations automatically+provide these lifting operations. Unfortunately we cannot define such+implicit lifting operations for neither the state monad functions nor+the environment monad functions as we were unable to define those+classes.+\begin{verbatim}++> -- Reference monad+> instance RefMonad m => RefMonad (ErrorT m) where+> newRef = liftErr . newRef+> readRef = liftErr . readRef+> writeRef ref = liftErr . writeRef ref++> instance RefMonad m => RefMonad (ReaderT s m) where+> newRef = liftRt . newRef+> readRef = liftRt . readRef+> writeRef ref = liftRt . writeRef ref++> instance RefMonad m => RefMonad (StateT s m) where+> newRef = liftSt . newRef+> readRef = liftSt . readRef+> writeRef ref = liftSt . writeRef ref++\end{verbatim}
+ src/CompilerResults.hs view
@@ -0,0 +1,24 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- CompilerResult - Provides a record for dealing with compiler results.+-- +-- January 2006,+-- Martin Engelke (men@informatik.uni-kiel.de)+--+module CompilerResults where+++-------------------------------------------------------------------------------++--+data CompilerResults+ = CompilerResults{ unchangedIntf :: Maybe FilePath }++--+defaultResults :: CompilerResults+defaultResults = CompilerResults{ unchangedIntf = Nothing }+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/CurryBuilder.hs view
@@ -0,0 +1,204 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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++import System.Exit+import System.Time+import Control.Monad+import Data.Maybe+import Data.List +import System.IO++import Modules (compileModule_)+import CurryCompilerOpts +import CurryDeps+import Ident+import PathUtils+import Env++-------------------------------------------------------------------------------++-- 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' <- getSourcePath 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+++-------------------------------------------------------------------------------++makeCurry :: Options -> [(ModuleIdent,Source)] -> FilePath -> IO ()+makeCurry options deps file+ = mapM compile (map snd deps) >> return ()+ where+ compile (Source file' mods)+ | rootname file == rootname 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 file'] --[flatName file', flatIntName file']+ (file':(catMaybes (map flatInterface mods)))+ (compileFile file')+ (skipFile file')+ else compileFile file'+ compile _ = return ()++ compileFile file+ = do unless (noVerb options) (putStrLn ("compiling " ++ file ++ " ..."))+ compileCurry (compOpts True) file+ return ()++ skipFile file+ = do unless (noVerb options)+ (putStrLn ("skipping " ++ file ++ " ..."))++ generateFile file+ = do unless (noVerb options) + (putStrLn ("generating " + ++ (head (targetNames file)) + ++ " ..."))+ compileCurry (compOpts False) file+ return ()++ targetNames fn + | flat options = [flatName 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 fn] -- , flatIntName fn]++ flatInterface mod + = case (lookup mod deps) of+ Just (Source file _) -> Just (flatIntName (rootname file))+ Just (Interface file) -> Just (flatIntName (rootname file))+ _ -> Nothing++ compOpts isImport+ | isImport + = options + { flat = True,+ flatXml = False,+ abstract = False,+ untypedAbstract = False,+ parseOnly = False,+ dump = []+ }+ | otherwise = options++-------------------------------------------------------------------------------++-- Searches in 'paths' for the corresponding Curry file of 'fn' and returns+-- the complete path if it exist. The filename 'fn' doesn't need one of the +-- Curry file extensions ".curry" or ".lcurry"+getSourcePath :: [FilePath] -> FilePath -> IO (Maybe FilePath)+getSourcePath paths file = getCurryPath paths [] file+++-- 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 . sortDeps) (deps paths [] emptyEnv file)+++-------------------------------------------------------------------------------+-- A simple make function++-- 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++--+getDestTimes :: [FilePath] -> IO [ClockTime]+getDestTimes [] = return []+getDestTimes (file:files)+ = catch (do time <- getModuleModTime file+ times <- getDestTimes files+ return (time:times))+ (const (getDestTimes files))++--+getDepTimes :: [String] -> IO [ClockTime]+getDepTimes [] = return []+getDepTimes (file:files)+ = catch (do time <- getModuleModTime file+ times <- getDepTimes files+ return (time:times))+ (\err -> abortWith [show err])++--+outOfDate :: [ClockTime] -> [ClockTime] -> Bool+outOfDate tgtimes dptimes = or (map (\t -> or (map ((<) t) dptimes)) tgtimes)+++compileCurry = compileModule_++-------------------------------------------------------------------------------+-- Error handling++-- Prints an error message on 'stderr'+putErrLn :: String -> IO ()+putErrLn = hPutStrLn stderr++-- Prints a list of error messages on 'stderr'+putErrsLn :: [String] -> IO ()+putErrsLn = mapM_ putErrLn++-- Prints a list of error messages on 'stderr' and aborts the program+abortWith :: [String] -> IO a+abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)+++-- Error messages++missingModule :: FilePath -> String+missingModule file = "Error: missing module \"" ++ file ++ "\""++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/CurryCompilerOpts.hs view
@@ -0,0 +1,167 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 GetOpt+--import Options (Dump(..))+++-------------------------------------------------------------------------------++-- 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+ }+++-- 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 = []+ }+++-- 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]+ 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 "" ["dump-transformed"] (NoArg (Dump [DumpTransformed]))+ "dump IL code after debugging transformation",+ Option "" ["dump-normalized"] (NoArg (Dump [DumpNormalized]))+ "dump IL code after normalization",+ Option "?h" ["help"] (NoArg Help)+ "display this help and exit"+ ]+++-- Inserts an option (type 'Option') into the options record (type 'Options')+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 }+++-------------------------------------------------------------------------------++-- 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+ | DumpTransformed -- dump transformed code+ | DumpNormalized -- dump IL code after normalization+ deriving (Eq,Bounded,Enum,Show)+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/CurryDeps.lhs view
@@ -0,0 +1,417 @@++% $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 where++> import Data.List+> import Data.Maybe+> import Control.Monad++> import Error+> import Ident+> import Unlit+> import CurrySyntax hiding(Interface(..))+> import CurryParser(parseHeader)+> import SCC+> import Env++> import PathUtils++> data Source = Source FilePath [ModuleIdent]+> | Interface FilePath+> | Unknown+> deriving (Eq,Ord,Show)+> type SourceEnv = Env ModuleIdent Source++\end{verbatim}+The module has two entry points. The function \texttt{buildScript}+computes either a build or clean script for a module while+\texttt{makeDepend} computes dependency rules for inclusion into a+Makefile.+\begin{verbatim}++> buildScript :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool+> -> [FilePath] -> [FilePath] -> Maybe FilePath -> FilePath +> -> IO [String]+> buildScript clean debug linkAlways flat xml acy uacy+> paths libraryPaths ofn fn =+> do+> mfn' <- getCurryPath paths libraryPaths fn+> (fn',es1) <- return (maybe ("",["Error: missing module \"" ++ fn ++ "\""])+> (\x -> (x,[]))+> mfn')+> (ms,es2) <- fmap +> (flattenDeps . sortDeps)+> (deps paths (filter (`notElem` paths) libraryPaths) emptyEnv fn')+> es <- return (es1 ++ es2)+> when (null es)+> (putStr +> (makeScript clean debug flat xml acy uacy linkAlways +> (outputFile fn') fn ms))+> return es+> where outputFile fn+> | extension fn `elem` moduleExts ++ objectExts = Nothing+> | otherwise = ofn `mplus` Just fn+> makeScript clean = if clean then makeCleanScript else makeBuildScript++> makeDepend :: [FilePath] -> [FilePath] -> Maybe FilePath -> [FilePath]+> -> IO ()+> makeDepend paths libraryPaths ofn ms =+> do+> flatDeps <- liftM (makeDeps True) (allDeps flat)+> objectDeps <- liftM (makeDeps False) (allDeps nonFlat)+> maybe putStr writeFile ofn (flatDeps ++ objectDeps)+> where (flat,nonFlat) = partition (flatExt `isSuffixOf`) ms+> allDeps = foldM (deps paths libraryPaths') emptyEnv+> libraryPaths' = filter (`notElem` paths) libraryPaths++> 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 emptyEnv+> | e `elem` objectExts = targetDeps paths libraryPaths mEnv r+> | otherwise = targetDeps paths libraryPaths mEnv fn+> where r = rootname fn+> e = extension fn++> targetDeps :: [FilePath] -> [FilePath] -> SourceEnv -> FilePath+> -> IO SourceEnv+> targetDeps paths libraryPaths mEnv fn =+> lookupFile [fn ++ e | e <- sourceExts] >>=+> maybe (return (bindEnv 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}+++> lookupModule :: [FilePath] -> [FilePath] -> ModuleIdent+> -> IO (Maybe FilePath)+> lookupModule paths libraryPaths m =+> lookupFile [p `catPath` fn ++ e | p <- "" : paths, e <- moduleExts] >>=+> maybe (lookupFile [p `catPath` fn ++ e +> | p <- libraryPaths, e <- moduleExts])+> (return . Just)+> where fn = foldr1 catPath (moduleQualifiers m)+> -- | p <- libraryPaths, e <- [icurryExt, curryExt, lcurryExt]])++> --lookupModule :: [FilePath] -> [FilePath] -> ModuleIdent+> -- -> IO (Maybe FilePath)+> --lookupModule paths libraryPaths m =+> -- lookupFile [p `catPath` fn ++ e | p <- "" : paths, e <- moduleExts] >>=+> -- maybe (lookupFile [p `catPath` fn ++ icurryExt | p <- libraryPaths])+> -- (return . Just)+> -- where fn = foldr1 catPath (moduleQualifiers m)++\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 lookupEnv m mEnv of+> Just _ -> return mEnv+> Nothing ->+> do+> mbFn <- lookupModule paths libraryPaths m+> case mbFn of+> Just fn+> | icurryExt `isSuffixOf` fn ->+> return (bindEnv m (Interface fn) mEnv)+> | otherwise -> sourceDeps paths libraryPaths m mEnv fn+> Nothing -> return (bindEnv m Unknown mEnv)++> sourceDeps :: [FilePath] -> [FilePath] -> ModuleIdent -> SourceEnv+> -> FilePath -> IO SourceEnv+> sourceDeps paths libraryPaths m mEnv fn =+> do+> s <- readModule fn+> case parseHeader fn (unlitLiterate fn s) of+> Ok (Module m' _ ds) ->+> let ms = imports m' ds in+> foldM (moduleDeps paths libraryPaths) (bindEnv m (Source fn ms) mEnv) ms+> Error _ -> return (bindEnv m (Source fn []) mEnv)++> imports :: ModuleIdent -> [Decl] -> [ModuleIdent]+> imports m ds = nub $+> [preludeMIdent | m /= preludeMIdent] ++ [m | ImportDecl _ m _ _ _ <- ds]++> unlitLiterate :: FilePath -> String -> String+> unlitLiterate fn+> | lcurryExt `isSuffixOf` fn = snd . unlit fn+> | otherwise = id++\end{verbatim}+It is quite straight forward to generate Makefile dependencies from+the dependency environment. In order for these dependencies to work,+the Makefile must include a rule+\begin{verbatim}+.SUFFIXES: .lcurry .curry .icurry+.o.icurry: @echo interface $@ not found, remove $< and recompile; exit 1+\end{verbatim}+This dependency rule introduces an indirect dependency between a+module and its interface. In particular, the interface may be updated+when the module is recompiled and a new object file is generated but+it does not matter if the interface is out-of-date with respect to the+object code.+\begin{verbatim}++> makeDeps :: Bool -> SourceEnv -> String+> makeDeps flat mEnv =+> unlines (filter (not . null) (map (depsLine . snd) (envToList mEnv)))+> where depsLine (Source fn ms) =+> targetName fn ++ ": " ++ fn ++ " " +++> unwords (filter (not . null) (map interf ms))+> depsLine (Interface _) = []+> depsLine Unknown = []+> interf m = maybe [] interfFile (lookupEnv m mEnv)+> interfFile (Source fn _) = interfName fn+> interfFile (Interface fn) = fn+> interfFile Unknown = ""+> targetName = if flat then flatName else objectName False++\end{verbatim}+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.+\begin{verbatim}++> sortDeps :: SourceEnv -> [[(ModuleIdent,Source)]]+> sortDeps = scc (modules . fst) (imports . snd) . envToList+> where modules m = [m]+> imports (Source _ ms) = ms+> imports (Interface _) = []+> imports Unknown = []++> flattenDeps :: [[(ModuleIdent,Source)]] -> ([(ModuleIdent,Source)],[String])+> flattenDeps [] = ([],[])+> flattenDeps (dep:deps) =+> case dep of+> [] -> (ms',es')+> [m] -> (m:ms',es')+> _ -> (ms',cyclicError (map fst dep) : es')+> where (ms',es') = flattenDeps deps++> cyclicError :: [ModuleIdent] -> String+> cyclicError (m:ms) =+> "Cylic import dependency between modules " ++ show m ++ rest ms+> where rest [m] = " and " ++ show m+> rest (m:ms) = ", " ++ show m ++ rest' ms+> rest' [m] = ", and " ++ show m+> rest' (m:ms) = ", " ++ show m ++ rest' ms++\end{verbatim}+The function \texttt{makeBuildScript} returns a shell script that+rebuilds several program representations (e.g. interfaces, FlatCurry etc.)+given a sorted list of module informations. The+script uses the command \verb|compile| and \verb|link| to build+programs and representations. They should be defined to reasonable values in the+environment where the script is executed (e.g. compile=cyc+The script deliberately uses+the \verb|-e| shell option so that the script is terminated upon the+first error. Unlike the original function \texttt{makeBuildScript} this+modification uses the command "smake" to check the out-of-dateness+of dependend program files.+\begin{verbatim}++> makeBuildScript :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool +> -> Maybe FilePath -> FilePath -> [(ModuleIdent,Source)] +> -> String+> makeBuildScript debug flat xml acy uacy linkAlways ofn fn mEnv =+> unlines ("set -e" : (map (compCommands . snd) mEnv)+> ++ (maybe [] linkCommands ofn))+> where +> compCommands (Source fn' ms)+> | (acy || uacy) && rootname fn /= rootname fn'+> = (smake ([flatName fn', flatIntName fn'])+> (fn' : catMaybes (map flatInt ms))+> "")+> ++ " || (\\" --rm -f " ++ (interfName fn') ++ " && \\"+> ++ unwords ["compile", "--flat", fn', "-o",+> flatName fn']+> ++ ")"+> | otherwise+> = (smake (targetNames fn')+> (fn' : catMaybes (map flatInt ms))+> "")+> ++ " || (\\" --rm -f " ++ (interfName fn')+> ++ (compile fn') ++ ")"+> compCommands (Interface _) = []+> compCommands Unknown = []+>+> linkCommands fn'+> | linkAlways = [link fn' os]+> | otherwise = [smake [fn'] os "", " || \\", (link fn' os)]+> where os = reverse (catMaybes (map (object . snd) mEnv))+>+> smake ts ds rule+> = "$CURRY_PATH/smake " +> ++ (unwords ts) ++ " : " +> ++ (unwords ds)+> ++ (if null rule then "" else " : " ++ rule)+>+> compile fn' = unwords ["compile", cFlag, fn', "-o", +> head (targetNames fn')] +>+> cFlag | flat = "--flat"+> | xml = "--xml"+> | acy = "--acy"+> | uacy = "--uacy"+> | otherwise = "-c"+>+> oGen fn' | flat || xml || acy || uacy = []+> | otherwise = ["-o", head (targetNames fn')]+>+> link fn' os = unwords ("link" : "-o" : fn' : os)+>+> flatInt m =+> case lookup m mEnv of+> Just (Source fn' _) +> -> Just (flatIntName fn')+> Just (Interface fn') +> -> Just (flatIntName (basename (rootname fn')))+> Just Unknown +> -> Nothing+> _ -> Nothing+>+> object (Source fn' _) = Just (head (targetNames fn'))+> object (Interface _) = Nothing+> object Unknown = Nothing+>+> targetNames fn' | flat = [flatName fn', flatIntName fn']+> | xml = [xmlName fn']+> | acy = [acyName fn']+> | uacy = [uacyName fn']+> | otherwise = [objectName debug fn']+++\end{verbatim}+The function \texttt{makeCleanScript} returns a shell script that+removes all compiled files for a module. The script uses the command+\verb|remove| to delete the files. It should be defined to a+reasonable value in the environment where the script is executed.+\begin{verbatim}++> makeCleanScript :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool +> -> Maybe FilePath -> FilePath -> [(ModuleIdent,Source)] +> -> String+> makeCleanScript debug flat xml acy uacy _ ofn _ mEnv =+> unwords ("remove" : foldr files (maybe [] return ofn) (map snd mEnv))+> where d = if debug then 2 else 0+> files = if flat then flatFiles else nonFlatFiles+> flatFiles (Source fn _) fs =+> drop d [interfName fn,flatName fn] ++ fs+> flatFiles (Interface _) fs = fs+> flatFiles Unknown fs = fs+> nonFlatFiles (Source fn _) fs =+> drop d [interfName fn,objectName False fn,objectName True fn] +++> fs+> nonFlatFiles (Interface _) fs = fs+> nonFlatFiles Unknown fs = fs++\end{verbatim}+The function \verb|getCurryPath| searches in predefined paths+for the corresponding \texttt{.curry} or \texttt{.lcurry} file, +if the given file name has no extension.+\begin{verbatim}++> getCurryPath :: [FilePath] -> [FilePath] -> FilePath -> IO (Maybe FilePath)+> getCurryPath paths libraryPaths fn+> = lookupFile filepaths+> where+> filepaths = [p `catPath` fn' | p <- "":(paths ++ libraryPaths),+> fn' <- fns']+> fns' | null (extension fn) = [fn ++ ext' | ext' <- sourceExts]+> | otherwise = [fn]++> --getSourceName :: FilePath -> IO FilePath+> --getSourceName fn+> -- | null (extension fn)+> -- = do mfn <- lookupFile [fn ++ ext' | ext' <- sourceExts]+> -- return (fromMaybe fn mfn)+> -- | otherwise +> -- = return fn+++\end{verbatim}+The following functions compute the name of the target file (e.g.+interface file, flat curry file etc.)+for a source module. Note that+output files are always created in the same directory as the source+file.+\begin{verbatim}++> interfName :: FilePath -> FilePath+> interfName sfn = rootname sfn ++ icurryExt++> flatName :: FilePath -> FilePath+> flatName fn = rootname fn ++ flatExt++> flatIntName :: FilePath -> FilePath+> flatIntName fn = rootname fn ++ flatIntExt++> xmlName :: FilePath -> FilePath+> xmlName fn = rootname fn ++ xmlExt++> acyName :: FilePath -> FilePath+> acyName fn = rootname fn ++ acyExt++> uacyName :: FilePath -> FilePath+> uacyName fn = rootname fn ++ uacyExt++> sourceRepName :: FilePath -> FilePath+> sourceRepName fn = rootname fn ++ sourceRepExt++> objectName :: Bool -> FilePath -> FilePath+> objectName debug = name (if debug then debugExt else oExt)+> where name ext fn = rootname fn ++ ext++> curryExt, lcurryExt, icurryExt, oExt :: String+> curryExt = ".curry"+> lcurryExt = ".lcurry"+> icurryExt = ".icurry"+> flatExt = ".fcy"+> flatIntExt = ".fint"+> xmlExt = "_flat.xml"+> acyExt = ".acy"+> uacyExt = ".uacy"+> sourceRepExt = ".cy"+> oExt = ".o"+> debugExt = ".d.o"++> sourceExts, moduleExts, objectExts :: [String]+> sourceExts = [curryExt,lcurryExt]+> moduleExts = sourceExts ++ [icurryExt]+> objectExts = [oExt]++\end{verbatim}
+ src/CurryEnv.hs view
@@ -0,0 +1,182 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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, + moduleId, exports, imports, interface, infixDecls,+ typeSynonyms, curryEnv) where++import Data.Maybe++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)+ = map (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 _ _ _ + = internalError "@CurryInfo.genTypeSynDecl: illegal declaration"++--+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 view
@@ -0,0 +1,158 @@+module CurryHtml(program2html,source2html) where++import SyntaxColoring+import Ident+import Data.Char hiding(Space)+import CurryDeps(getCurryPath)+import PathUtils (writeModule)+ +--- 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 output + else writeFile output)+ (program2html modulname program)+ + +--- 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 (CodeError _ _) = "codeerror"+code2class (CodeWarning _ _) = "codewarning"+code2class (NotParsed _) = "notparsed"+++code2html :: Bool -> Code -> String +code2html _ code@(CodeError _ c) =+ (spanTag (code2class code) + (code2html False c))+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 cl str+ |null cl = str+ | otherwise = "<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) = splitQualIdent 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/CurryLexer.lhs view
@@ -0,0 +1,629 @@++% $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 CurryLexer (lexFile,lexer, Token (..), Category(..), Attributes(..)) where++> import Data.Char +> import Data.List++> import LexComb+> import Position+> import Map+++\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 :: FM String Category+> reserved_ops = fromListFM [+> ("@", At),+> ("::", DoubleColon),+> ("..", DotDot),+> ("=", Equals),+> ("\\", Backslash),+> ("|", Bar),+> ("<-", LeftArrow),+> ("->", RightArrow),+> ("~", Tilde),+> (":=", Binds)+> ]+> reserved_and_special_ops = foldr (uncurry addToFM) reserved_ops [+> (":", Colon),+> (".", Sym_Dot),+> ("-", Sym_Minus),+> ("-.", Sym_MinusDot)+> ]++> reserved_ids, reserved_and_special_ids :: FM String Category+> reserved_ids = fromListFM [+> ("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 addToFM) 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)+> (lookupFM 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 (lookupFM 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)+> (lookupFM 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)+> (lookupFM 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/CurryPP.lhs view
@@ -0,0 +1,369 @@++% $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 CurryPP(module CurryPP, Doc) where+> import Ident+> import CurrySyntax+> import Pretty++\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}+Goals+\begin{verbatim}++> ppGoal :: Goal -> Doc+> ppGoal (Goal _ e ds) = sep [ppExpr 0 e,indent (ppLocalDefs ds)]++\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/CurryParser.lhs view
@@ -0,0 +1,818 @@++% $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 CurryParser where+> import Ident+> import Position+> import Error+> import LLParseComb+> import CurrySyntax+> import CurryLexer++> instance Symbol Token where+> isEOF (Token c _) = c == EOF++\end{verbatim}+\paragraph{Modules}+\begin{verbatim}++> parseSource :: Bool -> FilePath -> String -> Error Module+> parseSource flat path mod = +> fmap addSrcRefs (applyParser (parseModule flat) lexer path mod)++> parseHeader :: FilePath -> String -> Error Module+> parseHeader = prefixParser (moduleHeader <*->+> (leftBrace `opt` undefined) <*>+> many (importDecl <*-> many semicolon))+> lexer++> parseModule :: Bool -> Parser Token Module a+> parseModule flat = moduleHeader <*> decls flat++> 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{Goals}+\begin{verbatim}++> parseGoal :: String -> Error Goal+> parseGoal s = applyParser goal lexer "" s++> goal :: Parser Token Goal a+> goal = Goal <$> position <*> expr False <*> localDefs False++\end{verbatim}+\paragraph{Declarations}+\begin{verbatim}++> decls :: Bool -> Parser Token [Decl] a+> decls flat = layout (globalDecls flat)++> 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 t -> mkIdentPosition pos $ sval t) <$> 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 t -> mkIdentPosition pos $ sval t) <$> 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 str -> qualify $+> addPositionIdent p (tupleId $ +> (1 + ) $ +> length str))+> <$> 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 cs = foldr1 (<|>) (map token cs)++> 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 str = addPositionIdent pos $ mkIdent str++\end{verbatim}
+ src/CurrySubdir.hs view
@@ -0,0 +1,90 @@+module CurrySubdir where++import System.FilePath+import System.Directory+import System.Time (ClockTime)+import Control.Monad (when)+import Data.List(intersperse)++-- some definitions from PathUtils++curDirPath :: FilePath+curDirPath = "."++-- divide given puth names in directories++path :: String -> [String]+path = canonPath . separateBy (==pathSeparator) + where+ canonPath (c:cs) = c:filter (not . null) cs++-- separate a list by separator predicate++separateBy :: (a -> Bool) -> [a] -> [[a]]+separateBy p = sep id + where+ sep xs [] = [xs []]+ sep xs (c:cs) = if p c then xs [] : sep id cs+ else sep (xs . (c:)) cs++-- make canonical path from list of directories++unpath :: [String] -> String+unpath = concat . intersperse [pathSeparator]++--When we split a path into its basename and directory we will make+--sure that the basename does not contain any path separators.+ +dirname, basename :: FilePath -> FilePath+dirname = unpath . init . path+basename = last . path++-- add a subdirectory to a given filename +-- if it is not already present++inSubdir :: String -> String -> String+inSubdir sub fn = unpath $ add (path fn) + where+ add ps@[n] = sub:ps+ add ps@[p,n] | p==sub = ps+ add (p:ps) = p:add ps++--The sub directory to hide files in:++currySubdir :: String +currySubdir = ".curry"++inCurrySubdir :: String -> String+inCurrySubdir = inSubdir currySubdir++--write a file to curry subdirectory++writeModule :: String -> String -> IO ()+writeModule filename contents = do+ --writeFile filename contents+ let filename' = inCurrySubdir filename+ subdir = dirname filename'+ ex <- doesDirectoryExist subdir+ when (not ex) (createDirectory subdir)+ writeFile filename' contents++-- do things with file in subdir++onExistingFileDo :: (String -> IO a) -> String -> IO a+onExistingFileDo act filename = do+ ex <- doesFileExist filename+ if ex then act filename + else act $ inCurrySubdir filename++readModule :: String -> IO String+readModule = onExistingFileDo readFile++maybeReadModule :: String -> IO (Maybe String)+maybeReadModule filename = + catch (readModule filename >>= return . Just) (\_ -> return Nothing)++doesModuleExist :: String -> IO Bool+doesModuleExist = onExistingFileDo doesFileExist++getModuleModTime :: String -> IO ClockTime+getModuleModTime = onExistingFileDo getModificationTime
+ src/CurrySyntax.lhs view
@@ -0,0 +1,323 @@+> {-# 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 CurrySyntax where+> import Ident+> import 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}+\paragraph{Goals}+A goal is equivalent to an unconditional right hand side of an equation.+\begin{verbatim}++> data Goal = Goal Position Expression [Decl] deriving (Eq,Show,Read,Typeable,Data)++\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 CurrySyntax.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')+> +> current,next :: State Int SrcRef+> current = liftM (SrcRef . (:[])) get+>+> next = do+> i <- get+> put $! i+1+> return (SrcRef [i])
+ src/Desugar.lhs view
@@ -0,0 +1,917 @@++% $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,desugarGoal) where++> import Data.Maybe+> import Control.Monad+> import Data.List++> import Base+> import Combined+> import Typing+> import Utils+> import Ident+++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 = StateT ValueEnv (StateT Int Id) a++> run :: DesugarState a -> ValueEnv -> a+> run m tyEnv = runSt (callSt 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' <- fetchSt+> return (filter isTypeDecl ds' ++ ds'', tyEnv')++\end{verbatim}+While a goal of type \texttt{IO \_} is executed directly by the+runtime system, all other goals are evaluated under an interactive+top-level which displays the solutions of the goal and in particular+the bindings of the free variables. For this reason, the free+variables declared in the \texttt{where} clause of a goal are+translated into free variables of the goal. In addition, the goal+is transformed into a first order expression by performing a+unification with another variable. Thus, a goal+\begin{quote}+ \emph{expr}+ \texttt{where} $v_1$,\dots,$v_n$ \texttt{free}; \emph{decls}+\end{quote}+where no free variable declarations occur in \emph{decls} is+translated into the function+\begin{quote}+ \emph{f} $v_0$ $v_1$ \dots{} $v_n$ \texttt{=}+ $v_0$ \texttt{=:=} \emph{expr}+ \texttt{where} \emph{decls}+\end{quote}+where $v_0$ is a fresh variable.++\textbf{Note:} The debugger assumes that the goal is always a nullary+function. This means that we must not $\eta$-expand functional goal+expressions. In order to avoid the $\eta$-expansion we cheat a little+bit here and change the type of the goal into $\forall\alpha.\alpha$+if it really has a functional type.++\ToDo{Fix the debugger to handle functional goals so that this+hack is no longer needed.}+\begin{verbatim}++> desugarGoal :: Bool -> ValueEnv -> TCEnv -> ModuleIdent -> Ident -> Goal+> -> (Maybe [Ident],Module,ValueEnv)+> desugarGoal debug tyEnv tcEnv m g (Goal p e ds)+> | debug || isIO ty =+> desugarGoalIO tyEnv tcEnv p m g (Let ds e)+> (if debug && arrowArity ty > 0 then typeVar 0 else ty)+> | otherwise = desugarGoal' tyEnv tcEnv p m g vs e' ty+> where ty = typeOf tyEnv e+> (vs,e') = liftGoalVars (if null ds then e else Let ds e)+> isIO (TypeConstructor tc [_]) = tc == qIOId+> isIO _ = False++> desugarGoalIO :: ValueEnv -> TCEnv -> Position -> ModuleIdent -> Ident+> -> Expression -> Type -> (Maybe [Ident],Module,ValueEnv)+> desugarGoalIO tyEnv tcEnv p m g e ty =+> (Nothing,+> Module m Nothing [goalDecl p g [] e'],+> bindFun m g (polyType ty) tyEnv')+> where (e',tyEnv') = run (desugarGoalExpr m tcEnv e) tyEnv++> desugarGoal' :: ValueEnv -> TCEnv -> Position -> ModuleIdent -> Ident -> [Ident]+> -> Expression -> Type -> (Maybe [Ident],Module,ValueEnv)+> desugarGoal' tyEnv tcEnv p m g vs e ty =+> (Just vs',+> Module m Nothing [goalDecl p g (v0:vs') (apply prelUnif [mkVar v0,e'])],+> bindFun m v0 (monoType ty) (bindFun m g (polyType ty') tyEnv'))+> where (e',tyEnv') = run (desugarGoalExpr m tcEnv e) tyEnv+> v0 = anonId+> vs' = filter (`elem` qfv m e') vs+> ty' = TypeArrow ty (foldr (TypeArrow . typeOf tyEnv) successType vs')++> goalDecl :: Position -> Ident -> [Ident] -> Expression -> Decl+> goalDecl p g vs e = funDecl p g (map VariablePattern vs) e++> desugarGoalExpr :: ModuleIdent -> TCEnv -> Expression+> -> DesugarState (Expression,ValueEnv)+> desugarGoalExpr m tcEnv e =+> do+> e' <- desugarExpr m tcEnv (first "") e+> tyEnv' <- fetchSt+> return (e',tyEnv')++> liftGoalVars :: Expression -> ([Ident],Expression)+> liftGoalVars (Let ds e) =+> (concat [vs | ExtraVariables _ vs <- vds],Let ds' e)+> where (vds,ds') = partition isExtraVariables ds+> liftGoalVars e = ([],e)++\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 <- fetchSt+> 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 <- fetchSt+> 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) fetchSt+> where +> fixType tyEnv+> | typeOf tyEnv v == floatType +> = Float (ast $ 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 <- fetchSt+> liftM (if isNewtypeConstr tyEnv c then id else apSnd (constrPat c))+> (desugarTerm m tcEnv p ds t)+> where constrPat c t = ConstructorPattern c [t]+> desugarTerm m tcEnv p ds (ConstructorPattern c ts) =+> liftM (apSnd (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 (apSnd (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 (apSnd (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 <- fetchSt +> 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 <- fetchSt >>= freshIdent m "_#lazy" . monoType . flip typeOf t+> let v' = addPositionIdent (AST pos) v0+> return (patDecl p{ast=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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt >>=+> 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 <- fetchSt >>= freshIdent m "_#case" . monoType . flip typeOf e+> alts' <- mapM (desugarAltLhs m tcEnv) alts+> tyEnv <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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'+> updateSt_ (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 <- fetchSt+> 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))+> updateSt_ (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 <- fetchSt+> 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) (liftSt (updateSt (1 +)))+> updateSt_ (bindFun m x ty)+> return x+> where mkName pre n = mkIdent (pre ++ show n)++\end{verbatim}+Prelude entities+\begin{verbatim}++> prelUnif = Variable $ preludeIdent "=:="+> 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 []+> successPattern = ConstructorPattern (qualify successId) []++> 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.lhs view
@@ -0,0 +1,57 @@+% -*- LaTeX -*-+% $Id: Env.lhs,v 1.9 2002/12/20 15:07:56 lux Exp $+%+% Copyright (c) 2002, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{Env.lhs}+\section{Environments}+The module \texttt{Env} implements environments. An environment+$\rho = \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. For any environment we have the+following definitions:+\begin{displaymath}+ \begin{array}{l}+ \rho(x) = \left\{\begin{array}{ll}+ t_i&\mbox{if $x=x_i$}\\+ \bot&\mbox{otherwise}\end{array}\right. \\+ \mathop{{\mathcal D}om}(\rho) = \left\{x_1,\dots,x_n\right\} \\+ \mathop{{\mathcal C}odom}(\rho) = \left\{t_1,\dots,t_n\right\}+ \end{array}+\end{displaymath}++Unfortunately we cannot define \texttt{Env} as a \texttt{newtype}+because of a bug in the nhc compiler.+\begin{verbatim}++> module Env where+> import Map++> newtype Env a b = Env (FM a b) deriving Show++> emptyEnv :: Ord a => Env a b+> emptyEnv = Env zeroFM++> environment :: Ord a => [(a,b)] -> Env a b+> environment = foldr (uncurry bindEnv) emptyEnv++> envToList :: Ord v => Env v e -> [(v,e)]+> envToList (Env rho) = toListFM rho++> bindEnv :: Ord v => v -> e -> Env v e -> Env v e+> bindEnv v e (Env rho) = Env (addToFM v e rho)++> unbindEnv :: Ord v => v -> Env v e -> Env v e+> unbindEnv v (Env rho) = Env (deleteFromFM v rho)++> lookupEnv :: Ord v => v -> Env v e -> Maybe e+> lookupEnv v (Env rho) = lookupFM v rho++> envSize :: Ord v => Env v e -> Int+> envSize (Env rho) = length (toListFM rho)++> instance Ord a => Functor (Env a) where+> fmap f (Env rho) = Env (fmap f rho)++\end{verbatim}
+ src/Error.lhs view
@@ -0,0 +1,42 @@+% -*- LaTeX -*-+% $Id: Error.lhs,v 1.1 2003/05/07 22:38:42 wlux Exp $+%+% Copyright (c) 2003, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{Error.lhs}+\section{Errors}\label{sec:error}+The \texttt{Error} type is used for describing the result of a+computation that can fail. In contrast to the standard \texttt{Maybe}+type, its \texttt{Error} case provides for an error message that+describes the failure.+\begin{verbatim}++> module Error where+> import Control.Monad++> data Error a = Ok a | Error String deriving (Eq,Ord,Show)++> instance Functor Error where+> fmap f (Ok x) = Ok (f x)+> fmap f (Error e) = Error e++> instance Monad Error where+> return x = Ok x+> fail s = Error s+> Ok x >>= f = f x+> Error e >>= _ = Error e++> ok :: Error a -> a+> ok (Ok x) = x+> ok (Error e) = error e++> okM :: Monad m => Error a -> m a+> okM (Ok x) = return x+> okM (Error e) = fail e++> emap :: (String -> String) -> Error a -> Error a+> emap _ (Ok x) = Ok x+> emap f (Error e) = Error (f e)++\end{verbatim}
+ src/Eval.lhs view
@@ -0,0 +1,96 @@++% $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,evalEnvGoal) where+> import Base+> import Env++\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 emptyEnv++> evalEnvGoal :: Goal -> EvalEnv+> evalEnvGoal (Goal _ e ds) =+> collectAnnotsExpr e (foldr collectAnnotsDecl emptyEnv ds)++> collectAnnotsDecl :: Decl -> EvalEnv -> EvalEnv+> collectAnnotsDecl (EvalAnnot _ fs ev) env = foldr (flip bindEval 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.lhs view
@@ -0,0 +1,460 @@++% $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 Base+> import Map+> import Set+> 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 linear [unqualify tc | ExportTypeWith tc _ <- es'] of+> Linear ->+> case linear ([c | ExportTypeWith _ cs <- es', c <- cs] +++> [unqualify f | Export f <- es']) of+> Linear -> Module m (Just (Exporting noPos es')) ds+> NonLinear v -> errorAt' (ambiguousExportValue v)+> NonLinear tc -> errorAt' (ambiguousExportType tc) +> where ms = fromListSet [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 ModuleIdent -> ModuleIdent -> TCEnv -> ValueEnv+> -> ExportSpec -> [Export]+> expandSpecs ms m tcEnv tyEnv (Exporting _ es) =+> concat (map (expandExport ms m tcEnv tyEnv) es)++> expandExport :: 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 `elemSet` ms then expandModule tcEnv tyEnv m else [])+> ++ expandLocalModule tcEnv tyEnv+> | m' `elemSet` 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) <- toListFM (foldr joinType zeroFM es)] +++> [Export f | f <- toListSet (foldr joinFun zeroSet es)]++> joinType :: Export -> FM QualIdent [Ident] -> FM QualIdent [Ident]+> joinType (Export _) tcs = tcs+> joinType (ExportTypeWith tc cs) tcs =+> addToFM tc (cs `union` fromMaybe [] (lookupFM tc tcs)) tcs++> joinFun :: Export -> Set QualIdent -> Set QualIdent+> joinFun (Export f) fs = f `addToSet` 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 (fst (splitQualIdent 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 modul (foldr identsDecl [] ds)))+> where nub = toListSet . fromListSet+> modul = fst . splitQualIdent++> 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 <- toListSet tcs, not (isQualified tc)]+> where tcs = foldr deleteFromSet (fromListSet (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/ExtendedFlat.hs view
@@ -0,0 +1,513 @@+------------------------------------------------------------------------------+--- Library to support meta-programming in Curry.+---+--- This library contains a definition for representing FlatCurry programs+--- in Haskell (type "Prog").+---+--- @author Michael Hanus+--- @version September 2003+---+--- Version for Haskell (slightly modified):+--- December 2004, Martin Engelke (men@informatik.uni-kiel.de)+---+--- Added part calls for constructors, Bernd Brassel, August 2005+--- Added source references, Bernd Brassel, May 2009+------------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable, RankNTypes #-}++module ExtendedFlat (SrcRef,Prog(..), QName(..), Visibility(..),+ TVarIndex, TypeDecl(..), ConsDecl(..), TypeExpr(..),+ OpDecl(..), Fixity(..),+ VarIndex(..), + FuncDecl(..), Rule(..), + CaseType(..), CombType(..), Expr(..), BranchExpr(..),+ Pattern(..), Literal(..), + readFlatCurry, readFlatInterface, readFlat, + writeFlatCurry,gshowsPrec,+ qnOf,mkQName,+ mkIdx,idxOf) where++import PathUtils (writeModule,maybeReadModule)+import Data.List(intersperse)+import Control.Monad (liftM)+import Data.Generics hiding (Fixity)+import Position (SrcRef)+++------------------------------------------------------------------------------+-- Definition of data types for representing FlatCurry programs:+-- =============================================================++--- Data type for representing a Curry module in the intermediate form.+--- A value of this data type has the form+--- <CODE>+--- (Prog modname imports typedecls functions opdecls translation_table)+--- </CODE>+--- where modname: name of this module,+--- imports: list of modules names that are imported,+--- typedecls, opdecls, functions, translation of type names+--- and constructor/function names: see below++data Prog = Prog String [String] [TypeDecl] [FuncDecl] [OpDecl] + deriving (Read, Show, Eq,Data,Typeable)+++-------------------------------------------------------------------------+--- The data type for representing qualified names.+--- In FlatCurry all names are qualified to avoid name clashes.+--- The first component is the module name and the second component the+--- unqualified name as it occurs in the source program.+--- The additional information about source references and types should+--- be invisible for the normal usage of QName.+-------------------------------------------------------------------------++data QName = QName {srcRef :: Maybe SrcRef,+ typeofQName :: Maybe TypeExpr,+ modName :: String,+ localName :: String} deriving (Data,Typeable)+++app_prec = 10+hi_prec = app_prec+1++instance Read QName where+ readsPrec d r = + [ (mkQName nm,s) | (nm,s) <- readsPrec d r ]+ ++ readParen (d > app_prec) + (\r' -> [ (QName ref typ n m,res) + | ("QName",s0) <- lex r',+ (ref,s1) <- readsPrec hi_prec s0,+ (typ,s2) <- readsPrec hi_prec s1,+ (n,s3) <- readsPrec hi_prec s2,+ (m,res) <- readsPrec hi_prec s3 ]) r+ ++instance Show QName where+ showsPrec d (QName r t m n)= + showParen (d > app_prec) $ showString "QName " .+ showsPrec hi_prec r . showChar ' ' .+ showsPrec hi_prec t . showChar ' ' .+ showsPrec hi_prec m . showChar ' ' .+ showsPrec hi_prec n++instance Eq QName where (==) = onName (==)+instance Ord QName where compare = onName compare++mkQName :: (String,String) -> QName+mkQName = uncurry (QName Nothing Nothing)++qnOf :: QName -> (String,String) +qnOf QName{modName=m,localName=n} = (m,n)++onName :: ((String,String) -> (String,String) -> a) -> QName -> QName -> a+onName f QName{modName=m,localName=l} QName{modName=m',localName=l'} =+ f (m,l) (m',l')+++-------------------------------------------------------------------------+--- The data type for representing variable names.+--- The additional information should+--- be invisible for the normal usage of VarIndex.+-------------------------------------------------------------------------++data VarIndex = VarIndex {+ typeofVar :: Maybe TypeExpr,+ index :: Int+ } deriving (Data,Typeable)++onIndex :: (Int -> a) -> VarIndex -> a+onIndex f VarIndex{index=i} = f i++(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d+f .: g = \x -> f . g x++onIndexes :: (Int -> Int -> a) -> VarIndex -> VarIndex -> a+onIndexes = onIndex .: onIndex++mkIdx :: Int -> VarIndex+mkIdx = VarIndex Nothing++idxOf :: VarIndex -> Int+idxOf VarIndex{index=i}= i++instance Read VarIndex where+ readsPrec d r = + [ (mkIdx i,s) | (i,s) <- readsPrec d r ]+ ++ readParen (d > app_prec) + (\r' -> [ (VarIndex typ i,res) + | ("VarIndex",s0) <- lex r',+ (typ,s1) <- readsPrec hi_prec s0,+ (i,res) <- readsPrec hi_prec s1]) r+ ++instance Show VarIndex where+ showsPrec d (VarIndex t i)= + showParen (d > app_prec) $ showString "VarIndex " .+ showsPrec hi_prec t . showChar ' ' .+ showsPrec hi_prec i+++instance Eq VarIndex where (==) = onIndexes (==)+instance Ord VarIndex where compare = onIndexes compare++instance Num VarIndex where+ (+) = mkIdx .: onIndexes (+)+ (*) = mkIdx .: onIndexes (*)+ (-) = mkIdx .: onIndexes (-)+ abs = mkIdx . onIndex abs+ signum = mkIdx . onIndex signum+ fromInteger = mkIdx . fromInteger++------------------------------------------------------------+--- Data type to specify the visibility of various entities.+------------------------------------------------------------++data Visibility = Public -- public (exported) entity+ | Private -- private entity+ deriving (Read, Show, Eq,Data,Typeable)++--- The data type for representing type variables.+--- They are represented by (TVar i) where i is a type variable index.++type TVarIndex = Int++--- Data type for representing definitions of algebraic data types.+--- <PRE>+--- A data type definition of the form+---+--- data t x1...xn = ...| c t1....tkc |...+---+--- is represented by the FlatCurry term+---+--- (Type t [i1,...,in] [...(Cons c kc [t1,...,tkc])...])+---+--- where each ij is the index of the type variable xj+---+--- Note: the type variable indices are unique inside each type declaration+--- and are usually numbered from 0+---+--- Thus, a data type declaration consists of the name of the data type,+--- a list of type parameters and a list of constructor declarations.+--- </PRE>++data TypeDecl = Type QName Visibility [TVarIndex] [ConsDecl]+ | TypeSyn QName Visibility [TVarIndex] TypeExpr+ deriving (Read, Show, Eq,Data,Typeable)++--- A constructor declaration consists of the name and arity of the+--- constructor and a list of the argument types of the constructor.++data ConsDecl = Cons QName Int Visibility [TypeExpr]+ deriving (Read, Show, Eq,Data,Typeable)+++--- Data type for type expressions.+--- A type expression is either a type variable, a function type,+--- or a type constructor application.+---+--- Note: the names of the predefined type constructors are+--- "Int", "Float", "Bool", "Char", "IO", "Success",+--- "()" (unit type), "(,...,)" (tuple types), "[]" (list type)++data TypeExpr =+ TVar TVarIndex -- type variable+ | FuncType TypeExpr TypeExpr -- function type t1->t2+ | TCons QName [TypeExpr] -- type constructor application+ deriving (Read, Show, Eq,Data,Typeable) -- TCons module name typeargs+++--- Data type for operator declarations.+--- An operator declaration "fix p n" in Curry corresponds to the+--- FlatCurry term (Op n fix p).+--- Note: the constructor definition of 'Op' differs from the original+--- PAKCS definition using Haskell type 'Integer' instead of 'Int'+--- for representing the precedence. ++data OpDecl = Op QName Fixity Integer deriving (Read, Show, Eq,Data,Typeable)++--- Data types for the different choices for the fixity of an operator.++data Fixity = InfixOp | InfixlOp | InfixrOp deriving (Read, Show, Eq,Data,Typeable)+++--- Data type for representing object variables.+--- Object variables occurring in expressions are represented by (Var i)+--- where i is a variable index.++--- Data type for representing function declarations.+--- <PRE>+--- A function declaration in FlatCurry is a term of the form+---+--- (Func name arity type (Rule [i_1,...,i_arity] e))+---+--- and represents the function "name" with definition+---+--- name :: type+--- name x_1...x_arity = e+---+--- where each i_j is the index of the variable x_j+---+--- Note: the variable indices are unique inside each function declaration+--- and are usually numbered from 0+---+--- External functions are represented as (Func name arity type (External s))+--- where s is the external name associated to this function.+---+--- Thus, a function declaration consists of the name, arity, type, and rule.+--- </PRE>++data FuncDecl = Func QName Int Visibility TypeExpr Rule+ deriving (Read, Show, Eq,Data,Typeable)+++--- A rule is either a list of formal parameters together with an expression+--- or an "External" tag.++data Rule = Rule [VarIndex] Expr+ | External String+ deriving (Read, Show, Eq,Data,Typeable)++--- Data type for classifying case expressions.+--- Case expressions can be either flexible or rigid in Curry.++data CaseType = Rigid | Flex deriving (Read, Show, Eq,Data,Typeable)++--- Data type for classifying combinations+--- (i.e., a function/constructor applied to some arguments).+--- @cons FuncCall - a call to a function all arguments are provided+--- @cons ConsCall - a call with a constructor at the top,+--- all arguments are provided+--- @cons FuncPartCall - a partial call to a function+--- (i.e., not all arguments are provided) +--- where the parameter is the number of+--- missing arguments+--- @cons ConsPartCall - a partial call to a constructor along with +--- number of missing arguments++data CombType = FuncCall + | ConsCall + | FuncPartCall Int + | ConsPartCall Int deriving (Read, Show, Eq,Data,Typeable)++--- Data type for representing expressions.+---+--- Remarks:+--- <PRE>+--- 1. if-then-else expressions are represented as function calls:+--- (if e1 then e2 else e3)+--- is represented as+--- (Comb FuncCall ("Prelude","if_then_else") [e1,e2,e3])+--- +--- 2. Higher order applications are represented as calls to the (external)+--- function "apply". For instance, the rule+--- app f x = f x+--- is represented as+--- (Rule [0,1] (Comb FuncCall ("Prelude","apply") [Var 0, Var 1]))+--- +--- 3. A conditional rule is represented as a call to an external function+--- "cond" where the first argument is the condition (a constraint).+--- For instance, the rule+--- equal2 x | x=:=2 = success+--- is represented as+--- (Rule [0]+--- (Comb FuncCall ("Prelude","cond")+--- [Comb FuncCall ("Prelude","=:=") [Var 0, Lit (Intc 2)],+--- Comb FuncCall ("Prelude","success") []]))+--- +--- 4. Functions with evaluation annotation "choice" are represented+--- by a rule whose right-hand side is enclosed in a call to the+--- external function "Prelude.commit".+--- Furthermore, all rules of the original definition must be+--- represented by conditional expressions (i.e., (cond [c,e]))+--- after pattern matching.+--- Example:+--- +--- m eval choice+--- m [] y = y+--- m x [] = x+--- +--- is translated into (note that the conditional branches can be also+--- wrapped with Free declarations in general):+--- +--- Rule [0,1]+--- (Comb FuncCall ("Prelude","commit")+--- [Or (Case Rigid (Var 0)+--- [(Pattern ("Prelude","[]") []+--- (Comb FuncCall ("Prelude","cond")+--- [Comb FuncCall ("Prelude","success") [],+--- Var 1]))] )+--- (Case Rigid (Var 1)+--- [(Pattern ("Prelude","[]") []+--- (Comb FuncCall ("Prelude","cond")+--- [Comb FuncCall ("Prelude","success") [],+--- Var 0]))] )])+--- +--- Operational meaning of (Prelude.commit e):+--- evaluate e with local search spaces and commit to the first+--- (Comb FuncCall ("Prelude","cond") [c,ge]) in e whose constraint c+--- is satisfied+--- </PRE>+--- @cons Var - variable (represented by unique index)+--- @cons Lit - literal (Integer/Float/Char constant)+--- @cons Comb - application (f e1 ... en) of function/constructor f+--- with n<=arity(f)+--- @cons Free - introduction of free local variables+--- @cons Or - disjunction of two expressions (used to translate rules+--- with overlapping left-hand sides)+--- @cons Case - case distinction (rigid or flex)++data Expr = Var VarIndex + | Lit Literal+ | Comb CombType QName [Expr]+ | Free [VarIndex] Expr+ | Let [(VarIndex,Expr)] Expr+ | Or Expr Expr+ | Case SrcRef CaseType Expr [BranchExpr]+ deriving (Read, Show, Eq,Data,Typeable)+++--- Data type for representing branches in a case expression.+--- <PRE>+--- Branches "(m.c x1...xn) -> e" in case expressions are represented as+---+--- (Branch (Pattern (m,c) [i1,...,in]) e)+---+--- where each ij is the index of the pattern variable xj, or as+---+--- (Branch (LPattern (Intc i)) e)+---+--- for integers as branch patterns (similarly for other literals+--- like float or character constants).+--- </PRE>++data BranchExpr = Branch Pattern Expr deriving (Read, Show, Eq,Data,Typeable)++--- Data type for representing patterns in case expressions.++data Pattern = Pattern QName [VarIndex]+ | LPattern Literal+ deriving (Read, Show, Eq,Data,Typeable)++--- Data type for representing literals occurring in an expression+--- or case branch. It is either an integer, a float, or a character constant.+--- Note: the constructor definition of 'Intc' differs from the original+--- PAKCS definition. It uses Haskell type 'Integer' instead of 'Int'+--- to provide an unlimited range of integer numbers. Furthermore+--- float values are represented with Haskell type 'Double' instead of+--- 'Float'.++data Literal = Intc SrcRef Integer+ | Floatc SrcRef Double+ | Charc SrcRef Char+ deriving (Read, Show, Eq,Data,Typeable)+++------------------------------------------------------------------------------+------------------------------------------------------------------------------++-- Reads a FlatCurry file (extension ".fcy") and returns the corresponding+-- FlatCurry program term (type 'Prog') as a value of type 'Maybe'.+readFlatCurry :: FilePath -> IO (Maybe Prog)+readFlatCurry fn + = do let filename = genFlatFilename ".fcy" fn+ readFlat filename++-- Reads a FlatInterface file (extension ".fint") and returns the+-- corresponding term (type 'Prog') as a value of type 'Maybe'.+readFlatInterface :: String -> IO (Maybe Prog)+readFlatInterface fn+ = do let filename = genFlatFilename ".fint" fn+ readFlat filename++-- Reads a Flat file and returns the corresponding term (type 'Prog') as+-- a value of type 'Maybe'.+readFlat :: FilePath -> IO (Maybe Prog)+readFlat = liftM (fmap read) . maybeReadModule+ +-- Writes a FlatCurry program term into a file.+writeFlatCurry :: String -> Prog -> IO ()+writeFlatCurry filename prog+ = writeModule filename (showFlatCurry' prog)++-- Writes a FlatCurry program term with source references into a file.+writeFlatWithSrcRefs :: String -> Prog -> IO ()+writeFlatWithSrcRefs filename prog+ = writeModule filename (showFlatCurry prog)++-- Shows FlatCurry program in a more nicely way.+showFlatCurry :: Prog -> String+showFlatCurry (Prog mname imps types funcs ops) =+ "Prog "++show mname++"\n "+++ show imps ++"\n ["+++ concat (intersperse ",\n " (map (\t->show t) types)) ++"]\n ["+++ concat (intersperse ",\n " (map (\f->show f) funcs)) ++"]\n "+++ show ops ++"\n"+ ++-- Add the extension 'ext' to the filename 'fn' if it doesn't+-- already exist.+genFlatFilename :: String -> FilePath -> FilePath+genFlatFilename ext fn+ | drop (length fn - length ext) fn == ext+ = fn+ | otherwise+ = fn ++ ext++showFlatCurry' :: Prog -> String+showFlatCurry' x = gshowsPrec False x ""+++gshowsPrec :: Data a => Bool -> a -> ShowS+gshowsPrec d = + genericShowsPrec d `ext1Q` showsList+ `ext2Q` showsTuple+ `extQ` (const id :: SrcRef -> ShowS)+ `extQ` (const id :: [SrcRef] -> ShowS)+ `extQ` (shows :: String -> ShowS)+ `extQ` (shows :: Char -> ShowS)+ `extQ` showsQName+ `extQ` showsVarIndex+ + where+ showsQName :: QName -> ShowS+ showsQName QName{modName=m,localName=n} = shows (m,n)++ showsVarIndex :: VarIndex -> ShowS+ showsVarIndex VarIndex{index=i} = shows i++ genericShowsPrec :: Data a => Bool -> a -> ShowS+ genericShowsPrec d t = let args = intersperse (showChar ' ') $+ gmapQ (gshowsPrec True) t in+ showParen (d && not (null args)) $+ showString (showConstr (toConstr t)) .+ (if null args then id else showChar ' ') .+ foldr (.) id args++ showsList :: Data a => [a] -> ShowS+ showsList xs = showChar '[' . + foldr (.) (showChar ']') + (intersperse (showChar ',') $ + map (gshowsPrec False) xs)+ ++ showsTuple :: (Data a,Data b) => (a,b) -> ShowS+ showsTuple (x,y) = showChar '(' . + gshowsPrec False x . + showChar ',' .+ gshowsPrec False y .+ showChar ')' +++newtype Q r a = Q (a -> r)+ +ext2Q :: (Data d, Typeable2 t) => (d -> q) -> + (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q) -> d -> q+ext2Q def ext arg =+ case dataCast2 (Q ext) of+ Just (Q ext') -> ext' arg+ Nothing -> def arg++------------------------------------------------------------------------------+------------------------------------------------------------------------------+
+ src/Frontend.hs view
@@ -0,0 +1,262 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- Frontend - Provides an API for dealing with several kinds of Curry+-- program representations+--+-- December 2005,+-- Martin Engelke (men@informatik.uni-kiel.de)+--+module Frontend (lex, parse, fullParse, typingParse, abstractIO, flatIO,+ Result(..), Message(..)+ )where++import Data.List+import Data.Maybe+import Control.Monad+import Prelude hiding (lex)++import Modules+import CurryBuilder+import CurryCompilerOpts+import CurryParser+import CurryLexer+import GenAbstractCurry+import GenFlatCurry+import CaseCompletion+import CurryDeps hiding (unlitLiterate)+import qualified CurrySyntax as CS+import qualified AbstractCurry as ACY+import qualified ExtendedFlat as FCY+import qualified Error as Err+import CompilerResults+import Message+import CurryEnv+import Unlit+import Ident+import Position+import PathUtils+import Env+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++-- 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 -> Result [(Position,Token)]+lex fn src = genToks (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 -> Result CS.Module+parse fn src = let (err, src') = unlitLiterate fn src+ in if null err+ then genCurrySyntax fn (parseSource True fn src')+ else Failure [message_ Error err]+++-- 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 (Result CS.Module)+fullParse paths fn src =+ 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 (Result 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 (Result 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 (Result FCY.Prog)+flatIO paths fn src = + genFlatIO paths fn (parse fn src)+++-------------------------------------------------------------------------------+-- Result handling++data Result a = Result [Message] a | Failure [Message] deriving Show++-- See module "Message":++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+-- Privates...+++opts paths = defaultOpts{ + importPaths = paths,+ noVerb = True,+ noWarn = True,+ abstract = True+ }+++--+genToks :: Err.Error [(Position,Token)] -> Result [(Position,Token)]+genToks (Err.Ok toks) = Result [] toks+genToks (Err.Error err) = Failure [message_ Error err]+++--+genCurrySyntax :: FilePath -> Err.Error CS.Module -> Result (CS.Module)+genCurrySyntax fn (Err.Ok mod)+ = let mod'@(CS.Module mid _ _) = patchModuleId fn (importPrelude fn mod)+ in if isValidModuleId fn mid+ then Result [] mod'+ else Failure [message_ Error (err_invalidModuleName mid)]+genCurrySyntax _ (Err.Error err)+ = Failure [message_ Error err]+++--+genFullCurrySyntax check paths fn (Result msgs mod)+ = do errs <- makeInterfaces paths mod+ if null errs+ then do mEnv <- loadInterfaces paths mod+ (_, _, _, mod', _, msgs') <- check (opts paths) mEnv mod+ return (Result (msgs ++ msgs') mod')+ else return (Failure (msgs ++ map (message_ Error) errs))+genFullCurrySyntax _ _ _ (Failure msgs) = return (Failure msgs)+++--+genAbstractIO :: [FilePath] -> FilePath -> Result CS.Module+ -> IO (Result ACY.CurryProg)+genAbstractIO paths fn (Result msgs 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 (Result (msgs ++ msgs') + (genTypedAbstract tyEnv tcEnv mod'))+ else return (Failure (msgs ++ map (message_ Error) errs))+genAbstractIO _ _ (Failure msgs) = return (Failure msgs)+++--+genFlatIO :: [FilePath] -> FilePath -> Result CS.Module -> IO (Result FCY.Prog)+genFlatIO paths fn (Result msgs 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 (Result (msgs'' ++ msgs ++ msgs') prog)+ )+ else return (Failure (msgs ++ map (message_ Error) errs))+genFlatIO _ _ (Failure msgs) = return (Failure msgs)+++-------------------------------------------------------------------------------++-- 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 . sortDeps)+ (foldM (moduleDeps paths []) emptyEnv imports)+ when (null errs) (mapM_ (compile deps . snd) deps)+ return errs+ where+ compile deps (Source file' mods)+ = do smake [flatName file', flatIntName file']+ (file':catMaybes (map (flatInterface deps) mods))+ (compileCurry (opts paths) file')+ (return defaultResults)+ return ()+ compile _ _ = return ()++ flatInterface deps mod + = case (lookup mod deps) of+ Just (Source file _) -> Just (flatIntName (rootname file))+ Just (Interface file) -> Just (flatIntName (rootname file))+ _ -> Nothing++-- Declares the filename as module name, if the module name is not+-- explicitly declared in the module.+patchModuleId :: FilePath -> CS.Module -> CS.Module+patchModuleId fn (CS.Module mid mexports decls)+ | (moduleName mid) == "main"+ = CS.Module (mkMIdent [basename (rootname fn)]) mexports decls+ | otherwise+ = CS.Module mid mexports decls+++-- Adds an import declaration for the prelude to the module, if+-- it is not the prelude itself. If the module already has an explicit+-- import for the prelude, then a qualified import is added.+importPrelude :: FilePath -> CS.Module -> CS.Module+importPrelude fn (CS.Module m es ds)+ = CS.Module m es (if m == preludeMIdent then ds else ds')+ where ids = [decl | decl@(CS.ImportDecl _ _ _ _ _) <- ds]+ ds' = CS.ImportDecl (first fn) preludeMIdent+ (preludeMIdent `elem` map importedModule ids)+ Nothing Nothing : ds+ importedModule (CS.ImportDecl _ m q asM is) = fromMaybe m asM+++-- Returns 'True', if file name and module name are equal.+isValidModuleId :: FilePath -> ModuleIdent -> Bool+isValidModuleId fn mid+ = last (moduleQualifiers mid) == basename (rootname fn)+++-- Converts a literate source program to a non-literate source program+unlitLiterate :: FilePath -> String -> (String,String)+unlitLiterate fn src+ | isLiterateSource fn = unlit fn src+ | otherwise = ("",src)++isLiterateSource :: FilePath -> Bool+isLiterateSource fn = litExt `isSuffixOf` fn++litExt = ".lcurry"++compileCurry = compileModule_++-------------------------------------------------------------------------------+-- Messages++err_invalidModuleName :: ModuleIdent -> String+err_invalidModuleName mid + = "module \"" ++ moduleName mid + ++ "\" must be in a file \"" ++ moduleName mid ++ ".curry\""+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/GenAbstractCurry.hs view
@@ -0,0 +1,1108 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- GenAbstractCurry - Generates an AbstractCurry program term+-- (type 'CurryProg')+--+-- July 2005,+-- Martin Engelke (men@informatik.uni-kiel.de)+--+module GenAbstractCurry (genTypedAbstract, + genUntypedAbstract) where++import Data.Maybe+import Data.List+import Data.Char++import AbstractCurry+import Base+import Types+import Ident+import Position+import TopEnv+import Env+++-------------------------------------------------------------------------------++-- 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, _) + = mapfoldl (genFuncDecl False) + env + (funcDecls partitions)+ (ops, _) + = mapfoldl genOpDecl env (reverse (opDecls partitions))+ in CurryProg modname imps types 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+ = insertEntry id ((genDecl id):(fromMaybe [] (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 :: [(Ident,[Decl])],+ opDecls :: [Decl]+ } deriving Show++-- Generates initial partitions.+emptyPartitions = Partitions {importDecls = [],+ typeDecls = [],+ funcDecls = [],+ 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 rec@(RecordType _ _)+ -> let (CRecordType fields rbase, env2) = genTypeExpr env1 rec+ fields' = foldr (\ (l,t) -> insertEntry l t) + 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)+ 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]) -> (CFuncDecl, AbstractEnv)+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 = applyMaybe 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 (CFunc name arity visibility typeexpr rule, env3)+ | otherwise+ = internalError ("missing declaration for function \""+ ++ show ident ++ "\"")+ where+ genFuncType env decls+ | acytype == UntypedAcy+ = applyMaybe (genTypeSig env) (find isTypeSig decls)+ | acytype == TypedAcy+ = applyMaybe (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 -> [(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 -> [(Ident,[Decl])] -> Ident + -> (CLocalDecl, AbstractEnv)+ genLocalFuncDecl env fdecls ident+ = let fdecl = fromMaybe + (internalError ("missing declaration" + ++ " for local function \""+ ++ show ident ++ "\""))+ (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 (\e1 e2 -> Apply (Apply cons e1) e2) 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+ ident = unqualify qident++ genQualName qid+ = let (mmid, id) = splitQualIdent qid+ mid = maybe (moduleId env)+ (\mid' -> fromMaybe mid' (lookupEnv 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 :: Env Ident (),+ imports :: Env ModuleIdent ModuleIdent,+ varIndex :: Int,+ tvarIndex :: Int,+ varScope :: [Env Ident Int],+ tvarScope :: [Env 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) emptyEnv exps',+ imports = foldl buildImportTable emptyEnv decls,+ varIndex = 0,+ tvarIndex = 0,+ varScope = [emptyEnv],+ tvarScope = [emptyEnv],+ 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] -> Env Ident () -> Export + -> Env 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 :: Env Ident () -> Ident -> Env Ident ()+insertExportedIdent env ident = bindEnv 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 :: Env ModuleIdent ModuleIdent -> Decl+ -> Env ModuleIdent ModuleIdent+buildImportTable env (ImportDecl _ mid _ malias _)+ = bindEnv (fromMaybe mid malias) mid env+buildImportTable env _ = env+++-- Checks whether an identifier is exported or not.+isExported :: AbstractEnv -> Ident -> Bool+isExported env ident = isJust (lookupEnv 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 emptyEnv else head vtabs+ in (idx, env {varIndex = idx + 1,+ varScope = (bindEnv 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 emptyEnv else head vtabs+ in (idx, env {tvarIndex = idx + 1,+ tvarScope = (bindEnv 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 = lookupEnv 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 = lookupEnv 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)++-- Generates an indentifier which doesn't occur in the type variable table+-- of the current scope.+freshTVar :: AbstractEnv -> String -> Ident+freshTVar env name = genFreshTVar env name 0+ where+ genFreshTVar env name idx+ | isJust (getTVarIndex env ident)+ = genFreshTVar 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 = [emptyEnv],+ tvarScope = [emptyEnv]}++-- 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) = splitQualIdent 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 (toCSType 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 (toCSType ty)) ts+ _ -> Nothing+++-- Converts the internal representation of the types from the type+-- envorinment to CurrySyntax representation+toCSType :: Type -> TypeExpr+toCSType = fromType +{-+toCSType (TypeConstructor qident types)+ = ConstructorType qident (map toCSType types)+toCSType (TypeVariable idx)+ = VariableType (mkVarIdent idx)+toCSType (TypeConstrained types _)+ = toCSType (head types)+toCSType (TypeArrow type1 type2)+ = ArrowType (toCSType type1) (toCSType type2)+toCSType (TypeSkolem idx)+ = VariableType (mkVarIdent idx)+-}++{-+--+solveTypeSyn :: TCEnv -> QualIdent -> [TypeExpr] -> Maybe TypeExpr+solveTypeSyn tcEnv qident args+ = case (qualLookupTC qident tcEnv) of+ [AliasType _ _ t] -> Just (adaptType args t)+ _ -> case (lookupTC (unqualify qident) tcEnv) of+ [AliasType _ _ t] -> Just (adaptType args t)+ _ -> Nothing++--+adaptType :: [TypeExpr] -> Type -> TypeExpr+adaptType args texpr = adapt (zip [0 .. ((length args) - 1)] args) texpr+ where+ adapt its (TypeConstructor qident types)+ = ConstructorType qident (map (adapt its) types)+ adapt its (TypeVariable idx)+ = fromMaybe (internalError "cannot adapt type variable")+ (lookup idx its)+ adapt its (TypeConstrained types _)+ = adapt its (head types)+ adapt its (TypeArrow type1 type2)+ = ArrowType (adapt its type1) (adapt its type2)+ adapt its (TypeSkolem idx)+ = adapt its (TypeVariable idx)+-}++-- Generates a variable name from an index.+mkVarIdent :: Int -> Ident+mkVarIdent i | i < 0 = mkIdent ('b':(show (i * (-1)))) + | i < 26 = mkIdent [chr (i + ord 'a')]+ | otherwise = mkIdent ('a':(show i))+ +++-- The following functions transform left-hand-side and right-hand-side terms+-- for a better handling+simplifyLhs :: Lhs -> [ConstrTerm]+simplifyLhs lhs = snd (flatLhs lhs)++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+++-- Applies the function 'f' on the value which is wrapped in 'Just'.+applyMaybe :: (a -> b) -> Maybe a -> Maybe b+applyMaybe f (Just x) = Just (f x)+applyMaybe _ Nothing = Nothing++-- 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 view
@@ -0,0 +1,1140 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 Debug.Trace++import Control.Monad.State+import Control.Monad+import Data.Maybe+import Data.List++import Base (ArityEnv, ArityInfo(..), ModuleEnv, PEnv, PrecInfo(..), + OpPrec(..), TCEnv, TypeInfo(..), ValueEnv, ValueInfo(..),+ lookupValue, qualLookupTC,+ qualLookupArity, lookupArity, internalError)++--import FlatWithSrcRefs+import ExtendedFlat++import qualified IL+import qualified CurrySyntax as CS++import CurryEnv (CurryEnv)+import qualified CurryEnv++import ScopeEnv (ScopeEnv)+import qualified ScopeEnv+++import Types+import CurryCompilerOpts+import Message+import PatchPrelude+import Ident as Id+import Env+import Map+++-------------------------------------------------------------------------------++-- transforms intermediate language code (IL) to FlatCurry code+genFlatCurry :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv + -> ArityEnv -> IL.Module -> (Prog, [Message])+genFlatCurry opts cEnv mEnv tyEnv tcEnv aEnv mod+ = (patchPreludeFCY prog, messages)+ where (prog, messages) + = run opts cEnv mEnv tyEnv tcEnv aEnv False (visitModule mod)+++-- transforms intermediate language code (IL) to FlatCurry interfaces+genFlatInterface :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv+ -> ArityEnv -> IL.Module -> (Prog, [Message])+genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv mod+ = (patchPreludeFCY intf, messages)+ where (intf, messages) + = run opts cEnv mEnv tyEnv tcEnv aEnv True (visitModule mod)+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++--+visitModule :: IL.Module -> FlatState Prog+visitModule (IL.Module mid imps decls)+ = 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 <- visitQualIdent 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 <- visitQualIdent qident+ if (qualName qident) == "Identity"+ then return (head texprs)+ else return (TCons qname texprs)+visitType (IL.TypeVariable index)+ = return (TVar (int2num 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)+ = whenFlatCurry+ (do setFunctionId qident+ is <- mapM newVarIndex params+ texpr <- visitType typeexpr+ expr <- visitExpression expression+ qname <- visitQualIdent qident+ vis <- getVisibility False qident+ clearVarIndices+ return (Func qname (length params) vis texpr (Rule is expr)))+ (do setFunctionId qident+ texpr <- visitType typeexpr+ qname <- visitQualIdent qident+ 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+ maybe (internalError (funcArity qident))+ (\arity -> genFuncCall qident arity [])+ arity_+visitExpression (IL.Constructor qident arity)+ = do arity_ <- lookupIdArity qident+ maybe (internalError (consArity qident))+ (\arity -> genConsCall qident arity [])+ arity_+visitExpression (IL.Apply expression1 expression2)+ = genFlatApplication (IL.Apply expression1 expression2)+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+ case expr of+ Let binds expr' -> return (Let (bind:binds) expr')+ _ -> return (Let [bind] expr)+visitExpression (IL.Letrec bindings expression)+ = do beginScope+ mapM_ newVarIndex (map bindingIdent bindings)+ binds <- mapM visitBinding bindings+ expr <- visitExpression expression+ endScope+ return (Let binds expr)+++getTypeOf :: Ident -> FlatState (Maybe TypeExpr)+getTypeOf ident = do+ (valEnv, _) <- environments+ case lookupValue ident valEnv of + Value _ (ForAll _ t) : _ + -> do t <- visitType (ttrans t)+ trace ("getTypeOf(" ++ show ident ++ ") = " ++ show t)$+ return (Just t)+ v -> trace ("lookupValue did not return a value for index " ++ show ident ++ ", instead " ++ show v)+ (return Nothing)+ where ttrans :: Type -> IL.Type + ttrans (TypeConstructor i ts)+ = IL.TypeConstructor i (map ttrans ts)+ ttrans (TypeVariable v)+ = IL.TypeVariable v+ ttrans (TypeConstrained [] v)+ = trace (msg1 v) $ IL.TypeVariable v+ ttrans (TypeConstrained (v:_) i)+ = trace (msg2 i ilt) ilt+ where ilt = 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+ msg1 i = "in ttrans: empty TypeConstrained, coerced to type var #" ++ show i+ msg2 i t = "in ttrans: TypeConstrained with index " ++ show i ++ ", coerced to " ++ show t++--+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")+ (fst (splitQualIdent qident))+ is = [0 .. (length params) - 1]+ cdecls <- mapM (visitConstrIDecl mid (zip params is)) + (catMaybes constrs_)+ qname <- visitQualIdent 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 <- visitQualIdent 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 (map (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 mident = return (Id.moduleName mident)++--+visitQualIdent :: QualIdent -> FlatState QName+visitQualIdent qident+ = do mid <- moduleId+ let (mmod, ident) = splitQualIdent qident+ mod | elem ident [listId, consId, nilId, unitId] || isTupleId ident+ = Id.moduleName preludeMIdent+ | otherwise+ = maybe (Id.moduleName mid) Id.moduleName mmod+ return (curry mkQName 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 (envToList (getExpImports mid emptyEnv exps))++--+getExpImports :: ModuleIdent -> Env ModuleIdent [CS.Export] -> [CS.Export]+ -> Env 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 (bindEnv mident' [] expenv) exps++--+bindExpImport :: ModuleIdent -> QualIdent -> CS.Export + -> Env ModuleIdent [CS.Export] -> Env ModuleIdent [CS.Export]+bindExpImport mident qident export expenv+ | isJust (localIdent mident qident)+ = expenv+ | otherwise+ = let (mmod, _) = splitQualIdent qident+ mod = fromJust mmod+ in maybe (bindEnv mod [export] expenv)+ (\es -> bindEnv mod (export:es) expenv) + (lookupEnv 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 -> FlatState Expr+genFlatApplication applicexpr+ = genFlatApplic [] applicexpr+ where+ genFlatApplic args expression + = case expression of+ (IL.Apply expr1 expr2) + -> genFlatApplic (expr2:args) expr1+ (IL.Function qident _)+ -> do arity_ <- lookupIdArity qident+ maybe (internalError (funcArity qident))+ (\arity -> genFuncCall qident arity args)+ arity_+ (IL.Constructor qident _)+ -> do arity_ <- lookupIdArity qident+ maybe (internalError (consArity qident))+ (\arity -> genConsCall qident arity args)+ arity_+ _ -> do expr <- visitExpression expression+ genApplicComb expr args++--+genFuncCall :: QualIdent -> Int -> [IL.Expression] -> FlatState Expr+genFuncCall qident arity args+ | arity > cnt + = genComb qident args (FuncPartCall (arity - cnt))+ | arity < cnt + = do let (funcargs, applicargs) = splitAt arity args+ funccall <- genComb qident funcargs FuncCall+ genApplicComb funccall applicargs+ | otherwise + = genComb qident args FuncCall+ where cnt = length args++--+genConsCall :: QualIdent -> Int -> [IL.Expression] -> FlatState Expr+genConsCall qident arity args+ | arity > cnt + = genComb qident args (ConsPartCall (arity - cnt))+ | arity < cnt+ = do let (funcargs, applicargs) = splitAt arity args+ conscall <- genComb qident funcargs ConsCall+ genApplicComb conscall applicargs+ | otherwise + = genComb qident args ConsCall + where cnt = length args++--+genComb :: QualIdent -> [IL.Expression] -> CombType -> FlatState Expr+genComb qident args combtype+ = do exprs <- mapM visitExpression args+ qname <- visitQualIdent qident+ 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 >>= (\fix -> mapM genOpDecl fix)++--+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,tcEnv) <- environments+ let typeexpr' = elimRecordTypes tyEnv tcEnv typeexpr+ texpr <- visitType (fst (cs2ilType (zip params is) typeexpr'))+ qname <- visitQualIdent 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) = splitQualIdent 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,tcEnv) <- environments+ 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) zeroFM fs'+ types = map (\i -> maybe + (CS.VariableType + (mkIdent ("#tvar" ++ show i)))+ (elimRecordTypes tyEnv tcEnv)+ (lookupFM 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)] -> FM Int CS.TypeExpr+ -> (Ident, Type) -> FM Int CS.TypeExpr+matchTypeVars fs ms (l,ty)+ = maybe ms (match ms ty) (lookup l fs)+ where+ match ms (TypeVariable i) typeexpr = addToFM 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 typeexprs+ = foldl (\ms' (ty,typeexpr) -> match ms' ty typeexpr)+ ms+ (zip tys typeexprs)+++flattenRecordTypeFields :: [([Ident],CS.TypeExpr)] -> [(Ident,CS.TypeExpr)]+flattenRecordTypeFields fss+ = concatMap (\ (labels, typeexpr)+ -> map (\label -> (label,typeexpr)) labels)+ fss++-------------------------------------------------------------------------------++--+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 = (OverlapRules,+ "function \""+ ++ show qid + ++ "\" is non-deterministic due to non-trivial "+ ++ "overlapping rules")+++-------------------------------------------------------------------------------+prelude_types :: [TypeDecl]+prelude_types = [(Type (preludeName "()") Public [] + [(Cons (preludeName "()") 0 Public [])]),+ (Type (preludeName "[]") Public [0] + [(Cons (preludeName "[]") 0 Public []),+ (Cons (preludeName ":") 2 Public + [(TVar 0),(TCons (preludeName "[]") [(TVar 0)])])])]+ ++ map mkTupleType [2..15]+ where+ preludeName = curry mkQName "Prelude"+ mkTupleType n = let last = n-1+ name = preludeName("(" ++ replicate last ',' ++ ")")+ idxs = [0..last]+ vars = map TVar idxs+ in Type name Public idxs [Cons name n Public vars]+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++--+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++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++int2num :: Int -> Int+int2num = abs+++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'')++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++-- Data type for representing an environment which contains information needed+-- for generating FlatCurry code.+data FlatEnv = FlatEnv{ moduleIdE :: ModuleIdent,+ functionIdE :: QualIdent,+ compilerOptsE :: Options,+ moduleEnvE :: ModuleEnv,+ arityEnvE :: ArityEnv,+ typeEnvE :: ValueEnv,+ tConsEnvE :: TCEnv,+ publicEnvE :: Env 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,+ tvarIdsE :: ScopeEnv Ident TVarIndex,+ messagesE :: [Message],+ genInterfaceE :: Bool+ }++data IdentExport = NotConstr -- function, type-constructor+ | OnlyConstr -- constructor+ | NotOnlyConstr -- constructor, function, type-constructor++++-- The environment 'FlatEnv' is embedded in the monadic representation+-- 'FlatState' which allows the usage of 'do' expressions.+type FlatState a = State FlatEnv a+++-- Runs a 'FlatState' action and returns the result+run :: Options -> CurryEnv -> ModuleEnv -> ValueEnv -> TCEnv -> ArityEnv + -> Bool -> FlatState a -> (a, [Message])+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,+ tvarIdsE = ScopeEnv.new,+ messagesE = [],+ genInterfaceE = genIntf+ }+++--+moduleId :: FlatState ModuleIdent+moduleId = gets moduleIdE++--+functionId :: FlatState QualIdent+functionId = gets functionIdE++--+setFunctionId :: QualIdent -> 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++--+environments :: FlatState (ValueEnv,TCEnv)+environments = gets (\env -> (typeEnvE env, tConsEnvE env))++--+isPublic :: Bool -> QualIdent -> FlatState Bool+isPublic isConstr qid = gets (\env -> maybe False isP+ (lookupEnv (unqualify qid) + (publicEnvE env)))+ where+ isP NotConstr = not isConstr+ isP OnlyConstr = isConstr+ isP NotOnlyConstr = True++--+lookupModuleIntf :: ModuleIdent -> FlatState (Maybe [CS.IDecl])+lookupModuleIntf mid+ = gets (lookupEnv 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++-- Generates a new index for a variable+newVarIndex :: Ident -> FlatState VarIndex+newVarIndex id+ = do idx0 <- gets varIndexE+ ty <- getTypeOf id+ let idx = idx0 + 1+ vid = VarIndex ty idx+ vids <- gets varIdsE+ modify (\env -> env{ varIndexE = idx,+ varIdsE = ScopeEnv.insert id 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 + })++-- Generates a new index for a type variable+newTVarIndex :: Ident -> FlatState Int+newTVarIndex id+ = do idx0 <- gets tvarIndexE+ let idx = 1 + idx0+ vids <- gets tvarIdsE+ modify (\env -> env{ tvarIndexE = idx,+ tvarIdsE = ScopeEnv.insert id idx vids+ })+ return idx++-- Looks up the index of an existing type variable or generates a new index,+-- if the type variable doesn't exist+getTVarIndex :: Ident -> FlatState Int+getTVarIndex id+ = do idx0 <- gets tvarIndexE+ let idx = idx0 + 1+ vids <- gets tvarIdsE + maybe (do modify (\env -> env{ tvarIndexE = idx,+ tvarIdsE = ScopeEnv.insert id idx vids })+ return idx)+ return+ (ScopeEnv.lookup id vids)++--+lookupTVarIndex :: Ident -> FlatState (Maybe Int)+lookupTVarIndex id+ = gets (ScopeEnv.lookup id . tvarIdsE)++--+clearTVarIndices :: FlatState ()+clearTVarIndices = modify (\env -> env { tvarIndexE = 0,+ tvarIdsE = ScopeEnv.new + })++--+genWarning :: (WarningType,String) -> FlatState ()+genWarning (warnType,msg)+ = modify (\env -> env{ messagesE = warnMsg:(messagesE env) })+ where warnMsg = message_ (Warning warnType) msg++--+genInterface :: FlatState Bool+genInterface = gets genInterfaceE++--+beginScope :: FlatState ()+beginScope = modify+ (\env -> env { varIdsE = ScopeEnv.beginScope (varIdsE env),+ tvarIdsE = ScopeEnv.beginScope (tvarIdsE env)+ })++--+endScope :: FlatState ()+endScope = modify+ (\env -> env { varIdsE = ScopeEnv.endScope (varIdsE env),+ tvarIdsE = ScopeEnv.endScope (tvarIdsE 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] -> Env Ident IdentExport+genPubEnv mid idecls = foldl (bindEnvIDecl mid) emptyEnv idecls++bindIdentExport :: Ident -> Bool -> Env Ident IdentExport -> Env Ident IdentExport+bindIdentExport id isConstr env =+ maybe (bindEnv id (if isConstr then OnlyConstr else NotConstr) env)+ (\ ie -> bindEnv id (updateIdentExport ie isConstr) env)+ (lookupEnv id env)+ where+ updateIdentExport OnlyConstr True = OnlyConstr+ updateIdentExport OnlyConstr False = NotOnlyConstr+ updateIdentExport NotConstr True = NotOnlyConstr+ updateIdentExport NotConstr False = NotConstr+ updateIdentExport NotOnlyConstr _ = NotOnlyConstr+++--+bindEnvIDecl :: ModuleIdent -> Env Ident IdentExport -> CS.IDecl -> Env 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 :: Env Ident IdentExport -> Ident -> CS.TypeExpr+ -> Env 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 :: Env Ident IdentExport -> CS.ConstrDecl -> Env Ident IdentExport+bindEnvConstrDecl env (CS.ConstrDecl _ _ id _) = bindIdentExport id True env+bindEnvConstrDecl env (CS.ConOpDecl _ _ _ id _) = bindIdentExport id True env++--+bindEnvNewConstrDecl :: Env Ident IdentExport -> CS.NewConstrDecl -> Env Ident IdentExport+bindEnvNewConstrDecl env (CS.NewConstrDecl _ _ id _) = bindIdentExport id False env++--+bindEnvRecordLabel :: Ident -> Env Ident IdentExport -> ([Ident],CS.TypeExpr) + -> Env Ident IdentExport+bindEnvRecordLabel rec env ([lab],_)+ = bindIdentExport (recSelectorId (qualify rec) lab)+ False+ (bindIdentExport (recUpdateId (qualify rec) lab) False env)+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/GetOpt.hs view
@@ -0,0 +1,194 @@+-----------------------------------------------------------------------------------------+-- A Haskell port of GNU's getopt library+-- +-- Sven Panne <Sven.Panne@informatik.uni-muenchen.de> Oct. 1996 (small changes Dec. 1997)+--+-- Two rather obscure features are missing: The Bash 2.0 non-option hack (if you don't+-- already know it, you probably don't want to hear about it...) and the recognition of+-- long options with a single dash (e.g. '-help' is recognised as '--help', as long as+-- there is no short option 'h').+--+-- Other differences between GNU's getopt and this implementation:+-- * To enforce a coherent description of options and arguments, there are explanation+-- fields in the option/argument descriptor.+-- * Error messages are now more informative, but no longer POSIX compliant... :-(+-- +-- And a final Haskell advertisement: The GNU C implementation uses well over 1100 lines,+-- we need only 195 here, including a 46 line example! :-)+-----------------------------------------------------------------------------------------++module GetOpt (ArgOrder(..), OptDescr(..), ArgDescr(..), usageInfo, getOpt) where++import Data.List(isPrefixOf)++data ArgOrder a -- what to do with options following non-options:+ = RequireOrder -- no option processing after first non-option+ | Permute -- freely intersperse options and non-options+ | ReturnInOrder (String -> a) -- wrap non-options into options++data OptDescr a = -- description of a single options:+ Option [Char] -- list of short option characters+ [String] -- list of long option strings (without "--")+ (ArgDescr a) -- argument descriptor+ String -- explanation of option for user++data ArgDescr a -- description of an argument option:+ = NoArg a -- no argument expected+ | ReqArg (String -> a) String -- option requires argument+ | OptArg (Maybe String -> a) String -- optional argument++data OptKind a -- kind of cmd line arg (internal use only):+ = Opt a -- an option+ | NonOpt String -- a non-option+ | EndOfOpts -- end-of-options marker (i.e. "--")+ | OptErr String -- something went wrong...++usageInfo :: String -- header+ -> [OptDescr a] -- option descriptors+ -> String -- nicely formatted decription of options+usageInfo header optDescr = unlines (header:table)+ where (ss,ls,ds) = (unzip3 . map fmtOpt) optDescr+ table = zipWith3 paste (sameLen ss) (sameLen ls) (sameLen ds)+ paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z+ sameLen xs = flushLeft ((maximum . map length) xs) xs+ flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ]++fmtOpt :: OptDescr a -> (String,String,String)+fmtOpt (Option sos los ad descr) = (sepBy ", " (map (fmtShort ad) sos),+ sepBy ", " (map (fmtLong ad) los),+ descr)+ where sepBy sep [] = ""+ sepBy sep [x] = x+ sepBy sep (x:xs) = x ++ sep ++ sepBy sep xs++fmtShort :: ArgDescr a -> Char -> String+fmtShort (NoArg _ ) so = "-" ++ [so]+fmtShort (ReqArg _ ad) so = "-" ++ [so] ++ " " ++ ad+fmtShort (OptArg _ ad) so = "-" ++ [so] ++ "[" ++ ad ++ "]"++fmtLong :: ArgDescr a -> String -> String+fmtLong (NoArg _ ) lo = "--" ++ lo+fmtLong (ReqArg _ ad) lo = "--" ++ lo ++ "=" ++ ad+fmtLong (OptArg _ ad) lo = "--" ++ lo ++ "[=" ++ ad ++ "]"++getOpt :: ArgOrder a -- non-option handling+ -> [OptDescr a] -- option descriptors+ -> [String] -- the commandline arguments+ -> ([a],[String],[String]) -- (options,non-options,error messages)+getOpt _ _ [] = ([],[],[])+getOpt ordering optDescr (arg:args) = procNextOpt opt ordering+ where procNextOpt (Opt o) _ = (o:os,xs,es)+ procNextOpt (NonOpt x) RequireOrder = ([],x:rest,[])+ procNextOpt (NonOpt x) Permute = (os,x:xs,es)+ procNextOpt (NonOpt x) (ReturnInOrder f) = (f x :os, xs,es)+ procNextOpt EndOfOpts RequireOrder = ([],rest,[])+ procNextOpt EndOfOpts Permute = ([],rest,[])+ procNextOpt EndOfOpts (ReturnInOrder f) = (map f rest,[],[])+ procNextOpt (OptErr e) _ = (os,xs,e:es)++ (opt,rest) = getNext arg args optDescr+ (os,xs,es) = getOpt ordering optDescr rest++-- take a look at the next cmd line arg and decide what to do with it+getNext :: String -> [String] -> [OptDescr a] -> (OptKind a,[String])+getNext "--" rest _ = (EndOfOpts,rest)+getNext ('-':'-':xs) rest optDescr = longOpt xs rest optDescr+getNext ('-':x:xs) rest optDescr = shortOpt x xs rest optDescr+getNext a rest _ = (NonOpt a,rest)++-- handle long option+longOpt :: String -> [String] -> [OptDescr a] -> (OptKind a,[String])+longOpt xs rest optDescr = long ads arg rest+ where (opt,arg) = break (=='=') xs+ options = [ o | o@(Option _ ls _ _) <- optDescr, l <- ls, opt `isPrefixOf` l ]+ ads = [ ad | Option _ _ ad _ <- options ]+ optStr = ("--"++opt)++ long (_:_:_) _ rest = (errAmbig options optStr,rest)+ long [NoArg a ] [] rest = (Opt a,rest)+ long [NoArg a ] ('=':xs) rest = (errNoArg optStr,rest)+ long [ReqArg f d] [] [] = (errReq d optStr,[])+ long [ReqArg f _] [] (r:rest) = (Opt (f r),rest)+ long [ReqArg f _] ('=':xs) rest = (Opt (f xs),rest)+ long [OptArg f _] [] rest = (Opt (f Nothing),rest)+ long [OptArg f _] ('=':xs) rest = (Opt (f (Just xs)),rest)+ long _ _ rest = (errUnrec optStr,rest)++-- handle short option+shortOpt :: Char -> String -> [String] -> [OptDescr a] -> (OptKind a,[String])+shortOpt x xs rest optDescr = short ads xs rest+ where options = [ o | o@(Option ss _ _ _) <- optDescr, s <- ss, x == s ]+ ads = [ ad | Option _ _ ad _ <- options ]+ optStr = '-':[x]++ short (_:_:_) _ rest = (errAmbig options optStr,rest)+ short (NoArg a :_) [] rest = (Opt a,rest)+ short (NoArg a :_) xs rest = (Opt a,('-':xs):rest)+ short (ReqArg f d:_) [] [] = (errReq d optStr,[])+ short (ReqArg f _:_) [] (r:rest) = (Opt (f r),rest)+ short (ReqArg f _:_) xs rest = (Opt (f xs),rest)+ short (OptArg f _:_) [] rest = (Opt (f Nothing),rest)+ short (OptArg f _:_) xs rest = (Opt (f (Just xs)),rest)+ short [] [] rest = (errUnrec optStr,rest)+ short [] xs rest = (errUnrec optStr,('-':xs):rest)++-- miscellaneous error formatting++errAmbig :: [OptDescr a] -> String -> OptKind a+errAmbig ods optStr = OptErr (usageInfo header ods)+ where header = "option `" ++ optStr ++ "' is ambiguous; could be one of:"++errReq :: String -> String -> OptKind a+errReq d optStr = OptErr ("option `" ++ optStr ++ "' requires an argument " ++ d ++ "\n")++errUnrec :: String -> OptKind a+errUnrec optStr = OptErr ("unrecognized option `" ++ optStr ++ "'\n")++errNoArg :: String -> OptKind a+errNoArg optStr = OptErr ("option `" ++ optStr ++ "' doesn't allow an argument\n")++{-+-----------------------------------------------------------------------------------------+-- and here a small and hopefully enlightening example:++data Flag = Verbose | Version | Name String | Output String | Arg String deriving Show++options :: [OptDescr Flag]+options =+ [Option ['v'] ["verbose"] (NoArg Verbose) "verbosely list files",+ Option ['V','?'] ["version","release"] (NoArg Version) "show version info",+ Option ['o'] ["output"] (OptArg out "FILE") "use FILE for dump",+ Option ['n'] ["name"] (ReqArg Name "USER") "only dump USER's files"]++out :: Maybe String -> Flag+out Nothing = Output "stdout"+out (Just o) = Output o++test :: ArgOrder Flag -> [String] -> String+test order cmdline = case getOpt order options cmdline of+ (o,n,[] ) -> "options=" ++ show o ++ " args=" ++ show n ++ "\n"+ (_,_,errs) -> concat errs ++ usageInfo header options+ where header = "Usage: foobar [OPTION...] files..."++-- example runs:+-- putStr (test RequireOrder ["foo","-v"])+-- ==> options=[] args=["foo", "-v"]+-- putStr (test Permute ["foo","-v"])+-- ==> options=[Verbose] args=["foo"]+-- putStr (test (ReturnInOrder Arg) ["foo","-v"])+-- ==> options=[Arg "foo", Verbose] args=[]+-- putStr (test Permute ["foo","--","-v"])+-- ==> options=[] args=["foo", "-v"]+-- putStr (test Permute ["-?o","--name","bar","--na=baz"])+-- ==> options=[Version, Output "stdout", Name "bar", Name "baz"] args=[]+-- putStr (test Permute ["--ver","foo"])+-- ==> option `--ver' is ambiguous; could be one of:+-- -v --verbose verbosely list files+-- -V, -? --version, --release show version info +-- Usage: foobar [OPTION...] files...+-- -v --verbose verbosely list files +-- -V, -? --version, --release show version info +-- -o[FILE] --output[=FILE] use FILE for dump +-- -n USER --name=USER only dump USER's files+-----------------------------------------------------------------------------------------+-}
+ src/IL.lhs view
@@ -0,0 +1,108 @@+% $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 where+> import Ident+> import 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)++> 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/ILPP.lhs view
@@ -0,0 +1,166 @@+% -*- LaTeX -*-+% $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 ILPP(module ILPP, Doc) where+> import Ident+> import IL+> import Pretty++> 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/ILScope.hs view
@@ -0,0 +1,124 @@+module ILScope (getModuleScope,+ insertDeclScope, insertConstrDeclScope,+ insertCallConvScope, insertTypeScope,+ insertLiteralScope, insertConstrTermScope,+ insertExprScope, insertAltScope,+ insertBindingScope) where+++import IL+import Ident+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/ILTrans.lhs view
@@ -0,0 +1,594 @@++% $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 ILTrans(ilTrans,ilTransIntf) where++> import Data.Maybe+> import Data.List++> import Base+> import qualified IL+> import Utils+> import Env+> import Set+> import Map++++\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)+> zeroFM+> fs'+> tys = map (\i -> maybe (TypeVariable (i+n))+> (elimRecordTypes m tyEnv tcEnv n)+> (lookupFM i vs))+> is +> in TypeConstructor r tys+> _ -> internalError "elimRecordTypes: no record type"+> _ -> internalError "elimRecordTypes: no label"++> matchTypeVars :: [(Ident,Type)] -> FM Int Type -> (Ident,Type) +> -> FM Int Type+> matchTypeVars fs vs (l,ty) =+> maybe vs (match vs ty) (lookup l fs)+> where+> match vs (TypeVariable i) ty' = addToFM 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 = Env 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' = lookupEval 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 (ast pos) IL.Rigid vs +> (map (translEquation tyEnv vs vs'') eqs))+> | otherwise+> = match (ast 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 emptyEnv)) ts+> where translArg env (VariablePattern v) = fromJust (lookupEnv 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 emptyEnv 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 (ast (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 = bindEnv v' v env+> bindRenameEnv v (ConstructorPattern _ ts) env =+> foldr2 bindRenameEnv env (argNames v) ts+> bindRenameEnv v (AsPattern v' t) env = bindEnv 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)+> (nonArgs,args) = partition (null.fst) 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 = lookupEnv (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 bindEnv 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 = toListSet . deleteFromSet m . fromListSet . 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) (fst (splitQualIdent x))++\end{verbatim}+
+ src/ILxml.lhs view
@@ -0,0 +1,518 @@++% $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 ILxml(module ILxml, Doc) where++> import Data.Maybe+> import Data.Char(chr,ord,isAlphaNum)++> import Ident+> import IL+> import qualified CurrySyntax as CS+> import CurryEnv+> import Pretty++++> -- 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,dicc) = 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,d1) = 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,d1) = 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 (ord 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/Ident.lhs view
@@ -0,0 +1,415 @@+> {-# LANGUAGE DeriveDataTypeable #-}++% $Id: Ident.lhs,v 1.21 2004/10/29 13:08:09 wlux Exp $+%+% Copyright (c) 1999-2004, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{Ident.lhs}+\section{Identifiers}+This module provides the implementation of identifiers and some+utility functions for identifiers, which are used at various places in+the compiler.++Identifiers comprise the name of the denoted entity and an \emph{id},+which can be used for renaming identifiers, e.g., in order to resolve+name conflicts between identifiers from different scopes. An+identifier with an \emph{id} $0$ is considered as not being renamed+and, hence, its \emph{id} will not be shown.++\ToDo{Probably we should use \texttt{Integer} for the \emph{id}s.}++Qualified identifiers may optionally be prefixed by a module+name. \textbf{The order of the cases \texttt{UnqualIdent} and+\texttt{QualIdent} is important. Some parts of the compiler rely on+the fact that all qualified identifiers are greater than any+unqualified identifier.}+\begin{verbatim}++> module Ident(Ident,QualIdent,ModuleIdent,SrcRefOf(..),+> mkIdent,name,qualName,uniqueId,renameIdent,unRenameIdent,+> mkMIdent,moduleName,moduleQualifiers,isInfixOp,isQInfixOp,+> qualify,qualifyWith,qualQualify,isQualified,+> unqualify,qualUnqualify,localIdent,splitQualIdent,+> emptyMIdent,mainMIdent,preludeMIdent,+> anonId,unitId,boolId,charId,intId,floatId,listId,ioId,+> successId,trueId,falseId,nilId,consId,mainId,+> tupleId,isTupleId,tupleArity,+> minusId,fminusId,updIdentName,+> qUnitId,qBoolId,qCharId,qIntId,qFloatId,qListId,qIOId,+> qSuccessId,qTrueId,qFalseId,qNilId,qConsId,+> qTupleId,isQTupleId,qTupleArity,+> fpSelectorId,isFpSelectorId,isQualFpSelectorId,+> recSelectorId,qualRecSelectorId,+> recUpdateId, qualRecUpdateId, recordExtId, labelExtId,+> isRecordExtId, isLabelExtId, fromRecordExtId, fromLabelExtId,+> renameLabel, isLabel, fpSelExt, recSelExt, recUpdExt,+> recordExt, labelExt, mkLabelIdent,hasPositionIdent,+> showsIdent,showsQualIdent,showsModuleIdent,+> addPositionIdent, removePositionIdent, positionOfIdent,+> addPositionModuleIdent, removePositionModuleIdent,addRef,addRefId,+> positionOfModuleIdent,positionOfQualIdent,updQualIdent ) where++> import Data.Char+> import Data.List+> import Data.Maybe+> import Data.Generics++> import Position+++> data Ident = Ident String Int +> | IdentPosition Position String Int deriving (Read,Data,Typeable)+> data QualIdent = UnqualIdent Ident | QualIdent ModuleIdent Ident+> deriving (Eq,Ord,Read,Data,Typeable)+> data ModuleIdent = ModuleIdent [String] +> |ModuleIdentPosition Position [String] deriving (Data,Typeable)++> instance Eq Ident where+> ident1 == ident2 = name ident1 == name ident2 && +> uniqueId ident1 == uniqueId ident2++> instance Ord ModuleIdent where+> mident1 `compare` mident2 =+> moduleQualifiers mident1 `compare` moduleQualifiers mident2++> instance Eq ModuleIdent where+> mident1 == mident2 = moduleQualifiers mident1 == moduleQualifiers mident2 ++> instance Read ModuleIdent where+> readsPrec p s = [ (mkMIdent [m],s') | (m,s') <- readsPrec p s ]++> instance Ord Ident where+> ident1 `compare` ident2 =+> (name ident1,uniqueId ident1) `compare` (name ident2,uniqueId ident2)++> instance Show Ident where+> showsPrec _ (Ident x n)+> | n == 0 = showString x+> | otherwise = showString x . showChar '.' . shows n+> showsPrec _ (IdentPosition _ x n)+> | n == 0 = showString x+> | otherwise = showString x . showChar '.' . shows n+> instance Show QualIdent where+> showsPrec _ (UnqualIdent x) = shows x+> showsPrec _ (QualIdent m x) = shows m . showChar '.' . shows x+> instance Show ModuleIdent where+> showsPrec _ m = showString (moduleName m)++> hasPositionIdent :: Ident -> Bool+> hasPositionIdent (Ident _ _ ) = False+> hasPositionIdent (IdentPosition _ _ _) = True++> addPositionIdent :: Position -> Ident -> Ident+> addPositionIdent pos (Ident x n) = IdentPosition pos x n+> addPositionIdent AST{ast=sr} (IdentPosition pos x n) = +> IdentPosition pos{ast=sr} x n+> addPositionIdent pos (IdentPosition _ x n) = +> IdentPosition pos x n++> removePositionIdent :: Ident -> Ident+> removePositionIdent (Ident x n) = (Ident x n)+> removePositionIdent (IdentPosition _ x n) = (Ident x n)++> positionOfIdent :: Ident -> Position+> positionOfIdent (Ident _ _) = noPos+> positionOfIdent (IdentPosition pos _ _) = pos++> addPositionModuleIdent :: Position -> ModuleIdent -> ModuleIdent+> addPositionModuleIdent pos (ModuleIdent x) = ModuleIdentPosition pos x +> addPositionModuleIdent pos (ModuleIdentPosition _ x) = ModuleIdentPosition pos x ++> removePositionModuleIdent :: ModuleIdent -> ModuleIdent+> removePositionModuleIdent (ModuleIdent x) = (ModuleIdent x)+> removePositionModuleIdent (ModuleIdentPosition _ x) = (ModuleIdent x)++> positionOfModuleIdent :: ModuleIdent -> Position+> positionOfModuleIdent (ModuleIdent _) = noPos+> positionOfModuleIdent (ModuleIdentPosition pos _) = pos++> positionOfQualIdent :: QualIdent -> Position+> positionOfQualIdent = positionOfIdent . snd . splitQualIdent++> mkIdent :: String -> Ident+> mkIdent x = Ident x 0++> name :: Ident -> String+> name (Ident x _) = x+> name (IdentPosition _ x _) = x++> qualName :: QualIdent -> String+> qualName (UnqualIdent x) = name x+> qualName (QualIdent m x) = moduleName m ++ "." ++ name x++> uniqueId :: Ident -> Int+> uniqueId (Ident _ n) = n+> uniqueId (IdentPosition _ _ n) = n++> renameIdent :: Ident -> Int -> Ident+> renameIdent (Ident x _) n = Ident x n+> renameIdent (IdentPosition p x _) n = IdentPosition p x n++> unRenameIdent :: Ident -> Ident+> unRenameIdent (Ident x _) = Ident x 0+> unRenameIdent (IdentPosition p x _) = IdentPosition p x 0++> mkMIdent :: [String] -> ModuleIdent+> mkMIdent = ModuleIdent++> moduleName :: ModuleIdent -> String+> moduleName (ModuleIdent xs) = concat (intersperse "." xs)+> moduleName (ModuleIdentPosition _ xs) = concat (intersperse "." xs)++> moduleQualifiers :: ModuleIdent -> [String]+> moduleQualifiers (ModuleIdent xs) = xs+> moduleQualifiers (ModuleIdentPosition _ xs) = xs++> isInfixOp :: Ident -> Bool+> isInfixOp (Ident ('<':c:cs) _)=+> last (c:cs) /= '>' || not (isAlphaNum c) && c `notElem` "_(["+> isInfixOp (Ident (c:_) _) = not (isAlphaNum c) && c `notElem` "_(["+> isInfixOp (Ident _ _) = False -- error "Zero-length identifier"+> isInfixOp x@(IdentPosition _ _ _) = isInfixOp $ removePositionIdent x++> isQInfixOp :: QualIdent -> Bool+> isQInfixOp (UnqualIdent x) = isInfixOp x+> isQInfixOp (QualIdent _ x) = isInfixOp x++\end{verbatim}+The functions \texttt{qualify} and \texttt{qualifyWith} convert an+unqualified identifier into a qualified identifier (without and with a+given module prefix, respectively).+\begin{verbatim}++> qualify :: Ident -> QualIdent+> qualify = UnqualIdent++> qualifyWith :: ModuleIdent -> Ident -> QualIdent+> qualifyWith = QualIdent++> qualQualify :: ModuleIdent -> QualIdent -> QualIdent+> qualQualify m (UnqualIdent x) = QualIdent m x+> qualQualify _ x = x++> isQualified :: QualIdent -> Bool+> isQualified (UnqualIdent _) = False+> isQualified (QualIdent _ _) = True++> unqualify :: QualIdent -> Ident+> unqualify (UnqualIdent x) = x+> unqualify (QualIdent _ x) = x++> qualUnqualify :: ModuleIdent -> QualIdent -> QualIdent+> qualUnqualify m (UnqualIdent x) = UnqualIdent x+> qualUnqualify m (QualIdent m' x)+> | m == m' = UnqualIdent x+> | otherwise = QualIdent m' x++> localIdent :: ModuleIdent -> QualIdent -> Maybe Ident+> localIdent _ (UnqualIdent x) = Just x+> localIdent m (QualIdent m' x)+> | m == m' = Just x+> | otherwise = Nothing++> splitQualIdent :: QualIdent -> (Maybe ModuleIdent,Ident)+> splitQualIdent (UnqualIdent x) = (Nothing,x)+> splitQualIdent (QualIdent m x) = (Just m,x)++> updQualIdent :: (ModuleIdent -> ModuleIdent) -> (Ident -> Ident) -> QualIdent -> QualIdent+> updQualIdent _ g (UnqualIdent x) = UnqualIdent (g x)+> updQualIdent f g (QualIdent m x) = QualIdent (f m) (g x)++> addRef :: SrcRef -> QualIdent -> QualIdent+> addRef r = updQualIdent id (addRefId r)++> addRefId :: SrcRef -> Ident -> Ident+> addRefId r = addPositionIdent (AST r)++\end{verbatim}+A few identifiers a predefined here.+\begin{verbatim}++> emptyMIdent, mainMIdent, preludeMIdent :: ModuleIdent+> emptyMIdent = ModuleIdent []+> mainMIdent = ModuleIdent ["main"]+> preludeMIdent = ModuleIdent ["Prelude"]++> anonId :: Ident+> anonId = Ident "_" 0++> unitPId :: Position -> Ident+> unitPId p = IdentPosition p "()" 0++> unitId, boolId, charId, intId, floatId, listId, ioId, successId :: Ident+> unitId = Ident "()" 0+> boolId = Ident "Bool" 0+> charId = Ident "Char" 0+> intId = Ident "Int" 0+> floatId = Ident "Float" 0+> listId = Ident "[]" 0+> ioId = Ident "IO" 0+> successId = Ident "Success" 0++> trueId, falseId, nilId, consId :: Ident+> trueId = Ident "True" 0+> falseId = Ident "False" 0+> nilId = Ident "[]" 0+> consId = Ident ":" 0++> tupleId :: Int -> Ident+> tupleId n+> | n >= 2 = Ident ("(" ++ replicate (n - 1) ',' ++ ")") 0+> | otherwise = error "internal error: tupleId"++> isTupleId :: Ident -> Bool+> isTupleId x = n > 1 && x == tupleId n+> where n = length (name x) - 1++> tupleArity :: Ident -> Int+> tupleArity x+> | n > 1 && x == tupleId n = n+> | otherwise = error "internal error: tupleArity"+> where n = length (name x) - 1++> mainId, minusId, fminusId :: Ident+> mainId = Ident "main" 0+> minusId = Ident "-" 0+> fminusId = Ident "-." 0++> qUnitId, qNilId, qConsId, qListId :: QualIdent+> qUnitId = UnqualIdent unitId+> qListId = UnqualIdent listId+> qNilId = UnqualIdent nilId+> qConsId = UnqualIdent consId++> qBoolId, qCharId, qIntId, qFloatId, qSuccessId, qIOId :: QualIdent+> qBoolId = QualIdent preludeMIdent boolId+> qCharId = QualIdent preludeMIdent charId+> qIntId = QualIdent preludeMIdent intId+> qFloatId = QualIdent preludeMIdent floatId+> qSuccessId = QualIdent preludeMIdent successId+> qIOId = QualIdent preludeMIdent ioId++> qTrueId, qFalseId :: QualIdent+> qTrueId = QualIdent preludeMIdent trueId+> qFalseId = QualIdent preludeMIdent falseId++> qTupleId :: Int -> QualIdent+> qTupleId = UnqualIdent . tupleId++> isQTupleId :: QualIdent -> Bool+> isQTupleId = isTupleId . unqualify++> qTupleArity :: QualIdent -> Int+> qTupleArity = tupleArity . unqualify++\end{verbatim}+Micellaneous function for generating and testing extended identifiers.+\begin{verbatim}++> fpSelectorId :: Int -> Ident+> fpSelectorId n = Ident (fpSelExt ++ show n) 0++> isFpSelectorId :: Ident -> Bool+> isFpSelectorId f = any (fpSelExt `isPrefixOf`) (tails (name f))++> isQualFpSelectorId :: QualIdent -> Bool+> isQualFpSelectorId = isFpSelectorId . unqualify++> recSelectorId :: QualIdent -> Ident -> Ident+> recSelectorId r l =+> mkIdent (recSelExt ++ name (unqualify r) ++ "." ++ name l)++> qualRecSelectorId :: ModuleIdent -> QualIdent -> Ident -> QualIdent+> qualRecSelectorId m r l = qualifyWith m' (recSelectorId r l)+> where m' = (fromMaybe m (fst (splitQualIdent r)))++> recUpdateId :: QualIdent -> Ident -> Ident+> recUpdateId r l = +> mkIdent (recUpdExt ++ name (unqualify r) ++ "." ++ name l)++> qualRecUpdateId :: ModuleIdent -> QualIdent -> Ident -> QualIdent+> qualRecUpdateId m r l = qualifyWith m' (recUpdateId r l)+> where m' = (fromMaybe m (fst (splitQualIdent r)))++> recordExtId :: Ident -> Ident+> recordExtId r = mkIdent (recordExt ++ name r)++> labelExtId :: Ident -> Ident+> labelExtId l = mkIdent (labelExt ++ name l)++> fromRecordExtId :: Ident -> Ident+> fromRecordExtId r +> | p == recordExt = mkIdent r'+> | otherwise = r+> where (p,r') = splitAt (length recordExt) (name r)++> fromLabelExtId :: Ident -> Ident+> fromLabelExtId l +> | p == labelExt = mkIdent l'+> | otherwise = l+> where (p,l') = splitAt (length labelExt) (name l)++> isRecordExtId :: Ident -> Bool+> isRecordExtId r = recordExt `isPrefixOf` name r++> isLabelExtId :: Ident -> Bool+> isLabelExtId l = labelExt `isPrefixOf` name l++> mkLabelIdent :: String -> Ident+> mkLabelIdent c = renameIdent (mkIdent c) (-1)++> renameLabel :: Ident -> Ident+> renameLabel l = renameIdent l (-1)++> isLabel :: Ident -> Bool+> isLabel l = uniqueId l == (-1)+++> fpSelExt = "_#selFP"+> recSelExt = "_#selR@"+> recUpdExt = "_#updR@"+> recordExt = "_#Rec:"+> labelExt = "_#Lab:"++> showsString :: String -> ShowS+> showsString = (++)++> space :: ShowS+> space = showsString " "++> showsIdent :: Ident -> ShowS+> showsIdent x@(IdentPosition _ _ _) = showsIdent $ removePositionIdent x+> showsIdent (Ident name n)+> = showsString "(Ident " . shows name . space . shows n . showsString ")"++> showsQualIdent :: QualIdent -> ShowS+> showsQualIdent (UnqualIdent ident)+> = showsString "(UnqualIdent " . showsIdent ident . showsString ")"+> showsQualIdent (QualIdent mident ident)+> = showsString "(QualIdent "+> . showsModuleIdent mident . space+> . showsIdent ident+> . showsString ")"++> showsModuleIdent :: ModuleIdent -> ShowS+> showsModuleIdent = shows . moduleName++showsModuleIdent x@(ModuleIdentPosition _ _) = + showsModuleIdent $ removePositionModuleIdent x+showsModuleIdent (ModuleIdent []) = showsString "(ModuleIdent [])"+showsModuleIdent (ModuleIdent (s:strs))+ = showsString "(ModuleIdent ["+ . foldl (\sys y -> sys . showsString "," . shows y) (shows s) strs+ . showsString "])"++\end{verbatim}++> instance SrcRefOf Ident where srcRefOf = srcRefOf . positionOfIdent+> instance SrcRefOf QualIdent where srcRefOf = srcRefOf . unqualify++> updIdentName :: (String -> String) -> Ident -> Ident+> updIdentName f ident = let p=positionOfIdent ident+> i=uniqueId ident+> n=name ident in+> addPositionIdent p $ flip renameIdent i $ mkIdent (f n)
+ src/Imports.lhs view
@@ -0,0 +1,380 @@++% $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 Base+> import Env+> import TopEnv+> import Map+> import Set++\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 = Env Ident PrecInfo+> type ExpTCEnv = Env Ident TypeInfo+> type ExpValueEnv = Env Ident ValueInfo+> type ExpArityEnv = Env 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 (fromListSet (foldr addType [] is'))+> vs = isVisible is (fromListSet (foldr addValue [] is'))+> as = isVisible is (fromListSet (foldr addArity [] is'))++> isVisible :: Maybe ImportSpec -> Set Ident -> Ident -> Bool+> isVisible (Just (Importing _ _)) xs = (`elemSet` xs)+> isVisible (Just (Hiding _ _)) xs = (`notElemSet` xs)+> isVisible _ _ = const True++> importEntities :: Entity a => ModuleIdent -> Bool -> (Ident -> Bool)+> -> (a -> a) -> Env 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) <- envToList 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 -> Env Ident a -> Env Ident a)+> -> Interface -> Env Ident a+> intfEnv bind (Interface m ds) = foldr (bind m) emptyEnv ds++> bindPrec :: ModuleIdent -> IDecl -> ExpPEnv -> ExpPEnv+> bindPrec m (IInfixDecl _ fix p op) =+> bindEnv (unqualify op) (PrecInfo (qualQualify m op) (OpPrec fix p))+> bindPrec _ _ = id++> bindTC :: ModuleIdent -> IDecl -> ExpTCEnv -> ExpTCEnv+> bindTC m (IDataDecl _ tc tvs cs) mTCEnv +> | isJust (lookupEnv (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 =+> bindEnv (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) =+> bindEnv (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) =+> -- bindEnv 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 = bindEnv c (f (qualifyLike tc c) sigma)+> where sigma = ForAllExist (length tvs) (length evs) (toQualType m tvs ty)+> qualifyLike x = maybe qualify qualifyWith (fst (splitQualIdent x))++> bindA :: ModuleIdent -> IDecl -> ExpArityEnv -> ExpArityEnv+> bindA m (IDataDecl _ _ _ cs) expAEnv+> = foldr (bindConstrA m) expAEnv (catMaybes cs)+> bindA m (IFunctionDecl _ f a _) expAEnv+> = bindEnv (unqualify f) (ArityInfo (qualQualify m f) a) expAEnv+> bindA _ _ expAEnv = expAEnv++> bindConstrA :: ModuleIdent -> ConstrDecl -> ExpArityEnv -> ExpArityEnv+> bindConstrA m (ConstrDecl _ _ c tys) expAEnv+> = bindEnv c (ArityInfo (qualifyWith m c) (length tys)) expAEnv+> bindConstrA m (ConOpDecl _ _ _ c _) expAEnv+> = bindEnv 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 lookupEnv 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 lookupEnv 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 lookupEnv 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 lookupEnv 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 lookupEnv 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 lookupEnv 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) zeroFM (allImports tcEnv))) tcEnv+> where setInfo tcs t = fromJust (lookupFM (origName t) tcs)+> mergeData t tcs =+> addToFM tc (maybe t (fromJust . merge t) (lookupFM 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)++> undefinedType :: ModuleIdent -> Ident -> (Position,String)+> undefinedType m tc =+> (positionOfIdent tc, +> "Module " ++ moduleName m ++ " does not export a type " ++ name tc)++> 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 view
@@ -0,0 +1,142 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 ExtendedFlat++++-------------------------------------------------------------------------------++-- 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/KindCheck.lhs view
@@ -0,0 +1,322 @@++% $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,kindCheckGoal) where++> import Data.Maybe++> 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 linear (map tconstr ds') of+> Linear -> map (checkDecl m kEnv) ds+> NonLinear (PIdent p tc) -> errorAt' (duplicateType tc)+> where ds' = filter isTypeDecl ds+> kEnv = foldr (bindArity m) (fmap tcArity tcEnv) ds'++> kindCheckGoal :: TCEnv -> Goal -> Goal+> kindCheckGoal tcEnv (Goal p e ds) =+> Goal p (checkExpr m kEnv e) (map (checkDecl m kEnv) ds)+> where kEnv = fmap tcArity tcEnv+> m = mkMIdent []++\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 kEnv [] = []++> 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 -> PIdent+> tconstr (DataDecl p tc _ _) = PIdent p tc+> tconstr (NewtypeDecl p tc _ _) = PIdent p tc+> tconstr (TypeDecl p tc _ _) = PIdent p 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/LLParseComb.lhs view
@@ -0,0 +1,292 @@+% -*- LaTeX -*-+% $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 LLParseComb(Symbol(..),Parser,+> applyParser,prefixParser, position,succeed,symbol,+> (<?>),(<|>),(<|?>),(<*>),(<\>),(<\\>),+> opt,(<$>),(<$->),(<*->),(<-*>),(<**>),(<??>),(<.>),+> many,many1, sepBy,sepBy1, chainr,chainr1,chainl,chainl1,+> bracket,ops, layoutOn,layoutOff,layoutEnd) where++> import Data.Maybe+> import Control.Monad++> import Position+> import Set+> import Map+> import Error+> import LexComb++> 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 Empty = 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))+> (FM 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 (domainFM ps)++> applyParser :: Symbol s => Parser s a a -> Lexer s a -> FilePath -> String+> -> Error 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+> -> Error 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 lookupFM 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) zeroFM+> where p success _ pos = success pos pos++> succeed :: Symbol s => a -> Parser s a b+> succeed x = Parser (Just p) zeroFM+> where p success _ = success x++> symbol :: Symbol s => s -> Parser s s a+> symbol s = Parser Nothing (addToFM s p zeroFM)+> 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) zeroFM+> 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 (nullSet common) = error ("Ambiguous parser for " ++ show common)+> | otherwise = Parser (e1 `mplus` e2) (insertIntoFM ps1 ps2)+> where common = domainFM ps1 `intersectionSet` domainFM 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) (insertIntoFM ps1' ps2)+> where ps1' = fromListFM [(s,maybe p (try p) (lookupFM s ps2))+> | (s,p) <- toListFM 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)+> (insertIntoFM (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++> insertIntoFM :: Ord a => FM a b -> FM a b -> FM a b+> insertIntoFM map1 map2 = foldr (uncurry addToFM) map2 (toListFM map1)++\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 fst (toListFM ps)++> (<\\>) :: Symbol s => Parser s a b -> [s] -> Parser s a b+> Parser e ps <\\> xs = Parser e (foldr deleteFromFM 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) zeroFM+> where on success _ pos = pushContext (column pos) . success undefined pos++> layoutOff :: Symbol s => Parser s a b+> layoutOff = Parser (Just off) zeroFM+> where off success _ pos = pushContext (-1) . success undefined pos++> layoutEnd :: Symbol s => Parser s a b+> layoutEnd = Parser (Just end) zeroFM+> where end success _ pos = popContext . success undefined pos++\end{verbatim}
+ src/LexComb.lhs view
@@ -0,0 +1,102 @@+% -*- 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 string to be parsed, the second is the current position, and the+third 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 LexComb where+> import Position+> import Error+> import Data.Char++> infixl 1 `thenP`, `thenP_`++> type Indent = Int+> type Context = [Indent]+> type P a = Position -> String -> Bool -> Context -> Error a++> parse :: P a -> FilePath -> String -> Error 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 _ _ _ _ = Ok 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 _ _ _ _ = Error (parseError pos msg)++> closeP0 :: P a -> P (P a)+> closeP0 lex pos s bol ctxt = Ok (\_ _ _ _ -> lex pos s bol ctxt)++> closeP1 :: (a -> P b) -> P (a -> P b)+> closeP1 f pos s bol ctxt = Ok (\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/Lift.lhs view
@@ -0,0 +1,317 @@++% $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 Data.List++> import Base+> import Env+> import TopEnv+> import Set+++> import Combined+> 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') =+> runSt (callSt (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 = StateT ValueEnv (StateT EvalEnv Id) a+> type AbstractEnv = Env Ident Expression++> abstractModule :: ModuleIdent -> [Decl]+> -> AbstractState ([Decl],ValueEnv,EvalEnv)+> abstractModule m ds =+> do+> ds' <- mapM (abstractDecl m "" [] emptyEnv) ds+> tyEnv' <- fetchSt+> evEnv' <- liftSt fetchSt+> 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) fetchSt+> updateSt_ (abstractFunTypes m pre fvs fs')+> liftSt (updateSt_ (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) (toListSet fvsRhs)+> env' = foldr (bindF (map mkVar fvs)) env fs+> fvsRhs = unionSets+> [fromListSet (maybe [v] (qfv m) (lookupEnv v env)) | v <- qfv m fds]+> bindF fvs f = bindEnv 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 lookupEnv f evEnv of+> Just ev -> bindEnv (liftIdent pre f) ev (unbindEnv 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)+> (lookupEnv (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)++> abstractCondExpr :: ModuleIdent -> String -> [Ident] -> AbstractEnv+> -> CondExpr -> AbstractState CondExpr+> abstractCondExpr m pre lvs env (CondExpr p g e) =+> do+> g' <- abstractExpr m pre lvs env g+> e' <- abstractExpr m pre lvs env e+> return (CondExpr p g' e')++\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++> liftCondExpr :: CondExpr -> (CondExpr,[Decl])+> liftCondExpr (CondExpr p g e) = (CondExpr p g' e',ds' ++ ds'')+> where (g',ds') = liftExpr g+> (e',ds'') = liftExpr e++\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/Map.lhs view
@@ -0,0 +1,225 @@+% -*- LaTeX -*-+% $Id: Map.lhs,v 1.6 2003/04/24 08:02:39 wlux Exp $+%+% Copyright (c) 1999-2002, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{Map.lhs}+\section{Maps}+The module \texttt{Map} implements finite maps using 2-3 trees.+\begin{verbatim}++> module Map(FM, nullFM, zeroFM, unitFM, addToFM, deleteFromFM,+> lookupFM, fromListFM, toListFM) where+> import Data.List++\end{verbatim}+A 2-3 tree is either empty or a node with either two or three children+that are themselves 2-3 trees of the same height. Thus, a 2-3 is+always balanced.+\begin{verbatim}++> data FM a b =+> Empty+> | Node2 (FM a b) (a,b) (FM a b)+> | Node3 (FM a b) (a,b) (FM a b) (a,b) (FM a b)++> nullFM :: Ord a => FM a b -> Bool+> nullFM Empty = True+> nullFM _ = False++> zeroFM :: Ord a => FM a b+> zeroFM = Empty++> unitFM :: Ord a => a -> b -> FM a b+> unitFM x y = Node2 Empty (x,y) Empty++\end{verbatim}+Insertion into the map is performed with the help of an auxiliary+function. This function returns either the updated node or a triple of+a left and right subtree together with the element between them+if the height of the tree must be changed.+\begin{verbatim}++> addToFM :: Ord a => a -> b -> FM a b -> FM a b+> addToFM x y xys =+> case insertNode x y xys of+> Left xys' -> xys'+> Right (l,x,r) -> Node2 l x r++> fromListFM :: Ord a => [(a,b)] -> FM a b+> fromListFM = foldr (uncurry addToFM) zeroFM++> insertNode :: Ord a => a -> b -> FM a b+> -> Either (FM a b) ((FM a b),(a,b),(FM a b))+> insertNode k x Empty = Right (Empty,(k,x),Empty)+> insertNode k x (Node2 a y b) =+> Left (case compareKey k y of+> LT -> balanceL (insertNode k x a) y b+> EQ -> Node2 a (k,x) b+> GT -> balanceR a y (insertNode k x b))+> where balanceL (Left a) x b = Node2 a x b+> balanceL (Right (a,x,b)) y c = Node3 a x b y c+> balanceR a x (Left b) = Node2 a x b+> balanceR a x (Right (b,y,c)) = Node3 a x b y c+> insertNode k x (Node3 a y b z c) =+> case compareKey k y of+> LT -> balanceL (insertNode k x a) y b z c+> EQ -> Left (Node3 a (k,x) b z c)+> GT ->+> case compareKey k z of+> LT -> balanceM a y (insertNode k x b) z c+> EQ -> Left (Node3 a y b (k,x) c)+> GT -> balanceR a y b z (insertNode k x c)+> where balanceL (Left a) x b y c = Left (Node3 a x b y c)+> balanceL (Right (a,x,b)) y c z d = Right (Node2 a x b,y,Node2 c z d)+> balanceM a x (Left b) y c = Left (Node3 a x b y c)+> balanceM a x (Right (b,y,c)) z d = Right (Node2 a x b,y,Node2 c z d)+> balanceR a x b y (Left c) = Left (Node3 a x b y c)+> balanceR a x b y (Right (c,z,d)) = Right (Node2 a x b,y,Node2 c z d)++> compareKey :: Ord a => a -> (a,b) -> Ordering+> compareKey k1 (k2,_) = compare k1 k2++\end{verbatim}+Deletion also uses an auxiliary function. This function returns the+new node after the element has been deleted together with a boolean+flag that indicates whether the height was decremented.+\begin{verbatim}++> deleteFromFM :: Ord a => a -> FM a b -> FM a b+> deleteFromFM x xys = snd (deleteNode x xys)++> deleteNode :: Ord a => a -> FM a b -> (Bool,FM a b)+> deleteNode _ Empty = (False,Empty)+> deleteNode x (Node2 a y b) =+> case compareKey x y of+> LT -> balanceL (deleteNode x a) y b+> EQ+> | nullFM a -> (True,b)+> | otherwise -> balanceR a u (deleteNode (fst u) b)+> where u = findMin b+> GT -> balanceR a y (deleteNode x b)+> where balanceL (False,a) x b = (False,Node2 a x b)+> balanceL (True,a) x (Node2 b y c) = (True,Node3 a x b y c)+> balanceL (True,a) x (Node3 b y c z d) =+> (False,Node2 (Node2 a x b) y (Node2 c z d))+> balanceR a x (False,b) = (False,Node2 a x b)+> balanceR (Node2 a x b) y (True,c) = (True,Node3 a x b y c)+> balanceR (Node3 a x b y c) z (True,d) =+> (False,Node2 (Node2 a x b) y (Node2 c z d))+> deleteNode x (Node3 a y b z c) =+> (False,+> case compareKey x y of+> LT -> balanceL (deleteNode x a) y b z c+> EQ+> | nullFM a -> Node2 b z c+> | otherwise -> balanceM a u (deleteNode (fst u) b) z c+> where u = findMin b+> GT ->+> case compareKey x z of+> LT -> balanceM a y (deleteNode x b) z c+> EQ+> | nullFM c -> Node2 a y b+> | otherwise -> balanceR a y b u (deleteNode (fst u) c)+> where u = findMin c+> GT -> balanceR a y b z (deleteNode x c))+> where balanceL (False,a) x b y c = Node3 a x b y c+> balanceL (True,a) x (Node2 b y c) z d = Node2 (Node3 a x b y c) z d+> balanceL (True,a) w (Node3 b x c y d) z e =+> Node3 (Node2 a w b) x (Node2 c y d) z e+> balanceM a x (False,b) y c = Node3 a x b y c+> balanceM a x (True,b) y (Node2 c z d) = Node2 a x (Node3 b y c z d)+> balanceM a w (True,b) x (Node3 c y d z e) =+> Node3 a w (Node2 b x c) y (Node2 d z e)+> balanceR a x b y (False,c) = Node3 a x b y c+> balanceR a x (Node2 b y c) z (True,d) = Node2 a x (Node3 b y c z d)+> balanceR a w (Node3 b x c y d) z (True,e) =+> Node3 a w (Node2 b x c) y (Node2 d z e)++> findMin :: Ord a => FM a b -> (a,b)+> findMin (Node2 a x _)+> | nullFM a = x+> | otherwise = findMin a+> findMin (Node3 a x _ _ _)+> | nullFM a = x+> | otherwise = findMin a++\end{verbatim}+Looking up an element is trivial.+\begin{verbatim}++> lookupFM :: Ord a => a -> FM a b -> Maybe b+> lookupFM _ Empty = Nothing+> lookupFM x (Node2 a y b) =+> case compareKey x y of+> LT -> lookupFM x a+> EQ -> Just (snd y)+> GT -> lookupFM x b+> lookupFM x (Node3 a y b z c) =+> case compareKey x y of+> LT -> lookupFM x a+> EQ -> Just (snd y)+> GT -> lookupFM x (Node2 b z c)++\end{verbatim}+The function \texttt{toListFM} returns an association list of all+elements in the map. We use a functional difference list approach+similar to \texttt{show} in order to achieve an efficiency which is+linear in the number of elements in the finite map.+\begin{verbatim}++> toListFM :: Ord a => FM a b -> [(a,b)]+> toListFM = flip elems []+> where elems Empty xs = xs+> elems (Node2 a x b) xs = elems a (x : elems b xs)+> elems (Node3 a x b y c) xs = elems a (x : elems b (y : elems c xs))++\end{verbatim}+Two finite maps are considered equal if they contain the same+elements. Note that the representation trees of the two maps may be+different. Therefore we must use the list of elements in order to+compare the maps.+\begin{verbatim}++> instance (Ord a,Eq b) => Eq (FM a b) where+> xys1 == xys2 = toListFM xys1 == toListFM xys2++\end{verbatim}+When we display a finite map we will show only its semantic+information not the underlying tree representation.+\begin{verbatim}++> instance (Ord a,Show a,Show b) => Show (FM a b) where+> showsPrec p xys =+> showChar '{' . showList (map showAssoc (toListFM xys)) . showChar '}'+> where showList = flip (foldr ($)) . intersperse (showChar ',') -- $+> showAssoc (x,y) = showsPrec 0 x . showString "|->" . showsPrec 0 y++\end{verbatim}+A finite map is a functor with respect to its data argument.+\begin{verbatim}++> instance Ord a => Functor (FM a) where+> fmap f Empty = Empty+> fmap f (Node2 a (k,x) b) = Node2 (fmap f a) (k,f x) (fmap f b)+> fmap f (Node3 a (k,x) b (l,y) c) =+> Node3 (fmap f a) (k,f x) (fmap f b) (l,f y) (fmap f c)++\end{verbatim}+The function \texttt{checkTree} verifies that a 2-3 tree is actually+balanced. The function returns the height of the tree.+\begin{verbatim}++> checkTree :: Ord a => FM a b -> Int+> checkTree Empty = 0+> checkTree (Node2 a _ b)+> | h == checkTree b = h + 1+> | otherwise = error "checkTree: unbalanced 2-3 tree"+> where h = checkTree a+> checkTree (Node3 a _ b _ c)+> | h == checkTree b && h == checkTree c = h + 1+> | otherwise = error "checkTree: unbalanced 2-3 tree"+> where h = checkTree a++\end{verbatim}
+ src/Message.hs view
@@ -0,0 +1,74 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- Message - A library for dealing with compiler messages+--+-- Note: This module overwrites the functions declared in "Message"+-- +-- January 2006,+-- Martin Engelke (men@informatik.uni-kiel.de)+--+module Message where++import Position+++-------------------------------------------------------------------------------++-- Type for representing compiler messages (currently errors and warnings)+data Message = Message MessageType (Maybe Position) String++-- Data type for representing available compiler message types+data MessageType = Warning WarningType | Error deriving Eq++-- the different warnings are categorized by WarningType+data WarningType = UnrefTypeVar+ | UnrefVar+ | ShadowingVar+ | IdleCaseAlt+ | OverlapCase+ | OverlapRules+ | RulesNotTogether+ | MultipleImportModule+ | MultipleImportSymbol+ | MultipleHiding + deriving Eq++-- An instance of Show for converting messages to readable strings+instance Show Message where+ show (Message (Warning _) mpos msg) = showMessage "Warning" mpos msg+ show (Message Error mpos msg) = showMessage "ERROR" mpos msg+++-------------------------------------------------------------------------------++--+message :: MessageType -> Position -> String -> Message+message mtype pos msg = Message mtype (Just pos) msg++--+message_ :: MessageType -> String -> Message+message_ mtype msg = Message mtype Nothing msg++--+countMessages :: MessageType -> [Message] -> Int+countMessages mtype msgs = length (filter (((==) mtype) . messageType) msgs)++--+messageType :: Message -> MessageType+messageType (Message mtype _ _) = mtype+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++--+showMessage :: String -> (Maybe Position) -> String -> String+showMessage what mpos msg+ = what ++ ": " ++ pos ++ msg+ where+ pos = maybe "" (\p -> show p ++ ": ") mpos+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/Modules.lhs view
@@ -0,0 +1,799 @@++% $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, compileModule_,+> loadInterfaces, transModule,+> simpleCheckModule, checkModule+> ) where++> import Data.List+> import System.IO+> import Data.Maybe+> import Control.Monad++> import Base+> import Unlit(unlit)+> import CurryParser(parseSource,parseGoal) -- xxxGoal entfernen+> import ShowCurrySyntax(showModule)+> import KindCheck(kindCheck,kindCheckGoal)+> import SyntaxCheck(syntaxCheck)+> import PrecCheck(precCheck,precCheckGoal)+> import TypeCheck(typeCheck,typeCheckGoal)+> import WarnCheck+> import Message+> import Arity+> import Imports(importInterface,importInterfaceIntf,importUnifyData)+> import Exports(expandInterface,exportInterface)+> import Eval(evalEnv,evalEnvGoal)+> import Qual(qual,qualGoal)+> import Desugar(desugar,desugarGoal)+> import Simplify(simplify)+> import Lift(lift)+> import qualified IL+> import ILTrans(ilTrans,ilTransIntf)+> import ILxml(xmlModule) -- check+> import ExtendedFlat+> import GenFlatCurry (genFlatCurry,genFlatInterface)+> import AbstractCurry+> import GenAbstractCurry+> import InterfaceCheck+> import CurryEnv+> import CurryPP(ppModule,ppInterface,ppIDecl,ppGoal)+> import qualified ILPP(ppModule)+> import CurryCompilerOpts(Options(..),Dump(..))+> import CompilerResults+> import CaseCompletion+> import PathUtils+> import TypeSubst+> import Pretty+> import Error+> import Env+> 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 ()+> compileModule opts fn = compileModule_ opts fn >> return ()++> compileModule_ :: Options -> FilePath -> IO CompilerResults+> compileModule_ opts fn =+> do+> mod <- liftM (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 (rootname fn ++ sourceRepExt) +> id +> (output opts)+> outputMod = showModule m'+> writeModule outputFile outputMod+> return defaultResults+> else+> do (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 defaultResults++> parseModule :: Bool -> FilePath -> String -> Module+> parseModule likeFlat fn =+> importPrelude fn . ok . parseSource likeFlat fn . unlitLiterate fn++> loadInterfaces :: [FilePath] -> Module -> IO ModuleEnv+> loadInterfaces paths (Module m _ ds) =+> foldM (loadInterface paths [m]) emptyEnv+> [(p,m) | ImportDecl p m _ _ _ <- ds]++> checkModuleId :: Monad m => FilePath -> Module -> m ()+> checkModuleId fn (Module mid _ _)+> | last (moduleQualifiers mid) == basename (rootname 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,[Message])+> 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+> (pEnv'',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,[Message])+> 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+> (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,ILPP.ppModule il),+> (DumpCase,ILPP.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 (envToList 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++> --ilImports :: ValueEnv -> TCEnv -> ModuleEnv -> IL.Module -> [IL.Decl]+> --ilImports tyEnv tcEnv mEnv (IL.Module _ is _) =+> -- concat [ilTransIntf tyEnv tcEnv (Interface m ds) +> -- | (m,ds) <- envToList mEnv, m `elem` is]++> writeXML :: Maybe FilePath -> FilePath -> CurryEnv -> IL.Module -> IO ()+> writeXML tfn sfn cEnv il = writeModule ofn (showln code)+> where ofn = fromMaybe (rootname sfn ++ xmlExt) 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 (rootname sfn ++ flatExt) tfn)++> writeFInt :: Options -> Maybe FilePath -> FilePath -> CurryEnv -> ModuleEnv+> -> ValueEnv -> TCEnv -> ArityEnv -> IL.Module -> IO Prog+> writeFInt opts tfn sfn cEnv mEnv tyEnv tcEnv aEnv il +> = writeFlatFile opts (genFlatInterface opts cEnv mEnv tyEnv tcEnv aEnv il)+> (fromMaybe (rootname sfn ++ fintExt) tfn)++> writeFlatFile :: (Show a) => Options -> (Prog, [a]) -> String -> IO Prog+> writeFlatFile opts (res,msgs) fname = do+> unless (noWarn opts) (printMessages msgs)+> writeFlatCurry fname res+> return res+++> writeTypedAbs :: Maybe FilePath -> FilePath -> ValueEnv -> TCEnv -> Module+> -> IO ()+> writeTypedAbs tfn sfn tyEnv tcEnv mod+> = writeCurry fname (genTypedAbstract tyEnv tcEnv mod)+> where fname = fromMaybe (rootname sfn ++ acyExt) tfn++> writeUntypedAbs :: Maybe FilePath -> FilePath -> ValueEnv -> TCEnv +> -> Module -> IO ()+> writeUntypedAbs tfn sfn tyEnv tcEnv mod+> = writeCurry fname (genUntypedAbstract tyEnv tcEnv mod)+> where fname = fromMaybe (rootname sfn ++ uacyExt) tfn++> --writeCode :: Maybe FilePath -> FilePath -> Either CFile [CFile] -> IO ()+> --writeCode tfn sfn (Left cfile) = writeCCode ofn cfile+> -- where ofn = fromMaybe (rootname sfn ++ cExt) tfn+> --writeCode tfn sfn (Right cfiles) = zipWithM_ (writeCCode . mkFn) [1..] cfiles+> -- where prefix = fromMaybe (rootname sfn) tfn+> -- mkFn i = prefix ++ show i ++ cExt++> --writeCCode :: FilePath -> CFile -> IO ()+> --writeCCode fn = writeFile fn . showln . ppCFile++> showln :: Show a => a -> String+> showln x = shows x "\n"++\end{verbatim}+A goal is compiled with respect to a given module. If no module is+specified the Curry prelude is used. The source module has to be+parsed and type checked before the goal can be compiled. Otherwise+compilation of a goal is similar to that of a module.++\em{Note:} These functions are obsolete when using the MCC as frontend+for PAKCS.+\begin{verbatim}++> --compileGoal :: Options -> Maybe String -> Maybe FilePath -> IO ()+> --compileGoal opts g fn =+> -- do+> -- (ccode,dumps) <- maybe (return startupCode) goalCode g+> -- mapM_ (doDump opts) dumps+> -- writeCCode ofn ccode+> -- where ofn = fromMaybe (internalError "No filename for startup code")+> -- (output opts)+> -- startupCode = (genMain "curry_run",[])+> -- goalCode = doCompileGoal (debug opts) (importPath opts) fn++> --doCompileGoal :: Bool -> [FilePath] -> Maybe FilePath -> String+> -- -> IO (CFile,[(Dump,Doc)])+> --doCompileGoal debug paths fn g =+> -- do+> -- (mEnv,_,ds) <- loadGoalModule paths fn+> -- let (tyEnv,g') = checkGoal mEnv ds (ok (parseGoal g))+> -- (ccode,dumps) =+> -- transGoal debug runGoal mEnv tyEnv (mkIdent "goal") g'+> -- ccode' = genMain runGoal+> -- return (mergeCFile ccode ccode',dumps)+> -- where runGoal = "curry_runGoal"++> --typeGoal :: Options -> String -> Maybe FilePath -> IO ()+> --typeGoal opts g fn =+> -- do+> -- (mEnv,m,ds) <- loadGoalModule (importPath opts) fn+> -- let (tyEnv,Goal _ e _) = checkGoal mEnv ds (ok (parseGoal g))+> -- print (ppType m (typeOf tyEnv e))++> --loadGoalModule :: [FilePath] -> Maybe FilePath+> -- -> IO (ModuleEnv,ModuleIdent,[Decl])+> --loadGoalModule paths fn =+> -- do+> -- Module m _ ds <- maybe (return emptyModule) parseGoalModule fn+> -- mEnv <- loadInterfaces paths (Module m Nothing ds)+> -- let (_,_,_,_,intf) = checkModule mEnv (Module m Nothing ds)+> -- return (bindModule intf mEnv,m,filter isImportDecl ds ++ [importMain m])+> -- where emptyModule = importPrelude "" (Module emptyMIdent Nothing [])+> -- parseGoalModule fn = liftM (parseModule False fn) (readFile fn)+> -- importMain m = ImportDecl (first "") m False Nothing Nothing++> --checkGoal :: ModuleEnv -> [Decl] -> Goal -> (ValueEnv,Goal)+> --checkGoal mEnv impDs g = (tyEnv'',qualGoal tyEnv' g')+> -- where (pEnv,tcEnv,tyEnv,aEnv) = importModules mEnv impDs+> -- g' = precCheckGoal pEnv $ syntaxCheckGoal tyEnv+> -- $ kindCheckGoal tcEnv g+> -- tyEnv' = typeCheckGoal tcEnv tyEnv g'+> -- (_,_,tyEnv'',_) = qualifyEnv mEnv pEnv tcEnv tyEnv' emptyTopEnv++> --transGoal :: Bool -> String -> ModuleEnv -> ValueEnv -> Ident -> Goal+> -- -> (CFile,[(Dump,Doc)])+> --transGoal debug run mEnv tyEnv goalId g = (ccode,dumps)+> -- where qGoalId = qualifyWith emptyMIdent goalId+> -- evEnv = evalEnvGoal g+> -- (vs,desugared,tyEnv') = desugarGoal debug tyEnv emptyMIdent goalId g+> -- (simplified,tyEnv'') = simplify False tyEnv' evEnv desugared+> -- (lifted,tyEnv''',evEnv') = lift tyEnv'' evEnv simplified+> -- il = ilTrans False tyEnv''' evEnv' lifted+> -- ilDbg = if debug then dAddMain goalId (dTransform False il) else il+> -- ilNormal = liftProg ilDbg+> -- cam = camCompile ilNormal+> -- imports = camCompileData (ilImports mEnv ilDbg)+> -- ccode =+> -- genModule imports cam +++> -- genEntry run (fun qGoalId) (fmap (map name) vs)+> -- dumps = [+> -- (DumpRenamed,ppGoal g),+> -- (DumpTypes,ppTypes emptyMIdent (localBindings tyEnv)),+> -- (DumpDesugared,ppModule desugared),+> -- (DumpSimplified,ppModule simplified),+> -- (DumpLifted,ppModule lifted),+> -- (DumpIL,ILPP.ppModule il),+> -- (DumpTransformed,ILPP.ppModule ilDbg),+> -- (DumpNormalized,ILPP.ppModule ilNormal),+> -- (DumpCam,CamPP.ppModule cam)+> -- ]++\end{verbatim}+The compiler adds a startup function for the default goal+\texttt{main.main} to the \texttt{main} module. Thus, there is no need+to determine the type of the goal when linking the program.+\begin{verbatim}++> --compileDefaultGoal :: Bool -> ModuleEnv -> Interface -> Maybe CFile+> --compileDefaultGoal debug mEnv (Interface m ds)+> -- | m == mainMIdent && any (qMainId ==) [f | IFunctionDecl _ f _ _ <- ds] =+> -- Just ccode+> -- | otherwise = Nothing+> -- where qMainId = qualify mainId+> -- mEnv' = bindModule (Interface m ds) mEnv+> -- (tyEnv,g) =+> -- checkGoal mEnv' [ImportDecl (first "") m False Nothing Nothing]+> -- (Goal (first "") (Variable qMainId) [])+> -- (ccode,_) = transGoal debug "curry_run" mEnv' tyEnv mainId g++\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 lookupModule 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 initLabelEnv ds+> where+> importLabelTypes lEnv (ImportDecl p m _ asM is) =+> case (lookupModule 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 (envToList lEnv))+> where+> addLabelType (LabelType l r ty) tyEnv = +> let m' = fromMaybe m (fst (splitQualIdent 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 = filter isImportDecl ds+> ds' = ImportDecl (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) (lookupModule 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 (first fn) (interfaceNotFound m)) mintf+> (Prog mod _ _ _ _) = intf+> m' = mkMIdent [mod]+> unless (m' == m) (errorAt (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 = first m++> --checkInterface :: ModuleEnv -> Interface -> Interface+> --checkInterface mEnv (Interface m ds) =+> -- intfCheck pEnv tcEnv tyEnv (Interface m ds)+> -- where (pEnv,tcEnv,tyEnv) = foldl importInterface initEnvs ds+> -- importInterface (pEnv,tcEnv,tyEnv) (IImportDecl p m) =+> -- case lookupModule m mEnv of+> -- Just ds -> importInterfaceIntf (Interface m ds) pEnv tcEnv tyEnv+> -- Nothing -> internalError "importInterface"+> -- importInterface (pEnv,tcEnv,tyEnv) _ = (pEnv,tcEnv,tyEnv)+++\end{verbatim}+Interface files are updated by the Curry builder when necessary.+(see module \texttt{CurryBuilder}).++Description of the following obsolete functions:+After checking the module successfully, the compiler may need to+update the module's interface file. The file will be updated only if+the interface has been changed or the file did not exist before.++The code is a little bit tricky because we must make sure that the+interface file is closed before rewriting the interface, even if it+has not been read completely. On the other hand, we must not apply+\texttt{hClose} too early. Note that there is no need to close the+interface explicitly if the interface check succeeds because the whole+file must have been read in this case. In addition, we do not update+the interface file in this case and therefore it doesn't matter when+the file is closed.+\begin{verbatim}++> --updateInterface :: FilePath -> Interface -> IO ()+> --updateInterface sfn i =+> -- do+> -- eq <- catch (matchInterface ifn i) (const (return False))+> -- unless eq (writeInterface ifn i)+> -- where ifn = rootname sfn ++ intfExt++> --matchInterface :: FilePath -> Interface -> IO Bool+> --matchInterface ifn i =+> -- do+> -- h <- openFile ifn ReadMode+> -- s <- hGetContents h+> -- case parseInterface ifn s of+> -- Ok i' | i `intfEquiv` fixInterface i' -> return True+> -- _ -> hClose h >> return False++> --writeInterface :: FilePath -> Interface -> IO ()+> --writeInterface ifn = writeFile ifn . showln . ppInterface++\end{verbatim}+The compiler searches for interface files in the import search path+using the extension \texttt{".fint"}. Note that the current+directory is always searched first.+\begin{verbatim}++> lookupInterface :: [FilePath] -> ModuleIdent -> IO (Maybe FilePath)+> lookupInterface paths m = lookupFile (ifn : [catPath p ifn | p <- paths])+> where ifn = foldr1 catPath (moduleQualifiers m) ++ fintExt++\end{verbatim}+Literate source files use the extension \texttt{".lcurry"}.+\begin{verbatim}++> unlitLiterate :: FilePath -> String -> String+> unlitLiterate fn s+> | not (isLiterateSource fn) = s+> | null es = s'+> | otherwise = error es+> where (es,s') = unlit fn s++> isLiterateSource :: FilePath -> Bool+> isLiterateSource fn = litExt `isSuffixOf` fn++\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"+> --dumpHeader DumpTransformed = "Transformed code" +> --dumpHeader DumpNormalized = "Intermediate code after normalization"+> --dumpHeader DumpCam = "Abstract machine code"+++\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 CompilerResults+> 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 defaultResults+> 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 defaultResults+> else return defaultResults+> | flatXml opts+> = writeXML (output opts) fname cEnv il >> return defaultResults+> | otherwise+> = internalError "@Modules.genFlat: illegal option"+> where+> fintName = rootname fname ++ fintExt+> cEnv = curryEnv mEnv tcEnv intf mod+> emptyIntf = Prog "" [] [] [] []+> writeInterface intf msgs = do+> unless (noWarn opts) (printMessages msgs)+> writeFlatCurry fintName intf+++> genAbstract :: Options -> FilePath -> ValueEnv -> TCEnv -> Module +> -> IO CompilerResults+> genAbstract opts fname tyEnv tcEnv mod+> | abstract opts+> = do writeTypedAbs Nothing fname tyEnv tcEnv mod +> return defaultResults+> | untypedAbstract opts+> = do writeUntypedAbs Nothing fname tyEnv tcEnv mod+> return defaultResults+> | otherwise+> = internalError "@Modules.genAbstract: illegal option"++> printMessages :: Show a => [a] -> IO ()+> printMessages [] = return ()+> printMessages msgs = hPutStrLn stderr $ unlines $ map show 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 [basename (rootname fn)]) mexports decls+> | otherwise+> = Module mid mexports decls+++\end{verbatim}+Various filename extensions+\begin{verbatim}++> cExt = ".c"+> xmlExt = "_flat.xml"+> flatExt = ".fcy"+> fintExt = ".fint"+> acyExt = ".acy"+> uacyExt = ".uacy"+> sourceRepExt = ".cy"+> intfExt = ".icurry"+> litExt = ".lcurry"++\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}
+ src/NestEnv.lhs view
@@ -0,0 +1,73 @@++% $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 Env+> import TopEnv+> import Ident++> data NestEnv a = GlobalEnv (TopEnv a) | LocalEnv (NestEnv a) (Env 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 lookupEnv x env of+> Just _ -> error "internal error: bindNestEnv"+> Nothing -> LocalEnv genv (bindEnv 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 lookupEnv x' env of+> Just _ -> error "internal error: qualBindNestEnv"+> Nothing -> LocalEnv genv (bindEnv 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 lookupEnv 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 emptyEnv++\end{verbatim}
+ src/OldScopeEnv.hs view
@@ -0,0 +1,170 @@+module OldScopeEnv (ScopeEnv,+ newScopeEnv,+ insertIdent, getIdentLevel,+ isVisible, isDeclared,+ beginScope, endScope,+ getLevel,+ genIdent, genIdentList) where++import Data.Maybe++import Ident+import Env++++-------------------------------------------------------------------------------++-- 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 = (newIdEnv, [], 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, [newIdEnv], 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 = Env IdRep Int++data IdRep = Name String | Index Int deriving (Eq, Ord)+++-------------------------------------------------------------------------------++--+newIdEnv :: IdEnv+newIdEnv = emptyEnv+++--+insertId :: Int -> Ident -> IdEnv -> IdEnv+insertId level ident env+ = bindEnv (Name (name ident)) + level + (bindEnv (Index (uniqueId ident)) level env)+++--+idExists :: Ident -> IdEnv -> Bool+idExists ident env = indexExists (uniqueId ident) env+++--+getIdLevel :: Ident -> IdEnv -> Maybe Int+getIdLevel ident env = lookupEnv (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 (lookupEnv (Name name) env)+++--+indexExists :: Int -> IdEnv -> Bool+indexExists index env = isJust (lookupEnv (Index index) env)+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/PatchPrelude.hs view
@@ -0,0 +1,40 @@+module PatchPrelude where+++import ExtendedFlat+++-- 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/PathUtils.lhs view
@@ -0,0 +1,60 @@++% $Id: PathUtils.lhs,v 1.5 2003/05/04 16:12:35 wlux Exp $+%+% Copyright (c) 1999-2003, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{PathUtils.lhs}+\section{Pathnames}+This module implements some utility functions for manipulating path+names and finding files.+\begin{verbatim}++> module PathUtils(basename, rootname,extension, catPath,+> lookupFile,+> currySubdir,writeModule,readModule,+> doesModuleExist,maybeReadModule,getModuleModTime) where++> import System.FilePath+> import System.Directory+> import CurrySubdir++\end{verbatim}++Most of this module is superseded by System.FilePath from package filepath.++Within this module we assume Unix style path semantics, i.e.\ +components of a path name are separated by forward slash characters+(\texttt{/}) and file extensions are separated with a dot character+(\texttt{.}).++\end{verbatim}++> catPath :: FilePath -> FilePath -> FilePath+> catPath = combine+>+> rootname, extension :: FilePath -> FilePath+> rootname = dropExtension+> extension = takeExtension++\end{verbatim}++The function \texttt{lookupFile} can be used to search for files. It+returns the first name from the argument list for which a regular file+exists in the file system.+\begin{verbatim}++> lookupFile :: [FilePath] -> IO (Maybe FilePath)+> lookupFile fns = lookupFile' (concatMap (\ fn -> [inCurrySubdir fn,fn]) fns)+> where+> lookupFile' [] = return Nothing+> lookupFile' (fn:fns) =+> do+> so <- doesFileExist fn+> if so then return (Just fn) else lookupFile' fns++\end{verbatim}++++
+ src/Position.lhs view
@@ -0,0 +1,95 @@+> {-# LANGUAGE DeriveDataTypeable #-}++% -*- LaTeX -*-+% $Id: Position.lhs,v 1.2 2000/10/08 09:55:43 lux Exp $+%+% $Log: Position.lhs,v $+% Revision 1.2 2000/10/08 09:55:43 lux+% Column numbers now start at 1. If the column number is less than 1 it+% will not be shown.+%+% Revision 1.1 2000/07/23 11:03:37 lux+% Positions now implemented in a separate module.+%+%+\nwfilename{Position.lhs}+\section{Positions}+A source file position consists of a filename, a line number, and a+column number. A tab stop is assumed at every eighth column.+\begin{verbatim}++> module Position where+> import Data.Generics++> newtype SrcRef = SrcRef [Int] deriving (Typeable,Data) -- a pointer to the origin++-- the instances for standard classes or such that SrcRefs are invisible++> instance Show SrcRef where show _ = ""+> instance Read SrcRef where readsPrec _ s = [(noRef,s)]+> instance Eq SrcRef where _ == _ = True+> instance Ord SrcRef where compare _ _ = EQ++> noRef :: SrcRef+> noRef = SrcRef []+>+> incSrcRef :: SrcRef -> Int -> SrcRef+> incSrcRef (SrcRef [i]) j = SrcRef [i+j]+> incSrcRef is _ = error $ "internal error; increment source ref: " ++ show is++> data Position +> = Position{ file :: FilePath, line :: Int, column :: Int, ast :: SrcRef }+> | AST { ast :: SrcRef }+> deriving (Eq, Ord,Data,Typeable)+>+> incPosition :: Position -> Int -> Position+> incPosition p j = p{ast=incSrcRef (ast p) j}+++> instance Read Position where+> readsPrec p s = +> [ (Position{file="",line=i,column=j,ast=noRef},s') | ((i,j),s') <- readsPrec p s]++> instance Show Position where+> showsPrec _ Position{file=fn,line=l,column=c} =+> (if null fn then id else shows fn . showString ", ") .+> showString "line " . shows l .+> (if c > 0 then showChar '.' . shows c else id)+> showsPrec _ AST{} = id++> tabWidth :: Int+> tabWidth = 8++> first :: FilePath -> Position+> first fn = Position fn 1 1 noRef++> incr :: Position -> Int -> Position+> incr p@Position{column=c} n = p{column=c + n}++> next :: Position -> Position+> next = flip incr 1++> tab :: Position -> Position+> tab p@Position{column=c} = p{column=c + tabWidth - (c - 1) `mod` tabWidth}++> nl :: Position -> Position+> nl p@Position{line=l} = p{line=l + 1, column=1}++> noPos, noPos' :: Position+> noPos = Position{ file = "", line = 0, column = 0, ast = noRef }+> noPos' = AST noRef++> showLine :: Position -> String+> showLine x@Position{line=l,column=c} +> | x == noPos = ""+> | otherwise = "(line " ++ show l ++ "." ++ show c ++ ") "++\end{verbatim}++> class SrcRefOf a where+> srcRefsOf :: a -> [SrcRef]+> srcRefsOf = (:[]) . srcRefOf+> srcRefOf :: a -> SrcRef+> srcRefOf = head . srcRefsOf++> instance SrcRefOf Position where srcRefOf = ast
+ src/PrecCheck.lhs view
@@ -0,0 +1,462 @@++% $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,precCheckGoal) where++> import Data.List++> 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 linear ops of+> Linear ->+> case [PIdent p op | PIdent p op <- ops, op `notElem` bvs] of+> [] -> foldr bindPrec pEnv fixDs+> PIdent p op : _ -> errorAt' (undefinedOperator op)+> NonLinear (PIdent p op) -> errorAt' (duplicatePrecedence op)+> where (fixDs,nonFixDs) = partition isInfixDecl ds+> bvs = concatMap boundValues nonFixDs+> ops = [PIdent p 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++> precCheckGoal :: PEnv -> Goal -> Goal+> precCheckGoal pEnv (Goal p e ds) = Goal p (checkExpr m pEnv' e) ds'+> where (pEnv',ds') = checkDecls m pEnv ds+> m = emptyMIdent++> 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 fix1 pr1 = opPrec op1 pEnv+> 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/Pretty.lhs view
@@ -0,0 +1,905 @@+Hand converted to standard Haskell -- jcp++*********************************************************************************+* *+* John Hughes's and Simon Peyton Jones's Pretty Printer Combinators *+* *+* based on "The Design of a Pretty-printing Library" *+* in Advanced Functional Programming, *+* Johan Jeuring and Erik Meijer (eds), LNCS 925 *+* http://www.cs.chalmers.se/~rjmh/Papers/pretty.ps *+* *+* Heavily modified by Simon Peyton Jones, Dec 96 *+* *+*********************************************************************************++Version 3.0 28 May 1997+ * Cured massive performance bug. If you write++ foldl <> empty (map (text.show) [1..10000])++ you get quadratic behaviour with V2.0. Why? For just the same reason as you get+ quadratic behaviour with left-associated (++) chains.++ This is really bad news. One thing a pretty-printer abstraction should+ certainly guarantee is insensivity to associativity. It matters: suddenly+ GHC's compilation times went up by a factor of 100 when I switched to the+ new pretty printer.+ + I fixed it with a bit of a hack (because I wanted to get GHC back on the+ road). I added two new constructors to the Doc type, Above and Beside:+ + <> = Beside+ $$ = Above+ + Then, where I need to get to a "TextBeside" or "NilAbove" form I "force"+ the Doc to squeeze out these suspended calls to Beside and Above; but in so+ doing I re-associate. It's quite simple, but I'm not satisfied that I've done+ the best possible job. I'll send you the code if you are interested.++ * Added new exports:+ punctuate, hang+ int, integer, float, double, rational,+ lparen, rparen, lbrack, rbrack, lbrace, rbrace,++ * fullRender's type signature has changed. Rather than producing a string it+ now takes an extra couple of arguments that tells it how to glue fragments+ of output together:++ fullRender :: Mode+ -> Int -- Line length+ -> Float -- Ribbons per line+ -> (TextDetails -> a -> a) -- What to do with text+ -> a -- What to do at the end+ -> Doc+ -> a -- Result++ The "fragments" are encapsulated in the TextDetails data type:+ data TextDetails = Chr Char+ | Str String+ | PStr FAST_STRING++ The Chr and Str constructors are obvious enough. The PStr constructor has a packed+ string (FAST_STRING) inside it. It's generated by using the new "ptext" export.++ An advantage of this new setup is that you can get the renderer to do output+ directly (by passing in a function of type (TextDetails -> IO () -> IO ()),+ rather than producing a string that you then print.+++Version 2.0 24 April 1997+ * Made empty into a left unit for <> as well as a right unit;+ it is also now true that+ nest k empty = empty+ which wasn't true before.++ * Fixed an obscure bug in sep that occassionally gave very wierd behaviour++ * Added $+$++ * Corrected and tidied up the laws and invariants++======================================================================+Relative to John's original paper, there are the following new features:++1. There's an empty document, "empty". It's a left and right unit for + both <> and $$, and anywhere in the argument list for+ sep, hcat, hsep, vcat, fcat etc.++ It is Really Useful in practice.++2. There is a paragraph-fill combinator, fsep, that's much like sep,+ only it keeps fitting things on one line until itc can't fit any more.++3. Some random useful extra combinators are provided. + <+> puts its arguments beside each other with a space between them,+ unless either argument is empty in which case it returns the other+++ hcat is a list version of <>+ hsep is a list version of <+>+ vcat is a list version of $$++ sep (separate) is either like hsep or like vcat, depending on what fits++ cat is behaves like sep, but it uses <> for horizontal conposition+ fcat is behaves like fsep, but it uses <> for horizontal conposition++ These new ones do the obvious things:+ char, semi, comma, colon, space,+ parens, brackets, braces, + quotes, doubleQuotes+ +4. The "above" combinator, $$, now overlaps its two arguments if the+ last line of the top argument stops before the first line of the second begins.+ For example: text "hi" $$ nest 5 "there"+ lays out as+ hi there+ rather than+ hi+ there++ There are two places this is really useful++ a) When making labelled blocks, like this:+ Left -> code for left+ Right -> code for right+ LongLongLongLabel ->+ code for longlonglonglabel+ The block is on the same line as the label if the label is+ short, but on the next line otherwise.++ b) When laying out lists like this:+ [ first+ , second+ , third+ ]+ which some people like. But if the list fits on one line+ you want [first, second, third]. You can't do this with+ John's original combinators, but it's quite easy with the+ new $$.++ The combinator $+$ gives the original "never-overlap" behaviour.++5. Several different renderers are provided:+ * a standard one+ * one that uses cut-marks to avoid deeply-nested documents + simply piling up in the right-hand margin+ * one that ignores indentation (fewer chars output; good for machines)+ * one that ignores indentation and newlines (ditto, only more so)++6. Numerous implementation tidy-ups+ Use of unboxed data types to speed up the implementation++++\begin{code}+module Pretty (+ Doc, -- Abstract+ Mode(..), TextDetails(..),+ Style,++ empty, nest,++ text, char, ptext,+ int, integer, float, double, rational,+ parens, brackets, braces, quotes, doubleQuotes,+ semi, comma, colon, space, equals,+ lparen, rparen, lbrack, rbrack, lbrace, rbrace,++ (<>), (<+>), hcat, hsep, + ($$), ($+$), vcat, + sep, cat, + fsep, fcat, ++ hang, punctuate,+ + renderStyle, + render, fullRender+ ) where++-- Don't import Util( assertPanic ) because it makes a loop in the module structure++import Data.Ratio+infixl 6 <> +infixl 6 <+>+infixl 5 $$, $+$+\end{code}++++*********************************************************+* *+\subsection{CPP magic so that we can compile with both GHC and Hugs}+* *+*********************************************************++The library uses unboxed types to get a bit more speed, but these CPP macros+allow you to use either GHC or Hugs. To get GHC, just set the CPP variable+ __GLASGOW_HASKELL__+++*********************************************************+* *+\subsection{The interface}+* *+*********************************************************++The primitive @Doc@ values++\begin{code}+empty :: Doc+text :: String -> Doc +char :: Char -> Doc++semi, comma, colon, space, equals :: Doc+lparen, rparen, lbrack, rbrack, lbrace, rbrace :: Doc++parens, brackets, braces :: Doc -> Doc +quotes, doubleQuotes :: Doc -> Doc++int :: Int -> Doc+integer :: Integer -> Doc+float :: Float -> Doc+double :: Double -> Doc+rational :: Rational -> Doc+\end{code}+++Combining @Doc@ values++\begin{code}+(<>) :: Doc -> Doc -> Doc -- Beside+hcat :: [Doc] -> Doc -- List version of <>+(<+>) :: Doc -> Doc -> Doc -- Beside, separated by space+hsep :: [Doc] -> Doc -- List version of <+>++($$) :: Doc -> Doc -> Doc -- Above; if there is no+ -- overlap it "dovetails" the two+vcat :: [Doc] -> Doc -- List version of $$++cat :: [Doc] -> Doc -- Either hcat or vcat+sep :: [Doc] -> Doc -- Either hsep or vcat+fcat :: [Doc] -> Doc -- ``Paragraph fill'' version of cat+fsep :: [Doc] -> Doc -- ``Paragraph fill'' version of sep++nest :: Int -> Doc -> Doc -- Nested+\end{code}++GHC-specific ones.++\begin{code}+hang :: Doc -> Int -> Doc -> Doc+punctuate :: Doc -> [Doc] -> [Doc] -- punctuate p [d1, ... dn] = [d1 <> p, d2 <> p, ... dn-1 <> p, dn]+\end{code}++Displaying @Doc@ values. ++\begin{code}+instance Show Doc where+ showsPrec prec doc cont = showDoc doc cont++render :: Doc -> String -- Uses default style+fullRender :: Mode+ -> Int -- Line length+ -> Float -- Ribbons per line+ -> (TextDetails -> a -> a) -- What to do with text+ -> a -- What to do at the end+ -> Doc+ -> a -- Result++renderStyle :: Style -> Doc -> String+data Style = Style { lineLength :: Int, -- In chars+ ribbonsPerLine :: Float, -- Ratio of ribbon length to line length+ mode :: Mode+ }+style :: Style -- The default style+style = Style { lineLength = 100, ribbonsPerLine = 2.5, mode = PageMode }++data Mode = PageMode -- Normal + | ZigZagMode -- With zig-zag cuts+ | LeftMode -- No indentation, infinitely long lines+ | OneLineMode -- All on one line++\end{code}+++*********************************************************+* *+\subsection{The @Doc@ calculus}+* *+*********************************************************++The @Doc@ combinators satisfy the following laws:+\begin{verbatim}+Laws for $$+~~~~~~~~~~~+<a1> (x $$ y) $$ z = x $$ (y $$ z)+<a2> empty $$ x = x+<a3> x $$ empty = x++ ...ditto $+$...++Laws for <>+~~~~~~~~~~~+<b1> (x <> y) <> z = x <> (y <> z)+<b2> empty <> x = empty+<b3> x <> empty = x++ ...ditto <+>...++Laws for text+~~~~~~~~~~~~~+<t1> text s <> text t = text (s++t)+<t2> text "" <> x = x, if x non-empty++Laws for nest+~~~~~~~~~~~~~+<n1> nest 0 x = x+<n2> nest k (nest k' x) = nest (k+k') x+<n3> nest k (x <> y) = nest k z <> nest k y+<n4> nest k (x $$ y) = nest k x $$ nest k y+<n5> nest k empty = empty+<n6> x <> nest k y = x <> y, if x non-empty++** Note the side condition on <n6>! It is this that+** makes it OK for empty to be a left unit for <>.++Miscellaneous+~~~~~~~~~~~~~+<m1> (text s <> x) $$ y = text s <> ((text "" <> x)) $$ + nest (-length s) y)++<m2> (x $$ y) <> z = x $$ (y <> z)+ if y non-empty+++Laws for list versions+~~~~~~~~~~~~~~~~~~~~~~+<l1> sep (ps++[empty]++qs) = sep (ps ++ qs)+ ...ditto hsep, hcat, vcat, fill...++<l2> nest k (sep ps) = sep (map (nest k) ps)+ ...ditto hsep, hcat, vcat, fill...++Laws for oneLiner+~~~~~~~~~~~~~~~~~+<o1> oneLiner (nest k p) = nest k (oneLiner p)+<o2> oneLiner (x <> y) = oneLiner x <> oneLiner y +\end{verbatim}+++You might think that the following verion of <m1> would+be neater:+\begin{verbatim}+<3 NO> (text s <> x) $$ y = text s <> ((empty <> x)) $$ + nest (-length s) y)+\end{verbatim}+But it doesn't work, for if x=empty, we would have+\begin{verbatim}+ text s $$ y = text s <> (empty $$ nest (-length s) y)+ = text s <> nest (-length s) y+\end{verbatim}++++*********************************************************+* *+\subsection{Simple derived definitions}+* *+*********************************************************++\begin{code}+semi = char ';'+colon = char ':'+comma = char ','+space = char ' '+equals = char '='+lparen = char '('+rparen = char ')'+lbrack = char '['+rbrack = char ']'+lbrace = char '{'+rbrace = char '}'++int n = text (show n)+integer n = text (show n)+float n = text (show n)+double n = text (show n)+rational n = text (show n)+-- SIGBJORN wrote instead:+-- rational n = text (show (fromRationalX n))++quotes p = char '`' <> p <> char '\''+doubleQuotes p = char '"' <> p <> char '"'+parens p = char '(' <> p <> char ')'+brackets p = char '[' <> p <> char ']'+braces p = char '{' <> p <> char '}'+++hcat = foldr (<>) empty+hsep = foldr (<+>) empty+vcat = foldr ($$) empty++hang d1 n d2 = d1 $$ (nest n d2)++punctuate p [] = []+punctuate p (d:ds) = go d ds+ where+ go d [] = [d]+ go d (e:es) = (d <> p) : go e es+\end{code}+++*********************************************************+* *+\subsection{The @Doc@ data type}+* *+*********************************************************++A @Doc@ represents a {\em set} of layouts. A @Doc@ with+no occurrences of @Union@ or @NoDoc@ represents just one layout.+\begin{code}+data Doc+ = Empty -- empty+ | NilAbove Doc -- text "" $$ x+ | TextBeside TextDetails Int Doc -- text s <> x + | Nest Int Doc -- nest k x+ | Union Doc Doc -- ul `union` ur+ | NoDoc -- The empty set of documents+ | Beside Doc Bool Doc -- True <=> space between+ | Above Doc Bool Doc -- True <=> never overlap++type RDoc = Doc -- RDoc is a "reduced Doc", guaranteed not to have a top-level Above or Beside+++reduceDoc :: Doc -> RDoc+reduceDoc (Beside p g q) = beside p g (reduceDoc q)+reduceDoc (Above p g q) = above p g (reduceDoc q)+reduceDoc p = p+++data TextDetails = Chr Char+ | Str String+ | PStr String+space_text = Chr ' '+nl_text = Chr '\n'+\end{code}++Here are the invariants:+\begin{itemize}+\item+The argument of @NilAbove@ is never @Empty@. Therefore+a @NilAbove@ occupies at least two lines.++\item+The arugment of @TextBeside@ is never @Nest@.++\item +The layouts of the two arguments of @Union@ both flatten to the same string.++\item +The arguments of @Union@ are either @TextBeside@, or @NilAbove@.++\item+The right argument of a union cannot be equivalent to the empty set (@NoDoc@).+If the left argument of a union is equivalent to the empty set (@NoDoc@),+then the @NoDoc@ appears in the first line.++\item +An empty document is always represented by @Empty@.+It can't be hidden inside a @Nest@, or a @Union@ of two @Empty@s.++\item +The first line of every layout in the left argument of @Union@+is longer than the first line of any layout in the right argument.+(1) ensures that the left argument has a first line. In view of (3),+this invariant means that the right argument must have at least two+lines.+\end{itemize}++\begin{code}+ -- Arg of a NilAbove is always an RDoc+nilAbove_ p = NilAbove p++ -- Arg of a TextBeside is always an RDoc+textBeside_ s sl p = TextBeside s sl p++ -- Arg of Nest is always an RDoc+nest_ k p = Nest k p++ -- Args of union are always RDocs+union_ p q = Union p q++\end{code}+++Notice the difference between+ * NoDoc (no documents)+ * Empty (one empty document; no height and no width)+ * text "" (a document containing the empty string;+ one line high, but has no width)++++*********************************************************+* *+\subsection{@empty@, @text@, @nest@, @union@}+* *+*********************************************************++\begin{code}+empty = Empty++char c = textBeside_ (Chr c) 1 Empty+text s = case length s of {sl -> textBeside_ (Str s) sl Empty}+ptext s = case length s of {sl -> textBeside_ (PStr s) sl Empty}++nest k p = mkNest k (reduceDoc p) -- Externally callable version++-- mkNest checks for Nest's invariant that it doesn't have an Empty inside it+mkNest k (Nest k1 p) = mkNest (k + k1) p+mkNest k NoDoc = NoDoc+mkNest k Empty = Empty+mkNest 0 p = p -- Worth a try!+mkNest k p = nest_ k p++-- mkUnion checks for an empty document+mkUnion Empty q = Empty+mkUnion p q = p `union_` q+\end{code}++*********************************************************+* *+\subsection{Vertical composition @$$@}+* *+*********************************************************+++\begin{code}+p $$ q = Above p False q+p $+$ q = Above p True q++above :: Doc -> Bool -> RDoc -> RDoc+above (Above p g1 q1) g2 q2 = above p g1 (above q1 g2 q2)+above p@(Beside _ _ _) g q = aboveNest (reduceDoc p) g 0 (reduceDoc q)+above p g q = aboveNest p g 0 (reduceDoc q)++aboveNest :: RDoc -> Bool -> Int -> RDoc -> RDoc+-- Specfication: aboveNest p g k q = p $g$ (nest k q)++aboveNest NoDoc g k q = NoDoc+aboveNest (p1 `Union` p2) g k q = aboveNest p1 g k q `union_` + aboveNest p2 g k q+ +aboveNest Empty g k q = mkNest k q+aboveNest (Nest k1 p) g k q = nest_ k1 (aboveNest p g (k - k1) q)+ -- p can't be Empty, so no need for mkNest+ +aboveNest (NilAbove p) g k q = nilAbove_ (aboveNest p g k q)+aboveNest (TextBeside s sl p) g k q = textBeside_ s sl rest+ where+ k1 = k - sl+ rest = case p of+ Empty -> nilAboveNest g k1 q+ other -> aboveNest p g k1 q+\end{code}++\begin{code}+nilAboveNest :: Bool -> Int -> RDoc -> RDoc+-- Specification: text s <> nilaboveNest g k q +-- = text s <> (text "" $g$ nest k q)++nilAboveNest g k Empty = Empty -- Here's why the "text s <>" is in the spec!+nilAboveNest g k (Nest k1 q) = nilAboveNest g (k + k1) q++nilAboveNest g k q | (not g) && (k > 0) -- No newline if no overlap+ = textBeside_ (Str (spaces k)) k q+ | otherwise -- Put them really above+ = nilAbove_ (mkNest k q)+\end{code}+++*********************************************************+* *+\subsection{Horizontal composition @<>@}+* *+*********************************************************++\begin{code}+p <> q = Beside p False q+p <+> q = Beside p True q++beside :: Doc -> Bool -> RDoc -> RDoc+-- Specification: beside g p q = p <g> q+ +beside NoDoc g q = NoDoc+beside (p1 `Union` p2) g q = (beside p1 g q) `union_` (beside p2 g q)+beside Empty g q = q+beside (Nest k p) g q = nest_ k (beside p g q) -- p non-empty+beside p@(Beside p1 g1 q1) g2 q2 + {- (A `op1` B) `op2` C == A `op1` (B `op2` C) iff op1 == op2 + [ && (op1 == <> || op1 == <+>) ] -}+ | g1 == g2 = beside p1 g1 (beside q1 g2 q2)+ | otherwise = beside (reduceDoc p) g2 q2+beside p@(Above _ _ _) g q = beside (reduceDoc p) g q+beside (NilAbove p) g q = nilAbove_ (beside p g q)+beside (TextBeside s sl p) g q = textBeside_ s sl rest+ where+ rest = case p of+ Empty -> nilBeside g q+ other -> beside p g q+\end{code}++\begin{code}+nilBeside :: Bool -> RDoc -> RDoc+-- Specification: text "" <> nilBeside g p +-- = text "" <g> p++nilBeside g Empty = Empty -- Hence the text "" in the spec+nilBeside g (Nest _ p) = nilBeside g p+nilBeside g p | g = textBeside_ space_text 1 p+ | otherwise = p+\end{code}++*********************************************************+* *+\subsection{Separate, @sep@, Hughes version}+* *+*********************************************************++\begin{code}+-- Specification: sep ps = oneLiner (hsep ps)+-- `union`+-- vcat ps++sep = sepX True -- Separate with spaces+cat = sepX False -- Don't++sepX x [] = empty+sepX x (p:ps) = sep1 x (reduceDoc p) 0 ps+++-- Specification: sep1 g k ys = sep (x : map (nest k) ys)+-- = oneLiner (x <g> nest k (hsep ys))+-- `union` x $$ nest k (vcat ys)++sep1 :: Bool -> RDoc -> Int -> [Doc] -> RDoc+sep1 g NoDoc k ys = NoDoc+sep1 g (p `Union` q) k ys = sep1 g p k ys+ `union_`+ (aboveNest q False k (reduceDoc (vcat ys)))++sep1 g Empty k ys = mkNest k (sepX g ys)+sep1 g (Nest n p) k ys = nest_ n (sep1 g p (k - n) ys)++sep1 g (NilAbove p) k ys = nilAbove_ (aboveNest p False k (reduceDoc (vcat ys)))+sep1 g (TextBeside s sl p) k ys = textBeside_ s sl (sepNB g p (k - sl) ys)++-- Specification: sepNB p k ys = sep1 (text "" <> p) k ys+-- Called when we have already found some text in the first item+-- We have to eat up nests++sepNB g (Nest _ p) k ys = sepNB g p k ys++sepNB g Empty k ys = oneLiner (nilBeside g (reduceDoc rest))+ `mkUnion` + nilAboveNest False k (reduceDoc (vcat ys))+ where+ rest | g = hsep ys+ | otherwise = hcat ys++sepNB g p k ys = sep1 g p k ys+\end{code}++*********************************************************+* *+\subsection{@fill@}+* *+*********************************************************++\begin{code}+fsep = fill True+fcat = fill False++-- Specification: +-- fill [] = empty+-- fill [p] = p+-- fill (p1:p2:ps) = oneLiner p1 <#> nest (length p1) +-- (fill (oneLiner p2 : ps))+-- `union`+-- p1 $$ fill ps++fill g [] = empty+fill g (p:ps) = fill1 g (reduceDoc p) 0 ps+++fill1 :: Bool -> RDoc -> Int -> [Doc] -> Doc+fill1 g NoDoc k ys = NoDoc+fill1 g (p `Union` q) k ys = fill1 g p k ys+ `union_`+ (aboveNest q False k (fill g ys))++fill1 g Empty k ys = mkNest k (fill g ys)+fill1 g (Nest n p) k ys = nest_ n (fill1 g p (k - n) ys)++fill1 g (NilAbove p) k ys = nilAbove_ (aboveNest p False k (fill g ys))+fill1 g (TextBeside s sl p) k ys = textBeside_ s sl (fillNB g p (k - sl) ys)++fillNB g (Nest _ p) k ys = fillNB g p k ys+fillNB g Empty k [] = Empty+fillNB g Empty k (y:ys) = nilBeside g (fill1 g (oneLiner (reduceDoc y)) k1 ys)+ `mkUnion` + nilAboveNest False k (fill g (y:ys))+ where+ k1 | g = k - 1+ | otherwise = k++fillNB g p k ys = fill1 g p k ys+\end{code}+++*********************************************************+* *+\subsection{Selecting the best layout}+* *+*********************************************************++\begin{code}+best :: Mode+ -> Int -- Line length+ -> Int -- Ribbon length+ -> RDoc+ -> RDoc -- No unions in here!++best OneLineMode w r p+ = get p+ where+ get Empty = Empty+ get NoDoc = NoDoc+ get (NilAbove p) = nilAbove_ (get p)+ get (TextBeside s sl p) = textBeside_ s sl (get p)+ get (Nest k p) = get p -- Elide nest+ get (p `Union` q) = first (get p) (get q)++best mode w r p+ = get w p+ where+ get :: Int -- (Remaining) width of line+ -> Doc -> Doc+ get w Empty = Empty+ get w NoDoc = NoDoc+ get w (NilAbove p) = nilAbove_ (get w p)+ get w (TextBeside s sl p) = textBeside_ s sl (get1 w sl p)+ get w (Nest k p) = nest_ k (get (w - k) p)+ get w (p `Union` q) = nicest w r (get w p) (get w q)++ get1 :: Int -- (Remaining) width of line+ -> Int -- Amount of first line already eaten up+ -> Doc -- This is an argument to TextBeside => eat Nests+ -> Doc -- No unions in here!++ get1 w sl Empty = Empty+ get1 w sl NoDoc = NoDoc+ get1 w sl (NilAbove p) = nilAbove_ (get (w - sl) p)+ get1 w sl (TextBeside t tl p) = textBeside_ t tl (get1 w (sl + tl) p)+ get1 w sl (Nest k p) = get1 w sl p+ get1 w sl (p `Union` q) = nicest1 w r sl (get1 w sl p) + (get1 w sl q)++nicest w r p q = nicest1 w r 0 p q+nicest1 w r sl p q | fits ((w `minn` r) - sl) p = p+ | otherwise = q++fits :: Int -- Space available+ -> Doc+ -> Bool -- True if *first line* of Doc fits in space available+ +fits n p | n < 0 = False+fits n NoDoc = False+fits n Empty = True+fits n (NilAbove _) = True+fits n (TextBeside _ sl p) = fits (n - sl) p++minn x y | x < y = x+ | otherwise = y+\end{code}++@first@ and @nonEmptySet@ are similar to @nicest@ and @fits@, only simpler.+@first@ returns its first argument if it is non-empty, otherwise its second.++\begin{code}+first p q | nonEmptySet p = p + | otherwise = q++nonEmptySet NoDoc = False+nonEmptySet (p `Union` q) = True+nonEmptySet Empty = True+nonEmptySet (NilAbove p) = True -- NoDoc always in first line+nonEmptySet (TextBeside _ _ p) = nonEmptySet p+nonEmptySet (Nest _ p) = nonEmptySet p+\end{code}++@oneLiner@ returns the one-line members of the given set of @Doc@s.++\begin{code}+oneLiner :: Doc -> Doc+oneLiner NoDoc = NoDoc+oneLiner Empty = Empty+oneLiner (NilAbove p) = NoDoc+oneLiner (TextBeside s sl p) = textBeside_ s sl (oneLiner p)+oneLiner (Nest k p) = nest_ k (oneLiner p)+oneLiner (p `Union` q) = oneLiner p+\end{code}++++*********************************************************+* *+\subsection{Displaying the best layout}+* *+*********************************************************+++\begin{code}+renderStyle Style{mode=mode, lineLength=lineLength, ribbonsPerLine=ribbonsPerLine} doc + = fullRender mode lineLength ribbonsPerLine string_txt "" doc++render doc = showDoc doc ""+showDoc doc rest = fullRender PageMode 100 1.5 string_txt rest doc++string_txt (Chr c) s = c:s+string_txt (Str s1) s2 = s1 ++ s2+string_txt (PStr s1) s2 = s1 ++ s2+\end{code}++\begin{code}++fullRender OneLineMode _ _ txt end doc = easy_display space_text txt end (reduceDoc doc)+fullRender LeftMode _ _ txt end doc = easy_display nl_text txt end (reduceDoc doc)++fullRender mode line_length ribbons_per_line txt end doc+ = display mode line_length ribbon_length txt end best_doc+ where + best_doc = best mode hacked_line_length ribbon_length (reduceDoc doc)++ hacked_line_length, ribbon_length :: Int+ ribbon_length = round (fromIntegral line_length / ribbons_per_line)+ hacked_line_length = case mode of { ZigZagMode -> maxBound; other -> line_length }++display mode page_width ribbon_width txt end doc+ = case page_width - ribbon_width of { gap_width ->+ case gap_width `quot` 2 of { shift ->+ let+ lay k (Nest k1 p) = lay (k + k1) p+ lay k Empty = end+ + lay k (NilAbove p) = nl_text `txt` lay k p+ + lay k (TextBeside s sl p)+ = case mode of+ ZigZagMode | k >= gap_width+ -> nl_text `txt` (+ Str (multi_ch shift '/') `txt` (+ nl_text `txt` (+ lay1 (k - shift) s sl p)))++ | k < 0+ -> nl_text `txt` (+ Str (multi_ch shift '\\') `txt` (+ nl_text `txt` (+ lay1 (k + shift) s sl p )))++ other -> lay1 k s sl p+ + lay1 k s sl p = Str (indent k) `txt` (s `txt` lay2 (k + sl) p)+ + lay2 k (NilAbove p) = nl_text `txt` lay k p+ lay2 k (TextBeside s sl p) = s `txt` (lay2 (k + sl) p)+ lay2 k (Nest _ p) = lay2 k p+ lay2 k Empty = end+ in+ lay 0 doc+ }}++cant_fail = error "easy_display: NoDoc"+easy_display nl_text txt end doc + = lay doc cant_fail+ where+ lay NoDoc no_doc = no_doc+ lay (Union p q) no_doc = {- lay p -} (lay q cant_fail) -- Second arg can't be NoDoc+ lay (Nest k p) no_doc = lay p no_doc+ lay Empty no_doc = end+ lay (NilAbove p) no_doc = nl_text `txt` lay p cant_fail -- NoDoc always on first line+ lay (TextBeside s sl p) no_doc = s `txt` lay p no_doc++indent n | n >= 8 = '\t' : indent (n - 8)+ | otherwise = spaces n++multi_ch 0 ch = ""+multi_ch n ch = ch : multi_ch (n - 1) ch++spaces 0 = ""+spaces n = ' ' : spaces (n - 1)+\end{code}+
+ src/Qual.lhs view
@@ -0,0 +1,166 @@++% $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,qualGoal) where+> import Base+> import TopEnv++> qual :: ModuleIdent -> ValueEnv -> [Decl] -> [Decl]+> qual m tyEnv ds = map (qualDecl m tyEnv) ds++> qualGoal :: ValueEnv -> Goal -> Goal+> qualGoal tyEnv (Goal p e ds) =+> Goal p (qualExpr (mkMIdent []) tyEnv e) +> (map (qualDecl (mkMIdent []) 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 view
@@ -0,0 +1,59 @@++% $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 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 zeroSet [])+> where dfs [] marks stack = (marks,stack)+> dfs (x:xs) marks stack+> | x `elemSet` marks = dfs xs marks stack+> | otherwise = dfs xs marks' (x:stack')+> where (marks',stack') = dfs (defs x) (x `addToSet` 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 zeroSet [])+> where dfs [] marks stack = (marks,stack)+> dfs (x:xs) marks stack+> | x `elemSet` marks = dfs xs marks stack+> | otherwise = dfs xs marks' ((x:concat stack'):stack)+> where (marks',stack') = dfs (uses x) (x `addToSet` marks) []+> uses x = filter (any (`elem` bvs x) . fvs) xs++\end{verbatim}
+ src/ScopeEnv.hs view
@@ -0,0 +1,176 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 Env+import Prelude hiding (lookup)++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++-- Returns an empty scope environment+new :: Ord a => ScopeEnv a b+new = ScopeEnv 0 emptyEnv []+++-- 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 = bindEnv 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') -> bindEnv key (val,lev') local)+ (lookupEnv 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') -> bindEnv key (fun val', lev') local)+ (lookupEnv 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) (lookupEnv 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 (lookupEnv 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) (lookupEnv 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 (envToList top)) []+endScopeUp (ScopeEnv lev top (local:local':locals))+ = ScopeEnv (lev - 1) + top + ((foldr (updateSE local) local' (envToList 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)) (envToList 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) (envToList local))+++-- Returns the current level+currentLevel :: Ord a => ScopeEnv a b -> Int+currentLevel env = selectSE const env+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+-- Privates...++--+modifySE :: (Int -> Env a (b,Int) -> Env 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 -> Env 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 => Env a (b,Int) -> (a,(b,Int)) -> Env a (b,Int) + -> Env a (b,Int)+updateSE local (key,(_,lev)) local'+ = maybe local' + (\ (val',lev') + -> if lev == lev' then bindEnv key (val',lev) local' + else local')+ (lookupEnv key local)++++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++-- Data type for representing information in nested scopes.+data ScopeEnv a b = ScopeEnv Int (Env a (b,Int)) [Env a (b,Int)]+ deriving Show+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------
+ src/Set.lhs view
@@ -0,0 +1,91 @@+% -*- LaTeX -*-+% $Id: Set.lhs,v 1.6 2002/12/20 14:58:46 lux Exp $+%+% Copyright (c) 2002, Wolfgang Lux+% See LICENSE for the full license.+%+\nwfilename{Set.lhs}+\section{Sets}+The module \texttt{Set} implements sets as a special case of finite+maps.+\begin{verbatim}++> module Set where++> import Data.List+> import Data.Maybe++> import Map++> infixl 8 `addToSet`, `deleteFromSet`+> infixl 7 `unionSet`, `intersectionSet`+> infixl 6 `diffSet`, `symDiffSet`+> infix 4 `subsetSet`, `elemSet`, `notElemSet`++> newtype Set a = Set (FM a ())++\end{verbatim}+Two sets are equal if both contain the same elements.+\begin{verbatim}++> instance Ord a => Eq (Set a) where+> xs == ys = toListSet xs == toListSet ys++> instance (Ord a, Show a) => Show (Set a) where+> showsPrec p set =+> showChar '{' . showElems (map shows (toListSet set)) . showChar '}'+> where showElems = flip (foldr ($)) . intersperse (showChar ',') -- $++> nullSet :: Ord a => Set a -> Bool+> nullSet = null . toListSet++> zeroSet :: Ord a => Set a+> zeroSet = Set zeroFM++> unitSet :: Ord a => a -> Set a+> unitSet x = Set (unitFM x ())++> addToSet :: Ord a => a -> Set a -> Set a+> addToSet x (Set xs) = Set (addToFM x () xs)++> deleteFromSet :: Ord a => a -> Set a -> Set a+> deleteFromSet x (Set xs) = Set (deleteFromFM x xs)++> elemSet :: Ord a => a -> Set a -> Bool+> elemSet x (Set xs) = isJust (lookupFM x xs)++> notElemSet :: Ord a => a -> Set a -> Bool+> notElemSet x set = not (elemSet x set)++> subsetSet :: Ord a => Set a -> Set a -> Bool+> subsetSet xs ys = all (`elemSet` ys) (toListSet xs)++> fromListSet :: Ord a => [a] -> Set a+> fromListSet = foldr addToSet zeroSet++> toListSet :: Ord a => Set a -> [a]+> toListSet (Set xs) = map fst (toListFM xs)++> unionSet :: Ord a => Set a -> Set a -> Set a+> unionSet xs ys = foldr addToSet xs (toListSet ys)++> unionSets :: Ord a => [Set a] -> Set a+> unionSets = foldr unionSet zeroSet++> intersectionSet :: Ord a => Set a -> Set a -> Set a+> intersectionSet xs ys =+> foldr addToSet zeroSet [y | y <- toListSet ys, y `elemSet` xs]++> diffSet :: Ord a => Set a -> Set a -> Set a+> diffSet xs ys = foldr deleteFromSet xs (toListSet ys)++> symDiffSet :: Ord a => Set a -> Set a -> Set a+> symDiffSet xs ys = unionSet (diffSet xs ys) (diffSet ys xs)++> mapSet :: (Ord a, Ord b) => (a -> b) -> Set a -> Set b+> mapSet f = fromListSet . map f . toListSet++> domainFM :: Ord a => FM a b -> Set a+> domainFM = Set . fmap (const ())++\end{verbatim}
+ src/ShowCurrySyntax.hs view
@@ -0,0 +1,493 @@+--- 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 ShowCurrySyntax ( showModule ) where++import Ident+import Position+import CurrySyntax++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 ")"+showsConstrDecl (ConOpDecl pos idents rtyp ident ltyp)+ = showsString "(ConOpDecl "+ . showsPosition pos . space+ . showsList showsIdent idents . space+ . showsTypeExpr rtyp . space+ . showsIdent ident . space+ . showsTypeExpr ltyp+ . 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 ")"++
+ src/Simplify.lhs view
@@ -0,0 +1,466 @@+% $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++> import Base+> import Combined+> import Env+> import SCC+> import Typing+++> type SimplifyState a = StateT ValueEnv (ReaderT EvalEnv (StateT Int Id)) a+> type InlineEnv = Env Ident Expression+> type SimplifyFlags = Bool+ +> flatFlag :: SimplifyFlags -> Bool+> flatFlag x = x++> simplify :: SimplifyFlags -> ValueEnv -> EvalEnv -> Module -> (Module,ValueEnv)+> simplify flags tyEnv evEnv m +> = runSt (callRt (callSt (simplifyModule flags m) tyEnv) evEnv) 1++> simplifyModule :: SimplifyFlags -> Module -> SimplifyState (Module,ValueEnv)+> simplifyModule flat (Module m es ds) =+> do+> ds' <- mapM (simplifyDecl flat m emptyEnv) ds+> tyEnv <- fetchSt+> 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 <- fetchSt+> evEnv <- liftSt envRt+> 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) _)+> | 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 (merge p f ts' vs') eqs'+> where n :: Int -- type signature necessary for nhc+> (n,vs',ts',e') = etaReduce 0 [] (reverse ts) e+> merge 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)+> (lookupEnv (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 <- fetchSt+> 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 <- fetchSt+> 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 = bindEnv v e env+> where canInline (Literal _) = True+> canInline (Constructor _) = True+> 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 (ast 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 = lookupEnv f evEnv++> freshIdent :: ModuleIdent -> (Int -> Ident) -> TypeScheme+> -> SimplifyState Ident+> freshIdent m f ty =+> do+> x <- liftM f (liftSt (liftRt (updateSt (1 +))))+> updateSt_ (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 view
@@ -0,0 +1,127 @@+% -*- LaTeX -*-+% $Id: Subst.lhs,v 1.7 2002/12/20 13:12:51 lux Exp $+%+% 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 Map++> data Subst a b = Subst Bool (FM a b) deriving Show++> idSubst :: Ord a => Subst a b+> idSubst = Subst False zeroFM++> substToList :: Ord v => Subst v e -> [(v,e)]+> substToList (Subst _ sigma) = toListFM sigma++> bindSubst :: Ord v => v -> e -> Subst v e -> Subst v e+> bindSubst v e (Subst comp sigma) = Subst comp (addToFM v e sigma)++> unbindSubst :: Ord v => v -> Subst v e -> Subst v e+> unbindSubst v (Subst comp sigma) = Subst comp (deleteFromFM 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' (lookupFM 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' (lookupFM 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 zeroFM)+> (filter ((`elem` vs) . fst) (toListFM sigma))++\end{verbatim}
+ src/SyntaxCheck.lhs view
@@ -0,0 +1,1183 @@++% $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 Control.Monad++> import Base+> import Env+> import NestEnv+> import Combined+> 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 linear (concatMap constrs tds) of+> --Linear -> tds ++ run (checkModule withExt m env vds)+> Linear -> map (checkTypeDecl withExt m) tds+> ++ run (checkModule withExt m env2 vds)+> NonLinear 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++> --syntaxCheckGoal :: Bool -> ValueEnv -> Goal -> Goal+> --syntaxCheckGoal withExt tyEnv g =+> -- run (checkGoal withExt (mkMIdent []) (globalEnv (fmap renameInfo tyEnv)) g)++\end{verbatim}+A global state transformer is used for generating fresh integer keys+by which the variables get renamed.+\begin{verbatim}++> type RenameState a = StateT Int Id a++> run :: RenameState a -> a+> run m = runSt m (globalKey + 1)++> newId :: RenameState Int+> newId = updateSt (1 +)++\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) = splitQualIdent 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) = splitQualIdent 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++> --checkGoal :: Bool -> ModuleIdent -> RenameEnv -> Goal -> RenameState Goal+> --checkGoal withExt m env (Goal p e ds) =+> -- do+> -- (env',ds') <- checkLocalDecls withExt m env ds+> -- e' <- checkExpr withExt p m env' e+> -- return (Goal p e' 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') = splitQualIdent 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 linear bvs of+> Linear ->+> case linear tys of+> Linear ->+> case linear evs of+> Linear ->+> case filter (`notElem` tys) fs' of+> [] -> liftM ((,) env') +> (mapM (checkDeclRhs withExt bvs m env'') ds)+> f : _ -> errorAt' (noTypeSig f)+> NonLinear v -> errorAt' (duplicateEvalAnnot v)+> NonLinear v -> errorAt' (duplicateTypeSig v)+> NonLinear 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 linear bvs of+> Linear -> (foldr bindVar env bvs,ts)+> NonLinear 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 patt) = head fs+> p' = positionOfIdent label+> 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 expr) = 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 expr) = 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 emptyEnv [] decls+> where+> sortFD env res [] = reverse res+> sortFD env res (decl:decls)+> = case decl of+> FunctionDecl _ ident _+> | isJust (lookupEnv ident env)+> -> sortFD env (insertBy cmpFuncDecl decl res) decls+> | otherwise+> -> sortFD (bindEnv 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++> getDeclPos :: Decl -> Position+> getDeclPos (ImportDecl pos _ _ _ _) = pos+> getDeclPos (InfixDecl pos _ _ _) = pos+> getDeclPos (DataDecl pos _ _ _) = pos+> getDeclPos (NewtypeDecl pos _ _ _) = pos+> getDeclPos (TypeDecl pos _ _ _) = pos+> getDeclPos (TypeSig pos _ _) = pos+> getDeclPos (EvalAnnot pos _ _) = pos+> getDeclPos (FunctionDecl pos _ _) = pos+> getDeclPos (ExternalDecl pos _ _ _ _) = pos+> getDeclPos (FlatExternalDecl pos _) = pos+> getDeclPos (PatternDecl pos _ _) = pos+> getDeclPos (ExtraVariables pos _) = pos++\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"++> --partialFuncPatt :: QualIdent -> Int -> Int -> String+> --partialFuncPatt f arity argc =+> -- "Function pattern " ++ qualName f ++ " expects at least " +> -- ++ arguments arity ++ " but is applied to " ++ show argc+> -- where arguments 0 = "no arguments"+> -- arguments 1 = "1 argument"+> -- arguments n = show n ++ " arguments"++> noExpressionStatement :: String+> noExpressionStatement =+> "Last statement in a do expression must be an expression"++> 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 view
@@ -0,0 +1,873 @@+module SyntaxColoring (Program,Code(..),TypeKind(..),ConstructorKind(..),+ IdentifierKind(..),FunctionKind(..),filename2program,+ code2string,getQualIdent, position2code,+ area2codes) where++import Debug.Trace++import Data.Maybe+import Data.List++import CurryLexer+import Position+import Frontend+import Ident+import CurrySyntax +import Data.Char hiding(Space)+import Message+import Control.Exception+import PathUtils (readModule)+++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++debug'' = False -- parseResults und codes++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 [Message] Code+ | CodeError [Message] 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 importpaths+--- @param filename +--- @return program+filename2program :: [String] -> String -> IO Program+filename2program paths filename=+ readModule filename >>= \ cont ->+ (catchError show (typingParse paths filename cont)) >>= \ typingParseResult ->+ (catchError show (fullParse paths filename cont)) >>= \ fullParseResult -> + (catchError show (return (parse filename cont))) >>= \ parseResult ->+ (catchError show (return (Frontend.lex filename cont))) >>= \ lexResult -> + return (genProgram cont (typingParseResult : fullParseResult : [parseResult]) lexResult) + ++ + +--- @param plaintext+--- @param list with parse-Results with descending quality e.g. [typingParse,fullParse,parse] +--- @param lex-Result+--- @return program+genProgram :: String -> [Result Module] -> Result [(Position,Token)] -> Program +genProgram _ parseResults (Result mess posNtokList) = + let messages = (prepareMessages + (concatMap getMessages parseResults ++ + mess))+ mergedMessages = (mergeMessages' (trace' ("Messages: " ++ show messages) messages) + posNtokList)+ (nameList,codes) = catIdentifiers parseResults in+ trace''' ("parseResults : " ++ show parseResults ++ "\n\nCodes: " ++ show codes ++ "\n\nToken: " ++ show mergedMessages)+ (tokenNcodes2codes+ nameList+ 1 + 1+ mergedMessages + codes) ++ +genProgram plainText parseResults (Failure messages) =+ trace' (unlines (map (\(Message _ _ str) -> str) allMessages)) + (buildMessagesIntoPlainText allMessages plainText) + where+ allMessages = prepareMessages (concatMap getMessages parseResults ++ + messages) + ++ +--- @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+ ++--- 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 +catchError :: (Result a -> String) -> IO (Result a) -> IO (Result a)+catchError toString toDo = Control.Exception.catch (toDo >>= returnComplete toString) handler + where + handler (ErrorCall str) = return (Failure [setMessagePosition (Message Error Nothing str)])+ handler e = return (Failure [Message Error Nothing (show e)]) + + returnComplete :: (a -> String) -> a -> IO a+ returnComplete toString a = f (toString a) (return a)+ where+ f [] r = r+ f (_:xs) r = f xs r + +--- @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 + + +-- privates-----------------------------------------------------------------------------------++ +codeWithoutPos :: (Int,Int,Code) -> Code+codeWithoutPos (_,_,c) = c + +-- DEBUGGING----------- wird bald nicht mehr gebraucht++setMessagePosition :: Message -> Message+setMessagePosition m@(Message _ (Just p) _) = trace'' ("pos:" ++ show p ++ ":" ++ show m) m+setMessagePosition (Message typ _ m) = + let mes@(Message _ pos _) = (Message typ (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,ast=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 (CodeError _ code) = code+flatCode code = code+ ++ +-- ----------Message--------------------------------------- + ++getMessages :: Result a -> [Message]+getMessages (Result mess _) = mess+getMessages (Failure mess) = mess++lessMessage :: Message -> Message -> Bool+lessMessage (Message _ mPos1 _) (Message _ mPos2 _) = mPos1 < mPos2++nubMessages :: [Message] -> [Message] +nubMessages = nubBy eqMessage++eqMessage :: Message -> Message -> Bool+eqMessage (Message f1 p1 s1) (Message f2 p2 s2) = (f1 == f2) && (p1 == p2) && (s1 == s2)++prepareMessages :: [Message] -> [Message] +prepareMessages = qsort lessMessage . map setMessagePosition . nubMessages++hasError [] = False+hasError ((Message Error _ _):ms) = True+hasError (_:ms) = hasError ms++buildMessagesIntoPlainText :: [Message] -> String -> Program+buildMessagesIntoPlainText messages text = + buildMessagesIntoPlainText' messages (lines text) [] 1+ where+ buildMessagesIntoPlainText' :: [Message] -> [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)) : + (if hasError pre then (ln,1,CodeError pre (NotParsed str)) : [(ln,1,NewLine)] + else (ln,1,CodeWarning pre (NotParsed str)) : [(ln,1,NewLine)]) +++ (buildMessagesIntoPlainText' post preStrs [] (ln + 1)) + where + isLeq (Message _ (Just p) _) = line p <= ln + isLeq _ = True+ + + ++ +--- @param parse-Modules [typingParse,fullParse,parse] +catIdentifiers :: [Result Module] -> ([(ModuleIdent,ModuleIdent)],[Code])+catIdentifiers [] = ([],[])+catIdentifiers [(Failure _)] = ([],[])+catIdentifiers [(Result _ m@(Module moduleIdent maybeExportSpec decls))] =+ catIdentifiers' m Nothing+catIdentifiers ((Failure _):y:ys) = + catIdentifiers (y:ys) +catIdentifiers rs@((Result _ m@(Module _ _ _)):y:ys) = + catIdentifiers' (getLastModule (reverse rs)) (Just m)+ where+ getLastModule ((Failure _):xs) = getLastModule xs+ getLastModule ((Result _ m@(Module _ _ _)):_) = m+ +--- @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 qualIdents (CodeError mess code) =+ (CodeError mess (idOccur2functionCall qualIdents code)) +idOccur2functionCall _ code = code+ ++addModuleIdent :: ModuleIdent -> Code -> Code+addModuleIdent moduleIdent (Function x qualIdent) + | uniqueId (unqualify qualIdent) == 0 =+ (Function x (qualQualify moduleIdent qualIdent))+ | otherwise = (Function x qualIdent) +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 moduleIdent (CodeError mess code) =+ (CodeError mess (addModuleIdent moduleIdent code)) +addModuleIdent _ c = c+ +-- ----------------------------------------++mergeMessages :: [Message] -> [(Position,Token)] -> [([Message],Position,Token)]+mergeMessages mess pos = mergeMessages' (prepareMessages mess) pos++++mergeMessages' :: [Message] -> [(Position,Token)] -> [([Message],Position,Token)]+mergeMessages' _ [] = []+mergeMessages' [] ((p,t):ps) = ([],p,t) : mergeMessages' [] ps+mergeMessages' mss@(m@(Message _ 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 -> [([Message],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 $ maybe mid id (lookup mid nameList)++ addMessage [] = []+ addMessage ((l,c,code):cs)+ | null messages = ((l,c,code):cs)+ | hasError messages = + trace' ("Error bei code: " ++ show codes ++ ":" ++ show messages) + ((l,c,CodeError messages code): addMessage 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 (splitQualIdent qualIdent))+ Identifier x qualIdent -> Identifier x (rename qualIdent (splitQualIdent qualIdent))+ _ -> c+ where+ rename x (Nothing,_) = x+ rename x (Just m,i) = maybe x (\ m' -> qualifyWith m' i) (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) = fst $ splitQualIdent qualIdent+getModuleIdent (Function _ qualIdent) = fst $ splitQualIdent qualIdent+getModuleIdent (ModuleName moduleIdent) = Just moduleIdent+getModuleIdent (Identifier _ qualIdent) = fst $ splitQualIdent qualIdent +getModuleIdent (TypeConstructor _ qualIdent) = fst $ splitQualIdent 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 decl1 decl2 = getPosition decl1 < getPosition decl2++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])) ++basename = reverse . takeWhile (/='/') . reverse++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 = reverse . tail . reverse . tail . show
+ src/TopEnv.lhs view
@@ -0,0 +1,146 @@++% $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 Env+> import Ident+> import Utils++> 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 (Env QualIdent [(Source,a)]) deriving Show++> instance Functor TopEnv where+> fmap f (TopEnv env) = TopEnv (fmap (map (apSnd f)) env)++> entities :: QualIdent -> Env QualIdent [(Source,a)] -> [(Source,a)]+> entities x env = fromMaybe [] (lookupEnv x env)++> emptyTopEnv :: TopEnv a+> emptyTopEnv = TopEnv emptyEnv++> predefTopEnv :: Entity a => QualIdent -> a -> TopEnv a -> TopEnv a+> predefTopEnv x y (TopEnv env) =+> case lookupEnv x env of+> Just _ -> error "internal error: predefTopEnv"+> Nothing -> TopEnv (bindEnv x [(Import [],y)] env)++> importTopEnv :: Entity a => ModuleIdent -> Ident -> a -> TopEnv a -> TopEnv a+> importTopEnv m x y (TopEnv env) =+> TopEnv (bindEnv 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 (bindEnv 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 (bindEnv 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 (bindEnv 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 (bindEnv 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) <- envToList env, (Import _,y) <- ys]++> unqualBindings :: TopEnv a -> [(Ident,(Source,a))]+> unqualBindings (TopEnv env) =+> [(x',y) | (x,ys) <- takeWhile (not . isQualified . fst) (envToList 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/TypeCheck.lhs view
@@ -0,0 +1,1346 @@++% $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,typeCheckGoal) where++> import Control.Monad+> import Data.List+> import Data.Maybe++> import Base+> import Pretty+> import Ident+> import CurryPP+> import Env+> import TopEnv+> import Set+> import Combined+> 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' emptyEnv vds >>+> liftSt fetchSt >>= \theta -> fetchSt >>= \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}+Type checking of a goal expression is simpler because the type+constructor environment is fixed already and there are no+type declarations in a goal.+\begin{verbatim}++> typeCheckGoal :: TCEnv -> ValueEnv -> Goal -> ValueEnv+> typeCheckGoal tcEnv tyEnv (Goal p e ds) =+> run (tcRhs m0 tcEnv tyEnv emptyEnv (SimpleRhs p e ds) >>+> liftSt fetchSt >>= \theta -> fetchSt >>= \tyEnv' ->+> return (subst theta tyEnv')) tyEnv+> where m0 = mkMIdent []++\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 = StateT ValueEnv (StateT TypeSubst (StateT Int Id)) a++> run :: TcState a -> ValueEnv -> a+> run m tyEnv = runSt (callSt (callSt 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 = Env Ident TypeExpr++> bindTypeSig :: Ident -> TypeExpr -> SigEnv -> SigEnv+> bindTypeSig = bindEnv++> 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 = lookupEnv++> 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', tvs') = nameTypes tys tvs+> (rty', tvs'') = 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 <- fetchSt+> tysLhs <- mapM (tcDeclLhs m tcEnv sigs) ds+> tysRhs <- mapM (tcDeclRhs m tcEnv tyEnv0 sigs) ds+> sequence_ (zipWith3 (unifyDecl m) ds tysLhs tysRhs)+> theta <- liftSt fetchSt+> 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 =+> -- updateSt_ (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 =+> updateSt_ (bindFun m f (expandPolyType m tcEnv ty))++> tcFlatExternalFunct :: ModuleIdent -> TCEnv -> SigEnv -> Ident -> TcState ()+> tcFlatExternalFunct m tcEnv sigs f =+> typeOf f tcEnv sigs >>= updateSt_ . 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 >>= updateSt_ . 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 Int -> TypeSubst -> Decl+> -> TcState ()+> genDecl m tcEnv sigs lvs theta (FunctionDecl _ f _) =+> updateSt_ (genVar True m tcEnv sigs lvs theta f)+> genDecl m tcEnv sigs lvs theta (PatternDecl p t _) =+> mapM_ (updateSt_ . genVar False m tcEnv sigs lvs theta ) (bv t)++> genVar :: Bool -> ModuleIdent -> TCEnv -> SigEnv -> 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]+> updateSt_ (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+> updateSt_ (bindFun m v (monoType ty))+> return ty+> +> tcConstrTerm m tcEnv sigs p t@(ConstructorPattern c ts) =+> do+> tyEnv <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> ty' <- maybe (updateSt_ (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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> let p = positionOfIdent l+> lty <- maybe (freshTypeVar+> >>= (\lty' ->+> updateSt_+> (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 -> fetchSt >>= inst . funType m v+> tcExpr m tcEnv sigs p (Constructor c) = fetchSt >>= instExist . constrType m c+> tcExpr m tcEnv sigs p (Typed e sig) =+> do+> tyEnv0 <- fetchSt+> ty <- tcExpr m tcEnv sigs p e+> inst sigma' >>=+> flip (unify p "explicitly typed expression" (ppExpr 0 e) m) ty+> theta <- liftSt fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> theta <- liftSt fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> 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 <- fetchSt+> lty <- maybe (freshTypeVar +> >>= (\lty' -> +> updateSt_ +> (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 <- fetchSt+> let p = positionOfIdent l+> lty <- maybe (freshTypeVar +> >>= (\lty' -> +> updateSt_ +> (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 <- liftSt fetchSt+> unaryArrow (subst theta ty)+> where unaryArrow (TypeArrow ty1 ty2) = return (ty1,ty2)+> unaryArrow (TypeVariable tv) =+> do+> alpha <- freshTypeVar+> beta <- freshTypeVar+> liftSt (updateSt_ (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+> liftSt (updateSt_ (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 =+> liftSt $ {-$-}+> do+> theta <- fetchSt+> let ty1' = subst theta ty1+> let ty2' = subst theta ty2+> either (errorAt p . typeMismatch what doc m ty1' ty2')+> (updateSt_ . 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 <- liftSt fetchSt+> let ty' = subst theta ty+> fs = fsEnv (subst theta tyEnv)+> unless (all (`elemSet` 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 (liftSt (liftSt (updateSt (1 +))))++> 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 Int -> Type -> TypeScheme+> gen gvs ty =+> ForAll (length tvs) (subst (foldr2 bindSubst idSubst tvs tvs') ty)+> where tvs = [tv | tv <- nub (typeVars ty), tv `notElemSet` 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)++> sureFunType :: ModuleIdent -> QualIdent -> ValueEnv -> Maybe TypeScheme+> sureFunType m f tyEnv =+> case (qualLookupValue f tyEnv) of+> [Value _ sigma] -> Just sigma+> vs -> case (qualLookupValue (qualQualify m f) tyEnv) of+> [Value _ sigma] -> Just sigma+> _ -> Nothing++> labelType :: Ident -> ValueEnv -> TypeScheme+> labelType l tyEnv =+> case lookupValue l tyEnv of+> Label _ _ sigma : _ -> sigma+> _ -> internalError ("labelType " ++ show l)++> 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 Int+> fvEnv tyEnv =+> fromListSet [tv | ty <- localTypes tyEnv, tv <- typeVars ty, tv < 0]++> fsEnv :: ValueEnv -> Set Int+> fsEnv tyEnv = unionSets (map (fromListSet . 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]++> invalidCType :: String -> ModuleIdent -> Type -> String+> invalidCType what m ty = show $+> vcat [text ("Invalid " ++ what ++ " type in foreign declaration"),+> 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}
+ src/TypeSubst.lhs view
@@ -0,0 +1,102 @@++% $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 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 view
@@ -0,0 +1,217 @@+% $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 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 (Eq,Show)++\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 (Eq,Show)+> data ExistTypeScheme = ForAllExist Int Int Type deriving (Eq,Show)++\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}
+ src/Typing.lhs view
@@ -0,0 +1,401 @@++% $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 Base+> import TypeSubst+> import Combined+> 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 = StateT TypeSubst (StateT Int Id) a++> run :: TyState a -> ValueEnv -> a+> run m tyEnv = runSt (callSt 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 <- fetchSt+> 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 $ liftSt $ updateSt (1 +)++> 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 =+> updateSt_ (\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 <- fetchSt+> case subst theta ty of+> TypeVariable tv+> | tv >= 0 ->+> do+> ty1 <- freshTypeVar+> ty2 <- freshTypeVar+> updateSt_ (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/Unlit.lhs view
@@ -0,0 +1,110 @@+% -*- LaTeX -*-+% $Id: Unlit.lhs,v 1.2 2002/10/01 06:55:50 lux Exp $+%+% $Log: Unlit.lhs,v $+% Revision 1.2 2002/10/01 06:55:50 lux+% unlit returns an error message to the caller instead of calling error.+%+% Revision 1.1 2000/02/07 14:05:55 lux+% The compiler now supports literate source files. Literate source files+% must end with the suffix ".lcurry".+%+%+\nwfilename{Unlit.lhs}+\section{Literate comments}+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.++The module \texttt{Unlit} acts as a preprocessor which converts+literate source programs into the ``un-literate'' format accepted by+the lexer. The implementation, together with the comments below, was+derived from appendix D in the Haskell 1.2 report.+\begin{verbatim}++> module Unlit(unlit) where+> import Data.Char+> import Position++\end{verbatim}+Each of the lines in a literate script is a program line, a blank+line, or a comment line. In the first case the text is kept with the+line.+\begin{verbatim}++> data Classified = Program String | Blank | Comment++\end{verbatim}+In a literate program, program lines begin with a \verb|>| character,+blank lines contain only whitespace, and all other lines are comment+lines.+\begin{verbatim}++> classify :: String -> Classified+> classify "" = Blank+> classify (c:cs)+> | c == '>' = Program cs+> | all isSpace (c:cs) = Blank+> | otherwise = Comment++\end{verbatim}+In the corresponding program, program lines have the leading \verb|>|+replaced by a leading space, to preserve tab alignments.+\begin{verbatim}++> unclassify :: Classified -> String+> unclassify (Program cs) = ' ' : cs+> unclassify Blank = ""+> unclassify Comment = ""++\end{verbatim}+Process a literate program into error messages (if any) and the+corresponding non-literate program.+\begin{verbatim}++> unlit :: FilePath -> String -> (String,String)+> unlit fn lcy = (es,cy)+> where cs = map classify (lines lcy)+> es = unlines (errors fn cs)+> cy = unlines (map unclassify cs)++\end{verbatim}+Check that each program line is not adjacent to a comment line and+there is at least one program line.+\begin{verbatim}++> errors :: FilePath -> [Classified] -> [String]+> errors fn cs =+> concat (zipWith3 adjacent (iterate nl (first fn)) cs (tail cs)) +++> empty fn (filter isProgram cs)++\end{verbatim}+Given a line number and a pair of adjacent lines, generate a list of+error messages, which will contain either one entry or none.+\begin{verbatim}++> adjacent :: Position -> Classified -> Classified -> [String]+> adjacent p (Program _) Comment = [message (nl p) "after"]+> adjacent p Comment (Program _) = [message p "before"]+> adjacent p _ _ = []++> message p w = show p ++ ": comment line " ++ w ++ " program line."++\end{verbatim}+Given the list of program lines generate an error if this list is+empty.+\begin{verbatim}++> empty :: FilePath -> [Classified] -> [String]+> empty fn [] = [show (first fn) ++ ": no code in literate script"]+> empty fn _ = []++> isProgram :: Classified -> Bool+> isProgram (Program _) = True+> isProgram _ = False++\end{verbatim}
+ src/Utils.lhs view
@@ -0,0 +1,101 @@+% -*- LaTeX -*-+% $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{Pairs}+The functions \texttt{apFst} and \texttt{apSnd} apply a function to+the first and second components of a pair, resp.+\begin{verbatim}++> apFst f (x,y) = (f x,y)+> apSnd f (x,y) = (x,f y)++\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 f z [] = z+> foldl_strict f z (x:xs) = let z' = f z x in z' `seq` foldl_strict f z' xs++\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 view
@@ -0,0 +1,910 @@+-------------------------------------------------------------------------------+--+-- 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+import Data.List++import CurrySyntax+import Ident+import Position+import Base (ValueEnv, ValueInfo(..), qualLookupValue, lookupValue)+import TopEnv+import qualified ScopeEnv+import ScopeEnv (ScopeEnv)+import Message+import Env+++++-------------------------------------------------------------------------------++-- 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] -> [Message]+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++--+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 "") emptyEnv 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 (bindEnv ident pos env) decls)+ (\pos' -> genWarning' (rulesNotTogether ident pos')+ >> checkDO ident env decls)+ (lookupEnv 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 emptyEnv imps+ where+ checkImps env [] = return ()+ checkImps env ((ImportDecl pos mid _ _ spec):imps)+ | mid /= preludeMIdent+ = maybe (checkImps (bindEnv mid (fromImpSpec spec) env) imps)+ (\ishs -> checkImpSpec env pos mid ishs spec+ >>= (\env' -> checkImps env' imps))+ (lookupEnv 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 (bindEnv mid (is',hs) env)+ | null iis+ = return (bindEnv mid (is' ++ is,hs) env)+ | otherwise+ = do foldM' genWarning'+ (map ((multiplyImportedSymbol mid) . impName) iis)+ return (bindEnv 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 (bindEnv mid (is,hs' ++ hs) env)+ | otherwise+ = do foldM' genWarning' + (map ((multiplyHiddenSymbol mid) . impName) ihs)+ return (bindEnv 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+++-- 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.+data CheckState a = CheckState (CState () -> CState a)++data CState a = CState {messages :: [Message],+ scope :: ScopeEnv QualIdent IdInfo,+ values :: ValueEnv,+ moduleId :: ModuleIdent,+ result :: a+ }++--+emptyState :: CState ()+emptyState = CState {messages = [],+ scope = ScopeEnv.new,+ values = emptyTopEnv,+ moduleId = mkMIdent [],+ result = ()+ }++--+modifyScope :: (ScopeEnv QualIdent IdInfo -> ScopeEnv QualIdent IdInfo)+ -> CState a -> CState a+modifyScope f state = state{ scope = f (scope state) }+++-- 'CheckState' is declared as an instance of 'Monad' to use its actions+-- in 'do' expressions+instance Monad CheckState where++ -- (>>=) :: CheckState a -> (a -> CheckState b) -> CheckState b+ (CheckState f) >>= g + = CheckState (\state -> let state' = f state+ CheckState h = g (result state')+ in h (state'{ result = () }))++ -- (>>) :: CheckState a -> CheckState b -> CheckState b+ a >> b = a >>= (\_ -> b)++ -- return :: a -> CheckState a+ return val = CheckState (\state -> state{ result = val })+++--+genWarning :: Position -> (WarningType,String) -> CheckState ()+genWarning pos (warnType,msg)+ = CheckState (\state -> state{ messages = warnMsg:(messages state) })+ where warnMsg = message (Warning warnType) pos msg+ +genWarning' :: (Position,WarningType,String) -> CheckState ()+genWarning' (pos,warnType,msg)+ = CheckState (\state -> state{ messages = warnMsg:(messages state) })+ where warnMsg = message (Warning warnType) pos msg ++--+insertVar :: Ident -> CheckState ()+insertVar id + | isAnnonId id = return ()+ | otherwise+ = CheckState + (\state -> modifyScope + (ScopeEnv.insert (commonId id) (VarInfo False)) state)++--+insertTypeVar :: Ident -> CheckState ()+insertTypeVar id+ | isAnnonId id = return ()+ | otherwise + = CheckState + (\state -> modifyScope + (ScopeEnv.insert (typeId id) (VarInfo False)) state)++--+insertConsId :: Ident -> CheckState ()+insertConsId id+ = CheckState + (\state -> modifyScope (ScopeEnv.insert (commonId id) ConsInfo) state)++--+insertTypeConsId :: Ident -> CheckState ()+insertTypeConsId id+ = CheckState + (\state -> modifyScope (ScopeEnv.insert (typeId id) ConsInfo) state)++--+isVarId :: Ident -> CheckState Bool+isVarId id+ = CheckState (\state -> state{ result = isVar state (commonId id) })++--+isConsId :: Ident -> CheckState Bool+isConsId id + = CheckState (\state -> state{ result = isCons state (qualify id) })++--+isQualConsId :: QualIdent -> CheckState Bool+isQualConsId qid+ = CheckState (\state -> state{ result = isCons state qid })++--+isShadowingVar :: Ident -> CheckState Bool+isShadowingVar id + = CheckState + (\state -> state{ result = isShadowing state (commonId id) })++--+isShadowingTypeVar :: Ident -> CheckState Bool+isShadowingTypeVar id+ = CheckState + (\state -> state{ result = isShadowing state (typeId id) })++--+visitId :: Ident -> CheckState ()+visitId id + = CheckState + (\state -> modifyScope + (ScopeEnv.modify visitVariable (commonId id)) state)++--+visitTypeId :: Ident -> CheckState ()+visitTypeId id + = CheckState + (\state -> modifyScope + (ScopeEnv.modify visitVariable (typeId id)) state)++--+isUnrefVar :: Ident -> CheckState Bool+isUnrefVar id + = CheckState (\state -> state{ result = isUnref state (commonId id) })++--+isUnrefTypeVar :: Ident -> CheckState Bool+isUnrefTypeVar id+ = CheckState (\state -> state{ result = isUnref state (typeId id) })++--+returnUnrefVars :: CheckState [Ident]+returnUnrefVars + = CheckState (\state -> + let ids = map fst (ScopeEnv.toLevelList (scope state))+ unrefs = filter (isUnref state) ids+ in state{ result = map unqualify unrefs })++--+addModuleId :: ModuleIdent -> CheckState ()+addModuleId mid = CheckState (\state -> state{ moduleId = mid })++--+returnModuleId :: CheckState ModuleIdent+returnModuleId = CheckState (\state -> state{ result = moduleId state })++--+beginScope :: CheckState ()+beginScope = CheckState (\state -> modifyScope ScopeEnv.beginScope state)++--+endScope :: CheckState ()+endScope = CheckState (\state -> modifyScope ScopeEnv.endScopeUp state)+++-- Adds the content of a value environment to the state+addImportedValues :: ValueEnv -> CheckState ()+addImportedValues vals = CheckState (\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+++-- Runs a 'CheckState' action and returns the list of messages+run :: CheckState a -> [Message]+run (CheckState f)+ = reverse (messages (f emptyState))+++-------------------------------------------------------------------------------++--+isShadowing :: CState a -> 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 a -> 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 a -> QualIdent -> Bool+isVar state qid = maybe (isAnnonId (unqualify qid)) + isVariable + (ScopeEnv.lookup qid (scope state))++--+isCons :: CState a -> 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,WarningType,String)+unrefTypeVar id = + (positionOfIdent id,+ UnrefTypeVar,+ "unreferenced type variable \"" ++ show id ++ "\"")++unrefVar :: Ident -> (Position,WarningType,String)+unrefVar id = + (positionOfIdent id,+ UnrefVar,+ "unreferenced variable \"" ++ show id ++ "\"")++shadowingVar :: Ident -> (Position,WarningType,String)+shadowingVar id = + (positionOfIdent id,+ ShadowingVar,+ "shadowing symbol \"" ++ show id ++ "\"")++idleCaseAlts :: (WarningType,String)+idleCaseAlts = (IdleCaseAlt,"idle case alternative(s)")++overlappingCaseAlt :: (WarningType,String)+overlappingCaseAlt = (OverlapCase,"redundant overlapping case alternative")++rulesNotTogether :: Ident -> Position -> (Position,WarningType,String)+rulesNotTogether id pos+ = (positionOfIdent id,+ RulesNotTogether,+ "rules for function \"" ++ show id ++ "\" " + ++ "are not together "+ ++ "(first occurrence at " + ++ show (line pos) ++ "." ++ show (column pos) ++ ")")++multiplyImportedModule :: ModuleIdent -> (Position,WarningType,String)+multiplyImportedModule mid + = (positionOfModuleIdent mid,+ MultipleImportModule,+ "module \"" ++ show mid ++ "\" was imported more than once")++multiplyImportedSymbol :: ModuleIdent -> Ident -> (Position,WarningType,String)+multiplyImportedSymbol mid ident+ = (positionOfIdent ident,+ MultipleImportSymbol,+ "symbol \"" ++ show ident ++ "\" was imported from module \""+ ++ show mid ++ "\" more than once")++multiplyHiddenSymbol :: ModuleIdent -> Ident -> (Position,WarningType,String)+multiplyHiddenSymbol mid ident+ = (positionOfIdent ident,+ MultipleHiding,+ "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++head_ :: a -> [a] -> a+head_ alt [] = alt+head_ _ (x:_) = x++--+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 view
@@ -0,0 +1,34 @@+/* 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
@@ -0,0 +1,110 @@+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+--+-- 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 Main(main) where++import Data.List+import Data.Maybe+import System.IO+import System.Environment+import System.Exit+import Control.Monad (unless)+import Data.Char (isDigit)++import GetOpt+import CurryBuilder+import CurryCompilerOpts+import CurryHtml++-------------------------------------------------------------------------------++-- The command line tool.+main :: IO ()+main = do prog <- getProgName+ args <- getArgs+ cymake prog args +++-------------------------------------------------------------------------------++-- Checks the command line arguments and invokes the 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 1.1." + ++ filter isDigit "$Revision: 3620 $")+ 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+++-- Prints 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 mapM (\err -> putErrLn (prog ++ ": " ++ err)) errs+ abortWith ["Try '" ++ prog ++ " -" ++ "-help' for more information"]+++-- Checks options and files.+check :: Options -> [String] -> [String]+check opts files+ | null files + = ["no files"]+ | isJust (output opts) && length files > 1+ = ["cannot specify -o with multiple targets"]+ | otherwise+ = []+++-------------------------------------------------------------------------------+-- Error handling++-- Prints an error message on 'stderr'+putErrLn :: String -> IO ()+putErrLn = hPutStrLn stderr++-- Prints a list of error messages on 'stderr'+putErrsLn :: [String] -> IO ()+putErrsLn = mapM_ putErrLn++-- Prints a list of error messages on 'stderr' and aborts the program+abortWith :: [String] -> IO a+abortWith errs = putErrsLn errs >> exitWith (ExitFailure 1)+++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------