summaryrefslogtreecommitdiff
path: root/src-3.0/GF/Grammar
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/Grammar
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/Grammar')
-rw-r--r--src-3.0/GF/Grammar/AbsCompute.hs145
-rw-r--r--src-3.0/GF/Grammar/Abstract.hs38
-rw-r--r--src-3.0/GF/Grammar/AppPredefined.hs159
-rw-r--r--src-3.0/GF/Grammar/Compute.hs426
-rw-r--r--src-3.0/GF/Grammar/Grammar.hs244
-rw-r--r--src-3.0/GF/Grammar/Lockfield.hs46
-rw-r--r--src-3.0/GF/Grammar/LookAbs.hs196
-rw-r--r--src-3.0/GF/Grammar/Lookup.hs275
-rw-r--r--src-3.0/GF/Grammar/MMacros.hs341
-rw-r--r--src-3.0/GF/Grammar/Macros.hs814
-rw-r--r--src-3.0/GF/Grammar/PatternMatch.hs155
-rw-r--r--src-3.0/GF/Grammar/PrGrammar.hs286
-rw-r--r--src-3.0/GF/Grammar/Refresh.hs133
-rw-r--r--src-3.0/GF/Grammar/ReservedWords.hs44
-rw-r--r--src-3.0/GF/Grammar/SGrammar.hs169
-rw-r--r--src-3.0/GF/Grammar/TC.hs299
-rw-r--r--src-3.0/GF/Grammar/TypeCheck.hs311
-rw-r--r--src-3.0/GF/Grammar/Unify.hs96
-rw-r--r--src-3.0/GF/Grammar/Values.hs109
19 files changed, 4286 insertions, 0 deletions
diff --git a/src-3.0/GF/Grammar/AbsCompute.hs b/src-3.0/GF/Grammar/AbsCompute.hs
new file mode 100644
index 000000000..57e21f1dd
--- /dev/null
+++ b/src-3.0/GF/Grammar/AbsCompute.hs
@@ -0,0 +1,145 @@
+----------------------------------------------------------------------
+-- |
+-- Module : AbsCompute
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/10/02 20:50:19 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.8 $
+--
+-- computation in abstract syntax w.r.t. explicit definitions.
+--
+-- old GF computation; to be updated
+-----------------------------------------------------------------------------
+
+module GF.Grammar.AbsCompute (LookDef,
+ compute,
+ computeAbsTerm,
+ computeAbsTermIn,
+ beta
+ ) where
+
+import GF.Data.Operations
+
+import GF.Grammar.Abstract
+import GF.Grammar.PrGrammar
+import GF.Grammar.LookAbs
+import GF.Grammar.Compute
+
+import Debug.Trace
+import Data.List(intersperse)
+import Control.Monad (liftM, liftM2)
+
+-- for debugging
+tracd m t = t
+-- tracd = trace
+
+compute :: GFCGrammar -> Exp -> Err Exp
+compute = computeAbsTerm
+
+computeAbsTerm :: GFCGrammar -> Exp -> Err Exp
+computeAbsTerm gr = computeAbsTermIn (lookupAbsDef gr) []
+
+-- | a hack to make compute work on source grammar as well
+type LookDef = Ident -> Ident -> Err (Maybe Term)
+
+computeAbsTermIn :: LookDef -> [Ident] -> Exp -> Err Exp
+computeAbsTermIn lookd xs e = errIn ("computing" +++ prt e) $ compt xs e where
+ compt vv t = case t of
+-- Prod x a b -> liftM2 (Prod x) (compt vv a) (compt (x:vv) b)
+-- Abs x b -> liftM (Abs x) (compt (x:vv) b)
+ _ -> do
+ let t' = beta vv t
+ (yy,f,aa) <- termForm t'
+ let vv' = yy ++ vv
+ aa' <- mapM (compt vv') aa
+ case look f of
+ Just (Eqs eqs) -> tracd ("\nmatching" +++ prt f) $
+ case findMatch eqs aa' of
+ Ok (d,g) -> do
+ --- let (xs,ts) = unzip g
+ --- ts' <- alphaFreshAll vv' ts
+ let g' = g --- zip xs ts'
+ d' <- compt vv' $ substTerm vv' g' d
+ tracd ("by Egs:" +++ prt d') $ return $ mkAbs yy $ d'
+ _ -> tracd ("no match" +++ prt t') $
+ do
+ let v = mkApp f aa'
+ return $ mkAbs yy $ v
+ Just d -> tracd ("define" +++ prt t') $ do
+ da <- compt vv' $ mkApp d aa'
+ return $ mkAbs yy $ da
+ _ -> do
+ let t2 = mkAbs yy $ mkApp f aa'
+ tracd ("not defined" +++ prt_ t2) $ return t2
+
+ look t = case t of
+ (Q m f) -> case lookd m f of
+ Ok (Just EData) -> Nothing -- canonical --- should always be QC
+ Ok md -> md
+ _ -> Nothing
+ Eqs _ -> return t ---- for nested fn
+ _ -> Nothing
+
+beta :: [Ident] -> Exp -> Exp
+beta vv c = case c of
+ Let (x,(_,a)) b -> beta vv $ substTerm vv [(x,beta vv a)] (beta (x:vv) b)
+ App f a ->
+ let (a',f') = (beta vv a, beta vv f) in
+ case f' of
+ Abs x b -> beta vv $ substTerm vv [(x,a')] (beta (x:vv) b)
+ _ -> (if a'==a && f'==f then id else beta vv) $ App f' a'
+ Prod x a b -> Prod x (beta vv a) (beta (x:vv) b)
+ Abs x b -> Abs x (beta (x:vv) b)
+ _ -> c
+
+-- special version of pattern matching, to deal with comp under lambda
+
+findMatch :: [([Patt],Term)] -> [Term] -> Err (Term, Substitution)
+findMatch cases terms = case cases of
+ [] -> Bad $"no applicable case for" +++ unwords (intersperse "," (map prt terms))
+ (patts,_):_ | length patts /= length terms ->
+ Bad ("wrong number of args for patterns :" +++
+ unwords (map prt patts) +++ "cannot take" +++ unwords (map prt terms))
+ (patts,val):cc -> case mapM tryMatch (zip patts terms) of
+ Ok substs -> return (tracd ("value" +++ prt_ val) val, concat substs)
+ _ -> findMatch cc terms
+
+tryMatch :: (Patt, Term) -> Err [(Ident, Term)]
+tryMatch (p,t) = do
+ t' <- termForm t
+ trym p t'
+ where
+
+ trym p t' = err (\s -> tracd s (Bad s)) (\t -> tracd (prtm p t) (return t)) $ ----
+ case (p,t') of
+ (PV IW, _) | notMeta t -> return [] -- optimization with wildcard
+ (PV x, _) | notMeta t -> return [(x,t)]
+ (PString s, ([],K i,[])) | s==i -> return []
+ (PInt s, ([],EInt i,[])) | s==i -> return []
+ (PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
+ (PP q p pp, ([], QC r f, tt)) |
+ p `eqStrIdent` f && length pp == length tt -> do
+ matches <- mapM tryMatch (zip pp tt)
+ return (concat matches)
+ (PP q p pp, ([], Q r f, tt)) |
+ p `eqStrIdent` f && length pp == length tt -> do
+ matches <- mapM tryMatch (zip pp tt)
+ return (concat matches)
+ (PT _ p',_) -> trym p' t'
+ (_, ([],Alias _ _ d,[])) -> tryMatch (p,d)
+ (PAs x p',_) -> do
+ subst <- trym p' t'
+ return $ (x,t) : subst
+ _ -> Bad ("no match in pattern" +++ prt p +++ "for" +++ prt t)
+
+ notMeta e = case e of
+ Meta _ -> False
+ App f a -> notMeta f && notMeta a
+ Abs _ b -> notMeta b
+ _ -> True
+
+ prtm p g =
+ prt p +++ ":" ++++ unwords [" " ++ prt_ x +++ "=" +++ prt_ y +++ ";" | (x,y) <- g]
diff --git a/src-3.0/GF/Grammar/Abstract.hs b/src-3.0/GF/Grammar/Abstract.hs
new file mode 100644
index 000000000..c03783a52
--- /dev/null
+++ b/src-3.0/GF/Grammar/Abstract.hs
@@ -0,0 +1,38 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Abstract
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:22:18 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.4 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Abstract (
+
+module GF.Grammar.Grammar,
+module GF.Grammar.Values,
+module GF.Grammar.Macros,
+module GF.Infra.Ident,
+module GF.Grammar.MMacros,
+module GF.Grammar.PrGrammar,
+
+Grammar
+
+ ) where
+
+import GF.Grammar.Grammar
+import GF.Grammar.Values
+import GF.Grammar.Macros
+import GF.Infra.Ident
+import GF.Grammar.MMacros
+import GF.Grammar.PrGrammar
+
+type Grammar = SourceGrammar ---
+
+
+
diff --git a/src-3.0/GF/Grammar/AppPredefined.hs b/src-3.0/GF/Grammar/AppPredefined.hs
new file mode 100644
index 000000000..fa0048c80
--- /dev/null
+++ b/src-3.0/GF/Grammar/AppPredefined.hs
@@ -0,0 +1,159 @@
+----------------------------------------------------------------------
+-- |
+-- Module : AppPredefined
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/10/06 14:21:34 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.13 $
+--
+-- Predefined function type signatures and definitions.
+-----------------------------------------------------------------------------
+
+module GF.Grammar.AppPredefined (isInPredefined, typPredefined, appPredefined
+ ) where
+
+import GF.Data.Operations
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.Macros
+import GF.Grammar.PrGrammar (prt,prt_,prtBad)
+---- import PGrammar (pTrm)
+
+-- predefined function type signatures and definitions. AR 12/3/2003.
+
+isInPredefined :: Ident -> Bool
+isInPredefined = err (const True) (const False) . typPredefined
+
+typPredefined :: Ident -> Err Type
+typPredefined c@(IC f) = case f of
+ "Int" -> return typePType
+ "Float" -> return typePType
+ "Error" -> return typeType
+ "Ints" -> return $ mkFunType [cnPredef "Int"] typePType
+ "PBool" -> return typePType
+ "error" -> return $ mkFunType [typeStr] (cnPredef "Error") -- non-can. of empty set
+ "PFalse" -> return $ cnPredef "PBool"
+ "PTrue" -> return $ cnPredef "PBool"
+ "dp" -> return $ mkFunType [cnPredef "Int",typeTok] typeTok
+ "drop" -> return $ mkFunType [cnPredef "Int",typeTok] typeTok
+ "eqInt" -> return $ mkFunType [cnPredef "Int",cnPredef "Int"] (cnPredef "PBool")
+ "lessInt"-> return $ mkFunType [cnPredef "Int",cnPredef "Int"] (cnPredef "PBool")
+ "eqStr" -> return $ mkFunType [typeTok,typeTok] (cnPredef "PBool")
+ "length" -> return $ mkFunType [typeTok] (cnPredef "Int")
+ "occur" -> return $ mkFunType [typeTok,typeTok] (cnPredef "PBool")
+ "occurs" -> return $ mkFunType [typeTok,typeTok] (cnPredef "PBool")
+ "plus" -> return $ mkFunType [cnPredef "Int",cnPredef "Int"] (cnPredef "Int")
+---- "read" -> (P : Type) -> Tok -> P
+ "show" -> return $ mkProd -- (P : PType) -> P -> Tok
+ ([(zIdent "P",typePType),(wildIdent,Vr (zIdent "P"))],typeStr,[])
+ "toStr" -> return $ mkProd -- (L : Type) -> L -> Str
+ ([(zIdent "L",typeType),(wildIdent,Vr (zIdent "L"))],typeStr,[])
+ "mapStr" ->
+ let ty = zIdent "L" in
+ return $ mkProd -- (L : Type) -> (Str -> Str) -> L -> L
+ ([(ty,typeType),(wildIdent,mkFunType [typeStr] typeStr),(wildIdent,Vr ty)],Vr ty,[])
+ "take" -> return $ mkFunType [cnPredef "Int",typeTok] typeTok
+ "tk" -> return $ mkFunType [cnPredef "Int",typeTok] typeTok
+ _ -> prtBad "unknown in Predef:" c
+typPredefined c = prtBad "unknown in Predef:" c
+
+appPredefined :: Term -> Err (Term,Bool)
+appPredefined t = case t of
+
+ App f x0 -> do
+ (x,_) <- appPredefined x0
+ case f of
+ -- one-place functions
+ Q (IC "Predef") (IC f) -> case (f, x) of
+ ("length", K s) -> retb $ EInt $ toInteger $ length s
+ _ -> retb t ---- prtBad "cannot compute predefined" t
+
+ -- two-place functions
+ App (Q (IC "Predef") (IC f)) z0 -> do
+ (z,_) <- appPredefined z0
+ case (f, norm z, norm x) of
+ ("drop", EInt i, K s) -> retb $ K (drop (fi i) s)
+ ("take", EInt i, K s) -> retb $ K (take (fi i) s)
+ ("tk", EInt i, K s) -> retb $ K (take (max 0 (length s - fi i)) s)
+ ("dp", EInt i, K s) -> retb $ K (drop (max 0 (length s - fi i)) s)
+ ("eqStr",K s, K t) -> retb $ if s == t then predefTrue else predefFalse
+ ("occur",K s, K t) -> retb $ if substring s t then predefTrue else predefFalse
+ ("occurs",K s, K t) -> retb $ if any (flip elem t) s then predefTrue else predefFalse
+ ("eqInt",EInt i, EInt j) -> retb $ if i==j then predefTrue else predefFalse
+ ("lessInt",EInt i, EInt j) -> retb $ if i<j then predefTrue else predefFalse
+ ("plus", EInt i, EInt j) -> retb $ EInt $ i+j
+ ("show", _, t) -> retb $ foldr C Empty $ map K $ words $ prt t
+ ("read", _, K s) -> retb $ str2tag s --- because of K, only works for atomic tags
+ ("toStr", _, t) -> trm2str t >>= retb
+
+ _ -> retb t ---- prtBad "cannot compute predefined" t
+
+ -- three-place functions
+ App (App (Q (IC "Predef") (IC f)) z0) y0 -> do
+ (y,_) <- appPredefined y0
+ (z,_) <- appPredefined z0
+ case (f, z, y, x) of
+ ("mapStr",ty,op,t) -> retf $ mapStr ty op t
+ _ -> retb t ---- prtBad "cannot compute predefined" t
+
+ _ -> retb t ---- prtBad "cannot compute predefined" t
+ _ -> retb t
+ ---- should really check the absence of arg variables
+ where
+ retb t = return (t,True) -- no further computing needed
+ retf t = return (t,False) -- must be computed further
+ norm t = case t of
+ Empty -> K []
+ _ -> t
+ fi = fromInteger
+
+-- read makes variables into constants
+
+str2tag :: String -> Term
+str2tag s = case s of
+---- '\'' : cs -> mkCn $ pTrm $ init cs
+ _ -> Cn $ IC s ---
+ where
+ mkCn t = case t of
+ Vr i -> Cn i
+ App c a -> App (mkCn c) (mkCn a)
+ _ -> t
+
+
+predefTrue = Q (IC "Predef") (IC "PTrue")
+predefFalse = Q (IC "Predef") (IC "PFalse")
+
+substring :: String -> String -> Bool
+substring s t = case (s,t) of
+ (c:cs, d:ds) -> (c == d && substring cs ds) || substring s ds
+ ([],_) -> True
+ _ -> False
+
+trm2str :: Term -> Err Term
+trm2str t = case t of
+ R ((_,(_,s)):_) -> trm2str s
+ T _ ((_,s):_) -> trm2str s
+ TSh _ ((_,s):_) -> trm2str s
+ V _ (s:_) -> trm2str s
+ C _ _ -> return $ t
+ K _ -> return $ t
+ S c _ -> trm2str c
+ Empty -> return $ t
+ _ -> prtBad "cannot get Str from term" t
+
+-- simultaneous recursion on type and term: type arg is essential!
+-- But simplify the task by assuming records are type-annotated
+-- (this has been done in type checking)
+mapStr :: Type -> Term -> Term -> Term
+mapStr ty f t = case (ty,t) of
+ _ | elem ty [typeStr,typeTok] -> App f t
+ (_, R ts) -> R [(l,mapField v) | (l,v) <- ts]
+ (Table a b,T ti cs) -> T ti [(p,mapStr b f v) | (p,v) <- cs]
+ _ -> t
+ where
+ mapField (mty,te) = case mty of
+ Just ty -> (mty,mapStr ty f te)
+ _ -> (mty,te)
diff --git a/src-3.0/GF/Grammar/Compute.hs b/src-3.0/GF/Grammar/Compute.hs
new file mode 100644
index 000000000..c76058cc2
--- /dev/null
+++ b/src-3.0/GF/Grammar/Compute.hs
@@ -0,0 +1,426 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Compute
+-- 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.Grammar.Compute (computeConcrete, computeTerm,computeConcreteRec) where
+
+import GF.Data.Operations
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Option
+import GF.Data.Str
+import GF.Grammar.PrGrammar
+import GF.Infra.Modules
+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 Data.List (nub,intersperse)
+import Control.Monad (liftM2, liftM)
+
+-- | computation of concrete syntax terms into normal form
+-- used mainly for partial evaluation
+computeConcrete :: SourceGrammar -> Term -> Err Term
+computeConcrete g t = {- refreshTerm t >>= -} computeTerm g [] t
+computeConcreteRec g t = {- refreshTerm t >>= -} computeTermOpt True g [] t
+
+computeTerm :: SourceGrammar -> Substitution -> Term -> Err Term
+computeTerm = computeTermOpt False
+
+-- rec=True is used if it cannot be assumed that looked-up constants
+-- have already been computed (mainly with -optimize=noexpand in .gfr)
+
+computeTermOpt :: Bool -> SourceGrammar -> Substitution -> Term -> Err Term
+computeTermOpt rec gr = comput True where
+
+ comput full g t = ---- errIn ("subterm" +++ prt t) $ --- for debugging
+ case t of
+
+ Q (IC "Predef") _ -> return t
+ Q p c -> look p c
+
+ -- if computed do nothing
+ Computed t' -> return $ unComputed t'
+
+ Vr x -> do
+ t' <- maybe (prtBad ("no value given to variable") x) return $ lookup x g
+ case t' of
+ _ | t == t' -> return t
+ _ -> comp g t'
+
+ -- Abs x@(IA _) b -> do
+ Abs x b | full -> do
+ let (xs,b1) = termFormCnc t
+ b' <- comp ([(x,Vr x) | x <- xs] ++ g) b1
+ return $ mkAbs xs b'
+ -- b' <- comp (ext x (Vr x) g) b
+ -- return $ Abs x b'
+ Abs _ _ -> return t -- hnf
+
+ 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'
+
+ -- beta-convert
+ App f a -> case appForm t of
+ (h,as) | length as > 1 -> do
+ h' <- hnf g h
+ as' <- mapM (comp g) as
+ case h' of
+ _ | not (null [() | FV _ <- as']) -> compApp g (mkApp h' as')
+ c@(QC _ _) -> do
+ return $ mkApp c as'
+ Q (IC "Predef") f -> do
+ (t',b) <- appPredefined (mkApp h' as')
+ if b then return t' else comp g t'
+
+ Abs _ _ -> do
+ let (xs,b) = termFormCnc h'
+ let g' = (zip xs as') ++ g
+ let as2 = drop (length xs) as'
+ let xs2 = drop (length as') xs
+ b' <- comp g' (mkAbs xs2 b)
+ if null as2 then return b' else comp g (mkApp b' as2)
+
+ _ -> compApp g (mkApp h' as')
+ _ -> compApp g t
+
+ 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 (prtBad "no value for label" l) (comp g . snd) $
+ lookup l $ reverse r
+
+ ExtR a (R b) ->
+ case comp g (P (R b) l) of
+ Ok v -> return v
+ _ -> comp g (P a l)
+
+--- { - --- this is incorrect, since b can contain the proper value
+ ExtR (R a) b -> -- NOT POSSIBLE both a and b records!
+ case comp g (P (R a) l) of
+ Ok v -> return v
+ _ -> comp g (P b l)
+--- - } ---
+
+ Alias _ _ r -> comp g (P r l)
+
+ S (T i cs) e -> prawitz g i (flip P l) cs e
+ S (V i cs) e -> prawitzV g i (flip P l) cs e
+
+ _ -> returnC $ P t' l
+
+ PI t l i -> comp g $ P t l -----
+
+ S t@(T ti cc) v -> do
+ v' <- comp g v
+ case v' of
+ FV vs -> do
+ ts' <- mapM (comp g . S t) vs
+ return $ variants ts'
+ _ -> case ti of
+{-
+ TComp _ -> do
+ case term2patt v' of
+ Ok p' -> case lookup p' cc of
+ Just u -> comp g u
+ _ -> do
+ t' <- comp g t
+ return $ S t' v' -- if v' is not canonical
+ _ -> do
+ t' <- comp g t
+ return $ S t' v'
+-}
+ _ -> case matchPattern cc v' of
+ Ok (c,g') -> comp (g' ++ g) c
+ _ | isCan v' -> prtBad ("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' <- case t of
+-- T _ _ -> return t
+-- V _ _ -> return t
+ _ -> comp g t
+
+ v' <- comp g v
+
+ case v' of
+ FV vs -> mapM (\c -> comp g (S t' c)) vs >>= returnC . variants
+ _ -> case t' of
+ FV ccs -> mapM (\c -> comp g (S c v')) ccs >>= returnC . variants
+
+ 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
+
+ -- course-of-values table: look up by index, no pattern matching needed
+ V ptyp ts -> do
+ vs <- allParamValues gr ptyp
+ case lookup v' (zip vs [0 .. length vs - 1]) of
+ Just i -> comp g $ ts !! i
+----- _ -> prtBad "selection" $ S t' v' -- debug
+ _ -> return $ S t' v' -- if v' is not canonical
+
+ T (TComp _) cs -> do
+ case term2patt v' of
+ Ok p' -> case lookup p' cs of
+ Just u -> comp g u
+ _ -> return $ S t' v' -- if v' is not canonical
+ _ -> return $ S t' v'
+
+ T _ cc -> case matchPattern cc v' of
+ Ok (c,g') -> comp (g' ++ g) c
+ _ | isCan v' -> prtBad ("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
+ S (V i cs) e -> prawitzV 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
+ (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
+
+ (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
+ (S (V i cs) e, s) -> prawitzV g i (flip Glue s) cs e
+ (s, S (V i cs) e) -> prawitzV 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' <- strsFromTerm ka
+---- (Alts _, K a) -> checks [do
+ x' <- 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
+ ]
+ (C u v,_) -> comp g $ C u (Glue v y)
+
+ _ -> 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 <- 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) -> plusRecord r' s'
+ (RecType rs, RecType ss) -> plusRecType r' s'
+ _ -> return $ ExtR r' s'
+
+ -- case-expand tables
+ -- if already expanded, don't expand again
+ T i@(TComp ty) 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 $ V ty (map snd 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 <- getTableType i
+ ptyp <- comp g pty0
+ case allParamValues gr ptyp of
+ Ok vs -> do
+
+ cs' <- mapM (compBranchOpt g) cs
+ sts <- mapM (matchPattern cs') vs
+ ts <- mapM (\ (c,g') -> comp (g' ++ g) c) sts
+ ps <- mapM term2patt vs
+ let ps' = ps --- PT ptyp (head ps) : tail ps
+---- return $ V ptyp ts -- to save space, just course of values
+ return $ T (TComp ptyp) (zip ps' ts)
+ _ -> do
+ cs' <- mapM (compBranch g) cs
+ return $ T i cs' -- happens with variable types
+
+ Alias c a d -> do
+ d' <- comp g d
+ return $ Alias c a d' -- alias only disappears in certain redexes
+
+ -- otherwise go ahead
+ _ -> composOp (comp g) t >>= returnC
+
+ where
+
+ compApp g (App f a) = do
+ f' <- hnf g f
+ a' <- comp g a
+ case (f',a') of
+ (Abs x b, FV as) ->
+ mapM (\c -> comp (ext x c g) b) as >>= return . variants
+ (_, FV as) -> mapM (\c -> comp g (App f' c)) as >>= return . variants
+ (FV fs, _) -> mapM (\c -> comp g (App c a')) fs >>= return . variants
+ (Abs x b,_) -> comp (ext x a' g) b
+
+ (QC _ _,_) -> returnC $ App f' a'
+
+ (Alias _ _ d, _) -> comp g (App d a')
+
+ (S (T i cs) e,_) -> prawitz g i (flip App a') cs e
+ (S (V i cs) e,_) -> prawitzV g i (flip App a') cs e
+
+ _ -> do
+ (t',b) <- appPredefined (App f' a')
+ if b then return t' else comp g t'
+
+ hnf = comput False
+ comp = comput True
+
+ look p c
+ | rec = lookupResDef gr p c >>= comp []
+ | otherwise = lookupResDef gr p c
+
+{-
+ look p c = case lookupResDefKind gr p c of
+ Ok (t,_) | noExpand p || rec -> 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
+-}
+
+ 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
+ _ -> 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
+ prawitzV g i f cs e = do
+ cs' <- mapM (comp g) [(f v) | v <- cs]
+ return $ S (V i cs') e
+
+-- | argument variables cannot be glued
+checkNoArgVars :: Term -> Err Term
+checkNoArgVars t = case t of
+ Vr (IA _) -> Bad $ glueErrorMsg $ prt t
+ Vr (IAV _) -> Bad $ glueErrorMsg $ prt t
+ _ -> composOp checkNoArgVars t
+
+glueErrorMsg s =
+ "Cannot glue (+) term with run-time variable" +++ s ++ "." ++++
+ "Use Prelude.bind instead."
diff --git a/src-3.0/GF/Grammar/Grammar.hs b/src-3.0/GF/Grammar/Grammar.hs
new file mode 100644
index 000000000..95fdce611
--- /dev/null
+++ b/src-3.0/GF/Grammar/Grammar.hs
@@ -0,0 +1,244 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Grammar
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:22:20 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.8 $
+--
+-- GF source abstract syntax used internally in compilation.
+--
+-- AR 23\/1\/2000 -- 30\/5\/2001 -- 4\/5\/2003
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Grammar (SourceGrammar,
+ SourceModInfo,
+ SourceModule,
+ SourceAbs,
+ SourceRes,
+ SourceCnc,
+ Info(..),
+ PValues,
+ Perh,
+ MPr,
+ Type,
+ Cat,
+ Fun,
+ QIdent,
+ Term(..),
+ Patt(..),
+ TInfo(..),
+ Label(..),
+ MetaSymb(..),
+ Decl,
+ Context,
+ Equation,
+ Labelling,
+ Assign,
+ Case,
+ Cases,
+ LocalDef,
+ Param,
+ Altern,
+ Substitution,
+ Branch(..),
+ Con,
+ Trm,
+ wildPatt,
+ varLabel
+ ) where
+
+import GF.Data.Str
+import GF.Infra.Ident
+import GF.Infra.Option ---
+import GF.Infra.Modules
+
+import GF.Data.Operations
+
+-- | grammar as presented to the compiler
+type SourceGrammar = MGrammar Ident Option Info
+
+type SourceModInfo = ModInfo Ident Option Info
+
+type SourceModule = (Ident, SourceModInfo)
+
+type SourceAbs = Module Ident Option Info
+type SourceRes = Module Ident Option Info
+type SourceCnc = Module Ident Option Info
+
+-- this is created in CheckGrammar, and so are Val and PVal
+type PValues = [Term]
+
+-- | the constructors are judgements in
+--
+-- - abstract syntax (/ABS/)
+--
+-- - resource (/RES/)
+--
+-- - concrete syntax (/CNC/)
+--
+-- and indirection to module (/INDIR/)
+data Info =
+-- judgements in abstract syntax
+ AbsCat (Perh Context) (Perh [Term]) -- ^ (/ABS/) constructors; must be 'Id' or 'QId'
+ | AbsFun (Perh Type) (Perh Term) -- ^ (/ABS/) 'Yes f' = canonical
+ | AbsTrans Term -- ^ (/ABS/)
+
+-- judgements in resource
+ | ResParam (Perh ([Param],Maybe PValues)) -- ^ (/RES/)
+ | ResValue (Perh (Type,Maybe Int)) -- ^ (/RES/) to mark parameter constructors for lookup
+ | ResOper (Perh Type) (Perh Term) -- ^ (/RES/)
+
+ | ResOverload [(Type,Term)] -- ^ (/RES/)
+
+-- judgements in concrete syntax
+ | CncCat (Perh Type) (Perh Term) MPr -- ^ (/CNC/) lindef ini'zed,
+ | CncFun (Maybe (Ident,(Context,Type))) (Perh Term) MPr -- (/CNC/) type info added at 'TC'
+
+-- indirection to module Ident
+ | AnyInd Bool Ident -- ^ (/INDIR/) the 'Bool' says if canonical
+ deriving (Read, Show)
+
+-- | to express indirection to other module
+type Perh a = Perhaps a Ident
+
+-- | printname
+type MPr = Perhaps Term Ident
+
+type Type = Term
+type Cat = QIdent
+type Fun = QIdent
+
+type QIdent = (Ident,Ident)
+
+data Term =
+ Vr Ident -- ^ variable
+ | Cn Ident -- ^ constant
+ | Con Ident -- ^ constructor
+ | EData -- ^ to mark in definition that a fun is a constructor
+ | Sort String -- ^ basic type
+ | EInt Integer -- ^ integer literal
+ | EFloat Double -- ^ floating point literal
+ | K String -- ^ string literal or token: @\"foo\"@
+ | Empty -- ^ the empty string @[]@
+
+ | App Term Term -- ^ application: @f a@
+ | Abs Ident Term -- ^ abstraction: @\x -> b@
+ | Meta MetaSymb -- ^ metavariable: @?i@ (only parsable: ? = ?0)
+ | Prod Ident Term Term -- ^ function type: @(x : A) -> B@
+ | Eqs [Equation] -- ^ abstraction by cases: @fn {x y -> b ; z u -> c}@
+ -- only used in internal representation
+ | Typed Term Term -- ^ type-annotated term
+--
+-- /below this, the constructors are only for concrete syntax/
+ | Example Term String -- ^ example-based term: @in M.C "foo"
+ | RecType [Labelling] -- ^ record type: @{ p : A ; ...}@
+ | R [Assign] -- ^ record: @{ p = a ; ...}@
+ | P Term Label -- ^ projection: @r.p@
+ | PI Term Label Int -- ^ index-annotated projection
+ | ExtR Term Term -- ^ extension: @R ** {x : A}@ (both types and terms)
+
+ | Table Term Term -- ^ table type: @P => A@
+ | T TInfo [Case] -- ^ table: @table {p => c ; ...}@
+ | TSh TInfo [Cases] -- ^ table with disjunctive patters (only back end opt)
+ | V Type [Term] -- ^ table given as course of values: @table T [c1 ; ... ; cn]@
+ | S Term Term -- ^ selection: @t ! p@
+ | Val Type Int -- ^ parameter value number: @T # i#
+
+ | Let LocalDef Term -- ^ local definition: @let {t : T = a} in b@
+
+ | Alias Ident Type Term -- ^ constant and its definition, used in inlining
+
+ | Q Ident Ident -- ^ qualified constant from a package
+ | QC Ident Ident -- ^ qualified constructor from a package
+
+ | C Term Term -- ^ concatenation: @s ++ t@
+ | Glue Term Term -- ^ agglutination: @s + t@
+
+ | EPatt Patt -- ^ pattern (in macro definition): # p
+ | EPattType Term -- ^ pattern type: pattern T
+
+ | FV [Term] -- ^ alternatives in free variation: @variants { s ; ... }@
+
+ | Alts (Term, [(Term, Term)]) -- ^ alternatives by prefix: @pre {t ; s\/c ; ...}@
+ | Strs [Term] -- ^ conditioning prefix strings: @strs {s ; ...}@
+--
+-- /below this, the last three constructors are obsolete/
+ | LiT Ident -- ^ linearization type
+ | Ready Str -- ^ result of compiling; not to be parsed ...
+ | Computed Term -- ^ result of computing: not to be reopened nor parsed
+
+ deriving (Read, Show, Eq, Ord)
+
+data Patt =
+ PC Ident [Patt] -- ^ constructor pattern: @C p1 ... pn@ @C@
+ | PP Ident Ident [Patt] -- ^ package constructor pattern: @P.C p1 ... pn@ @P.C@
+ | PV Ident -- ^ variable pattern: @x@
+ | PW -- ^ wild card pattern: @_@
+ | PR [(Label,Patt)] -- ^ record pattern: @{r = p ; ...}@ -- only concrete
+ | PString String -- ^ string literal pattern: @\"foo\"@ -- only abstract
+ | PInt Integer -- ^ integer literal pattern: @12@ -- only abstract
+ | PFloat Double -- ^ float literal pattern: @1.2@ -- only abstract
+ | PT Type Patt -- ^ type-annotated pattern
+
+ | PVal Type Int -- ^ parameter value number: @T # i#
+
+ | PAs Ident Patt -- ^ as-pattern: x@p
+
+ -- regular expression patterns
+ | PNeg Patt -- ^ negated pattern: -p
+ | PAlt Patt Patt -- ^ disjunctive pattern: p1 | p2
+ | PSeq Patt Patt -- ^ sequence of token parts: p + q
+ | PRep Patt -- ^ repetition of token part: p*
+ | PChar -- ^ string of length one: ?
+ | PChars [Char] -- ^ character list: ["aeiou"]
+ | PMacro Ident -- #p
+ | PM Ident Ident -- #m.p
+
+ deriving (Read, Show, Eq, Ord)
+
+-- | to guide computation and type checking of tables
+data TInfo =
+ TRaw -- ^ received from parser; can be anything
+ | TTyped Type -- ^ type annontated, but can be anything
+ | TComp Type -- ^ expanded
+ | TWild Type -- ^ just one wild card pattern, no need to expand
+ deriving (Read, Show, Eq, Ord)
+
+-- | record label
+data Label =
+ LIdent String
+ | LVar Int
+ deriving (Read, Show, Eq, Ord)
+
+newtype MetaSymb = MetaSymb Int deriving (Read, Show, Eq, Ord)
+
+type Decl = (Ident,Term) -- (x:A) (_:A) A
+type Context = [Decl] -- (x:A)(y:B) (x,y:A) (_,_:A)
+type Equation = ([Patt],Term)
+
+type Labelling = (Label, Term)
+type Assign = (Label, (Maybe Type, Term))
+type Case = (Patt, Term)
+type Cases = ([Patt], Term)
+type LocalDef = (Ident, (Maybe Type, Term))
+
+type Param = (Ident, Context)
+type Altern = (Term, [(Term, Term)])
+
+type Substitution = [(Ident, Term)]
+
+-- | branches à la Alfa
+newtype Branch = Branch (Con,([Ident],Term)) deriving (Eq, Ord,Show,Read)
+type Con = Ident ---
+
+varLabel :: Int -> Label
+varLabel = LVar
+
+wildPatt :: Patt
+wildPatt = PV wildIdent
+
+type Trm = Term
diff --git a/src-3.0/GF/Grammar/Lockfield.hs b/src-3.0/GF/Grammar/Lockfield.hs
new file mode 100644
index 000000000..960b12983
--- /dev/null
+++ b/src-3.0/GF/Grammar/Lockfield.hs
@@ -0,0 +1,46 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Lockfield
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/11 23:24:34 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.7 $
+--
+-- Creating and using lock fields in reused resource grammars.
+--
+-- AR 8\/2\/2005 detached from 'compile/MkResource'
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Lockfield (lockRecType, unlockRecord, lockLabel, isLockLabel) where
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.Macros
+import GF.Grammar.PrGrammar
+
+import GF.Data.Operations
+
+lockRecType :: Ident -> Type -> Err Type
+lockRecType c t@(RecType rs) =
+ let lab = lockLabel c in
+ return $ if elem lab (map fst rs) || elem (prt c) ["String","Int"]
+ then t --- don't add an extra copy of lock field, nor predef cats
+ else RecType (rs ++ [(lockLabel c, RecType [])])
+lockRecType c t = plusRecType t $ RecType [(lockLabel c, RecType [])]
+
+unlockRecord :: Ident -> Term -> Err Term
+unlockRecord c ft = do
+ let (xs,t) = termFormCnc ft
+ t' <- plusRecord t $ R [(lockLabel c, (Just (RecType []),R []))]
+ return $ mkAbs xs t'
+
+lockLabel :: Ident -> Label
+lockLabel c = LIdent $ "lock_" ++ prt c ----
+
+isLockLabel :: Label -> Bool
+isLockLabel l = case l of
+ LIdent c -> take 5 c == "lock_"
+ _ -> False
diff --git a/src-3.0/GF/Grammar/LookAbs.hs b/src-3.0/GF/Grammar/LookAbs.hs
new file mode 100644
index 000000000..5bd4c1e41
--- /dev/null
+++ b/src-3.0/GF/Grammar/LookAbs.hs
@@ -0,0 +1,196 @@
+----------------------------------------------------------------------
+-- |
+-- Module : LookAbs
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/28 16:42:48 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.14 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Grammar.LookAbs (GFCGrammar,
+ lookupAbsDef,
+ lookupFunType,
+ lookupCatContext,
+ lookupTransfer,
+ isPrimitiveFun,
+ lookupRef,
+ refsForType,
+ funRulesOf,
+ hasHOAS,
+ allCatsOf,
+ allBindCatsOf,
+ funsForType,
+ funsOnType,
+ funsOnTypeFs,
+ allDefs,
+ lookupFunTypeSrc,
+ lookupCatContextSrc
+ ) where
+
+import GF.Data.Operations
+import qualified GF.Canon.GFC as C
+import GF.Grammar.Abstract
+import GF.Infra.Ident
+
+import GF.Infra.Modules
+
+import Data.List (nub)
+import Control.Monad
+
+type GFCGrammar = C.CanonGrammar
+
+lookupAbsDef :: GFCGrammar -> Ident -> Ident -> Err (Maybe Term)
+lookupAbsDef gr m c = errIn ("looking up absdef of" +++ prt c) $ do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ C.AbsFun _ t -> return $ return t
+ C.AnyInd _ n -> lookupAbsDef gr n c
+ _ -> return Nothing
+ _ -> Bad $ prt m +++ "is not an abstract module"
+
+lookupFunType :: GFCGrammar -> Ident -> Ident -> Err Type
+lookupFunType gr m c = errIn ("looking up funtype of" +++ prt c +++ "in module" +++ prt m) $ do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ C.AbsFun t _ -> return t
+ C.AnyInd _ n -> lookupFunType gr n c
+ _ -> prtBad "cannot find type of" c
+ _ -> Bad $ prt m +++ "is not an abstract module"
+
+lookupCatContext :: GFCGrammar -> Ident -> Ident -> Err Context
+lookupCatContext gr m c = errIn ("looking up context of cat" +++ prt c) $ do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ C.AbsCat co _ -> return co
+ C.AnyInd _ n -> lookupCatContext gr n c
+ _ -> prtBad "unknown category" c
+ _ -> Bad $ prt m +++ "is not an abstract module"
+
+-- | lookup for transfer function: transfer-module-name, category name
+lookupTransfer :: GFCGrammar -> Ident -> Ident -> Err Term
+lookupTransfer gr m c = errIn ("looking up transfer of cat" +++ prt c) $ do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ C.AbsTrans t -> return t
+ C.AnyInd _ n -> lookupTransfer gr n c
+ _ -> prtBad "cannot transfer function for" c
+ _ -> Bad $ prt m +++ "is not a transfer module"
+
+
+-- | should be revised (20\/9\/2003)
+isPrimitiveFun :: GFCGrammar -> Fun -> Bool
+isPrimitiveFun gr (m,c) = case lookupAbsDef gr m c of
+ Ok (Just (Eqs [])) -> True -- is canonical
+ Ok (Just _) -> False -- has defining clauses
+ _ -> True -- has no definition
+
+
+-- | looking up refinement terms
+lookupRef :: GFCGrammar -> Binds -> Term -> Err Val
+lookupRef gr binds at = case at of
+ Q m f -> lookupFunType gr m f >>= return . vClos
+ Vr i -> maybeErr ("unknown variable" +++ prt at) $ lookup i binds
+ EInt _ -> return valAbsInt
+ EFloat _ -> return valAbsFloat
+ K _ -> return valAbsString
+ _ -> prtBad "cannot refine with complex term" at ---
+
+refsForType :: (Val -> Type -> Bool) -> GFCGrammar -> Binds -> Val -> [(Term,(Val,Bool))]
+refsForType compat gr binds val =
+ -- bound variables --- never recursive?
+ [(vr i, (t,False)) | (i,t) <- binds, Ok ty <- [val2exp t], compat val ty] ++
+ -- integer and string literals
+ [(EInt i, (val,False)) | val == valAbsInt, i <- [0,1,2,5,11,1978]] ++
+ [(EFloat i, (val,False)) | val == valAbsFloat, i <- [3.1415926]] ++
+ [(K s, (val,False)) | val == valAbsString, s <- ["foo", "NN", "x"]] ++
+ -- functions defined in the current abstract syntax
+ [(qq f, (vClos t,isRecursiveType t)) | (f,t) <- funsForType compat gr val]
+
+
+funRulesOf :: GFCGrammar -> [(Fun,Type)]
+funRulesOf gr =
+---- funRulesForLiterals ++
+ [((i,f),typ) | (i, ModMod m) <- modules gr,
+ mtype m == MTAbstract,
+ (f, C.AbsFun typ _) <- tree2list (jments m)]
+
+-- testing for higher-order abstract syntax
+hasHOAS :: GFCGrammar -> Bool
+hasHOAS gr = any isHigherOrderType [t | (_,t) <- funRulesOf gr] where
+
+allCatsOf :: GFCGrammar -> [(Cat,Context)]
+allCatsOf gr =
+ [((i,c),cont) | (i, ModMod m) <- modules gr,
+ isModAbs m,
+ (c, C.AbsCat cont _) <- tree2list (jments m)]
+
+allBindCatsOf :: GFCGrammar -> [Cat]
+allBindCatsOf gr =
+ nub [c | (i, ModMod m) <- modules gr,
+ isModAbs m,
+ (c, C.AbsFun typ _) <- tree2list (jments m),
+ Ok (cont,_) <- [firstTypeForm typ],
+ c <- concatMap fst $ errVal [] $ mapM (catSkeleton . snd) cont
+ ]
+
+funsForType :: (Val -> Type -> Bool) -> GFCGrammar -> Val -> [(Fun,Type)]
+funsForType compat gr val = [(fun,typ) | (fun,typ) <- funRulesOf gr,
+ compat val typ]
+
+funsOnType :: (Val -> Type -> Bool) -> GFCGrammar -> Val -> [((Fun,Int),Type)]
+funsOnType compat gr = funsOnTypeFs compat (funRulesOf gr)
+
+funsOnTypeFs :: (Val -> Type -> Bool) -> [(Fun,Type)] -> Val -> [((Fun,Int),Type)]
+funsOnTypeFs compat fs val = [((fun,i),typ) |
+ (fun,typ) <- fs,
+ Ok (args,_,_) <- [typeForm typ],
+ (i,arg) <- zip [0..] (map snd args),
+ compat val arg]
+
+allDefs :: GFCGrammar -> [(Fun,Term)]
+allDefs gr = [((i,c),d) | (i, ModMod m) <- modules gr,
+ isModAbs m,
+ (c, C.AbsFun _ d) <- tree2list (jments m)]
+
+-- | this is needed at compile time
+lookupFunTypeSrc :: Grammar -> Ident -> Ident -> Err Type
+lookupFunTypeSrc gr m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ AbsFun (Yes t) _ -> return t
+ AnyInd _ n -> lookupFunTypeSrc gr n c
+ _ -> prtBad "cannot find type of" c
+ _ -> Bad $ prt m +++ "is not an abstract module"
+
+-- | this is needed at compile time
+lookupCatContextSrc :: Grammar -> Ident -> Ident -> Err Context
+lookupCatContextSrc gr m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ AbsCat (Yes co) _ -> return co
+ AnyInd _ n -> lookupCatContextSrc gr n c
+ _ -> prtBad "unknown category" c
+ _ -> Bad $ prt m +++ "is not an abstract module"
diff --git a/src-3.0/GF/Grammar/Lookup.hs b/src-3.0/GF/Grammar/Lookup.hs
new file mode 100644
index 000000000..81a62decf
--- /dev/null
+++ b/src-3.0/GF/Grammar/Lookup.hs
@@ -0,0 +1,275 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Lookup
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/10/27 13:21:53 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.15 $
+--
+-- Lookup in source (concrete and resource) when compiling.
+--
+-- lookup in resource and concrete in compiling; for abstract, use 'Look'
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Lookup (
+ lookupResDef,
+ lookupResDefKind,
+ lookupResType,
+ lookupOverload,
+ lookupParams,
+ lookupParamValues,
+ lookupFirstTag,
+ lookupValueIndex,
+ lookupIndexValue,
+ allOrigInfos,
+ allParamValues,
+ lookupAbsDef,
+ lookupLincat,
+ opersForType,
+ linTypeInt
+ ) where
+
+import GF.Data.Operations
+import GF.Grammar.Abstract
+import GF.Infra.Modules
+import GF.Grammar.Lockfield
+
+import Data.List (nub,sortBy)
+import Control.Monad
+
+-- whether lock fields are added in reuse
+lock c = lockRecType c -- return
+unlock c = unlockRecord c -- return
+
+lookupResDef :: SourceGrammar -> Ident -> Ident -> Err Term
+lookupResDef gr m c = liftM fst $ lookupResDefKind gr m c
+
+-- 0 = oper, 1 = lin, 2 = canonical. v > 0 means: no need to be recomputed
+lookupResDefKind :: SourceGrammar -> Ident -> Ident -> Err (Term,Int)
+lookupResDefKind gr m c = look True m c where
+ look isTop m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ ResOper _ (Yes t) -> return (qualifAnnot m t, 0)
+ ResOper _ Nope -> return (Q m c, 0) ---- if isTop then lookExt m c
+ ---- else prtBad "cannot find in exts" c
+
+ CncCat (Yes ty) _ _ -> liftM (flip (,) 1) $ lock c ty
+ CncCat _ _ _ -> liftM (flip (,) 1) $ lock c defLinType
+ CncFun (Just (cat,_)) (Yes tr) _ -> liftM (flip (,) 1) $ unlock cat tr
+
+ CncFun _ (Yes tr) _ -> liftM (flip (,) 1) $ unlock c tr
+
+ AnyInd _ n -> look False n c
+ ResParam _ -> return (QC m c,2)
+ ResValue _ -> return (QC m c,2)
+ _ -> Bad $ prt c +++ "is not defined in resource" +++ prt m
+ _ -> Bad $ prt m +++ "is not a resource"
+ lookExt m c =
+ checks ([look False n c | n <- allExtensions gr m] ++ [return (Q m c,3)])
+
+lookupResType :: SourceGrammar -> Ident -> Ident -> Err Type
+lookupResType gr m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ ResOper (Yes t) _ -> return $ qualifAnnot m t
+ ResOper (May n) _ -> lookupResType gr n c
+
+ -- used in reused concrete
+ CncCat _ _ _ -> return typeType
+ CncFun (Just (cat,(cont@(_:_),val))) _ _ -> do
+ val' <- lock cat val
+ return $ mkProd (cont, val', [])
+ CncFun _ _ _ -> lookFunType m m c
+ AnyInd _ n -> lookupResType gr n c
+ ResParam _ -> return $ typePType
+ ResValue (Yes (t,_)) -> return $ qualifAnnotPar m t
+ _ -> Bad $ prt c +++ "has no type defined in resource" +++ prt m
+ _ -> Bad $ prt m +++ "is not a resource"
+ where
+ lookFunType e m c = do
+ a <- abstractOfConcrete gr m
+ lookFun e m c a
+ lookFun e m c a = do
+ mu <- lookupModMod gr a
+ info <- lookupIdentInfo mu c
+ case info of
+ AbsFun (Yes ty) _ -> return $ redirectTerm e ty
+ AbsCat _ _ -> return typeType
+ AnyInd _ n -> lookFun e m c n
+ _ -> prtBad "cannot find type of reused function" c
+
+lookupOverload :: SourceGrammar -> Ident -> Ident -> Err [([Type],(Type,Term))]
+lookupOverload gr m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ ResOverload tysts ->
+ return [(map snd args,(val,tr)) |
+ (ty,tr) <- tysts, Ok (args,val) <- [typeFormCnc ty]]
+
+ AnyInd _ n -> lookupOverload gr n c
+ _ -> Bad $ prt c +++ "is not an overloaded operation"
+ _ -> Bad $ prt m +++ "is not a resource"
+
+lookupOrigInfo :: SourceGrammar -> Ident -> Ident -> Err Info
+lookupOrigInfo gr m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ AnyInd _ n -> lookupOrigInfo gr n c
+ i -> return i
+ _ -> Bad $ prt m +++ "is not run-time module"
+
+lookupParams :: SourceGrammar -> Ident -> Ident -> Err ([Param],Maybe PValues)
+lookupParams gr = look True where
+ look isTop m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ ResParam (Yes psm) -> return psm
+
+ AnyInd _ n -> look False n c
+ _ -> Bad $ prt c +++ "has no parameters defined in resource" +++ prt m
+ _ -> Bad $ prt m +++ "is not a resource"
+ lookExt m c =
+ checks [look False n c | n <- allExtensions gr m]
+
+lookupParamValues :: SourceGrammar -> Ident -> Ident -> Err [Term]
+lookupParamValues gr m c = do
+ (ps,mpv) <- lookupParams gr m c
+ case mpv of
+ Just ts -> return ts
+ _ -> liftM concat $ mapM mkPar ps
+ where
+ mkPar (f,co) = do
+ vs <- liftM combinations $ mapM (\ (_,ty) -> allParamValues gr ty) co
+ return $ map (mkApp (QC m f)) vs
+
+lookupFirstTag :: SourceGrammar -> Ident -> Ident -> Err Term
+lookupFirstTag gr m c = do
+ vs <- lookupParamValues gr m c
+ case vs of
+ v:_ -> return v
+ _ -> prtBad "no parameter values given to type" c
+
+lookupValueIndex :: SourceGrammar -> Type -> Term -> Err Term
+lookupValueIndex gr ty tr = do
+ ts <- allParamValues gr ty
+ case lookup tr $ zip ts [0..] of
+ Just i -> return $ Val ty i
+ _ -> Bad $ "no index for" +++ prt tr +++ "in" +++ prt ty
+
+lookupIndexValue :: SourceGrammar -> Type -> Int -> Err Term
+lookupIndexValue gr ty i = do
+ ts <- allParamValues gr ty
+ if i < length ts
+ then return $ ts !! i
+ else Bad $ "no value for index" +++ show i +++ "in" +++ prt ty
+
+allOrigInfos :: SourceGrammar -> Ident -> [(Ident,Info)]
+allOrigInfos gr m = errVal [] $ do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> return [(c,i) | (c,_) <- tree2list (jments mo), Ok i <- [look c]]
+ where
+ look = lookupOrigInfo gr m
+
+allParamValues :: SourceGrammar -> Type -> Err [Term]
+allParamValues cnc ptyp = case ptyp of
+ App (Q (IC "Predef") (IC "Ints")) (EInt n) ->
+ return [EInt i | i <- [0..n]]
+ QC p c -> lookupParamValues cnc p c
+ Q p c -> lookupParamValues cnc p c ----
+ RecType r -> do
+ let (ls,tys) = unzip $ sortByFst r
+ tss <- mapM allPV tys
+ return [R (zipAssign ls ts) | ts <- combinations tss]
+ _ -> prtBad "cannot find parameter values for" ptyp
+ where
+ allPV = allParamValues cnc
+ -- to normalize records and record types
+ sortByFst = sortBy (\ x y -> compare (fst x) (fst y))
+
+qualifAnnot :: Ident -> Term -> Term
+qualifAnnot _ = id
+-- Using this we wouldn't have to annotate constants defined in a module itself.
+-- But things are simpler if we do (cf. Zinc).
+-- Change Rename.self2status to change this behaviour.
+
+-- we need this for lookup in ResVal
+qualifAnnotPar m t = case t of
+ Cn c -> Q m c
+ Con c -> QC m c
+ _ -> composSafeOp (qualifAnnotPar m) t
+
+lookupAbsDef :: SourceGrammar -> Ident -> Ident -> Err (Maybe Term)
+lookupAbsDef gr m c = errIn ("looking up absdef of" +++ prt c) $ do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ AbsFun _ (Yes t) -> return $ return t
+ AnyInd _ n -> lookupAbsDef gr n c
+ _ -> return Nothing
+ _ -> Bad $ prt m +++ "is not an abstract module"
+
+linTypeInt :: Type
+linTypeInt = defLinType
+--- let ints k = App (Q (IC "Predef") (IC "Ints")) (EInt k) in
+--- RecType [
+--- (LIdent "last",ints 9),(LIdent "s", typeStr), (LIdent "size",ints 1)]
+
+lookupLincat :: SourceGrammar -> Ident -> Ident -> Err Type
+lookupLincat gr m c | elem c [zIdent "Int"] = return linTypeInt
+lookupLincat gr m c | elem c [zIdent "String", zIdent "Float"] =
+ return defLinType --- ad hoc; not needed?
+
+lookupLincat gr m c = do
+ mi <- lookupModule gr m
+ case mi of
+ ModMod mo -> do
+ info <- lookupIdentInfo mo c
+ case info of
+ CncCat (Yes t) _ _ -> return t
+ AnyInd _ n -> lookupLincat gr n c
+ _ -> Bad $ prt c +++ "has no linearization type in" +++ prt m
+ _ -> Bad $ prt m +++ "is not concrete"
+
+
+-- The first type argument is uncomputed, usually a category symbol.
+-- This is a hack to find implicit (= reused) opers.
+
+opersForType :: SourceGrammar -> Type -> Type -> [(QIdent,Term)]
+opersForType gr orig val =
+ [((i,f),ty) | (i,m) <- allModMod gr, (f,ty) <- opers i m val] where
+ opers i m val =
+ [(f,ty) |
+ (f,ResOper (Yes ty) _) <- tree2list $ jments m,
+ Ok valt <- [valTypeCnc ty],
+ elem valt [val,orig]
+ ] ++
+ let cat = err zIdent snd (valCat orig) in --- ignore module
+ [(f,ty) |
+ Ok a <- [abstractOfConcrete gr i >>= lookupModMod gr],
+ (f, AbsFun (Yes ty0) _) <- tree2list $ jments a,
+ let ty = redirectTerm i ty0,
+ Ok valt <- [valCat ty],
+ cat == snd valt ---
+ ]
diff --git a/src-3.0/GF/Grammar/MMacros.hs b/src-3.0/GF/Grammar/MMacros.hs
new file mode 100644
index 000000000..dd7331685
--- /dev/null
+++ b/src-3.0/GF/Grammar/MMacros.hs
@@ -0,0 +1,341 @@
+----------------------------------------------------------------------
+-- |
+-- Module : MMacros
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/05/10 12:49:13 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.9 $
+--
+-- some more abstractions on grammars, esp. for Edit
+-----------------------------------------------------------------------------
+
+module GF.Grammar.MMacros where
+
+import GF.Data.Operations
+import GF.Data.Zipper
+
+import GF.Grammar.Grammar
+import GF.Grammar.PrGrammar
+import GF.Infra.Ident
+import GF.Grammar.Refresh
+import GF.Grammar.Values
+----import GrammarST
+import GF.Grammar.Macros
+
+import Control.Monad
+
+nodeTree :: Tree -> TrNode
+argsTree :: Tree -> [Tree]
+
+nodeTree (Tr (n,_)) = n
+argsTree (Tr (_,ts)) = ts
+
+isFocusNode :: TrNode -> Bool
+bindsNode :: TrNode -> Binds
+atomNode :: TrNode -> Atom
+valNode :: TrNode -> Val
+constrsNode :: TrNode -> Constraints
+metaSubstsNode :: TrNode -> MetaSubst
+
+isFocusNode (N (_,_,_,_,b)) = b
+bindsNode (N (b,_,_,_,_)) = b
+atomNode (N (_,a,_,_,_)) = a
+valNode (N (_,_,v,_,_)) = v
+constrsNode (N (_,_,_,(c,_),_)) = c
+metaSubstsNode (N (_,_,_,(_,m),_)) = m
+
+atomTree :: Tree -> Atom
+valTree :: Tree -> Val
+
+atomTree = atomNode . nodeTree
+valTree = valNode . nodeTree
+
+mkNode :: Binds -> Atom -> Val -> (Constraints, MetaSubst) -> TrNode
+mkNode binds atom vtyp cs = N (binds,atom,vtyp,cs,False)
+
+type Var = Ident
+type Meta = MetaSymb
+
+metasTree :: Tree -> [Meta]
+metasTree = concatMap metasNode . scanTree where
+ metasNode n = [m | AtM m <- [atomNode n]] ++ map fst (metaSubstsNode n)
+
+varsTree :: Tree -> [(Var,Val)]
+varsTree t = [(x,v) | N (_,AtV x,v,_,_) <- scanTree t]
+
+constrsTree :: Tree -> Constraints
+constrsTree = constrsNode . nodeTree
+
+allConstrsTree :: Tree -> Constraints
+allConstrsTree = concatMap constrsNode . scanTree
+
+changeConstrs :: (Constraints -> Constraints) -> TrNode -> TrNode
+changeConstrs f (N (b,a,v,(c,m),x)) = N (b,a,v,(f c, m),x)
+
+changeMetaSubst :: (MetaSubst -> MetaSubst) -> TrNode -> TrNode
+changeMetaSubst f (N (b,a,v,(c,m),x)) = N (b,a,v,(c, f m),x)
+
+changeAtom :: (Atom -> Atom) -> TrNode -> TrNode
+changeAtom f (N (b,a,v,(c,m),x)) = N (b,f a,v,(c, m),x)
+
+-- * on the way to Edit
+
+uTree :: Tree
+uTree = Tr (uNode, []) -- unknown tree
+
+uNode :: TrNode
+uNode = mkNode [] uAtom uVal ([],[])
+
+
+uAtom :: Atom
+uAtom = AtM meta0
+
+mAtom :: Atom
+mAtom = AtM meta0
+
+uVal :: Val
+uVal = vClos uExp
+
+vClos :: Exp -> Val
+vClos = VClos []
+
+uExp :: Exp
+uExp = Meta meta0
+
+mExp, mExp0 :: Exp
+mExp = Meta meta0
+mExp0 = mExp
+
+meta2exp :: MetaSymb -> Exp
+meta2exp = Meta
+
+atomC :: Fun -> Atom
+atomC = AtC
+
+funAtom :: Atom -> Err Fun
+funAtom a = case a of
+ AtC f -> return f
+ _ -> prtBad "not function head" a
+
+uBoundVar :: Ident
+uBoundVar = zIdent "#h" -- used for suppressed bindings
+
+atomIsMeta :: Atom -> Bool
+atomIsMeta atom = case atom of
+ AtM _ -> True
+ _ -> False
+
+getMetaAtom :: Atom -> Err Meta
+getMetaAtom a = case a of
+ AtM m -> return m
+ _ -> Bad "the active node is not meta"
+
+cat2val :: Context -> Cat -> Val
+cat2val cont cat = vClos $ mkApp (qq cat) [mkMeta i | i <- [1..length cont]]
+
+val2cat :: Val -> Err Cat
+val2cat v = val2exp v >>= valCat
+
+substTerm :: [Ident] -> Substitution -> Term -> Term
+substTerm ss g c = case c of
+ Vr x -> maybe c id $ lookup x g
+ App f a -> App (substTerm ss g f) (substTerm ss g a)
+ Abs x b -> let y = mkFreshVarX ss x in
+ Abs y (substTerm (y:ss) ((x, Vr y):g) b)
+ Prod x a b -> let y = mkFreshVarX ss x in
+ Prod y (substTerm ss g a) (substTerm (y:ss) ((x,Vr y):g) b)
+ _ -> c
+
+metaSubstExp :: MetaSubst -> [(Meta,Exp)]
+metaSubstExp msubst = [(m, errVal (meta2exp m) (val2expSafe v)) | (m,v) <- msubst]
+
+-- * belong here rather than to computation
+
+substitute :: [Var] -> Substitution -> Exp -> Err Exp
+substitute v s = return . substTerm v s
+
+alphaConv :: [Var] -> (Var,Var) -> Exp -> Err Exp ---
+alphaConv oldvars (x,x') = substitute (x:x':oldvars) [(x,Vr x')]
+
+alphaFresh :: [Var] -> Exp -> Err Exp
+alphaFresh vs = refreshTermN $ maxVarIndex vs
+
+-- | done in a state monad
+alphaFreshAll :: [Var] -> [Exp] -> Err [Exp]
+alphaFreshAll vs = mapM $ alphaFresh vs
+
+-- | for display
+val2exp :: Val -> Err Exp
+val2exp = val2expP False
+
+-- | for type checking
+val2expSafe :: Val -> Err Exp
+val2expSafe = val2expP True
+
+val2expP :: Bool -> Val -> Err Exp
+val2expP safe v = case v of
+
+ VClos g@(_:_) e@(Meta _) -> if safe
+ then prtBad "unsafe value substitution" v
+ else substVal g e
+ VClos g e -> substVal g e
+ VApp f c -> liftM2 App (val2expP safe f) (val2expP safe c)
+ VCn c -> return $ qq c
+ VGen i x -> if safe
+ then prtBad "unsafe val2exp" v
+ else return $ vr $ x --- in editing, no alpha conversions presentv
+ where
+ substVal g e = mapPairsM (val2expP safe) g >>= return . (\s -> substTerm [] s e)
+
+isConstVal :: Val -> Bool
+isConstVal v = case v of
+ VApp f c -> isConstVal f && isConstVal c
+ VCn _ -> True
+ VClos [] e -> null $ freeVarsExp e
+ _ -> False --- could be more liberal
+
+mkProdVal :: Binds -> Val -> Err Val ---
+mkProdVal bs v = do
+ bs' <- mapPairsM val2exp bs
+ v' <- val2exp v
+ return $ vClos $ foldr (uncurry Prod) v' bs'
+
+freeVarsExp :: Exp -> [Ident]
+freeVarsExp e = case e of
+ Vr x -> [x]
+ App f c -> freeVarsExp f ++ freeVarsExp c
+ Abs x b -> filter (/=x) (freeVarsExp b)
+ Prod x a b -> freeVarsExp a ++ filter (/=x) (freeVarsExp b)
+ _ -> [] --- thus applies to abstract syntax only
+
+ident2string :: Ident -> String
+ident2string = prIdent
+
+tree :: (TrNode,[Tree]) -> Tree
+tree = Tr
+
+eqCat :: Cat -> Cat -> Bool
+eqCat = (==)
+
+addBinds :: Binds -> Tree -> Tree
+addBinds b (Tr (N (b0,at,t,c,x),ts)) = Tr (N (b ++ b0,at,t,c,x),ts)
+
+bodyTree :: Tree -> Tree
+bodyTree (Tr (N (_,a,t,c,x),ts)) = Tr (N ([],a,t,c,x),ts)
+
+refreshMetas :: [Meta] -> Exp -> Exp
+refreshMetas metas = fst . rms minMeta where
+ rms meta trm = case trm of
+ Meta m -> (Meta meta, nextMeta meta)
+ App f a -> let (f',msf) = rms meta f
+ (a',msa) = rms msf a
+ in (App f' a', msa)
+ Prod x a b ->
+ let (a',msa) = rms meta a
+ (b',msb) = rms msa b
+ in (Prod x a' b', msb)
+ Abs x b -> let (b',msb) = rms meta b in (Abs x b', msb)
+ _ -> (trm,meta)
+ minMeta = int2meta $
+ if null metas then 0 else (maximum (map metaSymbInt metas) + 1)
+
+ref2exp :: [Var] -> Type -> Ref -> Err Exp
+ref2exp bounds typ ref = do
+ cont <- contextOfType typ
+ xx0 <- mapM (typeSkeleton . snd) cont
+ let (xxs,cs) = unzip [(length hs, c) | (hs,c) <- xx0]
+ args = [mkAbs xs mExp | i <- xxs, let xs = mkFreshVars i bounds]
+ return $ mkApp ref args
+ -- no refreshment of metas
+
+-- | invariant: only 'Con' or 'Var'
+type Ref = Exp
+
+fun2wrap :: [Var] -> ((Fun,Int),Type) -> Exp -> Err Exp
+fun2wrap oldvars ((fun,i),typ) exp = do
+ cont <- contextOfType typ
+ args <- mapM mkArg (zip [0..] (map snd cont))
+ return $ mkApp (qq fun) args
+ where
+ mkArg (n,c) = do
+ cont <- contextOfType c
+ let vars = mkFreshVars (length cont) oldvars
+ return $ mkAbs vars $ if n==i then exp else mExp
+
+-- | weak heuristics: sameness of value category
+compatType :: Val -> Type -> Bool
+compatType v t = errVal True $ do
+ cat1 <- val2cat v
+ cat2 <- valCat t
+ return $ cat1 == cat2
+
+---
+
+mkJustProd :: Context -> Term -> Term
+mkJustProd cont typ = mkProd (cont,typ,[])
+
+int2var :: Int -> Ident
+int2var = zIdent . ('$':) . show
+
+meta0 :: Meta
+meta0 = int2meta 0
+
+termMeta0 :: Term
+termMeta0 = Meta meta0
+
+identVar :: Term -> Err Ident
+identVar (Vr x) = return x
+identVar _ = Bad "not a variable"
+
+
+-- | light-weight rename for user interaction; also change names of internal vars
+qualifTerm :: Ident -> Term -> Term
+qualifTerm m = qualif [] where
+ qualif xs t = case t of
+ Abs x b -> let x' = chV x in Abs x' $ qualif (x':xs) b
+ Prod x a b -> Prod x (qualif xs a) $ qualif (x:xs) b
+ Vr x -> let x' = chV x in if (elem x' xs) then (Vr x') else (Q m x)
+ Cn c -> Q m c
+ Con c -> QC m c
+ _ -> composSafeOp (qualif xs) t
+ chV x = string2var $ prIdent x
+
+string2var :: String -> Ident
+string2var s = case s of
+ c:'_':i -> identV (readIntArg i,[c]) ---
+ _ -> zIdent s
+
+-- | reindex variables so that they tell nesting depth level
+reindexTerm :: Term -> Term
+reindexTerm = qualif (0,[]) where
+ qualif dg@(d,g) t = case t of
+ Abs x b -> let x' = ind x d in Abs x' $ qualif (d+1, (x,x'):g) b
+ Prod x a b -> let x' = ind x d in Prod x' (qualif dg a) $ qualif (d+1, (x,x'):g) b
+ Vr x -> Vr $ look x g
+ _ -> composSafeOp (qualif dg) t
+ look x = maybe x id . lookup x --- if x is not in scope it is unchanged
+ ind x d = identC $ prIdent x ++ "_" ++ show d
+
+
+-- this method works for context-free abstract syntax
+-- and is meant to be used in simple embedded GF applications
+
+exp2tree :: Exp -> Err Tree
+exp2tree e = do
+ (bs,f,xs) <- termForm e
+ cont <- case bs of
+ [] -> return []
+ _ -> prtBad "cannot convert bindings in" e
+ at <- case f of
+ Q m c -> return $ AtC (m,c)
+ QC m c -> return $ AtC (m,c)
+ Meta m -> return $ AtM m
+ K s -> return $ AtL s
+ EInt n -> return $ AtI n
+ EFloat n -> return $ AtF n
+ _ -> prtBad "cannot convert to atom" f
+ ts <- mapM exp2tree xs
+ return $ Tr (N (cont,at,uVal,([],[]),True),ts)
diff --git a/src-3.0/GF/Grammar/Macros.hs b/src-3.0/GF/Grammar/Macros.hs
new file mode 100644
index 000000000..7a48e7c3a
--- /dev/null
+++ b/src-3.0/GF/Grammar/Macros.hs
@@ -0,0 +1,814 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Macros
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/11/11 16:38:00 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.24 $
+--
+-- Macros for constructing and analysing source code terms.
+--
+-- operations on terms and types not involving lookup in or reference to grammars
+--
+-- AR 7\/12\/1999 - 9\/5\/2000 -- 4\/6\/2001
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Macros where
+
+import GF.Data.Operations
+import GF.Data.Str
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.PrGrammar
+
+import Control.Monad (liftM, liftM2)
+import Data.Char (isDigit)
+
+firstTypeForm :: Type -> Err (Context, Type)
+firstTypeForm t = case t of
+ Prod x a b -> do
+ (x', val) <- firstTypeForm b
+ return ((x,a):x',val)
+ _ -> return ([],t)
+
+qTypeForm :: Type -> Err (Context, Cat, [Term])
+qTypeForm t = case t of
+ Prod x a b -> do
+ (x', cat, args) <- qTypeForm b
+ return ((x,a):x', cat, args)
+ App c a -> do
+ (_,cat, args) <- qTypeForm c
+ return ([],cat,args ++ [a])
+ Q m c ->
+ return ([],(m,c),[])
+ QC m c ->
+ return ([],(m,c),[])
+ _ ->
+ prtBad "no normal form of type" t
+
+qq :: QIdent -> Term
+qq (m,c) = Q m c
+
+typeForm :: Type -> Err (Context, Cat, [Term])
+typeForm = qTypeForm ---- no need to distinguish any more
+
+cPredef :: Ident
+cPredef = identC "Predef"
+
+cnPredef :: String -> Term
+cnPredef f = Q cPredef (identC f)
+
+typeFormCnc :: Type -> Err (Context, Type)
+typeFormCnc t = case t of
+ Prod x a b -> do
+ (x', v) <- typeFormCnc b
+ return ((x,a):x',v)
+ _ -> return ([],t)
+
+valCat :: Type -> Err Cat
+valCat typ =
+ do (_,cat,_) <- typeForm typ
+ return cat
+
+valType :: Type -> Err Type
+valType typ =
+ do (_,cat,xx) <- typeForm typ --- not optimal to do in this way
+ return $ mkApp (qq cat) xx
+
+valTypeCnc :: Type -> Err Type
+valTypeCnc typ =
+ do (_,ty) <- typeFormCnc typ
+ return ty
+
+typeRawSkeleton :: Type -> Err ([(Int,Type)],Type)
+typeRawSkeleton typ =
+ do (cont,typ) <- typeFormCnc typ
+ args <- mapM (typeRawSkeleton . snd) cont
+ return ([(length c, v) | (c,v) <- args], typ)
+
+type MCat = (Ident,Ident)
+
+sortMCat :: String -> MCat
+sortMCat s = (zIdent "_", zIdent s)
+
+--- hack for Editing.actCat in empty state
+errorCat :: MCat
+errorCat = (zIdent "?", zIdent "?")
+
+getMCat :: Term -> Err MCat
+getMCat t = case t of
+ Q m c -> return (m,c)
+ QC m c -> return (m,c)
+ Sort s -> return $ sortMCat s
+ App f _ -> getMCat f
+ _ -> prtBad "no qualified constant" t
+
+typeSkeleton :: Type -> Err ([(Int,MCat)],MCat)
+typeSkeleton typ = do
+ (cont,val) <- typeRawSkeleton typ
+ cont' <- mapPairsM getMCat cont
+ val' <- getMCat val
+ return (cont',val')
+
+catSkeleton :: Type -> Err ([MCat],MCat)
+catSkeleton typ =
+ do (args,val) <- typeSkeleton typ
+ return (map snd args, val)
+
+funsToAndFrom :: Type -> (MCat, [(MCat,[Int])])
+funsToAndFrom t = errVal undefined $ do ---
+ (cs,v) <- catSkeleton t
+ let cis = zip cs [0..]
+ return $ (v, [(c,[i | (c',i) <- cis, c' == c]) | c <- cs])
+
+typeFormConcrete :: Type -> Err (Context, Type)
+typeFormConcrete t = case t of
+ Prod x a b -> do
+ (x', typ) <- typeFormConcrete b
+ return ((x,a):x', typ)
+ _ -> return ([],t)
+
+isRecursiveType :: Type -> Bool
+isRecursiveType t = errVal False $ do
+ (cc,c) <- catSkeleton t -- thus recursivity on Cat level
+ return $ any (== c) cc
+
+isHigherOrderType :: Type -> Bool
+isHigherOrderType t = errVal True $ do -- pessimistic choice
+ co <- contextOfType t
+ return $ not $ null [x | (x,Prod _ _ _) <- co]
+
+contextOfType :: Type -> Err Context
+contextOfType typ = case typ of
+ Prod x a b -> liftM ((x,a):) $ contextOfType b
+ _ -> return []
+
+unComputed :: Term -> Term
+unComputed t = case t of
+ Computed v -> unComputed v
+ _ -> t --- composSafeOp unComputed t
+
+
+{-
+--- defined (better) in compile/PrOld
+
+stripTerm :: Term -> Term
+stripTerm t = case t of
+ Q _ c -> Cn c
+ QC _ c -> Cn c
+ T ti psts -> T ti [(stripPatt p, stripTerm v) | (p,v) <- psts]
+ _ -> composSafeOp stripTerm t
+ where
+ stripPatt p = errVal p $ term2patt $ stripTerm $ patt2term p
+-}
+
+computed :: Term -> Term
+computed = Computed
+
+termForm :: Term -> Err ([(Ident)], Term, [Term])
+termForm t = case t of
+ Abs x b ->
+ do (x', fun, args) <- termForm b
+ return (x:x', fun, args)
+ App c a ->
+ do (_,fun, args) <- termForm c
+ return ([],fun,args ++ [a])
+ _ ->
+ return ([],t,[])
+
+termFormCnc :: Term -> ([(Ident)], Term)
+termFormCnc t = case t of
+ Abs x b -> (x:xs, t') where (xs,t') = termFormCnc b
+ _ -> ([],t)
+
+appForm :: Term -> (Term, [Term])
+appForm t = case t of
+ App c a -> (fun, args ++ [a]) where (fun, args) = appForm c
+ _ -> (t,[])
+
+varsOfType :: Type -> [Ident]
+varsOfType t = case t of
+ Prod x _ b -> x : varsOfType b
+ _ -> []
+
+mkProdSimple :: Context -> Term -> Term
+mkProdSimple c t = mkProd (c,t,[])
+
+mkProd :: (Context, Term, [Term]) -> Term
+mkProd ([],typ,args) = mkApp typ args
+mkProd ((x,a):dd, typ, args) = Prod x a (mkProd (dd, typ, args))
+
+mkTerm :: ([(Ident)], Term, [Term]) -> Term
+mkTerm (xx,t,aa) = mkAbs xx (mkApp t aa)
+
+mkApp :: Term -> [Term] -> Term
+mkApp = foldl App
+
+mkAbs :: [Ident] -> Term -> Term
+mkAbs xx t = foldr Abs t xx
+
+appCons :: Ident -> [Term] -> Term
+appCons = mkApp . Cn
+
+appc :: String -> [Term] -> Term
+appc = appCons . zIdent
+
+appqc :: String -> String -> [Term] -> Term
+appqc q c = mkApp (Q (zIdent q) (zIdent c))
+
+mkLet :: [LocalDef] -> Term -> Term
+mkLet defs t = foldr Let t defs
+
+mkLetUntyped :: Context -> Term -> Term
+mkLetUntyped defs = mkLet [(x,(Nothing,t)) | (x,t) <- defs]
+
+isVariable :: Term -> Bool
+isVariable (Vr _ ) = True
+isVariable _ = False
+
+eqIdent :: Ident -> Ident -> Bool
+eqIdent = (==)
+
+zIdent :: String -> Ident
+zIdent s = identC s
+
+uType :: Type
+uType = Cn (zIdent "UndefinedType")
+
+assign :: Label -> Term -> Assign
+assign l t = (l,(Nothing,t))
+
+assignT :: Label -> Type -> Term -> Assign
+assignT l a t = (l,(Just a,t))
+
+unzipR :: [Assign] -> ([Label],[Term])
+unzipR r = (ls, map snd ts) where (ls,ts) = unzip r
+
+mkAssign :: [(Label,Term)] -> [Assign]
+mkAssign lts = [assign l t | (l,t) <- lts]
+
+zipAssign :: [Label] -> [Term] -> [Assign]
+zipAssign ls ts = [assign l t | (l,t) <- zip ls ts]
+
+ident2label :: Ident -> Label
+ident2label c = LIdent (prIdent c)
+
+label2ident :: Label -> Ident
+label2ident = identC . prLabel
+
+prLabel :: Label -> String
+prLabel = prt
+
+mapAssignM :: Monad m => (Term -> m c) -> [Assign] -> m [(Label,(Maybe c,c))]
+mapAssignM f = mapM (\ (ls,tv) -> liftM ((,) ls) (g tv))
+ where g (t,v) = liftM2 (,) (maybe (return Nothing) (liftM Just . f) t) (f v)
+
+mkRecordN :: Int -> (Int -> Label) -> [Term] -> Term
+mkRecordN int lab typs = R [ assign (lab i) t | (i,t) <- zip [int..] typs]
+
+mkRecord :: (Int -> Label) -> [Term] -> Term
+mkRecord = mkRecordN 0
+
+mkRecTypeN :: Int -> (Int -> Label) -> [Type] -> Type
+mkRecTypeN int lab typs = RecType [ (lab i, t) | (i,t) <- zip [int..] typs]
+
+mkRecType :: (Int -> Label) -> [Type] -> Type
+mkRecType = mkRecTypeN 0
+
+record2subst :: Term -> Err Substitution
+record2subst t = case t of
+ R fs -> return [(zIdent x, t) | (LIdent x,(_,t)) <- fs]
+ _ -> prtBad "record expected, found" t
+
+typeType, typePType, typeStr, typeTok, typeStrs :: Term
+
+typeType = srt "Type"
+typePType = srt "PType"
+typeStr = srt "Str"
+typeTok = srt "Tok"
+typeStrs = srt "Strs"
+
+typeString, typeFloat, typeInt :: Term
+typeInts :: Integer -> Term
+
+typeString = constPredefRes "String"
+typeInt = constPredefRes "Int"
+typeFloat = constPredefRes "Float"
+typeInts i = App (constPredefRes "Ints") (EInt i)
+
+isTypeInts :: Term -> Bool
+isTypeInts ty = case ty of
+ App c _ -> c == constPredefRes "Ints"
+ _ -> False
+
+constPredefRes :: String -> Term
+constPredefRes s = Q (IC "Predef") (zIdent s)
+
+isPredefConstant :: Term -> Bool
+isPredefConstant t = case t of
+ Q (IC "Predef") _ -> True
+ Q (IC "PredefAbs") _ -> True
+ _ -> False
+
+isPredefAbsType :: Ident -> Bool
+isPredefAbsType c = elem c [zIdent "Int", zIdent "String"]
+
+mkSelects :: Term -> [Term] -> Term
+mkSelects t tt = foldl S t tt
+
+mkTable :: [Term] -> Term -> Term
+mkTable tt t = foldr Table t tt
+
+mkCTable :: [Ident] -> Term -> Term
+mkCTable ids v = foldr ccase v ids where
+ ccase x t = T TRaw [(PV x,t)]
+
+mkDecl :: Term -> Decl
+mkDecl typ = (wildIdent, typ)
+
+eqStrIdent :: Ident -> Ident -> Bool
+eqStrIdent = (==)
+
+tupleLabel, linLabel :: Int -> Label
+tupleLabel i = LIdent $ "p" ++ show i
+linLabel i = LIdent $ "s" ++ show i
+
+theLinLabel :: Label
+theLinLabel = LIdent "s"
+
+tuple2record :: [Term] -> [Assign]
+tuple2record ts = [assign (tupleLabel i) t | (i,t) <- zip [1..] ts]
+
+tuple2recordType :: [Term] -> [Labelling]
+tuple2recordType ts = [(tupleLabel i, t) | (i,t) <- zip [1..] ts]
+
+tuple2recordPatt :: [Patt] -> [(Label,Patt)]
+tuple2recordPatt ts = [(tupleLabel i, t) | (i,t) <- zip [1..] ts]
+
+mkCases :: Ident -> Term -> Term
+mkCases x t = T TRaw [(PV x, t)]
+
+mkWildCases :: Term -> Term
+mkWildCases = mkCases wildIdent
+
+mkFunType :: [Type] -> Type -> Type
+mkFunType tt t = mkProd ([(wildIdent, ty) | ty <- tt], t, []) -- nondep prod
+
+plusRecType :: Type -> Type -> Err Type
+plusRecType t1 t2 = case (unComputed t1, unComputed t2) of
+ (RecType r1, RecType r2) -> case
+ filter (`elem` (map fst r1)) (map fst r2) of
+ [] -> return (RecType (r1 ++ r2))
+ ls -> Bad $ "clashing labels" +++ unwords (map prt ls)
+ _ -> Bad ("cannot add record types" +++ prt t1 +++ "and" +++ prt t2)
+
+plusRecord :: Term -> Term -> Err Term
+plusRecord t1 t2 =
+ case (t1,t2) of
+ (R r1, R r2 ) -> return (R ([(l,v) | -- overshadowing of old fields
+ (l,v) <- r1, not (elem l (map fst r2)) ] ++ r2))
+ (_, FV rs) -> mapM (plusRecord t1) rs >>= return . FV
+ (FV rs,_ ) -> mapM (`plusRecord` t2) rs >>= return . FV
+ _ -> Bad ("cannot add records" +++ prt t1 +++ "and" +++ prt t2)
+
+-- | default linearization type
+defLinType :: Type
+defLinType = RecType [(LIdent "s", typeStr)]
+
+-- | refreshing variables
+varX :: Int -> Ident
+varX i = identV (i,"x")
+
+-- | refreshing variables
+mkFreshVar :: [Ident] -> Ident
+mkFreshVar olds = varX (maxVarIndex olds + 1)
+
+-- | trying to preserve a given symbol
+mkFreshVarX :: [Ident] -> Ident -> Ident
+mkFreshVarX olds x = if (elem x olds) then (varX (maxVarIndex olds + 1)) else x
+
+maxVarIndex :: [Ident] -> Int
+maxVarIndex = maximum . ((-1):) . map varIndex
+
+mkFreshVars :: Int -> [Ident] -> [Ident]
+mkFreshVars n olds = [varX (maxVarIndex olds + i) | i <- [1..n]]
+
+-- | quick hack for refining with var in editor
+freshAsTerm :: String -> Term
+freshAsTerm s = Vr (varX (readIntArg s))
+
+-- | create a terminal for concrete syntax
+string2term :: String -> Term
+string2term = K
+
+int2term :: Integer -> Term
+int2term = EInt
+
+float2term :: Double -> Term
+float2term = EFloat
+
+-- | create a terminal from identifier
+ident2terminal :: Ident -> Term
+ident2terminal = K . prIdent
+
+-- | create a constant
+string2CnTrm :: String -> Term
+string2CnTrm = Cn . zIdent
+
+symbolOfIdent :: Ident -> String
+symbolOfIdent = prIdent
+
+symid :: Ident -> String
+symid = symbolOfIdent
+
+vr :: Ident -> Term
+cn :: Ident -> Term
+srt :: String -> Term
+meta :: MetaSymb -> Term
+cnIC :: String -> Term
+
+vr = Vr
+cn = Cn
+srt = Sort
+meta = Meta
+cnIC = cn . IC
+
+justIdentOf :: Term -> Maybe Ident
+justIdentOf (Vr x) = Just x
+justIdentOf (Cn x) = Just x
+justIdentOf _ = Nothing
+
+isMeta :: Term -> Bool
+isMeta (Meta _) = True
+isMeta _ = False
+
+mkMeta :: Int -> Term
+mkMeta = Meta . MetaSymb
+
+nextMeta :: MetaSymb -> MetaSymb
+nextMeta = int2meta . succ . metaSymbInt
+
+int2meta :: Int -> MetaSymb
+int2meta = MetaSymb
+
+metaSymbInt :: MetaSymb -> Int
+metaSymbInt (MetaSymb k) = k
+
+freshMeta :: [MetaSymb] -> MetaSymb
+freshMeta ms = MetaSymb (minimum [n | n <- [0..length ms],
+ notElem n (map metaSymbInt ms)])
+
+mkFreshMetasInTrm :: [MetaSymb] -> Trm -> Trm
+mkFreshMetasInTrm metas = fst . rms minMeta where
+ rms meta trm = case trm of
+ Meta m -> (Meta (MetaSymb meta), meta + 1)
+ App f a -> let (f',msf) = rms meta f
+ (a',msa) = rms msf a
+ in (App f' a', msa)
+ Prod x a b ->
+ let (a',msa) = rms meta a
+ (b',msb) = rms msa b
+ in (Prod x a' b', msb)
+ Abs x b -> let (b',msb) = rms meta b in (Abs x b', msb)
+ _ -> (trm,meta)
+ minMeta = if null metas then 0 else (maximum (map metaSymbInt metas) + 1)
+
+-- | decides that a term has no metavariables
+isCompleteTerm :: Term -> Bool
+isCompleteTerm t = case t of
+ Meta _ -> False
+ Abs _ b -> isCompleteTerm b
+ App f a -> isCompleteTerm f && isCompleteTerm a
+ _ -> True
+
+linTypeStr :: Type
+linTypeStr = mkRecType linLabel [typeStr] -- default lintype {s :: Str}
+
+linAsStr :: String -> Term
+linAsStr s = mkRecord linLabel [K s] -- default linearization {s = s}
+
+linDefStr :: Term
+linDefStr = Abs s (R [assign (linLabel 0) (Vr s)]) where s = zIdent "s"
+
+term2patt :: Term -> Err Patt
+term2patt trm = case termForm trm of
+ Ok ([], Vr x, []) -> return (PV x)
+ Ok ([], Val ty x, []) -> return (PVal ty x)
+ Ok ([], Con c, aa) -> do
+ aa' <- mapM term2patt aa
+ return (PC c aa')
+ Ok ([], QC p c, aa) -> do
+ aa' <- mapM term2patt aa
+ return (PP p c aa')
+
+ Ok ([], Q p c, []) -> do
+ return (PM p c)
+
+ Ok ([], R r, []) -> do
+ let (ll,aa) = unzipR r
+ aa' <- mapM term2patt aa
+ return (PR (zip ll aa'))
+ Ok ([],EInt i,[]) -> return $ PInt i
+ Ok ([],EFloat i,[]) -> return $ PFloat i
+ Ok ([],K s, []) -> return $ PString s
+
+--- encodings due to excessive use of term-patt convs. AR 7/1/2005
+ Ok ([], Cn (IC "@"), [Vr a,b]) -> do
+ b' <- term2patt b
+ return (PAs a b')
+ Ok ([], Cn (IC "-"), [a]) -> do
+ a' <- term2patt a
+ return (PNeg a')
+ Ok ([], Cn (IC "*"), [a]) -> do
+ a' <- term2patt a
+ return (PRep a')
+ Ok ([], Cn (IC "?"), []) -> do
+ return PChar
+ Ok ([], Cn (IC "[]"),[K s]) -> do
+ return $ PChars s
+ Ok ([], Cn (IC "+"), [a,b]) -> do
+ a' <- term2patt a
+ b' <- term2patt b
+ return (PSeq a' b')
+ Ok ([], Cn (IC "|"), [a,b]) -> do
+ a' <- term2patt a
+ b' <- term2patt b
+ return (PAlt a' b')
+
+ Ok ([], Cn c, []) -> do
+ return (PMacro c)
+
+ _ -> prtBad "no pattern corresponds to term" trm
+
+patt2term :: Patt -> Term
+patt2term pt = case pt of
+ PV x -> Vr x
+ PW -> Vr wildIdent --- not parsable, should not occur
+ PVal t i -> Val t i
+ PMacro c -> Cn c
+ PM p c -> Q p c
+
+ PC c pp -> mkApp (Con c) (map patt2term pp)
+ PP p c pp -> mkApp (QC p c) (map patt2term pp)
+
+ PR r -> R [assign l (patt2term p) | (l,p) <- r]
+ PT _ p -> patt2term p
+ PInt i -> EInt i
+ PFloat i -> EFloat i
+ PString s -> K s
+
+ PAs x p -> appc "@" [Vr x, patt2term p] --- an encoding
+ PChar -> appc "?" [] --- an encoding
+ PChars s -> appc "[]" [K s] --- an encoding
+ PSeq a b -> appc "+" [(patt2term a), (patt2term b)] --- an encoding
+ PAlt a b -> appc "|" [(patt2term a), (patt2term b)] --- an encoding
+ PRep a -> appc "*" [(patt2term a)] --- an encoding
+ PNeg a -> appc "-" [(patt2term a)] --- an encoding
+
+
+redirectTerm :: Ident -> Term -> Term
+redirectTerm n t = case t of
+ QC _ f -> QC n f
+ Q _ f -> Q n f
+ _ -> composSafeOp (redirectTerm n) t
+
+-- | to gather s-fields; assumes term in normal form, preserves label
+allLinFields :: Term -> Err [[(Label,Term)]]
+allLinFields trm = case unComputed trm of
+---- R rs -> return [[(l,t) | (l,(Just ty,t)) <- rs, isStrType ty]] -- good
+ R rs -> return [[(l,t) | (l,(_,t)) <- rs, isLinLabel l]] ---- bad
+ FV ts -> do
+ lts <- mapM allLinFields ts
+ return $ concat lts
+ _ -> prtBad "fields can only be sought in a record not in" trm
+
+-- | deprecated
+isLinLabel :: Label -> Bool
+isLinLabel l = case l of
+ LIdent ('s':cs) | all isDigit cs -> True
+ _ -> False
+
+-- | to gather ultimate cases in a table; preserves pattern list
+allCaseValues :: Term -> [([Patt],Term)]
+allCaseValues trm = case unComputed trm of
+ T _ cs -> [(p:ps, t) | (p,t0) <- cs, (ps,t) <- allCaseValues t0]
+ _ -> [([],trm)]
+
+-- | to gather all linearizations; assumes normal form, preserves label and args
+allLinValues :: Term -> Err [[(Label,[([Patt],Term)])]]
+allLinValues trm = do
+ lts <- allLinFields trm
+ mapM (mapPairsM (return . allCaseValues)) lts
+
+-- | to mark str parts of fields in a record f by a function f
+markLinFields :: (Term -> Term) -> Term -> Term
+markLinFields f t = case t of
+ R r -> R $ map mkField r
+ _ -> t
+ where
+ mkField (l,(_,t)) = if (isLinLabel l) then (assign l (mkTbl t)) else (assign l t)
+ mkTbl t = case t of
+ T i cs -> T i [(p, mkTbl v) | (p,v) <- cs]
+ _ -> f t
+
+-- | to get a string from a term that represents a sequence of terminals
+strsFromTerm :: Term -> Err [Str]
+strsFromTerm t = case unComputed t of
+ K s -> return [str s]
+ Empty -> return [str []]
+ C s t -> do
+ s' <- strsFromTerm s
+ t' <- strsFromTerm t
+ return [plusStr x y | x <- s', y <- t']
+ Glue s t -> do
+ s' <- strsFromTerm s
+ t' <- strsFromTerm t
+ return [glueStr x y | x <- s', y <- t']
+ Alts (d,vs) -> do
+ d0 <- strsFromTerm d
+ v0 <- mapM (strsFromTerm . fst) vs
+ c0 <- mapM (strsFromTerm . snd) vs
+ let vs' = zip v0 c0
+ return [strTok (str2strings def) vars |
+ def <- d0,
+ vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
+ vv <- combinations v0]
+ ]
+ FV ts -> mapM strsFromTerm ts >>= return . concat
+ Strs ts -> mapM strsFromTerm ts >>= return . concat
+ Ready ss -> return [ss]
+ Alias _ _ d -> strsFromTerm d --- should not be needed...
+ _ -> prtBad "cannot get Str from term" t
+
+-- | to print an Str-denoting term as a string; if the term is of wrong type, the error msg
+stringFromTerm :: Term -> String
+stringFromTerm = err id (ifNull "" (sstr . head)) . strsFromTerm
+
+
+-- | to define compositional term functions
+composSafeOp :: (Term -> Term) -> Term -> Term
+composSafeOp op trm = case composOp (mkMonadic op) trm of
+ Ok t -> t
+ _ -> error "the operation is safe isn't it ?"
+ where
+ mkMonadic f = return . f
+
+-- | to define compositional term functions
+composOp :: Monad m => (Term -> m Term) -> Term -> m Term
+composOp co trm =
+ case trm of
+ App c a ->
+ do c' <- co c
+ a' <- co a
+ return (App c' a')
+ Abs x b ->
+ do b' <- co b
+ return (Abs x b')
+ Prod x a b ->
+ do a' <- co a
+ b' <- co b
+ return (Prod x a' b')
+ S c a ->
+ do c' <- co c
+ a' <- co a
+ return (S c' a')
+ Table a c ->
+ do a' <- co a
+ c' <- co c
+ return (Table a' c')
+ R r ->
+ do r' <- mapAssignM co r
+ return (R r')
+ RecType r ->
+ do r' <- mapPairListM (co . snd) r
+ return (RecType r')
+ P t i ->
+ do t' <- co t
+ return (P t' i)
+ PI t i j ->
+ do t' <- co t
+ return (PI t' i j)
+ ExtR a c ->
+ do a' <- co a
+ c' <- co c
+ return (ExtR a' c')
+
+ T i cc ->
+ do cc' <- mapPairListM (co . snd) cc
+ i' <- changeTableType co i
+ return (T i' cc')
+
+ TSh i cc ->
+ do cc' <- mapPairListM (co . snd) cc
+ i' <- changeTableType co i
+ return (TSh i' cc')
+
+ Eqs cc ->
+ do cc' <- mapPairListM (co . snd) cc
+ return (Eqs cc')
+
+ V ty vs ->
+ do ty' <- co ty
+ vs' <- mapM co vs
+ return (V ty' vs')
+
+ Val ty i ->
+ do ty' <- co ty
+ return (Val ty' i)
+
+ Let (x,(mt,a)) b ->
+ do a' <- co a
+ mt' <- case mt of
+ Just t -> co t >>= (return . Just)
+ _ -> return mt
+ b' <- co b
+ return (Let (x,(mt',a')) b')
+ Alias c ty d ->
+ do v <- co d
+ ty' <- co ty
+ return $ Alias c ty' v
+ C s1 s2 ->
+ do v1 <- co s1
+ v2 <- co s2
+ return (C v1 v2)
+ Glue s1 s2 ->
+ do v1 <- co s1
+ v2 <- co s2
+ return (Glue v1 v2)
+ Alts (t,aa) ->
+ do t' <- co t
+ aa' <- mapM (pairM co) aa
+ return (Alts (t',aa'))
+ FV ts -> mapM co ts >>= return . FV
+ Strs tt -> mapM co tt >>= return . Strs
+
+ EPattType ty ->
+ do ty' <- co ty
+ return (EPattType ty')
+
+ _ -> return trm -- covers K, Vr, Cn, Sort, EPatt
+
+getTableType :: TInfo -> Err Type
+getTableType i = case i of
+ TTyped ty -> return ty
+ TComp ty -> return ty
+ TWild ty -> return ty
+ _ -> Bad "the table is untyped"
+
+changeTableType :: Monad m => (Type -> m Type) -> TInfo -> m TInfo
+changeTableType co i = case i of
+ TTyped ty -> co ty >>= return . TTyped
+ TComp ty -> co ty >>= return . TComp
+ TWild ty -> co ty >>= return . TWild
+ _ -> return i
+
+collectOp :: (Term -> [a]) -> Term -> [a]
+collectOp co trm = case trm of
+ App c a -> co c ++ co a
+ Abs _ b -> co b
+ Prod _ a b -> co a ++ co b
+ S c a -> co c ++ co a
+ Table a c -> co a ++ co c
+ ExtR a c -> co a ++ co c
+ R r -> concatMap (\ (_,(mt,a)) -> maybe [] co mt ++ co a) r
+ RecType r -> concatMap (co . snd) r
+ P t i -> co t
+ T _ cc -> concatMap (co . snd) cc -- not from patterns --- nor from type annot
+ TSh _ cc -> concatMap (co . snd) cc -- not from patterns --- nor from type annot
+ V _ cc -> concatMap co cc --- nor from type annot
+ Let (x,(mt,a)) b -> maybe [] co mt ++ co a ++ co b
+ C s1 s2 -> co s1 ++ co s2
+ Glue s1 s2 -> co s1 ++ co s2
+ Alts (t,aa) -> let (x,y) = unzip aa in co t ++ concatMap co (x ++ y)
+ FV ts -> concatMap co ts
+ Strs tt -> concatMap co tt
+ _ -> [] -- covers K, Vr, Cn, Sort, Ready
+
+-- | to find the word items in a term
+wordsInTerm :: Term -> [String]
+wordsInTerm trm = filter (not . null) $ case trm of
+ K s -> [s]
+ S c _ -> wo c
+ Alts (t,aa) -> wo t ++ concatMap (wo . fst) aa
+ Ready s -> allItems s
+ _ -> collectOp wo trm
+ where wo = wordsInTerm
+
+noExist :: Term
+noExist = FV []
+
+defaultLinType :: Type
+defaultLinType = mkRecType linLabel [typeStr]
+
+metaTerms :: [Term]
+metaTerms = map (Meta . MetaSymb) [0..]
+
+-- | from GF1, 20\/9\/2003
+isInOneType :: Type -> Bool
+isInOneType t = case t of
+ Prod _ a b -> a == b
+ _ -> False
+
diff --git a/src-3.0/GF/Grammar/PatternMatch.hs b/src-3.0/GF/Grammar/PatternMatch.hs
new file mode 100644
index 000000000..b96d35b93
--- /dev/null
+++ b/src-3.0/GF/Grammar/PatternMatch.hs
@@ -0,0 +1,155 @@
+----------------------------------------------------------------------
+-- |
+-- Module : PatternMatch
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/10/12 12:38:29 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.7 $
+--
+-- pattern matching for both concrete and abstract syntax. AR -- 16\/6\/2003
+-----------------------------------------------------------------------------
+
+module GF.Grammar.PatternMatch (matchPattern,
+ testOvershadow,
+ findMatch
+ ) where
+
+import GF.Data.Operations
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Grammar.Macros
+import GF.Grammar.PrGrammar
+
+import Data.List
+import Control.Monad
+
+
+matchPattern :: [(Patt,Term)] -> Term -> Err (Term, Substitution)
+matchPattern pts term =
+ if not (isInConstantForm term)
+ then prtBad "variables occur in" term
+ else
+ errIn ("trying patterns" +++ unwords (intersperse "," (map (prt . fst) pts))) $
+ findMatch [([p],t) | (p,t) <- pts] [term]
+
+testOvershadow :: [Patt] -> [Term] -> Err [Patt]
+testOvershadow pts vs = do
+ let numpts = zip pts [0..]
+ let cases = [(p,EInt i) | (p,i) <- numpts]
+ ts <- mapM (liftM fst . matchPattern cases) vs
+ return $ [p | (p,i) <- numpts, notElem i [i | EInt i <- ts] ]
+
+findMatch :: [([Patt],Term)] -> [Term] -> Err (Term, Substitution)
+findMatch cases terms = case cases of
+ [] -> Bad $"no applicable case for" +++ unwords (intersperse "," (map prt terms))
+ (patts,_):_ | length patts /= length terms ->
+ Bad ("wrong number of args for patterns :" +++
+ unwords (map prt patts) +++ "cannot take" +++ unwords (map prt terms))
+ (patts,val):cc -> case mapM tryMatch (zip patts terms) of
+ Ok substs -> return (val, concat substs)
+ _ -> findMatch cc terms
+
+tryMatch :: (Patt, Term) -> Err [(Ident, Term)]
+tryMatch (p,t) = do
+ t' <- termForm t
+ trym p t'
+ where
+ isInConstantFormt = True -- tested already
+ trym p t' =
+ case (p,t') of
+ (PVal _ i, (_,Val _ j,_))
+ | i == j -> return []
+ | otherwise -> Bad $ "no match of values"
+ (_,(x,Empty,y)) -> trym p (x,K [],y) -- because "" = [""] = []
+ (PV IW, _) | isInConstantFormt -> return [] -- optimization with wildcard
+ (PV x, _) | isInConstantFormt -> return [(x,t)]
+ (PString s, ([],K i,[])) | s==i -> return []
+ (PInt s, ([],EInt i,[])) | s==i -> return []
+ (PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
+ (PC p pp, ([], Con f, tt)) |
+ p `eqStrIdent` f && length pp == length tt ->
+ do matches <- mapM tryMatch (zip pp tt)
+ return (concat matches)
+
+ (PP q p pp, ([], QC r f, tt)) |
+ -- q `eqStrIdent` r && --- not for inherited AR 10/10/2005
+ p `eqStrIdent` f && length pp == length tt ->
+ do matches <- mapM tryMatch (zip pp tt)
+ return (concat matches)
+ ---- hack for AppPredef bug
+ (PP q p pp, ([], Q r f, tt)) |
+ -- q `eqStrIdent` r && ---
+ p `eqStrIdent` f && length pp == length tt ->
+ do matches <- mapM tryMatch (zip pp tt)
+ return (concat matches)
+
+ (PR r, ([],R r',[])) |
+ all (`elem` map fst r') (map fst r) ->
+ do matches <- mapM tryMatch
+ [(p,snd a) | (l,p) <- r, let Just a = lookup l r']
+ return (concat matches)
+ (PT _ p',_) -> trym p' t'
+ (_, ([],Alias _ _ d,[])) -> tryMatch (p,d)
+
+-- (PP (IC "Predef") (IC "CC") [p1,p2], ([],K s, [])) -> do
+
+ (PAs x p',_) -> do
+ subst <- trym p' t'
+ return $ (x,t) : subst
+
+ (PAlt p1 p2,_) -> checks [trym p1 t', trym p2 t']
+
+ (PNeg p',_) -> case tryMatch (p',t) of
+ Bad _ -> return []
+ _ -> prtBad "no match with negative pattern" p
+
+ (PSeq p1 p2, ([],K s, [])) -> do
+ let cuts = [splitAt n s | n <- [0 .. length s]]
+ matches <- checks [mapM tryMatch [(p1,K s1),(p2,K s2)] | (s1,s2) <- cuts]
+ return (concat matches)
+
+ (PRep p1, ([],K s, [])) -> checks [
+ trym (foldr (const (PSeq p1)) (PString "")
+ [1..n]) t' | n <- [0 .. length s]
+ ] >>
+ return []
+
+ (PChar, ([],K [_], [])) -> return []
+ (PChars cs, ([],K [c], [])) | elem c cs -> return []
+
+ _ -> prtBad "no match in case expr for" t
+
+isInConstantForm :: Term -> Bool
+isInConstantForm trm = case trm of
+ Cn _ -> True
+ Con _ -> True
+ Q _ _ -> True
+ QC _ _ -> True
+ Abs _ _ -> True
+ App c a -> isInConstantForm c && isInConstantForm a
+ R r -> all (isInConstantForm . snd . snd) r
+ K _ -> True
+ Empty -> True
+ Alias _ _ t -> isInConstantForm t
+ EInt _ -> True
+ _ -> False ---- isInArgVarForm trm
+
+varsOfPatt :: Patt -> [Ident]
+varsOfPatt p = case p of
+ PV x -> [x | not (isWildIdent x)]
+ PC _ ps -> concat $ map varsOfPatt ps
+ PP _ _ ps -> concat $ map varsOfPatt ps
+ PR r -> concat $ map (varsOfPatt . snd) r
+ PT _ q -> varsOfPatt q
+ _ -> []
+
+-- | to search matching parameter combinations in tables
+isMatchingForms :: [Patt] -> [Term] -> Bool
+isMatchingForms ps ts = all match (zip ps ts') where
+ match (PC c cs, (Cn d, ds)) = c == d && isMatchingForms cs ds
+ match _ = True
+ ts' = map appForm ts
+
diff --git a/src-3.0/GF/Grammar/PrGrammar.hs b/src-3.0/GF/Grammar/PrGrammar.hs
new file mode 100644
index 000000000..c3a21d1d6
--- /dev/null
+++ b/src-3.0/GF/Grammar/PrGrammar.hs
@@ -0,0 +1,286 @@
+----------------------------------------------------------------------
+-- |
+-- Module : PrGrammar
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/09/04 11:45:38 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.16 $
+--
+-- AR 7\/12\/1999 - 1\/4\/2000 - 10\/5\/2003
+--
+-- printing and prettyprinting class
+--
+-- 8\/1\/2004:
+-- Usually followed principle: 'prt_' for displaying in the editor, 'prt'
+-- in writing grammars to a file. For some constructs, e.g. 'prMarkedTree',
+-- only the former is ever needed.
+-----------------------------------------------------------------------------
+
+module GF.Grammar.PrGrammar (Print(..),
+ prtBad,
+ prGrammar, prModule,
+ prContext, prParam,
+ prQIdent, prQIdent_,
+ prRefinement, prTermOpt,
+ prt_Tree, prMarkedTree, prTree,
+ tree2string, prprTree,
+ prConstrs, prConstraints,
+ prMetaSubst, prEnv, prMSubst,
+ prExp, prPatt, prOperSignature,
+ lookupIdent, lookupIdentInfo
+ ) where
+
+import GF.Data.Operations
+import GF.Data.Zipper
+import GF.Grammar.Grammar
+import GF.Infra.Modules
+import qualified GF.Source.PrintGF as P
+import qualified GF.Canon.PrintGFC as C
+import qualified GF.Canon.AbsGFC as A
+import GF.Grammar.Values
+import GF.Source.GrammarToSource
+--- import GFC (CanonGrammar) --- cycle of modules
+
+import GF.Infra.Option
+import GF.Infra.Ident
+import GF.Data.Str
+
+import GF.Infra.CompactPrint
+
+import Data.List (intersperse)
+
+class Print a where
+ prt :: a -> String
+ -- | printing with parentheses, if needed
+ prt2 :: a -> String
+ -- | pretty printing
+ prpr :: a -> [String]
+ -- | printing without ident qualifications
+ prt_ :: a -> String
+ prt2 = prt
+ prt_ = prt
+ prpr = return . prt
+
+-- 8/1/2004
+--- Usually followed principle: prt_ for displaying in the editor, prt
+--- in writing grammars to a file. For some constructs, e.g. prMarkedTree,
+--- only the former is ever needed.
+
+-- | to show terms etc in error messages
+prtBad :: Print a => String -> a -> Err b
+prtBad s a = Bad (s +++ prt a)
+
+pprintTree :: P.Print a => a -> String
+pprintTree = compactPrint . P.printTree
+
+prGrammar :: SourceGrammar -> String
+prGrammar = pprintTree . trGrammar
+
+prModule :: (Ident, SourceModInfo) -> String
+prModule = pprintTree . trModule
+
+instance Print Term where
+ prt = pprintTree . trt
+ prt_ = prExp
+
+instance Print Ident where
+ prt = pprintTree . tri
+
+instance Print Patt where
+ prt = pprintTree . trp
+
+instance Print Label where
+ prt = pprintTree . trLabel
+
+instance Print MetaSymb where
+ prt (MetaSymb i) = "?" ++ show i
+
+prParam :: Param -> String
+prParam (c,co) = prt c +++ prContext co
+
+prContext :: Context -> String
+prContext co = unwords $ map prParenth [prt x +++ ":" +++ prt t | (x,t) <- co]
+
+-- some GFC notions
+
+instance Print A.Exp where prt = C.printTree
+instance Print A.Term where prt = C.printTree
+instance Print A.Case where prt = C.printTree
+instance Print A.CType where prt = C.printTree
+instance Print A.Label where prt = C.printTree
+instance Print A.Module where prt = C.printTree
+instance Print A.Def where prt = C.printTree
+instance Print A.Canon where prt = C.printTree
+instance Print A.Sort where prt = C.printTree
+
+instance Print A.Atom where
+ prt = C.printTree
+ prt_ (A.AC c) = prt_ c
+ prt_ (A.AD c) = prt_ c
+ prt_ a = prt a
+
+instance Print A.Patt where
+ prt = C.printTree
+ prt_ = prPatt
+
+instance Print A.CIdent where
+ prt = C.printTree
+ prt_ (A.CIQ _ c) = prt c
+
+-- printing values and trees in editing
+
+instance Print a => Print (Tr a) where
+ prt (Tr (n, trees)) = prt n +++ unwords (map prt2 trees)
+ prt2 t@(Tr (_,args)) = if null args then prt t else prParenth (prt t)
+
+-- | we cannot define the method prt_ in this way
+prt_Tree :: Tree -> String
+prt_Tree = prt_ . tree2exp
+
+instance Print TrNode where
+ prt (N (bi,at,vt,(cs,ms),_)) =
+ prBinds bi ++
+ prt at +++ ":" +++ prt vt
+ +++ prConstraints cs +++ prMetaSubst ms
+ prt_ (N (bi,at,vt,(cs,ms),_)) =
+ prBinds bi ++
+ prt_ at +++ ":" +++ prt_ vt
+ +++ prConstraints cs +++ prMetaSubst ms
+
+prMarkedTree :: Tr (TrNode,Bool) -> [String]
+prMarkedTree = prf 1 where
+ prf ind t@(Tr (node, trees)) =
+ prNode ind node : concatMap (prf (ind + 2)) trees
+ prNode ind node = case node of
+ (n, False) -> indent ind (prt_ n)
+ (n, _) -> '*' : indent (ind - 1) (prt_ n)
+
+prTree :: Tree -> [String]
+prTree = prMarkedTree . mapTr (\n -> (n,False))
+
+-- | a pretty-printer for parsable output
+tree2string :: Tree -> String
+tree2string = unlines . prprTree
+
+prprTree :: Tree -> [String]
+prprTree = prf False where
+ prf par t@(Tr (node, trees)) =
+ parIf par (prn node : concat [prf (ifPar t) t | t <- trees])
+ prn (N (bi,at,_,_,_)) = prb bi ++ prt_ at
+ prb [] = ""
+ prb bi = "\\" ++ concat (intersperse "," (map (prt_ . fst) bi)) ++ " -> "
+ parIf par (s:ss) = map (indent 2) $
+ if par
+ then ('(':s) : ss ++ [")"]
+ else s:ss
+ ifPar (Tr (N ([],_,_,_,_), [])) = False
+ ifPar _ = True
+
+
+-- auxiliaries
+
+prConstraints :: Constraints -> String
+prConstraints = concat . prConstrs
+
+prMetaSubst :: MetaSubst -> String
+prMetaSubst = concat . prMSubst
+
+prEnv :: Env -> String
+---- prEnv [] = prCurly "" ---- for debugging
+prEnv e = concatMap (\ (x,t) -> prCurly (prt x ++ ":=" ++ prt t)) e
+
+prConstrs :: Constraints -> [String]
+prConstrs = map (\ (v,w) -> prCurly (prt v ++ "<>" ++ prt w))
+
+prMSubst :: MetaSubst -> [String]
+prMSubst = map (\ (m,e) -> prCurly ("?" ++ show m ++ "=" ++ prt e))
+
+prBinds bi = if null bi
+ then []
+ else "\\" ++ concat (intersperse "," (map prValDecl bi)) +++ "-> "
+ where
+ prValDecl (x,t) = prParenth (prt_ x +++ ":" +++ prt_ t)
+
+instance Print Val where
+ prt (VGen i x) = prt x ++ "{-" ++ show i ++ "-}" ---- latter part for debugging
+ prt (VApp u v) = prt u +++ prv1 v
+ prt (VCn mc) = prQIdent_ mc
+ prt (VClos env e) = case e of
+ Meta _ -> prt_ e ++ prEnv env
+ _ -> prt_ e ---- ++ prEnv env ---- for debugging
+ prt VType = "Type"
+
+prv1 v = case v of
+ VApp _ _ -> prParenth $ prt v
+ VClos _ _ -> prParenth $ prt v
+ _ -> prt v
+
+instance Print Atom where
+ prt (AtC f) = prQIdent f
+ prt (AtM i) = prt i
+ prt (AtV i) = prt i
+ prt (AtL s) = prQuotedString s
+ prt (AtI i) = show i
+ prt (AtF i) = show i
+ prt_ (AtC (_,f)) = prt f
+ prt_ a = prt a
+
+prQIdent :: QIdent -> String
+prQIdent (m,f) = prt m ++ "." ++ prt f
+
+prQIdent_ :: QIdent -> String
+prQIdent_ (_,f) = prt f
+
+-- | print terms without qualifications
+prExp :: Term -> String
+prExp e = case e of
+ App f a -> pr1 f +++ pr2 a
+ Abs x b -> "\\" ++ prt x +++ "->" +++ prExp b
+ Prod x a b -> "(\\" ++ prt x +++ ":" +++ prExp a ++ ")" +++ "->" +++ prExp b
+ Q _ c -> prt c
+ QC _ c -> prt c
+ _ -> prt e
+ where
+ pr1 e = case e of
+ Abs _ _ -> prParenth $ prExp e
+ Prod _ _ _ -> prParenth $ prExp e
+ _ -> prExp e
+ pr2 e = case e of
+ App _ _ -> prParenth $ prExp e
+ _ -> pr1 e
+
+prPatt :: A.Patt -> String
+prPatt p = case p of
+ A.PC c ps -> prt_ c +++ unwords (map pr1 ps)
+ _ -> prt p --- PR
+ where
+ pr1 p = case p of
+ A.PC _ (_:_) -> prParenth $ prPatt p
+ _ -> prPatt p
+
+-- | option @-strip@ strips qualifications
+prTermOpt :: Options -> Term -> String
+prTermOpt opts = if oElem nostripQualif opts then prt else prExp
+
+-- | to get rid of brackets in the editor
+prRefinement :: Term -> String
+prRefinement t = case t of
+ Q m c -> prQIdent (m,c)
+ QC m c -> prQIdent (m,c)
+ _ -> prt t
+
+prOperSignature :: (QIdent,Type) -> String
+prOperSignature (f, t) = prQIdent f +++ ":" +++ prt t
+
+-- to look up a constant etc in a search tree
+
+lookupIdent :: Ident -> BinTree Ident b -> Err b
+lookupIdent c t = case lookupTree prt c t of
+ Ok v -> return v
+ _ -> prtBad "unknown identifier" c
+
+lookupIdentInfo :: Module Ident f a -> Ident -> Err a
+lookupIdentInfo mo i = lookupIdent i (jments mo)
diff --git a/src-3.0/GF/Grammar/Refresh.hs b/src-3.0/GF/Grammar/Refresh.hs
new file mode 100644
index 000000000..bc77c1837
--- /dev/null
+++ b/src-3.0/GF/Grammar/Refresh.hs
@@ -0,0 +1,133 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Refresh
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:22:27 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.6 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Refresh (refreshTerm, refreshTermN,
+ refreshModule
+ ) where
+
+import GF.Data.Operations
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+import GF.Infra.Modules
+import GF.Grammar.Macros
+import Control.Monad
+
+refreshTerm :: Term -> Err Term
+refreshTerm = refreshTermN 0
+
+refreshTermN :: Int -> Term -> Err Term
+refreshTermN i e = liftM snd $ refreshTermKN i e
+
+refreshTermKN :: Int -> Term -> Err (Int,Term)
+refreshTermKN i e = liftM (\ (t,(_,i)) -> (i,t)) $
+ appSTM (refresh e) (initIdStateN i)
+
+refresh :: Term -> STM IdState Term
+refresh e = case e of
+
+ Vr x -> liftM Vr (lookVar x)
+ Abs x b -> liftM2 Abs (refVarPlus x) (refresh b)
+
+ Prod x a b -> do
+ a' <- refresh a
+ x' <- refVar x
+ b' <- refresh b
+ return $ Prod x' a' b'
+
+ Let (x,(mt,a)) b -> do
+ a' <- refresh a
+ mt' <- case mt of
+ Just t -> refresh t >>= (return . Just)
+ _ -> return mt
+ x' <- refVar x
+ b' <- refresh b
+ return (Let (x',(mt',a')) b')
+
+ R r -> liftM R $ refreshRecord r
+
+ ExtR r s -> liftM2 ExtR (refresh r) (refresh s)
+
+ T i cc -> liftM2 T (refreshTInfo i) (mapM refreshCase cc)
+
+ _ -> composOp refresh e
+
+refreshCase :: (Patt,Term) -> STM IdState (Patt,Term)
+refreshCase (p,t) = liftM2 (,) (refreshPatt p) (refresh t)
+
+refreshPatt p = case p of
+ PV x -> liftM PV (refVar x)
+ PC c ps -> liftM (PC c) (mapM refreshPatt ps)
+ PP q c ps -> liftM (PP q c) (mapM refreshPatt ps)
+ PR r -> liftM PR (mapPairsM refreshPatt r)
+ PT t p' -> liftM2 PT (refresh t) (refreshPatt p')
+
+ PAs x p' -> liftM2 PAs (refVar x) (refreshPatt p')
+
+ PSeq p' q' -> liftM2 PSeq (refreshPatt p') (refreshPatt q')
+ PAlt p' q' -> liftM2 PAlt (refreshPatt p') (refreshPatt q')
+ PRep p' -> liftM PRep (refreshPatt p')
+ PNeg p' -> liftM PNeg (refreshPatt p')
+
+ _ -> return p
+
+refreshRecord r = case r of
+ [] -> return r
+ (x,(mt,a)):b -> do
+ a' <- refresh a
+ mt' <- case mt of
+ Just t -> refresh t >>= (return . Just)
+ _ -> return mt
+ b' <- refreshRecord b
+ return $ (x,(mt',a')) : b'
+
+refreshTInfo i = case i of
+ TTyped t -> liftM TTyped $ refresh t
+ TComp t -> liftM TComp $ refresh t
+ TWild t -> liftM TWild $ refresh t
+ _ -> return i
+
+-- for abstract syntax
+
+refreshEquation :: Equation -> Err ([Patt],Term)
+refreshEquation pst = err Bad (return . fst) (appSTM (refr pst) initIdState) where
+ refr (ps,t) = liftM2 (,) (mapM refreshPatt ps) (refresh t)
+
+-- for concrete and resource in grammar, before optimizing
+
+refreshGrammar :: SourceGrammar -> Err SourceGrammar
+refreshGrammar = liftM (MGrammar . snd) . foldM refreshModule (0,[]) . modules
+
+refreshModule :: (Int,[SourceModule]) -> SourceModule -> Err (Int,[SourceModule])
+refreshModule (k,ms) mi@(i,m) = case m of
+ ModMod mo@(Module mt fs st me ops js) | (isModCnc mo || isModRes mo) -> do
+ (k',js') <- foldM refreshRes (k,[]) $ tree2list js
+ return (k', (i, ModMod(Module mt fs st me ops (buildTree js'))) : ms)
+ _ -> return (k, mi:ms)
+ where
+ refreshRes (k,cs) ci@(c,info) = case info of
+ ResOper ptyp (Yes trm) -> do ---- refresh ptyp
+ (k',trm') <- refreshTermKN k trm
+ return $ (k', (c, ResOper ptyp (Yes trm')):cs)
+ ResOverload tyts -> do
+ (k',tyts') <- liftM (\ (t,(_,i)) -> (i,t)) $
+ appSTM (mapPairsM refresh tyts) (initIdStateN k)
+ return $ (k', (c, ResOverload tyts'):cs)
+ CncCat mt (Yes trm) pn -> do ---- refresh mt, pn
+ (k',trm') <- refreshTermKN k trm
+ return $ (k', (c, CncCat mt (Yes trm') pn):cs)
+ CncFun mt (Yes trm) pn -> do ---- refresh pn
+ (k',trm') <- refreshTermKN k trm
+ return $ (k', (c, CncFun mt (Yes trm') pn):cs)
+ _ -> return (k, ci:cs)
+
diff --git a/src-3.0/GF/Grammar/ReservedWords.hs b/src-3.0/GF/Grammar/ReservedWords.hs
new file mode 100644
index 000000000..b440141d6
--- /dev/null
+++ b/src-3.0/GF/Grammar/ReservedWords.hs
@@ -0,0 +1,44 @@
+----------------------------------------------------------------------
+-- |
+-- Module : ReservedWords
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:22:28 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.5 $
+--
+-- reserved words of GF. (c) Aarne Ranta 19\/3\/2002 under Gnu GPL.
+-- modified by Markus Forsberg 9\/4.
+-- modified by AR 12\/6\/2003 for GF2 and GFC
+-----------------------------------------------------------------------------
+
+module GF.Grammar.ReservedWords (isResWord, isResWordGFC) where
+
+import Data.List
+
+
+isResWord :: String -> Bool
+isResWord s = isInTree s resWordTree
+
+resWordTree :: BTree
+resWordTree =
+-- mapTree fst $ sorted2tree $ flip zip (repeat ()) $ sort allReservedWords
+-- nowadays obtained from LexGF.hs
+ B "let" (B "data" (B "Type" (B "Str" (B "PType" (B "Lin" N N) N) (B "Tok" (B "Strs" N N) N)) (B "cat" (B "case" (B "abstract" N N) N) (B "concrete" N N))) (B "in" (B "fn" (B "flags" (B "def" N N) N) (B "grammar" (B "fun" N N) N)) (B "instance" (B "incomplete" (B "include" N N) N) (B "interface" N N)))) (B "pre" (B "open" (B "lindef" (B "lincat" (B "lin" N N) N) (B "of" (B "lintype" N N) N)) (B "param" (B "out" (B "oper" N N) N) (B "pattern" N N))) (B "transfer" (B "reuse" (B "resource" (B "printname" N N) N) (B "table" (B "strs" N N) N)) (B "where" (B "variants" (B "union" N N) N) (B "with" N N))))
+
+isResWordGFC :: String -> Bool
+isResWordGFC s = isInTree s $
+ B "of" (B "fun" (B "concrete" (B "cat" (B "abstract" N N) N) (B "flags" N N)) (B "lin" (B "in" N N) (B "lincat" N N))) (B "resource" (B "param" (B "oper" (B "open" N N) N) (B "pre" N N)) (B "table" (B "strs" N N) (B "variants" N N)))
+
+data BTree = N | B String BTree BTree deriving (Show)
+
+isInTree :: String -> BTree -> Bool
+isInTree x tree = case tree of
+ N -> False
+ B a left right
+ | x < a -> isInTree x left
+ | x > a -> isInTree x right
+ | x == a -> True
+
diff --git a/src-3.0/GF/Grammar/SGrammar.hs b/src-3.0/GF/Grammar/SGrammar.hs
new file mode 100644
index 000000000..e0c001b6b
--- /dev/null
+++ b/src-3.0/GF/Grammar/SGrammar.hs
@@ -0,0 +1,169 @@
+----------------------------------------------------------------------
+-- |
+-- Module : SGrammar
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+--
+-- A simple format for context-free abstract syntax used e.g. in
+-- generation. AR 31\/3\/2006
+--
+-- (c) Aarne Ranta 2004 under GNU GPL
+--
+-- Purpose: to generate corpora. We use simple types and don't
+-- guarantee the correctness of bindings\/dependences.
+-----------------------------------------------------------------------------
+
+module GF.Grammar.SGrammar where
+
+import GF.Canon.GFC
+import GF.Grammar.LookAbs
+import GF.Grammar.PrGrammar
+import GF.Grammar.Macros
+import GF.Grammar.Values
+import GF.Grammar.Grammar
+import GF.Infra.Ident (Ident)
+
+import GF.Data.Operations
+import GF.Data.Zipper
+import GF.Infra.Option
+
+import Data.List
+
+-- (c) Aarne Ranta 2006 under GNU GPL
+
+
+type SGrammar = BinTree SCat [SRule]
+type SIdent = String
+type SRule = (SFun,SType)
+type SType = ([SCat],SCat)
+type SCat = SIdent
+type SFun = (Double,SIdent)
+
+allRules gr = concat [rs | (c,rs) <- tree2list gr]
+
+data STree =
+ SApp (SFun,[STree])
+ | SMeta SCat
+ | SString String
+ | SInt Integer
+ | SFloat Double
+ deriving (Show,Eq)
+
+depth :: STree -> Int
+depth t = case t of
+ SApp (_,ts@(_:_)) -> maximum (map depth ts) + 1
+ _ -> 1
+
+type Probs = BinTree Ident Double
+
+emptyProbs :: Probs
+emptyProbs = emptyBinTree
+
+prProbs :: Probs -> String
+prProbs = unlines . map pr . tree2list where
+ pr (f,p) = prt f ++ "\t" ++ show p
+
+------------------------------------------
+-- translate grammar to simpler form and generated trees back
+
+gr2sgr :: Options -> Probs -> GFCGrammar -> SGrammar
+gr2sgr opts probs gr = buildTree [(c,norm (noexp c rs)) | rs@((_,(_,c)):_) <- rules] where
+ noe = maybe [] (chunks ',') $ getOptVal opts (aOpt "noexpand")
+ only = maybe [] (chunks ',') $ getOptVal opts (aOpt "doexpand")
+ un = getOptInt opts (aOpt "atoms")
+ rules =
+ prune $
+ groupBy (\x y -> scat x == scat y) $
+ sortBy (\x y -> compare (scat x) (scat y)) $
+ [(trId f, ty') | (f,ty) <- funRulesOf gr, ty' <- trTy ty]
+ trId (_,f) = let f' = prt f in case lookupTree prt f probs of
+ Ok p -> (p,f')
+ _ -> (2.0, f')
+ trTy ty = case catSkeleton ty of
+ Ok (mcs,mc) -> [(map trCat mcs, trCat mc)]
+ _ -> []
+ trCat (m,c) = prt c ---
+ scat (_,(_,c)) = c
+
+ prune rs = maybe rs (\n -> map (onlyAtoms n) rs) $ un
+
+ norm = fillProb
+
+ onlyAtoms n rs =
+ let (rs1,rs2) = partition atom rs
+ in take n rs1 ++ rs2
+ atom = null . fst . snd
+
+ noexp c rs
+ | null only = if elem c noe then [((2.0,'?':c),([],c))] else rs
+ | otherwise = if elem c only then rs else [((2.0,'?':c),([],c))]
+
+-- for cases where explicit probability is not given (encoded as
+-- p > 1) divide the remaining mass by the number of such cases
+
+fillProb :: [SRule] -> [SRule]
+fillProb rs = [((defa p,f),ty) | ((p,f),ty) <- rs] where
+ defa p = if p > 1.0 then def else p
+ def = (1 - sum given) / genericLength nope
+ (nope,given) = partition (> 1.0) [p | ((p,_),_) <- rs]
+
+-- str2tr :: STree -> Exp
+str2tr t = case t of
+ SApp ((_,'?':c),[]) -> mkMeta 0 -- from noexpand=c
+ SApp ((_,f),ts) -> mkApp (trId f) (map str2tr ts)
+ SMeta _ -> mkMeta 0
+ SString s -> K s
+ SInt i -> EInt i
+ SFloat i -> EFloat i
+ where
+ trId = cn . zIdent
+
+-- tr2str :: Tree -> STree
+tr2str (Tr (N (_,at,val,_,_),ts)) = case (at,val) of
+ (AtC (_,f), _) -> SApp ((2.0,prt_ f),map tr2str ts)
+ (AtM _, v) -> SMeta (catOf v)
+ (AtL s, _) -> SString s
+ (AtI i, _) -> SInt i
+ (AtF i, _) -> SFloat i
+ _ -> SMeta "FAILED_TO_GENERATE" ---- err monad!
+ where
+ catOf v = case v of
+ VApp w _ -> catOf w
+ VCn (_,c) -> prt_ c
+ _ -> "FAILED_TO_GENERATE_FROM_META"
+
+
+------------------------------------------
+-- to test
+
+prSTree t = case t of
+ SApp ((_,f),ts) -> f ++ concat (map pr1 ts)
+ SMeta c -> '?':c
+ SString s -> prQuotedString s
+ SInt i -> show i
+ SFloat i -> show i
+ where
+ pr1 t@(SApp (_,ts)) = ' ' : (if null ts then id else prParenth) (prSTree t)
+ pr1 t = prSTree t
+
+pSRule :: String -> SRule
+pSRule s = case words s of
+ f : _ : cs -> ((2.0,f),(init cs', last cs'))
+ where cs' = [cs !! i | i <- [0,2..length cs - 1]]
+ _ -> error $ "not a rule" +++ s
+
+exSgr = map pSRule [
+ "Pred : NP -> VP -> S"
+ ,"Compl : TV -> NP -> VP"
+ ,"PredVV : VV -> VP -> VP"
+ ,"DefCN : CN -> NP"
+ ,"ModCN : AP -> CN -> CN"
+ ,"john : NP"
+ ,"walk : VP"
+ ,"love : TV"
+ ,"try : VV"
+ ,"girl : CN"
+ ,"big : AP"
+ ]
diff --git a/src-3.0/GF/Grammar/TC.hs b/src-3.0/GF/Grammar/TC.hs
new file mode 100644
index 000000000..be52d1889
--- /dev/null
+++ b/src-3.0/GF/Grammar/TC.hs
@@ -0,0 +1,299 @@
+----------------------------------------------------------------------
+-- |
+-- Module : TC
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/10/02 20:50:19 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.11 $
+--
+-- Thierry Coquand's type checking algorithm that creates a trace
+-----------------------------------------------------------------------------
+
+module GF.Grammar.TC (AExp(..),
+ Theory,
+ checkExp,
+ inferExp,
+ checkEqs,
+ eqVal,
+ whnf
+ ) where
+
+import GF.Data.Operations
+import GF.Grammar.Abstract
+import GF.Grammar.AbsCompute
+
+import Control.Monad
+import Data.List (sortBy)
+
+data AExp =
+ AVr Ident Val
+ | ACn QIdent Val
+ | AType
+ | AInt Integer
+ | AFloat Double
+ | AStr String
+ | AMeta MetaSymb Val
+ | AApp AExp AExp Val
+ | AAbs Ident Val AExp
+ | AProd Ident AExp AExp
+ | AEqs [([Exp],AExp)] --- not used
+ | AData Val
+ deriving (Eq,Show)
+
+type Theory = QIdent -> Err Val
+
+lookupConst :: Theory -> QIdent -> Err Val
+lookupConst th f = th f
+
+lookupVar :: Env -> Ident -> Err Val
+lookupVar g x = maybe (prtBad "unknown variable" x) return $ lookup x ((IW,uVal):g)
+-- wild card IW: no error produced, ?0 instead.
+
+type TCEnv = (Int,Env,Env)
+
+emptyTCEnv :: TCEnv
+emptyTCEnv = (0,[],[])
+
+whnf :: Val -> Err Val
+whnf v = ---- errIn ("whnf" +++ prt v) $ ---- debug
+ case v of
+ VApp u w -> do
+ u' <- whnf u
+ w' <- whnf w
+ app u' w'
+ VClos env e -> eval env e
+ _ -> return v
+
+app :: Val -> Val -> Err Val
+app u v = case u of
+ VClos env (Abs x e) -> eval ((x,v):env) e
+ _ -> return $ VApp u v
+
+eval :: Env -> Exp -> Err Val
+eval env e = ---- errIn ("eval" +++ prt e +++ "in" +++ prEnv env) $
+ case e of
+ Vr x -> lookupVar env x
+ Q m c -> return $ VCn (m,c)
+ QC m c -> return $ VCn (m,c) ---- == Q ?
+ Sort c -> return $ VType --- the only sort is Type
+ App f a -> join $ liftM2 app (eval env f) (eval env a)
+ _ -> return $ VClos env e
+
+eqVal :: Int -> Val -> Val -> Err [(Val,Val)]
+eqVal k u1 u2 = ---- errIn (prt u1 +++ "<>" +++ prBracket (show k) +++ prt u2) $
+ do
+ w1 <- whnf u1
+ w2 <- whnf u2
+ let v = VGen k
+ case (w1,w2) of
+ (VApp f1 a1, VApp f2 a2) -> liftM2 (++) (eqVal k f1 f2) (eqVal k a1 a2)
+ (VClos env1 (Abs x1 e1), VClos env2 (Abs x2 e2)) ->
+ eqVal (k+1) (VClos ((x1,v x1):env1) e1) (VClos ((x2,v x1):env2) e2)
+ (VClos env1 (Prod x1 a1 e1), VClos env2 (Prod x2 a2 e2)) ->
+ liftM2 (++)
+ (eqVal k (VClos env1 a1) (VClos env2 a2))
+ (eqVal (k+1) (VClos ((x1,v x1):env1) e1) (VClos ((x2,v x1):env2) e2))
+ (VGen i _, VGen j _) -> return [(w1,w2) | i /= j]
+ (VCn (_, i), VCn (_,j)) -> return [(w1,w2) | i /= j]
+ --- thus ignore qualifications; valid because inheritance cannot
+ --- be qualified. Simplifies annotation. AR 17/3/2005
+ _ -> return [(w1,w2) | w1 /= w2]
+-- invariant: constraints are in whnf
+
+checkType :: Theory -> TCEnv -> Exp -> Err (AExp,[(Val,Val)])
+checkType th tenv e = checkExp th tenv e vType
+
+checkExp :: Theory -> TCEnv -> Exp -> Val -> Err (AExp, [(Val,Val)])
+checkExp th tenv@(k,rho,gamma) e ty = do
+ typ <- whnf ty
+ let v = VGen k
+ case e of
+ Meta m -> return $ (AMeta m typ,[])
+ EData -> return $ (AData typ,[])
+
+ Abs x t -> case typ of
+ VClos env (Prod y a b) -> do
+ a' <- whnf $ VClos env a ---
+ (t',cs) <- checkExp th
+ (k+1,(x,v x):rho, (x,a'):gamma) t (VClos ((y,v x):env) b)
+ return (AAbs x a' t', cs)
+ _ -> prtBad ("function type expected for" +++ prt e +++ "instead of") typ
+
+-- {- --- to get deprec when checkEqs works (15/9/2005)
+ Eqs es -> do
+ bcs <- mapM (\b -> checkBranch th tenv b typ) es
+ let (bs,css) = unzip bcs
+ return (AEqs bs, concat css)
+-- - }
+ Prod x a b -> do
+ testErr (typ == vType) "expected Type"
+ (a',csa) <- checkType th tenv a
+ (b',csb) <- checkType th (k+1, (x,v x):rho, (x,VClos rho a):gamma) b
+ return (AProd x a' b', csa ++ csb)
+
+ _ -> checkInferExp th tenv e typ
+
+checkInferExp :: Theory -> TCEnv -> Exp -> Val -> Err (AExp, [(Val,Val)])
+checkInferExp th tenv@(k,_,_) e typ = do
+ (e',w,cs1) <- inferExp th tenv e
+ cs2 <- eqVal k w typ
+ return (e',cs1 ++ cs2)
+
+inferExp :: Theory -> TCEnv -> Exp -> Err (AExp, Val, [(Val,Val)])
+inferExp th tenv@(k,rho,gamma) e = case e of
+ Vr x -> mkAnnot (AVr x) $ noConstr $ lookupVar gamma x
+ Q m c
+ | m == cPredefAbs && (elem c (map identC ["Int","String","Float"])) ->
+ return (ACn (m,c) vType, vType, [])
+ | otherwise -> mkAnnot (ACn (m,c)) $ noConstr $ lookupConst th (m,c)
+ QC m c -> mkAnnot (ACn (m,c)) $ noConstr $ lookupConst th (m,c) ----
+ EInt i -> return (AInt i, valAbsInt, [])
+ EFloat i -> return (AFloat i, valAbsFloat, [])
+ K i -> return (AStr i, valAbsString, [])
+ Sort _ -> return (AType, vType, [])
+ App f t -> do
+ (f',w,csf) <- inferExp th tenv f
+ typ <- whnf w
+ case typ of
+ VClos env (Prod x a b) -> do
+ (a',csa) <- checkExp th tenv t (VClos env a)
+ b' <- whnf $ VClos ((x,VClos rho t):env) b
+ return $ (AApp f' a' b', b', csf ++ csa)
+ _ -> prtBad ("Prod expected for function" +++ prt f +++ "instead of") typ
+ _ -> prtBad "cannot infer type of expression" e
+ where
+ predefAbs c s = case c of
+ IC "Int" -> return $ const $ Q cPredefAbs cInt
+ IC "Float" -> return $ const $ Q cPredefAbs cFloat
+ IC "String" -> return $ const $ Q cPredefAbs cString
+ _ -> Bad s
+
+checkEqs :: Theory -> TCEnv -> (Fun,Trm) -> Val -> Err [(Val,Val)]
+checkEqs th tenv@(k,rho,gamma) (fun@(m,f),def) val = case def of
+ Eqs es -> liftM concat $ mapM checkBranch es
+ _ -> liftM snd $ checkExp th tenv def val
+ where
+ checkBranch (ps,df) =
+ let
+ (ps',_,vars) = foldr p2t ([],0,[]) ps
+ fps = mkApp (Q m f) ps'
+ in errIn ("branch" +++ prt fps) $ do
+ (aexp, typ, cs1) <- inferExp th tenv fps
+ let
+ bds = binds vars aexp
+ tenv' = (k, rho, bds ++ gamma)
+ (_,cs2) <- errIn (show bds) $ checkExp th tenv' df typ
+ return $ (cs1 ++ cs2)
+ p2t p (ps,i,g) = case p of
+ PW -> (meta (MetaSymb i) : ps, i+1, g)
+ PV IW -> (meta (MetaSymb i) : ps, i+1, g)
+ PV x -> (meta (MetaSymb i) : ps, i+1,upd x i g)
+ PString s -> ( K s : ps, i, g)
+ PInt n -> (EInt n : ps, i, g)
+ PFloat n -> (EFloat n : ps, i, g)
+ PP m c xs -> (mkApp (qq (m,c)) xss : ps, i', g')
+ where (xss,i',g') = foldr p2t ([],i,g) xs
+ _ -> error $ "undefined p2t case" +++ prt p +++ "in checkBranch"
+ upd x i g = (x,i) : g --- to annotate pattern variables: treat as metas
+
+ -- notice: in vars, the sequence 0.. is sorted. In subst aexp, all
+ -- this occurs and nothing else.
+ binds vars aexp = [(x,v) | ((x,_),v) <- zip vars metas] where
+ metas = map snd $ sortBy (\ (x,_) (y,_) -> compare x y) $ subst aexp
+ subst aexp = case aexp of
+ AMeta (MetaSymb i) v -> [(i,v)]
+ AApp c a _ -> subst c ++ subst a
+ _ -> [] -- never matter in patterns
+
+checkBranch :: Theory -> TCEnv -> Equation -> Val -> Err (([Exp],AExp),[(Val,Val)])
+checkBranch th tenv b@(ps,t) ty = errIn ("branch" +++ show b) $
+ chB tenv' ps' ty
+ where
+
+ (ps',_,rho2,k') = ps2ts k ps
+ tenv' = (k, rho2++rho, gamma) ---- k' ?
+ (k,rho,gamma) = tenv
+
+ chB tenv@(k,rho,gamma) ps ty = case ps of
+ p:ps2 -> do
+ typ <- whnf ty
+ case typ of
+ VClos env (Prod y a b) -> do
+ a' <- whnf $ VClos env a
+ (p', sigma, binds, cs1) <- checkP tenv p y a'
+ let tenv' = (length binds, sigma ++ rho, binds ++ gamma)
+ ((ps',exp),cs2) <- chB tenv' ps2 (VClos ((y,p'):env) b)
+ return ((p:ps',exp), cs1 ++ cs2) -- don't change the patt
+ _ -> prtBad ("Product expected for definiens" +++prt t +++ "instead of") typ
+ [] -> do
+ (e,cs) <- checkExp th tenv t ty
+ return (([],e),cs)
+ checkP env@(k,rho,gamma) t x a = do
+ (delta,cs) <- checkPatt th env t a
+ let sigma = [(x, VGen i x) | ((x,_),i) <- zip delta [k..]]
+ return (VClos sigma t, sigma, delta, cs)
+
+ ps2ts k = foldr p2t ([],0,[],k)
+ p2t p (ps,i,g,k) = case p of
+ PW -> (meta (MetaSymb i) : ps, i+1,g,k)
+ PV IW -> (meta (MetaSymb i) : ps, i+1,g,k)
+ PV x -> (vr x : ps, i, upd x k g,k+1)
+ PString s -> (K s : ps, i, g, k)
+ PInt n -> (EInt n : ps, i, g, k)
+ PFloat n -> (EFloat n : ps, i, g, k)
+ PP m c xs -> (mkApp (qq (m,c)) xss : ps, j, g',k')
+ where (xss,j,g',k') = foldr p2t ([],i,g,k) xs
+ _ -> error $ "undefined p2t case" +++ prt p +++ "in checkBranch"
+
+ upd x k g = (x, VGen k x) : g --- hack to recognize pattern variables
+
+
+checkPatt :: Theory -> TCEnv -> Exp -> Val -> Err (Binds,[(Val,Val)])
+checkPatt th tenv exp val = do
+ (aexp,_,cs) <- checkExpP tenv exp val
+ let binds = extrBinds aexp
+ return (binds,cs)
+ where
+ extrBinds aexp = case aexp of
+ AVr i v -> [(i,v)]
+ AApp f a _ -> extrBinds f ++ extrBinds a
+ _ -> [] -- no other cases are possible
+
+--- ad hoc, to find types of variables
+ checkExpP tenv@(k,rho,gamma) exp val = case exp of
+ Meta m -> return $ (AMeta m val, val, [])
+ Vr x -> return $ (AVr x val, val, [])
+ EInt i -> return (AInt i, valAbsInt, [])
+ EFloat i -> return (AFloat i, valAbsFloat, [])
+ K s -> return (AStr s, valAbsString, [])
+
+ Q m c -> do
+ typ <- lookupConst th (m,c)
+ return $ (ACn (m,c) typ, typ, [])
+ QC m c -> do
+ typ <- lookupConst th (m,c)
+ return $ (ACn (m,c) typ, typ, []) ----
+ App f t -> do
+ (f',w,csf) <- checkExpP tenv f val
+ typ <- whnf w
+ case typ of
+ VClos env (Prod x a b) -> do
+ (a',_,csa) <- checkExpP tenv t (VClos env a)
+ b' <- whnf $ VClos ((x,VClos rho t):env) b
+ return $ (AApp f' a' b', b', csf ++ csa)
+ _ -> prtBad ("Prod expected for function" +++ prt f +++ "instead of") typ
+ _ -> prtBad "cannot typecheck pattern" exp
+
+-- auxiliaries
+
+noConstr :: Err Val -> Err (Val,[(Val,Val)])
+noConstr er = er >>= (\v -> return (v,[]))
+
+mkAnnot :: (Val -> AExp) -> Err (Val,[(Val,Val)]) -> Err (AExp,Val,[(Val,Val)])
+mkAnnot a ti = do
+ (v,cs) <- ti
+ return (a v, v, cs)
+
diff --git a/src-3.0/GF/Grammar/TypeCheck.hs b/src-3.0/GF/Grammar/TypeCheck.hs
new file mode 100644
index 000000000..97b7ff243
--- /dev/null
+++ b/src-3.0/GF/Grammar/TypeCheck.hs
@@ -0,0 +1,311 @@
+----------------------------------------------------------------------
+-- |
+-- Module : TypeCheck
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/09/15 16:22:02 $
+-- > CVS $Author: aarne $
+-- > CVS $Revision: 1.16 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Grammar.TypeCheck (-- * top-level type checking functions; TC should not be called directly.
+ annotate, annotateIn,
+ justTypeCheck, checkIfValidExp,
+ reduceConstraints,
+ splitConstraints,
+ possibleConstraints,
+ reduceConstraintsNode,
+ performMetaSubstNode,
+ -- * some top-level batch-mode checkers for the compiler
+ justTypeCheckSrc,
+ grammar2theorySrc,
+ checkContext,
+ checkTyp,
+ checkEquation,
+ checkConstrs,
+ editAsTermCommand,
+ exp2termCommand,
+ exp2termlistCommand,
+ tree2termlistCommand
+ ) where
+
+import GF.Data.Operations
+import GF.Data.Zipper
+
+import GF.Grammar.Abstract
+import GF.Grammar.AbsCompute
+import GF.Grammar.Refresh
+import GF.Grammar.LookAbs
+import qualified GF.Grammar.Lookup as Lookup ---
+
+import GF.Grammar.TC
+
+import GF.Grammar.Unify ---
+
+import Control.Monad (foldM, liftM, liftM2)
+import Data.List (nub) ---
+
+-- top-level type checking functions; TC should not be called directly.
+
+annotate :: GFCGrammar -> Exp -> Err Tree
+annotate gr exp = annotateIn gr [] exp Nothing
+
+-- | type check in empty context, return a list of constraints
+justTypeCheck :: GFCGrammar -> Exp -> Val -> Err Constraints
+justTypeCheck gr e v = do
+ (_,constrs0) <- checkExp (grammar2theory gr) (initTCEnv []) e v
+ constrs1 <- reduceConstraints (lookupAbsDef gr) 0 constrs0
+ return $ fst $ splitConstraints gr constrs1
+
+-- | type check in empty context, return the expression itself if valid
+checkIfValidExp :: GFCGrammar -> Exp -> Err Exp
+checkIfValidExp gr e = do
+ (_,_,constrs0) <- inferExp (grammar2theory gr) (initTCEnv []) e
+ constrs1 <- reduceConstraints (lookupAbsDef gr) 0 constrs0
+ ifNull (return e) (Bad . unwords . prConstrs) constrs1
+
+annotateIn :: GFCGrammar -> Binds -> Exp -> Maybe Val -> Err Tree
+annotateIn gr gamma exp = maybe (infer exp) (check exp) where
+ infer e = do
+ (a,_,cs) <- inferExp theory env e
+ aexp2treeC (a,cs)
+ check e v = do
+ (a,cs) <- checkExp theory env e v
+ aexp2treeC (a,cs)
+ env = initTCEnv gamma
+ theory = grammar2theory gr
+ aexp2treeC (a,c) = do
+ c' <- reduceConstraints (lookupAbsDef gr) (length gamma) c
+ aexp2tree (a,c')
+
+-- | invariant way of creating TCEnv from context
+initTCEnv gamma =
+ (length gamma,[(x,VGen i x) | ((x,_),i) <- zip gamma [0..]], gamma)
+
+-- | process constraints after eqVal by computing by defs
+reduceConstraints :: LookDef -> Int -> Constraints -> Err Constraints
+reduceConstraints look i = liftM concat . mapM redOne where
+ redOne (u,v) = do
+ u' <- computeVal look u
+ v' <- computeVal look v
+ eqVal i u' v'
+
+computeVal :: LookDef -> Val -> Err Val
+computeVal look v = case v of
+ VClos g@(_:_) e -> do
+ e' <- compt (map fst g) e --- bindings of g in e?
+ whnf $ VClos g e'
+{- ----
+ _ -> do ---- how to compute a Val, really??
+ e <- val2exp v
+ e' <- compt [] e
+ whnf $ vClos e'
+-}
+ VApp f c -> liftM2 VApp (compv f) (compv c) >>= whnf
+ _ -> whnf v
+ where
+ compt = computeAbsTermIn look
+ compv = computeVal look
+
+-- | take apart constraints that have the form (? <> t), usable as solutions
+splitConstraints :: GFCGrammar -> Constraints -> (Constraints,MetaSubst)
+splitConstraints gr = splitConstraintsGen (lookupAbsDef gr)
+
+splitConstraintsSrc :: Grammar -> Constraints -> (Constraints,MetaSubst)
+splitConstraintsSrc gr = splitConstraintsGen (Lookup.lookupAbsDef gr)
+
+splitConstraintsGen :: LookDef -> Constraints -> (Constraints,MetaSubst)
+splitConstraintsGen look cs = csmsu where
+
+ csmsu = (nub [(a,b) | (a,b) <- csf1,a /= b],msf1)
+ (csf1,msf1) = unif (csf,msf) -- alternative: filter first
+ (csf,msf) = foldr mkOne ([],[]) cs
+
+ csmsf = foldr mkOne ([],msu) csu
+ (csu,msu) = unif (cs1,[]) -- alternative: unify first
+
+ cs1 = errVal cs $ reduceConstraints look 0 cs
+
+ mkOne (u,v) = case (u,v) of
+ (VClos g (Meta m), v) | null g -> sub m v
+ (v, VClos g (Meta m)) | null g -> sub m v
+ -- do nothing if meta has nonempty closure; null g || isConstVal v WAS WRONG
+ c -> con c
+ con c (cs,ms) = (c:cs,ms)
+ sub m v (cs,ms) = (cs,(m,v):ms)
+
+ unifo = id -- alternative: don't use unification
+
+ unif cm@(cs,ms) = errVal cm $ do --- alternative: use unification
+ (cs',ms') <- unifyVal cs
+ return (cs', ms' ++ ms)
+
+performMetaSubstNode :: MetaSubst -> TrNode -> TrNode
+performMetaSubstNode subst n@(N (b,a,v,(c,m),s)) = let
+ v' = metaSubstVal v
+ b' = [(x,metaSubstVal v) | (x,v) <- b]
+ c' = [(u',v') | (u,v) <- c,
+ let (u',v') = (metaSubstVal u, metaSubstVal v), u' /= v']
+ in N (b',a,v',(c',m),s)
+ where
+ metaSubstVal u = errVal u $ whnf $ case u of
+ VApp f a -> VApp (metaSubstVal f) (metaSubstVal a)
+ VClos g e -> VClos [(x,metaSubstVal v) | (x,v) <- g] (metaSubstExp e)
+ _ -> u
+ metaSubstExp e = case e of
+ Meta m -> errVal e $ maybe (return e) val2expSafe $ lookup m subst
+ _ -> composSafeOp metaSubstExp e
+
+reduceConstraintsNode :: GFCGrammar -> TrNode -> TrNode
+reduceConstraintsNode gr = changeConstrs red where
+ red cs = errVal cs $ reduceConstraints (lookupAbsDef gr) 0 cs
+
+-- | weak heuristic to narrow down menus; not used for TC. 15\/11\/2001.
+-- the age-old method from GF 0.9
+possibleConstraints :: GFCGrammar -> Constraints -> Bool
+possibleConstraints gr = and . map (possibleConstraint gr)
+
+possibleConstraint :: GFCGrammar -> (Val,Val) -> Bool
+possibleConstraint gr (u,v) = errVal True $ do
+ u' <- val2exp u >>= compute gr
+ v' <- val2exp v >>= compute gr
+ return $ cts u' v'
+ where
+ cts t u = isUnknown t || isUnknown u || case (t,u) of
+ (Q m c, Q n d) -> c == d || notCan (m,c) || notCan (n,d)
+ (QC m c, QC n d) -> c == d
+ (App f a, App g b) -> cts f g && cts a b
+ (Abs x b, Abs y c) -> cts b c
+ (Prod x a f, Prod y b g) -> cts a b && cts f g
+ (_ , _) -> False
+
+ isUnknown t = case t of
+ Vr _ -> True
+ Meta _ -> True
+ _ -> False
+
+ notCan = not . isPrimitiveFun gr
+
+-- interface to TC type checker
+
+type2val :: Type -> Val
+type2val = VClos []
+
+aexp2tree :: (AExp,[(Val,Val)]) -> Err Tree
+aexp2tree (aexp,cs) = do
+ (bi,at,vt,ts) <- treeForm aexp
+ ts' <- mapM aexp2tree [(t,[]) | t <- ts]
+ return $ Tr (N (bi,at,vt,(cs,[]),False),ts')
+ where
+ treeForm a = case a of
+ AAbs x v b -> do
+ (bi, at, vt, args) <- treeForm b
+ v' <- whnf v ---- should not be needed...
+ return ((x,v') : bi, at, vt, args)
+ AApp c a v -> do
+ (_,at,_,args) <- treeForm c
+ v' <- whnf v ----
+ return ([],at,v',args ++ [a])
+ AVr x v -> do
+ v' <- whnf v ----
+ return ([],AtV x,v',[])
+ ACn c v -> do
+ v' <- whnf v ----
+ return ([],AtC c,v',[])
+ AInt i -> do
+ return ([],AtI i,valAbsInt,[])
+ AFloat i -> do
+ return ([],AtF i,valAbsFloat,[])
+ AStr s -> do
+ return ([],AtL s,valAbsString,[])
+ AMeta m v -> do
+ v' <- whnf v ----
+ return ([],AtM m,v',[])
+ _ -> Bad "illegal tree" -- AProd
+
+grammar2theory :: GFCGrammar -> Theory
+grammar2theory gr (m,f) = case lookupFunType gr m f of
+ Ok t -> return $ type2val t
+ Bad s -> case lookupCatContext gr m f of
+ Ok cont -> return $ cont2val cont
+ _ -> Bad s
+
+cont2exp :: Context -> Exp
+cont2exp c = mkProd (c, eType, []) -- to check a context
+
+cont2val :: Context -> Val
+cont2val = type2val . cont2exp
+
+-- some top-level batch-mode checkers for the compiler
+
+justTypeCheckSrc :: Grammar -> Exp -> Val -> Err Constraints
+justTypeCheckSrc gr e v = do
+ (_,constrs0) <- checkExp (grammar2theorySrc gr) (initTCEnv []) e v
+ return $ filter notJustMeta constrs0
+---- return $ fst $ splitConstraintsSrc gr constrs0
+---- this change was to force proper tc of abstract modules.
+---- May not be quite right. AR 13/9/2005
+
+notJustMeta (c,k) = case (c,k) of
+ (VClos g1 (Meta m1), VClos g2 (Meta m2)) -> False
+ _ -> True
+
+grammar2theorySrc :: Grammar -> Theory
+grammar2theorySrc gr (m,f) = case lookupFunTypeSrc gr m f of
+ Ok t -> return $ type2val t
+ Bad s -> case lookupCatContextSrc gr m f of
+ Ok cont -> return $ cont2val cont
+ _ -> Bad s
+
+checkContext :: Grammar -> Context -> [String]
+checkContext st = checkTyp st . cont2exp
+
+checkTyp :: Grammar -> Type -> [String]
+checkTyp gr typ = err singleton prConstrs $ justTypeCheckSrc gr typ vType
+
+checkEquation :: Grammar -> Fun -> Trm -> [String]
+checkEquation gr (m,fun) def = err singleton id $ do
+ typ <- lookupFunTypeSrc gr m fun
+---- cs <- checkEqs (grammar2theorySrc gr) (initTCEnv []) ((m,fun),def) (vClos typ)
+ cs <- justTypeCheckSrc gr def (vClos typ)
+ let cs1 = filter notJustMeta cs ----- filter (not . possibleConstraint gr) cs ----
+ return $ ifNull [] (singleton . prConstraints) cs1
+
+checkConstrs :: Grammar -> Cat -> [Ident] -> [String]
+checkConstrs gr cat _ = [] ---- check constructors!
+
+
+
+
+
+
+{- ----
+err singleton concat . mapM checkOne where
+ checkOne con = do
+ typ <- lookupFunType gr con
+ typ' <- computeAbsTerm gr typ
+ vcat <- valCat typ'
+ return $ if (cat == vcat) then [] else ["wrong type in constructor" +++ prt con]
+-}
+
+editAsTermCommand :: GFCGrammar -> (Loc TrNode -> Err (Loc TrNode)) -> Exp -> [Exp]
+editAsTermCommand gr c e = err (const []) singleton $ do
+ t <- annotate gr $ refreshMetas [] e
+ t' <- c $ tree2loc t
+ return $ tree2exp $ loc2tree t'
+
+exp2termCommand :: GFCGrammar -> (Exp -> Err Exp) -> Tree -> Err Tree
+exp2termCommand gr f t = errIn ("modifying term" +++ prt t) $ do
+ let exp = tree2exp t
+ exp2 <- f exp
+ annotate gr exp2
+
+exp2termlistCommand :: GFCGrammar -> (Exp -> [Exp]) -> Tree -> [Tree]
+exp2termlistCommand gr f = err (const []) fst . mapErr (annotate gr) . f . tree2exp
+
+tree2termlistCommand :: GFCGrammar -> (Tree -> [Exp]) -> Tree -> [Tree]
+tree2termlistCommand gr f = err (const []) fst . mapErr (annotate gr) . f
diff --git a/src-3.0/GF/Grammar/Unify.hs b/src-3.0/GF/Grammar/Unify.hs
new file mode 100644
index 000000000..588c1b306
--- /dev/null
+++ b/src-3.0/GF/Grammar/Unify.hs
@@ -0,0 +1,96 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Unify
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:22:31 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.4 $
+--
+-- (c) Petri Mäenpää & Aarne Ranta, 1998--2001
+--
+-- brute-force adaptation of the old-GF program AR 21\/12\/2001 ---
+-- the only use is in 'TypeCheck.splitConstraints'
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Unify (unifyVal) where
+
+import GF.Grammar.Abstract
+
+import GF.Data.Operations
+
+import Data.List (partition)
+
+unifyVal :: Constraints -> Err (Constraints,MetaSubst)
+unifyVal cs0 = do
+ let (cs1,cs2) = partition notSolvable cs0
+ let (us,vs) = unzip cs1
+ us' <- mapM val2exp us
+ vs' <- mapM val2exp vs
+ let (ms,cs) = unifyAll (zip us' vs') []
+ return (cs1 ++ [(VClos [] t, VClos [] u) | (t,u) <- cs],
+ [(m, VClos [] t) | (m,t) <- ms])
+ where
+ notSolvable (v,w) = case (v,w) of -- don't consider nonempty closures
+ (VClos (_:_) _,_) -> True
+ (_,VClos (_:_) _) -> True
+ _ -> False
+
+type Unifier = [(MetaSymb, Trm)]
+type Constrs = [(Trm, Trm)]
+
+unifyAll :: Constrs -> Unifier -> (Unifier,Constrs)
+unifyAll [] g = (g, [])
+unifyAll ((a@(s, t)) : l) g =
+ let (g1, c) = unifyAll l g
+ in case unify s t g1 of
+ Ok g2 -> (g2, c)
+ _ -> (g1, a : c)
+
+unify :: Trm -> Trm -> Unifier -> Err Unifier
+unify e1 e2 g =
+ case (e1, e2) of
+ (Meta s, t) -> do
+ tg <- subst_all g t
+ let sg = maybe e1 id (lookup s g)
+ if (sg == Meta s) then extend g s tg else unify sg tg g
+ (t, Meta s) -> unify e2 e1 g
+ (Q _ a, Q _ b) | (a == b) -> return g ---- qualif?
+ (QC _ a, QC _ b) | (a == b) -> return g ----
+ (Vr x, Vr y) | (x == y) -> return g
+ (Abs x b, Abs y c) -> do let c' = substTerm [x] [(y,Vr x)] c
+ unify b c' g
+ (App c a, App d b) -> case unify c d g of
+ Ok g1 -> unify a b g1
+ _ -> prtBad "fail unify" e1
+ _ -> prtBad "fail unify" e1
+
+extend :: Unifier -> MetaSymb -> Trm -> Err Unifier
+extend g s t | (t == Meta s) = return g
+ | occCheck s t = prtBad "occurs check" t
+ | True = return ((s, t) : g)
+
+subst_all :: Unifier -> Trm -> Err Trm
+subst_all s u =
+ case (s,u) of
+ ([], t) -> return t
+ (a : l, t) -> do
+ t' <- (subst_all l t) --- successive substs - why ?
+ return $ substMetas [a] t'
+
+substMetas :: [(MetaSymb,Trm)] -> Trm -> Trm
+substMetas subst trm = case trm of
+ Meta x -> case lookup x subst of
+ Just t -> t
+ _ -> trm
+ _ -> composSafeOp (substMetas subst) trm
+
+occCheck :: MetaSymb -> Trm -> Bool
+occCheck s u = case u of
+ Meta v -> s == v
+ App c a -> occCheck s c || occCheck s a
+ Abs x b -> occCheck s b
+ _ -> False
+
diff --git a/src-3.0/GF/Grammar/Values.hs b/src-3.0/GF/Grammar/Values.hs
new file mode 100644
index 000000000..6e029d98b
--- /dev/null
+++ b/src-3.0/GF/Grammar/Values.hs
@@ -0,0 +1,109 @@
+----------------------------------------------------------------------
+-- |
+-- Module : Values
+-- Maintainer : AR
+-- Stability : (stable)
+-- Portability : (portable)
+--
+-- > CVS $Date: 2005/04/21 16:22:32 $
+-- > CVS $Author: bringert $
+-- > CVS $Revision: 1.7 $
+--
+-- (Description of the module)
+-----------------------------------------------------------------------------
+
+module GF.Grammar.Values (-- * values used in TC type checking
+ Exp, Val(..), Env,
+ -- * annotated tree used in editing
+ Tree, TrNode(..), Atom(..), Binds, Constraints, MetaSubst,
+ -- * for TC
+ valAbsInt, valAbsFloat, valAbsString, vType,
+ isPredefCat,
+ cType, cPredefAbs, cInt, cFloat, cString,
+ eType, tree2exp, loc2treeFocus
+ ) where
+
+import GF.Data.Operations
+import GF.Data.Zipper
+
+import GF.Grammar.Grammar
+import GF.Infra.Ident
+
+-- values used in TC type checking
+
+type Exp = Term
+
+data Val = VGen Int Ident | VApp Val Val | VCn QIdent | VType | VClos Env Exp
+ deriving (Eq,Show)
+
+type Env = [(Ident,Val)]
+
+-- annotated tree used in editing
+
+type Tree = Tr TrNode
+
+newtype TrNode = N (Binds,Atom,Val,(Constraints,MetaSubst),Bool)
+ deriving (Eq,Show)
+
+data Atom =
+ AtC Fun | AtM MetaSymb | AtV Ident | AtL String | AtI Integer | AtF Double
+ deriving (Eq,Show)
+
+type Binds = [(Ident,Val)]
+type Constraints = [(Val,Val)]
+type MetaSubst = [(MetaSymb,Val)]
+
+-- for TC
+
+valAbsInt :: Val
+valAbsInt = VCn (cPredefAbs, cInt)
+
+valAbsFloat :: Val
+valAbsFloat = VCn (cPredefAbs, cFloat)
+
+valAbsString :: Val
+valAbsString = VCn (cPredefAbs, cString)
+
+vType :: Val
+vType = VType
+
+cType :: Ident
+cType = identC "Type" --- #0
+
+cPredefAbs :: Ident
+cPredefAbs = identC "PredefAbs"
+
+cInt :: Ident
+cInt = identC "Int"
+
+cFloat :: Ident
+cFloat = identC "Float"
+
+cString :: Ident
+cString = identC "String"
+
+isPredefCat :: Ident -> Bool
+isPredefCat c = elem c [cInt,cString,cFloat]
+
+eType :: Exp
+eType = Sort "Type"
+
+tree2exp :: Tree -> Exp
+tree2exp (Tr (N (bi,at,_,_,_),ts)) = foldr Abs (foldl App at' ts') bi' where
+ at' = case at of
+ AtC (m,c) -> Q m c
+ AtV i -> Vr i
+ AtM m -> Meta m
+ AtL s -> K s
+ AtI s -> EInt s
+ AtF s -> EFloat s
+ bi' = map fst bi
+ ts' = map tree2exp ts
+
+loc2treeFocus :: Loc TrNode -> Tree
+loc2treeFocus (Loc (Tr (a,ts),p)) =
+ loc2tree (Loc (Tr (mark a, map (mapTr nomark) ts), mapPath nomark p))
+ where
+ (mark, nomark) = (\(N (a,b,c,d,_)) -> N(a,b,c,d,True),
+ \(N (a,b,c,d,_)) -> N(a,b,c,d,False))
+