{-
    BNF Converter: OCaml main file
    Copyright (C) 2005  Author:  Kristofer Johannisson

-}

-- based on BNFC Haskell backend


module BNFC.Backend.OCaml (makeOCaml) where

import System.FilePath (pathSeparator, (</>))

import BNFC.Backend.Base hiding (Backend)
import BNFC.Backend.Common.Makefile
import BNFC.Backend.OCaml.CFtoOCamlAbs
import BNFC.Backend.OCaml.CFtoOCamlLex
import BNFC.Backend.OCaml.CFtoOCamlPrinter
import BNFC.Backend.OCaml.CFtoOCamlShow
import BNFC.Backend.OCaml.CFtoOCamlTemplate
import BNFC.Backend.OCaml.CFtoOCamlTest
import BNFC.Backend.OCaml.CFtoOCamlYacc
import BNFC.Backend.XML
import BNFC.CF
import BNFC.Options
import BNFC.PrettyPrint
import BNFC.Utils

-- naming conventions

noLang :: SharedOptions -> String -> String
noLang :: SharedOptions -> [Char] -> [Char]
noLang SharedOptions
_ [Char]
name = [Char]
name

withLang :: SharedOptions -> String -> String
withLang :: SharedOptions -> [Char] -> [Char]
withLang SharedOptions
opts [Char]
name = [Char]
name [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ SharedOptions -> [Char]
sanitizedLang SharedOptions
opts

mkMod :: (SharedOptions -> String -> String) -> String -> SharedOptions -> String
mkMod :: (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod SharedOptions -> [Char] -> [Char]
addLang [Char]
name SharedOptions
opts =
    [Char]
pref [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ if SharedOptions -> Bool
inDir SharedOptions
opts then SharedOptions -> [Char]
sanitizedLang SharedOptions
opts [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"." [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
name else SharedOptions -> [Char] -> [Char]
addLang SharedOptions
opts [Char]
name
        where pref :: [Char]
pref = [Char] -> ([Char] -> [Char]) -> Maybe [Char] -> [Char]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Char]
"" ([Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++[Char]
".") (SharedOptions -> Maybe [Char]
inPackage SharedOptions
opts)

mkFile :: (SharedOptions -> String -> String) -> String -> String -> SharedOptions -> FilePath
mkFile :: (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
addLang [Char]
name [Char]
ext SharedOptions
opts =
    [Char]
pref [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ if SharedOptions -> Bool
inDir SharedOptions
opts
       then SharedOptions -> [Char]
sanitizedLang SharedOptions
opts [Char] -> [Char] -> [Char]
</> [Char]
name [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
ext'
       else SharedOptions -> [Char] -> [Char]
addLang SharedOptions
opts [Char]
name [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ if [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
ext then [Char]
"" else [Char]
ext'
    where pref :: [Char]
pref = [Char] -> ([Char] -> [Char]) -> Maybe [Char] -> [Char]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Char]
"" (\ [Char]
p -> [Char] -> [Char]
pkgToDir [Char]
p [Char] -> [Char] -> [Char]
</> [Char]
"") (SharedOptions -> Maybe [Char]
inPackage SharedOptions
opts)
          ext' :: [Char]
ext' = if [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
ext then [Char]
"" else [Char]
"." [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
ext

-- | Turn language name into a valid ocaml module identifier.
sanitizedLang :: SharedOptions -> String
sanitizedLang :: SharedOptions -> [Char]
sanitizedLang = [Char] -> [Char]
camelCase_ ([Char] -> [Char])
-> (SharedOptions -> [Char]) -> SharedOptions -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SharedOptions -> [Char]
lang


absFile, absFileM, ocamllexFile, ocamllexFileM, ocamlyaccFile, ocamlyaccFileM,
  utilFile, templateFile, templateFileM, printerFile, printerFileM,
  tFile :: SharedOptions -> String
absFile :: SharedOptions -> [Char]
absFile       = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Abs" [Char]
"ml"
absFileM :: SharedOptions -> [Char]
absFileM      = (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Abs"
ocamllexFile :: SharedOptions -> [Char]
ocamllexFile      = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Lex" [Char]
"mll"
ocamllexFileM :: SharedOptions -> [Char]
ocamllexFileM     = (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Lex"
ocamlyaccFile :: SharedOptions -> [Char]
ocamlyaccFile     = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Par" [Char]
"mly"
ocamlyaccFileM :: SharedOptions -> [Char]
ocamlyaccFileM    = (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Par"
templateFile :: SharedOptions -> [Char]
templateFile  = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Skel" [Char]
"ml"
templateFileM :: SharedOptions -> [Char]
templateFileM = (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Skel"
printerFile :: SharedOptions -> [Char]
printerFile   = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Print" [Char]
"ml"
printerFileM :: SharedOptions -> [Char]
printerFileM  = (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Print"
showFile :: SharedOptions -> [Char]
showFile      = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Show" [Char]
"ml"
showFileM :: SharedOptions -> [Char]
showFileM     = (SharedOptions -> [Char] -> [Char])
-> [Char] -> SharedOptions -> [Char]
mkMod  SharedOptions -> [Char] -> [Char]
withLang [Char]
"Show"
tFile :: SharedOptions -> [Char]
tFile         = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Test" [Char]
"ml"
utilFile :: SharedOptions -> [Char]
utilFile       = (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
noLang   [Char]
"BNFC_Util" [Char]
"ml"

makeOCaml :: SharedOptions -> CF -> MkFiles ()
makeOCaml :: SharedOptions -> CF -> MkFiles ()
makeOCaml SharedOptions
opts CF
cf = do
  let absMod :: [Char]
absMod = SharedOptions -> [Char]
absFileM SharedOptions
opts
      lexMod :: [Char]
lexMod = SharedOptions -> [Char]
ocamllexFileM SharedOptions
opts
      parMod :: [Char]
parMod = SharedOptions -> [Char]
ocamlyaccFileM SharedOptions
opts
      prMod :: [Char]
prMod  = SharedOptions -> [Char]
printerFileM SharedOptions
opts
      showMod :: [Char]
showMod = SharedOptions -> [Char]
showFileM SharedOptions
opts
  do
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
absFile SharedOptions
opts) ([Char] -> MkFiles ()) -> [Char] -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ [Char] -> CF -> [Char]
cf2Abstract [Char]
absMod CF
cf
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
ocamllexFile SharedOptions
opts) ([Char] -> MkFiles ()) -> [Char] -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> CF -> [Char]
cf2ocamllex [Char]
lexMod [Char]
parMod CF
cf
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
ocamlyaccFile SharedOptions
opts) ([Char] -> MkFiles ()) -> [Char] -> MkFiles ()
forall a b. (a -> b) -> a -> b
$
                 [Char] -> [Char] -> [Char] -> CF -> [Char]
cf2ocamlyacc [Char]
parMod [Char]
absMod [Char]
lexMod  CF
cf
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
templateFile SharedOptions
opts) ([Char] -> MkFiles ()) -> [Char] -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> CF -> [Char]
cf2Template (SharedOptions -> [Char]
templateFileM SharedOptions
opts) [Char]
absMod CF
cf
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
printerFile SharedOptions
opts)  ([Char] -> MkFiles ()) -> [Char] -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> CF -> [Char]
cf2Printer [Char]
prMod [Char]
absMod CF
cf
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
showFile SharedOptions
opts)  ([Char] -> MkFiles ()) -> [Char] -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> CF -> [Char]
cf2show [Char]
showMod [Char]
absMod CF
cf
    [Char] -> Doc -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
tFile SharedOptions
opts) (Doc -> MkFiles ()) -> Doc -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> [Char] -> [Char] -> [Char] -> CF -> Doc
ocamlTestfile [Char]
absMod [Char]
lexMod [Char]
parMod [Char]
prMod [Char]
showMod CF
cf
    [Char] -> [Char] -> MkFiles ()
forall c. FileContent c => [Char] -> c -> MkFiles ()
mkfile (SharedOptions -> [Char]
utilFile SharedOptions
opts) [Char]
utilM
    SharedOptions -> ([Char] -> Doc) -> MkFiles ()
mkMakefile SharedOptions
opts (([Char] -> Doc) -> MkFiles ()) -> ([Char] -> Doc) -> MkFiles ()
forall a b. (a -> b) -> a -> b
$ SharedOptions -> [Char] -> Doc
makefile SharedOptions
opts
    case SharedOptions -> Int
xml SharedOptions
opts of
      Int
2 -> SharedOptions -> Bool -> CF -> MkFiles ()
makeXML SharedOptions
opts Bool
True CF
cf
      Int
1 -> SharedOptions -> Bool -> CF -> MkFiles ()
makeXML SharedOptions
opts Bool
False CF
cf
      Int
_ -> () -> MkFiles ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

pkgToDir :: String -> FilePath
pkgToDir :: [Char] -> [Char]
pkgToDir = Char -> Char -> [Char] -> [Char]
forall a. Eq a => a -> a -> [a] -> [a]
replace Char
'.' Char
pathSeparator

codeDir :: SharedOptions -> FilePath
codeDir :: SharedOptions -> [Char]
codeDir SharedOptions
opts = let pref :: [Char]
pref = [Char] -> ([Char] -> [Char]) -> Maybe [Char] -> [Char]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [Char]
"" [Char] -> [Char]
pkgToDir (SharedOptions -> Maybe [Char]
inPackage SharedOptions
opts)
                   dir :: [Char]
dir = if SharedOptions -> Bool
inDir SharedOptions
opts then SharedOptions -> [Char]
sanitizedLang SharedOptions
opts else [Char]
""
                   sep :: [Char]
sep = if [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
pref Bool -> Bool -> Bool
|| [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
dir then [Char]
"" else [Char
pathSeparator]
                 in [Char]
pref [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
sep [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
dir

makefile :: SharedOptions -> String -> Doc
makefile :: SharedOptions -> [Char] -> Doc
makefile SharedOptions
opts [Char]
basename = [Doc] -> Doc
vcat
    [ [Char] -> [Char] -> Doc
mkVar [Char]
"OCAMLC" [Char]
"ocamlc"
    , [Char] -> [Char] -> Doc
mkVar [Char]
"OCAMLYACC" ([Char] -> Doc) -> [Char] -> Doc
forall a b. (a -> b) -> a -> b
$ case SharedOptions -> OCamlParser
ocamlParser SharedOptions
opts of
        OCamlParser
OCamlYacc -> [Char]
"ocamlyacc"
        OCamlParser
Menhir    -> [Char]
"menhir"
    , [Char] -> [Char] -> Doc
mkVar [Char]
"OCAMLLEX" [Char]
"ocamllex"
    , [Char] -> [Char] -> Doc
mkVar [Char]
"OCAMLCFLAGS" [Char]
""
    , [Char] -> [[Char]] -> [[Char]] -> Doc
mkRule [Char]
"all" []
        [ [Char]
"$(OCAMLYACC) " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ SharedOptions -> [Char]
ocamlyaccFile SharedOptions
opts
        , [Char]
"$(OCAMLLEX) "  [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ SharedOptions -> [Char]
ocamllexFile SharedOptions
opts
        , [Char]
"$(OCAMLC) $(OCAMLCFLAGS) -o " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Test" [Char]
"" SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          SharedOptions -> [Char]
utilFile SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          SharedOptions -> [Char]
absFile SharedOptions
opts [Char] -> [Char] -> [Char]
+++ SharedOptions -> [Char]
templateFile SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          SharedOptions -> [Char]
showFile SharedOptions
opts [Char] -> [Char] -> [Char]
+++ SharedOptions -> [Char]
printerFile SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Par" [Char]
"mli" SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Par" [Char]
"ml" SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Lex" [Char]
"ml" SharedOptions
opts [Char] -> [Char] -> [Char]
+++
                          SharedOptions -> [Char]
tFile SharedOptions
opts ]
    , [Char] -> [[Char]] -> [[Char]] -> Doc
mkRule [Char]
"clean" []
        [ [Char]
"-rm -f " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
unwords (([Char] -> [Char]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ([Char]
dir[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++) [ [Char]
"*.cmi", [Char]
"*.cmo", [Char]
"*.o" ]) ]
    , [Char] -> [[Char]] -> [[Char]] -> Doc
mkRule [Char]
"distclean" [[Char]
"clean"]
        [ [Char]
"-rm -f " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
unwords [ (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Lex" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Par" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Layout" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Skel" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Print" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Show" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Test" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Abs" [Char]
"*" SharedOptions
opts,
                                 (SharedOptions -> [Char] -> [Char])
-> [Char] -> [Char] -> SharedOptions -> [Char]
mkFile SharedOptions -> [Char] -> [Char]
withLang [Char]
"Test" [Char]
"" SharedOptions
opts,
                                 SharedOptions -> [Char]
utilFile SharedOptions
opts,
                                 [Char]
basename ]]
    ]
  where dir :: [Char]
dir = let d :: [Char]
d = SharedOptions -> [Char]
codeDir SharedOptions
opts in if [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
d then [Char]
"" else [Char]
d [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char
pathSeparator]

utilM :: String
utilM :: [Char]
utilM = [[Char]] -> [Char]
unlines
    [[Char]
"(* automatically generated by BNFC *)",
     [Char]
"",
     [Char]
"open Lexing",
     [Char]
"",
     [Char]
"(* this should really be in the parser, but ocamlyacc won't put it in the .mli *)",
     [Char]
"exception Parse_error of Lexing.position * Lexing.position"
    ]