alpha-0.9999: src/Context/Language.hs
{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts #-}
module Context.Language where
import My.Prelude
import Data.Maybe
import My.Data.List
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Bimap as BM
import My.Control.Monad
import My.Control.Monad.State
import Control.Monad.Trans
import qualified Data.Traversable as T
import ID
import PCode
import Context.Types as C
import Translate
showTable name showLine contents = (name++":"):map (" "++) (concatMap showLine contents)
instance Show Language where
show e = intercalate "\n" $ showTable "Context" id [
["Max ID: "++show (maxIDL e)],
showTable "Symbols" (\(s,i) -> [s++" -> "++show i]) $ BM.toList (symbolsL e),
showTable "Aliases" (\(i,i') -> [show i++" -> "++show i']) $ M.toList (aliasesL e),
showTable "Equivs" (\(i,i') -> [show i++" -> "++show i']) $ M.toList (equivsL e),
showTable "Modules" (\(s,Range r) -> [s++" -> "++show r]) $ BM.toList (languagesL e),
showTable "Values" (\(i,v) -> [show i++" -> "++show v]) $ M.toList (valuesL e),
["Exports: "++show (exportsL e)],
["Load code: "++show (initializeL e)]]
empty = Language (toEnum 0) BM.empty M.empty M.empty BM.empty M.empty S.empty []
createSym e@(Language { maxIDL = m }) = (m,e { maxIDL = succ m })
setSymVal id v e = e { valuesL = M.insert id v (valuesL e) }
lookupSymName id e = BM.lookupR id (symbolsL e)
lookupSymVal id e = fromMaybe NoValue $ M.lookup id (valuesL e)
lookupSymMod id e = BM.lookupR (singleRange id) (languagesL e)
addExport id e = e { exportsL = S.insert id (exportsL e) }
getImports e = map fst $ BM.toList $ languagesL e
isImport im e = BM.member im (languagesL e)
exportSymVal id v = setSymVal id v . addExport id
internSym s e = runState (st $ BM.lookup s (symbolsL e)) e
where st (Just id) = return id
st _ = do
i <- state createSym
modifyF symsF (BM.insert s i)
return i
envCast t = T.mapM (state . intern) t
where intern "?" = createSym
intern str = internSym str
importLanguage getImport loadImport imp = merge imp
where
merge imp = gets language >>= \l -> ifThenElse (imp`isImport`l) (return False) $ do
(comp,l') <- getImport False imp
comps <- mapM merge [imp | (imp,_) <- BM.toList (languagesL l')]
let recomp = or comps
l' <- if not comp && recomp then do
(_,l') <- getImport True imp
mapM merge [imp | (imp,_) <- BM.toList (languagesL l')]
return l'
else return l'
mergeLanguage imp l'
loadImport l'
return $ comp || recomp
mergeLanguage imp l' = doF languageF $ do
let Language { symbolsL = syms' , languagesL = mods' , maxIDL = mi' } = l'
mapM_ (state . internSym) $ BM.keys syms'
Language { maxIDL = mi, symbolsL = syms } <- get
let aliases = [(i'+mi,fromJust $ BM.lookup s' syms)
| (s',i') <- BM.toList syms']
modify $ \l -> l {
maxIDL = mi+mi',
aliasesL = aliasesL l `M.union` M.fromList aliases,
equivsL = equivsL l `M.union` M.fromList (map swap aliases)
}
Language { aliasesL = al , languagesL = mods } <- get
let tr s = fromMaybe (tr' s) $ M.lookup (tr' s) al
tr' s' = fromMaybe (s' + mi) $ do
m <- lookupSymMod s' l'
Range (r,_) <- BM.lookup m mods
Range (r',_) <- BM.lookup m mods'
return $ s'-r'+r
newVals = M.mapKeys tr $ M.map (translate tr) $ valuesL l'
modify $ \l -> l {
languagesL = BM.insert imp (Range (mi,mi+mi')) mods,
valuesL = M.unionWith (\_ a -> a) (valuesL l) newVals,
exportsL = exportsL l S.\\ M.keysSet newVals
}
exportLanguage e = e {
symbolsL = BM.filter exportNameP (symbolsL e),
valuesL = vals',
aliasesL = M.empty,
equivsL = M.empty,
exportsL = S.empty,
initializeL = translate trans (initializeL e)
}
where set2Map s = M.fromAscList (zip (S.toAscList s) (repeat undefined))
Language { exportsL = ex, equivsL = eqs } = e
vals' = M.map (translate trans) $ M.intersection (valuesL e) (set2Map ex)
trans s = fromMaybe s $ M.lookup s eqs
refs = S.fromList $ concatMap references $ M.elems vals'
exportNameP _ s = (S.member s ex || S.member s refs)
&& not (M.member s eqs)
references (Verb code) = codeRefs code
references (Noun size init) = codeRefs size ++ codeRefs init
references _ = []