PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Pugs/Compile.hs

https://github.com/gitpan/Perl6-Pugs
Haskell | 454 lines | 361 code | 40 blank | 53 comment | 18 complexity | a7f57a8f5f76281b8b54431da7a08514 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. {-# OPTIONS_GHC -fglasgow-exts -fallow-undecidable-instances -fno-warn-orphans -funbox-strict-fields -cpp -fno-warn-deprecations -fallow-overlapping-instances #-}
  2. {-|
  3. Compiler interface.
  4. > And words unheard were spoken then
  5. > Of folk and Men and Elven-kin,
  6. > Beyond the world were visions showed
  7. > Forbid to those that dwell therein...
  8. -}
  9. module Pugs.Compile (
  10. PIL_Stmts(..), PIL_Stmt(..), PIL_Expr(..), PIL_Decl(..), PIL_Literal(..), PIL_LValue(..),
  11. Compile(..),
  12. TEnv(..), initTEnv,
  13. TCxt(..), tcVoid, tcLValue,
  14. TParam(..),
  15. EnterClass(..),
  16. die, varText
  17. ) where
  18. import Pugs.AST
  19. import Pugs.Internals
  20. import Pugs.Types
  21. import Pugs.Monads
  22. import Pugs.PIL1
  23. import Emit.PIR
  24. import Text.PrettyPrint
  25. tcVoid, tcLValue :: TCxt
  26. tcVoid = TCxtVoid
  27. tcLValue = TCxtLValue anyType
  28. {-
  29. tcItem, tcSlurpy :: TCxt
  30. tcItem = TCxtItem anyType
  31. tcSlurpy = TCxtSlurpy anyType
  32. -}
  33. type Comp = Eval
  34. {-| Currently only 'Exp' 'PIL' -}
  35. class (Show a, Typeable b) => Compile a b where
  36. compile :: a -> Comp b
  37. compile x = fail ("Unrecognized construct: " ++ show x)
  38. -- Compile instances
  39. instance Compile () PIL_Environment where
  40. compile _ = do
  41. glob <- askGlobal
  42. main <- asks envBody
  43. globPIL <- compile glob
  44. mainPIL <- compile main
  45. return $ PIL_Environment globPIL mainPIL
  46. instance Compile (Var, [(TVar Bool, TVar VRef)]) PIL_Decl where
  47. compile = compError
  48. instance Compile Param TParam where
  49. compile prm = do
  50. defC <- if isOptional prm
  51. then fmap Just $ compile (paramDefault prm)
  52. else return Nothing
  53. return $ MkTParam
  54. { tpParam = prm
  55. , tpDefault = defC
  56. }
  57. {-| Compiles a 'Pad' to a list of 'PIL_Decl's. Currently, only subroutines and
  58. @\@*END@ are compiled. -}
  59. instance Compile Pad [PIL_Decl] where
  60. compile pad = do
  61. entries' <- mapM canCompile entries
  62. return $ concat entries'
  63. where
  64. entries = sortBy padSort [ (cast var, ref) | (var, ref) <- padToList pad ]
  65. canCompile (name@('&':_), xs) | length xs > 1 = do
  66. fmap concat $ mapM (\x -> canCompile (name, [x])) xs
  67. canCompile (name@('&':_), [(_, sym)]) = do
  68. ref <- liftSTM $ readTVar sym
  69. case ref of
  70. MkRef (ICode cv)
  71. -> doCode name =<< code_fetch cv
  72. MkRef (IScalar sv) | scalar_iType sv == mkType "Scalar::Const"
  73. -> doCode name =<< fromVal =<< scalar_fetch sv
  74. _ -> return []
  75. canCompile ("@*END", [(_, sym)]) = do
  76. ref <- liftSTM $ readTVar sym
  77. cvList <- fromVals =<< readRef ref :: Comp [VCode]
  78. decls <- eachM cvList $ \(i, cv) -> do
  79. compile (("&*END_" ++ show i), cv) :: Comp [PIL_Decl]
  80. compile ("&*END", concat decls)
  81. canCompile ((_:twigil:_), _) | not (isAlphaNum twigil) = return []
  82. canCompile (name, [(_, sym)]) = do
  83. -- translate them into store_global calls?
  84. -- placing them each into one separate init function?
  85. val <- readRef =<< liftSTM (readTVar sym)
  86. valC <- compile val
  87. let assignC = PAssign [PVar name'] valC
  88. bodyC = PStmts (PStmt . PExp $ assignC) PNil
  89. initL = "__init_" ++ (render $ varText name)
  90. name' | ':' `elem` name = name
  91. | otherwise = "Main::" ++ name -- XXX wrong
  92. return [PSub initL SubPrim [] False False bodyC]
  93. canCompile _ = return []
  94. doCode name vsub = case subBody vsub of
  95. Prim _ -> return []
  96. _ -> compile (name, vsub)
  97. eachM :: (Monad m) => [a] -> ((Int, a) -> m b) -> m [b]
  98. eachM = forM . ([0..] `zip`)
  99. instance Compile (SubName, [PIL_Decl]) [PIL_Decl] where
  100. compile (name, decls) = do
  101. let bodyC = [ PStmts . PStmt . PExp $ PApp tcVoid (PExp (PVar sub)) Nothing []
  102. | PSub sub _ _ _ _ _ <- decls
  103. ]
  104. return (PSub name SubPrim [] False False (combine bodyC PNil):decls)
  105. instance Compile (SubName, VCode) [PIL_Decl] where
  106. {-
  107. compile (name, vsub) | packageOf name /= packageOf (subName vsub) = do
  108. let storeC = PBind [PVar $ qualify name] (PExp . PVar . qualify $ subName vsub)
  109. bodyC = PStmts (PStmt . PExp $ storeC) PNil
  110. exportL = "__export_" ++ (render $ varText name)
  111. return [PSub exportL SubPrim [] False False bodyC]
  112. -}
  113. compile (name, vsub) = do
  114. bodyC <- enter cxtItemAny . compile $ case subBody vsub of
  115. Syn "block" [body] -> body
  116. body -> body
  117. paramsC <- compile $ subParams vsub
  118. return [PSub name (subType vsub) paramsC (subLValue vsub) (isMulti vsub) bodyC]
  119. instance Compile (String, [(TVar Bool, TVar VRef)]) PIL_Expr where
  120. compile (name, ((_, ref):_)) = do
  121. rv <- readRef =<< liftSTM (readTVar ref)
  122. case rv of
  123. VCode sub -> return $ PRawName (cast $ subName sub)
  124. _ -> return $ PRawName name
  125. compile (name, _) = return $ PRawName name
  126. instance Compile Exp PIL_Stmts where
  127. -- XXX: pragmas?
  128. compile (Ann Pos{} rest) = compile rest -- fmap (PPos pos rest) $ compile rest
  129. compile (Ann Prag{} rest) = compile rest -- fmap (PPos pos rest) $ compile rest
  130. compile (Ann (Cxt cxt) rest) = enter cxt $ compile rest
  131. compile (Ann _ rest) = compile rest
  132. compile (Stmts (Pad SOur _ exp) rest) = do
  133. compile $ mergeStmts exp rest
  134. compile (Stmts (Pad scope pad exp) rest) = do
  135. padC <- compile [ (cast var :: String, ref) | (var, ref) <- padToList pad ]
  136. let symC = (map (cast . fst) $ padToList pad) `zip` padC
  137. exps = [ Syn ":=" [_Var name, _Var from]
  138. | (name, PRawName from) <- symC
  139. , name /= from
  140. ]
  141. expC <- compile $ mergeStmts (foldl1 mergeStmts (exps ++ [exp])) rest
  142. return $ PPad scope symC expC
  143. compile exp = compileStmts exp
  144. class EnterClass m a where
  145. enter :: a -> m b -> m b
  146. instance EnterClass Comp VCode where
  147. enter sub = local (\e -> e{ envLValue = subLValue sub, envContext = CxtItem (subReturns sub) })
  148. instance EnterClass Comp Cxt where
  149. enter cxt = local (\e -> e{ envContext = cxt })
  150. compileStmts :: Exp -> Comp PIL_Stmts
  151. compileStmts exp = case exp of
  152. Stmts this Noop -> do
  153. thisC <- compile this
  154. return $ PStmts (tailCall thisC) PNil
  155. where
  156. tailCall (PStmt (PExp (PApp cxt fun inv args)))
  157. = PStmt $ PExp $ PApp (TTailCall cxt) fun inv args
  158. tailCall (PPos pos exp x) = PPos pos exp (tailCall x)
  159. tailCall x = x
  160. Stmts this (Syn "namespace" [Val (VStr sym), Val (VStr pkg), rest]) -> do
  161. thisC <- enter cxtVoid $ compile this
  162. declC <- enter cxtVoid $ compile decl
  163. restC <- enterPackage (cast pkg) $ compileStmts rest
  164. return $ PStmts thisC $ PStmts declC restC
  165. where
  166. -- XXX - kludge.
  167. decl = App (_Var func) Nothing [(Val (VStr pkg))]
  168. func = "&" ++ (capitalize sym) ++ "::_create"
  169. capitalize [] = []
  170. capitalize (c:cs) = toUpper c:cs
  171. Stmts this rest -> do
  172. thisC <- enter cxtVoid $ compile this
  173. restC <- compileStmts rest
  174. return $ PStmts thisC restC
  175. Noop -> return PNil
  176. _ -> compile (Stmts exp Noop)
  177. instance Compile Val PIL_Stmt where
  178. compile = fmap PStmt . compile . Val
  179. instance Compile Val PIL_Expr where
  180. compile = compile . Val
  181. instance Compile Exp PIL_Stmt where
  182. compile (Ann (Pos pos) rest) = fmap (PPos pos rest) $ compile rest
  183. compile (Ann (Cxt cxt) rest) = enter cxt $ compile rest
  184. -- XXX: pragmas?
  185. compile (Ann Prag{} rest) = compile rest -- fmap (PPos pos rest) $ compile rest
  186. compile (Ann _ rest) = compile rest
  187. compile Noop = return PNoop
  188. compile (Val val) = do
  189. cxt <- asks envContext
  190. if isVoidCxt cxt
  191. then case val of
  192. VBool True -> compile Noop
  193. _ -> do
  194. warn "Useless use of a constant in void context" val
  195. compile Noop
  196. else compile val
  197. compile (Syn "loop" [exp]) =
  198. compile (Syn "loop" $ [emptyExp, Val (VBool True), emptyExp, exp])
  199. compile (Syn "loop" [pre, cond, post, body]) = do
  200. preC <- compile pre
  201. -- loop (...; ; ...) {...} ->
  202. -- loop (...; True; ...) {...}
  203. let cond' | unwrap cond == Noop
  204. = return $ PStmts (PStmt . PLit . PVal $ VBool True) PNil
  205. | otherwise
  206. = compile cond
  207. condC <- cond'
  208. bodyC <- compile body
  209. postC <- compile post
  210. funC <- compile (_Var "&statement_control:loop")
  211. return . PStmt . PExp $ PApp TCxtVoid funC Nothing
  212. [preC, pBlock condC, bodyC, pBlock postC]
  213. compile exp@(Syn "unless" _) = fmap (PStmt . PExp) $ compConditional exp
  214. compile exp@(Syn "while" _) = compLoop exp
  215. compile exp@(Syn "until" _) = compLoop exp
  216. compile exp@(Syn "postwhile" _) = compLoop exp
  217. compile exp@(Syn "postuntil" _) = compLoop exp
  218. compile (Syn "for" [exp, body]) = do
  219. expC <- compile exp
  220. bodyC <- compile body
  221. funC <- compile (_Var "&statement_control:for")
  222. return . PStmt . PExp $ PApp TCxtVoid funC Nothing [expC, bodyC]
  223. compile (Syn "given" _) = compile (_Var "$_") -- XXX
  224. compile (Syn "when" _) = compile (_Var "$_") -- XXX
  225. compile exp = fmap PStmt $ compile exp
  226. pBlock :: PIL_Stmts -> PIL_Expr
  227. pBlock = PCode SubBlock [] False False
  228. {-
  229. subTCxt :: VCode -> Eval TCxt
  230. subTCxt sub = return $ if subLValue sub
  231. then TCxtLValue (subReturns sub)
  232. else TCxtItem (subReturns sub)
  233. -}
  234. askTCxt :: Eval TCxt
  235. askTCxt = do
  236. env <- ask
  237. return $ if envLValue env
  238. then TCxtLValue (typeOfCxt $ envContext env)
  239. else case envContext env of
  240. CxtVoid -> TCxtVoid
  241. CxtItem typ -> TCxtItem typ
  242. CxtSlurpy typ -> TCxtSlurpy typ
  243. instance (Compile a b) => Compile [a] [b] where
  244. compile = fmapM compile
  245. instance (Compile a b, Compile a c) => Compile [a] (b, c) where
  246. compile [x, y] = do { x' <- compile x ; y' <- compile y; return (x', y') }
  247. compile x = compError x
  248. instance (Compile a b, Compile a c, Compile a d) => Compile [a] (b, c, d) where
  249. compile [x, y, z] = do { x' <- compile x ; y' <- compile y; z' <- compile z; return (x', y', z') }
  250. compile x = compError x
  251. instance Compile Exp PIL_LValue where
  252. compile (Ann Pos{} rest) = compile rest -- fmap (PPos pos rest) $ compile rest
  253. compile (Ann Prag{} rest) = compile rest
  254. compile (Ann (Cxt cxt) rest) = enter cxt $ compile rest
  255. compile (Ann _ rest) = compile rest
  256. -- XXX: pragmas?
  257. compile (Var name) = return $ _PVar name
  258. compile (Syn (sigil:"::()") exps) = do
  259. compile $ App (_Var "&Pugs::Internals::symbolic_deref") Nothing $
  260. (Val . VStr $ sigil:""):exps
  261. compile (App (Var var) (Just inv) args) | var == cast "&goto" = do
  262. cxt <- askTCxt
  263. funC <- compile inv
  264. argsC <- enter cxtItemAny $ compile args
  265. return $ PApp (TTailCall cxt) funC Nothing argsC
  266. compile (App fun inv args) = do
  267. cxt <- askTCxt
  268. funC <- compile fun
  269. invC <- maybeM (return inv) compile
  270. argsC <- enter cxtItemAny $ compile args
  271. if isLogicalLazy funC
  272. then return $ PApp cxt funC invC (head argsC:map PThunk (tail argsC))
  273. else return $ PApp cxt funC invC argsC
  274. where
  275. -- XXX HACK
  276. isLogicalLazy (PExp (PVar "&infix:or")) = True
  277. isLogicalLazy (PExp (PVar "&infix:and")) = True
  278. isLogicalLazy (PExp (PVar "&infix:err")) = True
  279. isLogicalLazy (PExp (PVar "&infix:||")) = True
  280. isLogicalLazy (PExp (PVar "&infix:&&")) = True
  281. isLogicalLazy (PExp (PVar "&infix://")) = True
  282. isLogicalLazy _ = False
  283. compile exp@(Syn "if" _) = compConditional exp
  284. compile (Syn "{}" (x:xs)) = compile $ App (_Var "&postcircumfix:{}") (Just x) xs
  285. compile (Syn "[]" (x:xs)) = do
  286. compile (App (_Var "&postcircumfix:[]") (Just x) xs)
  287. compile (Syn "," exps) = do
  288. compile (App (_Var "&infix:,") Nothing exps)
  289. -- Minor hack, my $a = [] is parsed as my $a = [Noop], resulting in my $a =
  290. -- [undef], which is wrong.
  291. compile (Syn "\\[]" [Noop]) = do
  292. compile (App (_Var "&circumfix:[]") Nothing [])
  293. compile (Syn "\\[]" exps) = do
  294. compile (App (_Var "&circumfix:[]") Nothing exps)
  295. compile (Syn name@(sigil:"{}") exps) | (sigil ==) `any` "$@%&" = do
  296. compile (App (_Var $ "&circumfix:" ++ name) Nothing exps)
  297. compile (Syn "\\{}" exps) = do
  298. compile (App (_Var "&circumfix:{}") Nothing exps)
  299. compile (Syn "*" exps) = do
  300. compile (App (_Var "&prefix:*") Nothing exps)
  301. compile (Syn "=" [lhs, rhs]) = do
  302. lhsC <- enterLValue $ compile lhs
  303. rhsC <- enterRValue $ compile rhs
  304. return $ PAssign [lhsC] rhsC
  305. compile (Syn ":=" exps) = do
  306. (lhsC, rhsC) <- enterLValue $ compile exps
  307. return $ PBind [lhsC] rhsC
  308. compile (Syn syn [lhs, exp]) | last syn == '=' = do
  309. let op = "&infix:" ++ init syn
  310. compile $ Syn "=" [lhs, App (_Var op) Nothing [lhs, exp]]
  311. compile (Syn "but" [obj, block]) =
  312. compile $ App (_Var "&Pugs::Internals::but_block") Nothing [obj, block]
  313. compile exp@(Syn "namespace" _) = do
  314. -- XXX - Is there a better way to wrap Stmts as LValue?
  315. compile $ App (Syn "sub"
  316. [ Val . VCode $ mkSub
  317. { subBody = Stmts Noop exp
  318. , subParams = []
  319. }
  320. ]) Nothing []
  321. -- For PIL2 we want real zone separation, e.g.
  322. -- PApp { pNamedArgs = [...], pPositionalArgs = [...], ... }
  323. -- For now, using &Pugs::Internals::named_pair is probably ok.
  324. compile (Syn "named" kv@[_, _]) = do
  325. compile $ App (_Var "&Pugs::Internals::named_pair") Nothing kv
  326. compile exp = compError exp
  327. compLoop :: Exp -> Comp PIL_Stmt
  328. compLoop (Syn name [cond, body]) = do
  329. cxt <- askTCxt
  330. condC <- enter (CxtItem $ mkType "Bool") $ compile cond
  331. bodyC <- enter CxtVoid $ compile body
  332. funC <- compile (_Var $ "&statement_control:" ++ name)
  333. return . PStmt . PExp $ PApp cxt funC Nothing [pBlock condC, bodyC]
  334. compLoop exp = compError exp
  335. {-| Compiles a conditional 'Syn' (@if@ and @unless@) to a call to an
  336. appropriate function call (@&statement_control:if@ or
  337. @&statement_control:unless@). -}
  338. compConditional :: Exp -> Comp PIL_LValue
  339. compConditional (Syn name exps) = do
  340. [condC, trueC, falseC] <- compile exps
  341. funC <- compile $ _Var ("&statement_control:" ++ name)
  342. cxt <- askTCxt
  343. return $ PApp cxt funC Nothing [condC, PThunk trueC, PThunk falseC]
  344. compConditional exp = compError exp
  345. _PVar :: Var -> PIL_LValue
  346. _PVar = PVar . cast
  347. {-| Compiles various 'Exp's to 'PIL_Expr's. -}
  348. instance Compile Exp PIL_Expr where
  349. compile (Ann Pos{} rest) = compile rest -- fmap (PPos pos rest) $ compile rest
  350. compile (Ann Prag{} rest) = compile rest
  351. compile (Ann (Cxt cxt) rest) = enter cxt $ compile rest
  352. compile (Ann _ rest) = compile rest
  353. -- XXX: pragmas?
  354. compile (Var name) = return . PExp $ _PVar name
  355. compile exp@(Val (VCode _)) = compile $ Syn "sub" [exp]
  356. compile (Val val) = fmap PLit $ compile val
  357. compile Noop = compile (Val undef)
  358. compile (Syn "block" [body]) = do
  359. cxt <- askTCxt
  360. bodyC <- compile body
  361. return $ PExp $ PApp cxt (pBlock bodyC) Nothing []
  362. compile (Syn "sub" [Val (VCode sub)]) = do
  363. bodyC <- enter sub $ compile $ case subBody sub of
  364. Syn "block" [exp] -> exp
  365. exp -> exp
  366. paramsC <- compile $ subParams sub
  367. return $ PCode (subType sub) paramsC (subLValue sub) (isMulti sub) bodyC
  368. compile (Syn "module" _) = compile Noop
  369. compile (Syn "match" exp) = compile $ Syn "rx" exp -- wrong
  370. compile (Syn "//" exp) = compile $ Syn "rx" exp
  371. compile (Syn "rx" (exp:_)) = compile exp -- XXX WRONG - use PCRE
  372. compile (Syn "subst" (exp:_)) = compile exp -- XXX WRONG - use PCRE
  373. compile (Syn "trans" (exp:_)) = compile exp -- XXX WRONG
  374. compile (Syn "|" [exp]) = compile exp -- XXX WRONG
  375. compile (Syn "|<<" [exp]) = compile exp -- XXX WRONG
  376. compile exp@(App _ _ _) = fmap PExp $ compile exp
  377. compile exp@(Syn _ _) = fmap PExp $ compile exp
  378. compile exp = compError exp
  379. compError :: forall a b. Compile a b => a -> Comp b
  380. compError = die $ "Compile error -- invalid "
  381. ++ (show $ typeOf (undefined :: b))
  382. {-| Compiles a 'Val' to a 'PIL_Literal'. -}
  383. instance Compile Val PIL_Literal where
  384. compile (VList vs) = return $ PVal (VList (filter isSimple vs))
  385. where
  386. isSimple (VRef _) = False
  387. isSimple _ = True
  388. compile (VRef _) = return $ PVal VUndef
  389. compile val = return $ PVal val
  390. -- utility functions
  391. padSort :: (String, [(TVar Bool, TVar VRef)]) -> (String, [(a, b)]) -> Ordering
  392. padSort (a, [(_, _)]) (b, [(_, _)])
  393. | (head a == ':' && head b == '&') = LT
  394. | (head b == ':' && head a == '&') = GT
  395. | otherwise = GT
  396. padSort _ _ = EQ
  397. varText :: String -> Doc
  398. varText ('$':name) = text $ "s__" ++ escaped name
  399. varText ('@':name) = text $ "a__" ++ escaped name
  400. varText ('%':name) = text $ "h__" ++ escaped name
  401. varText ('&':name) = text $ "c__" ++ escaped name
  402. varText x = error $ "invalid name: " ++ x
  403. initTEnv :: Eval TEnv
  404. initTEnv = do
  405. initReg <- liftSTM $ newTVar (0, "")
  406. initLbl <- liftSTM $ newTVar 0
  407. return $ MkTEnv
  408. { tLexDepth = 0
  409. , tTokDepth = 0
  410. , tCxt = tcVoid
  411. , tReg = initReg
  412. , tLabel = initLbl
  413. }