diff options
Diffstat (limited to 'src/GF/Grammar/Lookup.hs')
| -rw-r--r-- | src/GF/Grammar/Lookup.hs | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/GF/Grammar/Lookup.hs b/src/GF/Grammar/Lookup.hs new file mode 100644 index 000000000..b8afbc21e --- /dev/null +++ b/src/GF/Grammar/Lookup.hs @@ -0,0 +1,393 @@ +module Lookup where + +import Operations +import Abstract +import Modules + +import List (nub) +import Monad + +-- lookup in resource and concrete in compiling; for abstract, use Look + +lookupResDef :: SourceGrammar -> Ident -> Ident -> Err Term +lookupResDef gr m c = do + mi <- lookupModule gr m + case mi of + ModMod mo -> do + info <- lookupInfo mo c + case info of + ResOper _ (Yes t) -> return $ qualifAnnot m t + AnyInd _ n -> lookupResDef gr n c + ResParam _ -> return $ QC m c + ResValue _ -> return $ QC m c + _ -> Bad $ prt c +++ "is not defined in resource" +++ prt m + _ -> Bad $ prt m +++ "is not a resource" + +lookupResType :: SourceGrammar -> Ident -> Ident -> Err Type +lookupResType gr m c = do + mi <- lookupModule gr m + case mi of + ModMod mo -> do + info <- lookupInfo mo c + case info of + ResOper (Yes t) _ -> return $ qualifAnnot m t + 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" + +lookupParams :: SourceGrammar -> Ident -> Ident -> Err [Param] +lookupParams gr m c = do + mi <- lookupModule gr m + case mi of + ModMod mo -> do + info <- lookupInfo mo c + case info of + ResParam (Yes ps) -> return ps + AnyInd _ n -> lookupParams gr n c + _ -> Bad $ prt c +++ "has no parameters defined in resource" +++ prt m + _ -> Bad $ prt m +++ "is not a resource" + +lookupParamValues :: SourceGrammar -> Ident -> Ident -> Err [Term] +lookupParamValues gr m c = do + ps <- lookupParams gr m c + 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 + +allParamValues :: SourceGrammar -> Type -> Err [Term] +allParamValues cnc ptyp = case ptyp of + QC p c -> lookupParamValues cnc p c + RecType r -> do + let (ls,tys) = unzip r + tss <- mapM allPV tys + return [R (zipAssign ls ts) | ts <- combinations tss] + _ -> prtBad "cannot find parameter values for" ptyp + where + allPV = allParamValues cnc + +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 + + +lookupLincat :: SourceGrammar -> Ident -> Ident -> Err Type +lookupLincat gr m c = do + mi <- lookupModule gr m + case mi of + ModMod mo -> do + info <- lookupInfo 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 type of oper may have to be inferred at TC, so it may be junk before it + +lookupResIdent :: Ident -> [(Ident, SourceRes)] -> Err (Term,Type) +lookupResIdent c ms = case lookupWhich ms c of + Ok (i,info) -> case info of + ResOper (Yes t) _ -> return (Q i c, t) + ResOper _ _ -> return (Q i c, undefined) ---- + ResParam _ -> return (Q i c, typePType) + ResValue (Yes t) -> return (QC i c, t) + _ -> Bad $ "not found in resource" +++ prt c + +-- NB we only have to look up cnc in canonical! + +-- you may want to strip the qualification if the module is the current one + +stripMod :: Ident -> Term -> Term +stripMod m t = case t of + Q n c | n==m -> Cn c + QC n c | n==m -> Con c + _ -> t + +-- what you want may be a pattern and not a term. Then use Macros.term2patt + + + + +-- an auxiliary for making ordered search through a list of modules + +lookups :: Ord i => (i -> m -> Err (Perhaps a m)) -> i -> [m] -> Err (Perhaps a m) +lookups look c [] = Bad "not found in any module" +lookups look c (m:ms) = case look c m of + Ok (Yes v) -> return $ Yes v + Ok (May m') -> look c m' + _ -> lookups look c ms + + +lookupAbstract :: AbstractST -> Ident -> Err AbsInfo +lookupAbstract g i = errIn ("not found in abstract" +++ prt i) $ lookupTree prt i g + +lookupFunsToCat :: AbstractST -> Ident -> Err [Fun] +lookupFunsToCat g c = errIn ("looking up functions to category" +++ prt c) $ do + info <- lookupAbstract g c + case info of + AbsCat _ _ fs _ -> return fs + _ -> prtBad "not category" c + +allFunsWithValCat ab = [(f,c) | (c, AbsCat _ _ fs _) <- abstr2list ab, f <- fs] + +allDefs ab = [(f,d) | (f,AbsFun _ (Just d)) <- abstr2list ab] + +lookupCatContext :: AbstractST -> Ident -> Err Context +lookupCatContext g c = errIn "context of category" $ do + info <- lookupAbstract g c + case info of + AbsCat c _ _ _ -> return c + _ -> prtBad "not category" c + +lookupFunType :: AbstractST -> Ident -> Err Term +lookupFunType g c = errIn "looking up type of function" $ case c of + IL s -> lookupLiteral s >>= return . fst + _ -> do + info <- lookupAbstract g c + case info of + AbsFun t _ -> return t + AbsType t -> return typeType + _ -> prtBad "not function" c + +lookupFunArity :: AbstractST -> Ident -> Err Int +lookupFunArity g c = do + typ <- lookupFunType g c + ctx <- contextOfType typ + return $ length ctx + +lookupAbsDef :: AbstractST -> Ident -> Err (Maybe Term) +lookupAbsDef g c = errIn "looking up definition in abstract syntax" $ do + info <- lookupAbstract g c + case info of + AbsFun _ t -> return t + AbsType t -> return $ Just t + _ -> return $ Nothing -- constant found and accepted as primitive + + +allCats :: AbstractST -> [Ident] +allCats abstr = [c | (c, AbsCat _ _ _ _) <- abstr2list abstr] + +allIndepCats :: AbstractST -> [Ident] +allIndepCats abstr = [c | (c, AbsCat [] _ _ _) <- abstr2list abstr] + +lookupConcrete :: ConcreteST -> Ident -> Err CncInfo +lookupConcrete g i = errIn ("not found in concrete" +++ prt i) $ lookupTree prt i g + +lookupPackage :: ConcreteST -> Ident -> Err ([Ident], ConcreteST) +lookupPackage g p = do + info <- lookupConcrete g p + case info of + CncPackage ps ins -> return (ps,ins) + _ -> prtBad "not package" p + +lookupInPackage :: ConcreteST -> (Ident,Ident) -> Err CncInfo +lookupInPackage = lookupLift (flip (lookupTree prt)) + +lookupInAll :: [BinTree (Ident,b)] -> Ident -> Err b +lookupInAll = lookInAll (flip (lookupTree prt)) + +lookInAll :: (BinTree (Ident,c) -> Ident -> Err b) -> + [BinTree (Ident,c)] -> Ident -> Err b +lookInAll look ts c = case ts of + t : ts' -> err (const $ lookInAll look ts' c) return $ look t c + [] -> prtBad "not found in any package" c + +lookupLift :: (ConcreteST -> Ident -> Err b) -> + ConcreteST -> (Ident,Ident) -> Err b +lookupLift look g (p,f) = do + (ps,ins) <- lookupPackage g p + ps' <- mapM (lookupPackage g) ps + lookInAll look (ins : reverse (map snd ps')) f + +termFromPackage :: ConcreteST -> Ident -> Term -> Err Term +termFromPackage g p = termFP where + termFP t = case t of + Cn c -> return $ if isInPack c + then Q p c + else Cn c + T (TTyped t) cs -> do + t' <- termFP t + liftM (T (TTyped t')) $ mapM branchInPack cs + T i cs -> liftM (T i) $ mapM branchInPack cs + _ -> composOp termFP t + isInPack c = case lookupInPackage g (p,c) of + Ok _ -> True + _ -> False + branchInPack (q,t) = do + p' <- pattInPack q + t' <- termFP t + return (p',t') + pattInPack q = case q of + PC c ps -> do + let pc = if isInPack c + then PP p c + else PC c + ps' <- mapM pattInPack ps + return $ pc ps' + _ -> return q + +lookupCncDef :: ConcreteST -> Ident -> Err Term +lookupCncDef g t@(IL _) = return $ cn t +lookupCncDef g c = errIn "looking up defining term" $ do + info <- lookupConcrete g c + case info of + CncOper _ t _ -> return t -- the definition + CncCat t _ _ _ -> return t -- the linearization type + _ -> return $ Cn c -- constant found and accepted + +lookupOperDef :: ConcreteST -> Ident -> Err Term +lookupOperDef g c = errIn "looking up defining term of oper" $ do + info <- lookupConcrete g c + case info of + CncOper _ t _ -> return t + _ -> prtBad "not oper" c + +lookupLincat :: ConcreteST -> Ident -> Err Term +lookupLincat g c = return $ errVal defaultLinType $ do + info <- lookupConcrete g c + case info of + CncCat t _ _ _ -> return t + _ -> prtBad "not category" c + +lookupLindef :: ConcreteST -> Ident -> Err Term +lookupLindef g c = return $ errVal linDefStr $ do + info <- lookupConcrete g c + case info of + CncCat _ (Just t) _ _ -> return t + CncCat _ _ _ _ -> return $ linDefStr --- wrong: this is only sof {s:Str} + _ -> prtBad "not category" c + +lookupLinType :: ConcreteST -> Ident -> Err Type +lookupLinType g c = errIn "looking up type in concrete syntax" $ do + info <- lookupConcrete g c + case info of + CncParType _ _ _ -> return typeType + CncParam ty _ -> return ty + CncOper (Just ty) _ _ -> return ty + _ -> prtBad "no type found for" c + +lookupLin :: ConcreteST -> Ident -> Err Term +lookupLin g c = errIn "looking up linearization rule" $ do + info <- lookupConcrete g c + case info of + CncFun t _ -> return t + _ -> prtBad "not category" c + +lookupFirstTag :: ConcreteST -> Ident -> Err Term +lookupFirstTag g c = do + vs <- lookupParamValues g c + case vs of + v:_ -> return v + _ -> prtBad "empty parameter type" c + +lookupPrintname :: ConcreteST -> Ident -> Err String +lookupPrintname g c = case lookupConcrete g c of + Ok info -> case info of + CncCat _ _ _ m -> mpr m + CncFun _ m -> mpr m + CncParType _ _ m -> mpr m + CncOper _ _ m -> mpr m + _ -> Bad "no possible printname" + Bad s -> Bad s + where + mpr = maybe (Bad "no printname") (return . stringFromTerm) + +-- this variant succeeds even if there's only abstr syntax +lookupPrintname' g c = case lookupConcrete g c of + Bad _ -> return $ prt c + Ok info -> case info of + CncCat _ _ _ m -> mpr m + CncFun _ m -> mpr m + CncParType _ _ m -> mpr m + CncOper _ _ m -> mpr m + _ -> return $ prt c + where + mpr = return . maybe (prt c) stringFromTerm + +allOperDefs :: ConcreteST -> [(Ident,CncInfo)] +allOperDefs cnc = [d | d@(_, CncOper _ _ _) <- concr2list cnc] + +allPackageDefs :: ConcreteST -> [(Ident,CncInfo)] +allPackageDefs cnc = [d | d@(_, CncPackage _ _) <- concr2list cnc] + +allOperDependencies :: ConcreteST -> [(Ident,[Ident])] +allOperDependencies cnc = + [(f, filter (/= f) $ -- package name may occur in the package itself + nub (concatMap (opersInCncInfo cnc f . snd) (tree2list ds))) | + (f, CncPackage _ ds) <- allPackageDefs cnc] ++ + [(f, nub (opersInTerm cnc t)) | + (f, CncOper _ t _) <- allOperDefs cnc] + +opersInTerm :: ConcreteST -> Term -> [Ident] +opersInTerm cnc t = case t of + Cn c -> [c | isOper c] + Q p c -> [p] + _ -> collectOp ops t + where + isOper (IL _) = False + isOper c = errVal False $ lookupOperDef cnc c >>= return . const True + ops = opersInTerm cnc + +-- this is used inside packages, to find references to outside the package +opersInCncInfo :: ConcreteST -> Ident -> CncInfo -> [Ident] +opersInCncInfo cnc p i = case i of + CncOper _ t _-> filter (not . internal) $ opersInTerm cnc t + _ -> [] + where + internal c = case lookupInPackage cnc (p,c) of + Ok _ -> True + _ -> False + +opersUsedInLins :: ConcreteST -> [(Ident,[Ident])] -> [Ident] +opersUsedInLins cnc deps = do + let ops0 = concat [opersInTerm cnc t | (_, CncFun t _) <- concr2list cnc] + nub $ closure ops0 + where + closure ops = case [g | (f,fs) <- deps, elem f ops, g <- fs, notElem g ops] of + [] -> ops + ops' -> ops ++ closure ops' + -- presupposes deps are not circular: check this first! + + + + +-- create refinement and wrapping lists + + +varOrConst :: AbstractST -> Ident -> Err Term +varOrConst abstr c = case lookupFunType abstr c of + Ok _ -> return $ Cn c --- bindings cannot overshadow constants + _ -> case c of + IL _ -> return $ Cn c + _ -> return $ Vr c + +-- a rename operation for parsing term input; for abstract syntax and parameters +renameTrm :: (Ident -> Err a) -> Term -> Term +renameTrm look = ren [] where + ren vars t = case t of + Vr x | notElem x vars && isNotError (look x) -> Cn x + Abs x b -> Abs x $ ren (x:vars) b + _ -> composSafeOp (ren vars) t +-} |
