packages feed

neil-0.0: src/Paper/Haskell2/Stage3.hs

module Paper.Haskell2.Stage3(stage3) where

import Data.Char
import Data.List
import System.FilePath
import Paper.Haskell2.Type
import Paper.Haskell2.Haskell


exts = "NoMonomorphismRestriction, MultiParamTypeClasses, FlexibleContexts, " ++
       "FlexibleInstances, UndecidableInstances, Rank2Types, EmptyDataDecls, " ++
       "FunctionalDependencies, TypeSynonymInstances, IncoherentInstances, " ++
       "ExtendedDefaultRules, ScopedTypeVariables, GADTs, ViewPatterns, " ++
       "GeneralizedNewtypeDeriving, DeriveDataTypeable"

prefix = "{-# LANGUAGE " ++ exts ++ " #-}\n" ++
         "{-# OPTIONS_GHC -w #-}\n"


stage3 :: FilePath -> [HsItem] -> [(FilePath,String)]
stage3 file xs = (filename "", importer) : [(filename n, text n) | n <- need]
    where
        filename n = dropFileName file </> modname n <.> "hs"
        modname n = capital (takeBaseName file) ++ ['_'| n/=""] ++ n
        need = allWhere $ map itemWhere xs

        importer = unlines $ ("module Main where") :
                             ["import " ++ modname n ++ "()" | n <- need] ++
                             ["main = putStrLn \"Successfully checked\""]

        text n = unlines $ prefix :
                           ("module " ++ modname n ++ " where") :
                           render items
            where items = filter (matchWhere n . itemWhere) xs


render = collectImports . f [] . zip [0..]
    where
        f seen [] = []
        f seen ((n,HsItem Stmt pos x _) : xs) =
                linePragma pos : defNote : lines x2 ++ "" : f seen2 xs
            where
                def = defines x
                defNote = "-- !defines " ++ show def
                bad = def `intersect` seen
                x2 = rename (zip bad $ prime n bad) x
                seen2 = def `union` seen

        f seen (x:xs) = error $ "Stage 4, todo: " ++ show x


collectImports xs = imports ++ map f xs
    where
        imports = filter (\x -> "import " `isPrefixOf` x && g x `notElem` modules) xs
        modules = map g (filter ("module " `isPrefixOf`) xs) \\ ["Prelude"]
        g = takeWhile (\x -> isAlphaNum x || x `elem` "._") . dropWhile isSpace . dropWhile (not . isSpace)
    
        f x | any (`isPrefixOf` x) ["import ","module "] = "-- HIDE " ++ x
            | otherwise = x


capital (x:xs) = toUpper x : xs


prime :: Int -> [String] -> [String]
prime n xs | length pos == length (nub pos) = pos
           | otherwise = def
    where
        end = "''" ++ (uniqueStr !! n)
        sym = uniqueSym !! n
        (pos,def) = unzip $ map f xs

        f (x:xs) | isHaskellSym (x:xs) = (x:xs ++ "++" ++ sym, x:xs ++ "++" ++ sym)
                 | otherwise = (x : (reverse $ drop (length end) $ reverse xs) ++ end, x:xs ++ end)



uniqueStr = map (:[]) one ++ two ++ error "Stage3, uniqueStr exhausted"
    where
        one = ['0'..'9'] ++ ['a'..'z'] ++ ['A'..'Z']
        two = [[a,b] | a <- one, b <- one]


uniqueSym = [[a,b] | a <- syms, b <- syms] ++ error "Stage3, uniqueSym exhausted"
    where syms = "!+-<>=*&^%$"