summaryrefslogtreecommitdiff
path: root/src-3.0/GF/Compile
diff options
context:
space:
mode:
authoraarne <aarne@cs.chalmers.se>2008-05-21 09:26:44 +0000
committeraarne <aarne@cs.chalmers.se>2008-05-21 09:26:44 +0000
commit055c0d0d5a5bb0dc75904fe53df7f2e4f5732a8f (patch)
tree0e63fb68c69c8f6ad0f78893c63420f0a3600e1c /src-3.0/GF/Compile
parent915a1de71783ab8446b1af9e72c7ba7dfbc12d3f (diff)
GF/src is now for 2.9, and the new sources are in src-3.0 - keep it this way until the release of GF 3
Diffstat (limited to 'src-3.0/GF/Compile')
-rw-r--r--src-3.0/GF/Compile/API.hs21
-rw-r--r--src-3.0/GF/Compile/BackOpt.hs141
-rw-r--r--src-3.0/GF/Compile/CheckGrammar.hs1078
-rw-r--r--src-3.0/GF/Compile/Compile.hs401
-rw-r--r--src-3.0/GF/Compile/Evaluate.hs477
-rw-r--r--src-3.0/GF/Compile/Extend.hs136
-rw-r--r--src-3.0/GF/Compile/Flatten.hs92
-rw-r--r--src-3.0/GF/Compile/GetGrammar.hs146
-rw-r--r--src-3.0/GF/Compile/GrammarToCanon.hs293
-rw-r--r--src-3.0/GF/Compile/MkConcrete.hs154
-rw-r--r--src-3.0/GF/Compile/MkResource.hs128
-rw-r--r--src-3.0/GF/Compile/MkUnion.hs83
-rw-r--r--src-3.0/GF/Compile/ModDeps.hs153
-rw-r--r--src-3.0/GF/Compile/NewRename.hs294
-rw-r--r--src-3.0/GF/Compile/NoParse.hs49
-rw-r--r--src-3.0/GF/Compile/Optimize.hs300
-rw-r--r--src-3.0/GF/Compile/PGrammar.hs77
-rw-r--r--src-3.0/GF/Compile/PrOld.hs84
-rw-r--r--src-3.0/GF/Compile/Rebuild.hs99
-rw-r--r--src-3.0/GF/Compile/RemoveLiT.hs63
-rw-r--r--src-3.0/GF/Compile/Rename.hs338
-rw-r--r--src-3.0/GF/Compile/ShellState.hs568
-rw-r--r--src-3.0/GF/Compile/Update.hs135
-rw-r--r--src-3.0/GF/Compile/Wordlist.hs108
24 files changed, 5418 insertions, 0 deletions
diff --git a/src-3.0/GF/Compile/API.hs b/src-3.0/GF/Compile/API.hs
new file mode 100644
index 000000000..242a9e87a
--- /dev/null
+++ b/src-3.0/GF/Compile/API.hs
@@ -0,0 +1,21 @@
+module GF.Compile.API (batchCompile, compileToGFCC) where
+
+import GF.Devel.Compile
+import GF.Devel.GrammarToGFCC
+import GF.GFCC.OptimizeGFCC
+import GF.GFCC.CheckGFCC
+import GF.GFCC.DataGFCC
+import GF.Infra.Option
+import GF.Devel.UseIO
+
+-- | Compiles a number of source files and builds a 'GFCC' structure for them.
+compileToGFCC :: Options -> [FilePath] -> IOE GFCC
+compileToGFCC opts fs =
+ do gr <- batchCompile opts fs
+ let name = justModuleName (last fs)
+ gc1 <- putPointE opts "linking ... " $
+ let (abs,gc0) = mkCanon2gfcc opts name gr
+ in ioeIO $ checkGFCCio gc0
+ let opt = if oElem (iOpt "noopt") opts then id else optGFCC
+ par = if oElem (iOpt "noparse") opts then id else addParsers
+ return (par (opt gc1))
diff --git a/src-3.0/GF/Compile/BackOpt.hs b/src-3.0/GF/Compile/BackOpt.hs
new file mode 100644
index 000000000..8356f2ba2
--- /dev/null
+++ b/src-3.0/GF/Compile/BackOpt.hs
@@ -0,0 +1,141 @@
+----------------------------------------------------------------------
+-- |
+-- Module : BackOpt
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:21:33 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.6 $
+--
+-- Optimizations on GF source code: sharing, parametrization, value sets.
+--
+-- optimization: sharing branches in tables. AR 25\/4\/2003.
+-- following advice of Josef Svenningsson
+-----------------------------------------------------------------------------
+
+module GF.Compile.BackOpt (shareModule, OptSpec, shareOpt, paramOpt, valOpt, allOpt) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import qualified GF.Grammar.Macros as C
+import GF.Grammar.PrGrammar (prt)
+import GF.Data.Operations
+import Data.List
+import qualified GF.Infra.Modules as M
+
+type OptSpec = [Integer] ---
+
+doOptFactor :: OptSpec -> Bool
+doOptFactor opt = elem 2 opt
+
+doOptValues :: OptSpec -> Bool
+doOptValues opt = elem 3 opt
+
+shareOpt :: OptSpec
+shareOpt = []
+
+paramOpt :: OptSpec
+paramOpt = [2]
+
+valOpt :: OptSpec
+valOpt = [3]
+
+allOpt :: OptSpec
+allOpt = [2,3]
+
+shareModule :: OptSpec -> (Ident, SourceModInfo) -> (Ident, SourceModInfo)
+shareModule opt (i,m) = case m of
+ M.ModMod (M.Module mt st fs me ops js) ->
+ (i,M.ModMod (M.Module mt st fs me ops (mapTree (shareInfo opt) js)))
+ _ -> (i,m)
+
+shareInfo opt (c, CncCat ty (Yes t) m) = (c,CncCat ty (Yes (shareOptim opt c t)) m)
+shareInfo opt (c, CncFun kxs (Yes t) m) = (c,CncFun kxs (Yes (shareOptim opt c t)) m)
+shareInfo opt (c, ResOper ty (Yes t)) = (c,ResOper ty (Yes (shareOptim opt c t)))
+shareInfo _ i = i
+
+-- the function putting together optimizations
+shareOptim :: OptSpec -> Ident -> Term -> Term
+shareOptim opt c
+ | doOptFactor opt && doOptValues opt = values . factor c 0
+ | doOptFactor opt = share . factor c 0
+ | doOptValues opt = values
+ | otherwise = share
+
+-- we need no counter to create new variable names, since variables are
+-- local to tables (only true in GFC) ---
+
+share :: Term -> Term
+share t = case t of
+ T ty@(TComp _) cs -> shareT ty [(p, share v) | (p, v) <- cs]
+ _ -> C.composSafeOp share t
+
+ where
+ shareT ty = finalize ty . groupC . sortC
+
+ sortC :: [(Patt,Term)] -> [(Patt,Term)]
+ sortC = sortBy $ \a b -> compare (snd a) (snd b)
+
+ groupC :: [(Patt,Term)] -> [[(Patt,Term)]]
+ groupC = groupBy $ \a b -> snd a == snd b
+
+ finalize :: TInfo -> [[(Patt,Term)]] -> Term
+ finalize ty css = TSh ty [(map fst ps, t) | ps@((_,t):_) <- css]
+
+-- do even more: factor parametric branches
+
+factor :: Ident -> Int -> Term -> Term
+factor c i t = case t of
+ T _ [_] -> t
+ T _ [] -> t
+ T (TComp ty) cs ->
+ T (TTyped ty) $ factors i [(p, factor c (i+1) v) | (p, v) <- cs]
+ _ -> C.composSafeOp (factor c i) t
+ where
+
+ factors i psvs = -- we know psvs has at least 2 elements
+ let p = qqIdent c i
+ vs' = map (mkFun p) psvs
+ in if allEqs vs'
+ then mkCase p vs'
+ else psvs
+
+ mkFun p (patt, val) = replace (C.patt2term patt) (Vr p) val
+
+ allEqs (v:vs) = all (==v) vs
+
+ mkCase p (v:_) = [(PV p, v)]
+
+--- we hope this will be fresh and don't check... in GFC would be safe
+
+qqIdent c i = identC ("q_" ++ prt c ++ "__" ++ show i)
+
+
+-- we need to replace subterms
+
+replace :: Term -> Term -> Term -> Term
+replace old new trm = case trm of
+
+ -- these are the important cases, since they can correspond to patterns
+ QC _ _ | trm == old -> new
+ App t ts | trm == old -> new
+ App t ts -> App (repl t) (repl ts)
+ R _ | isRec && trm == old -> new
+ _ -> C.composSafeOp repl trm
+ where
+ repl = replace old new
+ isRec = case trm of
+ R _ -> True
+ _ -> False
+
+-- It is very important that this is performed only after case
+-- expansion since otherwise the order and number of values can
+-- be incorrect. Guaranteed by the TComp flag.
+
+values :: Term -> Term
+values t = case t of
+ T ty [(ps,t)] -> T ty [(ps,values t)] -- don't destroy parametrization
+ T (TComp ty) cs -> V ty [values t | (_, t) <- cs]
+ _ -> C.composSafeOp values t
diff --git a/src-3.0/GF/Compile/CheckGrammar.hs b/src-3.0/GF/Compile/CheckGrammar.hs
new file mode 100644
index 000000000..b33d11017
--- /dev/null
+++ b/src-3.0/GF/Compile/CheckGrammar.hs
@@ -0,0 +1,1078 @@
+----------------------------------------------------------------------
+-- |
+-- Module : CheckGrammar
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/11 23:24:33 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.31 $
+--
+-- AR 4\/12\/1999 -- 1\/4\/2000 -- 8\/9\/2001 -- 15\/5\/2002 -- 27\/11\/2002 -- 18\/6\/2003
+--
+-- type checking also does the following modifications:
+--
+-- - types of operations and local constants are inferred and put in place
+--
+-- - both these types and linearization types are computed
+--
+-- - tables are type-annotated
+-----------------------------------------------------------------------------
+
+module GF.Compile.CheckGrammar (
+ showCheckModule, justCheckLTerm, allOperDependencies, topoSortOpers) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Grammar.Refresh ----
+
+import GF.Grammar.TypeCheck
+import GF.Grammar.Values (cPredefAbs) ---
+
+import GF.Grammar.PrGrammar
+import GF.Grammar.Lookup
+import GF.Grammar.LookAbs
+import GF.Grammar.Macros
+import GF.Grammar.ReservedWords ----
+import GF.Grammar.PatternMatch
+import GF.Grammar.AppPredefined
+import GF.Grammar.Lockfield (isLockLabel)
+
+import GF.Data.Operations
+import GF.Infra.CheckM
+
+import Data.List
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+import Control.Monad
+import Debug.Trace ---
+
+
+showCheckModule :: [SourceModule] -> SourceModule -> Err ([SourceModule],String)
+showCheckModule mos m = do
+ (st,(_,msg)) <- checkStart $ checkModule mos m
+ return (st, unlines $ reverse msg)
+
+-- | checking is performed in the dependency order of modules
+checkModule :: [SourceModule] -> SourceModule -> Check [SourceModule]
+checkModule ms (name,mod) = checkIn ("checking module" +++ prt name) $ case mod of
+
+ ModMod mo@(Module mt st fs me ops js) -> do
+ checkRestrictedInheritance ms (name, mo)
+ js' <- case mt of
+ MTAbstract -> mapMTree (checkAbsInfo gr name) js
+
+ MTTransfer a b -> mapMTree (checkAbsInfo gr name) js
+
+ MTResource -> mapMTree (checkResInfo gr name) js
+
+ MTConcrete a -> do
+ checkErr $ topoSortOpers $ allOperDependencies name js
+ ModMod abs <- checkErr $ lookupModule gr a
+ js1 <- checkCompleteGrammar abs mo
+ mapMTree (checkCncInfo gr name (a,abs)) js1
+
+ MTInterface -> mapMTree (checkResInfo gr name) js
+
+ MTInstance a -> do
+ ModMod abs <- checkErr $ lookupModule gr a
+ -- checkCompleteInstance abs mo -- this is done in Rebuild
+ mapMTree (checkResInfo gr name) js
+
+ return $ (name, ModMod (Module mt st fs me ops js')) : ms
+
+ _ -> return $ (name,mod) : ms
+ where
+ gr = MGrammar $ (name,mod):ms
+
+-- check if restricted inheritance modules are still coherent
+-- i.e. that the defs of remaining names don't depend on omitted names
+---checkRestrictedInheritance :: [SourceModule] -> SourceModule -> Check ()
+checkRestrictedInheritance mos (name,mo) = do
+ let irs = [ii | ii@(_,mi) <- extend mo, mi /= MIAll] -- names with restr. inh.
+ let mrs = [((i,m),mi) | (i,ModMod m) <- mos, Just mi <- [lookup i irs]]
+ -- the restr. modules themself, with restr. infos
+ mapM_ checkRem mrs
+ where
+ checkRem ((i,m),mi) = do
+ let (incl,excl) = partition (isInherited mi) (map fst (tree2list (jments m)))
+ let incld c = Set.member c (Set.fromList incl)
+ let illegal c = Set.member c (Set.fromList excl)
+ let illegals = [(f,is) |
+ (f,cs) <- allDeps, incld f, let is = filter illegal cs, not (null is)]
+ case illegals of
+ [] -> return ()
+ cs -> fail $ "In inherited module" +++ prt i ++
+ ", dependence of excluded constants:" ++++
+ unlines [" " ++ prt f +++ "on" +++ unwords (map prt is) |
+ (f,is) <- cs]
+ allDeps = ---- transClosure $ Map.fromList $
+ concatMap (allDependencies (const True))
+ [jments m | (_,ModMod m) <- mos]
+ transClosure ds = ds ---- TODO: check in deeper modules
+
+-- | check if a term is typable
+justCheckLTerm :: SourceGrammar -> Term -> Err Term
+justCheckLTerm src t = do
+ ((t',_),_) <- checkStart (inferLType src t)
+ return t'
+
+checkAbsInfo :: SourceGrammar -> Ident -> (Ident,Info) -> Check (Ident,Info)
+checkAbsInfo st m (c,info) = do
+---- checkReservedId c
+ case info of
+ AbsCat (Yes cont) _ -> mkCheck "category" $
+ checkContext st cont ---- also cstrs
+ AbsFun (Yes typ0) md -> do
+ typ <- compAbsTyp [] typ0 -- to calculate let definitions
+ mkCheck "type of function" $ checkTyp st typ
+ md' <- case md of
+ Yes d -> do
+ let d' = elimTables d
+ mkCheckWarn "definition of function" $ checkEquation st (m,c) d'
+ return $ Yes d'
+ _ -> return md
+ return $ (c,AbsFun (Yes typ) md')
+ _ -> return (c,info)
+ where
+ mkCheck cat ss = case ss of
+ [] -> return (c,info)
+ ["[]"] -> return (c,info) ----
+ _ -> checkErr $ prtBad (unlines ss ++++ "in" +++ cat) c
+ ---- temporary solution when tc of defs is incomplete
+ mkCheckWarn cat ss = case ss of
+ [] -> return (c,info)
+ ["[]"] -> return (c,info) ----
+ _ -> checkWarn (unlines ss ++++ "in" +++ cat +++ prt c) >> return (c,info)
+ compAbsTyp g t = case t of
+ Vr x -> maybe (fail ("no value given to variable" +++ prt x)) return $ lookup x g
+ Let (x,(_,a)) b -> do
+ a' <- compAbsTyp g a
+ compAbsTyp ((x, a'):g) b
+ Prod x a b -> do
+ a' <- compAbsTyp g a
+ b' <- compAbsTyp ((x,Vr x):g) b
+ return $ Prod x a' b'
+ Abs _ _ -> return t
+ _ -> composOp (compAbsTyp g) t
+
+ elimTables e = case e of
+ S t a -> elimSel (elimTables t) (elimTables a)
+ T _ cs -> Eqs [(elimPatt p, elimTables t) | (p,t) <- cs]
+ _ -> composSafeOp elimTables e
+ elimPatt p = case p of
+ PR lps -> map snd lps
+ _ -> [p]
+ elimSel t a = case a of
+ R fs -> mkApp t (map (snd . snd) fs)
+ _ -> mkApp t [a]
+
+checkCompleteGrammar :: SourceAbs -> SourceCnc -> Check (BinTree Ident Info)
+checkCompleteGrammar abs cnc = do
+ let js = jments cnc
+ let fs = tree2list $ jments abs
+ foldM checkOne js fs
+ where
+ checkOne js i@(c,info) = case info of
+ AbsFun (Yes _) _ -> case lookupIdent c js of
+ Ok _ -> return js
+ _ -> do
+ checkWarn $ "WARNING: no linearization of" +++ prt c
+ return js
+ AbsCat (Yes _) _ -> case lookupIdent c js of
+ Ok (AnyInd _ _) -> return js
+ Ok (CncCat (Yes _) _ _) -> return js
+ Ok (CncCat _ mt mp) -> do
+ checkWarn $
+ "Warning: no linearization type for" +++ prt c ++
+ ", inserting default {s : Str}"
+ return $ updateTree (c,CncCat (Yes defLinType) mt mp) js
+ _ -> do
+ checkWarn $
+ "Warning: no linearization type for" +++ prt c ++
+ ", inserting default {s : Str}"
+ return $ updateTree (c,CncCat (Yes defLinType) nope nope) js
+ _ -> return js
+
+-- | General Principle: only Yes-values are checked.
+-- A May-value has always been checked in its origin module.
+checkResInfo :: SourceGrammar -> Ident -> (Ident,Info) -> Check (Ident,Info)
+checkResInfo gr mo (c,info) = do
+ checkReservedId c
+ case info of
+ ResOper pty pde -> chIn "operation" $ do
+ (pty', pde') <- case (pty,pde) of
+ (Yes ty, Yes de) -> do
+ ty' <- check ty typeType >>= comp . fst
+ (de',_) <- check de ty'
+ return (Yes ty', Yes de')
+ (_, Yes de) -> do
+ (de',ty') <- infer de
+ return (Yes ty', Yes de')
+ (_,Nope) -> do
+ checkWarn "No definition given to oper"
+ return (pty,pde)
+ _ -> return (pty, pde) --- other cases are uninteresting
+ return (c, ResOper pty' pde')
+
+ ResOverload tysts -> chIn "overloading" $ do
+ tysts' <- mapM (uncurry $ flip check) tysts
+ let tysts2 = [(y,x) | (x,y) <- tysts']
+ --- this can only be a partial guarantee, since matching
+ --- with value type is only possible if expected type is given
+ checkUniq $
+ sort [t : map snd xs | (x,_) <- tysts2, Ok (xs,t) <- [typeFormCnc x]]
+ return (c,ResOverload tysts2)
+
+ ResParam (Yes (pcs,_)) -> chIn "parameter type" $ do
+---- mapM ((mapM (computeLType gr . snd)) . snd) pcs
+ mapM_ ((mapM_ (checkIfParType gr . snd)) . snd) pcs
+ ts <- checkErr $ lookupParamValues gr mo c
+ return (c,ResParam (Yes (pcs, Just ts)))
+
+ _ -> return (c,info)
+ where
+ infer = inferLType gr
+ check = checkLType gr
+ chIn cat = checkIn ("Happened in" +++ cat +++ prt c +++ ":")
+ comp = computeLType gr
+
+ checkUniq xss = case xss of
+ x:y:xs
+ | x == y -> raise $ "ambiguous for argument list" +++
+ unwords (map (prtType gr) x)
+ | otherwise -> checkUniq $ y:xs
+ _ -> return ()
+
+
+checkCncInfo :: SourceGrammar -> Ident -> (Ident,SourceAbs) ->
+ (Ident,Info) -> Check (Ident,Info)
+checkCncInfo gr m (a,abs) (c,info) = do
+ checkReservedId c
+ case info of
+
+ CncFun _ (Yes trm) mpr -> chIn "linearization of" $ do
+ typ <- checkErr $ lookupFunTypeSrc gr a c
+ cat0 <- checkErr $ valCat typ
+ (cont,val) <- linTypeOfType gr m typ -- creates arg vars
+ (trm',_) <- check trm (mkFunType (map snd cont) val) -- erases arg vars
+ checkPrintname gr mpr
+ cat <- return $ snd cat0
+ return (c, CncFun (Just (cat,(cont,val))) (Yes trm') mpr)
+ -- cat for cf, typ for pe
+
+ CncCat (Yes typ) mdef mpr -> chIn "linearization type of" $ do
+ checkErr $ lookupCatContextSrc gr a c
+ typ' <- checkIfLinType gr typ
+ mdef' <- case mdef of
+ Yes def -> do
+ (def',_) <- checkLType gr def (mkFunType [typeStr] typ)
+ return $ Yes def'
+ _ -> return mdef
+ checkPrintname gr mpr
+ return (c,CncCat (Yes typ') mdef' mpr)
+
+ _ -> checkResInfo gr m (c,info)
+
+ where
+ env = gr
+ infer = inferLType gr
+ comp = computeLType gr
+ check = checkLType gr
+ chIn cat = checkIn ("Happened in" +++ cat +++ prt c +++ ":")
+
+checkIfParType :: SourceGrammar -> Type -> Check ()
+checkIfParType st typ = checkCond ("Not parameter type" +++ prt typ) (isParType typ)
+ where
+ isParType ty = True ----
+{- case ty of
+ Cn typ -> case lookupConcrete st typ of
+ Ok (CncParType _ _ _) -> True
+ Ok (CncOper _ ty' _) -> isParType ty'
+ _ -> False
+ Q p t -> case lookupInPackage st (p,t) of
+ Ok (CncParType _ _ _) -> True
+ _ -> False
+ RecType r -> all (isParType . snd) r
+ _ -> False
+-}
+
+checkIfStrType :: SourceGrammar -> Type -> Check ()
+checkIfStrType st typ = case typ of
+ Table arg val -> do
+ checkIfParType st arg
+ checkIfStrType st val
+ _ | typ == typeStr -> return ()
+ _ -> prtFail "not a string type" typ
+
+
+checkIfLinType :: SourceGrammar -> Type -> Check Type
+checkIfLinType st typ0 = do
+ typ <- computeLType st typ0
+ case typ of
+ RecType r -> do
+ let (lins,ihs) = partition (isLinLabel .fst) r
+ --- checkErr $ checkUnique $ map fst r
+ mapM_ checkInh ihs
+ mapM_ checkLin lins
+ _ -> prtFail "a linearization type must be a record type instead of" typ
+ return typ
+
+ where
+ checkInh (label,typ) = checkIfParType st typ
+ checkLin (label,typ) = return () ---- checkIfStrType st typ
+
+
+computeLType :: SourceGrammar -> Type -> Check Type
+computeLType gr t = do
+ g0 <- checkGetContext
+ let g = [(x, Vr x) | (x,_) <- g0]
+ checkInContext g $ comp t
+ where
+ comp ty = case ty of
+
+ App (Q (IC "Predef") (IC "Ints")) _ -> return ty ---- shouldn't be needed
+ Q (IC "Predef") (IC "Int") -> return ty ---- shouldn't be needed
+ Q (IC "Predef") (IC "Float") -> return ty ---- shouldn't be needed
+ Q (IC "Predef") (IC "Error") -> return ty ---- shouldn't be needed
+
+ Q m c | elem c [cPredef,cPredefAbs] -> return ty
+ Q m c | elem c [zIdent "Int"] ->
+ return $ linTypeInt
+ Q m c | elem c [zIdent "Float",zIdent "String"] -> return defLinType ----
+
+ Q m ident -> checkIn ("module" +++ prt m) $ do
+ ty' <- checkErr (lookupResDef gr m ident)
+ if ty' == ty then return ty else comp ty' --- is this necessary to test?
+
+ Vr ident -> checkLookup ident -- never needed to compute!
+
+ App f a -> do
+ f' <- comp f
+ a' <- comp a
+ case f' of
+ Abs x b -> checkInContext [(x,a')] $ comp b
+ _ -> return $ App f' a'
+
+ Prod x a b -> do
+ a' <- comp a
+ b' <- checkInContext [(x,Vr x)] $ comp b
+ return $ Prod x a' b'
+
+ Abs x b -> do
+ b' <- checkInContext [(x,Vr x)] $ comp b
+ return $ Abs x b'
+
+ ExtR r s -> do
+ r' <- comp r
+ s' <- comp s
+ case (r',s') of
+ (RecType rs, RecType ss) -> checkErr (plusRecType r' s') >>= comp
+ _ -> return $ ExtR r' s'
+
+ RecType fs -> do
+ let fs' = sortBy (\x y -> compare (fst x) (fst y)) fs
+ liftM RecType $ mapPairsM comp fs'
+
+ _ | ty == typeTok -> return typeStr
+ _ | isPredefConstant ty -> return ty
+
+ _ -> composOp comp ty
+
+checkPrintname :: SourceGrammar -> Perh Term -> Check ()
+checkPrintname st (Yes t) = checkLType st t typeStr >> return ()
+checkPrintname _ _ = return ()
+
+-- | for grammars obtained otherwise than by parsing ---- update!!
+checkReservedId :: Ident -> Check ()
+checkReservedId x = let c = prt x in
+ if isResWord c
+ then checkWarn ("Warning: reserved word used as identifier:" +++ c)
+ else return ()
+
+-- to normalize records and record types
+labelIndex :: Type -> Label -> Int
+labelIndex ty lab = case ty of
+ RecType ts -> maybe (error ("label index" +++ prt lab)) id $ lookup lab $ labs ts
+ _ -> error $ "label index" +++ prt ty
+ where
+ labs ts = zip (map fst (sortBy (\ x y -> compare (fst x) (fst y)) ts)) [0..]
+
+-- the underlying algorithms
+
+inferLType :: SourceGrammar -> Term -> Check (Term, Type)
+inferLType gr trm = case trm of
+
+ Q m ident | isPredef m -> termWith trm $ checkErr (typPredefined ident)
+
+ Q m ident -> checks [
+ termWith trm $ checkErr (lookupResType gr m ident) >>= comp
+ ,
+ checkErr (lookupResDef gr m ident) >>= infer
+ ,
+{-
+ do
+ over <- getOverload gr Nothing trm
+ case over of
+ Just trty -> return trty
+ _ -> prtFail "not overloaded" trm
+ ,
+-}
+ prtFail "cannot infer type of constant" trm
+ ]
+
+ QC m ident | isPredef m -> termWith trm $ checkErr (typPredefined ident)
+
+ QC m ident -> checks [
+ termWith trm $ checkErr (lookupResType gr m ident) >>= comp
+ ,
+ checkErr (lookupResDef gr m ident) >>= infer
+ ,
+ prtFail "cannot infer type of canonical constant" trm
+ ]
+
+ Val ty i -> termWith trm $ return ty
+
+ Vr ident -> termWith trm $ checkLookup ident
+
+ Typed e t -> do
+ t' <- comp t
+ check e t'
+ return (e,t')
+
+ App f a -> do
+ over <- getOverload gr Nothing trm
+ case over of
+ Just trty -> return trty
+ _ -> do
+ (f',fty) <- infer f
+ fty' <- comp fty
+ case fty' of
+ Prod z arg val -> do
+ a' <- justCheck a arg
+ ty <- if isWildIdent z
+ then return val
+ else substituteLType [(z,a')] val
+ return (App f' a',ty)
+ _ -> raise ("function type expected for"+++
+ prt f +++"instead of" +++ prtType env fty)
+
+ S f x -> do
+ (f', fty) <- infer f
+ case fty of
+ Table arg val -> do
+ x'<- justCheck x arg
+ return (S f' x', val)
+ _ -> prtFail "table lintype expected for the table in" trm
+
+ P t i -> do
+ (t',ty) <- infer t --- ??
+ ty' <- comp ty
+----- let tr2 = PI t' i (labelIndex ty' i)
+ let tr2 = P t' i
+ termWith tr2 $ checkErr $ case ty' of
+ RecType ts -> maybeErr ("unknown label" +++ prt i +++ "in" +++ prt ty') $
+ lookup i ts
+ _ -> prtBad ("record type expected for" +++ prt t +++ "instead of") ty'
+ PI t i _ -> infer $ P t i
+
+ R r -> do
+ let (ls,fs) = unzip r
+ fsts <- mapM inferM fs
+ let ts = [ty | (Just ty,_) <- fsts]
+ checkCond ("cannot infer type of record"+++ prt trm) (length ts == length fsts)
+ return $ (R (zip ls fsts), RecType (zip ls ts))
+
+ T (TTyped arg) pts -> do
+ (_,val) <- checks $ map (inferCase (Just arg)) pts
+ check trm (Table arg val)
+ T (TComp arg) pts -> do
+ (_,val) <- checks $ map (inferCase (Just arg)) pts
+ check trm (Table arg val)
+ T ti pts -> do -- tries to guess: good in oper type inference
+ let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
+ case pts' of
+ [] -> prtFail "cannot infer table type of" trm
+---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
+ _ -> do
+ (arg,val) <- checks $ map (inferCase Nothing) pts'
+ check trm (Table arg val)
+ V arg pts -> do
+ (_,val) <- checks $ map infer pts
+ return (trm, Table arg val)
+
+ K s -> do
+ if elem ' ' s
+ then checkWarn ("WARNING: space in token \"" ++ s ++
+ "\". Lexical analysis may fail.")
+ else return ()
+ return (trm, typeStr)
+
+ EInt i -> return (trm, typeInt)
+
+ EFloat i -> return (trm, typeFloat)
+
+ Empty -> return (trm, typeStr)
+
+ C s1 s2 ->
+ check2 (flip justCheck typeStr) C s1 s2 typeStr
+
+ Glue s1 s2 ->
+ check2 (flip justCheck typeStr) Glue s1 s2 typeStr ---- typeTok
+
+---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
+ Strs (Cn (IC "#conflict") : ts) -> do
+ trace ("WARNING: unresolved constant, could be any of" +++ unwords (map prt ts)) (infer $ head ts)
+-- checkWarn ("WARNING: unresolved constant, could be any of" +++ unwords (map prt ts))
+-- infer $ head ts
+
+ Strs ts -> do
+ ts' <- mapM (\t -> justCheck t typeStr) ts
+ return (Strs ts', typeStrs)
+
+ Alts (t,aa) -> do
+ t' <- justCheck t typeStr
+ aa' <- flip mapM aa (\ (c,v) -> do
+ c' <- justCheck c typeStr
+ v' <- justCheck v typeStrs
+ return (c',v'))
+ return (Alts (t',aa'), typeStr)
+
+ RecType r -> do
+ let (ls,ts) = unzip r
+ ts' <- mapM (flip justCheck typeType) ts
+ return (RecType (zip ls ts'), typeType)
+
+ ExtR r s -> do
+ (r',rT) <- infer r
+ rT' <- comp rT
+ (s',sT) <- infer s
+ sT' <- comp sT
+
+ let trm' = ExtR r' s'
+ ---- trm' <- checkErr $ plusRecord r' s'
+ case (rT', sT') of
+ (RecType rs, RecType ss) -> do
+ rt <- checkErr $ plusRecType rT' sT'
+ check trm' rt ---- return (trm', rt)
+ _ | rT' == typeType && sT' == typeType -> return (trm', typeType)
+ _ -> prtFail "records or record types expected in" trm
+
+ Sort _ ->
+ termWith trm $ return typeType
+
+ Prod x a b -> do
+ a' <- justCheck a typeType
+ b' <- checkInContext [(x,a')] $ justCheck b typeType
+ return (Prod x a' b', typeType)
+
+ Table p t -> do
+ p' <- justCheck p typeType --- check p partype!
+ t' <- justCheck t typeType
+ return $ (Table p' t', typeType)
+
+ FV vs -> do
+ (_,ty) <- checks $ map infer vs
+--- checkIfComplexVariantType trm ty
+ check trm ty
+
+ _ -> prtFail "cannot infer lintype of" trm
+
+ where
+ env = gr
+ infer = inferLType env
+ comp = computeLType env
+
+ check = checkLType env
+
+ isPredef m = elem m [cPredef,cPredefAbs]
+
+ justCheck ty te = check ty te >>= return . fst
+
+ -- for record fields, which may be typed
+ inferM (mty, t) = do
+ (t', ty') <- case mty of
+ Just ty -> check ty t
+ _ -> infer t
+ return (Just ty',t')
+
+ inferCase mty (patt,term) = do
+ arg <- maybe (inferPatt patt) return mty
+ cont <- pattContext env arg patt
+ i <- checkUpdates cont
+ (_,val) <- infer term
+ checkResets i
+ return (arg,val)
+ isConstPatt p = case p of
+ PC _ ps -> True --- all isConstPatt ps
+ PP _ _ ps -> True --- all isConstPatt ps
+ PR ps -> all (isConstPatt . snd) ps
+ PT _ p -> isConstPatt p
+ PString _ -> True
+ PInt _ -> True
+ PFloat _ -> True
+ PChar -> True
+ PSeq p q -> isConstPatt p && isConstPatt q
+ PAlt p q -> isConstPatt p && isConstPatt q
+ PRep p -> isConstPatt p
+ PNeg p -> isConstPatt p
+ PAs _ p -> isConstPatt p
+ _ -> False
+
+ inferPatt p = case p of
+ PP q c ps | q /= cPredef -> checkErr $ lookupResType gr q c >>= valTypeCnc
+ PAs _ p -> inferPatt p
+ PNeg p -> inferPatt p
+ PAlt p q -> checks [inferPatt p, inferPatt q]
+ PSeq _ _ -> return $ typeStr
+ PChar -> return $ typeStr
+ PRep _ -> return $ typeStr
+ _ -> infer (patt2term p) >>= return . snd
+
+
+-- type inference: Nothing, type checking: Just t
+-- the latter permits matching with value type
+getOverload :: SourceGrammar -> Maybe Type -> Term -> Check (Maybe (Term,Type))
+getOverload env@gr mt t = case appForm t of
+ (f@(Q m c), ts) -> case lookupOverload gr m c of
+ Ok typs -> do
+ ttys <- mapM infer ts
+ v <- matchOverload f typs ttys
+ return $ Just v
+ _ -> return Nothing
+ _ -> return Nothing
+ where
+ infer = inferLType env
+ matchOverload f typs ttys = do
+ let (tts,tys) = unzip ttys
+ let vfs = lookupOverloadInstance tys typs
+
+ case [vf | vf@(v,f) <- vfs, matchVal mt v] of
+ [(val,fun)] -> return (mkApp fun tts, val)
+ [] -> raise $ "no overload instance of" +++ prt f +++
+ "for" +++ unwords (map (prtType env) tys) +++ "among" ++++
+ unlines [" " ++ unwords (map (prtType env) ty) | (ty,_) <- typs] ++
+ maybe [] (("with value type" +++) . prtType env) mt
+
+ ---- ++++ "DEBUG" +++ unwords (map show tys) +++ ";"
+ ---- ++++ unlines (map (show . fst) typs) ----
+
+ vfs' -> case [(v,f) | (v,f) <- vfs', noProd v] of
+ [(val,fun)] -> do
+ checkWarn $ "WARNING: overloading of" +++ prt f +++
+ "resolved by excluding partial applications:" ++++
+ unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
+ return (mkApp fun tts, val)
+
+ _ -> raise $ "ambiguous overloading of" +++ prt f +++
+ "for" +++ unwords (map (prtType env) tys) ++++ "with alternatives" ++++
+ unlines [prtType env ty | (ty,_) <- vfs']
+
+ matchVal mt v = elem mt ([Nothing,Just v] ++ unlocked) where
+ unlocked = case v of
+ RecType fs -> [Just $ RecType $ filter (not . isLockLabel . fst) fs]
+ _ -> []
+ ---- TODO: accept subtypes
+ ---- TODO: use a trie
+ lookupOverloadInstance tys typs =
+ [(mkFunType rest val, t) |
+ let lt = length tys,
+ (ty,(val,t)) <- typs, length ty >= lt,
+ let (pre,rest) = splitAt lt ty,
+ pre == tys
+ ]
+
+ noProd ty = case ty of
+ Prod _ _ _ -> False
+ _ -> True
+
+checkLType :: SourceGrammar -> Term -> Type -> Check (Term, Type)
+checkLType env trm typ0 = do
+
+ typ <- comp typ0
+
+ case trm of
+
+ Abs x c -> do
+ case typ of
+ Prod z a b -> do
+ checkUpdate (x,a)
+ (c',b') <- if isWildIdent z
+ then check c b
+ else do
+ b' <- checkIn "abs" $ substituteLType [(z,Vr x)] b
+ check c b'
+ checkReset
+ return $ (Abs x c', Prod x a b')
+ _ -> raise $ "product expected instead of" +++ prtType env typ
+
+ App f a -> do
+ over <- getOverload env (Just typ) trm
+ case over of
+ Just trty -> return trty
+ _ -> do
+ (trm',ty') <- infer trm
+ termWith trm' $ checkEq typ ty' trm'
+
+ Q _ _ -> do
+ over <- getOverload env (Just typ) trm
+ case over of
+ Just trty -> return trty
+ _ -> do
+ (trm',ty') <- infer trm
+ termWith trm' $ checkEq typ ty' trm'
+
+ T _ [] ->
+ prtFail "found empty table in type" typ
+ T _ cs -> case typ of
+ Table arg val -> do
+ case allParamValues env arg of
+ Ok vs -> do
+ let ps0 = map fst cs
+ ps <- checkErr $ testOvershadow ps0 vs
+ if null ps
+ then return ()
+ else checkWarn $ "WARNING: patterns never reached:" +++
+ concat (intersperse ", " (map prt ps))
+
+ _ -> return () -- happens with variable types
+ cs' <- mapM (checkCase arg val) cs
+ return (T (TTyped arg) cs', typ)
+ _ -> raise $ "table type expected for table instead of" +++ prtType env typ
+
+ R r -> case typ of --- why needed? because inference may be too difficult
+ RecType rr -> do
+ let (ls,_) = unzip rr -- labels of expected type
+ fsts <- mapM (checkM r) rr -- check that they are found in the record
+ return $ (R fsts, typ) -- normalize record
+
+ _ -> prtFail "record type expected in type checking instead of" typ
+
+ ExtR r s -> case typ of
+ _ | typ == typeType -> do
+ trm' <- comp trm
+ case trm' of
+ RecType _ -> termWith trm $ return typeType
+ ExtR (Vr _) (RecType _) -> termWith trm $ return typeType
+ -- ext t = t ** ...
+ _ -> prtFail "invalid record type extension" trm
+ RecType rr -> do
+ (r',ty,s') <- checks [
+ do (r',ty) <- infer r
+ return (r',ty,s)
+ ,
+ do (s',ty) <- infer s
+ return (s',ty,r)
+ ]
+ case ty of
+ RecType rr1 -> do
+ let (rr0,rr2) = recParts rr rr1
+ r2 <- justCheck r' rr0
+ s2 <- justCheck s' rr2
+ return $ (ExtR r2 s2, typ)
+ _ -> raise ("record type expected in extension of" +++ prt r +++
+ "but found" +++ prt ty)
+
+ ExtR ty ex -> do
+ r' <- justCheck r ty
+ s' <- justCheck s ex
+ return $ (ExtR r' s', typ) --- is this all?
+
+ _ -> prtFail "record extension not meaningful for" typ
+
+ FV vs -> do
+ ttys <- mapM (flip check typ) vs
+--- checkIfComplexVariantType trm typ
+ return (FV (map fst ttys), typ) --- typ' ?
+
+ S tab arg -> checks [ do
+ (tab',ty) <- infer tab
+ ty' <- comp ty
+ case ty' of
+ Table p t -> do
+ (arg',val) <- check arg p
+ checkEq typ t trm
+ return (S tab' arg', t)
+ _ -> raise $ "table type expected for applied table instead of" +++
+ prtType env ty'
+ , do
+ (arg',ty) <- infer arg
+ ty' <- comp ty
+ (tab',_) <- check tab (Table ty' typ)
+ return (S tab' arg', typ)
+ ]
+ Let (x,(mty,def)) body -> case mty of
+ Just ty -> do
+ (def',ty') <- check def ty
+ checkUpdate (x,ty')
+ body' <- justCheck body typ
+ checkReset
+ return (Let (x,(Just ty',def')) body', typ)
+ _ -> do
+ (def',ty) <- infer def -- tries to infer type of local constant
+ check (Let (x,(Just ty,def')) body) typ
+
+ _ -> do
+ (trm',ty') <- infer trm
+ termWith trm' $ checkEq typ ty' trm'
+ where
+ cnc = env
+ infer = inferLType env
+ comp = computeLType env
+
+ check = checkLType env
+
+ justCheck ty te = check ty te >>= return . fst
+
+ checkEq = checkEqLType env
+
+ recParts rr t = (RecType rr1,RecType rr2) where
+ (rr1,rr2) = partition (flip elem (map fst t) . fst) rr
+
+ checkM rms (l,ty) = case lookup l rms of
+ Just (Just ty0,t) -> do
+ checkEq ty ty0 t
+ (t',ty') <- check t ty
+ return (l,(Just ty',t'))
+ Just (_,t) -> do
+ (t',ty') <- check t ty
+ return (l,(Just ty',t'))
+ _ -> prtFail "cannot find value for label" l
+
+ checkCase arg val (p,t) = do
+ cont <- pattContext env arg p
+ i <- checkUpdates cont
+ t' <- justCheck t val
+ checkResets i
+ return (p,t')
+
+pattContext :: LTEnv -> Type -> Patt -> Check Context
+pattContext env typ p = case p of
+ PV x | not (isWildIdent x) -> return [(x,typ)]
+ PP q c ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
+ t <- checkErr $ lookupResType cnc q c
+ (cont,v) <- checkErr $ typeFormCnc t
+ checkCond ("wrong number of arguments for constructor in" +++ prt p)
+ (length cont == length ps)
+ checkEqLType env typ v (patt2term p)
+ mapM (uncurry (pattContext env)) (zip (map snd cont) ps) >>= return . concat
+ PR r -> do
+ typ' <- computeLType env typ
+ case typ' of
+ RecType t -> do
+ let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
+ ----- checkWarn $ prt p ++++ show pts ----- debug
+ mapM (uncurry (pattContext env)) pts >>= return . concat
+ _ -> prtFail "record type expected for pattern instead of" typ'
+ PT t p' -> do
+ checkEqLType env typ t (patt2term p')
+ pattContext env typ p'
+
+ PAs x p -> do
+ g <- pattContext env typ p
+ return $ (x,typ):g
+
+ PAlt p' q -> do
+ g1 <- pattContext env typ p'
+ g2 <- pattContext env typ q
+ let pts = [pt | pt <- g1, notElem pt g2] ++ [pt | pt <- g2, notElem pt g1]
+ checkCond
+ ("incompatible bindings of" +++
+ unwords (nub (map (prt . fst) pts))+++
+ "in pattern alterantives" +++ prt p) (null pts)
+ return g1 -- must be g1 == g2
+ PSeq p q -> do
+ g1 <- pattContext env typ p
+ g2 <- pattContext env typ q
+ return $ g1 ++ g2
+ PRep p' -> noBind typeStr p'
+ PNeg p' -> noBind typ p'
+
+ _ -> return [] ---- check types!
+ where
+ cnc = env
+ noBind typ p' = do
+ co <- pattContext env typ p'
+ if not (null co)
+ then checkWarn ("no variable bound inside pattern" +++ prt p)
+ >> return []
+ else return []
+
+-- auxiliaries
+
+type LTEnv = SourceGrammar
+
+termWith :: Term -> Check Type -> Check (Term, Type)
+termWith t ct = do
+ ty <- ct
+ return (t,ty)
+
+-- | light-weight substitution for dep. types
+substituteLType :: Context -> Type -> Check Type
+substituteLType g t = case t of
+ Vr x -> return $ maybe t id $ lookup x g
+ _ -> composOp (substituteLType g) t
+
+-- | compositional check\/infer of binary operations
+check2 :: (Term -> Check Term) -> (Term -> Term -> Term) ->
+ Term -> Term -> Type -> Check (Term,Type)
+check2 chk con a b t = do
+ a' <- chk a
+ b' <- chk b
+ return (con a' b', t)
+
+checkEqLType :: LTEnv -> Type -> Type -> Term -> Check Type
+checkEqLType env t u trm = do
+ (b,t',u',s) <- checkIfEqLType env t u trm
+ case b of
+ True -> return t'
+ False -> raise $ s +++ "type of" +++ prt trm +++
+ ": expected:" +++ prtType env t ++++
+ "inferred:" +++ prtType env u
+
+checkIfEqLType :: LTEnv -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
+checkIfEqLType env t u trm = do
+ t' <- comp t
+ u' <- comp u
+ case t' == u' || alpha [] t' u' of
+ True -> return (True,t',u',[])
+ -- forgive missing lock fields by only generating a warning.
+ --- better: use a flag to forgive? (AR 31/1/2006)
+ _ -> case missingLock [] t' u' of
+ Ok lo -> do
+ checkWarn $ "WARNING: missing lock field" +++ unwords (map prt lo)
+ return (True,t',u',[])
+ Bad s -> return (False,t',u',s)
+
+ where
+
+ -- t is a subtype of u
+ --- quick hack version of TC.eqVal
+ alpha g t u = case (t,u) of
+
+ -- error (the empty type!) is subtype of any other type
+ (_,Q (IC "Predef") (IC "Error")) -> True
+
+ -- contravariance
+ (Prod x a b, Prod y c d) -> alpha g c a && alpha ((x,y):g) b d
+
+ -- record subtyping
+ (RecType rs, RecType ts) -> all (\ (l,a) ->
+ any (\ (k,b) -> alpha g a b && l == k) ts) rs
+ (ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
+ (ExtR r s, t) -> alpha g r t || alpha g s t
+
+ -- the following say that Ints n is a subset of Int and of Ints m >= n
+ (App (Q (IC "Predef") (IC "Ints")) (EInt n),
+ App (Q (IC "Predef") (IC "Ints")) (EInt m)) -> m >= n
+ (App (Q (IC "Predef") (IC "Ints")) (EInt n),
+ Q (IC "Predef") (IC "Int")) -> True ---- check size!
+
+ (Q (IC "Predef") (IC "Int"), ---- why this ???? AR 11/12/2005
+ App (Q (IC "Predef") (IC "Ints")) (EInt n)) -> True
+
+ ---- this should be made in Rename
+ (Q m a, Q n b) | a == b -> elem m (allExtendsPlus env n)
+ || elem n (allExtendsPlus env m)
+ || m == n --- for Predef
+ (QC m a, QC n b) | a == b -> elem m (allExtendsPlus env n)
+ || elem n (allExtendsPlus env m)
+ (QC m a, Q n b) | a == b -> elem m (allExtendsPlus env n)
+ || elem n (allExtendsPlus env m)
+ (Q m a, QC n b) | a == b -> elem m (allExtendsPlus env n)
+ || elem n (allExtendsPlus env m)
+
+ (Table a b, Table c d) -> alpha g a c && alpha g b d
+ (Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
+ _ -> t == u
+ --- the following should be one-way coercions only. AR 4/1/2001
+ || elem t sTypes && elem u sTypes
+ || (t == typeType && u == typePType)
+ || (u == typeType && t == typePType)
+
+ missingLock g t u = case (t,u) of
+ (RecType rs, RecType ts) ->
+ let
+ ls = [l | (l,a) <- rs,
+ not (any (\ (k,b) -> alpha g a b && l == k) ts)]
+ (locks,others) = partition isLockLabel ls
+ in case others of
+ _:_ -> Bad $ "missing record fields" +++ unwords (map prt others)
+ _ -> return locks
+ -- contravariance
+ (Prod x a b, Prod y c d) -> do
+ ls1 <- missingLock g c a
+ ls2 <- missingLock g b d
+ return $ ls1 ++ ls2
+
+ _ -> Bad ""
+
+ sTypes = [typeStr, typeTok, typeString]
+ comp = computeLType env
+
+-- printing a type with a lock field lock_C as C
+prtType :: LTEnv -> Type -> String
+prtType env ty = case ty of
+ RecType fs -> case filter isLockLabel $ map fst fs of
+ [lock] -> (drop 5 $ prt lock) --- ++++ "Full form" +++ prt ty
+ _ -> prtt ty
+ Prod x a b -> prtType env a +++ "->" +++ prtType env b
+ _ -> prtt ty
+ where
+ prtt t = prt t
+ ---- use computeLType gr to check if really equal to the cat with lock
+
+
+-- | linearization types and defaults
+linTypeOfType :: SourceGrammar -> Ident -> Type -> Check (Context,Type)
+linTypeOfType cnc m typ = do
+ (cont,cat) <- checkErr $ typeSkeleton typ
+ val <- lookLin cat
+ args <- mapM mkLinArg (zip [0..] cont)
+ return (args, val)
+ where
+ mkLinArg (i,(n,mc@(m,cat))) = do
+ val <- lookLin mc
+ let vars = mkRecType varLabel $ replicate n typeStr
+ symb = argIdent n cat i
+ rec <- checkErr $ errIn ("extending" +++ prt vars +++ "with" +++ prt val) $
+ plusRecType vars val
+ return (symb,rec)
+ lookLin (_,c) = checks [ --- rather: update with defLinType ?
+ checkErr (lookupLincat cnc m c) >>= computeLType cnc
+ ,return defLinType
+ ]
+
+-- | dependency check, detecting circularities and returning topo-sorted list
+
+allOperDependencies :: Ident -> BinTree Ident Info -> [(Ident,[Ident])]
+allOperDependencies m = allDependencies (==m)
+
+allDependencies :: (Ident -> Bool) -> BinTree Ident Info -> [(Ident,[Ident])]
+allDependencies ism b =
+ [(f, nub (concatMap opty (pts i))) | (f,i) <- tree2list b]
+ where
+ opersIn t = case t of
+ Q n c | ism n -> [c]
+ QC n c | ism n -> [c]
+ _ -> collectOp opersIn t
+ opty (Yes ty) = opersIn ty
+ opty _ = []
+ pts i = case i of
+ ResOper pty pt -> [pty,pt]
+ ResParam (Yes (ps,_)) -> [Yes t | (_,cont) <- ps, (_,t) <- cont]
+ CncCat pty _ _ -> [pty]
+ CncFun _ pt _ -> [pt] ---- (Maybe (Ident,(Context,Type))
+ AbsFun pty ptr -> [pty] --- ptr is def, which can be mutual
+ AbsCat (Yes co) _ -> [Yes ty | (_,ty) <- co]
+ _ -> []
+
+topoSortOpers :: [(Ident,[Ident])] -> Err [Ident]
+topoSortOpers st = do
+ let eops = topoTest st
+ either
+ return
+ (\ops -> Bad ("circular definitions:" +++ unwords (map prt (head ops))))
+ eops
diff --git a/src-3.0/GF/Compile/Compile.hs b/src-3.0/GF/Compile/Compile.hs
new file mode 100644
index 000000000..422df0fd5
--- /dev/null
+++ b/src-3.0/GF/Compile/Compile.hs
@@ -0,0 +1,401 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Compile
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/10/05 20:02:19 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.45 $
+--
+-- The top-level compilation chain from source file to gfc\/gfr.
+-----------------------------------------------------------------------------
+
+module GF.Compile.Compile (compileModule, compileEnvShSt, compileOne,
+ CompileEnv, TimedCompileEnv,gfGrammarPathVar,pathListOpts,
+ getGFEFiles) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Option
+import GF.Infra.CompactPrint
+import GF.Grammar.PrGrammar
+import GF.Compile.Update
+import GF.Grammar.Lookup
+import GF.Infra.Modules
+import GF.Infra.ReadFiles
+import GF.Compile.ShellState
+import GF.Compile.MkResource
+---- import MkUnion
+
+-- the main compiler passes
+import GF.Compile.GetGrammar
+import GF.Compile.Extend
+import GF.Compile.Rebuild
+import GF.Compile.Rename
+import GF.Grammar.Refresh
+import GF.Compile.CheckGrammar
+import GF.Compile.Optimize
+import GF.Compile.Evaluate
+import GF.Compile.GrammarToCanon
+--import GF.Devel.GrammarToGFCC -----
+import GF.Devel.OptimizeGF (subexpModule,unsubexpModule)
+import GF.Canon.Share
+import GF.Canon.Subexpressions (elimSubtermsMod,unSubelimModule)
+import GF.UseGrammar.Linear (unoptimizeCanonMod) ----
+
+import qualified GF.Canon.CanonToGrammar as CG
+
+import qualified GF.Canon.GFC as GFC
+import qualified GF.Canon.MkGFC as MkGFC
+import GF.Canon.GetGFC
+
+import GF.Data.Operations
+import GF.Infra.UseIO
+import GF.Text.UTF8 ----
+import GF.System.Arch
+
+import Control.Monad
+import System.Directory
+import System.FilePath
+
+-- | in batch mode: write code in a file
+batchCompile f = liftM fst $ compileModule defOpts emptyShellState f
+ where
+ defOpts = options [emitCode]
+batchCompileOpt f = liftM fst $ compileModule defOpts emptyShellState f
+ where
+ defOpts = options [emitCode, optimizeCanon]
+
+batchCompileOld f = compileOld defOpts f
+ where
+ defOpts = options [emitCode]
+
+-- | compile with one module as starting point
+-- command-line options override options (marked by --#) in the file
+-- As for path: if it is read from file, the file path is prepended to each name.
+-- If from command line, it is used as it is.
+compileModule :: Options -> ShellState -> FilePath -> IOE TimedCompileEnv
+---- IOE (GFC.CanonGrammar, (SourceGrammar,[(String,(FilePath,ModTime))]))
+
+compileModule opts st0 file |
+ oElem showOld opts ||
+ elem suff [".cf",".ebnf",".gfm"] = do
+ let putp = putPointE opts
+ let putpp = putPointEsil opts
+ let path = [] ----
+ grammar1 <- case suff of
+ ".cf" -> putp ("- parsing" +++ suff +++ file) $ getCFGrammar opts file
+ ".ebnf" -> putp ("- parsing" +++ suff +++ file) $ getEBNFGrammar opts file
+ ".gfm" -> putp ("- parsing" +++ suff +++ file) $ getSourceGrammar opts file
+ _ -> putp ("- parsing old gf" +++ file) $ getOldGrammar opts file
+ let mods = modules grammar1
+ let env = compileEnvShSt st0 []
+ foldM (comp putpp path) env mods
+ where
+ suff = takeExtensions file
+ comp putpp path env sm0 = do
+ (k',sm,eenv') <- makeSourceModule opts (fst env) sm0
+ cm <- putpp " generating code... " $ generateModuleCode opts path sm
+ ft <- getReadTimes file ---
+ extendCompileEnvInt env (k',sm,cm) eenv' ft
+
+compileModule opts1 st0 file = do
+ opts0 <- ioeIO $ getOptionsFromFile file
+ let useFileOpt = maybe False (const True) $ getOptVal opts0 pathList
+ let useLineOpt = maybe False (const True) $ getOptVal opts1 pathList
+ let opts = addOptions opts1 opts0
+ let fpath = dropFileName file
+ ps0 <- ioeIO $ pathListOpts opts fpath
+
+ let ps1 = if (useFileOpt && not useLineOpt)
+ then (ps0 ++ map (combine fpath) ps0)
+ else ps0
+ ps <- ioeIO $ extendPathEnv ps1
+ let ioeIOIf = if oElem beVerbose opts then ioeIO else (const (return ()))
+ ioeIOIf $ putStrLn $ "module search path:" +++ show ps ----
+ let st = st0 --- if useFileOpt then emptyShellState else st0
+ let rfs = [(m,t) | (m,(_,t)) <- readFiles st]
+ let file' = if useFileOpt then takeFileName file else file -- to find file itself
+ files <- getAllFiles opts ps rfs file'
+ ioeIOIf $ putStrLn $ "files to read:" +++ show files ----
+ let names = map justModuleName files
+ ioeIOIf $ putStrLn $ "modules to include:" +++ show names ----
+ let env0 = compileEnvShSt st names
+ (e,mm) <- foldIOE (compileOne opts) env0 files
+ maybe (return ()) putStrLnE mm
+ return e
+
+getReadTimes file = do
+ t <- ioeIO getNowTime
+ let m = justModuleName file
+ return $ (m,(file,t)) : [(resModName m,(file,t)) | not (isGFC file)]
+
+compileEnvShSt :: ShellState -> [ModName] -> TimedCompileEnv
+compileEnvShSt st fs = ((0,sgr,cgr,eenv),fts) where
+ cgr = MGrammar [m | m@(i,_) <- modules (canModules st), notInc i]
+ sgr = MGrammar [m | m@(i,_) <- modules (srcModules st), notIns i]
+ notInc i = notElem (prt i) $ map dropExtension fs
+ notIns i = notElem (prt i) $ map dropExtension fs
+ fts = readFiles st
+ eenv = evalEnv st
+
+pathListOpts :: Options -> FileName -> IO [InitPath]
+pathListOpts opts file = return $ maybe [file] splitInModuleSearchPath $ getOptVal opts pathList
+
+reverseModules (MGrammar ms) = MGrammar $ reverse ms
+
+keepResModules :: Options -> SourceGrammar -> SourceGrammar
+keepResModules opts gr =
+ if oElem retainOpers opts
+ then MGrammar $ reverse [(i,mi) | (i,mi@(ModMod m)) <- modules gr, isModRes m]
+ else emptyMGrammar
+
+
+-- | the environment
+type CompileEnv = (Int,SourceGrammar, GFC.CanonGrammar,EEnv)
+
+emptyCompileEnv :: TimedCompileEnv
+emptyCompileEnv = ((0,emptyMGrammar,emptyMGrammar,emptyEEnv),[])
+
+extendCompileEnvInt ((_,MGrammar ss, MGrammar cs,_),fts) (k,sm,cm) eenv ft =
+ return ((k,MGrammar (sm:ss), MGrammar (cm:cs),eenv),ft++fts) --- reverse later
+
+extendCompileEnv e@((k,_,_,_),_) (sm,cm) = extendCompileEnvInt e (k,sm,cm)
+
+extendCompileEnvCanon ((k,s,c,e),fts) cgr eenv ft =
+ return ((k,s, MGrammar (modules cgr ++ modules c),eenv),ft++fts)
+
+type TimedCompileEnv = (CompileEnv,[(String,(FilePath,ModTime))])
+
+compileOne :: Options -> TimedCompileEnv -> FullPath -> IOE TimedCompileEnv
+compileOne opts env@((_,srcgr,cancgr0,eenv),_) file = do
+
+ let putp = putPointE opts
+ let putpp = putPointEsil opts
+ let putpOpt v m act
+ | oElem beVerbose opts = putp v act
+ | oElem beSilent opts = putpp v act
+ | otherwise = ioeIO (putStrFlush m) >> act
+
+ let gf = takeExtensions file
+ let path = dropFileName file
+ let name = dropExtension file
+ let mos = modules srcgr
+
+ case gf of
+ -- for multilingual canonical gf, just read the file and update environment
+ ".gfcm" -> do
+ cgr <- putp ("+ reading" +++ file) $ getCanonGrammar file
+ ft <- getReadTimes file
+ extendCompileEnvCanon env cgr eenv ft
+
+ -- for canonical gf, read the file and update environment, also source env
+ ".gfc" -> do
+ cm <- putp ("+ reading" +++ file) $ getCanonModule file
+ let cancgr = updateMGrammar (MGrammar [cm]) cancgr0
+ sm <- ioeErr $ CG.canon2sourceModule $ unoptimizeCanonMod cancgr $ unSubelimModule cm
+ ft <- getReadTimes file
+ extendCompileEnv env (sm, cm) eenv ft
+
+ -- for compiled resource, parse and organize, then update environment
+ ".gfr" -> do
+ sm0 <- putp ("| reading" +++ file) $ getSourceModule opts file
+ let sm1 = unsubexpModule sm0
+ sm <- {- putp "creating indirections" $ -} ioeErr $ extendModule mos sm1
+---- experiment with not optimizing gfr
+---- sm:_ <- putp " optimizing " $ ioeErr $ evalModule mos sm1
+ let gfc = gfcFile name
+ cm <- putp ("+ reading" +++ gfc) $ getCanonModule gfc
+ ft <- getReadTimes file
+ extendCompileEnv env (sm,cm) eenv ft
+
+ -- for gf source, do full compilation
+
+ _ -> do
+
+ --- hack fix to a bug in ReadFiles with reused concrete
+
+ let modu = dropExtension file
+ b1 <- ioeIO $ doesFileExist file
+ b2 <- ioeIO $ doesFileExist $ gfrFile modu
+ if not b1
+ then if b2
+ then compileOne opts env $ gfrFile $ modu
+ else compileOne opts env $ gfcFile $ modu
+ else do
+
+ sm0 <- putpOpt ("- parsing" +++ file) ("- compiling" +++ file ++ "... ") $
+ getSourceModule opts file
+ (k',sm,eenv') <- makeSourceModule opts (fst env) sm0
+ cm <- putpp " generating code... " $ generateModuleCode opts path sm
+ ft <- getReadTimes file
+
+ sm':_ <- case snd sm of
+---- ModMod n | isModRes n -> putp " optimizing " $ ioeErr $ evalModule mos sm
+ _ -> return [sm]
+
+ extendCompileEnvInt env (k',sm',cm) eenv' ft
+
+-- | dispatch reused resource at early stage
+makeSourceModule :: Options -> CompileEnv ->
+ SourceModule -> IOE (Int,SourceModule,EEnv)
+makeSourceModule opts env@(k,gr,can,eenv) mo@(i,mi) = case mi of
+
+ ModMod m -> case mtype m of
+ MTReuse c -> do
+ sm <- ioeErr $ makeReuse gr i (extend m) c
+ let mo2 = (i, ModMod sm)
+ mos = modules gr
+ --- putp " type checking reused" $ ioeErr $ showCheckModule mos mo2
+ return $ (k,mo2,eenv)
+{- ---- obsolete
+ MTUnion ty imps -> do
+ mo' <- ioeErr $ makeUnion gr i ty imps
+ compileSourceModule opts env mo'
+-}
+
+ _ -> compileSourceModule opts env mo
+ _ -> compileSourceModule opts env mo
+ where
+ putp = putPointE opts
+
+compileSourceModule :: Options -> CompileEnv ->
+ SourceModule -> IOE (Int,SourceModule,EEnv)
+compileSourceModule opts env@(k,gr,can,eenv) mo@(i,mi) = do
+
+ let putp = putPointE opts
+ putpp = putPointEsil opts
+ mos = modules gr
+
+ if (oElem showOld opts && oElem emitCode opts)
+ then do
+ let (file,out) = (gfFile (prt i), prGrammar (MGrammar [mo]))
+ putp (" wrote file" +++ file) $ ioeIO $ writeFile file out
+ else return ()
+
+ mo1 <- ioeErr $ rebuildModule mos mo
+
+ mo1b <- ioeErr $ extendModule mos mo1
+
+ case mo1b of
+ (_,ModMod n) | not (isCompleteModule n) -> do
+ return (k,mo1b,eenv) -- refresh would fail, since not renamed
+ _ -> do
+ mo2:_ <- putpp " renaming " $ ioeErr $ renameModule mos mo1b
+
+ (mo3:_,warnings) <- putpp " type checking" $ ioeErr $ showCheckModule mos mo2
+ if null warnings then return () else putp warnings $ return ()
+
+ (k',mo3r:_) <- putpp " refreshing " $ ioeErr $ refreshModule (k,mos) mo3
+
+ (mo4,eenv') <-
+ ---- if oElem "check_only" opts
+ putpp " optimizing " $ ioeErr $ optimizeModule opts (mos,eenv) mo3r
+ return (k',mo4,eenv')
+ where
+ ---- prDebug mo = ioeIO $ putStrLn $ prGrammar $ MGrammar [mo] ---- debug
+ prDebug mo = ioeIO $ print $ length $ lines $ prGrammar $ MGrammar [mo]
+
+generateModuleCode :: Options -> InitPath -> SourceModule -> IOE GFC.CanonModule
+generateModuleCode opts path minfo@(name,info) = do
+
+--- DEPREC
+--- if oElem (iOpt "gfcc") opts
+--- then ioeIO $ putStrLn $ prGrammar2gfcc minfo
+--- else return ()
+
+ let pname = path </> prt name
+ minfo0 <- ioeErr $ redModInfo minfo
+ let oopts = addOptions opts (iOpts (flagsModule minfo))
+ optims = maybe "all_subs" id $ getOptVal oopts useOptimizer
+ optim = takeWhile (/='_') optims
+ subs = drop 1 (dropWhile (/='_') optims) == "subs"
+ minfo1 <- return $
+ case optim of
+ "parametrize" -> shareModule paramOpt minfo0 -- parametrization and sharing
+ "values" -> shareModule valOpt minfo0 -- tables as courses-of-values
+ "share" -> shareModule shareOpt minfo0 -- sharing of branches
+ "all" -> shareModule allOpt minfo0 -- first parametrize then values
+ "none" -> minfo0 -- no optimization
+ _ -> shareModule shareOpt minfo0 -- sharing; default
+
+ -- do common subexpression elimination if required by flag "subs"
+ minfo' <-
+ if subs
+ then ioeErr $ elimSubtermsMod minfo1
+ else return minfo1
+
+ -- for resource, also emit gfr.
+ --- Also for incomplete, to create timestamped gfc/gfr files
+ case info of
+ ModMod m | emitsGFR m && emit && nomulti -> do
+ let rminfo = if isCompilable info
+ then subexpModule minfo
+ else (name, ModMod emptyModule)
+ let (file,out) = (gfrFile pname, prGrammar (MGrammar [rminfo]))
+ putp (" wrote file" +++ file) $ ioeIO $ writeFile file $ compactPrint out
+ _ -> return ()
+ let encode = case getOptVal opts uniCoding of
+ Just "utf8" -> encodeUTF8
+ _ -> id
+ (file,out) <- do
+ code <- return $ MkGFC.prCanonModInfo minfo'
+ return (gfcFile pname, encode code)
+ if emit && nomulti ---- && isCompilable info
+ then putp (" wrote file" +++ file) $ ioeIO $ writeFile file out
+ else putpp ("no need to save module" +++ prt name) $ return ()
+ return minfo'
+ where
+ putp = putPointE opts
+ putpp = putPointEsil opts
+
+ emitsGFR m = isModRes m ---- && isCompilable info
+ ---- isModRes m || (isModCnc m && mstatus m == MSIncomplete)
+ isCompilable mi = case mi of
+ ModMod m -> not $ isModCnc m && mstatus m == MSIncomplete
+ _ -> True
+ nomulti = not $ oElem makeMulti opts
+ emit = oElem emitCode opts && not (oElem notEmitCode opts)
+
+-- for old GF: sort into modules, write files, compile as usual
+
+compileOld :: Options -> FilePath -> IOE GFC.CanonGrammar
+compileOld opts file = do
+ let putp = putPointE opts
+ grammar1 <- putp ("- parsing old gf" +++ file) $ getOldGrammar opts file
+ files <- mapM writeNewGF $ modules grammar1
+ ((_,_,grammar,_),_) <- foldM (compileOne opts) emptyCompileEnv files
+ return grammar
+
+writeNewGF :: SourceModule -> IOE FilePath
+writeNewGF m@(i,_) = do
+ let file = gfFile $ prt i
+ ioeIO $ writeFile file $ prGrammar (MGrammar [m])
+ ioeIO $ putStrLn $ "wrote file" +++ file
+ return file
+
+--- this function duplicates a lot of code from compileModule.
+--- It does not really belong here either.
+-- It selects those .gfe files that a grammar depends on and that
+-- are younger than corresponding gf
+
+getGFEFiles :: Options -> FilePath -> IO [FilePath]
+getGFEFiles opts1 file = useIOE [] $ do
+ opts0 <- ioeIO $ getOptionsFromFile file
+ let useFileOpt = maybe False (const True) $ getOptVal opts0 pathList
+ let useLineOpt = maybe False (const True) $ getOptVal opts1 pathList
+ let opts = addOptions opts1 opts0
+ let fpath = dropFileName file
+ ps0 <- ioeIO $ pathListOpts opts fpath
+
+ let ps1 = if (useFileOpt && not useLineOpt)
+ then (map (combine fpath) ps0)
+ else ps0
+ ps <- ioeIO $ extendPathEnv ps1
+ let file' = if useFileOpt then takeFileName file else file -- to find file itself
+ files <- getAllFiles opts ps [] file'
+ efiles <- ioeIO $ filterM doesFileExist [replaceExtension f "gfe" | f <- files]
+ es <- ioeIO $ mapM (uncurry selectLater) [(f, init f) | f <- efiles] -- init gfe == gf
+ return $ filter ((=='e') . last) es
diff --git a/src-3.0/GF/Compile/Evaluate.hs b/src-3.0/GF/Compile/Evaluate.hs
new file mode 100644
index 000000000..a574fef40
--- /dev/null
+++ b/src-3.0/GF/Compile/Evaluate.hs
@@ -0,0 +1,477 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Evaluate
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/01 15:39:12 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.19 $
+--
+-- Computation of source terms. Used in compilation and in @cc@ command.
+-----------------------------------------------------------------------------
+
+module GF.Compile.Evaluate (appEvalConcrete, EEnv, emptyEEnv) where
+
+import GF.Data.Operations
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Data.Str
+import GF.Grammar.PrGrammar
+import GF.Infra.Modules
+import GF.Infra.Option
+import GF.Grammar.Macros
+import GF.Grammar.Lookup
+import GF.Grammar.Refresh
+import GF.Grammar.PatternMatch
+import GF.Grammar.Lockfield (isLockLabel) ----
+
+import GF.Grammar.AppPredefined
+
+import qualified Data.Map as Map
+
+import Data.List (nub,intersperse)
+import Control.Monad (liftM2, liftM)
+import Debug.Trace
+
+
+data EEnv = EEnv {
+ computd :: Map.Map (Ident,Ident) FTerm,
+ temp :: Int
+ }
+
+emptyEEnv = EEnv Map.empty 0
+
+lookupComputed :: (Ident,Ident) -> STM EEnv (Maybe FTerm)
+lookupComputed mc = do
+ env <- readSTM
+ return $ Map.lookup mc $ computd env
+
+updateComputed :: (Ident,Ident) -> FTerm -> STM EEnv ()
+updateComputed mc t =
+ updateSTM (\e -> e{computd = Map.insert mc t (computd e)})
+
+getTemp :: STM EEnv Ident
+getTemp = do
+ env <- readSTM
+ updateSTM (\e -> e{temp = temp e + 1})
+ return $ identC ("#" ++ show (temp env))
+
+data FTerm =
+ FTC Term
+ | FTF (Term -> FTerm)
+
+prFTerm :: Integer -> FTerm -> String
+prFTerm i t = case t of
+ FTC t -> prt t
+ FTF f -> show i +++ "->" +++ prFTerm (i + 1) (f (EInt i))
+
+term2fterm t = case t of
+ Abs x b -> FTF (\t -> term2fterm (subst [(x,t)] b))
+ _ -> FTC t
+
+traceFTerm c ft = ft ----
+----trace ("\n" ++ prt c +++ "=" +++ take 60 (prFTerm 0 ft)) ft
+
+fterm2term :: FTerm -> STM EEnv Term
+fterm2term t = case t of
+ FTC t -> return t
+ FTF f -> do
+ x <- getTemp
+ b <- fterm2term $ f (Vr x)
+ return $ Abs x b
+
+subst g t = case t of
+ Vr x -> maybe t id $ lookup x g
+ _ -> composSafeOp (subst g) t
+
+
+appFTerm :: FTerm -> [Term] -> FTerm
+appFTerm ft ts = case (ft,ts) of
+ (FTF f, x:xs) -> appFTerm (f x) xs
+ (FTC c, _:_) -> FTC $ foldl App c ts
+ _ -> ft
+
+apps :: Term -> (Term,[Term])
+apps t = case t of
+ App f a -> (f',xs ++ [a]) where (f',xs) = apps f
+ _ -> (t,[])
+
+appEvalConcrete gr bt env = appSTM (evalConcrete gr bt) env
+
+evalConcrete :: SourceGrammar -> BinTree Ident Info -> STM EEnv (BinTree Ident Info)
+evalConcrete gr mo = mapMTree evaldef mo where
+
+ evaldef (f,info) = case info of
+ CncFun (mt@(Just (_,ty@(cont,val)))) pde ppr ->
+ evalIn ("\nerror in linearization of function" +++ prt f +++ ":") $
+ do
+ pde' <- case pde of
+ Yes de -> do
+ liftM yes $ pEval ty de
+ _ -> return pde
+ --- ppr' <- liftM yes $ evalPrintname gr c ppr pde'
+ return $ (f, CncFun mt pde' ppr) -- only cat in type actually needed
+
+ _ -> return (f,info)
+
+ pEval (context,val) trm = do ---- errIn ("parteval" +++ prt_ trm) $ do
+ let
+ vars = map fst context
+ args = map Vr vars
+ subst = [(v, Vr v) | v <- vars]
+ trm1 = mkApp trm args
+ trm3 <- recordExpand val trm1 >>= comp subst >>= recomp subst
+ return $ mkAbs vars trm3
+
+ ---- temporary hack to ascertain full evaluation, because of bug in comp
+ recomp g t = if notReady t then comp g t else return t
+ notReady = not . null . redexes
+ redexes t = case t of
+ Q _ _ -> return [()]
+ _ -> collectOp redexes t
+
+ recordExpand typ trm = case unComputed typ of
+ RecType tys -> case trm of
+ FV rs -> return $ FV [R [assign lab (P r lab) | (lab,_) <- tys] | r <- rs]
+ _ -> return $ R [assign lab (P trm lab) | (lab,_) <- tys]
+ _ -> return trm
+
+ comp g t = case t of
+
+ Q (IC "Predef") _ -> return t ----trace ("\nPredef:\n" ++ prt t) $ return t
+
+ Q p c -> do
+ md <- lookupComputed (p,c)
+ case md of
+ Nothing -> do
+ d <- lookRes (p,c)
+ updateComputed (p,c) $ traceFTerm c $ term2fterm d
+ return d
+ Just d -> fterm2term d >>= comp g
+ App f a -> case apps t of
+{- ----
+ (h@(QC p c),xs) -> do
+ xs' <- mapM (comp g) xs
+ case lookupValueIndex gr ty t of
+ Ok v -> return v
+ _ -> return t
+-}
+ (h@(Q p c),xs) | p == IC "Predef" -> do
+ xs' <- mapM (comp g) xs
+ (t',b) <- stmErr $ appPredefined (foldl App h xs')
+ if b then return t' else comp g t'
+ (h@(Q p c),xs) -> do
+ xs' <- mapM (comp g) xs
+ md <- lookupComputed (p,c)
+ case md of
+ Just ft -> do
+ t <- fterm2term $ appFTerm ft xs'
+ comp g t
+ Nothing -> do
+ d <- lookRes (p,c)
+ let ft = traceFTerm c $ term2fterm d
+ updateComputed (p,c) ft
+ t' <- fterm2term $ appFTerm ft xs'
+ comp g t'
+ _ -> do
+ f' <- comp g f
+ a' <- comp g a
+ case (f',a') of
+ (Abs x b,_) -> comp (ext x a' g) b
+ (QC _ _,_) -> returnC $ App f' a'
+ (FV fs, _) -> mapM (\c -> comp g (App c a')) fs >>= return . variants
+ (_, FV as) -> mapM (\c -> comp g (App f' c)) as >>= return . variants
+
+ (Alias _ _ d, _) -> comp g (App d a')
+
+ (S (T i cs) e,_) -> prawitz g i (flip App a') cs e
+
+ _ -> do
+ (t',b) <- stmErr $ appPredefined (App f' a')
+ if b then return t' else comp g t'
+
+
+ Vr x -> do
+ t' <- maybe (prtRaise (
+ "context" +++ show g +++ ": no value given to variable") x) return $ lookup x g
+ case t' of
+ _ | t == t' -> return t
+ _ -> comp g t'
+
+ Abs x b -> do
+ b' <- comp (ext x (Vr x) g) b
+ return $ Abs x b'
+
+ Let (x,(_,a)) b -> do
+ a' <- comp g a
+ comp (ext x a' g) b
+
+ Prod x a b -> do
+ a' <- comp g a
+ b' <- comp (ext x (Vr x) g) b
+ return $ Prod x a' b'
+
+ P t l | isLockLabel l -> return $ R []
+ ---- a workaround 18/2/2005: take this away and find the reason
+ ---- why earlier compilation destroys the lock field
+
+
+ P t l -> do
+ t' <- comp g t
+ case t' of
+ FV rs -> mapM (\c -> comp g (P c l)) rs >>= returnC . variants
+ R r -> maybe
+ (prtRaise (prt t' ++ ": no value for label") l) (comp g . snd) $
+ lookup l r
+
+ ExtR a (R b) -> case lookup l b of ----comp g (P (R b) l) of
+ Just (_,v) -> comp g v
+ _ -> comp g (P a l)
+ ExtR (R a) b -> case lookup l a of ----comp g (P (R b) l) of
+ Just (_,v) -> comp g v
+ _ -> comp g (P b l)
+
+ S (T i cs) e -> prawitz g i (flip P l) cs e
+
+ _ -> returnC $ P t' l
+
+ S t@(T _ cc) v -> do
+ v' <- comp g v
+ case v' of
+ FV vs -> do
+ ts' <- mapM (comp g . S t) vs
+ return $ variants ts'
+ _ -> case matchPattern cc v' of
+ Ok (c,g') -> comp (g' ++ g) c
+ _ | isCan v' -> prtRaise ("missing case" +++ prt v' +++ "in") t
+ _ -> do
+ t' <- comp g t
+ return $ S t' v' -- if v' is not canonical
+
+ S t v -> do
+ t' <- comp g t
+ v' <- comp g v
+ case t' of
+ T _ [(PV IW,c)] -> comp g c --- an optimization
+ T _ [(PT _ (PV IW),c)] -> comp g c
+
+ T _ [(PV z,c)] -> comp (ext z v' g) c --- another optimization
+ T _ [(PT _ (PV z),c)] -> comp (ext z v' g) c
+
+ FV ccs -> mapM (\c -> comp g (S c v')) ccs >>= returnC . variants
+
+ V ptyp ts -> do
+ vs <- stmErr $ allParamValues gr ptyp
+ ps <- stmErr $ mapM term2patt vs
+ let cc = zip ps ts
+ case v' of
+ FV vs -> mapM (\c -> comp g (S t' c)) vs >>= returnC . variants
+ _ -> case matchPattern cc v' of
+ Ok (c,g') -> comp (g' ++ g) c
+ _ | isCan v' -> prtRaise ("missing case" +++ prt v' +++ "in") t
+ _ -> return $ S t' v' -- if v' is not canonical
+
+ T _ cc -> case v' of
+ FV vs -> mapM (\c -> comp g (S t' c)) vs >>= returnC . variants
+ _ -> case matchPattern cc v' of
+ Ok (c,g') -> comp (g' ++ g) c
+ _ | isCan v' -> prtRaise ("missing case" +++ prt v' +++ "in") t
+ _ -> return $ S t' v' -- if v' is not canonical
+
+ Alias _ _ d -> comp g (S d v')
+
+ S (T i cs) e -> prawitz g i (flip S v') cs e
+
+ _ -> returnC $ S t' v'
+
+ -- normalize away empty tokens
+ K "" -> return Empty
+
+ -- glue if you can
+ Glue x0 y0 -> do
+ x <- comp g x0
+ y <- comp g y0
+ case (x,y) of
+ (Alias _ _ d, y) -> comp g $ Glue d y
+ (x, Alias _ _ d) -> comp g $ Glue x d
+
+ (S (T i cs) e, s) -> prawitz g i (flip Glue s) cs e
+ (s, S (T i cs) e) -> prawitz g i (Glue s) cs e
+ (_,Empty) -> return x
+ (Empty,_) -> return y
+ (K a, K b) -> return $ K (a ++ b)
+ (_, Alts (d,vs)) -> do
+---- (K a, Alts (d,vs)) -> do
+ let glx = Glue x
+ comp g $ Alts (glx d, [(glx v,c) | (v,c) <- vs])
+ (Alts _, ka) -> checks [do
+ y' <- stmErr $ strsFromTerm ka
+---- (Alts _, K a) -> checks [do
+ x' <- stmErr $ strsFromTerm x -- this may fail when compiling opers
+ return $ variants [
+ foldr1 C (map K (str2strings (glueStr v u))) | v <- x', u <- y']
+---- foldr1 C (map K (str2strings (glueStr v (str a)))) | v <- x']
+ ,return $ Glue x y
+ ]
+ (FV ks,_) -> do
+ kys <- mapM (comp g . flip Glue y) ks
+ return $ variants kys
+ (_,FV ks) -> do
+ xks <- mapM (comp g . Glue x) ks
+ return $ variants xks
+
+ _ -> do
+ mapM_ checkNoArgVars [x,y]
+ r <- composOp (comp g) t
+ returnC r
+
+ Alts _ -> do
+ r <- composOp (comp g) t
+ returnC r
+
+ -- remove empty
+ C a b -> do
+ a' <- comp g a
+ b' <- comp g b
+ case (a',b') of
+ (Alts _, K a) -> checks [do
+ as <- stmErr $ strsFromTerm a' -- this may fail when compiling opers
+ return $ variants [
+ foldr1 C (map K (str2strings (plusStr v (str a)))) | v <- as]
+ ,
+ return $ C a' b'
+ ]
+ (Empty,_) -> returnC b'
+ (_,Empty) -> returnC a'
+ _ -> returnC $ C a' b'
+
+ -- reduce free variation as much as you can
+ FV ts -> mapM (comp g) ts >>= returnC . variants
+
+ -- merge record extensions if you can
+ ExtR r s -> do
+ r' <- comp g r
+ s' <- comp g s
+ case (r',s') of
+ (Alias _ _ d, _) -> comp g $ ExtR d s'
+ (_, Alias _ _ d) -> comp g $ Glue r' d
+
+ (R rs, R ss) -> stmErr $ plusRecord r' s'
+ (RecType rs, RecType ss) -> stmErr $ plusRecType r' s'
+
+ (_, FV ss) -> liftM FV $ mapM (comp g) [ExtR t u | u <- ss]
+
+ _ -> return $ ExtR r' s'
+
+ -- case-expand tables
+ -- if already expanded, don't expand again
+ T i@(TComp _) cs -> do
+ -- if there are no variables, don't even go inside
+ cs' <- {-if (null g) then return cs else-} mapPairsM (comp g) cs
+ return $ T i cs'
+
+ --- this means some extra work; should implement TSh directly
+ TSh i cs -> comp g $ T i [(p,v) | (ps,v) <- cs, p <- ps]
+
+ T i cs -> do
+ pty0 <- stmErr $ getTableType i
+ ptyp <- comp g pty0
+ case allParamValues gr ptyp of
+ Ok vs -> do
+
+ cs' <- mapM (compBranchOpt g) cs
+ sts <- stmErr $ mapM (matchPattern cs') vs
+ ts <- mapM (\ (c,g') -> comp (g' ++ g) c) sts
+ ps <- stmErr $ mapM term2patt vs
+ let ps' = ps --- PT ptyp (head ps) : tail ps
+ return $ --- V ptyp ts -- to save space, just course of values
+ T (TComp ptyp) (zip ps' ts)
+ _ -> do
+ cs' <- mapM (compBranch g) cs
+ return $ T i cs' -- happens with variable types
+
+ -- otherwise go ahead
+ _ -> composOp (comp g) t >>= returnC
+
+ lookRes (p,c) = case lookupResDefKind gr p c of
+ Ok (t,_) | noExpand p -> return t
+ Ok (t,0) -> comp [] t
+ Ok (t,_) -> return t
+ Bad s -> raise s
+
+ noExpand p = errVal False $ do
+ mo <- lookupModMod gr p
+ return $ case getOptVal (iOpts (flags mo)) useOptimizer of
+ Just "noexpand" -> True
+ _ -> False
+
+ prtRaise s t = raise (s +++ prt t)
+
+ ext x a g = (x,a):g
+
+ returnC = return --- . computed
+
+ variants ts = case nub ts of
+ [t] -> t
+ ts -> FV ts
+
+ isCan v = case v of
+ Con _ -> True
+ QC _ _ -> True
+ App f a -> isCan f && isCan a
+ R rs -> all (isCan . snd . snd) rs
+ _ -> False
+
+ compBranch g (p,v) = do
+ let g' = contP p ++ g
+ v' <- comp g' v
+ return (p,v')
+
+ compBranchOpt g c@(p,v) = case contP p of
+ [] -> return c
+ _ -> compBranch g c
+---- _ -> err (const (return c)) return $ compBranch g c
+
+ contP p = case p of
+ PV x -> [(x,Vr x)]
+ PC _ ps -> concatMap contP ps
+ PP _ _ ps -> concatMap contP ps
+ PT _ p -> contP p
+ PR rs -> concatMap (contP . snd) rs
+
+ PAs x p -> (x,Vr x) : contP p
+
+ PSeq p q -> concatMap contP [p,q]
+ PAlt p q -> concatMap contP [p,q]
+ PRep p -> contP p
+ PNeg p -> contP p
+
+ _ -> []
+
+ prawitz g i f cs e = do
+ cs' <- mapM (compBranch g) [(p, f v) | (p,v) <- cs]
+ return $ S (T i cs') e
+
+-- | argument variables cannot be glued
+checkNoArgVars :: Term -> STM EEnv Term
+checkNoArgVars t = case t of
+ Vr (IA _) -> raise $ glueErrorMsg $ prt t
+ Vr (IAV _) -> raise $ glueErrorMsg $ prt t
+ _ -> composOp checkNoArgVars t
+
+glueErrorMsg s =
+ "Cannot glue (+) term with run-time variable" +++ s ++ "." ++++
+ "Use Prelude.bind instead."
+
+stmErr :: Err a -> STM s a
+stmErr e = stm (\s -> do
+ v <- e
+ return (v,s)
+ )
+
+evalIn :: String -> STM s a -> STM s a
+evalIn msg st = stm $ \s -> case appSTM st s of
+ Bad e -> Bad $ msg ++++ e
+ Ok vs -> Ok vs
diff --git a/src-3.0/GF/Compile/Extend.hs b/src-3.0/GF/Compile/Extend.hs
new file mode 100644
index 000000000..ae87b3e71
--- /dev/null
+++ b/src-3.0/GF/Compile/Extend.hs
@@ -0,0 +1,136 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Extend
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/30 21:08:14 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.18 $
+--
+-- AR 14\/5\/2003 -- 11\/11
+--
+-- The top-level function 'extendModule'
+-- extends a module symbol table by indirections to the module it extends
+-----------------------------------------------------------------------------
+
+module GF.Compile.Extend (extendModule, extendMod
+ ) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.PrGrammar
+import GF.Infra.Modules
+import GF.Compile.Update
+import GF.Grammar.Macros
+import GF.Data.Operations
+
+import Control.Monad
+
+extendModule :: [SourceModule] -> SourceModule -> Err SourceModule
+extendModule ms (name,mod) = case mod of
+
+ ---- Just to allow inheritance in incomplete concrete (which are not
+ ---- compiled anyway), extensions are not built for them.
+ ---- Should be replaced by real control. AR 4/2/2005
+ ModMod m | mstatus m == MSIncomplete && isModCnc m -> return (name,mod)
+
+ ModMod m -> do
+ mod' <- foldM extOne m (extend m)
+ return (name,ModMod mod')
+ where
+ extOne mod@(Module mt st fs es ops js) (n,cond) = do
+ (m0,isCompl) <- do
+ m <- lookupModMod (MGrammar ms) n
+
+ -- test that the module types match, and find out if the old is complete
+ testErr (sameMType (mtype m) mt)
+ ("illegal extension type to module" +++ prt name)
+ return (m, isCompleteModule m)
+---- return (m, if (isCompleteModule m) then True else not (isCompleteModule mod))
+
+ -- build extension in a way depending on whether the old module is complete
+ js1 <- extendMod isCompl (n, isInherited cond) name (jments m0) js
+
+ -- if incomplete, throw away extension information
+ let me' = if isCompl then es else (filter ((/=n) . fst) es)
+ return $ Module mt st fs me' ops js1
+
+-- | When extending a complete module: new information is inserted,
+-- and the process is interrupted if unification fails.
+-- If the extended module is incomplete, its judgements are just copied.
+extendMod :: Bool -> (Ident,Ident -> Bool) -> Ident ->
+ BinTree Ident Info -> BinTree Ident Info ->
+ Err (BinTree Ident Info)
+extendMod isCompl (name,cond) base old new = foldM try new $ tree2list old where
+ try t i@(c,_) | not (cond c) = return t
+ try t i@(c,_) = errIn ("constant" +++ prt c) $
+ tryInsert (extendAnyInfo isCompl name base) indirIf t i
+ indirIf = if isCompl then indirInfo name else id
+
+indirInfo :: Ident -> Info -> Info
+indirInfo n info = AnyInd b n' where
+ (b,n') = case info of
+ ResValue _ -> (True,n)
+ ResParam _ -> (True,n)
+ AbsFun _ (Yes EData) -> (True,n)
+ AnyInd b k -> (b,k)
+ _ -> (False,n) ---- canonical in Abs
+
+perhIndir :: Ident -> Perh a -> Perh a
+perhIndir n p = case p of
+ Yes _ -> May n
+ _ -> p
+
+extendAnyInfo :: Bool -> Ident -> Ident -> Info -> Info -> Err Info
+extendAnyInfo isc n o i j =
+ errIn ("building extension for" +++ prt n +++ "in" +++ prt o) $ case (i,j) of
+ (AbsCat mc1 mf1, AbsCat mc2 mf2) ->
+ liftM2 AbsCat (updn isc n mc1 mc2) (updn isc n mf1 mf2) --- add cstrs
+ (AbsFun mt1 md1, AbsFun mt2 md2) ->
+ liftM2 AbsFun (updn isc n mt1 mt2) (updn isc n md1 md2) --- add defs
+ (ResParam mt1, ResParam mt2) ->
+ liftM ResParam $ updn isc n mt1 mt2
+ (ResValue mt1, ResValue mt2) ->
+ liftM ResValue $ updn isc n mt1 mt2
+ (ResOper mt1 m1, ResOper mt2 m2) -> ---- extendResOper n mt1 m1 mt2 m2
+ liftM2 ResOper (updn isc n mt1 mt2) (updn isc n m1 m2)
+ (CncCat mc1 mf1 mp1, CncCat mc2 mf2 mp2) ->
+ liftM3 CncCat (updn isc n mc1 mc2) (updn isc n mf1 mf2) (updn isc n mp1 mp2)
+ (CncFun m mt1 md1, CncFun _ mt2 md2) ->
+ liftM2 (CncFun m) (updn isc n mt1 mt2) (updn isc n md1 md2)
+
+---- (AnyInd _ _, ResOper _ _) -> return j ----
+
+ (AnyInd b1 m1, AnyInd b2 m2) -> do
+ testErr (b1 == b2) "inconsistent indirection status"
+---- commented out as work-around for a spurious problem in
+---- TestResourceFre; should look at building of completion. 17/11/2004
+ testErr (m1 == m2) $
+ "different sources of indirection: " +++ show m1 +++ show m2
+ return i
+
+ _ -> Bad $ "cannot unify information in" ++++ show i ++++ "and" ++++ show j
+
+--- where
+
+updn isc n = if isc then (updatePerhaps n) else (updatePerhapsHard n)
+updc isc n = if True then (updatePerhaps n) else (updatePerhapsHard n)
+
+
+
+{- ---- no more needed: this is done in Rebuild
+-- opers declared in an interface and defined in an instance are a special case
+
+extendResOper n mt1 m1 mt2 m2 = case (m1,m2) of
+ (Nope,_) -> return $ ResOper (strip mt1) m2
+ _ -> liftM2 ResOper (updatePerhaps n mt1 mt2) (updatePerhaps n m1 m2)
+ where
+ strip (Yes t) = Yes $ strp t
+ strip m = m
+ strp t = case t of
+ Q _ c -> Vr c
+ QC _ c -> Vr c
+ _ -> composSafeOp strp t
+-}
diff --git a/src-3.0/GF/Compile/Flatten.hs b/src-3.0/GF/Compile/Flatten.hs
new file mode 100644
index 000000000..6b25edebb
--- /dev/null
+++ b/src-3.0/GF/Compile/Flatten.hs
@@ -0,0 +1,92 @@
+module Flatten where
+
+import Data.List
+-- import GF.Data.Operations
+
+-- (AR 15/3/2006)
+--
+-- A method for flattening grammars: create many flat rules instead of
+-- a few deep ones. This is generally better for parsins.
+-- The rules are obtained as follows:
+-- 1. write a config file tellinq which constants are variables: format 'c : C'
+-- 2. generate a list of trees with their types: format 't : T'
+-- 3. for each such tree, form a fun rule 'fun fui : X -> Y -> T' and a lin
+-- rule 'lin fui x y = t' where x:X,y:Y is the list of variables in t, as
+-- found in the config file.
+-- 4. You can go on and produce def or transfer rules similar to the lin rules
+-- except for the keyword.
+--
+-- So far this module is used outside gf. You can e.g. generate a list of
+-- trees by 'gt', write it in a file, and then in ghci call
+-- flattenGrammar <Config> <Trees> <OutFile>
+
+type Ident = String ---
+type Term = String ---
+type Rule = String ---
+
+type Config = [(Ident,Ident)]
+
+flattenGrammar :: FilePath -> FilePath -> FilePath -> IO ()
+flattenGrammar conff tf out = do
+ conf <- readFile conff >>= return . lines
+ ts <- readFile tf >>= return . lines
+ writeFile out $ mkFlatten conf ts
+
+mkFlatten :: [String] -> [String] -> String
+mkFlatten conff = unlines . concatMap getOne . zip [1..] where
+ getOne (k,t) = let (x,y) = mkRules conf ("fu" ++ show k) t in [x,y]
+ conf = getConfig conff
+
+mkRules :: Config -> Ident -> Term -> (Rule,Rule)
+mkRules conf f t = (fun f ty, lin f (takeWhile (/=':') t)) where
+ args = mkArgs conf ts
+ ty = concat [a ++ " -> " | a <- map snd args] ++ val
+ (ts,val) = let tt = lexTerm t in (init tt,last tt)
+--- f = mkIdent t
+ fun c a = unwords [" fun", c, ":",a,";"]
+ lin c a = unwords $ [" lin", c] ++ map fst args ++ ["=",a,";"]
+
+mkArgs :: Config -> [Ident] -> [(Ident,Ident)]
+mkArgs conf ids = [(x,ty) | x <- ids, Just ty <- [lookup x conf]]
+
+mkIdent :: Term -> Ident
+mkIdent = map mkChar where
+ mkChar c = case c of
+ '(' -> '6'
+ ')' -> '9'
+ ' ' -> '_'
+ _ -> c
+
+-- to get just the identifiers
+lexTerm :: String -> [String]
+lexTerm ss = case lex ss of
+ [([c],ws)] | isSpec c -> lexTerm ws
+ [(w@(_:_),ws)] -> w : lexTerm ws
+ _ -> []
+ where
+ isSpec = flip elem "();:"
+
+
+getConfig :: [String] -> Config
+getConfig = map getOne . filter (not . null) where
+ getOne line = case lexTerm line of
+ v:c:_ -> (v,c)
+
+ex = putStrLn fs where
+ fs =
+ mkFlatten
+ ["man_N : N",
+ "sleep_V : V"
+ ]
+ ["PredVP (DefSg man_N) (UseV sleep_V) : Cl",
+ "PredVP (DefPl man_N) (UseV sleep_V) : Cl"
+ ]
+
+{-
+-- result of ex
+
+ fun fu1 : N -> V -> Cl ;
+ lin fu1 man_N sleep_V = PredVP (DefSg man_N) (UseV sleep_V) ;
+ fun fu2 : N -> V -> Cl ;
+ lin fu2 man_N sleep_V = PredVP (DefPl man_N) (UseV sleep_V) ;
+-}
diff --git a/src-3.0/GF/Compile/GetGrammar.hs b/src-3.0/GF/Compile/GetGrammar.hs
new file mode 100644
index 000000000..294edbf9a
--- /dev/null
+++ b/src-3.0/GF/Compile/GetGrammar.hs
@@ -0,0 +1,146 @@
+----------------------------------------------------------------------
+-- |
+-- Module : GetGrammar
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/15 17:56:13 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.16 $
+--
+-- this module builds the internal GF grammar that is sent to the type checker
+-----------------------------------------------------------------------------
+
+module GF.Compile.GetGrammar (
+ getSourceModule, getSourceGrammar,
+ getOldGrammar, getCFGrammar, getEBNFGrammar
+ ) where
+
+import GF.Data.Operations
+import qualified GF.Source.ErrM as E
+
+import GF.Infra.UseIO
+import GF.Grammar.Grammar
+import GF.Infra.Modules
+import GF.Grammar.PrGrammar
+import qualified GF.Source.AbsGF as A
+import GF.Source.SourceToGrammar
+---- import Macros
+---- import Rename
+import GF.Text.UTF8 ----
+import GF.Infra.Option
+--- import Custom
+import GF.Source.ParGF
+import qualified GF.Source.LexGF as L
+
+import GF.CF.CF (rules2CF)
+import GF.CF.PPrCF
+import GF.CF.CFtoGrammar
+import GF.CF.EBNF
+
+import GF.Infra.ReadFiles ----
+
+import Data.Char (toUpper)
+import Data.List (nub)
+import qualified Data.ByteString.Char8 as BS
+import Control.Monad (foldM)
+import System (system)
+import System.FilePath
+
+getSourceModule :: Options -> FilePath -> IOE SourceModule
+getSourceModule opts file0 = do
+ file <- case getOptVal opts usePreprocessor of
+ Just p -> do
+ let tmp = "_gf_preproc.tmp"
+ cmd = p +++ file0 ++ ">" ++ tmp
+ ioeIO $ system cmd
+ -- ioeIO $ putStrLn $ "preproc" +++ cmd
+ return tmp
+ _ -> return file0
+ string0 <- readFileIOE file
+ let string = case getOptVal opts uniCoding of
+ Just "utf8" -> decodeUTF8 string0
+ _ -> string0
+ let tokens = myLexer (BS.pack string)
+ mo1 <- ioeErr $ pModDef tokens
+ ioeErr $ transModDef mo1
+
+getSourceGrammar :: Options -> FilePath -> IOE SourceGrammar
+getSourceGrammar opts file = do
+ string <- readFileIOE file
+ let tokens = myLexer (BS.pack string)
+ gr1 <- ioeErr $ pGrammar tokens
+ ioeErr $ transGrammar gr1
+
+
+-- for old GF format with includes
+
+getOldGrammar :: Options -> FilePath -> IOE SourceGrammar
+getOldGrammar opts file = do
+ defs <- parseOldGrammarFiles file
+ let g = A.OldGr A.NoIncl defs
+ let name = takeFileName file
+ ioeErr $ transOldGrammar opts name g
+
+parseOldGrammarFiles :: FilePath -> IOE [A.TopDef]
+parseOldGrammarFiles file = do
+ putStrLnE $ "reading grammar of old format" +++ file
+ (_, g) <- getImports "" ([],[]) file
+ return g -- now we can throw away includes
+ where
+ getImports oldInitPath (oldImps, oldG) f = do
+ (path,s) <- readFileLibraryIOE oldInitPath f
+ if not (elem path oldImps)
+ then do
+ (imps,g) <- parseOldGrammar path
+ foldM (getImports (initFilePath path)) (path : oldImps, g ++ oldG) imps
+ else
+ return (oldImps, oldG)
+
+parseOldGrammar :: FilePath -> IOE ([FilePath],[A.TopDef])
+parseOldGrammar file = do
+ putStrLnE $ "reading old file" +++ file
+ s <- ioeIO $ readFileIf file
+ A.OldGr incl topdefs <- ioeErr $ pOldGrammar $ oldLexer $ fixNewlines s
+ includes <- ioeErr $ transInclude incl
+ return (includes, topdefs)
+
+----
+
+-- | To resolve the new reserved words:
+-- change them by turning the final letter to upper case.
+--- There is a risk of clash.
+oldLexer :: String -> [L.Token]
+oldLexer = map change . L.tokens . BS.pack where
+ change t = case t of
+ (L.PT p (L.TS s)) | elem s newReservedWords ->
+ (L.PT p (L.TV (init s ++ [toUpper (last s)])))
+ _ -> t
+
+getCFGrammar :: Options -> FilePath -> IOE SourceGrammar
+getCFGrammar opts file = do
+ let mo = takeWhile (/='.') file
+ s <- ioeIO $ readFileIf file
+ let files = case words (concat (take 1 (lines s))) of
+ "--":"include":fs -> fs
+ _ -> []
+ ss <- ioeIO $ mapM readFileIf files
+ cfs <- ioeErr $ mapM (pCF mo) $ s:ss
+ defs <- return $ cf2grammar $ rules2CF $ concat cfs
+ let g = A.OldGr A.NoIncl defs
+--- let ma = justModuleName file
+--- let mc = 'C':ma ---
+--- let opts' = addOptions (options [useAbsName ma, useCncName mc]) opts
+ ioeErr $ transOldGrammar opts file g
+
+getEBNFGrammar :: Options -> FilePath -> IOE SourceGrammar
+getEBNFGrammar opts file = do
+ let mo = takeWhile (/='.') file
+ s <- ioeIO $ readFileIf file
+ defs <- ioeErr $ pEBNFasGrammar s
+ let g = A.OldGr A.NoIncl defs
+--- let ma = justModuleName file
+--- let mc = 'C':ma ---
+--- let opts' = addOptions (options [useAbsName ma, useCncName mc]) opts
+ ioeErr $ transOldGrammar opts file g
diff --git a/src-3.0/GF/Compile/GrammarToCanon.hs b/src-3.0/GF/Compile/GrammarToCanon.hs
new file mode 100644
index 000000000..09c0d3d95
--- /dev/null
+++ b/src-3.0/GF/Compile/GrammarToCanon.hs
@@ -0,0 +1,293 @@
+----------------------------------------------------------------------
+-- |
+-- Module : GrammarToCanon
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/11 23:24:33 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.23 $
+--
+-- Code generator from optimized GF source code to GFC.
+-----------------------------------------------------------------------------
+
+module GF.Compile.GrammarToCanon (showGFC,
+ redModInfo, redQIdent
+ ) where
+
+import GF.Data.Operations
+import GF.Data.Zipper
+import GF.Infra.Option
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.PrGrammar
+import GF.Infra.Modules
+import GF.Grammar.Macros
+import qualified GF.Canon.AbsGFC as G
+import qualified GF.Canon.GFC as C
+import GF.Canon.MkGFC
+---- import Alias
+import qualified GF.Canon.PrintGFC as P
+
+import Control.Monad
+import Data.List (nub,sortBy)
+
+-- compilation of optimized grammars to canonical GF. AR 5/10/2001 -- 12/5/2003
+
+-- | This is the top-level function printing a gfc file
+showGFC :: SourceGrammar -> String
+showGFC = err id id . liftM (P.printTree . grammar2canon) . redGrammar
+
+-- | any grammar, first trying without dependent types
+-- abstract syntax without dependent types
+redGrammar :: SourceGrammar -> Err C.CanonGrammar
+redGrammar (MGrammar gr) = liftM MGrammar $ mapM redModInfo $ filter active gr where
+ active (_,m) = case typeOfModule m of
+ MTInterface -> False
+ _ -> True
+
+redModInfo :: (Ident, SourceModInfo) -> Err (Ident, C.CanonModInfo)
+redModInfo (c,info) = do
+ c' <- redIdent c
+ info' <- case info of
+ ModMod m -> do
+ let isIncompl = not $ isCompleteModule m
+ (e,os) <- if isIncompl then return ([],[]) else redExtOpen m ----
+ flags <- mapM redFlag $ flags m
+ (a,mt0) <- case mtype m of
+ MTConcrete a -> do
+ a' <- redIdent a
+ return (a', MTConcrete a')
+ MTAbstract -> return (c',MTAbstract) --- c' not needed
+ MTResource -> return (c',MTResource) --- c' not needed
+ MTInterface -> return (c',MTResource) ---- not needed
+ MTInstance _ -> return (c',MTResource) --- c' not needed
+ MTTransfer x y -> return (c',MTTransfer (om x) (om y)) --- c' not needed
+
+ --- this generates empty GFC reosurce for interface and incomplete
+ let js = if isIncompl then emptyBinTree else jments m
+ mt = mt0 ---- if isIncompl then MTResource else mt0
+
+ defss <- mapM (redInfo a) $ tree2list $ js
+ let defs0 = concat defss
+ let lgh = length defs0
+ defs <- return $ sorted2tree $ defs0 -- sorted, but reduced
+ let flags1 = if isIncompl then C.flagIncomplete : flags else flags
+ let flags' = G.Flg (identC "modulesize") (identC ("n"++show lgh)) : flags1
+ return $ ModMod $ Module mt MSComplete flags' e os defs
+ return (c',info')
+ where
+ redExtOpen m = do
+ e' <- case extends m of
+ es -> mapM (liftM inheritAll . redIdent) es
+ os' <- mapM (\o -> case o of
+ OQualif q _ i -> liftM (OSimple q) (redIdent i)
+ _ -> prtBad "cannot translate unqualified open in" c) $ opens m
+ return (e',nub os')
+ om = oSimple . openedModule --- normalizing away qualif
+
+redInfo :: Ident -> (Ident,Info) -> Err [(Ident,C.Info)]
+redInfo am (c,info) = errIn ("translating definition of" +++ prt c) $ do
+ c' <- redIdent c
+ case info of
+ AbsCat (Yes cont) pfs -> do
+ let fs = case pfs of
+ Yes ts -> [(m,c) | Q m c <- ts]
+ _ -> []
+ returns c' $ C.AbsCat cont fs
+ AbsFun (Yes typ) pdf -> do
+ let df = case pdf of
+ Yes t -> t -- definition or "data"
+ _ -> Eqs [] -- primitive notion
+ returns c' $ C.AbsFun typ df
+ AbsTrans t ->
+ returns c' $ C.AbsTrans t
+
+ ResParam (Yes (ps,_)) -> do
+ ps' <- mapM redParam ps
+ returns c' $ C.ResPar ps'
+
+ CncCat pty ptr ppr -> case (pty,ptr,ppr) of
+ (Yes ty, Yes (Abs _ t), Yes pr) -> do
+ ty' <- redCType ty
+ trm' <- redCTerm t
+ pr' <- redCTerm pr
+ return [(c', C.CncCat ty' trm' pr')]
+ _ -> prtBad ("cannot reduce rule for") c
+
+ CncFun mt ptr ppr -> case (mt,ptr,ppr) of
+ (Just (cat,_), Yes trm, Yes pr) -> do
+ cat' <- redIdent cat
+ (xx,body,_) <- termForm trm
+ xx' <- mapM redArgvar xx
+ body' <- errIn (prt body) $ redCTerm body ---- debug
+ pr' <- redCTerm pr
+ return [(c',C.CncFun (G.CIQ am cat') xx' body' pr')]
+ _ -> prtBad ("cannot reduce rule" +++ show info +++ "for") c ---- debug
+
+ AnyInd s b -> do
+ b' <- redIdent b
+ returns c' $ C.AnyInd s b'
+
+ _ -> return [] --- retain some operations
+ where
+ returns f i = return [(f,i)]
+
+redQIdent :: QIdent -> Err G.CIdent
+redQIdent (m,c) = return $ G.CIQ m c
+
+redIdent :: Ident -> Err Ident
+redIdent x
+ | isWildIdent x = return $ identC "h_" --- needed in declarations
+ | otherwise = return $ identC $ prt x ---
+
+redFlag :: Option -> Err G.Flag
+redFlag (Opt (f,[x])) = return $ G.Flg (identC f) (identC x)
+redFlag o = Bad $ "cannot reduce option" +++ prOpt o
+
+redDecl :: Decl -> Err G.Decl
+redDecl (x,a) = liftM2 G.Decl (redIdent x) (redType a)
+
+redType :: Type -> Err G.Exp
+redType = redTerm
+
+redTerm :: Type -> Err G.Exp
+redTerm t = return $ rtExp t
+
+-- to normalize records and record types
+sortByFst :: Ord a => [(a,b)] -> [(a,b)]
+sortByFst = sortBy (\ x y -> compare (fst x) (fst y))
+
+-- resource
+
+redParam :: Param -> Err G.ParDef
+redParam (c,cont) = do
+ c' <- redIdent c
+ cont' <- mapM (redCType . snd) cont
+ return $ G.ParD c' cont'
+
+redArgvar :: Ident -> Err G.ArgVar
+redArgvar x = case x of
+ IA (x,i) -> return $ G.A (identC x) (toInteger i)
+ IAV (x,b,i) -> return $ G.AB (identC x) (toInteger b) (toInteger i)
+ _ -> Bad $ "cannot reduce" +++ show x +++ "as argument variable"
+
+redLindef :: Term -> Err G.Term
+redLindef t = case t of
+ Abs x b -> redCTerm b ---
+ _ -> redCTerm t
+
+redCType :: Type -> Err G.CType
+redCType t = case t of
+ RecType lbs -> do
+ let (ls,ts) = unzip lbs
+ ls' = map redLabel ls
+ ts' <- mapM redCType ts
+ return $ G.RecType $ map (uncurry G.Lbg) $ sortByFst $ zip ls' ts'
+ Table p v -> liftM2 G.Table (redCType p) (redCType v)
+ Q m c -> liftM G.Cn $ redQIdent (m,c)
+ QC m c -> liftM G.Cn $ redQIdent (m,c)
+
+ App (Q (IC "Predef") (IC "Ints")) (EInt n) -> return $ G.TInts (toInteger n)
+
+ Sort "Str" -> return $ G.TStr
+ Sort "Tok" -> return $ G.TStr
+ _ -> prtBad "cannot reduce to canonical the type" t
+
+redCTerm :: Term -> Err G.Term
+redCTerm t = case t of
+ Vr x -> checkAgain
+ (liftM G.Arg $ redArgvar x)
+ (liftM G.LI $ redIdent x) --- for parametrize optimization
+ App _ s -> do -- only constructor applications can remain
+ (_,c,xx) <- termForm t
+ xx' <- mapM redCTerm xx
+ case c of
+ QC p c -> liftM2 G.Par (redQIdent (p,c)) (return xx')
+ Q (IC "Predef") (IC "error") -> fail $ "error: " ++ stringFromTerm s
+ _ -> prtBad "expected constructor head instead of" c
+ Q p c -> liftM G.I (redQIdent (p,c))
+ QC p c -> liftM2 G.Par (redQIdent (p,c)) (return [])
+ R rs -> do
+ let (ls,tts) = unzip rs
+ ls' = map redLabel ls
+ ts <- mapM (redCTerm . snd) tts
+ return $ G.R $ map (uncurry G.Ass) $ sortByFst $ zip ls' ts
+ RecType [] -> return $ G.R [] --- comes out in parsing
+ P tr l -> do
+ tr' <- redCTerm tr
+ return $ G.P tr' (redLabel l)
+ PI tr l _ -> redCTerm $ P tr l -----
+ T i cs -> do
+ ty <- getTableType i
+ ty' <- redCType ty
+ let (ps,ts) = unzip cs
+ ps' <- mapM redPatt ps
+ ts' <- mapM redCTerm ts
+ return $ G.T ty' $ map (uncurry G.Cas) $ zip (map singleton ps') ts'
+ TSh i cs -> do
+ ty <- getTableType i
+ ty' <- redCType ty
+ let (pss,ts) = unzip cs
+ pss' <- mapM (mapM redPatt) pss
+ ts' <- mapM redCTerm ts
+ return $ G.T ty' $ map (uncurry G.Cas) $ zip pss' ts'
+ V ty ts -> do
+ ty' <- redCType ty
+ ts' <- mapM redCTerm ts
+ return $ G.V ty' ts'
+ S u v -> liftM2 G.S (redCTerm u) (redCTerm v)
+ K s -> return $ G.K (G.KS s)
+ EInt i -> return $ G.EInt i
+ EFloat i -> return $ G.EFloat i
+ C u v -> liftM2 G.C (redCTerm u) (redCTerm v)
+ FV ts -> liftM G.FV $ mapM redCTerm ts
+--- Ready ss -> return $ G.Ready [redStr ss] --- obsolete
+
+ Alts (d,vs) -> do ---
+ d' <- redCTermTok d
+ vs' <- mapM redVariant vs
+ return $ G.K $ G.KP d' vs'
+
+ Empty -> return $ G.E
+
+--- Strs ss -> return $ G.Strs [s | K s <- ss] ---
+
+---- Glue obsolete in canon, should not occur here
+ Glue x y -> redCTerm (C x y)
+
+ _ -> Bad ("cannot reduce term" +++ prt t)
+
+redPatt :: Patt -> Err G.Patt
+redPatt p = case p of
+ PP m c ps -> liftM2 G.PC (redQIdent (m,c)) (mapM redPatt ps)
+ PR rs -> do
+ let (ls,tts) = unzip rs
+ ls' = map redLabel ls
+ ts <- mapM redPatt tts
+ return $ G.PR $ map (uncurry G.PAss) $ sortByFst $ zip ls' ts
+ PT _ q -> redPatt q
+ PInt i -> return $ G.PI i
+ PFloat i -> return $ G.PF i
+ PV x -> liftM G.PV $ redIdent x --- for parametrize optimization
+ _ -> prtBad "cannot reduce pattern" p
+
+redLabel :: Label -> G.Label
+redLabel (LIdent s) = G.L $ identC s
+redLabel (LVar i) = G.LV $ toInteger i
+
+redVariant :: (Term, Term) -> Err G.Variant
+redVariant (v,c) = do
+ v' <- redCTermTok v
+ c' <- redCTermTok c
+ return $ G.Var v' c'
+
+redCTermTok :: Term -> Err [String]
+redCTermTok t = case t of
+ K s -> return [s]
+ Empty -> return []
+ C a b -> liftM2 (++) (redCTermTok a) (redCTermTok b)
+ Strs ss -> return [s | K s <- ss] ---
+ _ -> prtBad "cannot get strings from term" t
+
diff --git a/src-3.0/GF/Compile/MkConcrete.hs b/src-3.0/GF/Compile/MkConcrete.hs
new file mode 100644
index 000000000..d016a7e47
--- /dev/null
+++ b/src-3.0/GF/Compile/MkConcrete.hs
@@ -0,0 +1,154 @@
+----------------------------------------------------------------------
+-- |
+-- Module : MkConcrete
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date:
+-- > CVS $Author:
+-- > CVS $Revision:
+--
+-- Compile a gfe file into a concrete syntax by using the parser on a resource grammar.
+-----------------------------------------------------------------------------
+
+module GF.Compile.MkConcrete (mkConcretes) where
+
+import GF.Grammar.Values (Tree,tree2exp)
+import GF.Grammar.PrGrammar (prt_,prModule)
+import GF.Grammar.Grammar --- (Term(..),SourceModule)
+import GF.Grammar.Macros (composSafeOp, composOp, record2subst, zIdent)
+import GF.Compile.ShellState --(firstStateGrammar,stateGrammarWords)
+import GF.Compile.PGrammar (pTerm,pTrm)
+import GF.Compile.Compile
+import GF.Compile.PrOld (stripTerm)
+import GF.Compile.GetGrammar
+import GF.API
+import GF.API.IOGrammar
+import qualified GF.Embed.EmbedAPI as EA
+
+import GF.Data.Operations
+import GF.Infra.UseIO
+import GF.Infra.Option
+import GF.Infra.Modules
+import GF.Infra.ReadFiles
+import GF.System.Arch
+import GF.UseGrammar.Treebank
+
+import System.Directory
+import System.FilePath
+import Data.Char
+import Control.Monad
+import Data.List
+
+-- translate strings into lin rules by parsing in a resource
+-- grammar. AR 2/6/2005
+
+-- Format of rule (on one line):
+-- lin F x y = in C "ssss" ;
+-- Format of resource path (on first line):
+-- --# -resource=PATH
+-- Other lines are copied verbatim.
+-- A sequence of files can be processed with the same resource without
+-- rebuilding the grammar and parser.
+
+-- notice: we use a hand-crafted lexer and parser in order to preserve
+-- the layout and comments in the rest of the file.
+
+mkConcretes :: Options -> [FilePath] -> IO ()
+mkConcretes opts files = do
+ ress <- mapM getResPath files
+ let grps = groupBy (\a b -> fst a == fst b) $
+ sortBy (\a b -> compare (fst a) (fst b)) $ zip ress files
+ mapM_ (mkCncGroups opts) [(rp,map snd gs) | gs@((rp,_):_) <- grps]
+
+mkCncGroups opts0 ((res,path),files) = do
+ putStrLnFlush $ "Going to preprocess examples in " ++ unwords files
+ putStrLn $ "Compiling resource " ++ res
+ let opts = addOptions (options [beSilent,pathList path]) opts0
+ let treebank = oElem (iOpt "treebank") opts
+ resf <- useIOE res $ do
+ (fp,_) <- readFileLibraryIOE "" res
+ return fp
+ egr <- appIOE $ shellStateFromFiles opts emptyShellState resf
+ (parser,morpho) <- if treebank then do
+ tb <- err (\_ -> error $ "no treebank of name" +++ path)
+ return
+ (egr >>= flip findTreebank (zIdent path))
+ return (\_ -> flip (,) "Not in treebank" . map pTrm . lookupTreebank tb,
+ isWordInTreebank tb)
+ else do
+ gr <- err (\s -> putStrLn s >> error "resource grammar rejected")
+ (return . firstStateGrammar) egr
+ return
+ (\cat s ->
+ errVal ([],"No parse") $
+ optParseArgErrMsg (options [newFParser, firstCat cat, beVerbose]) gr s >>=
+ (\ (ts,e) -> return (map tree2exp ts, e)) ,
+ isKnownWord gr)
+ putStrLn "Building parser"
+ mapM_ (mkConcrete parser morpho) files
+
+type Parser = String -> String -> ([Term],String)
+type Morpho = String -> Bool
+
+getResPath :: FilePath -> IO (String,String)
+getResPath file = do
+ s <- liftM lines $ readFileIf file
+ case filter (not . all isSpace) s of
+ res:path:_ | is "resource" res && is "path" path -> return (val res, val path)
+ res:path:_ | is "resource" res && is "treebank" path -> return (val res, val path)
+ res:_ | is "resource" res -> return (val res, "")
+ _ -> error
+ "expected --# -resource=FILE and optional --# -path=PATH or --# -treebank=IDENT"
+ where
+ val = dropWhile (isSpace) . tail . dropWhile (not . (=='='))
+ is tag s = case words s of
+ "--#":w:_ -> isPrefixOf ('-':tag) w
+ _ -> False
+
+
+mkConcrete :: Parser -> Morpho -> FilePath -> IO ()
+mkConcrete parser morpho file = do
+ src <- appIOE (getSourceModule noOptions file) >>= err error return
+ let (src',msgs) = mkModule parser morpho src
+ let out = addExtension (justModuleName file) "gf"
+ writeFile out $ "-- File generated by GF from " ++ file
+ appendFile out "\n"
+ appendFile out (prModule src')
+ appendFile out "{-\n"
+ appendFile out $ unlines $ filter (not . null) msgs
+ appendFile out "-}\n"
+
+mkModule :: Parser -> Morpho -> SourceModule -> (SourceModule,[String])
+mkModule parser morpho (name,src) = case src of
+ ModMod m@(Module mt st fs me ops js) ->
+
+ let js1 = jments m
+ (js2,msgs) = err error id $ appSTM (mapMTree mkInfo js1) []
+ mod2 = ModMod $ Module mt st fs me ops $ js2
+ in ((name,mod2), msgs)
+ where
+ mkInfo ni@(name,info) = case info of
+ CncFun mt (Yes trm) ppr -> do
+ trm' <- mkTrm trm
+ return (name, CncFun mt (Yes trm') ppr)
+ _ -> return ni
+ where
+ mkTrm t = case t of
+ Example (P _ cat) s -> parse cat s t
+ Example (Vr cat) s -> parse cat s t
+ _ -> composOp mkTrm t
+ parse cat s t = case parser (prt_ cat) s of
+ (tr:[], _) -> do
+ updateSTM ((("PARSED in" +++ prt_ name) : s : [prt_ tr]) ++)
+ return $ stripTerm tr
+ (tr:trs,_) -> do
+ updateSTM ((("AMBIGUOUS in" +++ prt_ name) : s : map prt_ trs) ++)
+ return $ stripTerm tr
+ ([],ms) -> do
+ updateSTM ((("NO PARSE in" +++ prt_ name) : s : ms : [morph s]) ++)
+ return t
+ morph s = case [w | w <- words s, not (morpho w)] of
+ [] -> ""
+ ws -> "unknown words: " ++ unwords ws
diff --git a/src-3.0/GF/Compile/MkResource.hs b/src-3.0/GF/Compile/MkResource.hs
new file mode 100644
index 000000000..10831b5c6
--- /dev/null
+++ b/src-3.0/GF/Compile/MkResource.hs
@@ -0,0 +1,128 @@
+----------------------------------------------------------------------
+-- |
+-- Module : MkResource
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/30 21:08:14 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.14 $
+--
+-- Compile a gfc module into a "reuse" gfr resource, interface, or instance.
+-----------------------------------------------------------------------------
+
+module GF.Compile.MkResource (makeReuse) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Grammar.Macros
+import GF.Grammar.Lockfield
+import GF.Grammar.PrGrammar
+
+import GF.Data.Operations
+
+import Control.Monad
+
+-- | extracting resource r from abstract + concrete syntax.
+-- AR 21\/8\/2002 -- 22\/6\/2003 for GF with modules
+makeReuse :: SourceGrammar -> Ident -> [(Ident,MInclude Ident)] ->
+ MReuseType Ident -> Err SourceRes
+makeReuse gr r me mrc = do
+ flags <- return [] --- no flags are passed: they would not make sense
+ case mrc of
+ MRResource c -> do
+ (ops,jms) <- mkFull True c
+ return $ Module MTResource MSComplete flags me ops jms
+
+ MRInstance c a -> do
+ (ops,jms) <- mkFull False c
+ return $ Module (MTInstance a) MSComplete flags me ops jms
+
+ MRInterface c -> do
+ mc <- lookupModule gr c
+
+ (ops,jms) <- case mc of
+ ModMod m -> case mtype m of
+ MTAbstract -> liftM ((,) (opens m)) $
+ mkResDefs True False gr r c me
+ (extend m) (jments m) emptyBinTree
+ _ -> prtBad "expected abstract to be the type of" c
+ _ -> prtBad "expected abstract to be the type of" c
+
+ return $ Module MTInterface MSIncomplete flags me ops jms
+
+ where
+ mkFull hasT c = do
+ mc <- lookupModule gr c
+
+ case mc of
+ ModMod m -> case mtype m of
+ MTConcrete a -> do
+ ma <- lookupModule gr a
+ jmsA <- case ma of
+ ModMod m' -> return $ jments m'
+ _ -> prtBad "expected abstract to be the type of" a
+ liftM ((,) (opens m)) $
+ mkResDefs hasT True gr r a me (extend m) jmsA (jments m)
+ _ -> prtBad "expected concrete to be the type of" c
+ _ -> prtBad "expected concrete to be the type of" c
+
+
+-- | the first Boolean indicates if the type needs be given
+-- the second Boolean indicates if the definition needs be given
+mkResDefs :: Bool -> Bool ->
+ SourceGrammar -> Ident -> Ident ->
+ [(Ident,MInclude Ident)] -> [(Ident,MInclude Ident)] ->
+ BinTree Ident Info -> BinTree Ident Info ->
+ Err (BinTree Ident Info)
+mkResDefs hasT isC gr r a mext maext abs cnc = mapMTree (mkOne a maext) abs where
+
+ ifTyped = yes --- if hasT then yes else const nope --- needed for TC
+ ifCompl = if isC then yes else const nope
+ doIf b t = if b then t else return typeType -- latter value not used
+
+ mkOne a mae (f,info) = case info of
+ AbsCat _ _ -> do
+ typ <- doIf isC $ err (const (return defLinType)) return $ look cnc f
+ typ' <- doIf isC $ lockRecType f typ
+ return (f, ResOper (ifTyped typeType) (ifCompl typ'))
+ AbsFun (Yes typ0) _ -> do
+ trm <- doIf isC $ look cnc f
+ testErr (not (isHardType typ0))
+ ("cannot build reuse for function" +++ prt f +++ ":" +++ prt typ0)
+ typ <- redirTyp True a mae typ0
+ cat <- valCat typ
+ trm' <- doIf isC $ unlockRecord (snd cat) trm
+ return (f, ResOper (ifTyped typ) (ifCompl trm'))
+ AnyInd b n -> do
+ mo <- lookupModMod gr n
+ info' <- lookupInfo mo f
+ mkOne n (extend mo) (f,info')
+
+ look cnc f = do
+ info <- lookupTree prt f cnc
+ case info of
+ CncCat (Yes ty) _ _ -> return ty
+ CncCat _ _ _ -> return defLinType
+ CncFun _ (Yes tr) _ -> return tr
+ AnyInd _ n -> do
+ mo <- lookupModMod gr n
+ t <- look (jments mo) f
+ redirTyp False n (extend mo) t
+ _ -> prtBad "not enough information to reuse" f
+
+ -- type constant qualifications changed from abstract to resource
+ redirTyp always a mae ty = case ty of
+ Q _ c | always -> return $ Q r c
+ Q n c | n == a || [n] == map fst mae -> return $ Q r c ---- FIX for non-singleton exts
+ _ -> composOp (redirTyp always a mae) ty
+
+-- | no reuse for functions of HO\/dep types
+isHardType t = case t of
+ Prod x a b -> not (isWild x) || isHardType a || isHardType b
+ App _ _ -> True
+ _ -> False
+ where
+ isWild x = isWildIdent x || prt x == "h_" --- produced by transl from canon
diff --git a/src-3.0/GF/Compile/MkUnion.hs b/src-3.0/GF/Compile/MkUnion.hs
new file mode 100644
index 000000000..b4b1f40c8
--- /dev/null
+++ b/src-3.0/GF/Compile/MkUnion.hs
@@ -0,0 +1,83 @@
+----------------------------------------------------------------------
+-- |
+-- Module : MkUnion
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:21:39 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.7 $
+--
+-- building union of modules.
+-- AR 1\/3\/2004 --- OBSOLETE 15\/9\/2004 with multiple inheritance
+-----------------------------------------------------------------------------
+
+module GF.Compile.MkUnion (makeUnion) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Grammar.Macros
+import GF.Grammar.PrGrammar
+
+import GF.Data.Operations
+import GF.Infra.Option
+
+import Data.List
+import Control.Monad
+
+makeUnion :: SourceGrammar -> Ident -> ModuleType Ident -> [(Ident,[Ident])] ->
+ Err SourceModule
+makeUnion gr m ty imps = do
+ ms <- mapM (lookupModMod gr . fst) imps
+ typ <- return ty ---- getTyp ms
+ ext <- getExt [i | Just i <- map extends ms]
+ ops <- return $ nub $ concatMap opens ms
+ flags <- return $ concatMap flags ms
+ js <- liftM (buildTree . concat) $ mapM getJments imps
+ return $ (m, ModMod (Module typ MSComplete flags ext ops js))
+
+ where
+ getExt es = case es of
+ [] -> return Nothing
+ i:is -> if all (==i) is then return (Just i)
+ else Bad "different extended modules in union forbidden"
+ getJments (i,fs) = do
+ m <- lookupModMod gr i
+ let js = jments m
+ if null fs
+ then
+ return (map (unqual i) $ tree2list js)
+ else do
+ ds <- mapM (flip justLookupTree js) fs
+ return $ map (unqual i) $ zip fs ds
+
+ unqual i (f,d) = curry id f $ case d of
+ AbsCat pty pts -> AbsCat (qualCo pty) (qualPs pts)
+ AbsFun pty pt -> AbsFun (qualP pty) (qualP pt)
+ AbsTrans t -> AbsTrans $ qual t
+ ResOper pty pt -> ResOper (qualP pty) (qualP pt)
+ CncCat pty pt pp -> CncCat (qualP pty) (qualP pt) (qualP pp)
+ CncFun mp pt pp -> CncFun (qualLin mp) (qualP pt) (qualP pp) ---- mp
+ ResParam (Yes ps) -> ResParam (yes (map qualParam ps))
+ ResValue pty -> ResValue (qualP pty)
+ _ -> d
+ where
+ qualP pt = case pt of
+ Yes t -> yes $ qual t
+ _ -> pt
+ qualPs pt = case pt of
+ Yes ts -> yes $ map qual ts
+ _ -> pt
+ qualCo pco = case pco of
+ Yes co -> yes $ [(x,qual t) | (x,t) <- co]
+ _ -> pco
+ qual t = case t of
+ Q m c | m==i -> Cn c
+ QC m c | m==i -> Cn c
+ _ -> composSafeOp qual t
+ qualParam (p,co) = (p,[(x,qual t) | (x,t) <- co])
+ qualLin (Just (c,(co,t))) = (Just (c,([(x,qual t) | (x,t) <- co], qual t)))
+ qualLin Nothing = Nothing
+
diff --git a/src-3.0/GF/Compile/ModDeps.hs b/src-3.0/GF/Compile/ModDeps.hs
new file mode 100644
index 000000000..8331057d1
--- /dev/null
+++ b/src-3.0/GF/Compile/ModDeps.hs
@@ -0,0 +1,153 @@
+----------------------------------------------------------------------
+-- |
+-- Module : ModDeps
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/11 23:24:34 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.14 $
+--
+-- Check correctness of module dependencies. Incomplete.
+--
+-- AR 13\/5\/2003
+-----------------------------------------------------------------------------
+
+module GF.Compile.ModDeps (mkSourceGrammar,
+ moduleDeps,
+ openInterfaces,
+ requiredCanModules
+ ) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Option
+import GF.Grammar.PrGrammar
+import GF.Compile.Update
+import GF.Grammar.Lookup
+import GF.Infra.Modules
+
+import GF.Data.Operations
+
+import Control.Monad
+import Data.List
+
+-- | 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]
+ _ -> return () --- Bad $ "bug: ModDeps does not treat" +++ show mo
+ where
+
+ test ms = testErr (all (`notElem` ns) ms)
+ ("import names clashing with module names among" +++
+ unwords (map prt ms))
+
+type Dependencies = [(IdentM Ident,[IdentM Ident])]
+
+-- | to decide what modules immediately depend on what, and check if the
+-- dependencies are appropriate
+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 of-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 <- mapM (lookupModuleType gr) es
+ testErr (all (compatMType ety) ests) "inappropriate extension module type"
+---- osts <- mapM (lookupModuleType gr . openedModule) os
+---- testErr (all (compatOType oty) osts) "inappropriate open module type"
+ let ab = case it of
+ IdentM _ (MTConcrete a) -> [IdentM a MTAbstract]
+ _ -> [] ----
+ return (it, ab ++
+ [IdentM e ety | e <- es] ++
+ [IdentM (openedModule o) oty | o <- os])
+
+ -- check for superficial compatibility, not submodule relation etc: what can be extended
+ compatMType mt0 mt = case (mt0,mt) of
+ (MTResource, MTConcrete _) -> True
+ (MTInstance _, MTConcrete _) -> True
+ (MTInterface, MTAbstract) -> True
+ (MTConcrete _, MTConcrete _) -> True
+ (MTInstance _, MTInstance _) -> True
+ (MTReuse _, MTReuse _) -> True
+ (MTInstance _, MTResource) -> True
+ (MTResource, MTInstance _) -> True
+ ---- some more?
+ _ -> mt0 == mt
+ -- in the same way; this defines what can be opened
+ compatOType mt0 mt = case mt0 of
+ MTAbstract -> mt == MTAbstract
+ MTTransfer _ _ -> mt == MTAbstract
+ _ -> case mt of
+ MTResource -> True
+ MTReuse _ -> True
+ MTInterface -> True
+ MTInstance _ -> True
+ _ -> False
+
+ gr = MGrammar ms --- hack
+
+openInterfaces :: Dependencies -> Ident -> Err [Ident]
+openInterfaces ds m = do
+ let deps = [(i,ds) | (IdentM i _,ds) <- ds]
+ let more (c,_) = [(i,mt) | Just is <- [lookup c deps], IdentM i mt <- is]
+ let mods = iterFix (concatMap more) (more (m,undefined))
+ return $ [i | (i,MTInterface) <- mods]
+
+-- | this function finds out what modules are really needed in the canonical gr.
+-- its argument is typically a concrete module name
+requiredCanModules :: (Ord i, Show i) => Bool -> MGrammar i f a -> i -> [i]
+requiredCanModules isSingle gr c = nub $ filter notReuse ops ++ exts where
+ exts = allExtends gr c
+ ops = if isSingle
+ then map fst (modules gr)
+ else iterFix (concatMap more) $ exts
+ more i = errVal [] $ do
+ m <- lookupModMod gr i
+ return $ extends m ++ [o | o <- map openedModule (opens m)]
+ notReuse i = errVal True $ do
+ m <- lookupModMod gr i
+ return $ isModRes m -- to exclude reused Cnc and Abs from required
+
+
+{-
+-- to test
+exampleDeps = [
+ (ir "Nat",[ii "Gen", ir "Adj"]),
+ (ir "Adj",[ii "Num", ii "Gen", ir "Nou"]),
+ (ir "Nou",[ii "Cas"])
+ ]
+
+ii s = IdentM (IC s) MTInterface
+ir s = IdentM (IC s) MTResource
+-}
+
diff --git a/src-3.0/GF/Compile/NewRename.hs b/src-3.0/GF/Compile/NewRename.hs
new file mode 100644
index 000000000..cec8ed24f
--- /dev/null
+++ b/src-3.0/GF/Compile/NewRename.hs
@@ -0,0 +1,294 @@
+----------------------------------------------------------------------
+-- |
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:21:41 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.6 $
+--
+-- AR 14\/5\/2003
+--
+-- The top-level function 'renameGrammar' does several things:
+--
+-- - extends each module symbol table by indirections to extended module
+--
+-- - changes unqualified and as-qualified imports to absolutely qualified
+--
+-- - goes through the definitions and resolves names
+--
+-- Dependency analysis between modules has been performed before this pass.
+-- Hence we can proceed by @fold@ing "from left to right".
+-----------------------------------------------------------------------------
+
+module GF.Compile.NewRename (renameSourceTerm, renameModule) where
+
+import GF.Grammar.Grammar
+import GF.Grammar.Values
+import GF.Infra.Modules
+import GF.Infra.Ident
+import GF.Grammar.Macros
+import GF.Grammar.PrGrammar
+import GF.Grammar.AppPredefined
+import GF.Grammar.Lookup
+import GF.Compile.Extend
+import GF.Data.Operations
+
+import Control.Monad
+
+-- | this gives top-level access to renaming term input in the cc command
+renameSourceTerm :: SourceGrammar -> Ident -> Term -> Err Term
+renameSourceTerm g m t = do
+ mo <- lookupErr m (modules g)
+ let status = (modules g,(m,mo)) --- <- buildStatus g m mo
+ renameTerm status [] t
+
+-- | this is used in the compiler, separately for each module
+renameModule :: [SourceModule] -> SourceModule -> Err [SourceModule]
+renameModule ms (name,mod) = errIn ("renaming module" +++ prt name) $ case mod of
+ ModMod m@(Module mt st fs me ops js) -> do
+ let js1 = jments m
+ let status = (ms, (name, mod))
+ js2 <- mapMTree (renameInfo status) js1
+ let mod2 = ModMod $ Module mt st fs me (map forceQualif ops) js2
+ return $ (name,mod2) : ms
+
+type Status = ([SourceModule],SourceModule) --- (StatusTree, [(OpenSpec Ident, StatusTree)])
+
+--- type StatusTree = BinTree (Ident,StatusInfo)
+
+--- type StatusInfo = Ident -> Term
+
+lookupStatusInfo :: Ident -> SourceModule -> Err Term
+lookupStatusInfo c (q,ModMod m) = do
+ i <- lookupTree prt c $ jments m
+ return $ case i of
+ AbsFun _ (Yes EData) -> QC q c
+ ResValue _ -> QC q c
+ ResParam _ -> QC q c
+ AnyInd True n -> QC n c --- should go further?
+ AnyInd False n -> Q n c
+ _ -> Q q c
+lookupStatusInfo c (q,_) = prtBad "ModMod expected for" q
+
+lookupStatusInfoMany :: [SourceModule] -> Ident -> Err Term
+lookupStatusInfoMany (m:ms) c = case lookupStatusInfo c m of
+ Ok v -> return v
+ _ -> lookupStatusInfoMany ms c
+lookupStatusInfoMany [] x =
+ prtBad "renaming failed to find unqualified constant" x
+---- should also give error if stg is found in more than one module
+
+renameIdentTerm :: Status -> Term -> Err Term
+renameIdentTerm env@(imps,act@(_,ModMod this)) t =
+ errIn ("atomic term" +++ prt t +++ "given" +++ unwords (map (prt . fst) qualifs)) $
+ case t of
+ Vr c -> do
+ f <- err (predefAbs c) return $ lookupStatusInfoMany openeds c
+ return $ f
+ Cn c -> do
+ f <- lookupStatusInfoMany openeds c
+ return $ f
+ Q m' c | m' == cPredef {- && isInPredefined c -} -> return t
+ Q m' c -> do
+ m <- lookupErr m' qualifs
+ f <- lookupStatusInfo c m
+ return $ f
+ QC m' c | m' == cPredef {- && isInPredefined c -} -> return t
+ QC m' c -> do
+ m <- lookupErr m' qualifs
+ f <- lookupStatusInfo c m
+ return $ f
+ _ -> return t
+ where
+ openeds = act : [(m,st) | OSimple _ m <- opens this, Just st <- [lookup m imps]]
+ qualifs =
+ [(m, (n,st)) | OQualif _ m n <- opens this, Just st <- [lookup n imps]]
+ ++
+ [(m, (m,st)) | OSimple _ m <- opens this, Just st <- [lookup m imps]]
+ -- qualif is always possible
+
+ -- this facility is mainly for BWC with GF1: you need not import PredefAbs
+ predefAbs c s = case c of
+ IC "Int" -> return $ Q cPredefAbs cInt
+ IC "String" -> return $ Q cPredefAbs cString
+ _ -> Bad s
+
+-- | would it make sense to optimize this by inlining?
+renameIdentPatt :: Status -> Patt -> Err Patt
+renameIdentPatt env p = do
+ let t = patt2term p
+ t' <- renameIdentTerm env t
+ term2patt t'
+
+{- deprec !
+info2status :: Maybe Ident -> (Ident,Info) -> (Ident,StatusInfo)
+info2status mq (c,i) = (c, case i of
+ AbsFun _ (Yes EData) -> maybe Con QC mq
+ ResValue _ -> maybe Con QC mq
+ ResParam _ -> maybe Con QC mq
+ AnyInd True m -> maybe Con (const (QC m)) mq
+ AnyInd False m -> maybe Cn (const (Q m)) mq
+ _ -> maybe Cn Q mq
+ )
+
+tree2status :: OpenSpec Ident -> BinTree (Ident,Info) -> BinTree (Ident,StatusInfo)
+tree2status o = case o of
+ OSimple _ i -> mapTree (info2status (Just i))
+ OQualif _ i j -> mapTree (info2status (Just j))
+
+buildStatus :: SourceGrammar -> Ident -> SourceModInfo -> Err Status
+buildStatus gr c mo = let mo' = self2status c mo in case mo of
+ ModMod m -> do
+ let gr1 = MGrammar $ (c,mo) : modules gr
+ ops = [OSimple OQNormal e | e <- allExtendsPlus gr1 c] ++ allOpens m
+ mods <- mapM (lookupModule gr1 . openedModule) ops
+ let sts = map modInfo2status $ zip ops mods
+ return $ if isModCnc m
+ then (NT, reverse sts) -- the module itself does not define any names
+ else (mo',reverse sts) -- so the empty ident is not needed
+
+modInfo2status :: (OpenSpec Ident,SourceModInfo) -> (OpenSpec Ident, StatusTree)
+modInfo2status (o,i) = (o,case i of
+ ModMod m -> tree2status o (jments m)
+ )
+
+self2status :: Ident -> SourceModInfo -> StatusTree
+self2status c i = mapTree (info2status (Just c)) js where -- qualify internal
+ js = case i of
+ ModMod m
+ | isModTrans m -> sorted2tree $ filter noTrans $ tree2list $ jments m
+ | otherwise -> jments m
+ noTrans (_,d) = case d of -- to enable other than transfer js in transfer module
+ AbsTrans _ -> False
+ _ -> True
+-}
+
+forceQualif o = case o of
+ OSimple q i -> OQualif q i i
+ OQualif q _ i -> OQualif q i i
+
+renameInfo :: Status -> (Ident,Info) -> Err (Ident,Info)
+renameInfo status (i,info) = errIn ("renaming definition of" +++ prt i) $
+ liftM ((,) i) $ case info of
+ AbsCat pco pfs -> liftM2 AbsCat (renPerh (renameContext status) pco)
+ (renPerh (mapM rent) pfs)
+ AbsFun pty ptr -> liftM2 AbsFun (ren pty) (ren ptr)
+ AbsTrans f -> liftM AbsTrans (rent f)
+
+ ResOper pty ptr -> liftM2 ResOper (ren pty) (ren ptr)
+ ResParam pp -> liftM ResParam (renPerh (mapM (renameParam status)) pp)
+ ResValue t -> liftM ResValue (ren t)
+ CncCat pty ptr ppr -> liftM3 CncCat (ren pty) (ren ptr) (ren ppr)
+ CncFun mt ptr ppr -> liftM2 (CncFun mt) (ren ptr) (ren ppr)
+ _ -> return info
+ where
+ ren = renPerh rent
+ rent = renameTerm status []
+
+renPerh ren pt = case pt of
+ Yes t -> liftM Yes $ ren t
+ _ -> return pt
+
+renameTerm :: Status -> [Ident] -> Term -> Err Term
+renameTerm env vars = ren vars where
+ ren vs trm = case trm of
+ Abs x b -> liftM (Abs x) (ren (x:vs) b)
+ Prod x a b -> liftM2 (Prod x) (ren vs a) (ren (x:vs) b)
+ Typed a b -> liftM2 Typed (ren vs a) (ren vs b)
+ Vr x
+ | elem x vs -> return trm
+ | otherwise -> renid trm
+ Cn _ -> renid trm
+ Con _ -> renid trm
+ Q _ _ -> renid trm
+ QC _ _ -> renid trm
+ Eqs eqs -> liftM Eqs $ mapM (renameEquation env vars) eqs
+ T i cs -> do
+ i' <- case i of
+ TTyped ty -> liftM TTyped $ ren vs ty -- the only annotation in source
+ _ -> return i
+ liftM (T i') $ mapM (renCase vs) cs
+
+ Let (x,(m,a)) b -> do
+ m' <- case m of
+ Just ty -> liftM Just $ ren vs ty
+ _ -> return m
+ a' <- ren vs a
+ b' <- ren (x:vs) b
+ return $ Let (x,(m',a')) b'
+
+ P t@(Vr r) l -- for constant t we know it is projection
+ | elem r vs -> return trm -- var proj first
+ | otherwise -> case renid (Q r (label2ident l)) of -- qualif second
+ Ok t -> return t
+ _ -> liftM (flip P l) $ renid t -- const proj last
+
+ _ -> composOp (ren vs) trm
+
+ renid = renameIdentTerm env
+ renCase vs (p,t) = do
+ (p',vs') <- renpatt p
+ t' <- ren (vs' ++ vs) t
+ return (p',t')
+ renpatt = renamePattern env
+
+-- | vars not needed in env, since patterns always overshadow old vars
+renamePattern :: Status -> Patt -> Err (Patt,[Ident])
+renamePattern env patt = case patt of
+
+ PC c ps -> do
+ c' <- renameIdentTerm env $ Cn c
+ psvss <- mapM renp ps
+ let (ps',vs) = unzip psvss
+ case c' of
+ QC p d -> return (PP p d ps', concat vs)
+ Q p d -> return (PP p d ps', concat vs) ---- should not happen
+ _ -> prtBad "unresolved pattern" c' ---- (PC c ps', concat vs)
+
+---- PP p c ps -> (PP p c ps',concat vs') where (ps',vs') = unzip $ map renp ps
+
+ PV x -> case renid patt of
+ Ok p -> return (p,[])
+ _ -> return (patt, [x])
+
+ PR r -> do
+ let (ls,ps) = unzip r
+ psvss <- mapM renp ps
+ let (ps',vs') = unzip psvss
+ return (PR (zip ls ps'), concat vs')
+
+ _ -> return (patt,[])
+
+ where
+ renp = renamePattern env
+ renid = renameIdentPatt env
+
+renameParam :: Status -> (Ident, Context) -> Err (Ident, Context)
+renameParam env (c,co) = do
+ co' <- renameContext env co
+ return (c,co')
+
+renameContext :: Status -> Context -> Err Context
+renameContext b = renc [] where
+ renc vs cont = case cont of
+ (x,t) : xts
+ | isWildIdent x -> do
+ t' <- ren vs t
+ xts' <- renc vs xts
+ return $ (x,t') : xts'
+ | otherwise -> do
+ t' <- ren vs t
+ let vs' = x:vs
+ xts' <- renc vs' xts
+ return $ (x,t') : xts'
+ _ -> return cont
+ ren = renameTerm b
+
+-- | vars not needed in env, since patterns always overshadow old vars
+renameEquation :: Status -> [Ident] -> Equation -> Err Equation
+renameEquation b vs (ps,t) = do
+ (ps',vs') <- liftM unzip $ mapM (renamePattern b) ps
+ t' <- renameTerm b (concat vs' ++ vs) t
+ return (ps',t')
diff --git a/src-3.0/GF/Compile/NoParse.hs b/src-3.0/GF/Compile/NoParse.hs
new file mode 100644
index 000000000..c8f828970
--- /dev/null
+++ b/src-3.0/GF/Compile/NoParse.hs
@@ -0,0 +1,49 @@
+----------------------------------------------------------------------
+-- |
+-- Module : NoParse
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/14 16:03:41 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.1 $
+--
+-- Probabilistic abstract syntax. AR 30\/10\/2005
+--
+-- (c) Aarne Ranta 2005 under GNU GPL
+--
+-- Contents: decide what lin rules no parser is generated.
+-- Usually a list of noparse idents from 'i -boparse=file'.
+
+-----------------------------------------------------------------------------
+
+module GF.Compile.NoParse (
+ NoParse -- = Ident -> Bool
+ ,getNoparseFromFile -- :: Opts -> IO NoParse
+ ,doParseAll -- :: NoParse
+ ) where
+
+import GF.Infra.Ident
+import GF.Data.Operations
+import GF.Infra.Option
+
+
+type NoParse = (Ident -> Bool)
+
+doParseAll :: NoParse
+doParseAll = const False
+
+getNoparseFromFile :: Options -> FilePath -> IO NoParse
+getNoparseFromFile opts file = do
+ let f = maybe file id $ getOptVal opts noparseFile
+ s <- readFile f
+ let tree = buildTree $ flip zip (repeat ()) $ concat $ map getIgnores $ lines s
+ tree `seq` return $ igns tree
+ where
+ igns tree i = isInBinTree i tree
+
+-- where
+getIgnores s = case dropWhile (/="--#") (words s) of
+ _:"noparse":fs -> map identC fs
+ _ -> []
diff --git a/src-3.0/GF/Compile/Optimize.hs b/src-3.0/GF/Compile/Optimize.hs
new file mode 100644
index 000000000..a540ee715
--- /dev/null
+++ b/src-3.0/GF/Compile/Optimize.hs
@@ -0,0 +1,300 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Optimize
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/09/16 13:56:13 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.18 $
+--
+-- Top-level partial evaluation for GF source modules.
+-----------------------------------------------------------------------------
+
+module GF.Compile.Optimize (optimizeModule) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Grammar.PrGrammar
+import GF.Grammar.Macros
+import GF.Grammar.Lookup
+import GF.Grammar.Refresh
+import GF.Grammar.Compute
+import GF.Compile.BackOpt
+import GF.Compile.CheckGrammar
+import GF.Compile.Update
+import GF.Compile.Evaluate
+
+import GF.Data.Operations
+import GF.Infra.CheckM
+import GF.Infra.Option
+
+import Control.Monad
+import Data.List
+
+import Debug.Trace
+
+
+-- conditional trace
+
+prtIf :: (Print a) => Bool -> a -> a
+prtIf b t = if b then trace (" " ++ prt t) t else t
+
+-- experimental evaluation, option to import
+oEval = iOpt "eval"
+
+-- | partial evaluation of concrete syntax. AR 6\/2001 -- 16\/5\/2003 -- 5\/2\/2005.
+-- only do this for resource: concrete is optimized in gfc form
+optimizeModule :: Options -> ([(Ident,SourceModInfo)],EEnv) ->
+ (Ident,SourceModInfo) -> Err ((Ident,SourceModInfo),EEnv)
+optimizeModule opts mse@(ms,eenv) mo@(_,mi) = case mi of
+ ModMod m0@(Module mt st fs me ops js) |
+ st == MSComplete && isModRes m0 && not (oElem oEval oopts)-> do
+ (mo1,_) <- evalModule oopts mse mo
+ let
+ mo2 = case optim of
+ "parametrize" -> shareModule paramOpt mo1 -- parametrization and sharing
+ "values" -> shareModule valOpt mo1 -- tables as courses-of-values
+ "share" -> shareModule shareOpt mo1 -- sharing of branches
+ "all" -> shareModule allOpt mo1 -- first parametrize then values
+ "none" -> mo1 -- no optimization
+ _ -> mo1 -- none; default for src
+ return (mo2,eenv)
+ _ -> evalModule oopts mse mo
+ where
+ oopts = addOptions opts (iOpts (flagsModule mo))
+ optim = maybe "all" id $ getOptVal oopts useOptimizer
+
+evalModule :: Options -> ([(Ident,SourceModInfo)],EEnv) -> (Ident,SourceModInfo) ->
+ Err ((Ident,SourceModInfo),EEnv)
+evalModule oopts (ms,eenv) mo@(name,mod) = case mod of
+
+ ModMod m0@(Module mt st fs me ops js) | st == MSComplete -> case mt of
+ _ | isModRes m0 && not (oElem oEval oopts) -> do
+ let deps = allOperDependencies name js
+ ids <- topoSortOpers deps
+ MGrammar (mod' : _) <- foldM evalOp gr ids
+ return $ (mod',eenv)
+
+ MTConcrete a | oElem oEval oopts -> do
+ (js0,eenv') <- appEvalConcrete gr js eenv
+ js' <- mapMTree (evalCncInfo oopts gr name a) js0 ---- <- gr0 6/12/2005
+ return $ ((name, ModMod (Module mt st fs me ops js')),eenv')
+
+ MTConcrete a -> do
+ js' <- mapMTree (evalCncInfo oopts gr name a) js ---- <- gr0 6/12/2005
+ return $ ((name, ModMod (Module mt st fs me ops js')),eenv)
+
+ _ -> return $ ((name,mod),eenv)
+ _ -> return $ ((name,mod),eenv)
+ where
+ gr0 = MGrammar $ ms
+ gr = MGrammar $ (name,mod) : ms
+
+ evalOp g@(MGrammar ((_, ModMod m) : _)) i = do
+ info <- lookupTree prt i $ jments m
+ info' <- evalResInfo oopts gr (i,info)
+ return $ updateRes g name i info'
+
+-- | only operations need be compiled in a resource, and this is local to each
+-- definition since the module is traversed in topological order
+evalResInfo :: Options -> SourceGrammar -> (Ident,Info) -> Err Info
+evalResInfo oopts gr (c,info) = case info of
+
+ ResOper pty pde -> eIn "operation" $ do
+ pde' <- case pde of
+ Yes de | optres -> liftM yes $ comp de
+ _ -> return pde
+ return $ ResOper pty pde'
+
+ _ -> return info
+ where
+ comp = if optres then computeConcrete gr else computeConcreteRec gr
+ eIn cat = errIn ("Error optimizing" +++ cat +++ prt c +++ ":")
+ optim = maybe "all" id $ getOptVal oopts useOptimizer
+ optres = case optim of
+ "noexpand" -> False
+ _ -> True
+
+
+evalCncInfo ::
+ Options -> SourceGrammar -> Ident -> Ident -> (Ident,Info) -> Err (Ident,Info)
+evalCncInfo opts gr cnc abs (c,info) = do
+
+ seq (prtIf (oElem beVerbose opts) c) $ return ()
+
+ errIn ("optimizing" +++ prt c) $ case info of
+
+ CncCat ptyp pde ppr -> do
+ pde' <- case (ptyp,pde) of
+ (Yes typ, Yes de) ->
+ liftM yes $ pEval ([(strVar, typeStr)], typ) de
+ (Yes typ, Nope) ->
+ liftM yes $ mkLinDefault gr typ >>= partEval noOptions gr ([(strVar, typeStr)],typ)
+ (May b, Nope) ->
+ return $ May b
+ _ -> return pde -- indirection
+
+ ppr' <- liftM yes $ evalPrintname gr c ppr (yes $ K $ prt c)
+
+ return (c, CncCat ptyp pde' ppr')
+
+ CncFun (mt@(Just (_,ty@(cont,val)))) pde ppr ->
+ eIn ("linearization in type" +++ prt (mkProd (cont,val,[])) ++++ "of function") $ do
+ pde' <- case pde of
+ Yes de | notNewEval -> do
+ liftM yes $ pEval ty de
+
+ _ -> return pde
+ ppr' <- liftM yes $ evalPrintname gr c ppr pde'
+ return $ (c, CncFun mt pde' ppr') -- only cat in type actually needed
+
+ _ -> return (c,info)
+ where
+ pEval = partEval opts gr
+ eIn cat = errIn ("Error optimizing" +++ cat +++ prt c +++ ":")
+ notNewEval = not (oElem oEval opts)
+
+-- | the main function for compiling linearizations
+partEval :: Options -> SourceGrammar -> (Context,Type) -> Term -> Err Term
+partEval opts gr (context, val) trm = errIn ("parteval" +++ prt_ trm) $ do
+ let vars = map fst context
+ args = map Vr vars
+ subst = [(v, Vr v) | v <- vars]
+ trm1 = mkApp trm args
+ trm3 <- if globalTable
+ then etaExpand subst trm1 >>= outCase subst
+ else etaExpand subst trm1
+ return $ mkAbs vars trm3
+
+ where
+
+ globalTable = oElem showAll opts --- i -all
+
+ comp g t = {- refreshTerm t >>= -} computeTerm gr g t
+
+ etaExpand su t = do
+ t' <- comp su t
+ case t' of
+ R _ | rightType t' -> comp su t' --- return t' wo noexpand...
+ _ -> recordExpand val t' >>= comp su
+ -- don't eta expand records of right length (correct by type checking)
+ rightType t = case (t,val) of
+ (R rs, RecType ts) -> length rs == length ts
+ _ -> False
+
+ outCase subst t = do
+ pts <- getParams context
+ let (args,ptyps) = unzip $ filter (flip occur t . fst) pts
+ if null args
+ then return t
+ else do
+ let argtyp = RecType $ tuple2recordType ptyps
+ let pvars = map (Vr . zIdent . prt) args -- gets eliminated
+ patt <- term2patt $ R $ tuple2record $ pvars
+ let t' = replace (zip args pvars) t
+ t1 <- comp subst $ T (TTyped argtyp) [(patt, t')]
+ return $ S t1 $ R $ tuple2record args
+
+ --- notice: this assumes that all lin types follow the "old JFP style"
+ getParams = liftM concat . mapM getParam
+ getParam (argv,RecType rs) = return
+ [(P (Vr argv) lab, ptyp) | (lab,ptyp) <- rs, not (isLinLabel lab)]
+ ---getParam (_,ty) | ty==typeStr = return [] --- in lindef
+ getParam (av,ty) =
+ Bad ("record type expected not" +++ prt ty +++ "for" +++ prt av)
+ --- all lin types are rec types
+
+ replace :: [(Term,Term)] -> Term -> Term
+ replace reps trm = case trm of
+ -- this is the important case
+ P _ _ -> maybe trm id $ lookup trm reps
+ _ -> composSafeOp (replace reps) trm
+
+ occur t trm = case trm of
+
+ -- this is the important case
+ P _ _ -> t == trm
+ S x y -> occur t y || occur t x
+ App f x -> occur t x || occur t f
+ Abs _ f -> occur t f
+ R rs -> any (occur t) (map (snd . snd) rs)
+ T _ cs -> any (occur t) (map snd cs)
+ C x y -> occur t x || occur t y
+ Glue x y -> occur t x || occur t y
+ ExtR x y -> occur t x || occur t y
+ FV ts -> any (occur t) ts
+ V _ ts -> any (occur t) ts
+ Let (_,(_,x)) y -> occur t x || occur t y
+ _ -> False
+
+
+-- here we must be careful not to reduce
+-- variants {{s = "Auto" ; g = N} ; {s = "Wagen" ; g = M}}
+-- {s = variants {"Auto" ; "Wagen"} ; g = variants {N ; M}} ;
+
+recordExpand :: Type -> Term -> Err Term
+recordExpand typ trm = case unComputed typ of
+ RecType tys -> case trm of
+ FV rs -> return $ FV [R [assign lab (P r lab) | (lab,_) <- tys] | r <- rs]
+ _ -> return $ R [assign lab (P trm lab) | (lab,_) <- tys]
+ _ -> return trm
+
+
+-- | auxiliaries for compiling the resource
+
+mkLinDefault :: SourceGrammar -> Type -> Err Term
+mkLinDefault gr typ = do
+ case unComputed typ of
+ RecType lts -> mapPairsM mkDefField lts >>= (return . Abs strVar . R . mkAssign)
+ _ -> prtBad "linearization type must be a record type, not" typ
+ where
+ mkDefField typ = case unComputed typ of
+ Table p t -> do
+ t' <- mkDefField t
+ let T _ cs = mkWildCases t'
+ return $ T (TWild p) cs
+ Sort "Str" -> return $ Vr strVar
+ QC q p -> lookupFirstTag gr q p
+ RecType r -> do
+ let (ls,ts) = unzip r
+ ts' <- mapM mkDefField ts
+ return $ R $ [assign l t | (l,t) <- zip ls ts']
+ _ | isTypeInts typ -> return $ EInt 0 -- exists in all as first val
+ _ -> prtBad "linearization type field cannot be" typ
+
+-- | Form the printname: if given, compute. If not, use the computed
+-- lin for functions, cat name for cats (dispatch made in evalCncDef above).
+--- We cannot use linearization at this stage, since we do not know the
+--- defaults we would need for question marks - and we're not yet in canon.
+evalPrintname :: SourceGrammar -> Ident -> MPr -> Perh Term -> Err Term
+evalPrintname gr c ppr lin =
+ case ppr of
+ Yes pr -> comp pr
+ _ -> case lin of
+ Yes t -> return $ K $ clean $ prt $ oneBranch t ---- stringFromTerm
+ _ -> return $ K $ prt c ----
+ where
+ comp = computeConcrete gr
+
+ oneBranch t = case t of
+ Abs _ b -> oneBranch b
+ R (r:_) -> oneBranch $ snd $ snd r
+ T _ (c:_) -> oneBranch $ snd c
+ V _ (c:_) -> oneBranch c
+ FV (t:_) -> oneBranch t
+ C x y -> C (oneBranch x) (oneBranch y)
+ S x _ -> oneBranch x
+ P x _ -> oneBranch x
+ Alts (d,_) -> oneBranch d
+ _ -> t
+
+ --- very unclean cleaner
+ clean s = case s of
+ '+':'+':' ':cs -> clean cs
+ '"':cs -> clean cs
+ c:cs -> c: clean cs
+ _ -> s
+
diff --git a/src-3.0/GF/Compile/PGrammar.hs b/src-3.0/GF/Compile/PGrammar.hs
new file mode 100644
index 000000000..521f616b5
--- /dev/null
+++ b/src-3.0/GF/Compile/PGrammar.hs
@@ -0,0 +1,77 @@
+----------------------------------------------------------------------
+-- |
+-- Module : PGrammar
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/25 10:27:12 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.8 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Compile.PGrammar (pTerm, pTrm, pTrms,
+ pMeta, pzIdent,
+ string2ident
+ ) where
+
+---import LexGF
+import GF.Source.ParGF
+import GF.Source.SourceToGrammar (transExp)
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import qualified GF.Canon.AbsGFC as A
+import qualified GF.Canon.GFC as G
+import GF.Compile.GetGrammar
+import GF.Grammar.Macros
+import GF.Grammar.MMacros
+
+import GF.Data.Operations
+import qualified Data.ByteString.Char8 as BS
+
+pTerm :: String -> Err Term
+pTerm s = do
+ e <- pExp $ myLexer (BS.pack s)
+ transExp e
+
+pTrm :: String -> Term
+pTrm = errVal (vr (zIdent "x")) . pTerm ---
+
+pTrms :: String -> [Term]
+pTrms = map pTrm . sep [] where
+ sep t cs = case cs of
+ ',' : cs2 -> reverse t : sep [] cs2
+ c : cs2 -> sep (c:t) cs2
+ _ -> [reverse t]
+
+pTrm' :: String -> [Term]
+pTrm' = err (const []) singleton . pTerm
+
+pMeta :: String -> Integer
+pMeta _ = 0 ---
+
+pzIdent :: String -> Ident
+pzIdent = zIdent
+
+{-
+string2formsAndTerm :: String -> ([Term],Term)
+string2formsAndTerm s = case s of
+ '[':_:_ -> case span (/=']') s of
+ (x,_:y) -> (pTrms (tail x), pTrm y)
+ _ -> ([],pTrm s)
+ _ -> ([], pTrm s)
+-}
+
+string2ident :: String -> Err Ident
+string2ident s = return $ string2var s
+
+{-
+-- reads the Haskell datatype
+readGrammar :: String -> Err GrammarST
+readGrammar s = case [x | (x,t) <- reads s, ("","") <- lex t] of
+ [x] -> return x
+ [] -> Bad "no parse of Grammar"
+ _ -> Bad "ambiguous parse of Grammar"
+-}
diff --git a/src-3.0/GF/Compile/PrOld.hs b/src-3.0/GF/Compile/PrOld.hs
new file mode 100644
index 000000000..29920fab6
--- /dev/null
+++ b/src-3.0/GF/Compile/PrOld.hs
@@ -0,0 +1,84 @@
+----------------------------------------------------------------------
+-- |
+-- Module : PrOld
+-- Maintainer : GF
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:21:44 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.8 $
+--
+-- a hack to print gf2 into gf1 readable files
+-- Works only for canonical grammars, printed into GFC. Otherwise we would have
+-- problems with qualified names.
+-- --- printnames are not preserved, nor are lindefs
+-----------------------------------------------------------------------------
+
+module GF.Compile.PrOld (printGrammarOld, stripTerm) where
+
+import GF.Grammar.PrGrammar
+import GF.Canon.CanonToGrammar
+import qualified GF.Canon.GFC as GFC
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.Macros
+import GF.Infra.Modules
+import qualified GF.Source.PrintGF as P
+import GF.Source.GrammarToSource
+
+import Data.List
+import GF.Data.Operations
+import GF.Infra.UseIO
+
+printGrammarOld :: GFC.CanonGrammar -> String
+printGrammarOld gr = err id id $ do
+ as0 <- mapM canon2sourceModule [im | im@(_,ModMod m) <- modules gr, isModAbs m]
+ cs0 <- mapM canon2sourceModule
+ [im | im@(_,ModMod m) <- modules gr, isModCnc m || isModRes m]
+ as1 <- return $ concatMap stripInfo $ concatMap (tree2list . js . snd) as0
+ cs1 <- return $ concatMap stripInfo $ concatMap (tree2list . js . snd) cs0
+ return $ unlines $ map prj $ srt as1 ++ srt cs1
+ where
+ js (ModMod m) = jments m
+ srt = sortBy (\ (i,_) (j,_) -> compare i j)
+ prj ii = P.printTree $ trAnyDef ii
+
+stripInfo :: (Ident,Info) -> [(Ident,Info)]
+stripInfo (c,i) = case i of
+ AbsCat (Yes co) (Yes fs) -> rc $ AbsCat (Yes (stripContext co)) nope
+ AbsFun (Yes ty) (Yes tr) -> rc $ AbsFun (Yes (stripTerm ty)) (Yes(stripTerm tr))
+ AbsFun (Yes ty) _ -> rc $ AbsFun (Yes (stripTerm ty)) nope
+ ResParam (Yes (ps,m)) -> rc $ ResParam (Yes ([(c,stripContext co) | (c,co)<- ps],Nothing))
+ CncCat (Yes ty) _ _ -> rc $
+ CncCat (Yes (stripTerm ty)) nope nope
+ CncFun _ (Yes tr) _ -> rc $ CncFun Nothing (Yes (stripTerm tr)) nope
+ _ -> []
+ where
+ rc j = [(c,j)]
+
+stripContext co = [(x, stripTerm t) | (x,t) <- co]
+
+stripTerm :: Term -> Term
+stripTerm t = case t of
+ Q _ c -> Vr c
+ QC _ c -> Vr c
+ T ti cs -> T ti' [(stripPattern p, stripTerm c) | (p,c) <- cs] where
+ ti' = case ti of
+ TTyped ty -> TTyped $ stripTerm ty
+ TComp ty -> TComp $ stripTerm ty
+ TWild ty -> TWild $ stripTerm ty
+ _ -> ti
+---- R [] -> EInt 8 --- GF 1.2 parser doesn't accept empty records
+---- RecType [] -> Cn (zIdent "Int") ---
+ _ -> composSafeOp stripTerm t
+
+stripPattern p = case p of
+ PC c [] -> PV c
+ PP _ c [] -> PV c
+ PC c ps -> PC c (map stripPattern ps)
+ PP _ c ps -> PC c (map stripPattern ps)
+ PR lps -> PR [(l, stripPattern p) | (l,p) <- lps]
+ PT t p -> PT (stripTerm t) (stripPattern p)
+ _ -> p
+
diff --git a/src-3.0/GF/Compile/Rebuild.hs b/src-3.0/GF/Compile/Rebuild.hs
new file mode 100644
index 000000000..152983b96
--- /dev/null
+++ b/src-3.0/GF/Compile/Rebuild.hs
@@ -0,0 +1,99 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Rebuild
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/30 21:08:14 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.14 $
+--
+-- Rebuild a source module from incomplete and its with-instance.
+-----------------------------------------------------------------------------
+
+module GF.Compile.Rebuild (rebuildModule) where
+
+import GF.Grammar.Grammar
+import GF.Compile.ModDeps
+import GF.Grammar.PrGrammar
+import GF.Grammar.Lookup
+import GF.Compile.Extend
+import GF.Grammar.Macros
+
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Data.Operations
+
+import Data.List (nub)
+
+-- | rebuilding instance + interface, and "with" modules, prior to renaming.
+-- AR 24/10/2003
+rebuildModule :: [SourceModule] -> SourceModule -> Err SourceModule
+rebuildModule ms mo@(i,mi) = do
+ let gr = MGrammar ms
+---- deps <- moduleDeps ms
+---- is <- openInterfaces deps i
+ let is = [] ---- the method above is buggy: try "i -src" for two grs. AR 8/3/2005
+ mi' <- case mi of
+
+ -- add the information given in interface into an instance module
+ ModMod m -> do
+ testErr (null is || mstatus m == MSIncomplete)
+ ("module" +++ prt i +++
+ "has open interfaces and must therefore be declared incomplete")
+ case mtype m of
+ MTInstance i0 -> do
+ m1 <- lookupModMod gr i0
+ testErr (isModRes m1) ("interface expected instead of" +++ prt i0)
+ m' <- do
+ js' <- extendMod False (i0,const True) i (jments m1) (jments m)
+ --- to avoid double inclusions, in instance I of I0 = J0 ** ...
+ case extends m of
+ [] -> return $ replaceJudgements m js'
+ j0s -> do
+ m0s <- mapM (lookupModMod gr) j0s
+ let notInM0 c _ = all (not . isInBinTree c . jments) m0s
+ let js2 = filterBinTree notInM0 js'
+ return $ replaceJudgements m js2
+ return $ ModMod m'
+ _ -> return mi
+
+ -- add the instance opens to an incomplete module "with" instances
+ -- ModWith mt stat ext me ops -> do
+ ModWith (Module mt stat fs_ me ops_ js_) (ext,incl) ops -> do
+ let insts = [(inf,inst) | OQualif _ inf inst <- ops]
+ let infs = map fst insts
+ let stat' = ifNull MSComplete (const MSIncomplete)
+ [i | i <- is, notElem i infs]
+ testErr (stat' == MSComplete || stat == MSIncomplete)
+ ("module" +++ prt i +++ "remains incomplete")
+ Module mt0 _ fs me' ops0 js <- lookupModMod gr ext
+ let ops1 = nub $
+ ops_ ++ -- N.B. js has been name-resolved already
+ ops ++ [o | o <- ops0, notElem (openedModule o) infs]
+ ++ [oQualif i i | i <- map snd insts] ----
+ ++ [oSimple i | i <- map snd insts] ----
+
+ --- check if me is incomplete
+ let fs1 = fs_ ++ fs -- new flags have priority
+ let js0 = [ci | ci@(c,_) <- tree2list js, isInherited incl c]
+ let js1 = buildTree (tree2list js_ ++ js0)
+ return $ ModMod $ Module mt0 stat' fs1 me ops1 js1
+ ---- (mapTree (qualifInstanceInfo insts) js) -- not needed
+
+ _ -> return mi
+ return (i,mi')
+
+checkCompleteInstance :: SourceRes -> SourceRes -> Err ()
+checkCompleteInstance abs cnc = ifNull (return ()) (Bad . unlines) $
+ checkComplete [f | (f, ResOper (Yes _) _) <- abs'] cnc'
+ where
+ abs' = tree2list $ jments abs
+ cnc' = jments cnc
+ checkComplete sought given = foldr ckOne [] sought
+ where
+ ckOne f = if isInBinTree f given
+ then id
+ else (("Error: no definition given to" +++ prt f):)
+
diff --git a/src-3.0/GF/Compile/RemoveLiT.hs b/src-3.0/GF/Compile/RemoveLiT.hs
new file mode 100644
index 000000000..28aae9b84
--- /dev/null
+++ b/src-3.0/GF/Compile/RemoveLiT.hs
@@ -0,0 +1,63 @@
+----------------------------------------------------------------------
+-- |
+-- Module : RemoveLiT
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:21:45 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.6 $
+--
+-- remove obsolete (Lin C) expressions before doing anything else. AR 21/6/2003
+--
+-- What the program does is replace the occurrences of Lin C with the actual
+-- definition T given in lincat C = T ; with {s : Str} if no lincat is found.
+-- The procedure is uncertain, if T contains another Lin.
+-----------------------------------------------------------------------------
+
+module GF.Compile.RemoveLiT (removeLiT) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Grammar.Macros
+import GF.Grammar.Lookup
+
+import GF.Data.Operations
+
+import Control.Monad
+
+removeLiT :: SourceGrammar -> Err SourceGrammar
+removeLiT gr = liftM MGrammar $ mapM (remlModule gr) (modules gr)
+
+remlModule :: SourceGrammar -> (Ident,SourceModInfo) -> Err (Ident,SourceModInfo)
+remlModule gr mi@(name,mod) = case mod of
+ ModMod (Module mt st fs me ops js) -> do
+ js1 <- mapMTree (remlResInfo gr) js
+ let mod2 = ModMod $ Module mt st fs me ops js1
+ return $ (name,mod2)
+ _ -> return mi
+
+remlResInfo :: SourceGrammar -> (Ident,Info) -> Err (Ident,Info)
+remlResInfo gr mi@(i,info) = case info of
+ ResOper pty ptr -> liftM ((,) i) $ liftM2 ResOper (ren pty) (ren ptr)
+ CncCat pty ptr ppr -> liftM ((,) i) $ liftM3 CncCat (ren pty) (ren ptr) (ren ppr)
+ CncFun mt ptr ppr -> liftM ((,) i) $ liftM2 (CncFun mt) (ren ptr) (ren ppr)
+ _ -> return mi
+ where
+ ren = remlPerh gr
+
+remlPerh gr pt = case pt of
+ Yes t -> liftM Yes $ remlTerm gr t
+ _ -> return pt
+
+remlTerm :: SourceGrammar -> Term -> Err Term
+remlTerm gr trm = case trm of
+ LiT c -> look c >>= remlTerm gr
+ _ -> composOp (remlTerm gr) trm
+ where
+ look c = err (const $ return defLinType) return $ lookupLincat gr m c
+ m = case [cnc | (cnc,ModMod m) <- modules gr, isModCnc m] of
+ cnc:_ -> cnc -- actually there is always exactly one
+ _ -> zIdent "CNC"
diff --git a/src-3.0/GF/Compile/Rename.hs b/src-3.0/GF/Compile/Rename.hs
new file mode 100644
index 000000000..c3fef557b
--- /dev/null
+++ b/src-3.0/GF/Compile/Rename.hs
@@ -0,0 +1,338 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Rename
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/30 18:39:44 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.19 $
+--
+-- AR 14\/5\/2003
+-- The top-level function 'renameGrammar' does several things:
+--
+-- - extends each module symbol table by indirections to extended module
+--
+-- - changes unqualified and as-qualified imports to absolutely qualified
+--
+-- - goes through the definitions and resolves names
+--
+-- Dependency analysis between modules has been performed before this pass.
+-- Hence we can proceed by @fold@ing "from left to right".
+-----------------------------------------------------------------------------
+
+module GF.Compile.Rename (renameGrammar,
+ renameSourceTerm,
+ renameModule
+ ) where
+
+import GF.Grammar.Grammar
+import GF.Grammar.Values
+import GF.Infra.Modules
+import GF.Infra.Ident
+import GF.Grammar.Macros
+import GF.Grammar.PrGrammar
+import GF.Grammar.AppPredefined
+import GF.Grammar.Lookup
+import GF.Compile.Extend
+import GF.Data.Operations
+
+import Control.Monad
+import Data.List (nub)
+import Debug.Trace (trace)
+
+renameGrammar :: SourceGrammar -> Err SourceGrammar
+renameGrammar g = liftM (MGrammar . reverse) $ foldM renameModule [] (modules g)
+
+-- | this gives top-level access to renaming term input in the cc command
+renameSourceTerm :: SourceGrammar -> Ident -> Term -> Err Term
+renameSourceTerm g m t = do
+ mo <- lookupErr m (modules g)
+ status <- buildStatus g m mo
+ renameTerm status [] t
+
+renameModule :: [SourceModule] -> SourceModule -> Err [SourceModule]
+renameModule ms (name,mod) = errIn ("renaming module" +++ prt name) $ case mod of
+ ModMod m@(Module mt st fs me ops js) -> do
+ let js1 = jments m
+ status <- buildStatus (MGrammar ms) name mod
+ js2 <- mapMTree (renameInfo status) js1
+ let mod2 = ModMod $ Module mt st fs me (map forceQualif ops) js2
+ return $ (name,mod2) : ms
+
+type Status = (StatusTree, [(OpenSpec Ident, StatusTree)])
+
+type StatusTree = BinTree Ident StatusInfo
+
+type StatusInfo = Ident -> Term
+
+renameIdentTerm :: Status -> Term -> Err Term
+renameIdentTerm env@(act,imps) t =
+ errIn ("atomic term" +++ prt t +++ "given" +++ unwords (map (prt . fst) qualifs)) $
+ case t of
+ Vr c -> ident predefAbs c
+ Cn c -> ident (\_ s -> Bad s) c
+ Q m' c | m' == cPredef {- && isInPredefined c -} -> return t
+ Q m' c -> do
+ m <- lookupErr m' qualifs
+ f <- lookupTree prt c m
+ return $ f c
+ QC m' c | m' == cPredef {- && isInPredefined c -} -> return t
+ QC m' c -> do
+ m <- lookupErr m' qualifs
+ f <- lookupTree prt c m
+ return $ f c
+ _ -> return t
+ where
+ opens = [st | (OSimple _ _,st) <- imps]
+ qualifs = [(m, st) | (OQualif _ m _, st) <- imps] ++
+ [(m, st) | (OSimple _ m, st) <- imps] -- qualif is always possible
+
+ -- this facility is mainly for BWC with GF1: you need not import PredefAbs
+ predefAbs c s = case c of
+ IC "Int" -> return $ Q cPredefAbs cInt
+ IC "Float" -> return $ Q cPredefAbs cFloat
+ IC "String" -> return $ Q cPredefAbs cString
+ _ -> Bad s
+
+ ident alt c = case lookupTree prt c act of
+ Ok f -> return $ f c
+ _ -> case lookupTreeManyAll prt opens c of
+ [f] -> return $ f c
+ [] -> alt c ("constant not found:" +++ prt c)
+ fs -> case nub [f c | f <- fs] of
+ [tr] -> return tr
+ ts@(t:_) -> trace ("WARNING: conflict" +++ unwords (map prt ts)) (return t)
+---- ts -> return $ Strs $ (cnIC "#conflict") : reverse ts
+ -- a warning will be generated in CheckGrammar, and the head returned
+ -- in next V:
+ -- Bad $ "conflicting imports:" +++ unwords (map prt ts)
+
+
+--- | would it make sense to optimize this by inlining?
+renameIdentPatt :: Status -> Patt -> Err Patt
+renameIdentPatt env p = do
+ let t = patt2term p
+ t' <- renameIdentTerm env t
+ term2patt t'
+
+info2status :: Maybe Ident -> (Ident,Info) -> (Ident,StatusInfo)
+info2status mq (c,i) = (c, case i of
+ AbsFun _ (Yes EData) -> maybe Con QC mq
+ ResValue _ -> maybe Con QC mq
+ ResParam _ -> maybe Con QC mq
+ AnyInd True m -> maybe Con (const (QC m)) mq
+ AnyInd False m -> maybe Cn (const (Q m)) mq
+ _ -> maybe Cn Q mq
+ )
+
+tree2status :: OpenSpec Ident -> BinTree Ident Info -> BinTree Ident StatusInfo
+tree2status o = case o of
+ OSimple _ i -> mapTree (info2status (Just i))
+ OQualif _ i j -> mapTree (info2status (Just j))
+
+buildStatus :: SourceGrammar -> Ident -> SourceModInfo -> Err Status
+buildStatus gr c mo = let mo' = self2status c mo in case mo of
+ ModMod m -> do
+ let gr1 = MGrammar $ (c,mo) : modules gr
+ ops = [OSimple OQNormal e | e <- allExtends gr1 c] ++ allOpens m
+ mods <- mapM (lookupModule gr1 . openedModule) ops
+ let sts = map modInfo2status $ zip ops mods
+ return $ if isModCnc m
+ then (emptyBinTree, reverse sts) -- the module itself does not define any names
+ else (mo',reverse sts) -- so the empty ident is not needed
+
+modInfo2status :: (OpenSpec Ident,SourceModInfo) -> (OpenSpec Ident, StatusTree)
+modInfo2status (o,i) = (o,case i of
+ ModMod m -> tree2status o (jments m)
+ )
+
+self2status :: Ident -> SourceModInfo -> StatusTree
+self2status c i = mapTree (info2status (Just c)) js where -- qualify internal
+ js = case i of
+ ModMod m
+ | isModTrans m -> sorted2tree $ filter noTrans $ tree2list $ jments m
+ | otherwise -> jments m
+ noTrans (_,d) = case d of -- to enable other than transfer js in transfer module
+ AbsTrans _ -> False
+ _ -> True
+
+forceQualif o = case o of
+ OSimple q i -> OQualif q i i
+ OQualif q _ i -> OQualif q i i
+
+renameInfo :: Status -> (Ident,Info) -> Err (Ident,Info)
+renameInfo status (i,info) = errIn ("renaming definition of" +++ prt i) $
+ liftM ((,) i) $ case info of
+ AbsCat pco pfs -> liftM2 AbsCat (renPerh (renameContext status) pco)
+ (renPerh (mapM rent) pfs)
+ AbsFun pty ptr -> liftM2 AbsFun (ren pty) (ren ptr)
+ AbsTrans f -> liftM AbsTrans (rent f)
+
+ ResOper pty ptr -> liftM2 ResOper (ren pty) (ren ptr)
+ ResOverload tysts -> liftM ResOverload $ mapM (pairM rent) tysts
+
+ ResParam (Yes (pp,m)) -> do
+ pp' <- mapM (renameParam status) pp
+ return $ ResParam $ Yes (pp',m)
+ ResValue (Yes (t,m)) -> do
+ t' <- rent t
+ return $ ResValue $ Yes (t',m)
+ CncCat pty ptr ppr -> liftM3 CncCat (ren pty) (ren ptr) (ren ppr)
+ CncFun mt ptr ppr -> liftM2 (CncFun mt) (ren ptr) (ren ppr)
+ _ -> return info
+ where
+ ren = renPerh rent
+ rent = renameTerm status []
+
+renPerh ren pt = case pt of
+ Yes t -> liftM Yes $ ren t
+ _ -> return pt
+
+renameTerm :: Status -> [Ident] -> Term -> Err Term
+renameTerm env vars = ren vars where
+ ren vs trm = case trm of
+ Abs x b -> liftM (Abs x) (ren (x:vs) b)
+ Prod x a b -> liftM2 (Prod x) (ren vs a) (ren (x:vs) b)
+ Typed a b -> liftM2 Typed (ren vs a) (ren vs b)
+ Vr x
+ | elem x vs -> return trm
+ | otherwise -> renid trm
+ Cn _ -> renid trm
+ Con _ -> renid trm
+ Q _ _ -> renid trm
+ QC _ _ -> renid trm
+ Eqs eqs -> liftM Eqs $ mapM (renameEquation env vars) eqs
+ T i cs -> do
+ i' <- case i of
+ TTyped ty -> liftM TTyped $ ren vs ty -- the only annotation in source
+ _ -> return i
+ liftM (T i') $ mapM (renCase vs) cs
+
+ Let (x,(m,a)) b -> do
+ m' <- case m of
+ Just ty -> liftM Just $ ren vs ty
+ _ -> return m
+ a' <- ren vs a
+ b' <- ren (x:vs) b
+ return $ Let (x,(m',a')) b'
+
+ P t@(Vr r) l -- for constant t we know it is projection
+ | elem r vs -> return trm -- var proj first
+ | otherwise -> case renid (Q r (label2ident l)) of -- qualif second
+ Ok t -> return t
+ _ -> case liftM (flip P l) $ renid t of
+ Ok t -> return t -- const proj last
+ _ -> prtBad "unknown qualified constant" trm
+
+ EPatt p -> do
+ (p',_) <- renpatt p
+ return $ EPatt p'
+
+ _ -> composOp (ren vs) trm
+
+ renid = renameIdentTerm env
+ renCase vs (p,t) = do
+ (p',vs') <- renpatt p
+ t' <- ren (vs' ++ vs) t
+ return (p',t')
+ renpatt = renamePattern env
+
+-- | vars not needed in env, since patterns always overshadow old vars
+renamePattern :: Status -> Patt -> Err (Patt,[Ident])
+renamePattern env patt = case patt of
+
+ PMacro c -> do
+ c' <- renid $ Vr c
+ case c' of
+ Q p d -> renp $ PM p d
+ _ -> prtBad "unresolved pattern" patt
+
+ PC c ps -> do
+ c' <- renameIdentTerm env $ Cn c
+ case c' of
+ QC p d -> renp $ PP p d ps
+-- Q p d -> renp $ PP p d ps --- why this? AR 15/3/2008
+ _ -> prtBad "unresolved pattern" c' ---- (PC c ps', concat vs)
+
+ PP p c ps -> do
+
+ (p', c') <- case renameIdentTerm env (QC p c) of
+ Ok (QC p' c') -> return (p',c')
+ _ -> return (p,c) --- temporarily, for bw compat
+ psvss <- mapM renp ps
+ let (ps',vs) = unzip psvss
+ return (PP p' c' ps', concat vs)
+
+ PM p c -> do
+ (p', c') <- case renameIdentTerm env (Q p c) of
+ Ok (Q p' c') -> return (p',c')
+ _ -> prtBad "not a pattern macro" patt
+ return (PM p' c', [])
+
+ PV x -> case renid (Vr x) of
+ Ok (QC m c) -> return (PP m c [],[])
+ _ -> return (patt, [x])
+
+ PR r -> do
+ let (ls,ps) = unzip r
+ psvss <- mapM renp ps
+ let (ps',vs') = unzip psvss
+ return (PR (zip ls ps'), concat vs')
+
+ PAlt p q -> do
+ (p',vs) <- renp p
+ (q',ws) <- renp q
+ return (PAlt p' q', vs ++ ws)
+
+ PSeq p q -> do
+ (p',vs) <- renp p
+ (q',ws) <- renp q
+ return (PSeq p' q', vs ++ ws)
+
+ PRep p -> do
+ (p',vs) <- renp p
+ return (PRep p', vs)
+
+ PNeg p -> do
+ (p',vs) <- renp p
+ return (PNeg p', vs)
+
+ PAs x p -> do
+ (p',vs) <- renp p
+ return (PAs x p', x:vs)
+
+ _ -> return (patt,[])
+
+ where
+ renp = renamePattern env
+ renid = renameIdentTerm env
+
+renameParam :: Status -> (Ident, Context) -> Err (Ident, Context)
+renameParam env (c,co) = do
+ co' <- renameContext env co
+ return (c,co')
+
+renameContext :: Status -> Context -> Err Context
+renameContext b = renc [] where
+ renc vs cont = case cont of
+ (x,t) : xts
+ | isWildIdent x -> do
+ t' <- ren vs t
+ xts' <- renc vs xts
+ return $ (x,t') : xts'
+ | otherwise -> do
+ t' <- ren vs t
+ let vs' = x:vs
+ xts' <- renc vs' xts
+ return $ (x,t') : xts'
+ _ -> return cont
+ ren = renameTerm b
+
+-- | vars not needed in env, since patterns always overshadow old vars
+renameEquation :: Status -> [Ident] -> Equation -> Err Equation
+renameEquation b vs (ps,t) = do
+ (ps',vs') <- liftM unzip $ mapM (renamePattern b) ps
+ t' <- renameTerm b (concat vs' ++ vs) t
+ return (ps',t')
diff --git a/src-3.0/GF/Compile/ShellState.hs b/src-3.0/GF/Compile/ShellState.hs
new file mode 100644
index 000000000..0e24da601
--- /dev/null
+++ b/src-3.0/GF/Compile/ShellState.hs
@@ -0,0 +1,568 @@
+----------------------------------------------------------------------
+-- |
+-- Module : ShellState
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/14 16:03:41 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.53 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Compile.ShellState where
+
+import GF.Data.Operations
+import GF.Canon.GFC
+import GF.Canon.AbsGFC
+import GF.GFCC.CId
+--import GF.GFCC.DataGFCC(mkGFCC)
+import GF.GFCC.Macros (lookFCFG)
+import GF.Canon.CanonToGFCC
+import GF.Grammar.Macros
+import GF.Grammar.MMacros
+
+import GF.Canon.Look
+import GF.Canon.Subexpressions
+import GF.Grammar.LookAbs
+import GF.Compile.ModDeps
+import GF.Compile.Evaluate
+import qualified GF.Infra.Modules as M
+import qualified GF.Grammar.Grammar as G
+import qualified GF.Grammar.PrGrammar as P
+import GF.CF.CF
+import GF.CF.CFIdent
+import GF.CF.CanonToCF
+import GF.UseGrammar.Morphology
+import GF.Probabilistic.Probabilistic
+import GF.Compile.NoParse
+import GF.Infra.Option
+import GF.Infra.Ident
+import GF.Infra.UseIO (justModuleName)
+import GF.System.Arch (ModTime)
+
+import qualified Transfer.InterpreterAPI as T
+
+import GF.Formalism.FCFG
+import qualified GF.OldParsing.ConvertGrammar as CnvOld -- OBSOLETE
+import qualified GF.Conversion.GFC as Cnv
+import qualified GF.Conversion.SimpleToFCFG as FCnv
+import qualified GF.Parsing.GFC as Prs
+
+import Control.Monad (mplus)
+import Data.List (nub,nubBy)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+
+
+-- AR 11/11/2001 -- 17/6/2003 (for modules) ---- unfinished
+
+-- | multilingual state with grammars and options
+data ShellState = ShSt {
+ abstract :: Maybe Ident , -- ^ pointer to actual abstract, if not empty st
+ concrete :: Maybe Ident , -- ^ pointer to primary concrete
+ concretes :: [((Ident,Ident),Bool)], -- ^ list of all concretes, and whether active
+ canModules :: CanonGrammar , -- ^ compiled abstracts and concretes
+ srcModules :: G.SourceGrammar , -- ^ saved resource modules
+ cfs :: [(Ident,CF)] , -- ^ context-free grammars (small, no parameters, very over-generating)
+ abstracts :: [(Ident,[Ident])], -- ^ abstracts and their associated concretes
+ mcfgs :: [(Ident, Cnv.MGrammar)], -- ^ MCFG, converted according to Ljunglöf (2004, ch 3)
+ fcfgs :: [(Ident, FGrammar)], -- ^ FCFG, optimized MCFG by Krasimir Angelov
+ cfgs :: [(Ident, Cnv.CGrammar)], -- ^ CFG, converted from mcfg
+ -- (large, with parameters, no-so overgenerating)
+ pInfos :: [(Ident, Prs.PInfo)], -- ^ parsing information (compiled mcfg&cfg grammars)
+ morphos :: [(Ident,Morpho)], -- ^ morphologies
+ treebanks :: [(Ident,Treebank)], -- ^ treebanks
+ probss :: [(Ident,Probs)], -- ^ probability distributions
+ gloptions :: Options, -- ^ global options
+ readFiles :: [(String,(FilePath,ModTime))],-- ^ files read
+ absCats :: [(G.Cat,(G.Context,
+ [(G.Fun,G.Type)],
+ [((G.Fun,Int),G.Type)]))], -- ^ cats, (their contexts,
+ -- functions to them,
+ -- functions on them)
+ statistics :: [Statistics], -- ^ statistics on grammars
+ transfers :: [(Ident,T.Env)], -- ^ transfer modules
+ evalEnv :: EEnv -- ^ evaluation environment
+ }
+
+type Treebank = Map.Map String [String] -- string, trees
+
+actualConcretes :: ShellState -> [((Ident,Ident),Bool)]
+actualConcretes sh = nub [((c,c),b) |
+ Just a <- [abstract sh],
+ ((c,_),_) <- concretes sh, ----concretesOfAbstract sh a,
+ let b = True -----
+ ]
+
+concretesOfAbstract :: ShellState -> Ident -> [Ident]
+concretesOfAbstract sh a = [c | (b,cs) <- abstracts sh, b == a, c <- cs]
+
+data Statistics =
+ StDepTypes Bool -- ^ whether there are dependent types
+ | StBoundVars [G.Cat] -- ^ which categories have bound variables
+ --- -- etc
+ deriving (Eq,Ord)
+
+emptyShellState :: ShellState
+emptyShellState = ShSt {
+ abstract = Nothing,
+ concrete = Nothing,
+ concretes = [],
+ canModules = M.emptyMGrammar,
+ srcModules = M.emptyMGrammar,
+ cfs = [],
+ abstracts = [],
+ mcfgs = [],
+ fcfgs = [],
+ cfgs = [],
+ pInfos = [],
+ morphos = [],
+ treebanks = [],
+ probss = [],
+ gloptions = noOptions,
+ readFiles = [],
+ absCats = [],
+ statistics = [],
+ transfers = [],
+ evalEnv = emptyEEnv
+ }
+
+optInitShellState :: Options -> ShellState
+optInitShellState os = addGlobalOptions os emptyShellState
+
+type Language = Ident
+
+language :: String -> Language
+language = identC
+
+prLanguage :: Language -> String
+prLanguage = prIdent
+
+-- | grammar for one language in a state, comprising its abs and cnc
+data StateGrammar = StGr {
+ absId :: Ident,
+ cncId :: Ident,
+ grammar :: CanonGrammar,
+ cf :: CF,
+ mcfg :: Cnv.MGrammar,
+ fcfg :: FGrammar,
+ cfg :: Cnv.CGrammar,
+ pInfo :: Prs.PInfo,
+ morpho :: Morpho,
+ probs :: Probs,
+ loptions :: Options
+ }
+
+emptyStateGrammar :: StateGrammar
+emptyStateGrammar = StGr {
+ absId = identC "#EMPTY", ---
+ cncId = identC "#EMPTY", ---
+ grammar = M.emptyMGrammar,
+ cf = emptyCF,
+ mcfg = [],
+ fcfg = ([], Map.empty),
+ cfg = [],
+ pInfo = Prs.buildPInfo [] ([], Map.empty) [],
+ morpho = emptyMorpho,
+ probs = emptyProbs,
+ loptions = noOptions
+ }
+
+-- analysing shell grammar into parts
+
+stateGrammarST :: StateGrammar -> CanonGrammar
+stateCF :: StateGrammar -> CF
+stateMCFG :: StateGrammar -> Cnv.MGrammar
+stateFCFG :: StateGrammar -> FGrammar
+stateCFG :: StateGrammar -> Cnv.CGrammar
+statePInfo :: StateGrammar -> Prs.PInfo
+stateMorpho :: StateGrammar -> Morpho
+stateProbs :: StateGrammar -> Probs
+stateOptions :: StateGrammar -> Options
+stateGrammarWords :: StateGrammar -> [String]
+stateGrammarLang :: StateGrammar -> (CanonGrammar, Ident)
+
+stateGrammarST = grammar
+stateCF = cf
+stateMCFG = mcfg
+stateFCFG = fcfg
+stateCFG = cfg
+statePInfo = pInfo
+stateMorpho = morpho
+stateProbs = probs
+stateOptions = loptions
+stateGrammarWords = allMorphoWords . stateMorpho
+stateGrammarLang st = (grammar st, cncId st)
+
+---- this should be computed at compile time and stored
+stateHasHOAS :: StateGrammar -> Bool
+stateHasHOAS = hasHOAS . stateGrammarST
+
+cncModuleIdST :: StateGrammar -> CanonGrammar
+cncModuleIdST = stateGrammarST
+
+-- | form a shell state from a canonical grammar
+grammar2shellState :: Options -> (CanonGrammar, G.SourceGrammar) -> Err ShellState
+grammar2shellState opts (gr,sgr) =
+ updateShellState opts doParseAll Nothing emptyShellState ((0,sgr,gr,emptyEEnv),[]) --- is 0 safe?
+
+-- | update a shell state from a canonical grammar
+updateShellState :: Options -> NoParse -> Maybe Ident -> ShellState ->
+ ((Int,G.SourceGrammar,CanonGrammar,EEnv),[(String,(FilePath,ModTime))]) ->
+ Err ShellState
+updateShellState opts ign mcnc sh ((_,sgr,gr,eenv),rts) = do
+ let cgr0 = M.updateMGrammar (canModules sh) gr
+
+ -- a0 = abstract of old state
+ -- a1 = abstract of compiled grammar
+
+ let a0 = abstract sh
+ a1 <- return $ case mcnc of
+ Just cnc -> err (const Nothing) Just $ M.abstractOfConcrete cgr0 cnc
+ _ -> M.greatestAbstract cgr0
+
+ -- abstr0 = a1 if it exists
+
+ let (abstr0,isNew) = case (a0,a1) of
+ (Just a, Just b) | a /= b -> (a1, True)
+ (Nothing, Just _) -> (a1, True)
+ _ -> (a0, False)
+
+ let concrs0 = maybe [] (M.allConcretes cgr0) abstr0
+
+ let abstrs = nubBy (\ (x,_) (y,_) -> x == y) $
+ maybe id (\a -> ((a,concrs0):)) abstr0 $ abstracts sh
+
+ let needed = nub $ concatMap (requiredCanModules (length abstrs == 1) cgr0) (maybe [] singleton abstr0 ++ concrs0)
+ purge = nubBy (\x y -> fst x == fst y) . filter (\(m,mo) -> elem m needed && not (isIncompleteCanon (m,mo)))
+
+ let cgr = M.MGrammar $ purge $ M.modules cgr0
+
+ let oldConcrs = map (snd . fst) (concretes sh)
+ newConcrs = maybe [] (M.allConcretes gr) abstr0
+ toRetain (c,v) = notElem c newConcrs
+ let complete m = case M.lookupModule gr m of
+ Ok mo -> not $ isIncompleteCanon (m,mo)
+ _ -> False
+
+ let concrs = filter (\i -> complete i && elem i needed) $ nub $ newConcrs ++ oldConcrs
+ concr0 = ifNull Nothing (return . head) concrs
+ notInrts f = notElem f $ map fst rts
+ subcgr = unSubelimCanon cgr
+ cf's0 <- if (not (oElem (iOpt "docf") opts) && -- cf only built with -docf
+ (oElem noCF opts || not (hasHOAS cgr))) -- or HOAS, if not -nocf
+ then return $ map snd $ cfs sh
+ else mapM (canon2cf opts ign subcgr) newConcrs
+ let cf's = zip newConcrs cf's0 ++ filter toRetain (cfs sh)
+
+ let morphs = [(c,mkMorpho subcgr c) | c <- newConcrs] ++ filter toRetain (morphos sh)
+ let probss = [] -----
+
+
+ let fromGFC = snd . snd . Cnv.convertGFC opts
+ (mcfgs, cfgs) = unzip $ map (curry fromGFC cgr) concrs
+ gfcc = canon2gfcc opts cgr ---- UTF8
+ fcfgs = [(c,g) | c@(IC cn) <- concrs, Just g <- [lookFCFG gfcc (CId cn)]]
+ pInfos = zipWith3 Prs.buildPInfo mcfgs (map snd fcfgs) cfgs
+
+ let funs = funRulesOf cgr
+ let cats = allCatsOf cgr
+ let csi = [(c,(co,
+ [(fun,typ) | (fun,typ) <- funs, compatType tc typ],
+ funsOnTypeFs compatType funs tc))
+ | (c,co) <- cats, let tc = cat2val co c]
+ let deps = True ---- not $ null $ allDepCats cgr
+ let binds = [] ---- allCatsWithBind cgr
+ let src = M.updateMGrammar (srcModules sh) sgr
+
+ return $ ShSt {
+ abstract = abstr0,
+ concrete = concr0,
+ concretes = zip (zip concrs concrs) (repeat True),
+ canModules = cgr,
+ srcModules = src,
+ cfs = cf's,
+ abstracts = maybe [] (\a -> [(a,concrs)]) abstr0,
+ mcfgs = zip concrs mcfgs,
+ fcfgs = fcfgs,
+ cfgs = zip concrs cfgs,
+ pInfos = zip concrs pInfos,
+ morphos = morphs,
+ treebanks = treebanks sh,
+ probss = zip concrs probss,
+ gloptions = gloptions sh, --- opts, -- this would be command-line options
+ readFiles = [ft | ft@(f,(_,_)) <- readFiles sh, notInrts f] ++ rts,
+ absCats = csi,
+ statistics = [StDepTypes deps,StBoundVars binds],
+ transfers = transfers sh,
+ evalEnv = eenv
+ }
+
+prShellStateInfo :: ShellState -> String
+prShellStateInfo sh = unlines [
+ "main abstract : " +++ abstractName sh,
+ "main concrete : " +++ maybe "(none)" P.prt (concrete sh),
+ "actual concretes : " +++ unwords (map (P.prt . fst . fst) (actualConcretes sh)),
+ "all abstracts : " +++ unwords (map (P.prt . fst) (abstracts sh)),
+ "all concretes : " +++ unwords (map (P.prt . fst . fst) (concretes sh)),
+ "canonical modules :" +++ unwords (map (P.prt .fst) (M.modules (canModules sh))),
+ "source modules : " +++ unwords (map (P.prt .fst) (M.modules (srcModules sh))),
+ "global options : " +++ prOpts (gloptions sh),
+ "transfer modules : " +++ unwords (map (P.prt . fst) (transfers sh)),
+ "treebanks : " +++ unwords (map (P.prt . fst) (treebanks sh))
+ ]
+
+abstractName :: ShellState -> String
+abstractName sh = maybe "(none)" P.prt (abstract sh)
+
+-- | throw away those abstracts that are not needed --- could be more aggressive
+filterAbstracts :: [Ident] -> CanonGrammar -> CanonGrammar
+filterAbstracts absts cgr = M.MGrammar (nubBy (\x y -> fst x == fst y) [m | m <- ms, needed m]) where
+ ms = M.modules cgr
+ needed (i,_) = elem i needs
+ needs = [i | (i,M.ModMod m) <- ms, not (M.isModAbs m) || any (dep i) absts]
+ dep i a = elem i (ext mse a)
+ mse = [(i,me) | (i,M.ModMod m) <- ms, M.isModAbs m, me <- [M.extends m]]
+ ext es a = case lookup a es of
+ Just e -> a : concatMap (ext es) e ---- FIX multiple exts
+ _ -> []
+
+purgeShellState :: ShellState -> ShellState
+purgeShellState sh = ShSt {
+ abstract = abstr,
+ concrete = concrete sh,
+ concretes = concrs,
+ canModules = M.MGrammar $ filter complete $ purge $ M.modules $ canModules sh,
+ srcModules = M.emptyMGrammar,
+ cfs = cfs sh,
+ abstracts = maybe [] (\a -> [(a,map (snd . fst) concrs)]) abstr,
+ mcfgs = mcfgs sh,
+ fcfgs = fcfgs sh,
+ cfgs = cfgs sh,
+ pInfos = pInfos sh,
+ morphos = morphos sh,
+ treebanks = treebanks sh,
+ probss = probss sh,
+ gloptions = gloptions sh,
+ readFiles = [],
+ absCats = absCats sh,
+ statistics = statistics sh,
+ transfers = transfers sh,
+ evalEnv = emptyEEnv
+ }
+ where
+ abstr = abstract sh
+ concrs = [((a,i),b) | ((a,i),b) <- concretes sh, elem i needed]
+ isSingle = length (abstracts sh) == 1
+ needed = nub $ concatMap (requiredCanModules isSingle (canModules sh)) acncs
+ purge = nubBy (\x y -> fst x == fst y) . filter (flip elem needed . fst)
+ acncs = maybe [] singleton abstr ++ map (snd . fst) (actualConcretes sh)
+ complete = not . isIncompleteCanon
+
+changeMain :: Maybe Ident -> ShellState -> Err ShellState
+changeMain Nothing (ShSt _ _ cs ms ss cfs old_pis mcfgs fcfgs cfgs pinfos mos tbs pbs os rs acs s trs ee) =
+ return (ShSt Nothing Nothing [] ms ss cfs old_pis mcfgs fcfgs cfgs pinfos mos tbs pbs os rs acs s trs ee)
+changeMain
+ (Just c) st@(ShSt _ _ cs ms ss cfs old_pis mcfgs fcfgs cfgs pinfos mos tbs pbs os rs acs s trs ee) =
+ case lookup c (M.modules ms) of
+ Just _ -> do
+ a <- M.abstractOfConcrete ms c
+ let cas = M.allConcretes ms a
+ let cs' = [((c,c),True) | c <- cas]
+ return (ShSt (Just a) (Just c) cs' ms ss cfs old_pis mcfgs fcfgs cfgs
+ pinfos mos tbs pbs os rs acs s trs ee)
+ _ -> P.prtBad "The state has no concrete syntax named" c
+
+-- | form just one state grammar, if unique, from a canonical grammar
+grammar2stateGrammar :: Options -> CanonGrammar -> Err StateGrammar
+grammar2stateGrammar opts gr = do
+ st <- grammar2shellState opts (gr,M.emptyMGrammar)
+ concr <- maybeErr "no concrete syntax" $ concrete st
+ return $ stateGrammarOfLang st concr
+
+resourceOfShellState :: ShellState -> Maybe Ident
+resourceOfShellState = M.greatestResource . srcModules
+
+qualifTop :: StateGrammar -> G.QIdent -> G.QIdent
+qualifTop gr (_,c) = (absId gr,c)
+
+stateGrammarOfLang :: ShellState -> Language -> StateGrammar
+stateGrammarOfLang = stateGrammarOfLangOpt True
+
+stateGrammarOfLangOpt :: Bool -> ShellState -> Language -> StateGrammar
+stateGrammarOfLangOpt purg st0 l = StGr {
+ absId = err (const (identC "Abs")) id $ M.abstractOfConcrete allCan l, ---
+ cncId = l,
+ grammar = allCan,
+ cf = maybe emptyCF id (lookup l (cfs st)),
+ mcfg = maybe [] id $ lookup l $ mcfgs st,
+ fcfg = maybe ([],Map.empty) id $ lookup l $ fcfgs st,
+ cfg = maybe [] id $ lookup l $ cfgs st,
+ pInfo = maybe (Prs.buildPInfo [] ([],Map.empty) []) id $ lookup l $ pInfos st,
+ morpho = maybe emptyMorpho id (lookup l (morphos st)),
+ probs = maybe emptyProbs id (lookup l (probss st)),
+ loptions = errVal noOptions $ lookupOptionsCan allCan
+ }
+ where
+ st = (if purg then purgeShellState else id) $ errVal st0 $ changeMain (Just l) st0
+ allCan = canModules st
+
+grammarOfLang :: ShellState -> Language -> CanonGrammar
+cfOfLang :: ShellState -> Language -> CF
+morphoOfLang :: ShellState -> Language -> Morpho
+probsOfLang :: ShellState -> Language -> Probs
+optionsOfLang :: ShellState -> Language -> Options
+
+grammarOfLang st = stateGrammarST . stateGrammarOfLang st
+cfOfLang st = stateCF . stateGrammarOfLang st
+morphoOfLang st = stateMorpho . stateGrammarOfLang st
+probsOfLang st = stateProbs . stateGrammarOfLang st
+optionsOfLang st = stateOptions . stateGrammarOfLang st
+
+removeLang :: Language -> ShellState -> ShellState
+removeLang lang st = purgeShellState $ st{concretes = concs1} where
+ concs1 = filter ((/=lang) . snd . fst) $ concretes st
+
+-- | the last introduced grammar, stored in options, is the default for operations
+firstStateGrammar :: ShellState -> StateGrammar
+firstStateGrammar st = errVal (stateAbstractGrammar st) $ do
+ concr <- maybeErr "no concrete syntax" $ concrete st
+ return $ stateGrammarOfLang st concr
+
+mkStateGrammar :: ShellState -> Language -> StateGrammar
+mkStateGrammar = stateGrammarOfLang
+
+stateAbstractGrammar :: ShellState -> StateGrammar
+stateAbstractGrammar st = StGr {
+ absId = maybe (identC "Abs") id (abstract st), ---
+ cncId = identC "#Cnc", ---
+ grammar = canModules st, ---- only abstarct ones
+ cf = emptyCF,
+ mcfg = [],
+ fcfg = ([],Map.empty),
+ cfg = [],
+ pInfo = Prs.buildPInfo [] ([],Map.empty) [],
+ morpho = emptyMorpho,
+ probs = emptyProbs,
+ loptions = gloptions st ----
+ }
+
+
+-- analysing shell state into parts
+
+globalOptions :: ShellState -> Options
+allLanguages :: ShellState -> [Language]
+allTransfers :: ShellState -> [Ident]
+allCategories :: ShellState -> [G.Cat]
+allStateGrammars :: ShellState -> [StateGrammar]
+allStateGrammarsWithNames :: ShellState -> [(Language, StateGrammar)]
+allGrammarFileNames :: ShellState -> [String]
+allActiveStateGrammarsWithNames :: ShellState -> [(Language, StateGrammar)]
+allActiveGrammars :: ShellState -> [StateGrammar]
+
+globalOptions = gloptions
+--allLanguages = map (fst . fst) . concretes
+allLanguages = map (snd . fst) . actualConcretes
+allTransfers = map fst . transfers
+allCategories = map fst . allCatsOf . canModules
+
+allStateGrammars = map snd . allStateGrammarsWithNames
+
+allStateGrammarsWithNames st =
+ [(c, mkStateGrammar st c) | ((c,_),_) <- actualConcretes st]
+
+allGrammarFileNames st = [prLanguage c ++ ".gf" | ((c,_),_) <- actualConcretes st]
+
+allActiveStateGrammarsWithNames st =
+ [(c, mkStateGrammar st c) | ((c,_),True) <- concretes st] --- actual
+
+allActiveGrammars = map snd . allActiveStateGrammarsWithNames
+
+pathOfModule :: ShellState -> Ident -> FilePath
+pathOfModule sh m = maybe "module not found" fst $ lookup (P.prt m) $ readFiles sh
+
+-- command-line option -lang=foo overrides the actual grammar in state
+grammarOfOptState :: Options -> ShellState -> StateGrammar
+grammarOfOptState opts st =
+ maybe (firstStateGrammar st) (stateGrammarOfLang st . language) $
+ getOptVal opts useLanguage
+
+languageOfOptState :: Options -> ShellState -> Maybe Language
+languageOfOptState opts st =
+ maybe (concrete st) (return . language) $ getOptVal opts useLanguage
+
+-- | command-line option -cat=foo overrides the possible start cat of a grammar
+firstCatOpts :: Options -> StateGrammar -> CFCat
+firstCatOpts opts sgr =
+ maybe (stateFirstCat sgr) (string2CFCat (P.prt (absId sgr))) $
+ getOptVal opts firstCat
+
+-- | the first cat for random generation
+firstAbsCat :: Options -> StateGrammar -> G.QIdent
+firstAbsCat opts = cfCat2Cat . firstCatOpts opts
+
+-- | Gets the start category for the grammar from the options.
+-- If the startcat is not set in the options, we look
+-- for a flag in the grammar. If there is no flag in the
+-- grammar, S is returned.
+startCatStateOpts :: Options -> StateGrammar -> CFCat
+startCatStateOpts opts sgr =
+ string2CFCat a (fromMaybe "S" (optsStartCat `mplus` grStartCat))
+ where optsStartCat = getOptVal opts gStartCat
+ grStartCat = getOptVal (stateOptions sgr) gStartCat
+ a = P.prt (absId sgr)
+
+-- | a grammar can have start category as option startcat=foo ; default is S
+stateFirstCat :: StateGrammar -> CFCat
+stateFirstCat = startCatStateOpts noOptions
+
+stateIsWord :: StateGrammar -> String -> Bool
+stateIsWord sg = isKnownWord (stateMorpho sg)
+
+addProbs :: (Ident,Probs) -> ShellState -> Err ShellState
+addProbs ip@(lang,probs) sh = do
+ let gr = grammarOfLang sh lang
+ probs' <- checkGrammarProbs gr probs
+ let pbs' = (lang,probs') : filter ((/= lang) . fst) (probss sh)
+ return $ sh{probss = pbs'}
+
+addTransfer :: (Ident,T.Env) -> ShellState -> ShellState
+addTransfer it@(i,_) sh =
+ sh {transfers = it : filter ((/= i) . fst) (transfers sh)}
+
+addTreebanks :: [(Ident,Treebank)] -> ShellState -> ShellState
+addTreebanks its sh = sh {treebanks = its ++ treebanks sh}
+
+findTreebank :: ShellState -> Ident -> Err Treebank
+findTreebank sh i = maybeErr "no treebank found" $ lookup i $ treebanks sh
+
+-- modify state
+
+type ShellStateOper = ShellState -> ShellState
+type ShellStateOperErr = ShellState -> Err ShellState
+
+reinitShellState :: ShellStateOper
+reinitShellState = const emptyShellState
+
+languageOn, languageOff :: Language -> ShellStateOper
+languageOn = languageOnOff True
+languageOff = languageOnOff False
+
+languageOnOff :: Bool -> Language -> ShellStateOper
+--- __________ this is OBSOLETE
+languageOnOff b lang sh = sh {concretes = cs'} where
+ cs' = [if lang==l then (lc,b) else i | i@(lc@(l,c),_) <- concretes sh]
+
+changeOptions :: (Options -> Options) -> ShellStateOper
+--- __________ this is OBSOLETE
+changeOptions f sh = sh {gloptions = f (gloptions sh)}
+
+addGlobalOptions :: Options -> ShellStateOper
+addGlobalOptions = changeOptions . addOptions
+
+removeGlobalOptions :: Options -> ShellStateOper
+removeGlobalOptions = changeOptions . removeOptions
+
diff --git a/src-3.0/GF/Compile/Update.hs b/src-3.0/GF/Compile/Update.hs
new file mode 100644
index 000000000..82d7a609e
--- /dev/null
+++ b/src-3.0/GF/Compile/Update.hs
@@ -0,0 +1,135 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Update
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/30 18:39:44 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.8 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Compile.Update (updateRes, buildAnyTree, combineAnyInfos, unifyAnyInfo,
+ -- * these auxiliaries should be somewhere else
+ -- since they don't use the info types
+ groupInfos, sortInfos, combineInfos, unifyInfos,
+ tryInsert, unifAbsDefs, unifConstrs
+ ) where
+
+import GF.Infra.Ident
+import GF.Grammar.Grammar
+import GF.Grammar.PrGrammar
+import GF.Infra.Modules
+
+import GF.Data.Operations
+
+import Data.List
+import Control.Monad
+
+-- | update a resource module by adding a new or changing an old definition
+updateRes :: SourceGrammar -> Ident -> Ident -> Info -> SourceGrammar
+updateRes gr@(MGrammar ms) m i info = MGrammar $ map upd ms where
+ upd (n,mod)
+ | n /= m = (n,mod)
+ | n == m = case mod of
+ ModMod r -> (m,ModMod $ updateModule r i info)
+ _ -> (n,mod) --- no error msg
+
+-- | combine a list of definitions into a balanced binary search tree
+buildAnyTree :: [(Ident,Info)] -> Err (BinTree Ident Info)
+buildAnyTree ias = do
+ ias' <- combineAnyInfos ias
+ return $ buildTree ias'
+
+
+-- | unifying information for abstract, resource, and concrete
+combineAnyInfos :: [(Ident,Info)] -> Err [(Ident,Info)]
+combineAnyInfos = combineInfos unifyAnyInfo
+
+unifyAnyInfo :: Ident -> Info -> Info -> Err Info
+unifyAnyInfo c i j = errIn ("combining information for" +++ prt c) $ case (i,j) of
+ (AbsCat mc1 mf1, AbsCat mc2 mf2) ->
+ liftM2 AbsCat (unifPerhaps mc1 mc2) (unifConstrs mf1 mf2) -- adding constrs
+ (AbsFun mt1 md1, AbsFun mt2 md2) ->
+ liftM2 AbsFun (unifPerhaps mt1 mt2) (unifAbsDefs md1 md2) -- adding defs
+
+ (ResParam mt1, ResParam mt2) -> liftM ResParam $ unifPerhaps mt1 mt2
+ (ResOper mt1 m1, ResOper mt2 m2) ->
+ liftM2 ResOper (unifPerhaps mt1 mt2) (unifPerhaps m1 m2)
+
+ (CncCat mc1 mf1 mp1, CncCat mc2 mf2 mp2) ->
+ liftM3 CncCat (unifPerhaps mc1 mc2) (unifPerhaps mf1 mf2) (unifPerhaps mp1 mp2)
+ (CncFun m mt1 md1, CncFun _ mt2 md2) ->
+ liftM2 (CncFun m) (unifPerhaps mt1 mt2) (unifPerhaps md1 md2) ---- adding defs
+-- for bw compatibility with unspecified printnames in old GF
+ (CncFun Nothing Nope (Yes pr),_) ->
+ unifyAnyInfo c (CncCat Nope Nope (Yes pr)) j
+ (_,CncFun Nothing Nope (Yes pr)) ->
+ unifyAnyInfo c i (CncCat Nope Nope (Yes pr))
+
+ _ -> Bad $ "cannot unify informations in" ++++ show i ++++ "and" ++++ show j
+
+--- these auxiliaries should be somewhere else since they don't use the info types
+
+groupInfos :: Eq a => [(a,b)] -> [[(a,b)]]
+groupInfos = groupBy (\i j -> fst i == fst j)
+
+sortInfos :: Ord a => [(a,b)] -> [(a,b)]
+sortInfos = sortBy (\i j -> compare (fst i) (fst j))
+
+combineInfos :: Ord a => (a -> b -> b -> Err b) -> [(a,b)] -> Err [(a,b)]
+combineInfos f ris = do
+ let riss = groupInfos $ sortInfos ris
+ mapM (unifyInfos f) riss
+
+unifyInfos :: (a -> b -> b -> Err b) -> [(a,b)] -> Err (a,b)
+unifyInfos _ [] = Bad "empty info list"
+unifyInfos unif ris = do
+ let c = fst $ head ris
+ let infos = map snd ris
+ let ([i],is) = splitAt 1 infos
+ info <- foldM (unif c) i is
+ return (c,info)
+
+
+tryInsert :: Ord a => (b -> b -> Err b) -> (b -> b) ->
+ BinTree a b -> (a,b) -> Err (BinTree a b)
+tryInsert unif indir tree z@(x, info) = case justLookupTree x tree of
+ Ok info0 -> do
+ info1 <- unif info info0
+ return $ updateTree (x,info1) tree
+ _ -> return $ updateTree (x,indir info) tree
+
+{- ----
+case tree of
+ NT -> return $ BT (x, indir info) NT NT
+ BT c@(a,info0) left right
+ | x < a -> do
+ left' <- tryInsert unif indir left z
+ return $ BT c left' right
+ | x > a -> do
+ right' <- tryInsert unif indir right z
+ return $ BT c left right'
+ | x == a -> do
+ info' <- unif info info0
+ return $ BT (x,info') left right
+-}
+
+--- addToMaybeList m c = maybe (return c) (\old -> return (c ++ old)) m
+
+unifAbsDefs :: Perh Term -> Perh Term -> Err (Perh Term)
+unifAbsDefs p1 p2 = case (p1,p2) of
+ (Nope, _) -> return p2
+ (_, Nope) -> return p1
+ (Yes (Eqs bs), Yes (Eqs ds)) -> return $ yes $ Eqs $ bs ++ ds --- order!
+ _ -> Bad "update conflict for definitions"
+
+unifConstrs :: Perh [Term] -> Perh [Term] -> Err (Perh [Term])
+unifConstrs p1 p2 = case (p1,p2) of
+ (Nope, _) -> return p2
+ (_, Nope) -> return p1
+ (Yes bs, Yes ds) -> return $ yes $ bs ++ ds
+ _ -> Bad "update conflict for constructors"
diff --git a/src-3.0/GF/Compile/Wordlist.hs b/src-3.0/GF/Compile/Wordlist.hs
new file mode 100644
index 000000000..3fbc066bd
--- /dev/null
+++ b/src-3.0/GF/Compile/Wordlist.hs
@@ -0,0 +1,108 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Wordlist
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date:
+-- > CVS $Author:
+-- > CVS $Revision:
+--
+-- Compile a gfwl file (multilingual word list) to an abstract + concretes
+-----------------------------------------------------------------------------
+
+module GF.Compile.Wordlist (mkWordlist) where
+
+import GF.Data.Operations
+import GF.Infra.UseIO
+import Data.List
+import Data.Char
+import System.FilePath
+
+-- read File.gfwl, write File.gf (abstract) and a set of concretes
+-- return the names of the concretes
+
+mkWordlist :: FilePath -> IO [FilePath]
+mkWordlist file = do
+ s <- readFileIf file
+ let abs = dropExtension file
+ let (cnchs,wlist) = pWordlist abs $ filter notComment $ lines s
+ let (gr,grs) = mkGrammars abs cnchs wlist
+ let cncfs = [cnc ++ ".gf" | (cnc,_) <- cnchs]
+ mapM_ (uncurry writeFile) $ (abs ++ ".gf",gr) : zip cncfs grs
+ putStrLn $ "wrote " ++ unwords ((abs ++ ".gf") : cncfs)
+ return cncfs
+
+{-
+-- syntax of files, e.g.
+
+ # Svenska - Franska - Finska -- names of concretes
+
+ berg - montagne - vuori -- word entry
+
+-- this creates:
+
+ cat S ;
+ fun berg_S : S ;
+ lin berg_S = {s = ["berg"]} ;
+ lin berg_S = {s = ["montagne"]} ;
+ lin berg_S = {s = ["vuori"]} ;
+
+-- support for different categories to be elaborated. The syntax it
+
+ Verb . klättra - grimper / escalader - kiivetä / kiipeillä
+
+-- notice that a word can have several alternative (separator /)
+-- and that an alternative can consist of several words
+-}
+
+type CncHeader = (String,String) -- module name, module header
+
+type Wordlist = [(String, [[String]])] -- cat, variants for each cnc
+
+
+pWordlist :: String -> [String] -> ([CncHeader],Wordlist)
+pWordlist abs ls = (headers,rules) where
+ (hs,rs) = span ((=="#") . take 1) ls
+ headers = map mkHeader $ chunks "-" $ filter (/="#") $ words $ concat hs
+ rules = map (mkRule . words) rs
+
+ mkHeader ws = case ws of
+ w:ws2 -> (w, unwords ("concrete":w:"of":abs:"=":ws2))
+ mkRule ws = case ws of
+ cat:".":vs -> (cat, mkWords vs)
+ _ -> ("S", mkWords ws)
+ mkWords = map (map unwords . chunks "/") . chunks "-"
+
+
+mkGrammars :: String -> [CncHeader] -> Wordlist -> (String,[String])
+mkGrammars ab hs wl = (abs,cncs) where
+ abs = unlines $ map unwords $
+ ["abstract",ab,"=","{"]:
+ cats ++
+ funs ++
+ [["}"]]
+
+ cncs = [unlines $ (h ++ " {") : map lin rs ++ ["}"] | ((_,h),rs) <- zip hs rss]
+
+ cats = [["cat",c,";"] | c <- nub $ map fst wl]
+ funs = [["fun", f , ":", c,";"] | (f,c,_) <- wlf]
+
+ wlf = [(ident f c, c, ws) | (c,ws@(f:_)) <- wl]
+
+ rss = [[(f, wss !! i) | (f,_,wss) <- wlf] | i <- [0..length hs - 1]]
+
+ lin (f,ss) = unwords ["lin", f, "=", "{s", "=", val ss, "}", ";"]
+
+ val ss = case ss of
+ [w] -> quote w
+ _ -> "variants {" ++ unwords (intersperse ";" (map quote ss)) ++ "}"
+
+ quote w = "[" ++ prQuotedString w ++ "]"
+
+ ident f c = concat $ intersperse "_" $ words (head f) ++ [c]
+
+
+notComment s = not (all isSpace s) && take 2 s /= "--"
+