------------------------------------------------------------------------------
--- 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 with extension .acy
---
--- @author Michael Hanus
--- @version July 2008
------------------------------------------------------------------------------
module AbstractCurry where
import Directory(doesFileExist)
import ReadShowTerm
import Distribution
import FileGoodies(stripSuffix)
------------------------------------------------------------------------------
-- 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
---
--- (CProg modname imports typedecls functions opdecls)
---
--- 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]
--- 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)
-- Data type to specify the visibility of various entities.
data CVisibility = Public -- exported entity
| Private -- private entity
--- 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.
---
--- 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.
---
data CTypeDecl = CType QName CVisibility [CTVarIName] [CConsDecl]
| CTypeSyn QName CVisibility [CTVarIName] CTypeExpr
--- 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]
--- 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
-- (CTCons (module,name) arguments)
--- 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 Int
data CFixity = CInfixOp -- non-associative infix operator
| CInfixlOp -- left-associative infix operator
| CInfixrOp -- right-associative infix operator
--- 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.
---
--- A function declaration in AbstractCurry is a term of the form
---
--- (CFunc name arity visibility type (CRules eval [CRule rule1,...,rulek]))
---
--- and represents the function name
defined by the rules
--- 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.
---
--- A function declaration with the constructor CmtFunc
--- is similarly to CFunc
but has a comment
--- as an additional first argument. This comment could be used
--- by pretty printers that generate a readable Curry program
--- containing documentation comments.
data CFuncDecl = CFunc QName Int CVisibility CTypeExpr CRules
| CmtFunc String QName Int CVisibility CTypeExpr CRules
--- 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
--- Data type for classifying evaluation annotations for functions.
--- They can be either flexible (default), rigid, or choice.
data CEvalAnnot = CFlex | CRigid | CChoice
--- 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]
--- 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
--- 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
--- 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
--- 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)
--- Data type for representing branches in case expressions.
data CBranchExpr = CBranch CPattern CExpr
--- Data type for representing literals occurring in an expression.
--- It is either an integer, a float, or a character constant.
data CLiteral = CIntc Int
| CFloatc Float
| CCharc Char
------------------------------------------------------------------------------
--- I/O action which parses a Curry program and returns the corresponding
--- typed Abstract Curry program.
--- Thus, the argument is the file name without suffix ".curry"
--- or ".lcurry") and the result is a Curry term representing this
--- program.
readCurry :: String -> IO CurryProg
readCurry prog = readCurryWithParseOptions prog (setQuiet True defaultParams)
--- I/O action which parses a Curry program and returns the corresponding
--- untyped Abstract Curry program.
--- Thus, the argument is the file name without suffix ".curry"
--- or ".lcurry") and the result is a Curry term representing this
--- program.
readUntypedCurry :: String -> IO CurryProg
readUntypedCurry prog =
readUntypedCurryWithParseOptions prog (setQuiet True defaultParams)
--- I/O action which reads a typed Curry program from a file (with extension
--- ".acy") with respect to some parser options.
--- This I/O action is used by the standard action readCurry
.
--- It is currently predefined only in Curry2Prolog.
--- @param progfile - the program file name (without suffix ".curry")
--- @param options - parameters passed to the front end
readCurryWithParseOptions :: String -> FrontendParams -> IO CurryProg
readCurryWithParseOptions progname options = do
existsCurry <- doesFileExist (progname++".curry")
existsLCurry <- doesFileExist (progname++".lcurry")
if existsCurry || existsLCurry
then callFrontendWithParams ACY options progname
else done
filename <- findFileInLoadPath (progname++".acy")
readAbstractCurryFile filename
--- I/O action which reads an untyped Curry program from a file (with extension
--- ".uacy") with respect to some parser options. For more details
--- see function 'readCurryWithParseOptions'
readUntypedCurryWithParseOptions :: String -> FrontendParams -> IO CurryProg
readUntypedCurryWithParseOptions progname options = do
existsCurry <- doesFileExist (progname++".curry")
existsLCurry <- doesFileExist (progname++".lcurry")
if existsCurry || existsLCurry
then callFrontendWithParams UACY options progname
else done
filename <- findFileInLoadPath (progname++".uacy")
readAbstractCurryFile filename
--- Transforms a name of a Curry program (with or without suffix ".curry"
--- or ".lcurry") into the name of the file containing the
--- corresponding AbstractCurry program.
abstractCurryFileName :: String -> String
abstractCurryFileName prog = inCurrySubdir (stripSuffix prog ++ ".acy")
--- Transforms a name of a Curry program (with or without suffix ".curry"
--- or ".lcurry") into the name of the file containing the
--- corresponding untyped AbstractCurry program.
untypedAbstractCurryFileName :: String -> String
untypedAbstractCurryFileName prog = inCurrySubdir (stripSuffix prog ++ ".uacy")
--- I/O action which reads an AbstractCurry program from a file in ".acy"
--- format. In contrast to readCurry
, this action does not parse
--- a source program. Thus, the argument must be the name of an existing
--- file (with suffix ".acy") containing an AbstractCurry program in ".acy"
--- format and the result is a Curry term representing this program.
--- It is currently predefined only in Curry2Prolog.
readAbstractCurryFile :: String -> IO CurryProg
readAbstractCurryFile filename = do
exacy <- doesFileExist filename
if exacy
then readExistingACY filename
else do let subdirfilename = inCurrySubdir filename
exdiracy <- doesFileExist subdirfilename
if exdiracy
then readExistingACY subdirfilename
else error ("EXISTENCE ERROR: AbstractCurry file '"++filename++
"' does not exist")
where
readExistingACY fname = do
filecontents <- readFile fname
return (readUnqualifiedTerm ["AbstractCurry","Prelude"] filecontents)
--- Writes an AbstractCurry program into a file in ".acy" format.
--- The first argument must be the name of the target file
--- (with suffix ".acy").
writeAbstractCurryFile :: String -> CurryProg -> IO ()
writeAbstractCurryFile file prog = writeFile file (showTerm prog)
------------------------------------------------------------------------------