summaryrefslogtreecommitdiff
path: root/src/GF/Compile/ModDeps.hs
blob: 2aa042a95fd530299bf6a7796165830c262f6d74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
module ModDeps where

import Grammar
import Ident
import Option
import PrGrammar
import Update
import Lookup
import Modules

import Operations

import Monad

-- AR 13/5/2003

-- to check uniqueness of module names and import names, the
-- appropriateness of import and extend types,
-- to build a dependency graph of modules, and to sort them topologically

mkSourceGrammar :: [(Ident,SourceModInfo)] -> Err SourceGrammar
mkSourceGrammar ms = do
  let ns = map fst ms
  checkUniqueErr ns
  mapM (checkUniqueImportNames ns . snd) ms
  deps    <- moduleDeps ms
  deplist <- either 
               return 
               (\ms -> Bad $ "circular modules" +++ unwords (map show ms)) $ 
               topoTest deps
  return $ MGrammar [(m, maybe undefined id $ lookup m ms)  | IdentM m _ <- deplist]

checkUniqueErr ::  (Show i, Eq i) => [i] -> Err ()
checkUniqueErr ms = do
  let msg = checkUnique ms
  if null msg then return () else Bad $ unlines msg

-- check that import names don't clash with module names

checkUniqueImportNames :: [Ident] -> SourceModInfo -> Err ()
checkUniqueImportNames ns mo = case mo of
  ModMod m -> test [n | OQualif n v <- opens m, n /= v]

 where

  test ms = testErr (all (`notElem` ns) ms)
                    ("import names clashing with module names among" +++ 
                       unwords (map prt ms))

-- to decide what modules immediately depend on what, and check if the
-- dependencies are appropriate

type Dependencies = [(IdentM Ident,[IdentM Ident])]

moduleDeps :: [(Ident,SourceModInfo)] -> Err Dependencies
moduleDeps ms = mapM deps ms where
  deps (c,mi) = errIn ("checking dependencies of module" +++ prt c) $ case mi of
    ModMod m -> case mtype m of
      MTConcrete a -> do
        aty <- lookupModuleType gr a
        testErr (aty == MTAbstract) "the for-module is not an abstract syntax" 
        chDep (IdentM c (MTConcrete a)) 
              (extends m) (MTConcrete a) (opens m) MTResource
      t -> chDep (IdentM c t) (extends m) t (opens m) t

  chDep it es ety os oty = do
    ests <- case es of
      Just e -> liftM singleton $ lookupModuleType gr e
      _ -> return []
    testErr (all (compatMType ety) ests) "inappropriate extension module type" 
    osts <- mapM (lookupModuleType gr . openedModule) os
    testErr (all (==oty) osts) "inappropriate open module type"
    let ab = case it of
               IdentM _ (MTConcrete a) -> [IdentM a MTAbstract]
               _ -> [] ---- 
    return (it, ab ++
                [IdentM e ety | Just e <- [es]] ++ 
                [IdentM (openedModule o) oty | o <- os])

  -- check for superficial compatibility, not submodule relation etc
  compatMType mt0 mt = case (mt0,mt) of
    (MTConcrete _, MTConcrete _) -> True
    (MTResourceImpl _, MTResourceImpl _) -> True
    (MTReuse _, MTReuse _) -> True
    ---- some more
    _ -> mt0 == mt

  gr = MGrammar ms --- hack