module Derive.Read(deriveRead) where import Syntax import MkSyntax(mkInt) import IntState import Id import IdKind import NT import State import Derive.Lib import TokenId(tFalse,tTrue,tRead,treadParen,treadsPrec ,t_greater,t_append,t_readCon0,t_readCon,t_readConArg ,t_readConInfix,t_readField,t_readFinal,isTidOp,dropM) import Nice(showsOp,showsVar) import Maybe deriveRead :: ((TokenId, IdKind) -> Id) -> Id -> Id -> [Id] -> [(Id, Id)] -> Pos -> State d IntState (Decl Id) IntState deriveRead tidFun cls typ tvs ctxs pos = getUnique >>>= \ d -> getUnique >>>= \ r -> let expD = ExpVar pos d expR = ExpVar pos r ireadsPrec = tidFun (treadsPrec,Method) expAppend = ExpVar pos (tidFun (t_append,Var)) in getInfo typ >>>= \ typInfo -> mapS getInfo (constrsI typInfo) >>>= \ constrInfos -> addInstMethod tRead (tidI typInfo) treadsPrec (NewType tvs [] ctxs [mkNTcons typ (map mkNTvar tvs)]) ireadsPrec >>>= \ fun -> mapS (mkReadExp expD expR tidFun pos) constrInfos >>>= \ (e:es) -> unitS $ DeclInstance pos (syntaxCtxs pos ctxs) cls [syntaxType pos typ tvs] $ DeclsParse [DeclFun pos fun [Fun [expD,expR] (Unguarded (foldr (\ e1 e2 -> ExpApplication pos [expAppend, e1, e2]) e es)) (DeclsParse [])] ] mkReadExp :: Exp Id -> Exp Id -> ((TokenId, IdKind) -> Id) -> Pos -> Info -> State d IntState (Exp Id) IntState mkReadExp expD expR tidFun pos constrInfo = let conTid = dropM (tidI constrInfo) con = ExpCon pos (uniqueI constrInfo) fields = fieldsI constrInfo in if isTidOp conTid then let expConOp = ExpLit pos (LitString Boxed (showsOp conTid "")) expTrue = ExpCon pos (tidFun (tTrue,Con)) in case ntI constrInfo of NewType _ _ _ [nt] -> -- This constructor has no arguments unitS (ExpApplication pos [ExpVar pos (tidFun (t_readCon0,Var)), expTrue, con, expConOp, expR]) NewType _ _ _ [a,b,r] -> -- Infix constructor with two arguments let (p,lp,rp) = case fixityI constrInfo of (Infix,p) -> (p,p+1,p+1) (InfixR,p) -> (p,p+1,p) (_,p) -> (p,p,p+1) in unitS (ExpApplication pos [ExpVar pos (tidFun (t_readConInfix,Var)) ,expD ,(mkInt pos p) ,(mkInt pos lp) ,(mkInt pos rp) ,con ,expConOp, expR]) NewType _ _ _ (_:nts) -> -- We only want a list with one element for each argument, the elements themselves are never used let readConArg = ExpVar pos (tidFun (t_readConArg,Var)) in unitS $ ExpApplication pos [ExpVar pos (tidFun (treadParen,Var)) ,ExpApplication pos [ExpVar pos (tidFun (t_greater,Var)), expD, mkInt pos 9] ,foldr (\ _ a -> ExpApplication pos [readConArg,a]) (ExpApplication pos [ExpVar pos (tidFun (t_readCon0,Var)), expTrue, con, expConOp]) nts ,expR] else if null fields || any isNothing fields -- ordinary constructor then let expConVar = ExpLit pos (LitString Boxed (showsVar conTid "")) expFalse = ExpCon pos (tidFun (tFalse,Con)) in case ntI constrInfo of NewType _ _ _ [nt] -> -- This constructor has no arguments unitS (ExpApplication pos [ExpVar pos (tidFun (t_readCon0,Var)), expFalse, con, expConVar, expR]) NewType _ _ _ (_:nts) -> -- We only want a list with one element for each argument, the elements themselves are never used let readConArg = ExpVar pos (tidFun (t_readConArg,Var)) in unitS $ ExpApplication pos [ExpVar pos (tidFun (treadParen,Var)) ,ExpApplication pos [ExpVar pos (tidFun (t_greater,Var)), expD, mkInt pos 9] ,foldr (\ _ a -> ExpApplication pos [readConArg,a]) (ExpApplication pos [ExpVar pos (tidFun (t_readCon,Var)), con, expConVar]) nts ,expR] else -- constructor with named fields let expConVar = ExpLit pos (LitString Boxed (showsVar conTid "")) expReadField = ExpVar pos (tidFun (t_readField,Var)) expReadFinal k = ExpApplication pos [ExpVar pos (tidFun (t_readFinal,Var)) ,ExpLit pos (LitString Boxed "}") ,k] expLabel prefix label k = ExpApplication pos [expReadField ,ExpLit pos (LitString Boxed prefix) ,ExpLit pos (LitString Boxed (showsVar (dropM (tidI label)) "")) ,k] (NewType _ _ _ (_:nts)) = ntI constrInfo -- get list, 1 elem per arg prefixes = "{": replicate (length nts - 1) "," in mapS (getInfo.fromJust) fields >>>= \labels-> unitS $ ExpApplication pos [ExpVar pos (tidFun (treadParen,Var)) ,ExpApplication pos [ExpVar pos (tidFun (t_greater,Var)), expD, mkInt pos 9] ,expReadFinal (foldr (\(p,l) a -> expLabel p l a) (ExpApplication pos [ExpVar pos (tidFun (t_readCon,Var)) ,con ,expConVar]) (reverse (zip prefixes labels))) ,expR]