{-
    BNF Converter: Abstract syntax
    Copyright (C) 2004  Author: Markus Forsberg, Aarne Ranta

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-}


module BNFC.MultiView where

import System.Directory	( doesFileExist, renameFile )

import qualified BNFC.CF as CF
import BNFC.Utils
import ParBNF
import PrintBNF
import Data.List(nub,partition)
import AbsBNF
-- import LexBNF
import ErrM
import Data.Char
import BNFC.TypeChecker

preprocessMCF :: FilePath -> IO ([FilePath],String)
preprocessMCF f = do
  s  <- readFile f
  gr <- case pLGrammar $ myLexer s of
    Ok g  -> return g
    Bad s -> error s
  let name = takeWhile (/='.') f
  let grs = extract name gr
  let entryp = entrypoint gr
  mapM_ writeCF grs
  return $ (map fst grs,entryp)

extract :: String -> LGrammar -> [(FilePath, Grammar)]
extract name (LGr ldefs) =
  [(file lang,Grammar [unldef ldef | ldef <- ldefs, isFor lang ldef]) |
      lang <- views]
 where
   views = [lang | LDefView langs <- ldefs, Ident lang <- langs]
   isFor lang ldef = case ldef of
     DefAll _ -> True
     DefSome ids _ -> elem (Ident lang) ids
     _ -> False
   unldef ldef = case ldef of
     DefAll d -> d
     DefSome _ d -> d
   file lang = name ++ "_" ++ lang ++ ".cf"

--- the entrypoint is the same for all languages - could be different

entrypoint :: LGrammar -> String
entrypoint (LGr rs0) = head $
  [c | Entryp (Ident c:_) <- rs] ++
  [c | Rule _ (IdCat (Ident c)) _ <- rs]
 where
   rs = concatMap getR rs0
   getR d = case d of
     DefAll d -> [d]
     DefSome _ d -> [d]
     _ -> [] --- LDefView

writeCF :: (FilePath, Grammar) -> IO ()
writeCF (file,gr) = do
  writeFile file $ printTree gr
  putStrLn $ "wrote file " ++ file

---- These are Haskell specific;
---- should be generalized by inspecting the options xx

mkTestMulti :: String -> [String] -> FilePath -> [FilePath] -> IO ()
mkTestMulti cat xx file files = do
  let abs  = takeWhile (/='.') file
  let cncs = map (takeWhile (/='.')) files
  let content = testfile cat xx abs cncs
  writeFile ("TestTrans" ++ abs ++ ".hs") content

mkMakefileMulti :: [String] -> FilePath -> [FilePath] -> IO ()
mkMakefileMulti xx file files = do
  let abs  = takeWhile (/='.') file
  let cncs = map (takeWhile (/='.')) files
  let content = makefile xx abs cncs
  writeFile "Makefile" content

makefile xx abs cncs = unlines $
  "all:" :
  ["\tmake -f Makefile_" ++ cnc | cnc <- cncs] ++
  ["\tghc --make -o TestTrans" ++ abs ++ " TestTrans" ++ abs,
   ""
  ]

testfile cat xx abs cncs = unlines $
  ["module Main where"] ++
  ["import qualified Lex" ++ cnc | cnc <- cncs] ++
  ["import qualified Par" ++ cnc | cnc <- cncs] ++
  ["import qualified Print" ++ cnc | cnc <- cncs] ++
  ["import Abs" ++ abs,
   "import ErrM",
   "import System.Environment (getArgs)",
   "",
   "main :: IO ()",
   "main = do",
   "  i:o:f:_ <- getArgs",
   "  s <- readFile f",
   "  case parse i s of",
   "    Ok t -> putStrLn $ prin o t",
   "    Bad s -> error s",
   "",
   "parse i = case i of"
  ] ++
  [
   "  " ++ sho cnc ++ " -> Par" ++ cnc ++ ".p" ++ cat ++
        " . Par" ++ cnc ++ ".myLexer" | cnc <- cncs
  ] ++
  [
   "",
   "prin o = case o of"
  ] ++
  [
   "  " ++ sho cnc ++ " -> Print" ++ cnc ++
                                         ".printTree" | cnc <- cncs
  ]
 where
   sho = show . tail . dropWhile (/='_')
