2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-2000
4 \section{Generate Java}
6 Name mangling for Java.
9 Haskell has a number of namespaces. The Java translator uses
10 the standard Haskell mangles (see OccName.lhs), and some extra
13 All names are hidden inside packages.
16 - becomes a first level java package.
17 - can not clash with java, because haskell modules are upper case,
18 java default packages are lower case.
21 - these turn into classes
22 - java keywords (eg. private) have the suffix "zdk" ($k) added.
25 - These have a base class, so need to appear in the
26 same name space as other object. for example data Foo = Foo
27 - We add a postfix to types: "zdc" ($c)
28 - Types are upper case, so never clash with keywords
31 - There are tWO classes for each Constructor
32 (1) - Class with the payload extends the relevent datatype baseclass.
33 - This class has the prefix zdw ($w)
34 (2) - Constructor *wrapper* just use their own name.
35 - Constructors are upper case, so never clash with keywords
36 - So Foo would become 2 classes.
37 * Foo -- the constructor wrapper
38 * zdwFoo -- the worker, with the payload
42 $k for keyword nameclash avoidance.
45 module JavaGen( javaGen ) where
49 import Literal ( Literal(..) )
50 import Id ( Id, isDataConId_maybe, isId, idName, isDeadBinder, idPrimRep
52 import Name ( NamedThing(..), getOccString, isGlobalName, isLocalName
54 import PrimRep ( PrimRep(..) )
55 import DataCon ( DataCon, dataConRepArity, dataConRepArgTys, dataConId )
56 import qualified TypeRep
58 import qualified CoreSyn
59 import CoreSyn ( CoreBind, CoreExpr, CoreAlt, CoreBndr,
60 Bind(..), Alt, AltCon(..), collectBinders, isValArg
62 import TysWiredIn ( boolTy, trueDataCon, falseDataCon )
63 import qualified CoreUtils
64 import Module ( Module, moduleString )
65 import TyCon ( TyCon, isDataTyCon, tyConDataCons )
71 #include "HsVersions.h"
77 javaGen :: Module -> [Module] -> [TyCon] -> [CoreBind] -> CompilationUnit
79 javaGen mod import_mods tycons binds
80 = liftCompilationUnit package
82 decls = [Import "haskell.runtime.*"] ++
83 [Import (moduleString mod) | mod <- import_mods] ++
84 concat (map javaTyCon (filter isDataTyCon tycons)) ++
85 concat (map javaTopBind binds)
86 package = Package (moduleString mod) decls
90 %************************************************************************
92 \subsection{Type declarations}
94 %************************************************************************
97 javaTyCon :: TyCon -> [Decl]
98 -- public class List {}
100 -- public class $wCons extends List {
101 -- Object f1; Object f2
103 -- public class $wNil extends List {}
106 = tycon_jclass : concat (map constr_class constrs)
108 constrs = tyConDataCons tycon
109 tycon_jclass_jname = javaTyConTypeName tycon ++ "zdc"
110 tycon_jclass = Class [Public] (shortName tycon_jclass_jname) [] [] []
112 constr_class data_con
113 = [ Class [Public] constr_jname [tycon_jclass_jname] []
114 (field_decls ++ [cons_meth,debug_meth])
117 constr_jname = shortName (javaConstrWkrName data_con)
119 field_names = constrToFields data_con
120 field_decls = [ Field [Public] n Nothing
124 cons_meth = mkCons constr_jname field_names
126 debug_meth = Method [Public] (Name "toString" stringType)
129 ( [ Declaration (Field [] txt Nothing) ]
134 getOccString data_con ++
143 (Op (Var n) "+" litSp)
148 ++ [ Return (Op (Var txt)
156 txt = Name "__txt" stringType
159 -- This checks to see the type is reasonable to call new with.
160 -- primitives might use a static method later.
161 mkNew :: Type -> [Expr] -> Expr
162 mkNew t@(PrimType primType) _ = error "new primitive -- fix it???"
163 mkNew t@(Type _) es = New t es Nothing
164 mkNew _ _ = error "new with strange arguments"
166 constrToFields :: DataCon -> [Name]
167 constrToFields cons =
169 | (i,t) <- zip [1..] (map primRepToType
170 (map Type.typePrimRep
171 (dataConRepArgTys cons)
176 mkCons :: TypeName -> [Name] -> Decl
177 mkCons name args = Constructor [Public] name
178 [ Parameter [] n | n <- args ]
179 [ ExprStatement (Assign
185 mkStr :: String -> Expr
186 mkStr str = Literal (StringLit str)
189 %************************************************************************
191 \subsection{Bindings}
193 %************************************************************************
196 javaTopBind :: CoreBind -> [Decl]
197 javaTopBind (NonRec bndr rhs) = [java_top_bind bndr rhs]
198 javaTopBind (Rec prs) = [java_top_bind bndr rhs | (bndr,rhs) <- prs]
200 java_top_bind :: Id -> CoreExpr -> Decl
201 -- public class f implements Code {
202 -- public Object ENTER() { ...translation of rhs... }
204 java_top_bind bndr rhs
205 = Class [Public] (shortName (javaIdTypeName bndr))
206 [] [codeName] [enter_meth]
208 enter_meth = Method [Public]
212 (javaExpr vmRETURN rhs)
215 %************************************************************************
217 \subsection{Expressions}
219 %************************************************************************
222 javaVar :: Id -> Expr
223 javaVar v | isGlobalName (idName v) = mkNew (javaIdType v) []
224 | otherwise = Var (javaName v)
226 javaLit :: Literal.Literal -> Expr
227 javaLit (MachInt i) = Literal (IntLit (fromInteger i))
228 javaLit (MachChar c) = Literal (CharLit c)
229 javaLit (MachStr fs) = Literal (StringLit str)
231 str = concatMap renderString (_UNPK_ fs) ++ "\\000"
232 -- This should really handle all the chars 0..31.
233 renderString '\NUL' = "\\000"
234 renderString other = [other]
236 javaLit other = pprPanic "javaLit" (ppr other)
238 -- Pass in the 'shape' of the result.
239 javaExpr :: (Expr -> Statement) -> CoreExpr -> [Statement]
240 -- Generate code to apply the value of
241 -- the expression to the arguments aleady on the stack
242 javaExpr r (CoreSyn.Var v) = [r (javaVar v)]
243 javaExpr r (CoreSyn.Lit l) = [r (javaLit l)]
244 javaExpr r (CoreSyn.App f a) = javaApp r f [a]
245 javaExpr r e@(CoreSyn.Lam _ _) = javaLam r (collectBinders e)
246 javaExpr r (CoreSyn.Case e x alts) = javaCase r e x alts
247 javaExpr r (CoreSyn.Let bind body) = javaBind bind ++ javaExpr r body
248 javaExpr r (CoreSyn.Note _ e) = javaExpr r e
250 javaCase :: (Expr -> Statement) -> CoreExpr -> Id -> [CoreAlt] -> [Statement]
251 -- case e of x { Nil -> r1
254 -- final Object x = VM.WHNF(...code for e...)
255 -- else if x instance_of Nil {
256 -- ...translation of r1...
257 -- } else if x instance_of Cons {
258 -- final Object p = ((Cons) x).f1
259 -- final Object q = ((Cons) x).f2
260 -- ...translation of r2...
261 -- } else throw java.lang.Exception
263 -- This first special case happens a lot, typically
264 -- during dictionary deconstruction.
265 -- We need to access at least *one* field, to check to see
266 -- if we have correct constructor.
267 -- If we've got the wrong one, this is _|_, and the
268 -- casting will catch this with an exception.
270 javaCase r e x [(DataAlt d,bs,rhs)] | length bs > 0
271 = java_expr PushExpr e ++
272 [ var [Final] (javaName x)
273 (whnf primRep (vmPOP (primRepToType primRep))) ] ++
277 primRep = idPrimRep x
278 whnf PtrRep = vmWHNF -- needs evaluation
279 whnf _ = id -- anything else does notg
281 bind_args d bs = [var [Final] (javaName b)
282 (Access (Cast (javaConstrWkrType d) (javaVar x)
285 | (b,f) <- filter isId bs `zip` (constrToFields d)
286 , not (isDeadBinder b)
290 | isIfThenElse && isPrimCmp =
291 javaIfThenElse r (fromJust maybePrim) tExpr fExpr
293 java_expr PushExpr e ++
294 [ var [Final] (javaName x)
295 (whnf primRep (vmPOP (primRepToType primRep)))
296 , mkIfThenElse (map mk_alt alts)
299 isIfThenElse = CoreUtils.exprType e == boolTy
300 -- also need to check that x is not free in
301 -- any of the branches.
302 maybePrim = findCmpPrim e []
303 isPrimCmp = isJust maybePrim
304 tExpr = matches trueDataCon alts
305 fExpr = matches falseDataCon alts
307 matches con [] = error "no match for true or false branch of if/then/else"
308 matches con ((DataAlt d,[],rhs):rest) | con == d = rhs
309 matches con ((DEFAULT,[],rhs):_) = rhs
310 matches con (other:rest) = matches con rest
312 primRep = idPrimRep x
313 whnf PtrRep = vmWHNF -- needs evaluation
316 mk_alt (DEFAULT, [], rhs) = (true, Block (javaExpr r rhs))
317 mk_alt (DataAlt d, bs, rhs) = (instanceOf x d, Block (bind_args d bs ++ javaExpr r rhs))
318 mk_alt alt@(LitAlt lit, [], rhs)
319 = (eqLit lit , Block (javaExpr r rhs))
320 mk_alt alt@(LitAlt _, _, _) = pprPanic "mk_alt" (ppr alt)
323 eqLit (MachInt n) = Op (Literal (IntLit n))
327 eqLit (MachChar n) = Op (Literal (CharLit n))
330 eqLit other = pprPanic "eqLit" (ppr other)
332 bind_args d bs = [var [Final] (javaName b)
333 (Access (Cast (javaConstrWkrType d) (javaVar x)
336 | (b,f) <- filter isId bs `zip` (constrToFields d)
337 , not (isDeadBinder b)
341 mkIfThenElse [(Var (Name "true" _),code)] = code
342 mkIfThenElse other = IfThenElse other
344 (Raise excName [Literal (StringLit "case failure")])
348 javaIfThenElse r cmp tExpr fExpr
350 - Now what we need to do is generate code for the if/then/else.
351 - [all arguments are already check for simpleness (Var or Lit).]
353 - if (<prim> arg1 arg2 arg3 ...) {
359 = [IfThenElse [(cmp,j_tExpr)] (Just j_fExpr)]
361 j_tExpr, j_fExpr :: Statement
362 j_tExpr = Block (javaExpr r tExpr)
363 j_fExpr = Block (javaExpr r fExpr)
365 javaBind (NonRec x rhs)
369 final Object x = new Thunk( new Code() { ...code for rhs_x... } )
372 = java_expr (SetVar name) rhs
374 name = case coreTypeToType rhs of
375 ty@(PrimType _) -> javaName x `withType` ty
376 _ -> javaName x `withType` codeType
379 {- rec { x = ...rhs_x...; y = ...rhs_y... }
381 class x implements Code {
383 public Object ENTER() { ...code for rhs_x...}
387 final x x_inst = new x();
390 final Thunk x = new Thunk( x_inst );
397 = (map mk_class prs) ++ (map mk_inst prs) ++
398 (map mk_thunk prs) ++ concat (map mk_knot prs)
400 mk_class (b,r) = Declaration (Class [] class_name [] [codeName] stmts)
402 class_name = javaIdTypeName b
403 stmts = [Field [] (javaName b `withType` codeType) Nothing | (b,_) <- prs] ++
404 [Method [Public] enterName [vmArg] [excName] (javaExpr vmRETURN r)]
406 mk_inst (b,r) = var [Final] name (mkNew ty [])
408 name@(Name _ ty) = javaInstName b
410 mk_thunk (b,r) = var [Final] (javaName b `withType` codeType)
411 (mkNew thunkType [Var (javaInstName b)])
413 mk_knot (b,_) = [ ExprStatement (Assign lhs rhs)
415 let lhs = Access (Var (javaInstName b)) (javaName b'),
416 let rhs = Var (javaName b')
419 javaLam :: (Expr -> Statement) -> ([CoreBndr], CoreExpr) -> [Statement]
420 javaLam r (bndrs, body)
421 | null val_bndrs = javaExpr r body
423 = vmCOLLECT (length val_bndrs) this
424 ++ [var [Final] n (vmPOP t) | n@(Name _ t) <- val_bndrs]
427 val_bndrs = map javaName (filter isId bndrs)
429 javaApp :: (Expr -> Statement) -> CoreExpr -> [CoreExpr] -> [Statement]
430 javaApp r (CoreSyn.App f a) as
431 | isValArg a = javaApp r f (a:as)
432 | otherwise = javaApp r f as
433 javaApp r (CoreSyn.Var f) as
434 = case isDataConId_maybe f of {
435 Just dc | length as == dataConRepArity dc
436 -- NOTE: Saturated constructors never returning a primitive at this point
438 -- We push the arguments backwards, because we are using
439 -- the (ugly) semantics of the order of evaluation of arguments,
440 -- to avoid making up local names. Oh to have a namesupply...
442 -> javaArgs (reverse as) ++
443 [r (New (javaIdType f)
451 vmCOLLECT (dataConRepArity dc) this ++
454 [ vmPOP ty | (Name _ ty) <- constrToFields dc ]
458 in javaArgs (reverse as) ++ [r (newCode stmts)]
459 ; other -> java_apply r (CoreSyn.Var f) as
462 javaApp r f as = java_apply r f as
464 -- This means, given a expression an a list of arguments,
465 -- generate code for "pushing the arguments on the stack,
466 -- and the executing the expression."
468 java_apply :: (Expr -> Statement) -> CoreExpr -> [CoreExpr] -> [Statement]
469 java_apply r f as = javaArgs as ++ javaExpr r f
471 -- This generates statements that have the net effect
472 -- of pushing values (perhaps thunks) onto the stack.
474 javaArgs :: [CoreExpr] -> [Statement]
475 javaArgs args = concat [ java_expr PushExpr a | a <- args, isValArg a]
477 javaPops :: [CoreExpr] -> [Expr]
478 javaPops args = [ vmPOP (primRepToType (Type.typePrimRep (CoreUtils.exprType a)))
484 -- The result is a list of statments that have the effect of
485 -- pushing onto the stack (via one of the VM.PUSH* commands)
486 -- the argument, (or returning, or setting a variable)
489 {- This is mixing two things.
490 (1) Optimizations for things like primitives, whnf calls, etc.
491 (2) If something needs a thunk constructor round it.
492 - Seperate them at some point!
494 data ExprRetStyle = SetVar Name | PushExpr | ReturnExpr
496 java_expr :: ExprRetStyle -> CoreExpr -> [Statement]
497 java_expr _ (CoreSyn.Type t) = pprPanic "java_expr" (ppr t)
499 | isPrimCall = [push (fromJust maybePrim)]
500 -- This is a shortcut,
501 -- basic names and literals do not need a code block
502 -- to compute the value.
503 | isPrim primty && CoreUtils.exprIsTrivial e = javaExpr push e
505 let expr = javaExpr vmRETURN e
506 code = access (vmWHNF (newCode expr)) (primRepToType primty)
509 let expr = javaExpr vmRETURN e
511 code' = if CoreUtils.exprIsValue e
512 || CoreUtils.exprIsTrivial e
518 maybePrim = findFnPrim e []
519 isPrimCall = isJust maybePrim
522 SetVar name -> var [Final] name e
524 ReturnExpr -> vmRETURN e
525 corety = CoreUtils.exprType e
526 primty = Type.typePrimRep corety
527 isPrim PtrRep = False -- only this needs updated
530 coreTypeToType = primRepToType . Type.typePrimRep . CoreUtils.exprType
532 renameForKeywords :: (NamedThing name) => name -> String
533 renameForKeywords name
534 | str `elem` keywords = "zdk" ++ str
537 str = getOccString name
554 %************************************************************************
556 \subsection{Helper functions}
558 %************************************************************************
561 true, this,javaNull :: Expr
563 true = Var (Name "true" (PrimType PrimBoolean))
564 javaNull = Var (Name "null" objectType)
566 vmCOLLECT :: Int -> Expr -> [Statement]
568 vmCOLLECT n e = [ExprStatement
569 (Call varVM collectName
570 [ Literal (IntLit (toInteger n))
576 vmPOP :: Type -> Expr
577 vmPOP ty = Call varVM (Name ("POP" ++ suffix ty) ty) []
579 vmPUSH :: Expr -> Statement
580 vmPUSH e = ExprStatement
581 (Call varVM (Name ("PUSH" ++ suffix (exprType e)) void) [e])
583 vmRETURN :: Expr -> Statement
584 vmRETURN e = Return (
586 PrimType _ -> Call varVM (Name ("RETURN" ++ suffix ty)
593 var :: [Modifier] -> Name -> Expr -> Statement
594 var ms field_name@(Name _ ty) value
595 | exprType value == ty = Declaration (Field ms field_name (Just value))
596 | otherwise = var ms field_name (Cast ty value)
598 vmWHNF :: Expr -> Expr
599 vmWHNF e = Call varVM whnfName [e]
601 suffix :: Type -> String
602 suffix (PrimType t) = primName t
605 primName :: PrimType -> String
606 primName PrimInt = "int"
607 primName PrimChar = "char"
608 primName PrimByte = "byte"
609 primName PrimBoolean = "boolean"
610 primName _ = error "unsupported primitive"
615 instanceOf :: Id -> DataCon -> Expr
616 instanceOf x data_con
617 = InstanceOf (Var (javaName x)) (javaConstrWkrType data_con)
619 newCode :: [Statement] -> Expr
620 newCode [Return e] = e
621 newCode stmts = New codeType [] (Just [Method [Public] enterName [vmArg] [excName] stmts])
623 newThunk :: Expr -> Expr
624 newThunk e = New thunkType [e] Nothing
627 vmArg = Parameter [Final] vmName
629 -- This is called with boolean compares, checking
630 -- to see if we can do an obvious shortcut.
631 -- If there is, we return a (GOO) expression for doing this,
633 -- So if, we have case (#< x y) of { True -> e1; False -> e2 },
634 -- we will call findCmpFn with (#< x y), this return Just (Op x "<" y)
636 findCmpPrim :: CoreExpr -> [Expr] -> Maybe Expr
637 findCmpPrim (CoreSyn.App f a) as =
639 CoreSyn.Var v -> findCmpPrim f (javaVar v:as)
640 CoreSyn.Lit l -> findCmpPrim f (javaLit l:as)
642 findCmpPrim (CoreSyn.Var p) as =
643 case isPrimOpId_maybe p of
644 Just prim -> find_cmp_prim prim as
646 findCmpPrim _ as = Nothing
648 find_cmp_prim cmpPrim args@[a,b] =
658 fn op = Just (Op a op b)
659 find_cmp_prim _ _ = Nothing
661 findFnPrim :: CoreExpr -> [Expr] -> Maybe Expr
662 findFnPrim (CoreSyn.App f a) as =
664 CoreSyn.Var v -> findFnPrim f (javaVar v:as)
665 CoreSyn.Lit l -> findFnPrim f (javaLit l:as)
667 findFnPrim (CoreSyn.Var p) as =
668 case isPrimOpId_maybe p of
669 Just prim -> find_fn_prim prim as
671 findFnPrim _ as = Nothing
673 find_fn_prim cmpPrim args@[a,b] =
680 fn op = Just (Op a op b)
681 find_fn_prim _ _ = Nothing
684 %************************************************************************
686 \subsection{Haskell to Java Types}
688 %************************************************************************
691 exprType (Var (Name _ t)) = t
692 exprType (Literal lit) = litType lit
693 exprType (Cast t _) = t
694 exprType (New t _ _) = t
695 exprType (Call _ (Name _ t) _) = t
696 exprType (Access _ (Name _ t)) = t
697 exprType (Raise t _) = error "do not know the type of raise!"
698 exprType (Op _ op _) | op `elem` ["==","/=","<","<=","=>",">"]
699 = PrimType PrimBoolean
700 exprType (Op x op _) | op `elem` ["+","-","*"]
702 exprType expr = error ("can't figure out an expression type: " ++ show expr)
704 litType (IntLit i) = PrimType PrimInt
705 litType (CharLit i) = PrimType PrimChar
706 litType (StringLit i) = stringType -- later, might use char array?
709 %************************************************************************
711 \subsection{Name mangling}
713 %************************************************************************
716 codeName, excName, thunkName :: TypeName
717 codeName = "haskell.runtime.Code"
718 thunkName = "haskell.runtime.Thunk"
719 excName = "java.lang.Exception"
721 enterName, vmName,thisName,collectName, whnfName :: Name
722 enterName = Name "ENTER" objectType
723 vmName = Name "VM" vmType
724 thisName = Name "this" (Type "<this>")
725 collectName = Name "COLLECT" void
726 whnfName = Name "WHNF" objectType
728 fieldName :: Int -> Type -> Name -- Names for fields of a constructor
729 fieldName n ty = Name ("f" ++ show n) ty
731 withType :: Name -> Type -> Name
732 withType (Name n _) t = Name n t
734 -- This maps (local only) names Ids to Names,
735 -- using the same string as the Id.
736 javaName :: Id -> Name
738 | isGlobalName (idName n) = error "useing javaName on global"
739 | otherwise = Name (getOccString n)
740 (primRepToType (idPrimRep n))
742 -- TypeName's are almost always global. This would typically return something
743 -- like Test.foo or Test.Foozdc or PrelBase.foldr.
744 -- Local might use locally bound types, (which do not have '.' in them).
746 javaIdTypeName :: Id -> TypeName
748 | isLocalName n' = renameForKeywords n'
749 | otherwise = moduleString (nameModule n') ++ "." ++ renameForKeywords n'
753 -- There is no such thing as a local type constructor.
755 javaTyConTypeName :: TyCon -> TypeName
756 javaTyConTypeName n = (moduleString (nameModule n') ++ "." ++ renameForKeywords n')
760 -- this is used for getting the name of a class when defining it.
761 shortName :: TypeName -> TypeName
762 shortName = reverse . takeWhile (/= '.') . reverse
764 -- The function that makes the constructor name
765 -- The constructor "Foo ..." in module Test,
766 -- would return the name "Test.Foo".
768 javaConstrWkrName :: DataCon -> TypeName
769 javaConstrWkrName = javaIdTypeName . dataConId
771 -- Makes x_inst for Rec decls
772 -- They are *never* is primitive
773 -- and always have local (type) names.
774 javaInstName :: Id -> Name
775 javaInstName n = Name (renameForKeywords n ++ "zdi_inst")
776 (Type (renameForKeywords n))
779 %************************************************************************
781 \subsection{Types and type mangling}
783 %************************************************************************
787 codeType, thunkType, valueType :: Type
788 codeType = Type codeName
789 thunkType = Type thunkName
790 valueType = Type "haskell.runtime.Value"
791 vmType = Type "haskell.runtime.VMEngine"
794 objectType, stringType :: Type
795 objectType = Type "java.lang.Object"
796 stringType = Type "java.lang.String"
799 void = PrimType PrimVoid
802 inttype = PrimType PrimInt
805 chartype = PrimType PrimChar
808 bytetype = PrimType PrimByte
810 -- This lets you get inside a possible "Value" type,
811 -- to access the internal unboxed object.
812 access :: Expr -> Type -> Expr
813 access expr (PrimType prim) = accessPrim (Cast valueType expr) prim
814 access expr other = expr
816 accessPrim expr PrimInt = Call expr (Name "intValue" inttype) []
817 accessPrim expr PrimChar = Call expr (Name "charValue" chartype) []
818 accessPrim expr PrimByte = Call expr (Name "byteValue" bytetype) []
819 accessPrim expr other = pprPanic "accessPrim" (text (show other))
821 -- This is where we map from typename to types,
822 -- allowing to match possible primitive types.
823 mkType :: TypeName -> Type
824 mkType "PrelGHC.Intzh" = inttype
825 mkType "PrelGHC.Charzh" = chartype
826 mkType other = Type other
828 -- Turns a (global) Id into a Type (fully qualified name).
829 javaIdType :: Id -> Type
830 javaIdType = mkType . javaIdTypeName
832 javaLocalIdType :: Id -> Type
833 javaLocalIdType = primRepToType . idPrimRep
835 primRepToType ::PrimRep -> Type
836 primRepToType PtrRep = objectType
837 primRepToType IntRep = inttype
838 primRepToType CharRep = chartype
839 primRepToType Int8Rep = bytetype
840 primRepToType AddrRep = objectType
841 primRepToType other = pprPanic "primRepToType" (ppr other)
843 -- The function that makes the constructor name
844 javaConstrWkrType :: DataCon -> Type
845 javaConstrWkrType con = Type (javaConstrWkrName con)
848 %************************************************************************
850 \subsection{Class Lifting}
852 %************************************************************************
854 This is a very simple class lifter. It works by carrying inwards a
855 list of bound variables (things that might need to be passed to a
857 * Any variable references is check with this list, and if it is
858 bound, then it is not top level, external reference.
859 * This means that for the purposes of lifting, it might be free
860 inside a lifted inner class.
861 * We remember these "free inside the inner class" values, and
862 use this list (which is passed, via the monad, outwards)
869 combine :: [Name] -> [Name] -> [Name]
870 combine [] names = names
871 combine names [] = names
872 combine (name:names) (name':names')
873 | name < name' = name : combine names (name':names')
874 | name > name' = name' : combine (name:names) names'
875 | name == name = name : combine names names'
876 | otherwise = error "names are not a total order"
878 both :: [Name] -> [Name] -> [Name]
881 both (name:names) (name':names')
882 | name < name' = both names (name':names')
883 | name > name' = both (name:names) names'
884 | name == name = name : both names names'
885 | otherwise = error "names are not a total order"
887 combineEnv :: Env -> [Name] -> Env
888 combineEnv (Env bound env) new = Env (bound `combine` new) env
890 addTypeMapping :: TypeName -> TypeName -> [Name] -> Env -> Env
891 addTypeMapping origName newName frees (Env bound env)
892 = Env bound ((origName,(newName,frees)) : env)
894 -- This a list of bound vars (with types)
895 -- and a mapping from old class name
896 -- to inner class name (with a list of frees that need passed
897 -- to the inner class.)
899 data Env = Env Bound [(TypeName,(TypeName,[Name]))]
902 LifterM { unLifterM ::
903 TypeName -> -- this class name
904 Int -> -- uniq supply
907 , [Decl] -- lifted classes
912 instance Monad LifterM where
913 return a = LifterM (\ n s -> (a,[],[],s))
914 (LifterM m) >>= fn = LifterM (\ n s ->
917 -> case unLifterM (fn a) n s of
918 (a,frees2,lifted2,s) -> ( a
919 , combine frees frees2
924 liftAccess :: Env -> Name -> LifterM ()
925 liftAccess env@(Env bound _) name
926 | name `elem` bound = LifterM (\ n s -> ((),[name],[],s))
927 | otherwise = return ()
929 scopedName :: TypeName -> LifterM a -> LifterM a
930 scopedName name (LifterM m) =
933 (a,frees,lifted,_) -> (a,frees,lifted,s)
936 genAnonInnerClassName :: LifterM TypeName
937 genAnonInnerClassName = LifterM (\ n s ->
945 genInnerClassName :: TypeName -> LifterM TypeName
946 genInnerClassName name = LifterM (\ n s ->
954 getFrees :: LifterM a -> LifterM (a,Frees)
955 getFrees (LifterM m) = LifterM (\ n s ->
957 (a,frees,lifted,n) -> ((a,frees),frees,lifted,n)
960 rememberClass :: Decl -> LifterM ()
961 rememberClass decl = LifterM (\ n s -> ((),[],[decl],s))
964 liftCompilationUnit :: CompilationUnit -> CompilationUnit
965 liftCompilationUnit (Package name ds) =
966 Package name (concatMap liftCompilationUnit' ds)
968 liftCompilationUnit' :: Decl -> [Decl]
969 liftCompilationUnit' decl =
970 case unLifterM (liftDecls True (Env [] []) [decl]) [] 1 of
971 (ds,_,ds',_) -> ds ++ ds'
974 -- The bound vars for the current class have
975 -- already be captured before calling liftDecl,
976 -- because they are in scope everywhere inside the class.
978 liftDecl :: Bool -> Env -> Decl -> LifterM Decl
979 liftDecl = \ top env decl ->
981 { Import n -> return (Import n)
983 do { e <- liftMaybeExpr env e
984 ; return (Field mfs (liftName env n) e)
986 ; Constructor mfs n as ss ->
987 do { let newBound = getBoundAtParameters as
988 ; (ss,_) <- liftStatements (combineEnv env newBound) ss
989 ; return (Constructor mfs n (liftParameters env as) ss)
991 ; Method mfs n as ts ss ->
992 do { let newBound = getBoundAtParameters as
993 ; (ss,_) <- liftStatements (combineEnv env newBound) ss
994 ; return (Method mfs (liftName env n) (liftParameters env as) ts ss)
996 ; Comment s -> return (Comment s)
997 ; Interface mfs n is ms -> error "interfaces not supported"
998 ; Class mfs n x is ms ->
999 do { let newBound = getBoundAtDecls ms
1000 ; ms <- scopedName n
1001 (liftDecls False (combineEnv env newBound) ms)
1002 ; return (Class mfs n x is ms)
1006 liftDecls :: Bool -> Env -> [Decl] -> LifterM [Decl]
1007 liftDecls top env = mapM (liftDecl top env)
1009 getBoundAtDecls :: [Decl] -> Bound
1010 getBoundAtDecls = foldr combine [] . map getBoundAtDecl
1012 getBoundAtDecl :: Decl -> Bound
1013 getBoundAtDecl (Field _ n _) = [n]
1014 getBoundAtDecl _ = []
1016 getBoundAtParameters :: [Parameter] -> Bound
1017 getBoundAtParameters = foldr combine [] . map getBoundAtParameter
1020 getBoundAtParameter :: Parameter -> Bound
1021 getBoundAtParameter (Parameter _ n) = [n]
1024 liftStatement :: Env -> Statement -> LifterM (Statement,Env)
1025 liftStatement = \ env stmt ->
1027 { Skip -> return (stmt,env)
1028 ; Return e -> do { e <- liftExpr env e
1029 ; return (Return e,env)
1031 ; Block ss -> do { (ss,env) <- liftStatements env ss
1032 ; return (Block ss,env)
1034 ; ExprStatement e -> do { e <- liftExpr env e
1035 ; return (ExprStatement e,env)
1037 ; Declaration decl@(Field mfs n e) ->
1038 do { e <- liftMaybeExpr env e
1039 ; return ( Declaration (Field mfs (liftName env n) e)
1040 , env `combineEnv` getBoundAtDecl decl
1043 ; Declaration decl@(Class mfs n x is ms) ->
1044 do { innerName <- genInnerClassName n
1045 ; frees <- liftClass env innerName ms x is
1046 ; return ( Declaration (Comment ["lifted " ++ n])
1047 , addTypeMapping n innerName frees env
1050 ; Declaration d -> error "general Decl not supported"
1051 ; IfThenElse ecs s -> ifthenelse env ecs s
1052 ; Switch e as d -> error "switch not supported"
1056 -> [(Expr,Statement)]
1057 -> (Maybe Statement)
1058 -> LifterM (Statement,Env)
1059 ifthenelse env pairs may_stmt =
1060 do { let (exprs,stmts) = unzip pairs
1061 ; exprs <- liftExprs env exprs
1062 ; (stmts,_) <- liftStatements env stmts
1063 ; may_stmt <- case may_stmt of
1064 Just stmt -> do { (stmt,_) <- liftStatement env stmt
1065 ; return (Just stmt)
1067 Nothing -> return Nothing
1068 ; return (IfThenElse (zip exprs stmts) may_stmt,env)
1071 liftStatements :: Env -> [Statement] -> LifterM ([Statement],Env)
1072 liftStatements env [] = return ([],env)
1073 liftStatements env (s:ss) =
1074 do { (s,env) <- liftStatement env s
1075 ; (ss,env) <- liftStatements env ss
1079 liftExpr :: Env -> Expr -> LifterM Expr
1080 liftExpr = \ env expr ->
1082 { Var n -> do { liftAccess env n
1083 ; return (Var (liftName env n))
1085 ; Literal l -> return expr
1086 ; Cast t e -> do { e <- liftExpr env e
1087 ; return (Cast (liftType env t) e)
1089 ; Access e n -> do { e <- liftExpr env e
1090 -- do not consider n as an access, because
1091 -- this is a indirection via a reference
1092 ; return (Access e n)
1094 ; Assign l r -> do { l <- liftExpr env l
1095 ; r <- liftExpr env r
1096 ; return (Assign l r)
1098 ; InstanceOf e t -> do { e <- liftExpr env e
1099 ; return (InstanceOf e (liftType env t))
1101 ; Raise n es -> do { es <- liftExprs env es
1102 ; return (Raise n es)
1104 ; Call e n es -> do { e <- liftExpr env e
1105 ; es <- mapM (liftExpr env) es
1106 ; return (Call e n es)
1108 ; Op e1 o e2 -> do { e1 <- liftExpr env e1
1109 ; e2 <- liftExpr env e2
1110 ; return (Op e1 o e2)
1112 ; New n es ds -> new env n es ds
1115 liftParameter env (Parameter ms n) = Parameter ms (liftName env n)
1116 liftParameters env = map (liftParameter env)
1118 liftName env (Name n t) = Name n (liftType env t)
1120 liftExprs :: Env -> [Expr] -> LifterM [Expr]
1121 liftExprs = mapM . liftExpr
1124 liftMaybeExpr :: Env -> (Maybe Expr) -> LifterM (Maybe Expr)
1125 liftMaybeExpr env Nothing = return Nothing
1126 liftMaybeExpr env (Just stmt) = do { stmt <- liftExpr env stmt
1127 ; return (Just stmt)
1132 new :: Env -> Type -> [Expr] -> Maybe [Decl] -> LifterM Expr
1133 new env@(Env _ pairs) typ args Nothing =
1134 do { args <- liftExprs env args
1135 ; return (liftNew env typ args)
1137 new env typ [] (Just inner) =
1138 -- anon. inner class
1139 do { innerName <- genAnonInnerClassName
1140 ; frees <- liftClass env innerName inner [] [unType typ]
1141 ; return (New (Type (innerName))
1145 where unType (Type name) = name
1146 unType _ = error "incorrect type style"
1147 new env typ _ (Just inner) = error "cant handle inner class with args"
1150 liftClass :: Env -> TypeName -> [Decl] -> [TypeName] -> [TypeName] -> LifterM [ Name ]
1151 liftClass env@(Env bound _) innerName inner xs is =
1152 do { let newBound = getBoundAtDecls inner
1154 getFrees (liftDecls False (env `combineEnv` newBound) inner)
1155 ; let trueFrees = filter (\ (Name xs _) -> xs /= "VM") (both frees bound)
1156 ; let freeDefs = [ Field [Final] n Nothing | n <- trueFrees ]
1157 ; let cons = mkCons innerName trueFrees
1158 ; let innerClass = Class [] innerName xs is (freeDefs ++ [cons] ++ inner)
1159 ; rememberClass innerClass
1163 liftType :: Env -> Type -> Type
1164 liftType (Env _ env) typ@(Type name)
1165 = case lookup name env of
1167 Just (nm,_) -> Type nm
1168 liftType _ typ = typ
1170 liftNew :: Env -> Type -> [Expr] -> Expr
1171 liftNew (Env _ env) typ@(Type name) exprs
1172 = case lookup name env of
1173 Nothing -> New typ exprs Nothing
1174 Just (nm,args) | null exprs
1175 -> New (Type nm) (map Var args) Nothing
1176 _ -> error "pre-lifted constructor with arguments"