Changeset 4913 for src/Pugs/Compile.hs

Show
Ignore:
Timestamp:
06/22/05 20:40:31 (3 years ago)
Author:
bsmith
svk:copy_cache_prev:
6641
Message:

Moved the Compile class to Pugs.Compile. The interface to the compilers
is in Pugs.Trans (for the moment at least).

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • src/Pugs/Compile.hs

    r4871 r4913  
    1 {-# OPTIONS_GHC -fglasgow-exts #-} 
     1{-# OPTIONS_GHC -fglasgow-exts -fallow-undecidable-instances -fno-warn-orphans -funbox-strict-fields -cpp #-} 
    22 
    33{-| 
     
    1313import Pugs.AST 
    1414import Pugs.Internals 
    15 import Pugs.Compile.PIR (genPIR) 
    16 import Pugs.Compile.Pugs (genPugs) 
    17 import Pugs.Compile.Haskell (genGHC) 
    18  
    19 compile :: String -> Env -> IO String 
    20 compile "GHC"     env = fmap vCast $ runEvalIO env genGHC 
    21 compile "Ghc"     env = fmap vCast $ runEvalIO env genGHC 
    22 compile "Haskell" env = fmap vCast $ runEvalIO env genGHC 
    23 compile "Parrot"  env = fmap vCast $ runEvalIO env genPIR 
    24 compile "Pir"     env = fmap vCast $ runEvalIO env genPIR 
    25 compile "PIR"     env = fmap vCast $ runEvalIO env genPIR 
    26 compile "Pugs"    env = fmap vCast $ runEvalIO env genPugs 
    27 compile s _ = fail $ "Cannot compile to " ++ s 
    28  
     15import Pugs.Types 
     16import Pugs.Eval 
     17import Emit.PIR 
     18import Text.PrettyPrint 
     19 
     20{-| 
     21    The plan here is to first compile the environment (subroutines, 
     22    statements, etc.) to an abstract syntax tree ('PIL' -- Pugs Intermediate 
     23    Language) using the 'compile' function and 'Compile' class. 
     24-} 
     25 
     26#ifndef HADDOCK 
     27-- Type-indexed with GADT; it is a bit too baroque -- refactor toward ANF? 
     28data (Typeable a) => PIL a where 
     29    PNil        :: PIL [a] 
     30    PNoop       :: PIL Stmt 
     31 
     32    PRawName    :: !VarName -> PIL Expression -- XXX HACK! 
     33 
     34    PExp        :: !(PIL LValue) -> PIL Expression  
     35    PLit        :: !(PIL Literal) -> PIL Expression 
     36    PPos        :: !Pos -> !Exp -> !(PIL a) -> PIL a 
     37    PStmt       :: !(PIL Expression) -> PIL Stmt  
     38    PThunk      :: !(PIL Expression) -> PIL Expression  
     39    PCode       :: !SubType -> ![TParam] -> !(PIL [Stmt]) -> PIL Expression  
     40 
     41    PVal        :: !Val -> PIL Literal 
     42    PVar        :: !VarName -> PIL LValue 
     43 
     44    PStmts      :: !(PIL Stmt) -> !(PIL [Stmt]) -> PIL [Stmt] 
     45    PApp        :: !TCxt -> !(PIL Expression) -> ![PIL Expression] -> PIL LValue 
     46    PAssign     :: ![PIL LValue] -> !(PIL Expression) -> PIL LValue 
     47    PBind       :: ![PIL LValue] -> !(PIL Expression) -> PIL LValue 
     48    PPad        :: !Scope -> ![(VarName, PIL Expression)] -> !(PIL [Stmt]) -> PIL [Stmt] 
     49 
     50    PSub        :: !SubName -> !SubType -> ![TParam] -> !(PIL [Stmt]) -> PIL Decl 
     51#endif 
     52 
     53instance Typeable1 PIL where 
     54    typeOf1 _ = typeOf () 
     55 
     56data TParam = MkTParam 
     57    { tpParam   :: !Param 
     58    , tpDefault :: !(Maybe (PIL Expression)) 
     59    } 
     60    deriving (Show, Typeable) 
     61 
     62data TCxt 
     63    = TCxtVoid | TCxtLValue !Type | TCxtItem !Type | TCxtSlurpy !Type 
     64    | TTailCall !TCxt 
     65    deriving (Show, Eq, Typeable) 
     66 
     67tcVoid, tcLValue :: TCxt 
     68tcVoid      = TCxtVoid 
     69tcLValue    = TCxtLValue anyType 
     70 
     71{- 
     72tcItem, tcSlurpy :: TCxt 
     73tcItem      = TCxtItem anyType 
     74tcSlurpy    = TCxtSlurpy anyType 
     75-} 
     76 
     77instance Show (PIL a) where 
     78    show (PVal x) = "(PVal " ++ show x ++ ")" 
     79    show (PVar x) = "(PVar " ++ show x ++ ")" 
     80    show (PLit x) = "(PLit " ++ show x ++ ")" 
     81    show (PStmts x y) = "(PStmts " ++ show x ++ " " ++ show y ++ ")" 
     82    show PNil = "PNil" 
     83    show PNoop = "PNoop" 
     84    show (PPos x y z) = "(PPos " ++ show x ++ " " ++ show y ++ " " ++ show z ++ ")" 
     85    show (PApp x y z) = "(PApp " ++ show x ++ " " ++ show y ++ " " ++ show z ++ ")" 
     86    show (PExp x) = "(PExp " ++ show x ++ ")" 
     87    show (PStmt x) = "(PStmt " ++ show x ++ ")" 
     88    show (PAssign x y) = "(PAssign " ++ show x ++ " " ++ show y ++ ")" 
     89    show (PBind x y) = "(PBind " ++ show x ++ " " ++ show y ++ ")" 
     90    show (PThunk x) = "(PThunk " ++ show x ++ ")" 
     91    show (PRawName x) = "(PRawName " ++ show x ++ ")" 
     92    show (PPad x y z) = unwords ["(PPad", show x, show y, show z, ")"] 
     93    show (PCode x y z) = unwords ["(PCode", show x, show y, show z, ")"] 
     94    show (PSub x y z w) = unwords ["(PSub", show x, show y, show z, show w, ")"] 
     95 
     96data TEnv = MkTEnv 
     97    { tLexDepth :: !Int                 -- ^ Lexical scope depth 
     98    , tTokDepth :: !Int                 -- ^ Exp nesting depth 
     99    , tCxt      :: !TCxt                -- ^ Current context 
     100    , tReg      :: !(TVar (Int, String))-- ^ Register name supply 
     101    , tLabel    :: !(TVar Int)          -- ^ Label name supply 
     102    } 
     103    deriving (Show, Eq) 
     104 
     105type Comp a = Eval a 
     106type CompMonad = EvalT (ContT Val (ReaderT Env SIO)) 
     107 
     108{-| Currently only 'Exp' → 'PIL' -} 
     109class (Show a, Typeable b) => Compile a b where 
     110    compile :: a -> Comp b 
     111    compile x = fail ("Unrecognized construct: " ++ show x) 
     112 
     113-- Compile instances 
     114instance Compile (Var, [(TVar Bool, TVar VRef)]) (PIL Decl) where 
     115    compile = compError 
     116 
     117instance Compile Param TParam where 
     118    compile prm = do 
     119        defC <- if isOptional prm 
     120            then fmap Just $ compile (paramDefault prm) 
     121            else return Nothing 
     122        return $ MkTParam 
     123            { tpParam = prm 
     124            , tpDefault = defC 
     125            } 
     126 
     127{-| Compiles a 'Pad' to a list of 'PIL Decl's. Currently, only subroutines and 
     128    @\@*END@ are compiled. -} 
     129instance Compile Pad [PIL Decl] where 
     130    compile pad = do 
     131        entries' <- mapM canCompile entries 
     132        return $ concat entries' 
     133        where 
     134        entries = sortBy padSort $ padToList pad 
     135        canCompile (name@('&':_), [(_, sym)]) = do 
     136            ref <- liftSTM $ readTVar sym 
     137            case ref of 
     138                MkRef (ICode cv) 
     139                    -> doCode name =<< code_fetch cv 
     140                MkRef (IScalar sv) | scalar_iType sv == mkType "Scalar::Const" 
     141                    -> doCode name =<< fromVal =<< scalar_fetch sv 
     142                _ -> return [] 
     143        canCompile ("@*END", [(_, sym)]) = do 
     144            ref     <- liftSTM $ readTVar sym 
     145            cvList  <- fromVals =<< readRef ref :: Comp [VCode] 
     146            decls   <- eachM cvList $ \(i, cv) -> do 
     147                compile (("&*END_" ++ show i), cv) :: Comp [PIL Decl] 
     148            compile ("&*END", concat decls) 
     149        canCompile ((_:twigil:_), _) | not (isAlphaNum twigil) = return [] 
     150        canCompile (name, [(_, sym)]) = do 
     151            -- translate them into store_global calls? 
     152            -- placing them each into one separate init function? 
     153            val     <- readRef =<< liftSTM (readTVar sym) 
     154            valC    <- compile val 
     155            let assignC = PAssign [PVar name'] valC 
     156                bodyC   = PStmts (PStmt . PExp $ assignC) PNil 
     157                initL   = "__init_" ++ (render $ varText name) 
     158                name' | ':' `elem` name = name 
     159                      | otherwise = "main::" ++ name -- XXX wrong 
     160            return [PSub initL SubPrim [] bodyC] 
     161        canCompile _ = return [] 
     162        doCode name vsub = case subBody vsub of 
     163            Prim _  -> return [] 
     164            _       -> compile (name, vsub) 
     165 
     166eachM :: (Monad m) => [a] -> ((Int, a) -> m b) -> m [b] 
     167eachM = forM . ([0..] `zip`) 
     168 
     169instance Compile (SubName, [PIL Decl]) [PIL Decl] where 
     170    compile (name, decls) = do 
     171        let bodyC = [ PStmts . PStmt . PExp $ PApp tcVoid (PExp (PVar sub)) [] 
     172                    | PSub sub _ _ _ <- decls 
     173                    ] 
     174        return (PSub name SubPrim [] (combine bodyC PNil):decls) 
     175 
     176instance Compile (SubName, VCode) [PIL Decl] where 
     177    compile (name, vsub) | packageOf name /= packageOf (subName vsub) = do 
     178        let storeC  = PBind [PVar $ qualify name] (PExp . PVar . qualify $ subName vsub) 
     179            bodyC   = PStmts (PStmt . PExp $ storeC) PNil 
     180            exportL = "__export_" ++ (render $ varText name) 
     181        return [PSub exportL SubPrim [] bodyC] 
     182    compile (name, vsub) = do 
     183        bodyC   <- enter cxtItemAny . compile $ case subBody vsub of 
     184            Syn "block" [body]  -> body 
     185            body                -> body 
     186        paramsC <- compile $ subParams vsub 
     187        return [PSub name (subType vsub) paramsC bodyC] 
     188 
     189instance Compile (String, [(TVar Bool, TVar VRef)]) (PIL Expression) where 
     190    compile (name, _) = return $ PRawName name 
     191 
     192instance Compile Exp (PIL [Stmt]) where 
     193    compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest 
     194    compile (Cxt cxt rest) = enter cxt $ compile rest 
     195    compile (Stmts (Pad SOur _ exp) rest) = do 
     196        compile $ mergeStmts exp rest 
     197    compile (Stmts (Pad _ pad exp) rest) = do 
     198        expC    <- compile $ mergeStmts exp rest 
     199        padC    <- compile $ padToList pad 
     200        return $ PPad SMy ((map fst $ padToList pad) `zip` padC) expC 
     201    compile exp = compileStmts exp 
     202 
     203class EnterClass m a where 
     204    enter :: a -> m b -> m b 
     205 
     206instance EnterClass CompMonad VCode where 
     207    enter sub = local (\e -> e{ envLValue = subLValue sub, envContext = CxtItem (subReturns sub) }) 
     208 
     209instance EnterClass CompMonad Cxt where 
     210    enter cxt = local (\e -> e{ envContext = cxt }) 
     211 
     212compileStmts :: Exp -> Comp (PIL [Stmt]) 
     213compileStmts exp = case exp of 
     214    Stmts this Noop -> do 
     215        thisC   <- compile this 
     216        return $ PStmts (tailCall thisC) PNil 
     217        where 
     218        tailCall (PStmt (PExp (PApp cxt fun args))) 
     219            = PStmt $ PExp $ PApp (TTailCall cxt) fun args 
     220        tailCall (PPos pos exp x) = PPos pos exp (tailCall x) 
     221        tailCall x = x 
     222    Stmts this rest -> do 
     223        thisC   <- enter cxtVoid $ compile this 
     224        restC   <- compileStmts rest 
     225        return $ PStmts thisC restC 
     226    Noop        -> return PNil 
     227    _           -> compile (Stmts exp Noop) 
     228 
     229instance Compile Val (PIL Stmt) where 
     230    compile = fmap PStmt . compile . Val 
     231 
     232instance Compile Val (PIL Expression) where 
     233    compile = compile . Val 
     234 
     235instance Compile Exp (PIL Stmt) where 
     236    compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest 
     237    compile (Cxt cxt rest) = enter cxt $ compile rest 
     238    compile Noop = return PNoop 
     239    compile (Val val) = do 
     240        cxt     <- asks envContext 
     241        if isVoidCxt cxt 
     242            then case val of 
     243                VBool True      -> compile Noop 
     244                _               -> do 
     245                    warn "Useless use of a constant in void context" val 
     246                    compile Noop 
     247            else compile val 
     248    compile (Syn "loop" [exp]) = 
     249        compile (Syn "loop" $ [emptyExp, Val (VBool True), emptyExp, exp]) 
     250    compile (Syn "loop" [pre, cond, post, (Syn "block" [body])]) = do 
     251        preC    <- compile pre 
     252        condC   <- compile cond 
     253        bodyC   <- compile body 
     254        postC   <- compile post 
     255        funC    <- compile (Var "&statement_control:loop") 
     256        return . PStmt . PExp $ PApp TCxtVoid funC 
     257            [preC, pBlock condC, pBlock bodyC, pBlock postC] 
     258    compile exp@(Syn "unless" _) = fmap (PStmt . PExp) $ compConditional exp 
     259    compile exp@(Syn "while" _) = compLoop exp 
     260    compile exp@(Syn "until" _) = compLoop exp 
     261    compile exp@(Syn "postwhile" _) = compLoop exp 
     262    compile exp@(Syn "postuntil" _) = compLoop exp 
     263    compile (Syn "for" [exp, body]) = do 
     264        expC    <- compile exp 
     265        bodyC   <- compile body 
     266        funC    <- compile (Var "&statement_control:for") 
     267        return . PStmt . PExp $ PApp TCxtVoid funC [expC, bodyC] 
     268    compile (Syn "given" _) = compile (Var "$_") -- XXX 
     269    compile (Syn "when" _) = compile (Var "$_") -- XXX 
     270    compile exp = fmap PStmt $ compile exp 
     271 
     272pBlock :: PIL [Stmt] -> PIL Expression 
     273pBlock = PCode SubBlock [] 
     274 
     275{- 
     276subTCxt :: VCode -> Eval TCxt 
     277subTCxt sub = return $ if subLValue sub 
     278    then TCxtLValue (subReturns sub) 
     279    else TCxtItem (subReturns sub) 
     280-} 
     281 
     282askTCxt :: Eval TCxt 
     283askTCxt = do 
     284    env <- ask 
     285    return $ if envLValue env 
     286        then TCxtLValue (typeOfCxt $ envContext env) 
     287        else case envContext env of 
     288            CxtVoid         -> TCxtVoid 
     289            CxtItem typ     -> TCxtItem typ 
     290            CxtSlurpy typ   -> TCxtSlurpy typ 
     291 
     292instance (Show (m a), FunctorM m, Typeable1 m, Compile a b) => Compile (m a) (m b) where 
     293    compile = fmapM compile 
     294 
     295instance (Compile a b, Compile a c) => Compile [a] (b, c) where 
     296    compile [x, y] = do { x' <- compile x ; y' <- compile y; return (x', y') } 
     297    compile x = compError x 
     298 
     299instance (Compile a b, Compile a c, Compile a d) => Compile [a] (b, c, d) where 
     300    compile [x, y, z] = do { x' <- compile x ; y' <- compile y; z' <- compile z; return (x', y', z') } 
     301    compile x = compError x 
     302 
     303instance Compile Exp (PIL LValue) where 
     304    compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest 
     305    compile (Cxt cxt rest) = enter cxt $ compile rest 
     306    compile (Var name) = return $ PVar name 
     307    compile (Syn (sigil:"::()") exps) = do 
     308        compile $ App (Var "&Pugs::Internals::symbolic_deref") Nothing $ 
     309            (Val . VStr $ sigil:""):exps 
     310    compile (App (Var "&goto") (Just inv) args) = do 
     311        cxt     <- askTCxt 
     312        funC    <- compile inv 
     313        argsC   <- enter cxtItemAny $ compile args 
     314        return $ PApp (TTailCall cxt) funC argsC 
     315    compile (App fun (Just inv) args) = do 
     316        compile (App fun Nothing (inv:args)) -- XXX WRONG 
     317    compile (App fun Nothing args) = do 
     318        cxt     <- askTCxt 
     319        funC    <- compile fun 
     320        argsC   <- enter cxtItemAny $ compile args 
     321        return $ PApp cxt funC argsC 
     322    compile exp@(Syn "if" _) = compConditional exp 
     323    compile (Syn "{}" (x:xs)) = compile $ App (Var "&postcircumfix:{}") (Just x) xs 
     324    compile (Syn "[]" (x:xs)) = do 
     325        compile (App (Var "&postcircumfix:[]") (Just x) xs) 
     326    compile (Syn "," exps) = do 
     327        compile (App (Var "&infix:,") Nothing exps) 
     328    compile (Syn "\\[]" exps) = do 
     329        compile (App (Var "&circumfix:[]") Nothing exps) 
     330    compile (Syn "\\{}" exps) = do 
     331        compile (App (Var "&circumfix:{}") Nothing exps) 
     332    compile (Syn "=" [lhs, rhs]) = do 
     333        lhsC <- enterLValue $ compile lhs 
     334        rhsC <- enterRValue $ compile rhs 
     335        return $ PAssign [lhsC] rhsC 
     336    compile (Syn ":=" exps) = do 
     337        (lhsC, rhsC) <- enterLValue $ compile exps 
     338        return $ PBind [lhsC] rhsC 
     339    compile (Syn syn [lhs, exp]) | last syn == '=' = do 
     340        let op = "&infix:" ++ init syn 
     341        compile $ Syn "=" [lhs, App (Var op) Nothing [lhs, exp]] 
     342    compile exp = compError exp 
     343 
     344compLoop :: Exp -> Comp (PIL Stmt) 
     345compLoop (Syn name [cond, body]) = do 
     346    cxt     <- askTCxt 
     347    condC   <- enter (CxtItem $ mkType "Bool") $ compile cond 
     348    bodyC   <- enter CxtVoid $ compile body 
     349    funC    <- compile (Var $ "&statement_control:" ++ name) 
     350    return . PStmt . PExp $ PApp cxt funC [pBlock condC, pBlock bodyC] 
     351compLoop exp = compError exp 
     352 
     353{-| Compiles a conditional 'Syn' (@if@ and @unless@) to a call to an 
     354    appropriate function call (@&statement_control:if@ or 
     355    @&statement_control:unless@). -} 
     356compConditional :: Exp -> Comp (PIL LValue) 
     357compConditional (Syn name exps) = do 
     358    [condC, trueC, falseC] <- compile exps 
     359    funC    <- compile $ Var ("&statement_control:" ++ name) 
     360    cxt     <- askTCxt 
     361    return $ PApp cxt funC [condC, PThunk trueC, PThunk falseC] 
     362compConditional exp = compError exp 
     363 
     364{-| Compiles various 'Exp's to 'PIL Expression's. -} 
     365instance Compile Exp (PIL Expression) where 
     366    compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest 
     367    compile (Cxt cxt rest) = enter cxt $ compile rest 
     368    compile (Var name) = return . PExp $ PVar name 
     369    compile exp@(Val (VCode _)) = compile $ Syn "sub" [exp] 
     370    compile (Val val) = fmap PLit $ compile val 
     371    compile Noop = compile (Val undef) 
     372    compile (Syn "block" [body]) = do 
     373        cxt     <- askTCxt 
     374        bodyC   <- compile body 
     375        return $ PExp $ PApp cxt (pBlock bodyC) [] 
     376    compile (Syn "sub" [Val (VCode sub)]) = do 
     377        bodyC   <- enter sub $ compile $ case subBody sub of 
     378            Syn "block" [exp]   -> exp 
     379            exp                 -> exp 
     380        paramsC <- compile $ subParams sub 
     381        return $ PCode (subType sub) paramsC bodyC 
     382    compile (Syn "module" _) = compile Noop 
     383    compile (Syn "match" exp) = compile $ Syn "rx" exp -- wrong 
     384    compile (Syn "//" exp) = compile $ Syn "rx" exp 
     385    compile (Syn "rx" [exp, _]) = compile exp -- XXX WRONG - use PCRE 
     386    compile (Syn "subst" [exp, _, _]) = compile exp -- XXX WRONG - use PCRE 
     387    compile exp@(App _ _ _) = fmap PExp $ compile exp 
     388    compile exp@(Syn _ _) = fmap PExp $ compile exp 
     389    compile exp = compError exp 
     390 
     391compError :: forall a b. Compile a b => a -> Comp b 
     392compError = die $ "Compile error -- invalid " 
     393    ++ (show $ typeOf (undefined :: b)) 
     394 
     395{-| Compiles a 'Val' to a 'PIL Literal'. -} 
     396instance Compile Val (PIL Literal) where 
     397    compile val = return $ PVal val 
     398 
     399die :: (MonadIO m, Show a) => String -> a -> m b 
     400die x y = do 
     401    warn x y 
     402    liftIO $ exitFailure 
     403 
     404warn :: (MonadIO m, Show a) => String -> a -> m () 
     405warn str val = liftIO $ do 
     406    hPutStrLn stderr $ "*** " ++ str ++ ":\n    " ++ show val 
     407 
     408-- utility functions 
     409padSort :: (Var, [(TVar Bool, TVar VRef)]) -> (String, [(a, b)]) -> Ordering 
     410padSort (a, [(_, _)]) (b, [(_, _)]) 
     411    | (head a == ':' && head b == '&') = LT 
     412    | (head b == ':' && head a == '&') = GT 
     413    | otherwise = GT 
     414padSort _ _ = EQ 
     415 
     416varText :: String -> Doc 
     417varText ('$':name)  = text $ "s__" ++ escaped name 
     418varText ('@':name)  = text $ "a__" ++ escaped name 
     419varText ('%':name)  = text $ "h__" ++ escaped name 
     420varText ('&':name)  = text $ "c__" ++ escaped name 
     421varText x           = error $ "invalid name: " ++ x 
     422 
     423packageOf :: String -> String 
     424packageOf name = case isQualified name of 
     425    Just (pkg, _)   -> pkg 
     426    _               -> "main" 
     427 
     428qualify :: String -> String 
     429qualify name = case isQualified name of 
     430    Just _  -> name 
     431    _       -> let (sigil, name') = span (not . isAlphaNum) name 
     432        in sigil ++ "main::" ++ name' 
     433 
     434isQualified :: String -> Maybe (String, String) 
     435isQualified name | Just (post, pre) <- breakOnGlue "::" (reverse name) = 
     436    let (sigil, pkg) = span (not . isAlphaNum) preName 
     437        name'       = possiblyFixOperatorName (sigil ++ postName) 
     438        preName     = reverse pre 
     439        postName    = reverse post 
     440    in Just (pkg, name') 
     441isQualified _ = Nothing