{---------------------------------------------------------------
--
-- Create.hs : contains function defination to generate program
-- parse trees.
-- T.Yu@cs.ucl.ac.uk September 25, 1997
--
--------------------------------------------------------------}
module Create (createTree,extract)where
import Header (TypeExp(..), Expression(..),ParseTree(..))
import Local (termEnv,funEnv,constant,adfs,args)
import Unify (applySub, unify, Theta(..))
import Array
-- selectTerm function -----------------------------------------------------------------
--
-- This function takes a type expression, a theta, a randomList and typeNum. It return a tuple
-- of the following elements: flag indicates whether a terminal is selected, the name
-- of the terminal, theta created, new random list and new typeNum.
-- If the expected retrun type contains temporary tyep variables,
-- we first instaniate dummy type variables in the selected terminal type
-- with new temporary type variables before "unifying" it with the return
-- type.
selectTerm :: TypeExp -> Theta -> [Int] -> Int -> (Bool, String,Theta, [Int], Int)
selectTerm retType theta rList typeNum =
let (start, end) = bounds termEnv
index = (head rList `mod` end) + start
match currIndex init =
if not init && (currIndex == index) then
(False, "", theta, tail rList, typeNum)
else if currIndex > end then
match start init
else
case ( termEnv ! currIndex ) of
{
(name,typeSig) ->
if hasTypeVar retType then
case (instDummy typeSig typeNum []) of
{
(typeSig', typeNum', dummyTheta) ->
case unify True [(retType, typeSig')] theta of
{
(unifiable, theta') ->
if unifiable then
(True, name, theta', tail rList, typeNum')
else
match (currIndex +1) False
}
}
else
case ( unify True [(retType,typeSig)][] ) of
{
(unifiable, theta') ->
if unifiable then
(True, name, theta, tail rList, typeNum)
else
match (currIndex +1) False
}
}
in
match index True
-- selectFun function -----------------------------------------------------------------
--
-- This function takes a type expression, a theta, first and last index and typeNum.
-- It return a tuple of the following elements: flag indicates whether a function is selected,
-- the name of the function, its argument type signatuer, theta created, index of the function
-- and new typeNum.
-- If the expected retrun type contains temporary tyep variables,
-- we first instaniate dummy type variables in the selected function type
-- with new temporary type variables before "unifying" it with the return
-- type.
selectFun :: TypeExp -> Theta -> Int -> Int -> Int -> (Bool, String, TypeExp, Theta, Int, Int)
selectFun retType theta first last typeNum =
--trace("selectFun : " ++ show first ++ show last ) $
let (start, end) = bounds funEnv
match currIndex init =
if not init && (currIndex == last) then
(False, "", retType, theta, first, typeNum) -- retType means nothing
else if currIndex > end then
match start init
else
let (name,typeSig) = funEnv ! currIndex
in if hasTypeVar retType then
let (typeSig', typeNum', dummyTheta) = instDummy typeSig typeNum []
(unifiable, argsType,theta') = getArgsType retType typeSig' theta
in
if unifiable then
(True, name, argsType, theta', currIndex, typeNum')
else
match (currIndex +1) False
else
let (unifiable, argsType,theta') = getArgsType retType typeSig []
in if unifiable then
let (argsType', typeNum', dummyTheta) = instDummy argsType typeNum []
in (True, name, argsType', theta, currIndex, typeNum')
else
match (currIndex + 1) False
in
match first True
-- instDummy function -----------------------------------------------------------------------
--
-- This fucntion takes a type expression and instantiates all dummy type variables with
-- temporary type variables. It returns the new type expression and new TypeNum
instDummy :: TypeExp -> Int -> Theta -> (TypeExp,Int,Theta)
instDummy typeExp typeNum theta =
case typeExp of
{
(DummyType x) -> let typeExp' = TypeVar ("T"++show typeNum)
in (typeExp',(typeNum + 1),(x,typeExp'):theta);
(Arrow t1 t2) -> let (t1', typeNum', theta') = instDummy t1 typeNum theta
(t2', typeNum'', theta'') = instDummy (applySub theta' t2) typeNum' theta'
in (Arrow t1' t2', typeNum'', theta'');
(Brackets t) -> let (t', typeNum', theta') = instDummy t typeNum theta
in (Brackets t',typeNum', theta');
(ListType t) -> let (t', typeNum', theta') = instDummy t typeNum theta
in (ListType t',typeNum', theta');
_ -> (typeExp, typeNum, theta)
}
-- hasTypeVar function ---------------------------------------------------------
--
--
hasTypeVar :: TypeExp -> Bool
hasTypeVar typeExp =
case typeExp of
{
(TypeVar _) -> True;
(Arrow t1 t2) -> (hasTypeVar t1) || (hasTypeVar t2);
(Brackets t) -> hasTypeVar t;
(ListType t) -> hasTypeVar t;
_ -> False
}
-- createTree function ----------------------------------------------------------
--
-- This function takes 6 arguments: a depth level, return type, randomList, theta typeNum and genTypes.
-- It returns a ParseTree with the specifed depth and return type.
-- We basically use "full" method unless no non-terminal to match the required type.
-- In that case, we pick a terminal and stop growing.
createTree :: Int -> TypeExp -> [Int] -> Theta -> Int -> ( ParseTree, [Int], Theta, Int)
createTree 1 retType rList theta typeNum =
--trace ("create1 "++show retType++show theta) $
let retType' = applySub theta retType
(findOne, name, theta', rList', typeNum') = selectTerm retType' theta rList typeNum
in
--trace ("selectTerm: "++show name++show theta') $
if not findOne then -- fail, no variable that matches the return type
(Empty, rList, theta, typeNum)
else
if (elem name constant) then
(ExpCons (Constant name), rList', theta', typeNum')
else
if name == "nil" then
(ExpCons (List []), rList', theta', typeNum')
else
(ExpCons (Variable name), rList', theta', typeNum')
createTree level retType rList theta typeNum =
--trace ("create "++show level++show retType++show theta) $
let retType' = applySub theta retType
(start, end) = bounds funEnv
orgIndex = (head rList `mod` end) + start
in
--trace ("info: "++show retType'++show start++show end++show orgIndex) $
let f1 first last init rList =
if not init && (first == last) then
createTree 1 retType' rList theta typeNum -- create leaf ( grow method )
else
let (findOne, name, argsType, theta', index, typeNum')=
selectFun retType' theta first last typeNum
in
--trace ("selectFun: "++show findOne++show name++show argsType++show theta'++show index) $
if not findOne then -- fail, no function matches the return type,
createTree 1 retType' rList theta typeNum -- create leaf ( grow method )
else
let f2 argType retType rList theta typeNum =
case argType of
{
(Arrow t1 t2) ->
let getRetType t =
case t of
{
(Arrow t1 s@(Arrow t2 t3)) ->
let (aType, rType)= getRetType s
in (Arrow t1 aType, rType);
(Arrow t1 t2) -> (t1,t2)
}
(argType', newRetType) = getRetType argType
(exp2, rList', theta', typeNum') =
createTree (level-1) newRetType rList theta typeNum
in if exp2 == Empty then
(Empty,Empty,rList',[],typeNum')
else
let argType'' = applySub theta' argType'
newRetType' = applySub theta' newRetType
(exp1', exp2',rList'',theta'',typeNum'') =
f2 argType'' (Arrow newRetType' retType) rList' theta' typeNum'
in if (exp1'==Empty) || (exp2'==Empty) then
(Empty,Empty,rList'',[],typeNum'')
else
(ExpCons (Application (extract exp1') (extract exp2')
(Arrow (applySub theta'' newRetType')
(applySub theta'' retType))), exp2, rList'', theta'', typeNum'');
_ -> case (createTree (level-1) argType rList theta typeNum) of
{
(exp2,rList',theta',typeNum') ->
if exp2 == Empty then
(Empty, Empty, rList, [], typeNum)
else
if (elem name adfs) then
( ExpCons(Function name), exp2, rList', theta', typeNum')
else
if (elem name args ) then
( ExpCons (Variable name), exp2, rList', theta', typeNum')
else
( ExpCons(Primitive name), exp2, rList', theta', typeNum')
}
}
in
--trace ("f1 in "++show name++show argTypes++show retType'++show newTheta) $
case (f2 argsType retType' rList theta' typeNum') of
{
(exp1, exp2, rList', theta'', typeNum'') ->
if (exp1==Empty) || (exp2==Empty) then
f1 (index +1) last False rList'
else
(ExpCons (Application (extract exp1)(extract exp2) retType'), rList', theta'', typeNum'')
}
in
f1 orgIndex orgIndex True (tail rList)
-- getArgsType function ----------------------------------------------------------------
--
-- This function takes an expected type and a function type. It unify the expected type
-- with the function return type. It then instaniate the argument type using the theta.
-- It returns the instantiated argument type.
getArgsType :: TypeExp -> TypeExp -> Theta -> (Bool, TypeExp, Theta)
getArgsType retType typeExp theta =
let unifyRetType aType theta = case aType of
{
(Arrow argType rType) -> unifyRetType rType theta;
_ -> unify True [(retType,aType)] theta
}
(unifiable,theta') = unifyRetType typeExp theta
in if unifiable then
let typeExp' = applySub theta' typeExp
retType' = applySub theta' retType
f exp = case exp of
{
(Arrow t1 t2) -> if t2 == retType' then t1
else (Arrow t1 (f t2));
_ -> error ("error in getArgsType ")
}
in
(True, (f typeExp'), theta')
else
(False, typeExp, theta)
--no need to deal with arrow situation since functions are curried
--extract -----------------------------------------------------------------------------
extract :: ParseTree -> Expression
extract exp = case exp of
{
Empty -> error "Empty expression";
(ExpCons x) -> x
}