~ubuntu-branches/ubuntu/raring/agda/raring-proposed

« back to all changes in this revision

Viewing changes to src/full/Agda/Compiler/MAlonzo/Compiler.hs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane
  • Date: 2010-01-05 23:43:20 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100105234320-6ksc0sdsfhtweknu
Tags: 2.2.6-1
* New upstream release 2.2.6, for headlines please see:
  http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Version-2-2-6
* debian/control
  + Bump standards-version to 3.8.3, no changes
  + Fix Vcs-Git to point to correct URL
  + Update build-depends for new upstream release
  + Undo arch/indep split per current pkg-haskell practice
  + Add Homepage field
* debian/copyright: Fix encoding to UTF-8 (thanks Lintian) 
* debian/README.source: Remove, no repacking so not necessary any more 
* debian/50agda.el:
  + Only load file if it exists, prevents a non-intrusive emacs warning
    where 50agda.el is left on system when package is removed. 
    (Closes: #559197). 
  + Do not load file on XEmacs — agda-mode is not compatible with XEmacs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
module Agda.Compiler.MAlonzo.Compiler where
4
4
 
5
5
import Control.Applicative
 
6
import qualified Control.Exception as E
6
7
import Control.Monad.Reader
7
8
import Control.Monad.State
8
9
import Data.Char
14
15
import System.Directory
15
16
import System.Exit
16
17
import System.IO
17
 
import qualified System.IO.UTF8 as UTF8
18
18
import System.Time
19
19
import System.Process
20
 
import System.FilePath ((</>))
 
20
import System.FilePath hiding (normalise, (<.>))
21
21
 
22
22
import Agda.Compiler.MAlonzo.Misc
23
23
import Agda.Compiler.MAlonzo.Pretty
24
24
import Agda.Compiler.MAlonzo.Primitives
 
25
import Agda.Interaction.FindFile
25
26
import Agda.Interaction.Imports
26
27
import Agda.Interaction.Monad
27
28
import Agda.Interaction.Options
28
29
import Agda.Syntax.Common
 
30
import qualified Agda.Syntax.Concrete.Name as CN
29
31
import Agda.Syntax.Internal
30
32
import Agda.Syntax.Literal
31
33
import Agda.TypeChecking.Monad
34
36
import Agda.TypeChecking.Pretty
35
37
import Agda.Utils.FileName
36
38
import Agda.Utils.Monad
 
39
import qualified Agda.Utils.IO.Locale as LocIO
 
40
import qualified Agda.Utils.IO.UTF8 as UTF8
37
41
import Agda.Utils.Impossible
38
42
 
39
43
#include "../../undefined.h"
40
44
 
41
 
compilerMain :: TCM Interface -> TCM ()
42
 
compilerMain typecheck = do
43
 
  i <- typecheck
44
 
  ignoreAbstractMode $ do
45
 
    t <- liftIO getClockTime
46
 
    let mainICT = (i, t)
47
 
    mapM_ compile =<< ((mainICT :) . M.elems <$> getVisitedModules)
48
 
    callGHC mainICT
49
 
 
50
 
compile :: (Interface, ClockTime) -> TCM ()
51
 
compile ict = do
52
 
  setInterface ict
 
45
compilerMain :: Interface -> TCM ()
 
46
compilerMain mainI =
 
47
  -- Preserve the state (the compiler modifies the state).
 
48
  bracket get put $ \_ -> do
 
49
 
 
50
    -- Compute the output directory.
 
51
    opts <- commandLineOptions
 
52
    malonzoDir <- case optMAlonzoDir opts of
 
53
      Just dir -> return dir
 
54
      Nothing  -> do
 
55
        -- The default output directory is the project root.
 
56
        let tm = toTopLevelModuleName $ iModuleName mainI
 
57
        f <- findFile tm
 
58
        return $ filePath $ CN.projectRoot f tm
 
59
    setCommandLineOptions PersistentOptions $
 
60
      opts { optMAlonzoDir = Just malonzoDir }
 
61
 
 
62
    ignoreAbstractMode $ do
 
63
      mapM_ (compile . miInterface) =<< (M.elems <$> getVisitedModules)
 
64
      callGHC mainI
 
65
 
 
66
compile :: Interface -> TCM ()
 
67
compile i = do
 
68
  setInterface i
53
69
  ifM uptodate noComp $ (yesComp >>) $ do
54
70
    writeModule =<< decl <$> curHsMod <*> (definitions =<< curDefs) <*> imports
55
71
  where
56
72
  decl mn ds imp = HsModule dummy mn Nothing imp ds
57
73
  uptodate = liftIO =<< (isNewerThan <$> outFile <*> ifile)
58
 
  ifile    = findFile InterfaceFile =<< curMName
 
74
  ifile    = maybe __IMPOSSIBLE__ filePath <$>
 
75
               (findInterfaceFile . toTopLevelModuleName =<< curMName)
59
76
  noComp   = reportSLn "" 1 . (++ " : no compilation is needed.").show =<< curMName
60
77
  yesComp  = reportSLn "" 1 . (`repl` "Compiling <<0>> in <<1>> to <<2>>") =<<
61
78
             sequence [show <$> curMName, ifile, outFile] :: TCM ()
67
84
--------------------------------------------------
68
85
 
69
86
imports :: TCM [HsImportDecl]
70
 
imports = (++) <$> unqualImps <*> qualImps where
71
 
  unqualImps = (L.map (decl False) . (unsafeCoerceMod :) . L.map Module) <$>
72
 
               getHaskellImports
73
 
  qualImps   = L.map (decl True) . uniq <$>
74
 
               ((++) <$> importsForPrim <*> (L.map mazMod <$> mnames))
75
 
  decl qual m = HsImportDecl dummy m qual Nothing Nothing
76
 
  mnames      = (++) <$> (S.elems <$> gets stImportedModules)
77
 
                     <*> (iImportedModules <$> curIF)
78
 
  uniq        = L.map head . group . L.sort
 
87
imports = (++) <$> hsImps <*> imps where
 
88
  hsImps = (L.map decl . S.toList .
 
89
            S.insert unsafeCoerceMod . S.map Module) <$>
 
90
             getHaskellImports
 
91
  imps   = L.map decl . uniq <$>
 
92
             ((++) <$> importsForPrim <*> (L.map mazMod <$> mnames))
 
93
  decl m = HsImportDecl dummy m True Nothing Nothing
 
94
  mnames = (++) <$> (S.elems <$> gets stImportedModules)
 
95
                <*> (iImportedModules <$> curIF)
 
96
  uniq   = L.map head . group . L.sort
79
97
 
80
98
--------------------------------------------------
81
99
-- Main compiling clauses
90
108
  (infodecl q :) <$> case d of
91
109
    Axiom{ axHsDef = Just (HsDefn ty hs) } -> return $ fbWithType ty (fakeExp hs)
92
110
    Axiom{}                                -> return $ fb axiomErr
93
 
    Function{ funClauses = cls } -> mkwhere <$> mapM (clause q) (tag 0 cls)
 
111
    Function{ funClauses =        cls } -> function cls
 
112
    Primitive{ primClauses = Just cls } -> function cls
 
113
    Primitive{ primClauses = Nothing, primName = s } -> fb <$> primBody s
94
114
    Datatype{ dataPars = np, dataIxs = ni, dataClause = cl, dataCons = cs, dataHsType = Just ty } -> do
95
115
      ccs <- concat <$> mapM checkConstructorType cs
96
116
      cov <- checkCover q ty np cs
97
 
      return $ tvaldecl q 0 (np + ni) [] (Just __IMPOSSIBLE__) ++ ccs ++ cov
 
117
      return $ tvaldecl q (dataInduction d) 0 (np + ni) [] (Just __IMPOSSIBLE__) ++ ccs ++ cov
98
118
    Datatype{ dataPars = np, dataIxs = ni, dataClause = cl, dataCons = cs, dataHsType = Nothing } -> do
99
119
      (ars, cds) <- unzip <$> mapM condecl cs
100
 
      return $ tvaldecl q (maximum (np:ars) - np) (np + ni) cds cl
 
120
      return $ tvaldecl q (dataInduction d) (maximum (np:ars) - np) (np + ni) cds cl
101
121
    Constructor{} -> return []
102
 
    Record{ recClause = cl, recFields = flds } -> do
 
122
    Record{ recClause = cl, recCon = c, recFields = flds } -> do
 
123
      let noFields = genericLength flds
103
124
      ar <- arity <$> normalise ty
104
 
      return $ tvaldecl q (genericLength flds) ar [cdecl q (genericLength flds)] cl
105
 
    Primitive{ primName = s } -> fb <$> primBody s
 
125
      cd <- case c of
 
126
        Nothing -> return $ cdecl q noFields
 
127
        Just c  -> snd <$> condecl c
 
128
      return $ tvaldecl q Inductive noFields ar [cd] cl
106
129
  where
 
130
  function cls = mkwhere <$> mapM (clause q) (tag 0 cls)
107
131
  tag _ []       = []
108
132
  tag i [cl]     = (i, True , cl): []
109
133
  tag i (cl:cls) = (i, False, cl): tag (i + 1) cls
169
193
  isCon _              = False
170
194
 
171
195
argpatts :: [Arg Pattern] -> [HsPat] -> TCM [HsPat]
172
 
argpatts ps0 bvs = evalStateT (mapM pat' ps0) bvs where
173
 
  pat (VarP _   ) = do v <- gets head; modify tail; return v
174
 
  pat (DotP _   ) = pat (VarP dummy)
175
 
  pat (ConP q ps) = (HsPParen .).HsPApp <$> lift (conhqn q) <*> mapM pat' ps
176
 
  pat (LitP l   ) = return $ HsPLit $ hslit l
 
196
argpatts ps0 bvs = evalStateT (mapM pat' ps0) bvs
 
197
  where
 
198
  pat   (VarP _   ) = do v <- gets head; modify tail; return v
 
199
  pat   (DotP _   ) = pat (VarP dummy)
 
200
  pat   (LitP l   ) = return $ HsPLit $ hslit l
 
201
  pat p@(ConP q ps) = do
 
202
    -- Note that irr is applied once for every subpattern, so in the
 
203
    -- worst case it is quadratic in the size of the pattern. I
 
204
    -- suspect that this will not be a problem in practice, though.
 
205
    irrefutable <- lift $ irr p
 
206
    let tilde = if   tildesEnabled && irrefutable
 
207
                then HsPParen . HsPIrrPat
 
208
                else id
 
209
    (tilde . HsPParen) <$>
 
210
      (HsPApp <$> lift (conhqn q) <*> mapM pat' ps)
 
211
 
177
212
  pat' = pat . unArg
178
213
 
 
214
  tildesEnabled = False
 
215
 
 
216
  -- | Is the pattern irrefutable?
 
217
  irr :: Pattern -> TCM Bool
 
218
  irr (VarP {})   = return True
 
219
  irr (DotP {})   = return True
 
220
  irr (LitP {})   = return False
 
221
  irr (ConP q ps) =
 
222
    (&&) <$> singleConstructorType q
 
223
         <*> (and <$> mapM (irr . unArg) ps)
 
224
 
179
225
clausebody :: ClauseBody -> TCM HsExp
180
226
clausebody b0 = runReaderT (go b0) 0 where
181
227
  go (Body   tm       ) = hsCast <$> term tm
208
254
 
209
255
hslit :: Literal -> HsLiteral
210
256
hslit l = case l of LitInt    _ x -> HsInt    x
 
257
                    LitLevel  _ x -> HsInt    x
211
258
                    LitFloat  _ x -> HsFrac   (toRational x)
212
259
                    LitString _ x -> HsString x
213
260
                    LitChar   _ x -> HsChar   x
222
269
cdecl q n = HsConDecl dummy (unqhname "C" q)
223
270
            [ HsUnBangedTy $ HsTyVar $ ihname "a" i | i <- [0 .. n - 1]]
224
271
 
225
 
tvaldecl :: QName -> Nat -> Nat -> [HsConDecl] -> Maybe Clause -> [HsDecl]
226
 
tvaldecl q ntv npar cds cl = let
227
 
    (tn, vn) = (unqhname "T" q, unqhname "d" q)
228
 
    tvs = [          ihname "a" i | i <- [0 .. ntv  - 1]]
229
 
    pvs = [ HsPVar $ ihname "a" i | i <- [0 .. npar - 1]]
230
 
  in HsFunBind [HsMatch dummy vn pvs (HsUnGuardedRhs unit_con) []] :
231
 
     maybe [HsDataDecl dummy [] tn tvs cds []] (const []) cl
 
272
tvaldecl :: QName
 
273
         -> Induction
 
274
            -- ^ Is the type inductive or coinductive?
 
275
         -> Nat -> Nat -> [HsConDecl] -> Maybe Clause -> [HsDecl]
 
276
tvaldecl q ind ntv npar cds cl =
 
277
  HsFunBind [HsMatch dummy vn pvs (HsUnGuardedRhs unit_con) []] :
 
278
  maybe [datatype] (const []) cl
 
279
  where
 
280
  (tn, vn) = (unqhname "T" q, unqhname "d" q)
 
281
  tvs = [          ihname "a" i | i <- [0 .. ntv  - 1]]
 
282
  pvs = [ HsPVar $ ihname "a" i | i <- [0 .. npar - 1]]
 
283
 
 
284
  -- Inductive data types consisting of a single constructor with a
 
285
  -- single argument are translated into newtypes.
 
286
  datatype = case (ind, cds) of
 
287
    (Inductive, [c@(HsConDecl _ _ [_])]) -> newtyp c
 
288
    (Inductive, [c@(HsRecDecl _ _ [_])]) -> newtyp c
 
289
    _                                    -> datatyp
 
290
 
 
291
  newtyp c = HsNewTypeDecl dummy [] tn tvs c   []
 
292
  datatyp  = HsDataDecl    dummy [] tn tvs cds []
232
293
 
233
294
infodecl :: QName -> HsDecl
234
295
infodecl q = fakeD (unqhname "name" q) $ show (show q)
259
320
 
260
321
writeModule :: HsModule -> TCM ()
261
322
writeModule m =
 
323
  -- Note that GHC assumes that sources use ASCII or UTF-8.
262
324
  liftIO . (`UTF8.writeFile` (preamble ++ prettyPrint m)) =<< outFile
263
325
  where
264
326
  preamble = unlines $ [ "{-# LANGUAGE EmptyDataDecls"
265
327
                       , "           , ExistentialQuantification"
266
328
                       , "           , ScopedTypeVariables"
267
 
                       , "           , UnicodeSyntax"
268
329
                       , "           , NoMonomorphismRestriction"
269
330
                       , "  #-}"
270
331
                       ]
271
332
 
 
333
malonzoDir :: TCM FilePath
 
334
malonzoDir = do
 
335
  mdir <- optMAlonzoDir <$> commandLineOptions
 
336
  case mdir of
 
337
    Just dir -> return dir
 
338
    Nothing  -> __IMPOSSIBLE__
 
339
 
272
340
outFile' = do
273
 
  mdir <- gets (optMAlonzoDir . stOptions)
274
 
  (fdir, fn, _) <- splitFilePath . repldot slash . prettyPrint <$> curHsMod
275
 
  let (dir, fp) = (addSlash mdir ++ fdir, addSlash dir ++ fn ++ ".hs")
 
341
  mdir <- malonzoDir
 
342
  (fdir, fn) <- splitFileName . repldot pathSeparator .
 
343
                prettyPrint <$> curHsMod
 
344
  let dir = mdir </> fdir
 
345
      fp  = dir </> replaceExtension fn "hs"
276
346
  liftIO $ createDirectoryIfMissing True dir
277
347
  return (mdir, fp)
278
348
  where
281
351
outFile :: TCM FilePath
282
352
outFile = snd <$> outFile'
283
353
 
284
 
callGHC :: (Interface, ClockTime) -> TCM ()
285
 
callGHC mainICT = do
286
 
  setInterface mainICT
287
 
  mdir          <- optMAlonzoDir <$> commandLineOptions
 
354
callGHC :: Interface -> TCM ()
 
355
callGHC i = do
 
356
  setInterface i
 
357
  mdir          <- malonzoDir
288
358
  hsmod         <- prettyPrint <$> curHsMod
289
359
  MName agdaMod <- curMName
290
360
  let outputName = case agdaMod of
291
361
        [] -> __IMPOSSIBLE__
292
362
        ms -> last ms
293
363
  (mdir, fp) <- outFile'
294
 
  opts       <- gets (optGhcFlags . stOptions)
 
364
  opts       <- optGhcFlags <$> commandLineOptions
 
365
 
295
366
  let overridableArgs =
296
367
        [ "-O"
297
368
        , "-o", mdir </> show outputName
307
378
        ]
308
379
      args     = overridableArgs ++ opts ++ otherArgs
309
380
      compiler = "ghc"
 
381
 
310
382
  reportSLn "" 1 $ "calling: " ++ L.intercalate " " (compiler : args)
311
 
  (exitcode, out, err) <- liftIO $ readProcessWithExitCode compiler args ""
 
383
  (inn, out, err, p) <-
 
384
    liftIO $ runInteractiveProcess compiler args Nothing Nothing
 
385
 
 
386
  liftIO $ do
 
387
    hClose inn
 
388
    -- The handles should be in text mode.
 
389
    hSetBinaryMode out False
 
390
    hSetBinaryMode err False
 
391
 
 
392
  -- GHC seems to use stderr for progress reports.
 
393
  s <- liftIO $ join <$> LocIO.hGetContents err <*> LocIO.hGetContents out
 
394
  reportSLn "" 1 s
 
395
 
 
396
  exitcode <- liftIO $ do
 
397
    -- Ensure that the output has been read before waiting for the
 
398
    -- process.
 
399
    E.evaluate (length s)
 
400
    waitForProcess p
312
401
  case exitcode of
313
 
    ExitFailure _ -> typeError $ CompilationError $ out ++ "\n" ++ err
 
402
    ExitFailure _ -> typeError (CompilationError s)
314
403
    _             -> return ()
 
404
 
 
405
  where
 
406
  -- Note that this function returns s1 before inspecting its input.
 
407
  join s1 s2 =
 
408
    s1 ++ (if L.null s1 || last s1 == '\n' then "" else "\n") ++ s2