| 28 | | |
| 29 | | #ifndef HADDOCK |
| 30 | | -- Type-indexed with GADT; it is a bit too baroque -- refactor toward ANF? |
| 31 | | data (Typeable a) => PIL a where |
| 32 | | PNil :: PIL [a] |
| 33 | | PNoop :: PIL Stmt |
| 34 | | |
| 35 | | PRawName :: !VarName -> PIL Expression -- XXX HACK! |
| 36 | | |
| 37 | | PExp :: !(PIL LValue) -> PIL Expression |
| 38 | | PLit :: !(PIL Literal) -> PIL Expression |
| 39 | | PPos :: !Pos -> !Exp -> !(PIL a) -> PIL a |
| 40 | | PStmt :: !(PIL Expression) -> PIL Stmt |
| 41 | | PThunk :: !(PIL Expression) -> PIL Expression |
| 42 | | PCode :: !SubType -> ![TParam] -> !(PIL [Stmt]) -> PIL Expression |
| 43 | | |
| 44 | | PVal :: !Val -> PIL Literal |
| 45 | | PVar :: !VarName -> PIL LValue |
| 46 | | |
| 47 | | PStmts :: !(PIL Stmt) -> !(PIL [Stmt]) -> PIL [Stmt] |
| 48 | | PApp :: !TCxt -> !(PIL Expression) -> ![PIL Expression] -> PIL LValue |
| 49 | | PAssign :: ![PIL LValue] -> !(PIL Expression) -> PIL LValue |
| 50 | | PBind :: ![PIL LValue] -> !(PIL Expression) -> PIL LValue |
| 51 | | PPad :: !Scope -> ![(VarName, PIL Expression)] -> !(PIL [Stmt]) -> PIL [Stmt] |
| 52 | | |
| 53 | | PSub :: !SubName -> !SubType -> ![TParam] -> !(PIL [Stmt]) -> PIL Decl |
| 54 | | #endif |
| 55 | | |
| 56 | | data TParam = MkTParam |
| 57 | | { tpParam :: !Param |
| 58 | | , tpDefault :: !(Maybe (PIL Expression)) |
| 59 | | } |
| 60 | | deriving (Show, Typeable) |
| 61 | | |
| 62 | | data TCxt |
| 63 | | = TCxtVoid | TCxtLValue !Type | TCxtItem !Type | TCxtSlurpy !Type |
| 64 | | | TTailCall !TCxt |
| 65 | | deriving (Show, Eq, Typeable) |
| 66 | | |
| 67 | | tcVoid, tcLValue :: TCxt |
| 68 | | tcVoid = TCxtVoid |
| 69 | | tcLValue = TCxtLValue anyType |
| 70 | | |
| 71 | | {- |
| 72 | | tcItem, tcSlurpy :: TCxt |
| 73 | | tcItem = TCxtItem anyType |
| 74 | | tcSlurpy = TCxtSlurpy anyType |
| 75 | | -} |
| 76 | | |
| 77 | | instance 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 | | |
| 96 | | data 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 | | |
| 105 | | type Comp a = Eval a |
| 106 | | type CompMonad = EvalT (ContT Val (ReaderT Env SIO)) |
| | 26 | import Pugs.Compile |
| | 27 | |
| 120 | | instance Compile (Var, [(TVar Bool, TVar VRef)]) (PIL Decl) where |
| 121 | | compile = compError |
| 122 | | |
| 123 | | instance Compile Param TParam where |
| 124 | | compile prm = do |
| 125 | | defC <- if isOptional prm |
| 126 | | then fmap Just $ compile (paramDefault prm) |
| 127 | | else return Nothing |
| 128 | | return $ MkTParam |
| 129 | | { tpParam = prm |
| 130 | | , tpDefault = defC |
| 131 | | } |
| 132 | | |
| 133 | | {-| Compiles a 'Pad' to a list of 'PIL Decl's. Currently, only subroutines and |
| 134 | | @\@*END@ are compiled. -} |
| 135 | | instance Compile Pad [PIL Decl] where |
| 136 | | compile pad = do |
| 137 | | entries' <- mapM canCompile entries |
| 138 | | return $ concat entries' |
| 139 | | where |
| 140 | | entries = sortBy padSort $ padToList pad |
| 141 | | canCompile (name@('&':_), [(_, sym)]) = do |
| 142 | | ref <- liftSTM $ readTVar sym |
| 143 | | case ref of |
| 144 | | MkRef (ICode cv) |
| 145 | | -> doCode name =<< code_fetch cv |
| 146 | | MkRef (IScalar sv) | scalar_iType sv == mkType "Scalar::Const" |
| 147 | | -> doCode name =<< fromVal =<< scalar_fetch sv |
| 148 | | _ -> return [] |
| 149 | | canCompile ("@*END", [(_, sym)]) = do |
| 150 | | ref <- liftSTM $ readTVar sym |
| 151 | | cvList <- fromVals =<< readRef ref :: Comp [VCode] |
| 152 | | decls <- eachM cvList $ \(i, cv) -> do |
| 153 | | compile (("&*END_" ++ show i), cv) :: Comp [PIL Decl] |
| 154 | | compile ("&*END", concat decls) |
| 155 | | canCompile ((_:twigil:_), _) | not (isAlphaNum twigil) = return [] |
| 156 | | canCompile (name, [(_, sym)]) = do |
| 157 | | -- translate them into store_global calls? |
| 158 | | -- placing them each into one separate init function? |
| 159 | | val <- readRef =<< liftSTM (readTVar sym) |
| 160 | | valC <- compile val |
| 161 | | let assignC = PAssign [PVar name'] valC |
| 162 | | bodyC = PStmts (PStmt . PExp $ assignC) PNil |
| 163 | | initL = "__init_" ++ (render $ varText name) |
| 164 | | name' | ':' `elem` name = name |
| 165 | | | otherwise = "main::" ++ name -- XXX wrong |
| 166 | | return [PSub initL SubPrim [] bodyC] |
| 167 | | canCompile _ = return [] |
| 168 | | doCode name vsub = case subBody vsub of |
| 169 | | Prim _ -> return [] |
| 170 | | _ -> compile (name, vsub) |
| 171 | | |
| 172 | | eachM :: (Monad m) => [a] -> ((Int, a) -> m b) -> m [b] |
| 173 | | eachM = forM . ([0..] `zip`) |
| 174 | | |
| 175 | | instance Compile (SubName, [PIL Decl]) [PIL Decl] where |
| 176 | | compile (name, decls) = do |
| 177 | | let bodyC = [ PStmts . PStmt . PExp $ PApp tcVoid (PExp (PVar sub)) [] |
| 178 | | | PSub sub _ _ _ <- decls |
| 179 | | ] |
| 180 | | return (PSub name SubPrim [] (combine bodyC PNil):decls) |
| 181 | | |
| 182 | | instance Compile (SubName, VCode) [PIL Decl] where |
| 183 | | compile (name, vsub) | packageOf name /= packageOf (subName vsub) = do |
| 184 | | let storeC = PBind [PVar $ qualify name] (PExp . PVar . qualify $ subName vsub) |
| 185 | | bodyC = PStmts (PStmt . PExp $ storeC) PNil |
| 186 | | exportL = "__export_" ++ (render $ varText name) |
| 187 | | return [PSub exportL SubPrim [] bodyC] |
| 188 | | compile (name, vsub) = do |
| 189 | | bodyC <- enter cxtItemAny . compile $ case subBody vsub of |
| 190 | | Syn "block" [body] -> body |
| 191 | | body -> body |
| 192 | | paramsC <- compile $ subParams vsub |
| 193 | | return [PSub name (subType vsub) paramsC bodyC] |
| 194 | | |
| 195 | | instance Compile (String, [(TVar Bool, TVar VRef)]) (PIL Expression) where |
| 196 | | compile (name, _) = return $ PRawName name |
| 197 | | |
| 198 | | instance Compile Exp (PIL [Stmt]) where |
| 199 | | compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest |
| 200 | | compile (Cxt cxt rest) = enter cxt $ compile rest |
| 201 | | compile (Stmts (Pad SOur _ exp) rest) = do |
| 202 | | compile $ mergeStmts exp rest |
| 203 | | compile (Stmts (Pad _ pad exp) rest) = do |
| 204 | | expC <- compile $ mergeStmts exp rest |
| 205 | | padC <- compile $ padToList pad |
| 206 | | return $ PPad SMy ((map fst $ padToList pad) `zip` padC) expC |
| 207 | | compile exp = compileStmts exp |
| 208 | | |
| 209 | | class EnterClass m a where |
| 210 | | enter :: a -> m b -> m b |
| 211 | | |
| 212 | | instance EnterClass CompMonad VCode where |
| 213 | | enter sub = local (\e -> e{ envLValue = subLValue sub, envContext = CxtItem (subReturns sub) }) |
| 214 | | |
| 215 | | instance EnterClass CompMonad Cxt where |
| 216 | | enter cxt = local (\e -> e{ envContext = cxt }) |
| 217 | | |
| 220 | | |
| 221 | | compileStmts :: Exp -> Comp (PIL [Stmt]) |
| 222 | | compileStmts exp = case exp of |
| 223 | | Stmts this Noop -> do |
| 224 | | thisC <- compile this |
| 225 | | return $ PStmts (tailCall thisC) PNil |
| 226 | | where |
| 227 | | tailCall (PStmt (PExp (PApp cxt fun args))) |
| 228 | | = PStmt $ PExp $ PApp (TTailCall cxt) fun args |
| 229 | | tailCall (PPos pos exp x) = PPos pos exp (tailCall x) |
| 230 | | tailCall x = x |
| 231 | | Stmts this rest -> do |
| 232 | | thisC <- enter cxtVoid $ compile this |
| 233 | | restC <- compileStmts rest |
| 234 | | return $ PStmts thisC restC |
| 235 | | Noop -> return PNil |
| 236 | | _ -> compile (Stmts exp Noop) |
| 237 | | |
| 238 | | instance Compile Val (PIL Stmt) where |
| 239 | | compile = fmap PStmt . compile . Val |
| 240 | | |
| 241 | | instance Compile Val (PIL Expression) where |
| 242 | | compile = compile . Val |
| 243 | | |
| 244 | | instance Compile Exp (PIL Stmt) where |
| 245 | | compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest |
| 246 | | compile (Cxt cxt rest) = enter cxt $ compile rest |
| 247 | | compile Noop = return PNoop |
| 248 | | compile (Val val) = do |
| 249 | | cxt <- asks envContext |
| 250 | | if isVoidCxt cxt |
| 251 | | then case val of |
| 252 | | VBool True -> compile Noop |
| 253 | | _ -> do |
| 254 | | warn "Useless use of a constant in void context" val |
| 255 | | compile Noop |
| 256 | | else compile val |
| 257 | | compile (Syn "loop" [exp]) = |
| 258 | | compile (Syn "loop" $ [emptyExp, Val (VBool True), emptyExp, exp]) |
| 259 | | compile (Syn "loop" [pre, cond, post, (Syn "block" [body])]) = do |
| 260 | | preC <- compile pre |
| 261 | | condC <- compile cond |
| 262 | | bodyC <- compile body |
| 263 | | postC <- compile post |
| 264 | | funC <- compile (Var "&statement_control:loop") |
| 265 | | return . PStmt . PExp $ PApp TCxtVoid funC |
| 266 | | [preC, pBlock condC, pBlock bodyC, pBlock postC] |
| 267 | | compile exp@(Syn "unless" _) = fmap (PStmt . PExp) $ compConditional exp |
| 268 | | compile exp@(Syn "while" _) = compLoop exp |
| 269 | | compile exp@(Syn "until" _) = compLoop exp |
| 270 | | compile exp@(Syn "postwhile" _) = compLoop exp |
| 271 | | compile exp@(Syn "postuntil" _) = compLoop exp |
| 272 | | compile (Syn "for" [exp, body]) = do |
| 273 | | expC <- compile exp |
| 274 | | bodyC <- compile body |
| 275 | | funC <- compile (Var "&statement_control:for") |
| 276 | | return . PStmt . PExp $ PApp TCxtVoid funC [expC, bodyC] |
| 277 | | compile (Syn "given" _) = compile (Var "$_") -- XXX |
| 278 | | compile (Syn "when" _) = compile (Var "$_") -- XXX |
| 279 | | compile exp = fmap PStmt $ compile exp |
| 280 | | |
| 281 | | pBlock :: PIL [Stmt] -> PIL Expression |
| 282 | | pBlock = PCode SubBlock [] |
| 283 | | |
| 284 | | {- |
| 285 | | subTCxt :: VCode -> Eval TCxt |
| 286 | | subTCxt sub = return $ if subLValue sub |
| 287 | | then TCxtLValue (subReturns sub) |
| 288 | | else TCxtItem (subReturns sub) |
| 289 | | -} |
| 290 | | |
| 291 | | askTCxt :: Eval TCxt |
| 292 | | askTCxt = do |
| 293 | | env <- ask |
| 294 | | return $ if envLValue env |
| 295 | | then TCxtLValue (typeOfCxt $ envContext env) |
| 296 | | else case envContext env of |
| 297 | | CxtVoid -> TCxtVoid |
| 298 | | CxtItem typ -> TCxtItem typ |
| 299 | | CxtSlurpy typ -> TCxtSlurpy typ |
| 300 | | |
| 301 | | instance (Show (m a), FunctorM m, Typeable1 m, Compile a b) => Compile (m a) (m b) where |
| 302 | | compile = fmapM compile |
| 303 | | |
| 304 | | instance (Compile a b, Compile a c) => Compile [a] (b, c) where |
| 305 | | compile [x, y] = do { x' <- compile x ; y' <- compile y; return (x', y') } |
| 306 | | compile x = compError x |
| 307 | | |
| 308 | | instance (Compile a b, Compile a c, Compile a d) => Compile [a] (b, c, d) where |
| 309 | | compile [x, y, z] = do { x' <- compile x ; y' <- compile y; z' <- compile z; return (x', y', z') } |
| 310 | | compile x = compError x |
| 311 | | |
| 312 | | instance Compile Exp (PIL LValue) where |
| 313 | | compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest |
| 314 | | compile (Cxt cxt rest) = enter cxt $ compile rest |
| 315 | | compile (Var name) = return $ PVar name |
| 316 | | compile (Syn (sigil:"::()") exps) = do |
| 317 | | compile $ App (Var "&Pugs::Internals::symbolic_deref") Nothing $ |
| 318 | | (Val . VStr $ sigil:""):exps |
| 319 | | compile (App (Var "&goto") (Just inv) args) = do |
| 320 | | cxt <- askTCxt |
| 321 | | funC <- compile inv |
| 322 | | argsC <- enter cxtItemAny $ compile args |
| 323 | | return $ PApp (TTailCall cxt) funC argsC |
| 324 | | compile (App fun (Just inv) args) = do |
| 325 | | compile (App fun Nothing (inv:args)) -- XXX WRONG |
| 326 | | compile (App fun Nothing args) = do |
| 327 | | cxt <- askTCxt |
| 328 | | funC <- compile fun |
| 329 | | argsC <- enter cxtItemAny $ compile args |
| 330 | | return $ PApp cxt funC argsC |
| 331 | | compile exp@(Syn "if" _) = compConditional exp |
| 332 | | compile (Syn "{}" (x:xs)) = compile $ App (Var "&postcircumfix:{}") (Just x) xs |
| 333 | | compile (Syn "[]" (x:xs)) = do |
| 334 | | compile (App (Var "&postcircumfix:[]") (Just x) xs) |
| 335 | | compile (Syn "," exps) = do |
| 336 | | compile (App (Var "&infix:,") Nothing exps) |
| 337 | | compile (Syn "\\[]" exps) = do |
| 338 | | compile (App (Var "&circumfix:[]") Nothing exps) |
| 339 | | compile (Syn "\\{}" exps) = do |
| 340 | | compile (App (Var "&circumfix:{}") Nothing exps) |
| 341 | | compile (Syn "=" [lhs, rhs]) = do |
| 342 | | lhsC <- enterLValue $ compile lhs |
| 343 | | rhsC <- enterRValue $ compile rhs |
| 344 | | return $ PAssign [lhsC] rhsC |
| 345 | | compile (Syn ":=" exps) = do |
| 346 | | (lhsC, rhsC) <- enterLValue $ compile exps |
| 347 | | return $ PBind [lhsC] rhsC |
| 348 | | compile (Syn syn [lhs, exp]) | last syn == '=' = do |
| 349 | | let op = "&infix:" ++ init syn |
| 350 | | compile $ Syn "=" [lhs, App (Var op) Nothing [lhs, exp]] |
| 351 | | compile exp = compError exp |
| 352 | | |
| 353 | | compLoop :: Exp -> Comp (PIL Stmt) |
| 354 | | compLoop (Syn name [cond, body]) = do |
| 355 | | cxt <- askTCxt |
| 356 | | condC <- enter (CxtItem $ mkType "Bool") $ compile cond |
| 357 | | bodyC <- enter CxtVoid $ compile body |
| 358 | | funC <- compile (Var $ "&statement_control:" ++ name) |
| 359 | | return . PStmt . PExp $ PApp cxt funC [pBlock condC, pBlock bodyC] |
| 360 | | compLoop exp = compError exp |
| 361 | | |
| 362 | | {-| Compiles a conditional 'Syn' (@if@ and @unless@) to a call to an |
| 363 | | appropriate function call (@&statement_control:if@ or |
| 364 | | @&statement_control:unless@). -} |
| 365 | | compConditional :: Exp -> Comp (PIL LValue) |
| 366 | | compConditional (Syn name exps) = do |
| 367 | | [condC, trueC, falseC] <- compile exps |
| 368 | | funC <- compile $ Var ("&statement_control:" ++ name) |
| 369 | | cxt <- askTCxt |
| 370 | | return $ PApp cxt funC [condC, PThunk trueC, PThunk falseC] |
| 371 | | compConditional exp = compError exp |
| 372 | | |
| 373 | | {-| Compiles various 'Exp's to 'PIL Expression's. -} |
| 374 | | instance Compile Exp (PIL Expression) where |
| 375 | | compile (Pos pos rest) = fmap (PPos pos rest) $ compile rest |
| 376 | | compile (Cxt cxt rest) = enter cxt $ compile rest |
| 377 | | compile (Var name) = return . PExp $ PVar name |
| 378 | | compile exp@(Val (VCode _)) = compile $ Syn "sub" [exp] |
| 379 | | compile (Val val) = fmap PLit $ compile val |
| 380 | | compile Noop = compile (Val undef) |
| 381 | | compile (Syn "block" [body]) = do |
| 382 | | cxt <- askTCxt |
| 383 | | bodyC <- compile body |
| 384 | | return $ PExp $ PApp cxt (pBlock bodyC) [] |
| 385 | | compile (Syn "sub" [Val (VCode sub)]) = do |
| 386 | | bodyC <- enter sub $ compile $ case subBody sub of |
| 387 | | Syn "block" [exp] -> exp |
| 388 | | exp -> exp |
| 389 | | paramsC <- compile $ subParams sub |
| 390 | | return $ PCode (subType sub) paramsC bodyC |
| 391 | | compile (Syn "module" _) = compile Noop |
| 392 | | compile (Syn "match" exp) = compile $ Syn "rx" exp -- wrong |
| 393 | | compile (Syn "//" exp) = compile $ Syn "rx" exp |
| 394 | | compile (Syn "rx" [exp, _]) = compile exp -- XXX WRONG - use PCRE |
| 395 | | compile (Syn "subst" [exp, _, _]) = compile exp -- XXX WRONG - use PCRE |
| 396 | | compile exp@(App _ _ _) = fmap PExp $ compile exp |
| 397 | | compile exp@(Syn _ _) = fmap PExp $ compile exp |
| 398 | | compile exp = compError exp |
| 399 | | |
| 400 | | compError :: forall a b. Compile a b => a -> Comp b |
| 401 | | compError = die $ "Compile error -- invalid " |
| 402 | | ++ (show $ typeOf (undefined :: b)) |