1 {-# OPTIONS -XFlexibleInstances #-}
5 import Text.PrettyPrint
6 import Control.Monad.State
7 import Control.Monad.Error
9 import Data.Maybe (fromJust, isNothing)
12 import Data.Function (on)
15 import qualified Data.Map as Map
18 import qualified Data.Set as Set
31 import System.Environment
36 inputFile :: Maybe String, -- ^ Path to input file
38 outputMode :: OutputMode
42 = Normal | Shapify | ShapifyPlus | Help | Debug
44 data OutputMode = PseudoCode | HaskellCode
46 defaultConfig = Config {
49 outputMode = PseudoCode }
51 parseArgs :: [[Char]] -> Config -> Config
55 parseArgs xs (conf { inputFile = Just x })
57 parseArgs xs (conf { execMode = Shapify })
59 parseArgs xs (conf { execMode = ShapifyPlus })
61 parseArgs xs (conf { execMode = Help })
63 parseArgs xs (conf { outputMode = HaskellCode, execMode = ShapifyPlus } )
65 parseArgs xs (conf { outputMode = PseudoCode } )
67 parseArgs xs (conf { execMode = Debug })
68 (x:xs) | isNothing (inputFile conf) ->
69 parseArgs xs (conf { inputFile = Just x })
80 nest 4 (text $ progName ++ "[-ss] (-P|-H) [-f] [FILENAME]\n") $+$
82 text ("This program is a prototype implementation of the paper:\n") $$
83 nest 4 (sep [text "Janis Voigtlander, Zhenjiang Hu, Kazutaka Matsuda and Meng Wang:",
84 text "Combining Syntactic and Semantic Bidirectionalization.",
87 wrap 80 ( "Given a \"get\" function defined in a file specified by FILENAME,"
88 ++ "the program returns \"put\" function by combining "
89 ++ "semantic bidirectionalization (Janis Voiglander: POPL'09) "
90 ++ "and syntatic bidirectionalization (Kazutaka Matsuda et al.: ICFP'07). A typical usage is \""++ progName ++ " -ss -H FILENAME\", which corresponding to the paper.\n"
95 (text "-ss", text"Converts \"List Unit\"s to \"Nat\"s"),
96 (text"-H", text"Returns a Haskell source code of \"put\" function." $$ text "This options implies \"-ss\"."),
97 (text"-P", text"Returns a pseudo code only after syntatic bidirectionalization [DEFAULT]"),
98 (text"-h", text"Show this help message") ])
99 -- vcat [nest 4 (text "-t"),
100 -- nest 8 (text "Type inference only"),
101 -- nest 4 (text "-s"),
102 -- nest 8 (vcat [text"Replace all expressions/patterns \"e :: t\"",
103 -- text"in function with type \"forall ...t... . ...\"."]) ,
104 -- nest 4 (text "-ss"),
105 -- nest 8 (vcat [text "Replace all expressions/patterns \"[] :: List Unit\" with \"Z :: Nat\"",
106 -- text "and \"Cons(_,x) :: List Unit\" with \"S(x)::Nat\"."]),
107 -- nest 4 (text "-h"),
108 -- nest 8 (text "Show this help messange.")]
110 pprOptions ps = vcat $ concatMap
111 (\(a,b) -> [nest 4 a,nest 8 b]) ps
112 wrap n s = wrap' n s []
113 where wrap' 0 (' ':s) buf = wrap' 0 s buf
114 wrap' 0 s buf = (text (reverse buf)) $$ wrap' n s []
115 wrap' m [] buf = (text (reverse buf))
117 | m - lnextSpace s < 0 =
118 text (reverse buf) $$ wrap' n s []
120 wrap' (m-1) s (' ':buf)
121 wrap' m (c:s) buf | m > 0 =
122 wrap' (m-1) s (c:buf)
124 lnextSpace (' ':_) = 0
125 lnextSpace (c:s) = 1 + lnextSpace s
128 main = do { args <- getArgs
129 ; let conf = parseArgs args defaultConfig
130 ; case execMode conf of
131 Help -> putStrLn usage
133 do { csterr <- case inputFile conf of
135 do cont <- getContents
136 return $ parseString cont
140 Left err -> hPutStrLn stderr (show err)
142 case execMode conf of
144 outputCode (outputMode conf) False (cprog) (typeInference cprog)
146 -- outputCode (outputMode conf) False (cprog) (shapify $ typeInference cprog)
147 putStrLn "Not Supported Now."
149 outputCode (outputMode conf) True (cprog) (introNat $ shapify $ typeInference cprog)
151 do { print $ ppr $ cprog
152 -- ; print $ pprAM $ constructAutomaton (typeInference cprog) initTAMap
153 ; let (p1,p2,p3) = constructBwdFunction (typeInference cprog)
154 ; print $ ppr p1 $$ ppr p2 $$ ppr p3
155 ; print $ ppr $ constructTypeDecl p2
156 ; print $ ppr $ generateCodeBwd (typeInference cprog, p1,p2,p3)
158 ; putStrLn $ "---- After \"Shapify\" ----"
159 ; let cprog' = introNat $ shapify $ typeInference cprog
160 -- ; print $ pprAM $ constructAutomaton cprog' initTAMap
162 ; let (p1,p2,p3) = constructBwdFunction cprog'
163 ; print $ ppr p1 $$ ppr p2 $$ ppr p3
169 outputCode o isShapify orig ast =
170 let (p1,p2,p3) = constructBwdFunction ast
173 do print $ ppr (constructTypeDecl p2)
174 print $ ppr orig $$ ppr p1 $$ ppr p2 $$ ppr p3
176 do putStrLn $ "import Control.Monad"
177 putStrLn $ "import BUtil"
179 print $ vcat $ map genBwdDef
180 (let AST decls = typeInference orig
181 in map (\(Decl f t _ _:_) -> (f,t)) $
182 groupBy isSameFunc decls)
183 print $ ppr (constructTypeDecl p2)
184 print $ ppr $ generateCodeBwd (orig,p1,p2,p3)
186 genBwdDef (Name fName,(TFun is ts t)) =
188 ([TCon (Name "List") [TVar i]],TCon (Name "List") [TVar j]) | i == j ->
189 ppr (Name fName) <> text "_Bb bias s v" $$
190 nest 4 (text "= gen_put_bias bias Main." <> ppr (Name fName)
191 <> text "(\\x y -> castError $ ("
192 <> ppr (NBwd $ IName fName is)
193 <> text " $! x) $! y) s v" ) $$
194 ppr (Name fName) <> text "_Bbd = withDefaultBias "
195 <> ppr (Name fName) <> text "_Bb" $$
196 ppr (Name fName) <> text "_Bd = withDefault "
197 <> ppr (Name fName) <> text "_B" $$
198 ppr (Name fName) <> text "_B s v = "
199 <> ppr (Name fName) <> text "_Bb rear s v"
205 checkTreeless :: AST -> Bool
206 checkTreeless (AST decls) = all checkTreelessD decls
208 checkTreelessD (Decl _ _ _ e) = checkTreelessE e
209 checkTreelessE (EVar _ _ _) = True
210 checkTreelessE (ECon _ _ _ es) = all checkTreelessE es
211 checkTreelessE (EFun _ _ _ es) = all isVariable es
212 isVariable (EVar _ _ _) = True
215 checkAffine :: AST -> Bool
216 checkAffine (AST decls) = all checkAffineD decls
218 checkAffineD (Decl _ _ _ e) = checkAffineE e
219 checkAffineE e = (varsE e == snub (varsE e))
220 varsE (EVar _ _ v) = [v]
221 varsE (ECon _ _ _ es) = concatMap varsE es
222 varsE (EFun _ _ _ es) = concatMap varsE es
226 type Automaton s = Map s [Deriv s]
227 data Deriv s = DCon Name [s]
232 vcat $ map pprDs $ Map.toList am
236 nest 4 (vcat $ map (\d -> text " -> " <> pprD d) ds)
237 pprD (DAny) = text "_"
238 pprD (DEps s) = ppr s
239 pprD (DCon c ss) = ppr c <> parens (hcat $ punctuate comma (map ppr ss))
241 data AState = ASType Int
246 instance Ppr AState where
247 ppr (ASType i) = text $ "T" ++ show i
248 ppr (ASExp x) = text $ "E" ++ show x
249 ppr (ASFun n) = text $ "F" ++ show n
251 instance Show AState where
254 initTAMap s = constructTypeMap s
256 uniq = do { i <- get; put (i+1); return i }
258 do { (st,m) <- constructTypeMap t
260 ; let m1 = Map.insert (ASType i) [DCon (Name "Nil")[],
261 DCon (Name "Cons") [ASType i, st]] m
262 ; return (ASType i, m1) }
264 do { let m1 = Map.insert (ASType 0) [DCon (Name "Z") [],
265 DCon (Name "S") [ASType 0]] (Map.empty)
266 ; return (ASType 0, m1) }
268 do { let m1 = Map.insert (ASType 1) [DAny] (Map.empty)
269 ; return (ASType 1, m1) }
270 constructTypeMap (TCon (Name "List") [t]) =
272 constructTypeMap (TCon (Name "Nat") []) =
274 constructTypeMap (TVar i) =
277 anyType -- Not Supported
279 testOverlap :: AST -> Doc
280 testOverlap (AST decl) =
281 let fDs = groupBy isSameFunc decl
282 in evalState (do { docs <- mapM f fDs
283 ; return $ vcat docs }) initCAConf
285 am = constructAutomaton (AST decl) initTAMap
286 f (ds@(Decl g t ps e:es)) =
287 do { b <- checkInjectivity am (AST decl) g
288 ; let di = text "Injectivity: " <> text (show $ b)
289 ; ba <- checkAmbiguity am (ASFun g)
290 ; let da = text "Ambiguity: " <> text (show $ ba)
292 ; return $ text (show g) $$ nest 4 (da $$ di $$ dol) }
293 pol ds = let is = [ ASExp $ fromJust $ idofE e | (Decl f t ps e) <- ds ]
294 ijs = [ (i,j) | vs <- [zip is [0..]], (i,x) <- vs, (j,y) <- vs ]
296 do { bs <- mapM (uncurry $ checkOverlapS am (Set.empty)) ijs
297 ; let vs = map (map snd) $ groupBy ((==) `on` (fst.fst)) $ zip ijs bs
298 ; return $ vcat ( map g vs )}
299 where g bs = hcat ( map (\h -> if h then text "O" else text "-") bs)
301 isNonErasing (Decl _ _ ps e) =
302 null $ (snub $ concatMap varsP ps) \\ varsE e
306 checkInjectivity am (AST decl) f =
307 checkInj (Set.empty) f
310 do { inj <- getInjSet
311 ; ninj <- getNonInjSet
312 ; if Set.member f inj || Set.member f env then
314 else if Set.member f ninj then
317 do { b1 <- checkAmbiguity am (ASFun f)
318 ; when b1 (addNonInj f)
319 ; let dsF = filter (\(Decl g _ _ _) -> g == f) decl
320 ; let b2 = all isNonErasing dsF
321 ; when (not b2) (addNonInj f )
322 ; let fs = concatMap calledFunctions dsF
323 ; b3 <- mapM (checkInj (Set.insert f env)) fs
324 ; when (not $ and b3) (addNonInj f)
325 ; if (not b1) && b2 && and b3 then
326 when (Set.null env) (addInj f) >> return True
331 evalState (do { cAst <- optimizedComplementation am ast
332 ; tAst <- doTupling am ast cAst
333 ; return tAst }) initCAConf
335 am = constructAutomaton ast initTAMap
338 data TypeDecl = TypeDecl Name [Int] [ConDef]
339 data ConDef = ConDef Name [Type] -- NB: First Order
341 instance Ppr TypeDecl where
342 ppr (TypeDecl c is cdefs) =
343 text "data" <+> ppr c <+>
344 hsep (map (\i -> text "t" <> ppr i) is) $$ nest 4 (ppr cdefs)
348 instance Ppr ConDef where
349 ppr (ConDef n ts) = ppr n <+> hsep (map pprT ts)
351 pprT (TVar i) = ppr (TVar i)
352 pprT t = parens (ppr t)
354 pprList (c:cs) = text "=" <+> ppr c $$
357 f [c] = text "|" <+> ppr c
358 f (c:cs) = text "|" <+> ppr c $$ f cs
360 -- Extract Type Definition from the complement definition
361 -- FIXME: More Smart Definition
362 constructTypeDecl :: AST -> [ TypeDecl ]
363 constructTypeDecl (AST cdecls) = [ TypeDecl (cmplName) vs condef ]
365 cmplName = Name "Cmpl"
366 vs = snub $ concat $ evalState (mapM extractVarsT cdecls) (0,[])
367 extractVarsT (Decl _ _ _ e) =
370 do { trav <- traversedList
371 ; if c `elem` trav then
375 ; let ws = [ w | (EVar _ _ w) <- es ]
376 ; is <- mapM (\_ -> uniq) ws
380 uniq = do { (i,t) <- get; put (i+1,t); return i }
381 traversedList = do { (i,t) <- get; return t }
382 addTraversed t = do { (i,tt) <- get; put (i,t:tt) }
383 condef = concat $ evalState (mapM mkConDef cdecls) (0,[])
384 mkConDef (Decl _ _ _ e) =
387 do { trav <- traversedList
388 ; if c `elem` trav then
392 ; let ws = [ w | (EVar _ _ w) <- es ]
393 ; let fs = [ TCon cmplName [ TVar i | i <- vs ] | (EFun _ _ _ _) <- es ]
394 ; is <- mapM (\_ -> uniq) ws
395 ; return $ [ ConDef c (map TVar is ++ fs) ] } }
403 constructBwdFunction :: AST -> (AST, AST, TAST)
404 constructBwdFunction ast =
405 evalState ( do { cmpl <- optimizedComplementation am ast
406 ; tpl <- doTupling am ast cmpl
407 ; let itpl = localInversion tpl
408 ; let fs = functions ast
409 ; bwds <- mapM constructBWD fs
410 ; return $ (AST bwds, cmpl, itpl)
413 am = constructAutomaton ast initTAMap
414 functions (AST decls) = map (\(Decl f _ _ _:_) -> f) $ groupBy isSameFunc decls
415 pS = PVar Nothing TUndet (Name "s")
416 pV = PVar Nothing TUndet (Name "v")
417 eS = EVar Nothing TUndet (Name "s")
418 eV = EVar Nothing TUndet (Name "v")
419 constructBWD f = do { b <- checkInjectivity am ast f
421 return $ Decl (NBwd f) FTUndet [pS,pV]
422 (EFun Nothing TUndet (NInv f) [eV])
424 return $ Decl (NBwd f) FTUndet [pS,pV]
425 (EFun Nothing TUndet (NInv (NTuple f))
426 [eV, EFun Nothing TUndet (NCmpl f) [eS]]) }
428 localInversion :: TAST -> TAST
429 localInversion (TAST tdecls) = TAST $ map localInversionD tdecls
431 localInversionD :: TDecl -> TDecl
432 localInversionD (TDecl f ps es vdecls) =
433 TDecl (NInv f) (map e2p es) (map p2e ps) (map linvVD vdecls)
435 e2p (EVar i t v) = PVar i t v
436 e2p (ECon i t c es) = PCon i t c (map e2p es)
437 p2e (PVar i t v) = EVar i t v
438 p2e (PCon i t c ps) = ECon i t c (map p2e ps)
439 linvVD (VDecl vs f us) = VDecl us (NInv f) vs
441 -- doTupling :: AST -> AST -> TAST
442 doTupling am (AST decls) (AST cdecls) =
443 do { tdecls <- mapM tupleD $ zip decls cdecls
444 ; return $ TAST tdecls }
446 fCalls (EFun _ _ f es) = [(f,es)]
447 fCalls (ECon _ _ _ es) = concatMap fCalls es
449 convE mp (EFun i t f es) = case lookup (f,es) mp of
451 Nothing -> EFun i t f es -- never happens
452 convE mp (EVar i t v ) = EVar i t v
453 convE mp (ECon i t c es) = ECon i t c (map (convE mp) es)
454 tupleD (Decl f _ ps e, Decl _ _ _ ce) =
455 do { b <- checkInjectivity am (AST decls) f
457 return $ tupleDInj f ps e
459 return $ tupleDNInj f ps e ce }
460 tupleDInj f ps e = TDecl f ps [convE vnMap e] wdecls -- keep function-name if injective
463 vnMap = zip funCalls [ NTupleV i | i <- [1..] ]
464 wdecls = map (\((f,es),v) -> VDecl [v] f [u | (EVar _ _ u) <- es ]) vnMap
465 tupleDNInj f ps e ce = TDecl (NTuple f) ps [convE vnMap e, convE cnMap ce] wdecls
468 ninjCalls = [ (f,es) | (NCmpl f, es) <- fCalls ce ]
469 injCalls = funCalls \\ ninjCalls
470 vnMap = zip funCalls [ NTupleV i | i <- [1..] ]
471 cnMap = zip (map (\(f,es) -> (NCmpl f,es)) funCalls) [ NTupleVC i | i <- [1..] ]
472 wdecls = map convW vnMap
474 convW ((f,es),v@(NTupleV i))
475 | (f,es) `elem` injCalls = VDecl [v] f [u | (EVar _ _ u) <- es ]
476 | otherwise = VDecl [v,NTupleVC i] (NTuple f) [u | (EVar _ _ u) <- es ]
486 calledFunctions (Decl _ _ _ e) = snub $ calledFunctionsE e
487 calledFunctionsE (ECon _ _ _ es) = concatMap calledFunctionsE es
488 calledFunctionsE (EFun _ _ f es) = f:concatMap calledFunctionsE es
489 calledFunctionsE _ = []
492 testComplementation (AST decls) =
493 evalState (optimizedComplementation am (AST decls)) initCAConf
495 am = constructAutomaton (AST decls) initTAMap
498 optimizedComplementation am (AST decls)
499 = do { cmpl <- complementation am (AST decls)
500 ; cmpl' <- optimizeByRemove am cmpl
501 ; cmpl'' <- optimizeByRename am cmpl'
504 optimizeByRename am (AST cdecls) =
505 do { let cfdeclss = groupBy isSameFunc cdecls
506 ; cfdeclss' <- mapM optRename cfdeclss
507 ; return $ AST $ concat cfdeclss' }
510 do { let ids = [ (i,[ (v,t) | (EVar _ t v) <- es ],length es)
511 | (Decl _ _ _ (ECon _ _ (NCConE i) es)) <- cfdecls ]
512 ; idss <- grouping [] ids
513 ; return $ map (doRename idss) cfdecls }
514 -- grouping :: [[(Int,[(Name,Type)])]] -> [(Int,[(Name,Type)])] -> State (CAConf AState) [[(Int,[(Name,Type)])]]
515 grouping gs [] = return gs
516 grouping gs (i:ids) =
517 do { gs' <- checkGroup i gs
519 -- checkGroup :: (Int,[(Name,Type)]) -> [[(Int,[(Name,Type)])]] -> State (CAConf AState) [[(Int,[(Name,Type)])]]
520 checkGroup i [] = return $ [ [i] ]
521 checkGroup i (g:gs) =
522 do { b <- compatible i g
526 do { gs' <- checkGroup i gs
528 compatible i [] = return $ True
529 compatible (i,vs,l) ((i',vs',l'):ls) =
530 do { b <- checkOverlapS am Set.empty (ASExp i) (ASExp i')
531 ; let b2 = (sort $ map snd vs) == (sort $ map snd vs')
532 ; if (not b) && b2 && l == l' then
533 compatible (i,vs,l) ls
536 doRename idss (Decl f t ps (ECon ei et (NCConE i) es)) =
537 Decl f t ps (ECon ei et (NCConU f j) es')
542 if i `elem` (map (\(a,_,_) -> a) is) then
546 es' = sortBy (compare `on` typeofE) [ e | (e@(EVar _ _ _)) <- es ]
547 ++ [ e | (e@(EFun _ _ _ _)) <- es ]
554 optimizeByRemove am (AST cdecls) =
555 do { let cfdeclss = groupBy isSameFunc cdecls
556 ; cfdeclss' <- mapM optRem cfdeclss
557 ; return $ AST $ concat cfdeclss' }
559 fromInj (Decl _ _ _ (ECon _ _ (NCConF _) _)) = True
562 | fromInj (head cfdecls) = return cfdecls
564 mapM (\(Decl f t ps e) -> do { e' <- tryRemove e; return $ Decl f t ps e'}) cfdecls
565 where ids = [ i | (Decl _ _ _ (ECon _ _ (NCConE i) _)) <- cfdecls ]
566 tryRemove (ex@(ECon ei et (NCConE i) [EFun ei' et' f es])) =
567 do { b <- checkNonOverlapAll i ids
569 return $ EFun ei' et' f es
572 tryRemove ex = return ex
573 checkNonOverlapAll i [] = return $ True
574 checkNonOverlapAll i (j:jds) | i == j = checkNonOverlapAll i jds
575 | otherwise = do { b <- checkOverlapS am (Set.empty) (ASExp i) (ASExp j)
579 checkNonOverlapAll i jds }
581 complementation am (ast@(AST decls)) =
582 do { cdecls <- mapM (complementationD am ast) decls
583 ; return $ AST cdecls }
585 complementationD am ast (Decl f ftype ps e) =
586 do { b <- checkInjectivity am ast f
588 return $ (Decl (NCmpl f) FTUndet ps (ECon Nothing TUndet cNameC []))
590 do { let fs = fCalls e
591 ; fs' <- filterNonInj fs
592 ; let e' = cExp unusedVars fs'
593 ; return $ (Decl (NCmpl f) FTUndet ps e') }
596 unusedVars = snub $ (snub $ concatMap varsWithTP ps) \\ (snub $ varsWithTE e)
597 varsWithTP (PVar _ t v) = [EVar Nothing t v]
598 varsWithTP (PCon _ _ _ ps) = concatMap varsWithTP ps
599 varsWithTE (EVar _ t v) = [EVar Nothing t v]
600 varsWithTE (ECon _ _ _ es) = concatMap varsWithTE es
601 varsWithTE (EFun _ _ _ es) = concatMap varsWithTE es
602 fCalls (ECon _ _ _ es) = concatMap fCalls es
603 fCalls (EFun _ _ f es) = (f,es):concatMap fCalls es
605 filterNonInj [] = return []
606 filterNonInj ((f,es):fs) = do { b <- checkInjectivity am ast f
610 do { fs' <- filterNonInj fs
611 ; return $ (f,es):fs' } }
613 cName = NCConE (fromJust $ idofE e)
614 cExp vs fs = ECon Nothing TUndet cName $
615 vs ++ (map (\(f,es) -> EFun Nothing TUndet (NCmpl f) es) fs)
619 constructAutomaton :: AST -> (Type -> State Int (AState,Automaton AState)) -> Automaton AState
620 constructAutomaton (AST decl) initTAMap =
621 removeEps $ evalState (unionM $ map constructAMD decl) 2
623 unionM [] = return $ Map.empty
624 unionM (m:ms) = do { r1 <- unionM ms
626 ; return $ Map.unionWith (++) r1 r2 }
627 constructAMD (Decl f t ps e) =
628 do { (st,m) <- constructAME e
629 ; return $ Map.insertWith (++) (ASFun f) [DEps st] m }
630 constructAME (ECon i t c es) =
631 do { ims <- mapM constructAME es
632 ; let (is,ms) = unzip ims
633 ; let m = Map.unions ms
634 ; let s = ASExp $ fromJust i
635 ; return (s, Map.insertWith (++) s [DCon c is] m)}
636 constructAME (EFun i t f es) = -- Assume Treeless
637 let s = ASExp $ fromJust i
638 in return (s, Map.insertWith (++) s [DEps $ ASFun f] (Map.empty))
639 constructAME (EVar i t x) =
640 do { (st,m) <- initTAMap t
641 ; let s = ASExp $ fromJust i
642 ; return (s, Map.insertWith (++) s [DEps st] m) }
644 allStates :: Ord s => Automaton s -> [s]
646 snub $ foldr (++) [] $ map (\(i,d) -> i:concatMap allStatesDerive d) $ Map.toList am
649 allStatesDerive (DCon _ is) = is
650 allStatesDerive (DAny) = []
651 allStatesDerive (DEps i) = [i]
653 removeEps :: Automaton AState -> Automaton AState
655 foldr (Map.unionWith (++)) Map.empty $
656 map f $ Map.toList am
658 f (i,ds) = Map.fromList [ (j,filter nonEpsD ds) | j <- reachableA i ]
659 isEps (_,DEps _) = True
661 nonEpsD (DEps _) = False
663 erules = filter isEps $ concatMap (\(i,ds) -> [(i,d)|d<-ds]) $ Map.toList am
664 aStates = allStates am
665 (graph,v2n,k2v) = graphFromEdges $ map (\(i,is) -> (i,i,is)) $
666 Map.toList $ Map.fromListWith (++) $
667 (map (\(i,DEps j) -> (j,[i])) erules
668 ++ map (\i->(i,[i])) aStates)
669 reachableA k = map (\(n,_,_) -> n) $ map v2n $ reachable graph (fromJust $ k2v k)
672 type AmbSet s = Set s
673 type UnAmbSet s = Set s
674 type OLSet s = Set (s,s)
675 type UnOLSet s = Set (s,s)
676 type InjSet = Set Name
677 type NonInjSet = Set Name
678 type CAConf s = (AmbSet s, UnAmbSet s, OLSet s, UnOLSet s, InjSet, NonInjSet)
680 initCAConf = (Set.empty,Set.empty,Set.empty,Set.empty,Set.empty,Set.empty)
682 ambset (s,_,_,_,_,_) = s
683 unambset (_,s,_,_,_,_) = s
684 olset (_,_,s,_,_,_) = s
685 unolset (_,_,_,s,_,_) = s
686 injset (_,_,_,_,s,_) = s
687 noninjset (_,_,_,_,_,s) = s
689 getAmbSet :: Ord s => State (CAConf s) (AmbSet s)
690 getAmbSet = get >>= (return . ambset)
692 getUnAmbSet :: Ord s => State (CAConf s) (UnAmbSet s)
693 getUnAmbSet = get >>= (return . unambset)
695 getOLSet :: Ord s => State (CAConf s) (OLSet s)
696 getOLSet = get >>= (return . olset)
698 getUnOLSet :: Ord s => State (CAConf s) (UnOLSet s)
699 getUnOLSet = get >>= (return . unolset)
701 getInjSet :: State (CAConf s) InjSet
702 getInjSet = get >>= (return . injset)
704 getNonInjSet :: State (CAConf s) NonInjSet
705 getNonInjSet = get >>= (return . noninjset)
707 addAmb x = do { (a,ua,o,uo,inj,ninj) <- get; put (Set.insert x a,ua,o,uo,inj,ninj) }
708 addUnAmb x = do { (a,ua,o,uo,inj,ninj) <- get; put (a,Set.insert x ua,o,uo,inj,ninj) }
709 addOL x = do { (a,ua,o,uo,inj,ninj) <- get; put (a,ua,Set.insert x o,uo,inj,ninj) }
710 addUnOL x = do { (a,ua,o,uo,inj,ninj) <- get; put (a,ua,o,Set.insert x uo,inj,ninj) }
711 addInj x = do { (a,ua,o,uo,inj,ninj) <- get; put (a,ua,o,uo,Set.insert x inj,ninj) }
712 addNonInj x = do { (a,ua,o,uo,inj,ninj) <- get; put (a,ua,o,uo,inj,Set.insert x ninj) }
714 checkAmbiguity :: Ord s => Automaton s -> s -> State (CAConf s) Bool
715 checkAmbiguity am s =
716 do { amb <- getAmbSet
717 ; unamb <- getUnAmbSet
718 ; if (Set.member s amb) then
720 else if (Set.member s unamb) then
723 do { b <- checkAmb am unamb s
724 ; when (not b) (addUnAmb s)
727 distinctPairs ds = let vs = zip ds [0..]
728 in [ (d1,d2) | (d1,i) <- vs, (d2,j) <- vs, i < j ]
729 checkOL (d1,d2) = checkOverlap am (Set.empty) d1 d2
731 let derives = fromJust $ Map.lookup s am
732 dPairs = distinctPairs derives
733 in do { rs <- mapM checkOL dPairs
735 addAmb s >> return True
737 do { let ss = [ s | d <- derives, s <- allStatesDerive d, not (Set.member s env) ]
738 ; rs <- mapM (checkAmb am (Set.insert s env)) ss
742 checkOverlap am env (DEps s1) (DEps s2) = checkOverlapS am env s1 s2
743 checkOverlap am env (DCon c1 s1) (DCon c2 s2)
745 do { rs <- mapM (uncurry (checkOverlapS am env)) $ zip s1 s2
747 | otherwise = return False
749 checkOverlap am env DAny _ = return True
750 checkOverlap am env _ DAny = return True
751 checkOverlap am env _ _ = return False
753 checkOverlapS :: Ord s => Automaton s -> Set (s,s) -> s -> s -> State (CAConf s) Bool
754 checkOverlapS am env s1 s2
755 | Set.member (s1,s2) env || Set.member (s2,s1) env
758 = do { ol <- getOLSet
760 ; if Set.member (s1,s2) ol || Set.member (s2,s1) ol then
762 else if Set.member (s1,s2) uol || Set.member (s2,s1) uol then
765 let derives1 = fromJust $ Map.lookup s1 am
766 derives2 = fromJust $ Map.lookup s2 am
767 comb = [ (d1,d2) | d1 <- derives1, d2 <- derives2 ]
768 in do { rs <- mapM (uncurry $ checkOverlap am (Set.insert (s1,s2) env)) comb
770 do { when (Set.null env) (addUnOL (s1,s2))