------------------------------------------------------------------------------ --- 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 March 2001 ------------------------------------------------------------------------------ module Flat where import Char import FileGoodies (getFileInPath) import FilePath (takeFileName, (), (<.>)) import System.CurryPath import System.FrontendExec ------------------------------------------------------------------------------ -- 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 --- --- (Prog modname imports typedecls functions opdecls translation_table) --- --- where modname: name of this module, --- imports: list of modules names that are imported, --- typedecls, opdecls, functions, translation_table: see below type Prog = Expr --- 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
---
--- 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.
--- 
data TypeDecl = Type String [TVarIndex] [ConsDecl] deriving Eq --- 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 String Int [TypeExpr] deriving Eq --- 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 String [TypeExpr] -- type constructor application deriving Eq --- 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 String Fixity Int deriving Eq --- Data types for the different choices for the fixity of an operator. data Fixity = InfixOp | InfixlOp | InfixrOp deriving (Eq, Show) --- Data types 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
---
---  (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.
--- 
data FuncDecl = Func String Int TypeExpr Rule deriving Eq --- 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 Eq --- 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 deriving (Eq, Show) --- Data type for classifying combinations --- (i.e., a function/constructor applied to some arguments). data CombType = FuncCall -- a call to a function | ConsCall -- a call with a constructor at the top | PartCall -- a partial application (i.e., FuncCall or -- ConsCall with some arguments missing) deriving (Eq, Show) --- Data types for representing expressions. data Expr = Var VarIndex -- variable (represented by unique index) | Lit Literal -- literal (Integer/Float/Char constant) | Comb CombType String [Expr] -- application (f e1 ... en) of function/ -- constructor f with n<=arity(f) | Apply Expr Expr -- application (e1 e2) | Constr [VarIndex] Expr -- constraint: let x1,...,xn free in e | Or Expr Expr -- disjunction of e1 e2 | Case CaseType Expr [BranchExpr] -- case (rigid or flex) | Choice Expr -- committed choice | GuardedExpr [VarIndex] Expr Expr -- guarded expression | SQ Expr | Prog String [String] [TypeDecl] [FuncDecl] [OpDecl] [Translation] deriving Eq {- The latter guarded expression represents conditional right-hand sides, possibly containing extra variables, i.e., (GuardedExpr [i1,...,in] c e) represents "| c = e where x1,...,xn free" i.e., c is always a constraint and each ij is the index of the variable xj. Remarks: 1. if-then-else expressions are represented as function calls: (if e1 then e2 else e3) is represented as (Comb FuncCall "if_then_else" [e1,e2,e3]) 2. Functions with evaluation annotation "choice" are represented by a rule whose right-hand side is enclosed in a "Choice". Furthermore, all rules of the original definition must be represented by GuardedExpr after pattern matching. Example: m eval choice m [] y = y m x [] = x is translated into: Rule [0,1] (Choice (Or (Case Rigid (Var 0) [(Pattern (Ident "[]") [] (GuardedExpr [] (Comb FuncCall "success" []) (Var 1)))] ) (Case Rigid (Var 1) [(Pattern (Ident "[]") [] (GuardedExpr [] (Comb FuncCall "success" []) (Var 0)))] )) Operational meaning of (Choice e): evaluate e with local search spaces and commit to the first (GuardedExpr [...] c ge) in e whose constraint c is satisfied -} --- Data types for representing branches in a case expressions. ---
--- Branches "(c x1...xn) -> e" in case expressions are represented as
---
---   (Branch (Pattern 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 deriving Eq --- Data type for representing patterns in case expressions. data Pattern = Pattern String [VarIndex] | LPattern Literal deriving Eq --- 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 deriving Eq --- Data type for translating external into internal names. --- Each module contains a translation table to translate the --- external names (visible to the user) into internal names (used in --- the implementation). Usually, the internal names are prefixed by --- the name of the module (except for the prelude). Thus, the translation --- table is a list of elements of the form --- (Trans name internal_name). data Translation = Trans String String deriving Eq ------------------------------------------------------------------------------ --- 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 readFlatCurry. --- 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 mbsrc <- lookupModuleSourceInLoadPath progname case mbsrc of Nothing -> do -- no source file, try to find FlatCurry file in load path: loadpath <- getLoadPathForModule progname filename <- getFileInPath (flatCurryFileName (takeFileName progname)) [""] loadpath readFlatCurryFile filename Just (dir,_) -> do callFrontendWithParams FCY options progname readFlatCurryFile (flatCurryFileName (dir takeFileName progname)) --- 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 (stripCurrySuffix 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 (stripCurrySuffix prog) <.> "fint" --- I/O action which reads a FlatCurry program from a file in ".fcy" format. --- In contrast to `readFlatCurry`, 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. --- It is currently predefined only in Curry2Prolog. readFlatCurryFile :: String -> IO Expr --Prog readFlatCurryFile fname = prim_readFlatCurryFile $## fname prim_readFlatCurryFile :: String -> IO Expr --Prog prim_readFlatCurryFile external ------------------------------------------------------------------------------ --- Splits an internal name into a pair of module name and name in local --- module. --- @param intname - the internal name of a (type) constructor or function --- occurring in the FlatCurry program --- @return (mod,lname) where mod is the module name and --- lname the local name of the parameter in this module splitFlatModName :: String -> (String,String) splitFlatModName name | isAlpha (head name) = let (modname,rname) = break (=='.') name in if rname=="" then ("Prelude",name) else (modname,tail rname) | otherwise = ("Prelude",name) ------------------------------------------------------------------------------