packages feed

maxsharing-1.0.2: MaxSharing.hs

{-# LANGUAGE UnicodeSyntax #-}
module Main where

import Prelude.Unicode
import Parser
import Lambda (Params (..), LetPrefixLengths (..), showNameless, showTRNameless,
	synthesise, scoped_Syn_R, dfa_Syn_R, readback_Syn_R, proof_Syn_R, unscoped_Syn_R)
import System.Environment
import Language.HaLex.Minimize
import System.Cmd
import Language.HaLex.FaAsDiGraph (tographviz)
import Language.HaLex.Dfa (Dfa, beautifyDfa)
import Language.HaLex.FaOperations (dfa2ndfa)
import Language.HaLex.Equivalence (equivDfa)
import Spanning
import Text.PrettyPrint.Boxes (render)
import System.Console.GetOpt
import Control.Monad (when)


data Opt
	= Help
	| OptNoVarBacklinks
	| OptNoSBacklinks
	| OptSharedVars
	| OptMaxPrefix
	| OptMinPrefix
	deriving Eq

options = let option s o d = Option [] [s] (NoArg o) d in
	[Option ['h'] ["help"]     (NoArg Help)      "show this usage information",
	 option "no-var-backlinks" OptNoVarBacklinks "no backlinks for variable occurrences",
	 option "no-s-backlinks"   OptNoSBacklinks   "no backlinks for delimiter vertices",
	 option "shared-variables" OptSharedVars     "implicit sharing of variable occurrences",
	 option "max-prefix"       OptMaxPrefix      "maximal (same) prefix lengths for let-bindings",
	 option "min-prefix"       OptMinPrefix      "minimal prefix lengths for let-bindings"]

usage = "maxsharing [options] file1 ..." 

main ∷ IO ()
main = do
	args ← getArgs

	case getOpt Permute options args of
		(opts, files, []) → do
			let params = processOptions opts
			if Help ∈ opts
				then putStr $ usageInfo usage options
				else mapM_ (processFile params) files
		(_,_,errs) → error (concat errs ++ usageInfo usage options)


processOptions options = let has opt = opt ∈ options in Params
	{letPrefixLengths   = if has OptMaxPrefix then MaxPrefix else if has OptMinPrefix then MinPrefix else MaxEagPre,
 	 withVarBacklinks   = not $ has OptNoVarBacklinks,
 	 withSBacklinks     = not $ has OptNoSBacklinks,
 	 withSharedVars     = has OptSharedVars}

processFile ∷ Params → FilePath → IO ()
processFile params f = let syn = synthesise params in do
	λTerm ← parseFile f
	putStrLn "λ-letrec-term:" >> print λTerm
	let λTermSyn = syn λTerm
	putStrLn $ "translation used: " ⧺ show (letPrefixLengths params) ⧺ "\n"
	let scoped = scoped_Syn_R λTermSyn
	putStrLn ("scoped (with adbmals):") >> print scoped
	putStrLn ("scoped (with scope delimiters and nameless abstractions):") >> putStrLn (showNameless scoped)
	putStrLn "derivation:" >> putStrLn (render $ proof_Syn_R λTermSyn)
	let dfa = dfa_Syn_R $ syn scoped
	putStr "DFA: " >> dot (f ⧺ ".dfa") dfa >> putStrLn ""
	let tree = spanning params dfa
	putStrLn "spanning tree:" >> putStrLn (showTRNameless tree)
	putStrLn "readback:" >> print (readback_Syn_R $ syn tree)

	let minDfa = stdMinimizeDfa dfa
	putStr "minimised DFA: " >> dot (f ⧺ ".dfa.min") minDfa >> putStrLn ""
	let minTree = spanning params minDfa
	putStrLn "spanning tree:" >> putStrLn (showTRNameless minTree)
	let minλTerm = readback_Syn_R $ syn minTree
	putStrLn "readback:" >> putStr (show $ unscoped_Syn_R $ syn minλTerm)

	let readbackDfa = dfa_Syn_R $ syn minλTerm
	let (beautifulMinDfa, beautifulReadbackDfa) = (beautifyDfa minDfa, beautifyDfa readbackDfa)
	when (not $ beautifulMinDfa `equivDfa` beautifulReadbackDfa) $ do
		putStrLn "Sanity check failed! Minimised DFA and readback DFA are not equivalent."
		putStrLn $ "(see files with .dfa.min.bf. and .dfa.rb. in their names)" 
		dot (f ⧺ "dfa.min.bf") beautifulMinDfa >> dot (f ⧺ ".dfa.rb") beautifulReadbackDfa

dot ∷ (Show st, Show sy, Ord st, Ord sy) ⇒ String → Dfa st sy → IO ()
dot name dfa = do
	let dotfile = name ⧺ ".dot"
	let pdffile = name ⧺ ".pdf"
	putStrLn $ "writing to files " ⧺ dotfile ⧺ " and " ⧺ pdffile
	writeFile dotfile (tographviz (dfa2ndfa dfa) "g" "circle" "TB" (show . show))
	_ ← system $ "dot -Tpdf -o" ⧺ pdffile ⧺ " " ⧺ dotfile
	return ()