diff --git a/source/BNFC.cabal b/source/BNFC.cabal index 8f4e2013..a1438210 100644 --- a/source/BNFC.cabal +++ b/source/BNFC.cabal @@ -55,7 +55,8 @@ Executable bnfc containers, pretty >=1.1 && <1.2, filepath, - deepseq + deepseq, + Cabal >= 1.16 && < 1.23 build-tools: alex, happy Main-is: Main.hs HS-source-dirs: src/ @@ -101,6 +102,7 @@ Executable bnfc BNFC.Backend.Haskell, BNFC.Backend.Haskell.ToCNF, BNFC.Backend.Haskell.RegToAlex, + BNFC.Backend.Haskell.CFtoCabal, BNFC.Backend.Haskell.CFtoTemplate, BNFC.Backend.Haskell.CFtoAlex3, BNFC.Backend.Haskell.CFtoAlex2, @@ -196,9 +198,21 @@ Executable bnfc -- --- Testing -------------------------------------------------------------- Test-suite unit-tests Type: exitcode-stdio-1.0 - Build-Depends: base>=4 && <5, mtl, directory, array, process, filepath, pretty, - hspec, QuickCheck >= 2.5, HUnit, - temporary, containers, deepseq + Build-Depends: + base>=4 && <5, + mtl, + directory, + array, + process, + filepath, + pretty, + hspec, + QuickCheck >= 2.5, + HUnit, + temporary, + containers, + deepseq, + Cabal >= 1.16 && < 1.23 Main-is: unit-tests.hs HS-source-dirs: src test extensions: diff --git a/source/src/BNFC/Backend/Haskell.hs b/source/src/BNFC/Backend/Haskell.hs index 6c7fb7f3..18a1ddc9 100644 --- a/source/src/BNFC/Backend/Haskell.hs +++ b/source/src/BNFC/Backend/Haskell.hs @@ -34,6 +34,7 @@ import BNFC.Backend.Haskell.CFtoAbstract import BNFC.Backend.Haskell.CFtoTemplate import BNFC.Backend.Haskell.CFtoPrinter import BNFC.Backend.Haskell.CFtoLayout +import BNFC.Backend.Haskell.CFtoCabal import BNFC.Backend.XML import BNFC.Backend.Haskell.HsOpts import BNFC.Backend.Haskell.ToCNF as ToCNF @@ -81,6 +82,7 @@ makeHaskell opts cf = do mkfile (txtFile opts) $ cfToTxt (lang opts) cf mkfile (templateFile opts) $ cf2Template (templateFileM opts) absMod errMod (functor opts) cf mkfile (printerFile opts) $ cf2Printer (byteStrings opts) (functor opts) False prMod absMod cf + mkfile (cabalFile opts) $ cf2Cabal opts when (hasLayout cf) $ mkfile (layoutFile opts) $ cf2Layout (alex1 opts) (inDir opts) layMod lexMod cf mkfile (errFile opts) $ mkErrM errMod (ghcExtensions opts) when (shareStrings opts) $ mkfile (shareFile opts) $ sharedString shareMod (byteStrings opts) cf @@ -106,9 +108,10 @@ makefile opts = makeA where [ if cnf opts then "ghc --make TestCNF.hs" else "ghc --make " ++ tFile opts ++ " -o " ++ mkFile withLang "Test" "" opts]) - , Makefile.mkRule "clean" [] + , Makefile.mkRule "clean" [] $ [ "-rm -f " ++ unwords - (map (dir++) [ "*.log", "*.aux", "*.hi", "*.o", "*.dvi" ]) ] + (map (dir++) [ "*.log", "*.aux", "*.hi", "*.o", "*.dvi" ]) ]++ + [ "cabal clean" | cabal opts ] , Makefile.mkRule "distclean" ["clean"] [ "-rm -f " ++ unwords [ mkFile withLang "Doc" "*" opts @@ -120,6 +123,7 @@ makefile opts = makeA where , mkFile withLang "Test" "*" opts , mkFile withLang "Abs" "*" opts , mkFile withLang "Test" "" opts + , mkFile withLang "" "cabal*" opts , mkFile noLang "ErrM" "*" opts , mkFile noLang "SharedString" "*" opts , mkFile noLang "ComposOp" "*" opts @@ -278,4 +282,3 @@ liftParser , " dec_fn f = decode (find f) r" , " in GLR_Result (\\ff -> dec_fn $ ff f) (dec_fn f)" ] - diff --git a/source/src/BNFC/Backend/Haskell/CFtoCabal.hs b/source/src/BNFC/Backend/Haskell/CFtoCabal.hs new file mode 100644 index 00000000..9b64894f --- /dev/null +++ b/source/src/BNFC/Backend/Haskell/CFtoCabal.hs @@ -0,0 +1,91 @@ +{- + BNF Converter: Abstract syntax Generator + Copyright (C) 2016 Author: Pascal Hof + + 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.Backend.Haskell.CFtoCabal (cf2Cabal) where + +import Distribution.Simple hiding (Language) +import Distribution.ModuleName(ModuleName,fromString) +import Distribution.PackageDescription +import Distribution.PackageDescription.Parse(showPackageDescription) + +import BNFC.Backend.Haskell.HsOpts +import BNFC.Options hiding (Version) +import Data.Monoid(mempty) + +-- to produce a Cabal file +cf2Cabal :: SharedOptions -> String +cf2Cabal = showPackageDescription . buildPackageDescription + +buildPackageDescription :: SharedOptions -> PackageDescription +buildPackageDescription opt = emptyPackageDescription + { package = + PackageIdentifier + { pkgName = PackageName (lang opt) + , pkgVersion = Version [0,1] []} + , library = Just (createLibrary opt) + , executables = [createExecutable opt] + , extraSrcFiles = [ happyFile opt, alexFile opt ] + , buildType = Just Simple + , license = AllRightsReserved + , specVersionRaw = Right (orLaterVersion $ Version [1,22] []) + } + +dependencies :: SharedOptions -> [Dependency] +dependencies opt = + [ Dependency (PackageName "base") (orLaterVersion $ Version [4] []) + , Dependency (PackageName "array") anyVersion + ] ++ + [ Dependency (PackageName "mtl") anyVersion | TargetHaskellGadt == target opt ] + +createLibrary :: SharedOptions -> Library +createLibrary opt = mempty + { exposedModules = exposedLibMods opt + , libExposed = True + , libBuildInfo = emptyBuildInfo + { buildable = True + , hsSourceDirs = ["."] + , targetBuildDepends = dependencies opt + } + } + +createExecutable :: SharedOptions -> Executable +createExecutable opt = Executable name mainIs buildInfo where + name :: String + name = "Test" ++ lang opt + + mainIs :: FilePath + mainIs = tFile opt + + buildInfo :: BuildInfo + buildInfo = mempty + { targetBuildDepends = dependencies opt + , otherModules = exposedLibMods opt + } + +-- |returns a list of all modules the library exposes +exposedLibMods :: SharedOptions -> [ModuleName] +exposedLibMods opt = map fromString $ + [absFileM opt + ,errFileM opt + ,printerFileM opt + ,alexFileM opt + ,happyFileM opt + ] ++ + [xmlFileM opt | xml opt > 0] ++ + [composOpFileM opt | TargetHaskellGadt == target opt ] diff --git a/source/src/BNFC/Backend/Haskell/HsOpts.hs b/source/src/BNFC/Backend/Haskell/HsOpts.hs index a37757b9..d2727ca3 100644 --- a/source/src/BNFC/Backend/Haskell/HsOpts.hs +++ b/source/src/BNFC/Backend/Haskell/HsOpts.hs @@ -45,7 +45,7 @@ xmlFile = mkFile withLang "XML" "hs" xmlFileM = mkMod withLang "XML" composOpFile = mkFile noLang "ComposOp" "hs" composOpFileM = mkMod noLang "ComposOp" - +cabalFile opt = lang opt ++ ".cabal" noLang :: Options -> String -> String noLang _ name = name diff --git a/source/src/BNFC/Backend/HaskellGADT.hs b/source/src/BNFC/Backend/HaskellGADT.hs index b0dc6c82..dc2de2eb 100644 --- a/source/src/BNFC/Backend/HaskellGADT.hs +++ b/source/src/BNFC/Backend/HaskellGADT.hs @@ -34,6 +34,7 @@ import BNFC.Backend.HaskellGADT.CFtoAbstractGADT import BNFC.Backend.HaskellGADT.CFtoTemplateGADT import BNFC.Backend.Haskell.CFtoPrinter import BNFC.Backend.Haskell.CFtoLayout +import BNFC.Backend.Haskell.CFtoCabal import BNFC.Backend.XML import BNFC.Backend.Haskell.MkErrM import BNFC.Backend.Haskell.MkSharedString @@ -71,6 +72,7 @@ makeHaskellGadt opts cf = do liftIO $ putStrLn " (Tested with Happy 1.15)" mkfile (templateFile opts) $ cf2Template (templateFileM opts) absMod errMod cf mkfile (printerFile opts) $ cf2Printer False False True prMod absMod cf + mkfile (cabalFile opts) $ cf2Cabal opts when (hasLayout cf) $ mkfile (layoutFile opts) $ cf2Layout (alexMode opts == Alex1) (inDir opts) layMod lexMod cf mkfile (tFile opts) $ Haskell.testfile opts cf mkfile (errFile opts) $ mkErrM errMod (ghcExtensions opts) diff --git a/source/src/BNFC/Options.hs b/source/src/BNFC/Options.hs index 636f2705..98a695b0 100644 --- a/source/src/BNFC/Options.hs +++ b/source/src/BNFC/Options.hs @@ -76,6 +76,7 @@ data SharedOptions = Options , glr :: HappyMode , xml :: Int , ghcExtensions :: Bool + , cabal :: Bool -- C++ specific , linenumbers :: Bool -- ^ Add and set line_number field for syntax classes -- C# specific @@ -103,6 +104,7 @@ defaultOptions = Options , glr = Standard , xml = 0 , ghcExtensions = False + , cabal = False , lang = error "lang not set" , linenumbers = False , visualStudio = False @@ -122,7 +124,7 @@ globalOptions = [ -- | Options for the target languages -- targetOptions :: [ OptDescr Target ] targetOptions :: [ OptDescr (SharedOptions -> SharedOptions)] -targetOptions = +targetOptions = [ Option "" ["java"] (NoArg (\o -> o {target = TargetJava})) "Output Java code [default: for use with JLex and CUP]" , Option "" ["haskell"] (NoArg (\o -> o {target = TargetHaskell})) @@ -206,6 +208,9 @@ specificOptions = , ( Option [] ["ghc"] (NoArg (\o -> o {ghcExtensions = True})) "Use ghc-specific language extensions" , [TargetHaskell, TargetHaskellGadt, TargetProfile] ) + , ( Option [] ["cabal"] (NoArg (\o -> o {cabal = True})) + "Also generate cabal file" + , [TargetHaskell,TargetHaskellGadt] ) , ( Option [] ["functor"] (NoArg (\o -> o {functor = True})) "Make the AST a functor and use it to store the position of the nodes" , [TargetHaskell] ) @@ -277,28 +282,27 @@ isUsageError _ = False -- A translating function to maintain backward compatiblicy -- with the old option syntay translateOldOptions :: [String] -> [String] -translateOldOptions = map translateOne - where translateOne "-java" = "--java" - translateOne "-java1.5" = "--java" - translateOne "-c" = "--c" - translateOne "-cpp" = "--cpp" - translateOne "-cpp_stl" = "--cpp" - translateOne "-cpp_no_stl" = "--cpp-nostl" - translateOne "-csharp" = "--csharp" - translateOne "-ocaml" = "--ocaml" - translateOne "-fsharp" = "fsharp" - translateOne "-haskell" = "--haskell" - translateOne "-prof" = "--profile" - translateOne "-gadt" = "--haskell-gadt" - translateOne "-alex1" = "--alex1" - translateOne "-alex2" = "--alex2" - translateOne "-alex3" = "--alex3" - translateOne "-sharestrings" = "--sharestring" - translateOne "-bytestrings" = "--bytestring" - translateOne "-glr" = "--glr" - translateOne "-xml" = "--xml" - translateOne "-xmlt" = "--xmlt" - translateOne "-vs" = "--vs" - translateOne "-wcf" = "--wcf" - translateOne other = other - +translateOldOptions = concatMap translateOne + where translateOne "-java" = return "--java" + translateOne "-java1.5" = return "--java" + translateOne "-c" = return "--c" + translateOne "-cpp" = return "--cpp" + translateOne "-cpp_stl" = return "--cpp" + translateOne "-cpp_no_stl" = return "--cpp-nostl" + translateOne "-csharp" = return "--csharp" + translateOne "-ocaml" = return "--ocaml" + translateOne "-fsharp" = return "fsharp" + translateOne "-haskell" = return "--haskell" + translateOne "-prof" = return "--profile" + translateOne "-gadt" = return "--haskell-gadt" + translateOne "-alex1" = return "--alex1" + translateOne "-alex2" = return "--alex2" + translateOne "-alex3" = return "--alex3" + translateOne "-sharestrings" = return "--sharestring" + translateOne "-bytestrings" = return "--bytestring" + translateOne "-glr" = return "--glr" + translateOne "-xml" = return "--xml" + translateOne "-xmlt" = return "--xmlt" + translateOne "-vs" = return "--vs" + translateOne "-wcf" = return "--wcf" + translateOne other = return other diff --git a/source/test/BNFC/Backend/HaskellSpec.hs b/source/test/BNFC/Backend/HaskellSpec.hs index 28cf78db..3340d4e8 100644 --- a/source/test/BNFC/Backend/HaskellSpec.hs +++ b/source/test/BNFC/Backend/HaskellSpec.hs @@ -56,3 +56,9 @@ spec = do calc <- getCalc let options = calcOptions { make = Just "MyMakefile" } makeHaskell options calc `shouldGenerate` "MyMakefile" + + context "with option --cabal and the Calc grammar" $ do + it "generates a cabal file" $ do + calc <- getCalc + let options = calcOptions { cabal = True } + makeHaskell options calc `shouldGenerate` "Calc.cabal" diff --git a/testing/Main.hs b/testing/Main.hs index 98b68f93..0fb780e6 100644 --- a/testing/Main.hs +++ b/testing/Main.hs @@ -1,17 +1,19 @@ module Main (main) where -import Test.Framework (htfMain) - +import Test.Framework (htfMain) +{-} +import HaskellCabalTests import HaskellCnfTests import ParameterizedTests -import PygmentsTests -import RegressionTests -import OutputParser +import PygmentsTests-} +import RegressionTests +--import OutputParser main = htfMain [ RegressionTests.all - , ParameterizedTests.all + {-, ParameterizedTests.all , PygmentsTests.all , HaskellCnfTests.all , OutputParser.tests + , HaskellCabalTests.all-} ] diff --git a/testing/src/HaskellCabalTests.hs b/testing/src/HaskellCabalTests.hs new file mode 100644 index 00000000..d4da7fa6 --- /dev/null +++ b/testing/src/HaskellCabalTests.hs @@ -0,0 +1,45 @@ +module HaskellCabalTests (all) where + +import Shelly +import Prelude hiding (all,unlines) +import Data.Text(Text,unlines,unpack) +import TestUtils(Test,makeShellyTest,makeTestSuite,assertFileExists) + +all = makeTestSuite "Haskell/Cabal" + [ mkTest target desc ps + | (desc,ps) <- params + , target <- ["--haskell","--haskell-gadt"] + ] + +-- |a list of test description and the respective arguments to bnfc +params :: [(String,[Text])] +params = + [("Cabal only",[]) + ,("Ghc",["--ghc"]) + ,("Functor",["--functor"]) + ,("Xml",["--xml"]) + ,("Xmlt",["--xmlt"]) + ,("Qualified",["-d"]) + ,("Namespace",["-p","Foobar"]) + ,("Qualified namespace",["-p","Foobar","-d"]) + ] + +-- |building the Shelly Test +mkTest :: Text -> String -> [Text] -> Test +mkTest target desc bnfcParams = + makeShellyTest description $ withTmpDir $ \tmp -> do + cd tmp + writefile "Test.cf" $ unlines + [ "Start. S ::= S \"parseMe\" ;" + , "End. S ::= ;" ] + run_ "bnfc" args + assertFileExists "Test.cabal" + cmd "cabal" "configure" + cmd "cabal" "build" + cmd "echo" "parseMe" -|- cmd "cabal" "run" + where + args :: [Text] + args = target:"--cabal":bnfcParams ++ ["Test.cf"] + + description :: String + description = desc++",Target "++drop 2 (unpack target)