packages feed

hat-2.7.0.0: trans/AuxLabelAST.hs

module AuxLabelAST
  ( auxLabelSyntaxTree
  ) where


import Data.List (nubBy)
import Data.Char (isUpper)
import Data.Maybe (isJust)
import AuxTypes(Environment,mkIdentMap,useIdentMap,useEnvironment
               ,Identifier(..)
               ,AuxiliaryInfo(letBound),InitAuxInfo,initAuxInfo,defaultAuxInfo)
import AuxFile(Visibility,PatSort(Refutable,Irrefutable)
              ,extendEnv,getImports,addPat,foldrPat)
import AuxFixity(fixInfixList)
import TraceId
import Flags(Flags(sDbgTrusted))
import Syntax
import SyntaxUtil (infixFun)
import TokenId (TokenId(..))
import AssocTree
import Extra (Pos,noPos)


-- `auxLabelSyntaxTree' relabels the entire abstract syntax tree,
-- replacing TokenId with TraceId (which basically adds arity and
-- binding information for each variable name).  Along the way, we
-- also need to resolve the fixity of all applications (originally
-- done in a later phase of the compiler).

auxLabelSyntaxTree :: Flags -> Module TokenId 
                   -> IO (Environment,Module TraceId)
auxLabelSyntaxTree flags
	mod@(Module p modId exports imports fixdecls (DeclsParse decls)) =
  do
    let (identMap,_) = mkIdentMap decls
    (importenv,hiddenEnvs) <- 
      getImports (\_->vi) (initAT,identMap) flags imports
    let (irrefutableIds,totalenv) = 
          extendEnv totalenv iai vi importenv 
            (map DeclFixity fixdecls ++ decls)
    let Module p modId exports imports fixdecls decls = 
          relabelModule iai totalenv importenv hiddenEnvs mod
    return $ (totalenv,Module p modId exports imports fixdecls 
                        (addVars iai totalenv irrefutableIds decls))
  where
  iai = initAuxInfo . not . sDbgTrusted $ flags


-- `vi' is a degenerate visibility function.  When writing the .hx file,
-- visibility in the export list is important, but when relabeling the
-- syntax tree, everything is visible.
vi :: Visibility
vi = \_-> True


-- `letVar' and `lookEnv' build a TraceId for any TokenId by
-- looking up the arity information in the environment.  For letVar,
-- the distinction between let-bound and lambda-bound variables
-- is decided by the caller, but for `lookEnv', it is decided by the
-- environment.


letVar :: Environment -> TokenId -> TraceId
letVar env id =
  case useEnvironment env id of
    Just info | letBound info -> id `plus` info
    _ -> error ("AuxLabelAST.letVar: "++show id++" not let-bound in env")

lookEnv :: Environment -> TokenId -> TraceId
lookEnv env id =
  case useEnvironment env id of
    Just info -> id `plus` info
    _ -> case id of
           -- this is a horrible hack to by-pass qualified names.
           -- (only needed for use of current module as qualifier?)
           Qualified _ x -> case useEnvironment env (Visible x) of
                              Just info -> id `plus` info
                              _ -> stop
           _ -> stop
  where
  stop = error ("Variable or constructor not in scope: " ++ show id)

lookupTyCls :: Environment -> TokenId -> TraceId
lookupTyCls (auxTree,_) id =
  case lookupAT auxTree (TypeClass (show id)) of
    Just info -> id `plus` info
    Nothing -> mkTyCon defaultAuxInfo id
               -- type or class not in scope, esp. predefined ones

-- The class `Relabel' walks the abstract syntax tree, relabelling all
-- TokenId to TraceId.  Most instances are pretty trivial - the only
-- interesting ones are at the end of this section.

class Relabel g where
  relabel :: InitAuxInfo -> Environment -> g TokenId -> g TraceId

relabelModule :: InitAuxInfo -> Environment -> Environment -> [Environment] 
              -> Module TokenId -> Module TraceId
relabelModule iai env impEnv hiddenEnvs 
  (Module p mod Nothing imps fixs decls) =
    Module p (mkModule iai mod) Nothing 
      (zipWith (relabelImports iai impEnv) hiddenEnvs imps) []
      (relabel iai env decls)
relabelModule iai env impEnv hiddenEnvs 
  (Module p mod (Just exps) imps fixs decls) =
    Module p (mkModule iai mod) (Just (map (relabel iai env) exps))
      (zipWith (relabelImports iai impEnv) hiddenEnvs imps) [] 
      (relabel iai env decls)
					-- fixdecls are folded into the decls

instance Relabel Export where
  relabel iai env (ExportEntity pos entity) = 
    ExportEntity pos (relabel iai env entity)
  relabel iai env (ExportModid pos id)      = 
    ExportModid pos (mkModule iai id)


relabelImports iai env hiddenEnv (Import (pos,id) impspec) =
  Import (pos,mkModule iai id) (relabelImpSpec iai env hiddenEnv impspec)
relabelImports iai env hiddenEnv (ImportQ (pos,id) impspec) =
  ImportQ (pos,mkModule iai id) (relabelImpSpec iai env hiddenEnv impspec)
relabelImports iai env hiddenEnv (ImportQas (p1,id1) (p2,id2) impspec) =
  ImportQas (p1,mkModule iai id1) (p2,mkModule iai id2) 
    (relabelImpSpec iai env hiddenEnv impspec)
relabelImports iai env hiddenEnv (Importas (p1,id1) (p2,id2) impspec) =
  Importas (p1,mkModule iai id1) (p2,mkModule iai id2) 
    (relabelImpSpec iai env hiddenEnv impspec)

relabelImpSpec iai env hiddenEnv (NoHiding entities) = 
  NoHiding (map (relabel iai env) entities)
relabelImpSpec iai env hiddenEnv (Hiding entities)   = 
  Hiding (map (relabel iai hiddenEnv) entities)

instance Relabel Entity where
  relabel _ env (EntityVar p id) = 
    EntityVar p (lookEnv env id)
  relabel _ env (EntityConClsAll p id) = 
    EntityConClsAll p (lookupTyCls env id)
  relabel _ env (EntityConClsSome p id cons) = 
    EntityConClsSome p (lookupTyCls env id) (relabelRealPosIds env cons)

instance Relabel InfixClass where
  relabel _ env InfixDef = InfixDef
  relabel _ env InfixL = InfixL
  relabel _ env InfixR = InfixR
  relabel _ env Infix  = Infix
  relabel iai env (InfixPre x) = (InfixPre (mkLambdaBound iai x))

instance Relabel FixId where
  relabel _ env (FixCon p i) = FixCon p (lookEnv env i)
  relabel _ env (FixVar p i) = FixVar p (lookEnv env i)

instance Relabel Decls where
  relabel iai env (DeclsParse decls) = DeclsParse (map (relabel iai env) decls)
  relabel iai env (DeclsScc deps)    = DeclsScc (map (relabel iai env) deps)

instance Relabel DeclsDepend where
  relabel iai env (DeclsNoRec decl) = DeclsNoRec (relabel iai env decl)
  relabel iai env (DeclsRec decls)  = DeclsRec (map (relabel iai env) decls)

instance Relabel Decl where
  relabel iai env (DeclType s typ) = 
    DeclType (relabel iai env s) (relabel iai env typ)
  relabel iai env (DeclTypeRenamed p n) = DeclTypeRenamed p n
  relabel iai env (DeclData mb ctxs simp constrs pis) =
    DeclData mb (map (relabel iai env) ctxs) (relabel iai env simp)
      (map (relabel iai env) constrs) (relabelPosIds iai pis)
  relabel iai env (DeclDataPrim p i n) = -- used?
    DeclDataPrim p (mkLambdaBound iai i) n
  relabel iai env (DeclConstrs p i piis) = -- used?
    DeclConstrs p (mkLambdaBound iai i)
      (map (\(p,i1,i2)->(p,mkLambdaBound iai i1,mkLambdaBound iai i2)) piis)
  relabel iai env (DeclClass p ctxs cls vars fundeps decls) =
    DeclClass p (map (relabel iai env) ctxs) (mkClass iai cls)
      (map (mkTyVar iai) vars) (map (relabel iai env) fundeps)
      (relabel iai env decls)
  relabel iai env (DeclInstance p ctxs cls insts decls) =
    DeclInstance p (map (relabel iai env) ctxs) (mkClass iai cls)
      (map (relabel iai env) insts) (relabel iai env decls)
  relabel iai env (DeclDefault typs) =
    DeclDefault (map (relabel iai env) typs)
  relabel iai env (DeclPrimitive p i n typ) = -- used?
    DeclPrimitive p (letVar env i) n (relabel iai env typ)
  relabel iai env (DeclForeignImp p callConv str i1 n fspec typ i2) =
    DeclForeignImp p callConv str (letVar env i1) n fspec (relabel iai env typ)
      (mkLambdaBound iai i2)
  relabel iai env (DeclForeignExp p callConv str id typ) =
    DeclForeignExp p callConv str (mkLambdaBound iai id) (relabel iai env typ)
  relabel iai env (DeclVarsType pis ctxs typ) =
    DeclVarsType (relabelRealPosIds env pis) (map (relabel iai env) ctxs)
      (relabel iai env typ)
  relabel iai env (DeclPat (Alt (ExpInfixList p exps) rhs decls))
    | isJust infixFunExps 
    = relabel iai env (DeclFun pos fun [Fun [e1,e2] rhs decls])
    where
    infixFunExps = infixFun exps
    Just (e1,pos,fun,e2) = infixFunExps
  relabel iai env (DeclPat (Alt pat rhs ds@(DeclsParse decls))) =
    let (irrefutableDeclIds,newEnv) = extendEnv undefined iai vi env decls
    in  DeclPat 
          (Alt (relabel iai newEnv pat) (relabel iai newEnv rhs) 
            (addVars iai newEnv (nubBy (\x y -> show x == show y) -- for scope 
              irrefutableDeclIds) 
              (relabel iai newEnv ds)))
          -- dont' use relable Alt, because that extends environment also
          -- by variables in the pattern
  relabel iai env (DeclFun p f funs) =
    DeclFun p 
      -- ensure that defined id always with arity, even in class/instance
      (modArity (letVar env f) (funArity . head $ funs))
      (map (relabel iai env) funs)
  relabel _ env (DeclIgnore str) = DeclIgnore str
  relabel _ env (DeclError str) = DeclError str
  relabel iai env (DeclAnnot decl annots) =
	DeclAnnot (relabel iai env decl) (map (relabel iai env) annots)
  relabel iai env (DeclFixity (fixclass,n,fixids)) =
	DeclFixity (relabel iai env fixclass, n, map (relabel iai env) fixids)

instance Relabel Annot where
  relabel iai env (AnnotArity (p,id) n) = AnnotArity (p,mkLambdaBound iai id) n
  relabel iai env (AnnotPrimitive (p,id) pstr) = 
    AnnotPrimitive (p,mkLambdaBound iai id) pstr
  relabel iai env (AnnotNeed idss) = 
    AnnotNeed (map (map (mkLambdaBound iai)) idss)
  relabel _ env (AnnotUnknown) = AnnotUnknown

instance Relabel Rhs where
  relabel iai env (Unguarded exp)  = Unguarded (relabel iai env exp)
  relabel iai env (Guarded gdexps) =
    Guarded (map (\(gd,exp)-> (relabel iai env gd, relabel iai env exp)) 
      gdexps)

instance Relabel Type where
  relabel iai env (TypeCons p c typs) = 
    TypeCons p (lookupTyCls env c) (map (relabel iai env) typs)
  relabel iai env (TypeApp t1 t2) = 
    TypeApp (relabel iai env t1) (relabel iai env t2)
  relabel iai env (TypeVar p v)       = 
    TypeVar p (mkTyVar iai v)
  relabel iai env (TypeStrict p t)    = 
    TypeStrict p (relabel iai env t)

instance Relabel Sig where
  relabel iai env (Sig pis typ) = 
    Sig (relabelPosIds iai pis) (relabel iai env typ)

instance Relabel Simple where
  relabel iai env (Simple p id pis) = 
    Simple p (mkTyCon iai id) (relabelPosIds iai pis)

instance Relabel Context where
  relabel iai env (Context p id pis) = 
    Context p (mkClass iai id) (relabelPosIds iai pis)

instance Relabel Constr where
  relabel iai env (Constr p id mbs) =
    Constr p (lookEnv env id) (map locust mbs)
    where 
    locust (Nothing,typ) = (Nothing,relabel iai env typ)
    locust (Just pis,typ) = 
      (Just (relabelRealPosIds env pis),relabel iai env typ)
  relabel iai env (ConstrCtx fvs ctxs p id mbs) =
    ConstrCtx (relabelPosIds iai fvs) (map (relabel iai env) ctxs) p
      (lookEnv env id) (map locust mbs)
      where 
      locust (Nothing,typ) = (Nothing,relabel iai env typ)
      locust (Just pis,typ) = 
        (Just (relabelRealPosIds env pis),relabel iai env typ)

instance Relabel Field where
  relabel iai env (FieldExp p id exp) = 
    FieldExp p (mkField iai id) (relabel iai env exp)
  relabel iai env (FieldPun p id) = FieldPun p (mkField iai id)

instance Relabel Stmt where
  relabel iai env (StmtExp exp)      = StmtExp (relabel iai env exp)
  relabel iai env (StmtBind pat exp) = 
    StmtBind (relabel iai env pat) (relabel iai env exp)
  relabel iai env (StmtLet decls)    = StmtLet (relabel iai env decls)

instance Relabel Qual where
  relabel iai env (QualPatExp pat exp) = 
    QualPatExp (relabel iai env pat) (relabel iai env exp)
  relabel iai env (QualExp exp) = QualExp (relabel iai env exp)
  relabel iai env (QualLet decls) = QualLet (relabel iai env decls)

instance Relabel FunDep where
  relabel iai env (as :->: bs) =
        (map (mkTyVar iai) as) :->: (map (mkTyVar iai) bs)


-- This is where the non-trivial syntax types start.  Local defns (let-bound)
-- and lhs patterns (lambda-bound) must be added to the environment before
-- relabeling the rhs of a function or binding.

instance Relabel Fun where
  relabel iai env (Fun pats rhs ds@(DeclsParse decls)) =
    let (irrefutableDeclIds,declEnv) = extendEnv undefined iai vi env decls
        (irrefutableIds,newEnv) = 
          foldrPat (addPat iai Refutable vi) declEnv pats 
    in
      Fun (map (relabel iai newEnv) pats) (relabel iai newEnv rhs) 
        (addVars iai newEnv 
          (nubBy (\x y -> show x == show y) -- for shadowing of scopes
            (irrefutableDeclIds++irrefutableIds)) 
          (relabel iai newEnv ds))

instance Relabel Alt where
  -- only used for Alts in cases, not in pattern bindings
  relabel iai env (Alt pat rhs ds@(DeclsParse decls)) =
    let (irrefutableDeclIds,declEnv) = extendEnv undefined iai vi env decls
        (irrefutableIds,newEnv) = 
          addPat iai Refutable vi pat declEnv
    in
      Alt (relabel iai newEnv pat) (relabel iai newEnv rhs) 
        (addVars iai newEnv (nubBy (\x y -> show x == show y) -- for scope 
          (irrefutableDeclIds++irrefutableIds)) 
        (relabel iai newEnv ds))

instance Relabel Exp where
  relabel iai env (ExpScc str exp) = ExpScc str (relabel iai env exp)
  relabel iai env (ExpDict exp) = ExpDict (relabel iai env exp)
  relabel iai env (ExpFatbar e1 e2) = 
    ExpFatbar (relabel iai env e1) (relabel iai env e2)
  relabel iai env (ExpFail) = ExpFail
  relabel iai env (ExpLambda p pats exp) =
	let (irrefutableIds,newEnv) = 
              foldrPat (addPat iai Refutable vi) env pats in
	ExpLambda p (map (relabel iai newEnv) pats) 
          ((if null irrefutableIds 
             then id else ExpLet p (addVars iai newEnv irrefutableIds noDecls))
            (relabel iai newEnv exp))
  relabel iai env (ExpLet p ds@(DeclsParse decls) exp) =
	let (irrefutableIds,newEnv) = extendEnv undefined iai vi env decls in
	ExpLet p (addVars iai newEnv irrefutableIds (relabel iai newEnv ds)) 
          (relabel iai newEnv exp)
  relabel iai env (ExpDo p stmts) =
	ExpDo p (doStmts env stmts)
    where doStmts env [] = []
	  doStmts env (s@(StmtExp _):ss) = relabel iai env s: doStmts env ss
	  doStmts env (s@(StmtBind pat _):ss) =
		let (irrefutableIds,newEnv) = addPat iai Refutable vi pat env 
                in
		relabel iai newEnv s : 
                (if null irrefutableIds 
                   then id 
                   else (StmtLet (addVars iai newEnv irrefutableIds noDecls):))
                  (doStmts newEnv ss)
	  doStmts env (s@(StmtLet (DeclsParse decls)):ss) =
		let (irrefutableIds,newEnv) = 
                      extendEnv undefined iai vi env decls 
                    StmtLet reDecls = relabel iai newEnv s
                in (StmtLet (addVars iai newEnv irrefutableIds reDecls) 
                   : doStmts newEnv ss)
  relabel iai env (ExpCase p exp alts) =
    ExpCase p (relabel iai env exp) (map (relabel iai env) alts)
  relabel iai env (ExpIf p cond thn els) =
    ExpIf p (relabel iai env cond) (relabel iai env thn) (relabel iai env els)
  relabel iai env (ExpType p exp ctxs typ) =
    ExpType p (relabel iai env exp) (map (relabel iai env) ctxs) 
      (relabel iai env typ)
  relabel iai env (ExpRecord exp fields) =
    ExpRecord (relabel iai env exp) (map (relabel iai env) fields)
  relabel iai env (ExpApplication p exps) =
    ExpApplication p (map (relabel iai env) exps)
  relabel _ env (ExpVar p id) = ExpVar p (lookEnv env id)
  relabel _ env (ExpCon p id)   = ExpCon p (lookEnv env id)
  relabel _ env (ExpVarOp p id) = ExpVarOp p (lookEnv env id)
  relabel _ env (ExpConOp p id) = ExpConOp p (lookEnv env id)
  relabel iai env (ExpInfixList p exps) = 
    relabel iai env (fixInfixList env exps)
  relabel _ env (ExpLit p lit)   = ExpLit p lit
  relabel iai env (ExpList p exps) = ExpList p (map (relabel iai env) exps)
  relabel iai env (PatAs p id pat) =
    PatAs p (lookEnv env id) (relabel iai env pat)
  relabel _ env (PatWildcard p)  = PatWildcard p
  relabel iai env (PatIrrefutable p pat) = 
    PatIrrefutable p (relabel iai env pat)
  relabel iai env (PatNplusK p id1 id2 exp1 exp2 exp3) = -- *** No, No, NO
    PatNplusK p (mkLambdaBound iai id1) (mkLambdaBound iai id2)
      (relabel iai env exp1) (relabel iai env exp2) (relabel iai env exp3)


-- `relabelPosIds' does the simplest possible renaming of a list of
-- position/id pairs from the TokenId type to TraceId type.
relabelPosIds :: InitAuxInfo -> [(Pos,TokenId)] -> [(Pos,TraceId)]
relabelPosIds iai = map (\(p,i)->(p,mkLambdaBound iai i))

-- `relabelRealPosIds' does the correct (as opposed to simplest) renaming
-- of a list of position/id pairs from the TokenId type to TraceId type.
relabelRealPosIds :: Environment -> [(Pos,TokenId)] -> [(Pos,TraceId)]
relabelRealPosIds env = map (\(p,i)->(p,lookEnv env i))

-- Create definitions for let-bound variants of irrefutable variables.
addVars :: InitAuxInfo -> Environment -> [TokenId] -> Decls TraceId 
        -> Decls TraceId
addVars iai env irrefutableIds (DeclsParse ds) =
  DeclsParse (map mkDef irrefutableIds ++ ds)
  where
  mkDef id = 
    DeclFun noPos traceId
      [Fun [] 
        (Unguarded (ExpVar noPos (modLambdaBound iai traceId))) noDecls]
    where  
    traceId = lookEnv env id