[project @ 2000-06-09 00:43:55 by andy]
[ghc-hetmet.git] / ghc / compiler / javaGen / JavaGen.lhs
index c9f86d2..5af2b0a 100644 (file)
@@ -1,22 +1,60 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-2000
 %
 \section{Generate Java}
 
+Name mangling for Java.
+~~~~~~~~~~~~~~~~~~~~~~
+
+Haskell has a number of namespaces. The Java translator uses
+the standard Haskell mangles (see OccName.lhs), and some extra
+mangles.
+
+All names are hidden inside packages.
+
+module name:
+  - becomes a first level java package.
+  - can not clash with java, because haskell modules are upper case,
+     java default packages are lower case.
+
+function names: 
+  - these turn into classes
+  - java keywords (eg. private) have the suffix "zdk" ($k) added.
+
+data *types*
+  - These have a base class, so need to appear in the 
+    same name space as other object. for example data Foo = Foo
+  - We add a postfix to types: "zdc" ($c)
+  - Types are upper case, so never clash with keywords
+
+data constructors
+  - There are tWO classes for each Constructor
+   (1) - Class with the payload extends the relevent datatype baseclass.
+       - This class has the prefix zdw ($W)
+   (2) - Constructor *wrapper* just use their own name.
+    - Constructors are upper case, so never clash with keywords
+    - So Foo would become 2 classes.
+       * Foo           -- the constructor wrapper
+       * zdwFoo        -- the worker, with the payload
+
 \begin{code}
 module JavaGen( javaGen ) where
 
 import Java
 
 import Literal ( Literal(..) )
-import Id      ( Id, isDataConId_maybe, isId, idName, isDeadBinder )
-import Name    ( NamedThing(..), getOccString, isGlobalName )
-import DataCon ( DataCon, dataConRepArity, dataConId )
-import qualified CoreSyn 
+import Id      ( Id, isDataConId_maybe, isId, idName, isDeadBinder, idPrimRep )
+import Name    ( NamedThing(..), getOccString, isGlobalName 
+               , nameModule )
+import PrimRep  ( PrimRep(..) )
+import DataCon ( DataCon, dataConRepArity, dataConRepArgTys, dataConId )
+import qualified TypeRep
+import qualified Type
+import qualified CoreSyn
 import CoreSyn ( CoreBind, CoreExpr, CoreAlt, CoreBndr,
                  Bind(..), Alt, AltCon(..), collectBinders, isValArg
                )
-import CoreUtils( exprIsValue, exprIsTrivial )
+import qualified CoreUtils
 import Module  ( Module, moduleString )
 import TyCon   ( TyCon, isDataTyCon, tyConDataCons )
 import Outputable
@@ -30,11 +68,13 @@ import Outputable
 javaGen :: Module -> [Module] -> [TyCon] -> [CoreBind] -> CompilationUnit
 
 javaGen mod import_mods tycons binds
-  = Package [moduleString mod] decls
+  = id {-liftCompilationUnit-} package
   where
-    decls = [Import [moduleString mod] | mod <- import_mods] ++
+    decls = [Import "haskell.runtime.*"] ++
+           [Import (moduleString mod) | mod <- import_mods] ++
            concat (map javaTyCon (filter isDataTyCon tycons)) ++ 
            concat (map javaTopBind binds)
+    package = Package (moduleString mod) decls
 \end{code}
 
 
@@ -54,23 +94,87 @@ javaTyCon :: TyCon -> [Decl]
 --     public class $wNil extends List {}
 
 javaTyCon tycon 
-  = tycon_jclass : map constr_class constrs
+  = tycon_jclass : concat (map constr_class constrs)
   where
     constrs = tyConDataCons tycon
-    tycon_jclass_jname = javaName tycon
-    tycon_jclass = Class [Public] tycon_jclass_jname [] [] []
+    tycon_jclass_jname =  javaTyConTypeName tycon ++ "zdc"
+    tycon_jclass = Class [Public] (shortName tycon_jclass_jname) [] [] []
 
     constr_class data_con
-       = Class [Public] constr_jname [tycon_jclass_jname] [] field_decls
+       = [ Class [Public] constr_jname [tycon_jclass_jname] []
+                               (field_decls ++ [cons_meth,debug_meth])
+         ]
        where
-         constr_jname = javaConstrWkrName data_con
-         enter_meth   = Method [Public] objectType enterName [] stmts
-         n_val_args   = dataConRepArity data_con
-         field_names  = map fieldName [1..n_val_args]
-         field_decls  = [Field [Public] objectType f Nothing | f <- field_names]
-         stmts        = vmCOLLECT n_val_args (Var thisName) ++
-                        [var [Final] objectType f vmPOP | f <- field_names] ++
-                        [Return (New constr_jname (map Var field_names) Nothing)]
+         constr_jname = shortName (javaConstrWkrName data_con)
+
+         field_names  = constrToFields data_con
+         field_decls  = [ Field [Public] n Nothing 
+                        | n <- field_names
+                        ]
+
+         cons_meth    = mkCons constr_jname field_names
+
+         debug_meth   = Method [Public] (Name "toString" stringType)
+                                        []
+                                        []
+                      (  [ Declaration (Field [] txt Nothing) ]
+                      ++ [ ExprStatement
+                               (Assign (Var txt)
+                                           (mkStr
+                                               ("( " ++ 
+                                                 getOccString data_con ++ 
+                                                 " ")
+                                            )
+                               )
+                         ]
+                      ++ [ ExprStatement
+                               (Assign (Var txt)
+                                  (Op (Var txt)
+                                       "+" 
+                                      (Op (Var n) "+" litSp)
+                                  )
+                               )
+                         | n <- field_names
+                         ]
+                      ++ [ Return (Op (Var txt)
+                                       "+" 
+                                     (mkStr ")")
+                                  )
+                         ]
+                      )
+
+         litSp    = mkStr " "
+         txt      = Name "__txt" stringType
+        
+
+-- This checks to see the type is reasonable to call new with.
+-- primitives might use a static method later.
+mkNew :: Type -> [Expr] -> Expr
+mkNew t@(PrimType primType) _  = error "new primitive -- fix it???"
+mkNew t@(Type _)            es = New t es Nothing
+mkNew _                     _  = error "new with strange arguments"
+
+constrToFields :: DataCon -> [Name]
+constrToFields cons = 
+       [ fieldName i t 
+       | (i,t) <- zip [1..] (map primRepToType
+                                 (map Type.typePrimRep
+                                      (dataConRepArgTys cons)
+                                 )
+                            )
+       ]
+
+mkCons :: TypeName -> [Name] -> Decl
+mkCons name args = Constructor [Public] name
+       [ Parameter [] n | n <- args ]
+       [ ExprStatement (Assign 
+                          (Access this n)
+                          (Var n)
+                        )
+                   | n <- args ]
+
+mkStr :: String -> Expr
+mkStr str = Literal (StringLit str)
 \end{code}
 
 %************************************************************************
@@ -89,12 +193,16 @@ java_top_bind :: Id -> CoreExpr -> Decl
 --       public Object ENTER() { ...translation of rhs... }
 --     }
 java_top_bind bndr rhs
-  = Class [Public] (javaName bndr) [] [codeName] [enter_meth]
+  = Class [Public] (shortName (javaIdTypeName bndr))
+               [] [codeName] [enter_meth]
   where
-    enter_meth = Method [Public] objectType enterName [] (javaExpr rhs)
+    enter_meth = Method [Public]
+                       enterName
+                       [vmArg]
+                       [excName]
+                       (javaExpr vmRETURN rhs)
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection{Expressions}
@@ -103,27 +211,27 @@ java_top_bind bndr rhs
 
 \begin{code}
 javaVar :: Id -> Expr
-javaVar v | isGlobalName (idName v) = New (javaName v) [] Nothing
-         | otherwise               = Var (javaName v)
-
+javaVar v | isGlobalName (idName v) = mkNew (javaIdType v) []
+         | otherwise               =   Var (javaName v)
 
-javaLit :: Literal.Literal -> Lit
-javaLit (MachInt i)  = UIntLit (fromInteger i)
-javaLit (MachChar c) = UCharLit c
+javaLit :: Literal.Literal -> Expr
+javaLit (MachInt i)  = Literal (IntLit (fromInteger i))
+javaLit (MachChar c) = Literal (CharLit c)             
 javaLit other       = pprPanic "javaLit" (ppr other)
 
-javaExpr :: CoreExpr -> [Statement]
+-- Pass in the 'shape' of the result.
+javaExpr :: (Expr -> Statement) -> CoreExpr -> [Statement]
 -- Generate code to apply the value of 
 -- the expression to the arguments aleady on the stack
-javaExpr (CoreSyn.Var v)   = [Return (javaVar v)]
-javaExpr (CoreSyn.Lit l)   = [Return (Literal (javaLit l))]
-javaExpr (CoreSyn.App f a) = javaApp f [a]
-javaExpr e@(CoreSyn.Lam _ _) = javaLam (collectBinders e)
-javaExpr (CoreSyn.Case e x alts) = javaCase e x alts
-javaExpr (CoreSyn.Let bind body) = javaBind bind ++ javaExpr body
-javaExpr (CoreSyn.Note _ e)     = javaExpr e
-
-javaCase :: CoreExpr -> Id -> [CoreAlt] -> [Statement]
+javaExpr r (CoreSyn.Var v)   = [r (javaVar v)]
+javaExpr r (CoreSyn.Lit l)   = [r (javaLit l)]
+javaExpr r (CoreSyn.App f a) = javaApp r f [a]
+javaExpr r e@(CoreSyn.Lam _ _) = javaLam r (collectBinders e)
+javaExpr r (CoreSyn.Case e x alts) = javaCase r e x alts
+javaExpr r (CoreSyn.Let bind body) = javaBind bind ++ javaExpr r body
+javaExpr r (CoreSyn.Note _ e)   = javaExpr r e
+
+javaCase :: (Expr -> Statement) -> CoreExpr -> Id -> [CoreAlt] -> [Statement]
 --     case e of x { Nil      -> r1
 --                   Cons p q -> r2 }
 -- ==>
@@ -136,18 +244,39 @@ javaCase :: CoreExpr -> Id -> [CoreAlt] -> [Statement]
 --             ...translation of r2...
 --     } else return null
 
-javaCase e x alts
-  =  [var [Final] objectType (javaName x) (vmWHNF (javaArg e)),
-      IfThenElse (map mk_alt alts) Nothing]
+javaCase r e x alts
+  -- TODO: This will need to map prims to "haskell.runtime.Value".
+  =  javaArg Nothing e ++
+     [ var [Final] (javaName x)
+                  (whnf primRep (vmPOP (primRepToType primRep)))
+     , IfThenElse (map mk_alt alts) (Just (Return javaNull))
+     ]
   where
-     mk_alt (DEFAULT, [], rhs)   = (true,          Block (javaExpr rhs))
-     mk_alt (DataAlt d, bs, rhs) = (instanceOf x d, Block (bind_args d bs ++ javaExpr rhs))
+     primRep = idPrimRep x
+     whnf PtrRep = vmWHNF      -- needs evaluation
+     whnf _      = id
+
+     mk_alt (DEFAULT, [], rhs)   = (true,          Block (javaExpr r rhs))
+     mk_alt (DataAlt d, bs, rhs) = (instanceOf x d, Block (bind_args d bs ++ javaExpr r rhs))
+     mk_alt alt@(LitAlt lit, [], rhs) 
+                                = (eqLit lit     , Block (javaExpr r rhs))
      mk_alt alt@(LitAlt _, _, _) = pprPanic "mk_alt" (ppr alt)
 
-     bind_args d bs = [var [Final] objectType (javaName b) 
-                          (Access (Cast (Type (javaConstrWkrName d)) (javaVar x)) f)
-                     | (b, f) <- filter isId bs `zip` map fieldName [1..],
-                       not (isDeadBinder b)
+
+     eqLit (MachInt n) = Op (Literal (IntLit n))
+                           "=="
+                           (Var (javaName x))
+     eqLit (MachChar n) = Op (Literal (CharLit n))
+                           "=="
+                           (Var (javaName x))
+     eqLit other       = pprPanic "eqLit" (ppr other)
+
+     bind_args d bs = [var [Final] (javaName b) 
+                          (Access (Cast (javaConstrWkrType d) (javaVar x)
+                                  ) f
+                          )
+                     | (b,f) <- filter isId bs `zip` (constrToFields d)
+                     , not (isDeadBinder b)
                      ]
 
 javaBind (NonRec x rhs)
@@ -156,7 +285,12 @@ javaBind (NonRec x rhs)
   ==>
        final Object x = new Thunk( new Code() { ...code for rhs_x... } )
 -}
-  = [var [Final] objectType (javaName x) (javaArg rhs)]
+
+  = javaArg (Just name) rhs
+  where
+    name = case coreTypeToType rhs of
+           ty@(PrimType _) -> javaName x `withType` ty
+           _               -> javaName x `withType` thunkType
 
 javaBind (Rec prs)
 {-     rec { x = ...rhs_x...; y = ...rhs_y... }
@@ -180,57 +314,107 @@ javaBind (Rec prs)
   = (map mk_class prs) ++ (map mk_inst prs) ++ 
     (map mk_thunk prs) ++ concat (map mk_knot prs)
   where
-    mk_class (b,r) = Declaration (Class [] (javaName b) [] [codeName] stmts)
+    mk_class (b,r) = Declaration (Class [] class_name [] [codeName] stmts)
                   where
-                    stmts = [Field [] codeType (javaName b) Nothing | (b,_) <- prs] ++
-                            [Method [Public] objectType enterName [] (javaExpr r)]     
+                    class_name = javaIdTypeName b
+                    stmts = [Field [] (javaName b `withType` codeType) Nothing | (b,_) <- prs] ++
+                            [Method [Public] enterName [vmArg] [excName] (javaExpr vmRETURN r)]        
 
-    mk_inst (b,r) = var [Final] (Type (javaName b)) (javaInstName b)
-                       (New (javaName b) [] Nothing)
+    mk_inst (b,r) = var [Final] (javaInstName b)
+                       (mkNew (javaIdType b) [])
 
-    mk_thunk (b,r) = var [Final] thunkType (javaName b)
-                        (New thunkName [Var (javaInstName b)] Nothing)
+    mk_thunk (b,r) = var [Final] (javaName b `withType` thunkType)
+                        (New thunkType [Var (javaInstName b)] Nothing)
 
-    mk_knot (b,_) = [ExprStatement (Assign lhs rhs) 
+    mk_knot (b,_) = [ ExprStatement (Assign lhs rhs) 
                    | (b',_) <- prs,
                      let lhs = Access (Var (javaInstName b)) (javaName b'),
                      let rhs = Var (javaName b')
                    ]
-               
-javaLam :: ([CoreBndr], CoreExpr) -> [Statement]
-javaLam (bndrs, body)
-  | null val_bndrs = javaExpr body
+
+-- We are needlessly
+javaLam :: (Expr -> Statement) -> ([CoreBndr], CoreExpr) -> [Statement]
+javaLam r (bndrs, body)
+  | null val_bndrs = javaExpr r body
   | otherwise
-  =  vmCOLLECT (length val_bndrs) (Var thisName)
-  ++ [var [Final] objectType (javaName n) vmPOP | n <- val_bndrs]
-  ++ javaExpr body
+  =  vmCOLLECT (length val_bndrs) this
+  ++ [var [Final] n (vmPOP t) | n@(Name _ t) <- val_bndrs]
+  ++ javaExpr r body
   where
-    val_bndrs = filter isId bndrs
+    val_bndrs = map javaName (filter isId bndrs)
 
-javaApp :: CoreExpr -> [CoreExpr] -> [Statement]
-javaApp (CoreSyn.App f a) as = javaApp f (a:as)
-javaApp (CoreSyn.Var f) as
+javaApp :: (Expr -> Statement) -> CoreExpr -> [CoreExpr] -> [Statement]
+javaApp r (CoreSyn.App f a) as = javaApp r f (a:as)
+javaApp r (CoreSyn.Var f) as
   = case isDataConId_maybe f of {
        Just dc | length as == dataConRepArity dc
                ->      -- Saturated constructors
-                  [Return (New (javaName f) (javaArgs as) Nothing)]
-
+                       -- never returning a primitive at this point
+                  javaArgs as ++
+                  [Return (New (javaIdType f) 
+                               (javaPops as)
+                               Nothing)]
     ; other ->   -- Not a saturated constructor
-       java_apply (CoreSyn.Var f) as
+       java_apply r (CoreSyn.Var f) as
     }
        
-javaApp f as = java_apply f as
-
-java_apply :: CoreExpr -> [CoreExpr] -> [Statement]
-java_apply f as = [ExprStatement (vmPUSH arg) | arg <- javaArgs as] ++ javaExpr f
-
-javaArgs :: [CoreExpr] -> [Expr]
-javaArgs args = [javaArg a | a <- args, isValArg a]
-
-javaArg :: CoreExpr -> Expr
-javaArg (CoreSyn.Type t) = pprPanic "javaArg" (ppr t)
-javaArg e | exprIsValue e || exprIsTrivial e = newCode (javaExpr e)
-         | otherwise                        = newThunk (newCode (javaExpr e))
+javaApp r f as = java_apply r f as
+
+-- This means, given a expression an a list of arguments,
+-- generate code for "pushing the arguments on the stack,
+--  and the executing the expression."
+
+java_apply :: (Expr -> Statement) -> CoreExpr -> [CoreExpr] -> [Statement]
+java_apply r f as = javaArgs as ++ javaExpr r f
+
+-- This generates statements that have the net effect
+-- of pushing values (perhaps thunks) onto the stack.
+
+javaArgs :: [CoreExpr] -> [Statement]
+javaArgs args = concat [ javaArg Nothing a | a <- args, isValArg a]
+
+javaPops :: [CoreExpr] -> [Expr]
+javaPops args = [ vmPOP (primRepToType (Type.typePrimRep (CoreUtils.exprType a)))
+               | a <- args 
+               , isValArg a
+               ]
+
+-- The arg's might or might not be thunkable.
+-- The result is a list of statments that have the effect of
+-- pushing onto the stack (via one of the VM.PUSH* commands)
+-- the argument, perhaps thunked.
+
+-- Later: this might take an argument that allows assignment
+-- into a variable rather than pushing onto the stack.
+
+javaArg :: Maybe Name -> CoreExpr -> [Statement]
+javaArg _ (CoreSyn.Type t) = pprPanic "javaArg" (ppr t)
+javaArg ret e 
+   | isPrim primty && CoreUtils.exprIsTrivial e = javaExpr push e
+   | isPrim primty = 
+         let expr  = javaExpr vmRETURN e
+             code  = access (vmWHNF (newCode expr)) (primRepToType primty)
+         in [push code]
+   | otherwise =
+         let expr  = javaExpr vmRETURN e
+             code  = newCode expr
+             code' = if CoreUtils.exprIsValue e 
+                     || CoreUtils.exprIsTrivial e 
+                     || isPrim primty
+                     then code
+                     else newThunk code
+         in [push code']
+   where
+       push e = case ret of
+                 Just name -> var [Final] name e
+                 Nothing -> vmPUSH e
+       corety = CoreUtils.exprType e
+       primty = Type.typePrimRep corety
+       isPrim PtrRep  = False
+       isPrim IntRep  = True
+       isPrim CharRep = True
+
+coreTypeToType = primRepToType . Type.typePrimRep . CoreUtils.exprType
 \end{code}
 
 %************************************************************************
@@ -240,37 +424,88 @@ javaArg e | exprIsValue e || exprIsTrivial e = newCode (javaExpr e)
 %************************************************************************
 
 \begin{code}
-true, this :: Expr
-this = Var thisName
-
-true = Var ["true"]
+true, this,javaNull :: Expr
+this = Var thisName 
+true = Var (Name "true" (PrimType PrimBoolean))
+javaNull = Var (Name "null" objectType)
 
 vmCOLLECT :: Int -> Expr -> [Statement]
 vmCOLLECT 0 e = []
-vmCOLLECT n e = [ExprStatement (Call (Var vmName) ["COLLECT"] [Literal (IntLit n), e])]
+vmCOLLECT n e = [ExprStatement 
+                   (Call varVM collectName
+                       [ Literal (IntLit (toInteger n))
+                       , e
+                       ]
+                   )
+               ]
+
+vmPOP :: Type -> Expr 
+vmPOP ty = Call varVM (Name ("POP" ++ suffix ty) ty) []
+
+vmPUSH :: Expr -> Statement
+vmPUSH e = ExprStatement 
+            (Call varVM (Name ("PUSH" ++ suffix (exprType e)) void) [e])
+
+vmRETURN :: Expr -> Statement
+vmRETURN e = Return (
+     case ty of
+       PrimType _ -> Call varVM (Name ("RETURN" ++ suffix ty)
+                                      valueType
+                                ) [e]
+       _ -> e)
+  where
+       ty = exprType e
 
-vmPOP :: Expr
-vmPOP = Call (Var vmName) ["POP"] []
+var :: [Modifier] -> Name -> Expr -> Statement
+var ms field_name value = Declaration (Field ms field_name (Just value))
 
-vmPUSH :: Expr -> Expr
-vmPUSH e = Call (Var vmName) ["PUSH"] [e]
+vmWHNF :: Expr -> Expr
+vmWHNF e = Call varVM whnfName [e]
 
-var :: [Modifier] -> Type -> Name -> Expr -> Statement
-var ms ty field_name value = Declaration (Field ms ty field_name (Just value))
+suffix :: Type -> String
+suffix (PrimType t) = primName t
+suffix _            = ""
 
-vmWHNF :: Expr -> Expr
-vmWHNF e = Call (Var vmName) ["WHNF"] [e]
+primName :: PrimType -> String
+primName PrimInt  = "int"
+primName PrimChar = "char"
+primName _         = error "unsupported primitive"
+
+varVM :: Expr
+varVM = Var vmName 
 
 instanceOf :: Id -> DataCon -> Expr
 instanceOf x data_con
-  = InstanceOf (Var (javaName x)) (Type (javaConstrWkrName data_con))
+  = InstanceOf (Var (javaName x)) (javaConstrWkrType data_con)
 
 newCode :: [Statement] -> Expr
 newCode [Return e] = e
-newCode stmts     = New codeName [] (Just [Method [Public] objectType enterName [] stmts])
+newCode stmts     = New codeType [] (Just [Method [Public] enterName [vmArg] [excName] stmts])
 
 newThunk :: Expr -> Expr
-newThunk e = New thunkName [e] Nothing
+newThunk e = New thunkType [e] Nothing
+
+vmArg :: Parameter
+vmArg = Parameter [Final] vmName
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection{Haskell to Java Types}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+exprType (Var (Name _ t)) = t
+exprType (Literal lit)    = litType lit
+exprType (Cast t _)       = t
+exprType (New t _ _)      = t
+exprType (Call _ (Name _ t) _) = t
+exprType expr = error ("can't figure out an expression type: " ++ show expr)
+
+litType (IntLit i)    = PrimType PrimInt
+litType (CharLit i)   = PrimType PrimChar
+litType (StringLit i) = error "<string?>"
 \end{code}
 
 %************************************************************************
@@ -280,38 +515,443 @@ newThunk e = New thunkName [e] Nothing
 %************************************************************************
 
 \begin{code}
-codeName, enterName, vmName :: Name
-codeName  = ["Code"]
-thunkName = ["Thunk"]
-enterName = ["ENTER"]
-vmName    = ["VM"]
-thisName  = ["this"]
+codeName, excName, thunkName :: TypeName
+codeName  = "haskell.runtime.Code"
+thunkName = "haskell.runtime.Thunk"
+excName   = "java.lang.Exception"
+
+enterName, vmName,thisName,collectName, whnfName :: Name
+enterName   = Name "ENTER"   objectType
+vmName      = Name "VM"      vmType
+thisName    = Name "this"    (Type "<this>")
+collectName = Name "COLLECT" void
+whnfName    = Name "WHNF"    objectType
+
+fieldName :: Int -> Type -> Name       -- Names for fields of a constructor
+fieldName n ty = Name ("f" ++ show n) ty
+
+withType :: Name -> Type -> Name
+withType (Name n _) t = Name n t
+
+-- This maps (local only) names Ids to Names, 
+-- using the same string as the Id.
+javaName :: Id -> Name
+javaName n 
+  | isGlobalName (idName n) = error "useing javaName on global"
+  | otherwise = Name (getOccString n)
+                    (primRepToType (idPrimRep n))
+
+-- TypeName's are always global. This would typically return something
+-- like Test.foo or Test.Foozdc or PrelBase.foldr.
+
+javaIdTypeName :: Id -> TypeName
+javaIdTypeName n = (moduleString (nameModule n') ++ "." ++ getOccString n')
+  where
+            n' = getName n
+
+javaTyConTypeName :: TyCon -> TypeName
+javaTyConTypeName n = (moduleString (nameModule n') ++ "." ++ getOccString n')
+  where
+            n' = getName n
 
-fieldName :: Int -> Name       -- Names for fields of a constructor
-fieldName n = ["f" ++ show n]
+-- this is used for getting the name of a class when defining it.
+shortName :: TypeName -> TypeName
+shortName = reverse . takeWhile (/= '.') . reverse
 
-javaName :: NamedThing a => a -> Name
-javaName n = [getOccString n]
+-- The function that makes the constructor name
+-- The constructor "Foo ..." in module Test,
+-- would return the name "Test.Foo".
 
-javaConstrWkrName :: DataCon ->  Name
--- The function that makes the constructor
-javaConstrWkrName con = [getOccString (dataConId con)]
+javaConstrWkrName :: DataCon -> TypeName
+javaConstrWkrName = javaIdTypeName . dataConId
 
-javaInstName :: NamedThing a => a -> Name
 -- Makes x_inst for Rec decls
-javaInstName n = [getOccString n ++ "_inst"]
+javaInstName :: Id -> Name
+javaInstName n = Name (getOccString n ++ "_inst")
+                     (primRepToType (idPrimRep n))
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection{Type mangling}
+\subsection{Types and type mangling}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
-codeType, thunkType, objectType :: Type
-objectType = Type ["Object"]
-codeType  = Type codeName
-thunkType = Type thunkName
+-- Haskell RTS types
+codeType, thunkType, valueType :: Type
+codeType   = Type codeName
+thunkType  = Type thunkName
+valueType  = Type "haskell.runtime.Value"
+vmType     = Type "haskell.runtime.VMEngine"
+
+-- Basic Java types
+objectType, stringType :: Type
+objectType = Type "java.lang.Object"
+stringType = Type "java.lang.String"
+
+void :: Type
+void = PrimType PrimVoid
+
+inttype :: Type
+inttype = PrimType PrimInt
+
+chartype :: Type
+chartype = PrimType PrimChar
+
+-- This lets you get inside a possible "Value" type,
+-- to access the internal unboxed object.
+access :: Expr -> Type -> Expr
+access expr (PrimType prim) = accessPrim (Cast valueType expr) prim
+access expr other           = expr
+
+accessPrim expr PrimInt  = Call expr (Name "intValue" inttype) []
+accessPrim expr PrimChar = Call expr (Name "intValue" chartype) []
+
+-- This is where we map from typename to types,
+-- allowing to match possible primitive types.
+mkType :: TypeName -> Type
+mkType "PrelGHC.Intzh"  = inttype
+mkType "PrelGHC.Charzh" = chartype
+mkType other            = Type other
+
+-- Turns a (global) Id into a Type (fully qualified name).
+javaIdType :: Id -> Type
+javaIdType = mkType . javaIdTypeName
+
+javaLocalIdType :: Id -> Type
+javaLocalIdType = primRepToType . idPrimRep
+
+primRepToType ::PrimRep -> Type
+primRepToType PtrRep  = objectType
+primRepToType IntRep  = inttype
+primRepToType CharRep = chartype
+
+-- The function that makes the constructor name
+javaConstrWkrType :: DataCon -> Type
+javaConstrWkrType con = Type (javaConstrWkrName con)
 \end{code}
 
+%************************************************************************
+%*                                                                     *
+\subsection{Class Lifting}
+%*                                                                     *
+%************************************************************************
+
+This is a very simple class lifter. It works by carrying inwards a
+list of bound variables (things that might need to be passed to a
+lifted inner class). 
+ * Any variable references is check with this list, and if it is
+   bound, then it is not top level, external reference. 
+ * This means that for the purposes of lifting, it might be free
+   inside a lifted inner class.
+ * We remember these "free inside the inner class" values, and 
+   use this list (which is passed, via the monad, outwards)
+   when lifting.
+
+\begin{code}
+{-
+type Bound = [Name]
+type Frees = [Name]
+
+combine :: [Name] -> [Name] -> [Name]
+combine []           names          = names
+combine names        []             = names
+combine (name:names) (name':names') 
+       | name < name' = name  : combine names (name':names')
+       | name > name' = name' : combine (name:names) names'
+       | name == name = name  : combine names names'
+       | otherwise    = error "names are not a total order"
+
+both :: [Name] -> [Name] -> [Name]
+both []           names          = []
+both names        []             = []
+both (name:names) (name':names') 
+       | name < name' = both names (name':names')
+       | name > name' = both (name:names) names'
+       | name == name = name  : both names names'
+       | otherwise    = error "names are not a total order"
+
+combineEnv :: Env -> [Name] -> Env
+combineEnv (Env bound env) new = Env (bound `combine` new) env
+
+addTypeMapping :: Name -> Name -> [Name] -> Env -> Env
+addTypeMapping origName newName frees (Env bound env) 
+       = Env bound ((origName,(newName,frees)) : env)
+
+-- This a list of bound vars (with types)
+-- and a mapping from types (?) to (result * [arg]) pairs
+data Env = Env Bound [(Name,(Name,[Name]))]
+
+newtype LifterM a = 
+       LifterM { unLifterM ::
+                    Name ->
+                    Int -> ( a                 -- *
+                           , Frees             -- frees
+                           , [Decl]            -- lifted classes
+                           , Int               -- The uniqs
+                           )
+               }
+
+instance Monad LifterM where
+       return a = LifterM (\ n s -> (a,[],[],s))
+       (LifterM m) >>= fn = LifterM (\ n s ->
+         case m n s of
+           (a,frees,lifted,s) 
+                -> case unLifterM (fn a) n s of
+                    (a,frees2,lifted2,s) -> ( a
+                                            , combine frees frees2
+                                            , lifted ++ lifted2
+                                            , s)
+         )
+
+access :: Env -> Name -> LifterM ()
+access env@(Env bound _) name 
+       | name `elem` bound = LifterM (\ n s -> ((),[name],[],s))
+       | otherwise         = return ()
+
+scopedName :: Name -> LifterM a -> LifterM a
+scopedName name (LifterM m) =
+   LifterM (\ _ s -> 
+      case m name 1 of
+       (a,frees,lifted,_) -> (a,frees,lifted,s)
+      )
+
+genAnonInnerClassName :: LifterM Name
+genAnonInnerClassName = LifterM (\ n s ->
+       ( n ++ "$" ++ show s
+       , []
+       , []
+       , s + 1
+       )
+    )
+
+genInnerClassName :: Name -> LifterM Name
+genInnerClassName name = LifterM (\ n s ->
+       ( n ++ "$" ++ name 
+       , []
+       , []
+       , s
+       )
+    )
+
+getFrees  :: LifterM a -> LifterM (a,Frees)
+getFrees (LifterM m) = LifterM (\ n s ->
+       case m n s of
+         (a,frees,lifted,n) -> ((a,frees),frees,lifted,n)
+    )
+
+rememberClass :: Decl -> LifterM ()
+rememberClass decl = LifterM (\ n s -> ((),[],[decl],s))
+
+
+liftCompilationUnit :: CompilationUnit -> CompilationUnit
+liftCompilationUnit (Package name ds) = 
+    Package name (concatMap liftCompilationUnit' ds)
+
+liftCompilationUnit' :: Decl -> [Decl]
+liftCompilationUnit' decl = 
+    case unLifterM (liftDecls True (Env [] []) [decl]) [] 1 of
+      (ds,_,ds',_) -> ds ++ ds'
+
+
+-- The bound vars for the current class have
+-- already be captured before calling liftDecl,
+-- because they are in scope everywhere inside the class.
+
+liftDecl :: Bool -> Env -> Decl -> LifterM Decl
+liftDecl = \ top env decl ->
+  case decl of
+    { Import n -> return (Import n)
+    ; Field mfs t n e -> 
+      do { e <- liftMaybeExpr env e
+        ; return (Field mfs (liftType env t) n e)
+        }
+    ; Constructor mfs n as ss -> 
+      do { let newBound = getBoundAtParameters as
+        ; (ss,_) <- liftStatements (combineEnv env newBound) ss
+        ; return (Constructor mfs n (liftParameters env as) ss)
+        }
+    ; Method mfs t n as ts ss -> 
+      do { let newBound = getBoundAtParameters as
+        ; (ss,_) <- liftStatements (combineEnv env newBound) ss
+        ; return (Method mfs (liftType env t) n (liftParameters env as) ts ss)
+        }
+    ; Comment s -> return (Comment s)
+    ; Interface mfs n is ms -> error "interfaces not supported"
+    ; Class mfs n x is ms -> 
+      do { let newBound = getBoundAtDecls ms
+        ; ms <- scopedName n
+                   (liftDecls False (combineEnv env newBound) ms)
+        ; return (Class mfs n x is ms)
+        }
+    }
+
+liftDecls :: Bool -> Env -> [Decl] -> LifterM [Decl]
+liftDecls top env = mapM (liftDecl top env)
+
+getBoundAtDecls :: [Decl] -> Bound
+getBoundAtDecls = foldr combine [] . map getBoundAtDecl
+
+-- TODO
+getBoundAtDecl :: Decl -> Bound
+getBoundAtDecl (Field _ _ n _) = [n]
+getBoundAtDecl _               = []
+
+getBoundAtParameters :: [Parameter] -> Bound
+getBoundAtParameters = foldr combine [] . map getBoundAtParameter
+
+-- TODO
+getBoundAtParameter :: Parameter -> Bound
+getBoundAtParameter (Parameter _ _ n) = [n]
+
+liftStatement :: Env -> Statement -> LifterM (Statement,Env)
+liftStatement = \ env stmt ->
+  case stmt of 
+    { Skip -> return (stmt,env)
+    ; Return e -> do { e <- liftExpr env e
+                    ; return (Return e,env)
+                    } 
+    ; Block ss -> do { (ss,env) <- liftStatements env ss
+                    ; return (Block ss,env)
+                    }
+    ; ExprStatement e -> do { e <- liftExpr env e
+                           ; return (ExprStatement e,env)
+                           }
+   ; Declaration decl@(Field mfs t n e) ->
+      do { e <- liftMaybeExpr env e
+        ; return ( Declaration (Field mfs t n e)
+                 , env `combineEnv` getBoundAtDecl decl
+                 )
+        }
+    ; Declaration decl@(Class mfs n x is ms) ->
+      do { innerName <- genInnerClassName n
+        ; frees <- liftClass env innerName ms x is
+        ; return ( Declaration (Comment ["lifted " ++  n])
+                 , addTypeMapping n innerName frees env
+                 )
+        }
+    ; Declaration d -> error "general Decl not supported"
+    ; IfThenElse ecs s -> ifthenelse env ecs s
+    ; Switch e as d -> error "switch not supported"
+    } 
+
+ifthenelse :: Env 
+          -> [(Expr,Statement)] 
+          -> (Maybe Statement) 
+          -> LifterM (Statement,Env)
+ifthenelse env pairs may_stmt =
+  do { let (exprs,stmts) = unzip pairs
+     ; exprs <- liftExprs env exprs
+     ; (stmts,_) <- liftStatements env stmts
+     ; may_stmt <- case may_stmt of
+                     Just stmt -> do { (stmt,_) <- liftStatement env stmt
+                                     ; return (Just stmt)
+                                     }
+                     Nothing -> return Nothing
+     ; return (IfThenElse (zip exprs stmts) may_stmt,env)
+     }
+
+liftStatements :: Env -> [Statement] -> LifterM ([Statement],Env)
+liftStatements env []     = return ([],env)
+liftStatements env (s:ss) = 
+       do { (s,env) <- liftStatement env s
+          ; (ss,env) <- liftStatements env ss
+          ; return (s:ss,env) 
+          }
+
+
+liftExpr :: Env -> Expr -> LifterM Expr
+liftExpr = \ env expr ->
+ case expr of
+   { Var n t -> do { access env n 
+                  ; return (Var n t)
+                  }
+   ; Literal l _ -> return expr
+   ; Cast t e -> do { e <- liftExpr env e
+                   ; return (Cast (liftType env t) e) 
+                   }
+   ; Access e n -> do { e <- liftExpr env e 
+                       -- do not consider n as an access, because
+                       -- this is a indirection via a reference
+                     ; return (Access e n) 
+                     }
+   ; Assign l r -> do { l <- liftExpr env l
+                     ; r <- liftExpr env r
+                     ; return (Assign l r)
+                     } 
+   ; InstanceOf e t -> do { e <- liftExpr env e
+                         ; return (InstanceOf e (liftType env t))
+                         }         
+   ; Call e n es -> do { e <- liftExpr env e
+                      ; es <- mapM (liftExpr env) es
+                      ; return (Call e n es) 
+                      }
+   ; Op e1 o e2 -> do { e1 <- liftExpr env e1
+                     ; e2 <- liftExpr env e2
+                     ; return (Op e1 o e2)
+                     }
+   ; New n es ds -> new env n es ds
+   }
+
+liftParameter env (Parameter ms t n) = Parameter ms (liftType env t) n
+liftParameters env = map (liftParameter env)
+
+liftExprs :: Env -> [Expr] -> LifterM [Expr]
+liftExprs = mapM . liftExpr
+
+liftMaybeExpr :: Env -> (Maybe Expr) -> LifterM (Maybe Expr)
+liftMaybeExpr env Nothing     = return Nothing
+liftMaybeExpr env (Just stmt) = do { stmt <- liftExpr env stmt
+                                    ; return (Just stmt)
+                                    }
+
+
+new :: Env -> Type -> [Expr] -> Maybe [Decl] -> LifterM Expr
+new env@(Env _ pairs) typ args Nothing =
+  do { args <- liftExprs env args
+     ; return (listNew env typ args)
+     }
+new env typ [] (Just inner) =
+  -- anon. inner class
+  do { innerName <- genAnonInnerClassName 
+     ; frees <- liftClass env innerName inner [] [unType typ]
+     ; return (New (Type (innerName)) 
+             [ Var name (Type "<arg>") | name <- frees ] Nothing)
+     }
+  where unType (Type name) = name
+       unType _             = error "incorrect type style"
+       
+new env typ _ (Just inner) = error "cant handle inner class with args"
+
+liftClass :: Env -> Name -> [Decl] -> [Name] -> [Name] -> LifterM [ Name ]
+liftClass env@(Env bound _) innerName inner xs is =
+  do { let newBound = getBoundAtDecls inner
+     ; (inner,frees) <- 
+          getFrees (liftDecls False (env `combineEnv` newBound) inner)
+     ; let trueFrees = filter (\ xs -> xs /= "VM") (both frees bound)
+     ; let freeDefs = [ Field [Final] objectType n Nothing | n <- trueFrees ]
+     ; let cons = mkCons innerName [(name,objectType) | name <- trueFrees ]
+     ; let innerClass = Class [] innerName xs is (freeDefs ++ [cons] ++ inner)
+     ; rememberClass innerClass
+     ; return trueFrees
+     }
+
+liftType :: Env -> Type -> Type
+liftType (Env _ env) typ@(Type name) 
+   = case lookup name env of
+       Nothing     -> typ
+       Just (nm,_) -> Type nm
+liftType _           typ = typ
+
+liftNew :: Env -> Type -> [Expr] -> Expr
+liftNew (Env _ env) typ@(Type name) exprs
+   = case lookup name env of
+       Nothing                     -> New typ exprs Nothing
+       Just (nm,args) | null exprs 
+               -> New (Type nm) (map (\ v -> Var v (Type "<arg>")) args) Nothing
+       _ -> error "pre-lifted constructor with arguments"
+listNew _           typ exprs = New typ exprs Nothing
+
+-}
+\end{code}