[project @ 2002-04-29 14:03:38 by simonmar]
[ghc-hetmet.git] / ghc / compiler / javaGen / JavaGen.lhs
index 9fdb550..55b2b71 100644 (file)
@@ -3,28 +3,71 @@
 %
 \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
+
+
+$i  for instances.
+$k  for keyword nameclash avoidance.
+
 \begin{code}
 module JavaGen( javaGen ) where
 
 import Java
 
 import Literal ( Literal(..) )
-import Id      ( Id, isDataConId_maybe, isId, idName, isDeadBinder, idPrimRep )
-import Name    ( NamedThing(..), getOccString, isGlobalName 
+import Id      ( Id, isDataConId_maybe, isId, idName, isDeadBinder, idPrimRep
+               , isPrimOpId_maybe )
+import Name    ( NamedThing(..), getOccString, isExternalName, isInternalName
                , nameModule )
 import PrimRep  ( PrimRep(..) )
-import DataCon ( DataCon, dataConRepArity, dataConRepArgTys, dataConId )
-import qualified TypeRep
+import DataCon ( DataCon, dataConRepArity, dataConRepArgTys, dataConWorkId )
 import qualified Type
 import qualified CoreSyn
 import CoreSyn ( CoreBind, CoreExpr, CoreAlt, CoreBndr,
-                 Bind(..), Alt, AltCon(..), collectBinders, isValArg
+                 Bind(..), AltCon(..), collectBinders, isValArg
                )
-import CoreUtils( exprIsValue, exprIsTrivial )
+import TysWiredIn      ( boolTy, trueDataCon, falseDataCon )
+import qualified CoreUtils
 import Module  ( Module, moduleString )
 import TyCon   ( TyCon, isDataTyCon, tyConDataCons )
 import Outputable
 
+import Maybe
+import PrimOp
+import Util     ( lengthIs, notNull )
+
 #include "HsVersions.h"
 
 \end{code}
@@ -63,41 +106,84 @@ javaTyCon tycon
   = tycon_jclass : concat (map constr_class constrs)
   where
     constrs = tyConDataCons tycon
-       -- We add a postfix to types ("$c"), because constructors
-       -- and datastructure types are in the same namespace in Java.
-    tycon_jclass_jname = javaName tycon ++ "zdc"
+    tycon_jclass_jname =  javaTyConTypeName tycon ++ "zdc"
     tycon_jclass = Class [Public] (shortName tycon_jclass_jname) [] [] []
 
     constr_class data_con
-       = [ Class [Public] (shortName constr_jname) [tycon_jclass_jname] [] field_decls
-         , Class [Public] (shortName constr_jname) [] [codeName] [enter_meth]
+       = [ Class [Public] constr_jname [tycon_jclass_jname] []
+                               (field_decls ++ [cons_meth,debug_meth])
          ]
        where
-         constr_jname = javaConstrWkrName data_con
-         constr_jtype = javaConstrWkrType data_con
+         constr_jname = shortName (javaConstrWkrName data_con)
 
          field_names  = constrToFields data_con
-         field_decls  = [ Field [Public] t f Nothing 
-                        | (f,t) <- field_names
+         field_decls  = [ Field [Public] n Nothing 
+                        | n <- field_names
                         ]
 
-         n_val_args   = length field_names
-         enter_meth   = Method [Public] objectType enterName [] [excName] stmts
-         stmts        = vmCOLLECT n_val_args this ++
-                        [var [Final] objectType f (vmPOP t) | (f,t) <- field_names] ++
-                        [Return (mkNew constr_jtype (map mkVar field_names))]
-
-         mkVar (f,t) = Var f t
-
+         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???"
+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,Type)]
-constrToFields cons = zip (map fieldName [1..])
-                         (map javaTauType (dataConRepArgTys cons))
+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}
 
 %************************************************************************
@@ -116,13 +202,16 @@ java_top_bind :: Id -> CoreExpr -> Decl
 --       public Object ENTER() { ...translation of rhs... }
 --     }
 java_top_bind bndr rhs
-  = Class [Public] (shortName (javaName bndr)) [] [codeName] [enter_meth]
+  = Class [Public] (shortName (javaIdTypeName bndr))
+               [] [codeName] [enter_meth]
   where
-    enter_meth = Method [Public] objectType enterName [vmArg] [excName] 
+    enter_meth = Method [Public]
+                       enterName
+                       [vmArg]
+                       [excName]
                        (javaExpr vmRETURN rhs)
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection{Expressions}
@@ -131,26 +220,34 @@ java_top_bind bndr rhs
 
 \begin{code}
 javaVar :: Id -> Expr
-javaVar v | isGlobalName (idName v) = mkNew (javaGlobType v) []
-         | otherwise               = Var (javaName v) (javaType v)
+javaVar v | isExternalName (idName v) = mkNew (javaIdType v) []
+         | otherwise               =   Var (javaName v)
 
 javaLit :: Literal.Literal -> Expr
-javaLit (MachInt i)  = Literal (UIntLit (fromInteger i)) (PrimType PrimInt)
-javaLit (MachChar c) = Literal (UCharLit c)              (PrimType PrimChar)
+javaLit (MachInt i)  = Literal (IntLit (fromInteger i))
+javaLit (MachChar c) = Literal (CharLit c)
+javaLit (MachStr fs) = Literal (StringLit str)
+   where
+       str = concatMap renderString (unpackFS fs) ++ "\\000"
+       -- This should really handle all the chars 0..31.
+       renderString '\NUL' = "\\000"
+       renderString other  = [other]
+
 javaLit other       = pprPanic "javaLit" (ppr other)
 
-javaExpr :: (Expr -> Expr) -> 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 r (CoreSyn.Var v)   = [Return (r (javaVar v))]
-javaExpr r (CoreSyn.Lit l)   = [Return (r (javaLit l))]
+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 -> Expr) -> CoreExpr -> Id -> [CoreAlt] -> [Statement]
+javaCase :: (Expr -> Statement) -> CoreExpr -> Id -> [CoreAlt] -> [Statement]
 --     case e of x { Nil      -> r1
 --                   Cons p q -> r2 }
 -- ==>
@@ -161,29 +258,111 @@ javaCase :: (Expr -> Expr) -> CoreExpr -> Id -> [CoreAlt] -> [Statement]
 --             final Object p = ((Cons) x).f1
 --             final Object q = ((Cons) x).f2
 --             ...translation of r2...
---     } else return null
-
+--     } else throw java.lang.Exception
+
+-- This first special case happens a lot, typically
+-- during dictionary deconstruction.
+-- We need to access at least *one* field, to check to see
+-- if we have correct constructor.
+-- If we've got the wrong one, this is _|_, and the
+-- casting will catch this with an exception.
+
+javaCase r e x [(DataAlt d,bs,rhs)] | notNull bs
+  = java_expr PushExpr e ++
+    [ var [Final] (javaName x)
+                 (whnf primRep (vmPOP (primRepToType primRep))) ] ++
+    bind_args d bs ++
+    javaExpr r rhs
+   where      
+     primRep = idPrimRep x
+     whnf PtrRep = vmWHNF      -- needs evaluation
+     whnf _      = id          -- anything else does notg
+
+     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)
+                     ]
+   
 javaCase r e x alts
-  =  [var [Final] objectType (javaName x) (vmWHNF (javaArg e)),
-      IfThenElse (map mk_alt alts) Nothing]
+  | isIfThenElse && isPrimCmp
+  = javaIfThenElse r (fromJust maybePrim) tExpr fExpr
+  | otherwise
+  = java_expr PushExpr e ++
+       [ var [Final] (javaName x)
+                          (whnf primRep (vmPOP (primRepToType primRep)))
+       , IfThenElse (map mk_alt con_alts) (Just default_code)
+       ]
   where
-     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 _, _, _) = pprPanic "mk_alt" (ppr alt)
-
-     bind_args d bs = [var [Final] t (javaName b) 
-                          (Access (Cast (javaConstrWkrType d) (javaVar x)) f)
-                     | (b, (f,t)) <- filter isId bs `zip` (constrToFields d)
+     isIfThenElse = CoreUtils.exprType e `Type.eqType` boolTy
+                   -- also need to check that x is not free in
+                   -- any of the branches.
+     maybePrim    = findCmpPrim e []
+     isPrimCmp    = isJust maybePrim
+     (_,_,tExpr)  = CoreUtils.findAlt (DataAlt trueDataCon) alts 
+     (_,_,fExpr)  = CoreUtils.findAlt (DataAlt falseDataCon) alts 
+
+     primRep = idPrimRep x
+     whnf PtrRep = vmWHNF      -- needs evaluation
+     whnf _      = id
+
+     (con_alts, maybe_default) = CoreUtils.findDefault alts
+     default_code = case maybe_default of
+                       Nothing  -> ExprStatement (Raise excName [Literal (StringLit "case failure")])
+                       Just rhs -> Block (javaExpr r rhs)
+
+     mk_alt (DataAlt d,  bs, rhs) = (instanceOf x d, Block (bind_args d bs ++ javaExpr r rhs))
+     mk_alt (LitAlt lit, bs, rhs) = (eqLit lit     , Block (javaExpr r rhs))
+
+
+     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)
                      ]
 
+javaIfThenElse r cmp tExpr fExpr 
+{-
+ - Now what we need to do is generate code for the if/then/else.
+ - [all arguments are already check for simpleness (Var or Lit).]
+ - 
+ - if (<prim> arg1 arg2 arg3 ...) {
+ -     trueCode
+ -  } else {
+ -     falseCode
+ - }
+ -}
+ = [IfThenElse [(cmp,j_tExpr)] (Just j_fExpr)]
+ where
+   j_tExpr, j_fExpr :: Statement
+   j_tExpr = Block (javaExpr r tExpr)
+   j_fExpr = Block (javaExpr r fExpr)
+
 javaBind (NonRec x rhs)
 {-
        x = ...rhs_x...
   ==>
        final Object x = new Thunk( new Code() { ...code for rhs_x... } )
 -}
-  = [var [Final] objectType (javaName x) (newThunk (newCode (javaExpr vmRETURN rhs)))]
+
+  = java_expr (SetVar name) rhs
+  where
+    name = case coreTypeToType rhs of
+           ty@(PrimType _) -> javaName x `withType` ty
+           _               -> javaName x `withType` codeType
 
 javaBind (Rec prs)
 {-     rec { x = ...rhs_x...; y = ...rhs_y... }
@@ -207,60 +386,158 @@ 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 [vmArg] [excName] (javaExpr vmRETURN 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] (javaGlobType b) (javaInstName b)
-                       (New (javaGlobType b) [] Nothing)
+    mk_inst (b,r) = var [Final] name (mkNew ty [])
+       where
+          name@(Name _ ty)  = javaInstName b
 
-    mk_thunk (b,r) = var [Final] thunkType (javaName b)
-                        (New thunkType [Var (javaInstName b) (Type "<inst>")] Nothing)
+    mk_thunk (b,r) = var [Final] (javaName b `withType` codeType)
+                        (mkNew thunkType [Var (javaInstName b)])
 
-    mk_knot (b,_) = [ExprStatement (Assign lhs rhs) 
+    mk_knot (b,_) = [ ExprStatement (Assign lhs rhs) 
                    | (b',_) <- prs,
-                     let lhs = Access (Var (javaInstName b) (Type "<inst>")) (javaName b'),
-                     let rhs = Var (javaName b') (Type "<inst>")
+                     let lhs = Access (Var (javaInstName b)) (javaName b'),
+                     let rhs = Var (javaName b')
                    ]
 
-
-javaLam :: (Expr -> Expr) -> ([CoreBndr], CoreExpr) -> [Statement]
+javaLam :: (Expr -> Statement) -> ([CoreBndr], CoreExpr) -> [Statement]
 javaLam r (bndrs, body)
   | null val_bndrs = javaExpr r body
   | otherwise
   =  vmCOLLECT (length val_bndrs) this
-  ++ [var [Final] t (javaName n) (vmPOP t) | (n,t) <- val_bndrs]
+  ++ [var [Final] n (vmPOP t) | n@(Name _ t) <- val_bndrs]
   ++ javaExpr r body
   where
-    val_bndrs = map (\ id -> (id,javaType id)) (filter isId bndrs)
+    val_bndrs = map javaName (filter isId bndrs)
 
-javaApp :: (Expr -> Expr) -> CoreExpr -> [CoreExpr] -> [Statement]
-javaApp r (CoreSyn.App f a) as = javaApp r f (a:as)
-javaApp r (CoreSyn.Var f) as
+javaApp :: (Expr -> Statement) -> CoreExpr -> [CoreExpr] -> [Statement]
+javaApp r (CoreSyn.App f a) as 
+       | isValArg a = javaApp r f (a:as)
+       | otherwise  = javaApp r f as
+javaApp r (CoreSyn.Var f) as 
   = case isDataConId_maybe f of {
-{- For now, we are turning off all optimizations.
-       Just dc | length as == dataConRepArity dc
-               ->      -- Saturated constructors
-                  [Return (New (javaGlobType f) (javaArgs as) Nothing)]
-
--}
-    ; other ->   -- Not a saturated constructor
-       java_apply r (CoreSyn.Var f) as
+       Just dc | as `lengthIs` dataConRepArity dc
+        -- NOTE: Saturated constructors never returning a primitive at this point
+        --
+        -- We push the arguments backwards, because we are using
+        -- the (ugly) semantics of the order of evaluation of arguments,
+        -- to avoid making up local names. Oh to have a namesupply...
+        --
+               -> javaArgs (reverse as) ++
+                  [r (New (javaIdType f)
+                          (javaPops as)
+                          Nothing
+                      )
+                  ]
+               | otherwise ->
+                  --  build a local 
+                  let stmts = 
+                         vmCOLLECT (dataConRepArity dc) this ++
+                       [ vmRETURN
+                          (New (javaIdType f)
+                               [ vmPOP ty | (Name _ ty) <- constrToFields dc ]
+                               Nothing
+                           )
+                       ]
+                  in javaArgs (reverse as) ++ [r (newCode stmts)]
+    ; other -> java_apply r (CoreSyn.Var f) as
     }
        
 javaApp r f as = java_apply r f as
 
-java_apply :: (Expr -> Expr) -> CoreExpr -> [CoreExpr] -> [Statement]
-java_apply r f as = [ExprStatement (vmPUSH arg) | arg <- javaArgs as] ++ javaExpr r f
-
-javaArgs :: [CoreExpr] -> [Expr]
-javaArgs args = [javaArg a | a <- args, isValArg a]
+-- 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 [ java_expr PushExpr a | a <- args, isValArg a]
+
+javaPops :: [CoreExpr] -> [Expr]
+javaPops args = [ vmPOP (primRepToType (Type.typePrimRep (CoreUtils.exprType a)))
+               | a <- args 
+               , isValArg a
+               ]
+
+
+-- 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, (or returning, or setting a variable)
+-- perhaps thunked.
+
+{- This is mixing two things.
+ (1) Optimizations for things like primitives, whnf calls, etc.
+ (2) If something needs a thunk constructor round it.
+ - Seperate them at some point!
+ -}
+data ExprRetStyle = SetVar Name | PushExpr | ReturnExpr
+
+java_expr :: ExprRetStyle -> CoreExpr -> [Statement]
+java_expr _ (CoreSyn.Type t) = pprPanic "java_expr" (ppr t)
+java_expr ret e
+   | isPrimCall = [push (fromJust maybePrim)]
+       -- This is a shortcut, 
+       -- basic names and literals do not need a code block
+       -- to compute the value.
+   | 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
+       maybePrim  = findFnPrim e []
+       isPrimCall = isJust maybePrim
+
+       push e = case ret of
+                 SetVar name -> var [Final] name e
+                 PushExpr -> vmPUSH e
+                 ReturnExpr -> vmRETURN e
+       corety = CoreUtils.exprType e
+       primty = Type.typePrimRep corety
+       isPrim PtrRep  = False  -- only this needs updated
+       isPrim _       = True
+
+coreTypeToType = primRepToType . Type.typePrimRep . CoreUtils.exprType
+
+renameForKeywords :: (NamedThing name) => name -> String
+renameForKeywords name 
+  | str `elem` keywords = "zdk" ++ str
+  | otherwise            = str
+  where
+       str = getOccString name
+
+keywords :: [String]
+keywords =
+       [ "return"
+       , "if"
+       , "then"
+       , "else"
+       , "class"
+       , "instance"
+       , "import"
+       , "throw"
+       , "try"
+       ]
 
-javaArg :: CoreExpr -> Expr
-javaArg (CoreSyn.Type t) = pprPanic "javaArg" (ppr t)
-javaArg e | exprIsValue e || exprIsTrivial e = newCode (javaExpr id e)
-         | otherwise                        = newThunk (newCode (javaExpr id e))
 \end{code}
 
 %************************************************************************
@@ -270,60 +547,127 @@ javaArg e | exprIsValue e || exprIsTrivial e = newCode (javaExpr id e)
 %************************************************************************
 
 \begin{code}
-true, this :: Expr
-this = Var thisName (Type "<this>")
-true = Var "true" (PrimType PrimBoolean)
+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 varVM "COLLECT" 
-                                    [Literal (IntLit n) (PrimType PrimInt), e])]
+vmCOLLECT n e = [ExprStatement 
+                   (Call varVM collectName
+                       [ Literal (IntLit (toInteger n))
+                       , e
+                       ]
+                   )
+               ]
 
 vmPOP :: Type -> Expr 
-vmPOP ty = Call varVM ("POP" ++ suffix ty) []
+vmPOP ty = Call varVM (Name ("POP" ++ suffix ty) ty) []
 
-vmPUSH :: Expr -> Expr
-vmPUSH e = Call varVM ("PUSH" ++ suffix (exprType e)) [e]
+vmPUSH :: Expr -> Statement
+vmPUSH e = ExprStatement 
+            (Call varVM (Name ("PUSH" ++ suffix (exprType e)) void) [e])
 
-vmRETURN :: Expr -> Expr
-vmRETURN e = 
+vmRETURN :: Expr -> Statement
+vmRETURN e = Return (
      case ty of
-       PrimType _ -> Call varVM ("RETURN" ++ suffix (exprType e)) [e]
-       _ -> e
+       PrimType _ -> Call varVM (Name ("RETURN" ++ suffix ty)
+                                      valueType
+                                ) [e]
+       _ -> e)
   where
        ty = exprType e
 
-var :: [Modifier] -> Type -> Name -> Expr -> Statement
-var ms ty field_name value = Declaration (Field ms ty field_name (Just value))
+var :: [Modifier] -> Name -> Expr -> Statement
+var ms field_name@(Name _ ty) value 
+   | exprType value == ty = Declaration (Field ms field_name (Just value))
+   | otherwise            = var ms field_name (Cast ty value)
 
 vmWHNF :: Expr -> Expr
-vmWHNF e = Call varVM "WHNF" [e]
+vmWHNF e = Call varVM whnfName [e]
 
 suffix :: Type -> String
 suffix (PrimType t) = primName t
 suffix _            = ""
 
 primName :: PrimType -> String
-primName PrimInt  = "int"
-primName PrimChar = "char"
-primName _         = error "unsupported primitive"
+primName PrimInt       = "int"
+primName PrimChar      = "char"
+primName PrimByte      = "byte"
+primName PrimBoolean   = "boolean"
+primName _             = error "unsupported primitive"
 
 varVM :: Expr
-varVM = Var vmName (Type "haskell.runtime.VMEngine")
+varVM = Var vmName 
 
 instanceOf :: Id -> DataCon -> Expr
 instanceOf x data_con
-  = InstanceOf (Var (javaName x) (Type "<instof>")) (javaConstrWkrType data_con)
+  = InstanceOf (Var (javaName x)) (javaConstrWkrType data_con)
 
 newCode :: [Statement] -> Expr
 newCode [Return e] = e
-newCode stmts     = New codeType [] (Just [Method [Public] objectType enterName [vmArg] [excName] stmts])
+newCode stmts     = New codeType [] (Just [Method [Public] enterName [vmArg] [excName] stmts])
 
 newThunk :: Expr -> Expr
 newThunk e = New thunkType [e] Nothing
 
 vmArg :: Parameter
-vmArg = Parameter [Final] (Type "haskell.runtime.VMEngine") vmName
+vmArg = Parameter [Final] vmName
+
+-- This is called with boolean compares, checking 
+-- to see if we can do an obvious shortcut.
+-- If there is, we return a (GOO) expression for doing this,
+
+-- So if, we have case (#< x y) of { True -> e1; False -> e2 },
+-- we will call findCmpFn with (#< x y), this return Just (Op x "<" y)
+
+findCmpPrim :: CoreExpr -> [Expr] -> Maybe Expr
+findCmpPrim (CoreSyn.App f a) as =
+     case a of
+       CoreSyn.Var v -> findCmpPrim f (javaVar v:as)
+       CoreSyn.Lit l -> findCmpPrim f (javaLit l:as)
+       _ -> Nothing
+findCmpPrim (CoreSyn.Var p)   as = 
+       case isPrimOpId_maybe p of
+         Just prim -> find_cmp_prim prim as
+         Nothing   -> Nothing
+findCmpPrim _                 as = Nothing
+
+find_cmp_prim cmpPrim args@[a,b] = 
+   case cmpPrim of
+     IntGtOp -> fn ">"
+     IntGeOp -> fn ">="
+     IntEqOp -> fn "=="
+     IntNeOp -> fn "/="
+     IntLtOp -> fn "<"
+     IntLeOp -> fn "<="
+     _ -> Nothing
+  where
+       fn op = Just (Op a op b)
+find_cmp_prim _ _ = Nothing
+
+findFnPrim :: CoreExpr -> [Expr] -> Maybe Expr
+findFnPrim (CoreSyn.App f a) as =
+     case a of
+       CoreSyn.Var v -> findFnPrim f (javaVar v:as)
+       CoreSyn.Lit l -> findFnPrim f (javaLit l:as)
+       _ -> Nothing
+findFnPrim (CoreSyn.Var p)   as = 
+       case isPrimOpId_maybe p of
+         Just prim -> find_fn_prim prim as
+         Nothing   -> Nothing
+findFnPrim _                 as = Nothing
+
+find_fn_prim cmpPrim args@[a,b] = 
+   case cmpPrim of
+     IntAddOp -> fn "+"
+     IntSubOp -> fn "-"
+     IntMulOp -> fn "*"
+     _ -> Nothing
+  where
+       fn op = Just (Op a op b)
+find_fn_prim _ _ = Nothing
 \end{code}
 
 %************************************************************************
@@ -333,11 +677,22 @@ vmArg = Parameter [Final] (Type "haskell.runtime.VMEngine") vmName
 %************************************************************************
 
 \begin{code}
-exprType (Var _ t)     = t
-exprType (Literal _ t) = t
-exprType (Cast t _)    = t
-exprType (New t _ _)   = t
-exprType _             = error "can't figure out an expression type"
+exprType (Var (Name _ t)) = t
+exprType (Literal lit)    = litType lit
+exprType (Cast t _)       = t
+exprType (New t _ _)      = t
+exprType (Call _ (Name _ t) _) = t
+exprType (Access _ (Name _ t)) = t
+exprType (Raise t _)           = error "do not know the type of raise!"
+exprType (Op _ op _) | op `elem` ["==","/=","<","<=","=>",">"]
+                    = PrimType PrimBoolean
+exprType (Op x op _) | op `elem` ["+","-","*"]
+                    = exprType x
+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) = stringType     -- later, might use char array?
 \end{code}
 
 %************************************************************************
@@ -347,79 +702,136 @@ exprType _             = error "can't figure out an expression type"
 %************************************************************************
 
 \begin{code}
-codeName, thunkName, enterName, vmName,excName :: Name
-codeName  = "Code"
-thunkName = "Thunk"
-enterName = "ENTER"
-vmName    = "VM"
-thisName  = "this"
-excName = "Exception"
-
-fieldName :: Int -> Name       -- Names for fields of a constructor
-fieldName n = "f" ++ show n
-
-javaName :: NamedThing a => a -> Name
-javaName n = if isGlobalName n'
-            then moduleString (nameModule n') ++ "." ++ getOccString n
-            else getOccString n
+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 
+  | isExternalName (idName n) = error "useing javaName on global"
+  | otherwise = Name (getOccString n)
+                    (primRepToType (idPrimRep n))
+
+-- TypeName's are almost always global. This would typically return something
+-- like Test.foo or Test.Foozdc or PrelBase.foldr.
+-- Local might use locally bound types, (which do not have '.' in them).
+
+javaIdTypeName :: Id -> TypeName
+javaIdTypeName n
+    | isInternalName n' = renameForKeywords n'
+    | otherwise      = moduleString (nameModule n') ++ "." ++ renameForKeywords n'
+  where
+            n' = getName n
+
+-- There is no such thing as a local type constructor.
+
+javaTyConTypeName :: TyCon -> TypeName
+javaTyConTypeName n = (moduleString (nameModule n') ++ "." ++ renameForKeywords n')
   where
             n' = getName n
 
 -- this is used for getting the name of a class when defining it.
+shortName :: TypeName -> TypeName
 shortName = reverse . takeWhile (/= '.') . reverse
 
-javaConstrWkrName :: DataCon -> Name
--- The function that makes the constructor
-javaConstrWkrName con = javaName (dataConId con)
+-- The function that makes the constructor name
+-- The constructor "Foo ..." in module Test,
+-- would return the name "Test.Foo".
+
+javaConstrWkrName :: DataCon -> TypeName
+javaConstrWkrName = javaIdTypeName . dataConWorkId
 
-javaInstName :: NamedThing a => a -> Name
 -- Makes x_inst for Rec decls
-javaInstName n = getOccString n ++ "_inst"
+-- They are *never* is primitive
+-- and always have local (type) names.
+javaInstName :: Id -> Name
+javaInstName n = Name (renameForKeywords n ++ "zdi_inst")
+                     (Type (renameForKeywords n))
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection{Type mangling}
+\subsection{Types and type mangling}
 %*                                                                     *
 %************************************************************************
 
 \begin{code}
--- This mapping a global haskell name (typically a function name)
--- to the name of the class that handles it.
--- The name must be global. So "Test.foo" maps to Type "Test.foo"
-
-javaGlobType :: NamedThing a => a -> Type
-javaGlobType n | '.' `notElem` name
-              = error ("not using a fully qualified name for javaGlobalType: " ++ name)
-              | otherwise
-              = mkType name
-  where name = javaName n
-
--- This takes an id, and finds the ids *type* (for example, Int, Bool, a, etc).
-javaType :: Id -> Type
-javaType id = case (idPrimRep id) of
-               IntRep -> PrimType PrimInt
-               _ -> if isGlobalName (idName id)
-                    then Type (javaName id)
-                    else objectType            -- TODO: ?? for now ??
-
--- This is where we map from type to possible primitive
-mkType "PrelGHC.Intzh" = PrimType PrimInt
-mkType other           = Type other
-
-javaTauType :: Type.TauType -> Type
-javaTauType (TypeRep.TyConApp tycon _) = javaGlobType tycon
-javaTauType (TypeRep.NoteTy _ t)       = javaTauType t
-javaTauType _                          = objectType
-
-javaConstrWkrType :: DataCon -> Type
--- The function that makes the constructor
-javaConstrWkrType con = Type (javaConstrWkrName con)
-
-codeType, thunkType, objectType :: Type
-objectType = Type ("java.lang.Object")
+-- 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
+
+bytetype :: Type
+bytetype = PrimType PrimByte
+
+-- 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 "charValue" chartype) []
+accessPrim expr PrimByte = Call expr (Name "byteValue" bytetype) []
+accessPrim expr other    = pprPanic "accessPrim" (text (show other))
+
+-- 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
+primRepToType Int8Rep = bytetype
+primRepToType AddrRep = objectType
+primRepToType other   = pprPanic "primRepToType" (ppr other)
+
+-- The function that makes the constructor name
+javaConstrWkrType :: DataCon -> Type
+javaConstrWkrType con = Type (javaConstrWkrName con)
 \end{code}
 
 %************************************************************************
@@ -464,16 +876,22 @@ both (name:names) (name':names')
 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) 
+addTypeMapping :: TypeName -> TypeName -> [Name] -> Env -> Env
+addTypeMapping origName newName frees (Env bound env)
        = Env bound ((origName,(newName,frees)) : env)
 
-data Env = Env Bound [(Name,(Name,[Name]))]
+-- This a list of bound vars (with types)
+-- and a mapping from old class name 
+--     to inner class name (with a list of frees that need passed
+--                         to the inner class.)
+
+data Env = Env Bound [(TypeName,(TypeName,[Name]))]
 
 newtype LifterM a = 
        LifterM { unLifterM ::
-                    Name ->
-                    Int -> ( a                 -- *
+                    TypeName ->                -- this class name
+                    Int ->                     -- uniq supply
+                         ( a                   -- *
                            , Frees             -- frees
                            , [Decl]            -- lifted classes
                            , Int               -- The uniqs
@@ -492,19 +910,19 @@ instance Monad LifterM where
                                             , s)
          )
 
-access :: Env -> Name -> LifterM ()
-access env@(Env bound _) name 
+liftAccess :: Env -> Name -> LifterM ()
+liftAccess env@(Env bound _) name 
        | name `elem` bound = LifterM (\ n s -> ((),[name],[],s))
        | otherwise         = return ()
 
-scopedName :: Name -> LifterM a -> LifterM a
+scopedName :: TypeName -> 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 TypeName
 genAnonInnerClassName = LifterM (\ n s ->
        ( n ++ "$" ++ show s
        , []
@@ -513,7 +931,7 @@ genAnonInnerClassName = LifterM (\ n s ->
        )
     )
 
-genInnerClassName :: Name -> LifterM Name
+genInnerClassName :: TypeName -> LifterM TypeName
 genInnerClassName name = LifterM (\ n s ->
        ( n ++ "$" ++ name 
        , []
@@ -550,19 +968,19 @@ liftDecl :: Bool -> Env -> Decl -> LifterM Decl
 liftDecl = \ top env decl ->
   case decl of
     { Import n -> return (Import n)
-    ; Field mfs t n e -> 
+    ; Field mfs n e -> 
       do { e <- liftMaybeExpr env e
-        ; return (Field mfs (liftType env t) n e)
+        ; return (Field mfs (liftName env 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 -> 
+    ; Method mfs 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)
+        ; return (Method mfs (liftName env n) (liftParameters env as) ts ss)
         }
     ; Comment s -> return (Comment s)
     ; Interface mfs n is ms -> error "interfaces not supported"
@@ -580,17 +998,17 @@ liftDecls top env = mapM (liftDecl top env)
 getBoundAtDecls :: [Decl] -> Bound
 getBoundAtDecls = foldr combine [] . map getBoundAtDecl
 
--- TODO
 getBoundAtDecl :: Decl -> Bound
-getBoundAtDecl (Field _ _ n _) = [n]
-getBoundAtDecl _               = []
+getBoundAtDecl (Field _ n _) = [n]
+getBoundAtDecl _             = []
 
 getBoundAtParameters :: [Parameter] -> Bound
 getBoundAtParameters = foldr combine [] . map getBoundAtParameter
 
 -- TODO
 getBoundAtParameter :: Parameter -> Bound
-getBoundAtParameter (Parameter _ _ n) = [n]
+getBoundAtParameter (Parameter _ n) = [n]
+
 
 liftStatement :: Env -> Statement -> LifterM (Statement,Env)
 liftStatement = \ env stmt ->
@@ -605,9 +1023,9 @@ liftStatement = \ env stmt ->
     ; ExprStatement e -> do { e <- liftExpr env e
                            ; return (ExprStatement e,env)
                            }
-   ; Declaration decl@(Field mfs t n e) ->
+    ; Declaration decl@(Field mfs n e) ->
       do { e <- liftMaybeExpr env e
-        ; return ( Declaration (Field mfs t n e)
+        ; return ( Declaration (Field mfs (liftName env n) e)
                  , env `combineEnv` getBoundAtDecl decl
                  )
         }
@@ -647,14 +1065,13 @@ liftStatements env (s: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
+   { Var n -> do { liftAccess env n 
+                ; return (Var (liftName env n))
+                }
+   ; Literal l -> return expr
    ; Cast t e -> do { e <- liftExpr env e
                    ; return (Cast (liftType env t) e) 
                    }
@@ -670,23 +1087,29 @@ liftExpr = \ env expr ->
    ; InstanceOf e t -> do { e <- liftExpr env e
                          ; return (InstanceOf e (liftType env t))
                          }         
+   ; Raise n es -> do { es <- liftExprs env es
+                     ; return (Raise n es)
+                     }
    ; 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 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
+liftParameter env (Parameter ms n) = Parameter ms (liftName env n)
 liftParameters env = map (liftParameter env)
 
+liftName env (Name n t) = Name n (liftType env t)
+
 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
@@ -694,37 +1117,33 @@ liftMaybeExpr env (Just stmt) = do { stmt <- liftExpr env 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)
+     ; return (liftNew 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)
+                  (map Var 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 -> TypeName -> [Decl] -> [TypeName] -> [TypeName] -> 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 mirrorFrees = [ "_" ++ name ++ "_" | name <- trueFrees ]
-     ; let freeDefs = [ Field [Final] objectType n Nothing | n <- trueFrees ]
-     ; let cons = Constructor [Public] innerName 
-                   [ Parameter [] objectType name | name <- mirrorFrees ]
-                   [ ExprStatement (Assign (Var true (Type "<frees>")) 
-                                           (Var mirror (Type "<frees>")))
-                   | (true,mirror) <- zip trueFrees mirrorFrees
-                   ]
+     ; let trueFrees = filter (\ (Name xs _) -> xs /= "VM") (both frees bound)
+     ; let freeDefs = [ Field [Final] n Nothing | n <- trueFrees ]
+     ; let cons = mkCons innerName trueFrees
      ; let innerClass = Class [] innerName xs is (freeDefs ++ [cons] ++ inner)
      ; rememberClass innerClass
      ; return trueFrees
@@ -742,7 +1161,6 @@ 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 "<v-varg")) args) Nothing
+               -> New (Type nm) (map Var args) Nothing
        _ -> error "pre-lifted constructor with arguments"
-listNew _           typ exprs = New typ exprs Nothing
 \end{code}