module Derive.Ix(deriveIx) where import Syntax import IntState import IdKind import NT import State import Derive.Lib import TokenId(tIx,trange,tindex,tinRange,t_enumRange,t_enumIndex,t_enumInRange ,t_tupleRange,t_andand,t_tupleIndex,t_Tuple,dropM) import Util.Extra(strPos) deriveIx :: ((TokenId,IdKind) -> Id) -> Id -> Id -> [Id] -> [(Id,Id)] -> Pos -> a -> IntState -> (Decl Id,IntState) deriveIx tidFun cls typ tvs ctxs pos = getInfo typ >>>= \ typInfo -> mapS getInfo (constrsI typInfo) >>>= \ constrInfos -> if all noArgs constrInfos -- enumeration then let nt = NewType tvs [] ctxs [mkNTcons typ (map mkNTvar tvs)] tidTyp = tidI typInfo msg = ExpLit pos (LitString Boxed (show (dropM tidTyp))) in addInstMethod tIx tidTyp trange nt (tidFun (trange,Method)) >>>= \ funRange -> addInstMethod tIx tidTyp tindex nt (tidFun (tindex,Method)) >>>= \ funIndex -> addInstMethod tIx tidTyp tinRange nt (tidFun (tinRange,Method)) >>>= \ funInRange -> (unitS (ExpVar pos) =>>> getUnique) >>>= \expA -> (unitS (ExpVar pos) =>>> getUnique) >>>= \expB -> (unitS (ExpVar pos) =>>> getUnique) >>>= \expC -> (unitS (ExpVar pos) =>>> getUnique) >>>= \expD -> (unitS (ExpVar pos) =>>> getUnique) >>>= \expE -> unitS $ DeclInstance pos (syntaxCtxs pos ctxs) cls [syntaxType pos typ tvs] $ DeclsParse [DeclFun pos funRange [Fun [expA] (Unguarded (ExpApplication pos [ExpVar pos (tidFun (t_enumRange,Var)),expA])) (DeclsParse [])] ,DeclFun pos funIndex [Fun [expB,expC] (Unguarded (ExpApplication pos [ExpVar pos (tidFun (t_enumIndex,Var)),msg,expB,expC])) (DeclsParse [])] ,DeclFun pos funInRange [Fun [expD,expE] (Unguarded (ExpApplication pos [ExpVar pos (tidFun (t_enumInRange,Var)),expD,expE])) (DeclsParse []) ] ] else if length constrInfos > 1 then deriveError ("Deriving of Ix is only allowed for enumeration or tuple types, and " ++ show (tidI typInfo) ++ " at " ++ strPos pos ++ " is neither.") else -- tupleType let constrInfo = head constrInfos conI = uniqueI constrInfo arity = arityI constrInfo expPair = ExpCon pos (tidFun (t_Tuple 2,Con)) expConstr = ExpCon pos conI exp_tupleRange = ExpVar pos (tidFun (t_tupleRange,Var)) expAnd = ExpVar pos (tidFun (t_andand,Var)) exp_tupleIndex = ExpVar pos (tidFun (t_tupleIndex,Var)) expInRange = ExpVar pos (tidFun (tinRange,Var)) nt = NewType tvs [] ctxs [mkNTcons typ (map mkNTvar tvs)] tidTyp = tidI typInfo in addInstMethod tIx tidTyp trange nt (tidFun (trange,Method)) >>>= \ funRange -> addInstMethod tIx tidTyp tindex nt (tidFun (tindex,Method)) >>>= \ funIndex -> addInstMethod tIx tidTyp tinRange nt (tidFun (tinRange,Method)) >>>= \ funInRange -> newArgs pos arity >>>= \ rangeL -> newArgs pos arity >>>= \ rangeU -> newArgs pos arity >>>= \ inRangeL -> newArgs pos arity >>>= \ inRangeU -> newArgs pos arity >>>= \ inRangeI -> newArgs pos arity >>>= \ indexL@(headL:tailL) -> newArgs pos arity >>>= \ indexU@(headU:tailU) -> newArgs pos arity >>>= \ indexI@(headI:tailI) -> unitS $ DeclInstance pos (syntaxCtxs pos ctxs) cls [syntaxType pos typ tvs] $ DeclsParse [DeclFun pos funRange [Fun [ExpApplication pos [expPair ,ExpApplication pos (expConstr:rangeL) ,ExpApplication pos (expConstr:rangeU)] ] (Unguarded (foldr ( \ (l,u) z -> ExpApplication pos [exp_tupleRange,l,u,z]) (ExpList pos [expConstr]) (reverse (zip rangeL rangeU)))) (DeclsParse [])] ,DeclFun pos funIndex [Fun [ExpApplication pos [expPair ,ExpApplication pos (expConstr:indexL) ,ExpApplication pos (expConstr:indexU)] ,ExpApplication pos (expConstr:indexI) ] (Unguarded (foldr (\ (l,u,i) z -> ExpApplication pos [exp_tupleIndex,l,u,i,z]) (ExpApplication pos [ExpVar pos (tidFun (tindex,Var)) ,ExpApplication pos [expPair,headL,headU],headI]) (reverse (zip3 tailL tailU tailI)))) (DeclsParse [])] ,DeclFun pos funInRange [Fun [ExpApplication pos [expPair ,ExpApplication pos (expConstr:inRangeL) ,ExpApplication pos (expConstr:inRangeU)] ,ExpApplication pos (expConstr:inRangeI) ] (Unguarded (foldr1 (\ a b -> ExpApplication pos [expAnd,a,b]) (map (\ (l,u,i) -> ExpApplication pos [expInRange,ExpApplication pos [expPair,l,u],i]) (zip3 inRangeL inRangeU inRangeI)))) (DeclsParse [])] ] newArgs :: Num a => Pos -> a -> b -> IntState -> ([Exp Id],IntState) newArgs pos 0 = unitS [] newArgs pos n = unitS ((:) . ExpVar pos) =>>> getUnique =>>> newArgs pos (n-1)