KiCS-0.8.9: src/lib/Curry/Module/FlatCurry.curry
------------------------------------------------------------------------------
--- Library to support meta-programming in Curry.
---
--- This library contains a definition for representing FlatCurry programs
--- in Curry (type "Prog") and an I/O action to read Curry programs and
--- transform them into this representation (function "readFlatCurry").
---
--- @author Michael Hanus
--- @version August 2005
------------------------------------------------------------------------------
module FlatCurry where
import Directory(doesFileExist)
import ReadShowTerm
import Distribution
import FileGoodies(stripSuffix)
------------------------------------------------------------------------------
-- 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]
--- 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.
type QName = (String,String)
--- Data type to specify the visibility of various entities.
data Visibility = Public -- public (exported) entity
| Private -- private entity
--- 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.
---
--- A data type definition of the form
---
--- <code>data t x1...xn = ...| c t1....tkc |...</code>
---
--- is represented by the FlatCurry term
---
--- <code>(Type t [i1,...,in] [...(Cons c kc [t1,...,tkc])...])</code>
---
--- where each <code>ij</code> is the index of the type variable
--- <code>xj</code>.
---
--- 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 TypeDecl = Type QName Visibility [TVarIndex] [ConsDecl]
| TypeSyn QName Visibility [TVarIndex] TypeExpr
--- 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]
--- 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
-- 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).
data OpDecl = Op QName Fixity Int
--- Data types for the different choices for the fixity of an operator.
data Fixity = InfixOp | InfixlOp | InfixrOp
--- Data type for representing object variables.
--- Object variables occurring in expressions are represented by (Var i)
--- where i is a variable index.
type VarIndex = Int
--- Data type for representing function declarations.
---
--- A function declaration in FlatCurry is a term of the form
---
--- <code>(Func name arity type (Rule [i_1,...,i_arity] e))</code>
---
--- and represents the function "name" with definition
---
--- <code>name :: type</code><br/>
--- <code>name x_1...x_arity = e</code>
---
--- where each <code>i_j</code> is the index of the variable <code>x_j</code>.
---
--- Note: the variable indices are unique inside each function declaration
--- and are usually numbered from 0
---
--- External functions are represented as
--- <code>(Func name arity type (External s))</code>
--- where s is the external name associated to this function.
---
--- Thus, a function declaration consists of the name, arity, type, and rule.
data FuncDecl = Func QName Int Visibility TypeExpr Rule
--- A rule is either a list of formal parameters together with an expression
--- or an "External" tag.
data Rule = Rule [VarIndex] Expr
| External String
--- Data type for classifying case expressions.
--- Case expressions can be either flexible or rigid in Curry.
data CaseType = Rigid | Flex -- type of a case expression
--- Data type for classifying combinations
--- (i.e., a function/constructor applied to some arguments).
--- @cons FuncCall - a call to a function where 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 (i.e., not all arguments
--- are provided) where the parameter is the number of
--- missing arguments
data CombType = FuncCall | ConsCall | FuncPartCall Int | ConsPartCall Int
--- Data type for representing expressions.
---
--- Remarks:
---
--- <ol>
--- <li> if-then-else expressions are represented as function calls:
---
--- <code>(if e1 then e2 else e3)</code>
---
--- is represented as
---
--- <code>(Comb FuncCall ("Prelude","if_then_else") [e1,e2,e3])</code>
--- </li>
--- <li>
--- Higher-order applications are represented as calls to the (external)
--- function "apply". For instance, the rule
---
--- <code>app f x = f x</code>
---
--- is represented as
---
--- <code>(Rule [0,1] (Comb FuncCall ("Prelude","apply") [Var 0, Var 1]))</code>
--- </li>
--- <li>
--- 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
---
--- <code>equal2 x | x=:=2 = success</code>
---
--- is represented as
---
--- <code>(Rule [0]
--- (Comb FuncCall ("Prelude","cond")
--- [Comb FuncCall ("Prelude","=:=") [Var 0, Lit (Intc 2)],
--- Comb FuncCall ("Prelude","success") []]))</code>
--- </li>
--- </ol>
---
--- @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]
| Let [(VarIndex,Expr)] Expr
| Free [VarIndex] Expr
| Or Expr Expr
| Case CaseType Expr [BranchExpr]
--- Data type for representing branches in a case expression.
---
--- 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).
data BranchExpr = Branch Pattern Expr
--- Data type for representing patterns in case expressions.
data Pattern = Pattern QName [VarIndex]
| LPattern Literal
--- Data type for representing literals occurring in an expression
--- or case branch. It is either an integer, a float, or a character constant.
data Literal = Intc Int
| Floatc Float
| Charc Char
------------------------------------------------------------------------------
--- I/O action which parses a Curry program and returns the corresponding
--- FlatCurry program.
--- Thus, the argument is the file name without suffix ".curry"
--- (or ".lcurry") and the result is a FlatCurry term representing this
--- program.
readFlatCurry :: String -> IO Prog
readFlatCurry progfile =
readFlatCurryWithParseOptions progfile (setQuiet True defaultParams)
--- I/O action which reads a FlatCurry program from a file
--- with respect to some parser options.
--- This I/O action is used by the standard action <CODE>readFlatCurry</CODE>.
--- It is currently predefined only in Curry2Prolog.
--- @param progfile - the program file name (without suffix ".curry")
--- @param options - parameters passed to the front end
readFlatCurryWithParseOptions :: String -> FrontendParams -> IO Prog
readFlatCurryWithParseOptions progname options = do
mbCurryFile <- lookupFileInLoadPath (progname++".curry")
mbLCurryFile <- lookupFileInLoadPath (progname++".lcurry")
if mbCurryFile==Nothing && mbLCurryFile==Nothing
then done
else callFrontendWithParams FCY options progname
filename <- findFileInLoadPath (progname++".fcy")
readFlatCurryFile filename
--- Transforms a name of a Curry program (with or without suffix ".curry"
--- or ".lcurry") into the name of the file containing the
--- corresponding FlatCurry program.
flatCurryFileName :: String -> String
flatCurryFileName prog = inCurrySubdir (stripSuffix prog ++ ".fcy")
--- Transforms a name of a Curry program (with or without suffix ".curry"
--- or ".lcurry") into the name of the file containing the
--- corresponding FlatCurry program.
flatCurryIntName :: String -> String
flatCurryIntName prog = inCurrySubdir (stripSuffix prog ++ ".fint")
--- I/O action which reads a FlatCurry program from a file in ".fcy" format.
--- In contrast to <CODE>readFlatCurry</CODE>, this action does not parse
--- a source program. Thus, the argument must be the name of an existing
--- file (with suffix ".fcy") containing a FlatCurry program in ".fcy"
--- format and the result is a FlatCurry term representing this program.
readFlatCurryFile :: String -> IO Prog
readFlatCurryFile filename = do
exfcy <- doesFileExist filename
if exfcy
then readExistingFCY filename
else do let subdirfilename = inCurrySubdir filename
exdirfcy <- doesFileExist subdirfilename
if exdirfcy
then readExistingFCY subdirfilename
else error ("EXISTENCE ERROR: FlatCurry file '"++filename++
"' does not exist")
where
readExistingFCY fname = do
filecontents <- readFile fname
return (readTerm filecontents)
--- I/O action which returns the interface of a Curry program, i.e.,
--- a FlatCurry program containing only "Public" entities and function
--- definitions without rules (i.e., external functions).
--- The argument is the file name without suffix ".curry"
--- (or ".lcurry") and the result is a FlatCurry term representing the
--- interface of this program.
readFlatCurryInt :: String -> IO Prog
readFlatCurryInt progname = do
existsCurry <- doesFileExist (progname++".curry")
existsLCurry <- doesFileExist (progname++".lcurry")
if existsCurry || existsLCurry
then callFrontend FINT progname
else done
filename <- findFileInLoadPath (progname++".fint")
readFlatCurryFile filename
--- Writes a FlatCurry program into a file in ".fcy" format.
--- The first argument must be the name of the target file
--- (with suffix ".fcy").
writeFCY :: String -> Prog -> IO ()
writeFCY file prog = writeFile file (showTerm prog)
-----------------------------------------------------------------------
--- Translates a given qualified type name into external name relative to
--- a module. Thus, names not defined in this module (except for names
--- defined in the prelude) are prefixed with their module name.
showQNameInModule :: String -> (String,String) -> String
showQNameInModule mod (qmod,name) =
if qmod==mod || qmod=="Prelude"
then name
else qmod++"."++name