shithub: MicroHs

Download patch

ref: 75f35221224c8c5c4da65675125d99e05d60bc41
parent: a8308e68a3bc58aa85203174b241630c107e1604
author: Lennart Augustsson <lennart.augustsson@epicgames.com>
date: Wed Sep 20 16:43:23 EDT 2023

Various changes for an interactive version.

Not ready yet.

--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@
 ### Build the compiler with ghc, using standard libraries (Prelude, Data.List, etc)
 ###
 $(BIN)/$(MHS):	src/*.hs src/*/*.hs $(TOOLS)/convertX.sh
-	$(GHCE) -isrc -Wall -O src/MicroHs/Main.hs -main-is MicroHs.Main -o $(BIN)/$(MHS)
+	$(GHCE) -isrc -ighc -Wall -O src/MicroHs/Main.hs -main-is MicroHs.Main -o $(BIN)/$(MHS)
 
 ###
 ### Build the compiler with ghc, using MicroHs libraries (Prelude, Data.List, etc)
@@ -68,6 +68,7 @@
 	$(GHCC) -c lib/Data/Integer.hs
 	$(GHCC) -c lib/Control/Monad/State/Strict.hs
 #	$(GHCC) -c lib/Debug/Trace.hs
+	$(GHCC) -c lib/System/Console/SimpleReadline.hs
 	$(GHCC) -c src/Text/ParserComb.hs
 	$(GHCC) -c src/MicroHs/Ident.hs
 	$(GHCC) -c src/MicroHs/Expr.hs
@@ -84,8 +85,9 @@
 	$(GHCC) -c src/MicroHs/StateIO.hs
 	$(GHCC) -c src/MicroHs/Compile.hs
 	$(GHCC) -c src/MicroHs/Translate.hs
+	$(GHCC) -c src/MicroHs/Interactive.hs
 	$(GHCC) -c -main-is MicroHs.Main src/MicroHs/Main.hs
-	$(GHC) $(PROF) -hide-all-packages -package time -o $(BIN)/boot$(MHS) $(BOOTDIR)/*.o $(BOOTDIR)/*/*.o $(BOOTDIR)/*/*/*/*.o
+	$(GHC) $(PROF) -hide-all-packages -package time -o $(BIN)/boot$(MHS) $(BOOTDIR)/*.o $(BOOTDIR)/*/*.o $(BOOTDIR)/*/*/*.o $(BOOTDIR)/*/*/*/*.o
 #	$(GHC) $(PROF) -hide-all-packages -package containers -o $(BIN)/boot$(MHS) $(BOOTDIR)/*.o $(BOOTDIR)/*/*.o $(BOOTDIR)/*/*/*/*.o
 
 # Compare version compiled with normal GHC libraries and $(MHS) libraries
@@ -138,7 +140,7 @@
 ###
 ### Make an eval.c that contains the combinator code.
 ###
-tmp/eval.c: src/runtime/eval.c $(BIN)/eval
+tmp/eval.c: src/runtime/eval.c $(BIN)/eval $(COMB)$(MHS).comb 
 	@mkdir -p tmp
 	cp src/runtime/eval.c tmp/eval.c
 	$(BIN)/eval +RTS -K10M -r$(COMB)$(MHS).comb -RTS -ilib -iTools -r Addcombs -- $(COMB)$(MHS).comb >> tmp/eval.c
--- a/comb/mhs.comb
+++ b/comb/mhs.comb
@@ -1,3 +1,3 @@
 v3.4
-854
-(($A :0 ((_649 _598) (($B ((($S' ($C ((($C' ($S' _649)) (($B ($C _2)) _581)) (($B ($B (_649 _678))) ((($C' ($C' $C)) ((($C' ($S' ($C' $C))) ((($C' ($C' ($C' $C))) ((($C' ($C' ($C' ($C' $S')))) (($B ($B ($B ($B $C)))) ((($C' ($C' ($C' $B))) (($B ($B ($B ($C' $S)))) ((($C' ($C' ($C' ($C' $C)))) ((($C' ($C' ($C' ($C' ($C' $S'))))) (($B ($B ($B ($B ($B $C))))) ((($C' ($C' ($C' ($C' ($C' $C))))) ((($C' ($C' ($C' $B))) (($B ($B ($B ($C' ($C' $S'))))) ((($C' ($C' ($C' ($C' ($C' $C'))))) ((($C' ($C' ($C' ($S' ($C' $C'))))) (($B ($B ($B ($B $B')))) ((($S' $B) ($B' ($B' (($B ($S' $B)) (($B ($B _650)) ((($C' $B) (($B _747) (($B _668) ((($C' _783) _9) 0)))) (($B (_747 _671)) (($B (_684 "top level defns: ")) _629)))))))) ((($S' $B) ($B' (($B ($C' $B)) (($B $B') (($B ($B _650)) ((($C' $B) (($B _747) (($B _668) ((($C' _783) _9) 1)))) (_667 ($T (($B ($B (_747 _671))) ((($C' $B) (($B _684) ((($C' _684) _587) " = "))) (($C _407) $K))))))))))) ((($C' $B) ((($S' $C') (($B $C') (($B $C') _10))) ((($S' $B) (($B ($C' ($C' _650))) ((($C' $B) ($B' (($B _747) (($B _673) _12)))) (($B _684) ((($C' _684) (($B (_684 _1)) _629)) (($O 10) $K)))))) (($B ($B (_649 _678))) ((($C' $B) ($B' (($B _747) (($B _668) ((($C' _783) _9) 0))))) (($B ($B (_747 _671))) ((($C' ($C' _684)) (($B ($B (_684 "final pass            "))) (($B ($B (_643 6))) (($B ($B _629)) _777)))) "ms"))))))) _3))))) ((($C' ($C' $C)) (($B (($C' $C) (($B ($C _689)) _407))) (($C _702) (_718 0)))) $K))) (($B ($C $B)) (($B ($B ($C $B))) (($B ($B $BK)) (($B ($B (($C' $B) (($B _748) (($B _684) ((($C' _684) (($B (_684 "(($A :")) _629)) (($O 32) $K))))))) ((($C' $B) (($B ($C' _748)) ($B _407))) (($B (_748 (_684 ") "))) (($C _748) (_684 (($O 41) $K)))))))))))) $T)) (($B $Y) ((($C' ($C' $S)) ((($C' ($C' $S)) ((($C' $B) $P) ((($S' ($C' $B)) ($B _382)) $I))) ($BK $K))) $K))))) (($B (($S' _747) (($B _744) (($B (_747 _792)) (($B (_684 "main: findIdent: ")) _587))))) (($C' _617) _584)))) _624))) (($B ($B _621)) ((($C' $B) (($B _686) (($B $T) (($B ($C $B)) (($B ($B $BK)) ((($C' ($C' ($C' $O))) ($B (($C' $P) _584))) $K)))))) (($C _702) (_718 0))))))) ($T $A))) ($T $K))) $I)) (($B (_747 _381)) (($B (_747 _581)) (($B (_684 (($O 95) $K))) _629)))))))) (($S (($S ((($S' _8) (($B _701) (_688 (_641 "-v")))) ((_717 _641) "-r"))) (($B (_682 (($O 46) $K))) (($B _746) (_687 ((_706 _768) "-i")))))) (($B (_747 _713)) ((($C' _684) (($B _746) (_687 ((_706 _768) "-o")))) (($O "out.comb") $K))))) (($B (($S (($C ((($C' _779) _701) 1)) (_792 "Usage: mhs [-v] [-r] [-iPATH] [-oFILE] ModuleName"))) _713)) (_688 ((_748 _788) ((_748 (_641 (($O 45) $K))) (_699 1))))))) (_709 ((_748 _788) (_641 "--")))))) (($A :1 "v3.4\10&") (($A :2 ((($S' ($S' _649)) _17) (($B ($B ($B (_649 _678)))) ((($C' ($C' $B)) (($B ($B ($C' (($S' _649) (($B _651) (_740 _225)))))) (($B ($B ($B ($B $T)))) (($B ($B ($B ($B (_649 _678))))) ((($C' $B) (($B ($C' $B)) (($B ($B ($C' _650))) ((($C' $B) ($B' (($B _747) (($B _668) ((($C' _783) _9) 0))))) (($B ($B (_747 _671))) ((($C' ($C' _684)) (($B ($B (_684 "combinator conversion "))) (($B ($B (_643 6))) (($B ($B _629)) _777)))) "ms")))))) (($B ($B _651)) (($B $P) (($C _590) (_581 "main"))))))))) (_686 ($T ((($C' ($C' $O)) ((($C' $B) $P) _410)) $K))))))) (($A :3 (($B (_649 _598)) (($B (($C' _599) ((($C' _772) (($B _701) (_709 ((_748 _788) (_641 "--"))))) 1))) (($B (_747 _7)) _4)))) (($A :4 ($T (($C ((($C' $C') (($B $S) ($C $C))) (($B ($B $Y)) (($B ($B ($B _571))) (($C' ($C' _686)) (($B ($B $T)) ((($C' ($C' ($C' ($C' $O)))) (($B ($B (($C' $B) $P))) ($B _5))) $K))))))) (($B (($S' _747) (($B _744) (($B (_747 _792)) (($B (_684 "not found ")) _587))))) ($C _572))))) (($A :5 ((($C' $C) ((($S' $C) ((($C' ($C' $S')) (($S $P) ((($S' ($C' $B)) (($B ($B _7)) _5)) _5))) ($BK $K))) ((($C' ($S' $C)) ((($C' ($C' $C)) (($B (($C' $C) (($B ($P _7)) $K))) ((($C' $B) _5) _409))) ((($S' _747) (($B _744) (($B (_747 _792)) (_684 "primlookup: ")))) (($C (_723 _641)) _6)))) $K))) (_792 "trans: impossible"))) (($A :6 (($O (($P (($O 66) $K)) $B)) (($O (($P (($O 79) $K)) $O)) (($O (($P (($O 75) $K)) $K)) (($O (($P "C'") $C')) (($O (($P (($O 67)
\ No newline at end of file
+871
+(($A :0 ((_663 _612) (($B ((($S' ($C (($C (($C $S') _3)) ((($C' ($C' $P)) ((($C' $B) _1) _595)) ($K ($K (_807 "Usage: mhs [-v] [-r] [-iPATH] [-oFILE] [ModuleName]"))))))) (($S (($S ((($S' _21) (($B _716) (_703 (_655 "-v")))) ((_732 _655) "-r"))) (($B (_697 (($O 46) $K))) (($B _761) (_702 ((_721 _783) "-i")))))) (($B (_762 _728)) ((($C' _699) (($B _761) (_702 ((_721 _783) "-o")))) (($O "out.comb") $K))))) (_703 ((_763 _803) ((_763 (_655 (($O 45) $K))) (_714 1)))))) (_724 ((_763 _803) (_655 "--")))))) (($A :1 ((($S' ($S' _663)) _30) (($B ($B ($B (_663 _693)))) ((($C' ($C' ($C' $C))) ((($C' $B) (($B ($C' $C)) ((($C' ($S' ($C' $C'))) (($B ($B ($B $C))) ((($C' ($C' ($C' $C))) ((($C' ($C' ($C' ($C' $S')))) (($B ($B ($B ($B $C)))) ((($C' ($C' ($C' ($C' $C)))) ((($C' ($C' ($C' ($S' ($C' $S'))))) ((($C' ($C' ($C' ($C' ($C' $C'))))) ((($C' ($S' ($C' ($C' ($C' $C'))))) (($B ($B ($B ($B $B')))) ((($C' ($S' ($C' $B))) (($B ($B ($B $C))) ((($S' $B) ($B' (($B ($S' $C')) (($B $B') (($B ($B _664)) ((($C' $B) (($B _762) (($B _683) ((($C' _798) _22) 0)))) (($B (_762 _686)) (($B (_699 "top level defns: ")) _643)))))))) ((($S' ($C' $B)) (($B $B') (($B $B') (($B $B') (($B ($B _664)) ((($C' $B) (($B _762) (($B _683) ((($C' _798) _22) 1)))) (_682 ($T (($B ($B (_762 _686))) ((($C' $B) (($B _699) ((($C' _699) _601) " = "))) (($C _421) $K))))))))))) ((($C' ($C' ($C' ($C' $B)))) ((($S' $B) ($B' ($B' _23))) ((($S' $B) (($B ($C' ($C' _664))) ((($C' $B) ($B' (($B _762) (($B _688) _25)))) (($B _699) ((($C' _699) (($B (_699 _2)) _643)) (($O 10) $K)))))) (($B ($B (_663 _693))) ((($C' $B) ($B' (($B _762) (($B _683) ((($C' _798) _22) 0))))) (($B ($B (_762 _686))) ((($C' ($C' _699)) (($B ($B (_699 "final pass            "))) (($B ($B (_657 6))) (($B ($B _643)) _792)))) "ms"))))))) _16))))) ($C $P)))) ((($C' ($C' $C)) (($B (($C' $C) (($B ($C _704)) _421))) (($C _717) (_733 0)))) $K))) (($B ($C $B)) (($B ($B ($C $B))) (($B ($B $BK)) (($B ($B (($C' $B) (($B _763) (($B _699) ((($C' _699) (($B (_699 "(($A :")) _643)) (($O 32) $K))))))) ((($C' $B) (($B ($C' _763)) ($B _421))) (($B (_763 (_699 ") "))) (($C _763) (_699 (($O 41) $K))))))))))) $T)) (($B $Y) ((($C' ($C' $S)) ((($C' ($C' $S)) ((($C' $B) $P) ((($S' ($C' $B)) ($B _396)) $I))) ($BK $K))) $K))))) (($B (($S' _762) (($B _759) (($B (_762 _807)) (($B (_699 "main: findIdent: ")) _601))))) (($C' _631) _598)))) _638))) (($B ($B _635)) (($B (($C' _701) (($B $T) (($B ($C $B)) (($B ($B $BK)) ((($C' ($C' ($C' $O))) ($B (($C' $P) _598))) $K)))))) (($C _717) (_733 0))))))) (($C _604) (_595 "main")))) (($B (_762 _395)) (($B (_762 _595)) (($B (_699 (($O 95) $K))) _643))))))) (($A :2 "v3.4\10&") (($A :3 (($B (_664 (_686 "Type ':quit' to quit"))) ((($C' _663) (($B (_569 _5)) ($P _4))) ($K (_665 _809))))) (($A :4 ((_699 ((_699 ((_699 ((_699 "module ") _6)) "(module ")) _6)) ") where\10&import Prelude\10&import Unsafe.Coerce\10&")) (($A :5 ((_570 ((_762 _579) ((_13 ".mhsi") "> "))) (($P _5) (($C (($S (($C _655) ":quit")) ((($C' _571) _9) _5))) ((_762 _579) (_686 "Bye")))))) (($A :6 "Interactive") (($A :7 "_it") (($A :8 ((($C' _699) (_699 ((_699 ((_699 ((_699 _7) " :: Any\10&")) _7)) " = unsafeCoerce ("))) (($O 41) $K))) (($A :9 (($B (_570 _578)) (($B $T) ((($S' ($S' $B)) (($B ($B _570)) (($B ($B _10)) (($B (($C' _699) (($C _699) (($O 10) $K)))) _8)))) ((($C' ($C' ($C' $P))) (($B ($B $BK)) (($B ($B (($C' (($S' _570) _10)) (($B ($B ($P (($B (_762 _579)) _686)))) (($B $BK) (($B ($B _577)) ($C $P))))))) (($C' _699) (($C _699) (($O 10) $K)))))) _11))))) (($A :10 ((($C' _571) (($B (_762 _579)) (_688 ((_699 _6) ".hs")))) ((_570 (_574 _771)) ((($C' _570) (($B (_762 _579)) (($C _30) (_595 _6)))) (($B _572) _774))))) (($A :11 (($B (($B (_762 _579)) (($S (($C _867) (_686 "Type must be Int or IO"))) (($B (_762 _686)) (($B (_762 _643)) _20))))) (($B _17) ($P (_595 ((_699 ((_699 _6) (($O 46) $K))) _7)))))) (($A :12 ((($C' _664) _684) ((_663 (((_15 (($P _696) _696)) $K) $K)) ($T ($K _665))))) (($A :13 ((($S' $B) (($B _663) (($C _676) _659))) (($B ($B (($C' _663) (($P (_665 _696)) ((($C' _663) _690) (($B ((($S' _695) _716) _665)) _652)))))
\ No newline at end of file
--- a/ghc/Primitives.hs
+++ b/ghc/Primitives.hs
@@ -167,3 +167,9 @@
 primGetTimeMilli  = floor . (1000 *) . nominalDiffTimeToSeconds . utcTimeToPOSIXSeconds <$> getCurrentTime
 primGetRaw       :: IO Int
 primGetRaw        = return (-1) -- not implemented
+
+-- Temporary until overloading
+primIsInt        :: Any -> Bool
+primIsInt         = error "isInt"
+primIsIO         :: Any -> Bool
+primIsIO          = error "isIO"
--- /dev/null
+++ b/ghc/System/Console/SimpleReadline.hs
@@ -1,0 +1,4 @@
+module System.Console.SimpleReadline where
+
+getInputLineHist :: FilePath -> String -> IO (Maybe String)
+getInputLineHist _ _ = error "getInputLineHist"
--- a/lib/Primitives.hs
+++ b/lib/Primitives.hs
@@ -143,3 +143,9 @@
 
 primWithDropArgs :: forall a . Int -> IO a -> IO a
 primWithDropArgs i ioa = primThen (primDropArgs i) ioa
+
+-- Temporary until overloading
+primIsInt        :: Any -> Bool
+primIsInt         = primitive "isInt"
+primIsIO         :: Any -> Bool
+primIsIO          = primitive "isIO"
--- a/lib/System/IO.hs
+++ b/lib/System/IO.hs
@@ -25,6 +25,9 @@
 return      :: forall a . a -> IO a
 return       = primReturn
 
+fail        :: forall a . String -> IO a
+fail s       = error s
+
 hSerialize   :: forall a . Handle -> a -> IO ()
 hSerialize   = primHSerialize
 hDeserialize :: forall a . Handle -> IO a
--- a/lib/Unsafe/Coerce.hs
+++ b/lib/Unsafe/Coerce.hs
@@ -1,4 +1,4 @@
-module Unsafe.Coerce(module Unsafe.Coerce, Any) where
+module Unsafe.Coerce(module Unsafe.Coerce, Any, primIsInt, primIsIO) where
 import Primitives
 
 unsafeCoerce :: forall a b . a -> b
--- a/src/Compat.hs
+++ b/src/Compat.hs
@@ -10,6 +10,7 @@
 import Data.List
 import System.Environment
 import System.IO
+import GHC.Types(Any)
 
 -- Functions needed for ghc
 eqChar :: Char -> Char -> Bool
@@ -105,6 +106,9 @@
         (a2, b2) ->
           eqa a1 a2 && eqb b1 b2
 
+showPair :: (a -> String) -> (b -> String) -> (a, b) -> String
+showPair f g (a, b) = "(" ++ f a ++ "," ++ g b ++ ")"
+
 eqInt :: Int -> Int -> Bool
 eqInt = (==)
 
@@ -171,3 +175,9 @@
 neBool :: Bool -> Bool -> Bool
 neBool True  x = not x
 neBool False x = x
+
+-- Temporary until overloading
+primIsInt        :: Any -> Bool
+primIsInt         = error "isInt"
+primIsIO         :: Any -> Bool
+primIsIO          = error "isIO"
--- a/src/CompatIO.hs
+++ b/src/CompatIO.hs
@@ -14,3 +14,6 @@
 
 when :: Bool -> IO () -> IO ()
 when = M.when
+
+fail        :: forall a . String -> IO a
+fail s       = error s
--- a/src/MicroHs/Compile.hs
+++ b/src/MicroHs/Compile.hs
@@ -1,7 +1,7 @@
 -- Copyright 2023 Lennart Augustsson
 -- See LICENSE file for full license.
 module MicroHs.Compile(
-  compile,
+  compile, compileTop,
   Flags(..), verbose, runIt, output
   ) where
 import Prelude --Xhiding (Monad(..), mapM, showString, showList)
@@ -13,6 +13,7 @@
 import qualified MicroHs.IdentMap as M
 import MicroHs.StateIO as S
 import MicroHs.Desugar
+import MicroHs.Exp
 import MicroHs.Expr
 import MicroHs.Ident
 import MicroHs.Parse
@@ -52,6 +53,20 @@
 
 -----------------
 
+
+--compileTop :: Flags -> IdentModule -> IO [LDef]
+compileTop :: Flags -> Ident -> IO [(Ident, Exp)]
+compileTop flags mn = IO.do
+  ds <- compile flags mn
+  t1 <- getTimeMilli
+  let
+    dsn = [ (n, compileOpt e) | (n, e) <- ds ]
+  () <- IO.return (forceList forceLDef dsn)
+  t2 <- getTimeMilli
+  IO.when (verbose flags > 0) $
+    putStrLn $ "combinator conversion " ++ padLeft 6 (showInt (t2-t1)) ++ "ms"
+  IO.return dsn
+
 compile :: Flags -> IdentModule -> IO [LDef]
 compile flags nm = IO.do
   ((_, t), ch) <- runStateIO (compileModuleCached flags nm) (Cache [] M.empty)
@@ -62,7 +77,7 @@
   IO.return $ concatMap defs $ M.elems $ cache ch
 
 -- Compile a module with the given name.
--- If the module has already been compiled, return the caches result.
+-- If the module has already been compiled, return the cached result.
 compileModuleCached :: Flags -> IdentModule -> StateIO Cache (CModule, Time)
 compileModuleCached flags nm = S.do
   ch <- gets cache
@@ -76,7 +91,8 @@
         liftIO $ putStrLn $ "importing " ++ showIdent nm
       (cm, tp, tt, ts) <- compileModule flags nm
       S.when (verbose flags > 0) $
-        liftIO $ putStrLn $ "importing done " ++ showIdent nm ++ ", " ++ showInt (tp + tt) ++ "ms (" ++ showInt tp ++ " + " ++ showInt tt ++ ")"
+        liftIO $ putStrLn $ "importing done " ++ showIdent nm ++ ", " ++ showInt (tp + tt) ++
+                 "ms (" ++ showInt tp ++ " + " ++ showInt tt ++ ")"
       c <- get
       put $ Cache (tail (working c)) (M.insert nm cm (cache c))
       S.return (cm, tp + tt + ts)
--- a/src/MicroHs/Desugar.hs
+++ b/src/MicroHs/Desugar.hs
@@ -485,7 +485,7 @@
     [] -> ds
     (i1:i2:_) : _ ->
       errorMessage (getSLocIdent i1) $ "Duplicate " ++ showIdent i1 ++ " " ++ showSLoc (getSLocIdent i2)
-    _ -> undefined
+    _ -> error "checkDup"
 
 forceLDef :: LDef -> ()
 forceLDef (i, e) = case forceIdent i of { () -> forceExp e }
--- a/src/MicroHs/Expr.hs
+++ b/src/MicroHs/Expr.hs
@@ -114,10 +114,10 @@
             Con -> Ident
 conIdent (ConData _ i) = i
 conIdent (ConNew i) = i
-conIdent _ = undefined
+conIdent _ = error "conIdent"
 
 conArity :: Con -> Int
-conArity (ConData cs i) = fromMaybe undefined $ lookupBy eqIdent i cs
+conArity (ConData cs i) = fromMaybe (error "conArity") $ lookupBy eqIdent i cs
 conArity (ConNew _) = 1
 conArity (ConLit _) = 0
 
@@ -313,7 +313,7 @@
 setSLocExpr l (EVar i) = EVar (setSLocIdent l i)
 setSLocExpr l (ECon c) = ECon (setSLocCon l c)
 setSLocExpr l (ELit _ k) = ELit l k
-setSLocExpr _ _ = undefined  -- what other cases do we need?
+setSLocExpr _ _ = error "setSLocExpr"  -- what other cases do we need?
 
 setSLocCon :: SLoc -> Con -> Con
 setSLocCon l (ConData ti i) = ConData ti (setSLocIdent l i)
--- a/src/MicroHs/Ident.hs
+++ b/src/MicroHs/Ident.hs
@@ -66,9 +66,9 @@
 unQualString s =
   case span isIdentChar s of
     ("", r) -> r
+    (r, "") -> r                       -- XXX bug!  swapping with next line goes wrong
     (_, '.':r) -> unQualString r
-    (r, "") -> r
-    _ -> undefined
+    x -> error $ "unQualString: " ++ showPair showString (showPair showString showString) (s, x)
 
 isConIdent :: Ident -> Bool
 isConIdent (Ident _ i) =
--- /dev/null
+++ b/src/MicroHs/Interactive.hs
@@ -1,0 +1,77 @@
+module MicroHs.Interactive(module MicroHs.Interactive) where
+import Prelude
+import qualified MicroHs.StateIO as S
+import MicroHs.Compile
+import MicroHs.Exp(Exp)
+import MicroHs.Ident(Ident, mkIdent)
+import MicroHs.Translate
+import Unsafe.Coerce
+import System.Console.SimpleReadline
+--Ximport Compat
+
+type LDef = (Ident, Exp)  -- XXX why?
+
+type IState = (String, Flags)
+
+type I a = S.StateIO IState a
+
+mainInteractive :: Flags -> IO ()
+mainInteractive flags = do
+  putStrLn "Type ':quit' to quit"
+  _ <- S.runStateIO repl (preamble, flags)
+  return ()
+
+preamble :: String
+preamble = "module " ++ interactiveName ++ "(module " ++ interactiveName ++ ") where\nimport Prelude\nimport Unsafe.Coerce\n"
+
+repl :: I ()
+repl = S.do
+  ms <- S.liftIO $ getInputLineHist ".mhsi" "> "
+  case ms of
+    Nothing -> repl
+    Just ":quit" -> S.liftIO $ putStrLn "Bye"
+    Just s -> S.do
+      oneline s
+      repl
+
+interactiveName :: String
+interactiveName = "Interactive"
+
+itName :: String
+itName = "_it"
+
+mkIt :: String -> String
+mkIt l = itName ++ " :: Any\n" ++ itName ++ " = unsafeCoerce (" ++ l ++ ")"
+
+oneline :: String -> I ()
+oneline line = S.do
+  (ls, flgs) <- S.get
+  exprTest <- tryCompile (ls ++ "\n" ++ mkIt line)
+  case exprTest of
+    Right m -> evalExpr m
+    Left  _ -> S.do
+      let lls = ls ++ "\n" ++ line
+      defTest <- tryCompile lls
+      case defTest of
+        Right _ -> S.put (lls, flgs)
+        Left  s -> S.liftIO $ putStrLn s
+
+tryCompile :: String -> I (Either String [LDef])
+tryCompile file = S.do
+  S.liftIO $ writeFile (interactiveName ++ ".hs") file
+  flgs <- S.gets snd
+  cmdl <- S.liftIO $ compileTop flgs (mkIdent interactiveName)
+  S.return (Right cmdl)
+
+evalExpr :: [LDef] -> I ()
+evalExpr cmdl = S.do
+  let val = translate (mkIdent (interactiveName ++ "." ++ itName), cmdl)
+  S.liftIO $
+    if primIsInt val then
+      putStrLn $ showInt $ unsafeCoerce val
+{-
+    else if primIsIO val then
+      unsafeCoerce val
+-}
+    else
+      putStrLn "Type must be Int or IO"
--- a/src/MicroHs/Main.hs
+++ b/src/MicroHs/Main.hs
@@ -7,11 +7,10 @@
 import Data.Maybe
 import System.Environment
 import MicroHs.Compile
-import MicroHs.Desugar
-import MicroHs.Expr
 import MicroHs.Exp
 import MicroHs.Ident
 import MicroHs.Translate
+import MicroHs.Interactive
 --Ximport Compat
 
 main :: IO ()
@@ -19,18 +18,23 @@
   aargs <- getArgs
   let
     args = takeWhile (not . eqString "--") aargs
-    mn =
-      let
-        ss = filter (not . (eqString "-") . take 1) args
-      in   if length ss == 1 then head ss else error "Usage: mhs [-v] [-r] [-iPATH] [-oFILE] ModuleName"
+    ss = filter (not . (eqString "-") . take 1) args
     flags = Flags (length (filter (eqString "-v") args))
                   (elemBy eqString "-r" args)
                   ("." : catMaybes (map (stripPrefixBy eqChar "-i") args))
                   (head $ catMaybes (map (stripPrefixBy eqChar "-o") args) ++ ["out.comb"])
-  cmdl <- compileTop flags (mkIdent mn)
+  case ss of
+    [] -> mainInteractive flags
+    [s] -> mainCompile flags (mkIdent s)
+    _ -> error "Usage: mhs [-v] [-r] [-iPATH] [-oFILE] [ModuleName]"
+
+mainCompile :: Flags -> Ident -> IO ()
+mainCompile flags mn = do
+  ds <- compileTop flags mn
   t1 <- getTimeMilli
   let
-    (mainName, ds) = cmdl
+    mainName = qualIdent mn (mkIdent "main")
+    cmdl = (mainName, ds)
     ref i = Var $ mkIdent $ "_" ++ showInt i
     defs = M.fromList [ (unIdent n, ref i) | ((n, _), i) <- zip ds (enumFrom 0) ]
     findIdent n = fromMaybe (error $ "main: findIdent: " ++ showIdent n) $
@@ -65,17 +69,3 @@
 
 version :: String
 version = "v3.4\n"
-
-type Program = (Ident, [LDef])
-
-compileTop :: Flags -> IdentModule -> IO Program
-compileTop flags mn = do
-  ds <- compile flags mn
-  t1 <- getTimeMilli
-  let
-    dsn = [ (n, compileOpt e) | (n, e) <- ds ]
-  () <- return (forceList forceLDef dsn)
-  t2 <- getTimeMilli
-  when (verbose flags > 0) $
-    putStrLn $ "combinator conversion " ++ padLeft 6 (showInt (t2-t1)) ++ "ms"
-  return (qualIdent mn (mkIdent "main"), dsn)
--- a/src/MicroHs/Parse.hs
+++ b/src/MicroHs/Parse.hs
@@ -515,7 +515,7 @@
 -------------
 
 eTuple :: [Expr] -> Expr
-eTuple [] = undefined
+eTuple [] = error "eTuple"
 eTuple [e] = e
 eTuple es = ETuple es
 
--- a/src/MicroHs/Translate.hs
+++ b/src/MicroHs/Translate.hs
@@ -13,12 +13,12 @@
 --Ximport PrimTable
 --Yimport PrimTable
 
-import MicroHs.Desugar
 import MicroHs.Expr
 import MicroHs.Exp
 import MicroHs.Ident
 
-translateAndRun :: (Ident, [LDef]) -> IO ()
+--translateAndRun :: (Ident, [LDef]) -> IO ()
+translateAndRun :: (Ident, [(Ident, Exp)]) -> IO ()
 translateAndRun defs = do
   -- Drop all argument up to '--'
   args <- getArgs
@@ -26,7 +26,8 @@
   withDropArgs (length (takeWhile (not . eqString "--") args) + 1)
     prog
 
-translate :: (Ident, [LDef]) -> Any
+--translate :: (Ident, [LDef]) -> Any
+translate :: (Ident, [(Ident, Exp)]) -> Any
 translate (mainName, ds) =
   let
     look m n = fromMaybe (error $ "not found " ++ showIdent n) $ M.lookup n m
@@ -100,5 +101,7 @@
   ("IO.getArgs", primitive "IO.getArgs"),
   ("IO.dropArgs", primitive "IO.dropArgs"),
   ("IO.performIO", primitive "IO.performIO"),
-  ("IO.getTimeMilli", primitive "IO.getTimeMilli")
+  ("IO.getTimeMilli", primitive "IO.getTimeMilli"),
+  ("isInt", primitive "isInt"),
+  ("isIO", primitive "isIO")
   ]
--- a/src/MicroHs/TypeCheck.hs
+++ b/src/MicroHs/TypeCheck.hs
@@ -116,7 +116,7 @@
 
 tyQIdent :: Entry -> Ident
 tyQIdent (Entry (EVar qi) _) = qi
-tyQIdent _ = undefined
+tyQIdent _ = error "tyQIdent"
 
 constrsOf :: Ident -> [(Ident, [Entry])] -> [ValueExport]
 constrsOf qi ies =
@@ -132,7 +132,7 @@
 getAppCon :: EType -> Ident
 getAppCon (EVar i) = i
 getAppCon (EApp f _) = getAppCon f
-getAppCon _ = undefined
+getAppCon _ = error "getAppCon"
 
 eVarI :: SLoc -> String -> Expr
 eVarI loc = EVar . mkIdentSLoc loc
--- a/src/runtime/eval.c
+++ b/src/runtime/eval.c
@@ -157,6 +157,7 @@
                 T_IO_GETTIMEMILLI, T_IO_PRINT,
                 T_IO_CCALL, T_IO_GETRAW, T_IO_FLUSH,
                 T_STR,
+                T_ISINT, T_ISIO,
                 T_LAST_TAG,
 };
 
@@ -458,6 +459,8 @@
   { "IO.dropArgs", T_IO_DROPARGS },
   { "IO.getTimeMilli", T_IO_GETTIMEMILLI },
   { "IO.performIO", T_IO_PERFORMIO },
+  { "isInt", T_ISINT },
+  { "isIO", T_ISIO },
 };
 
 void
@@ -1137,6 +1140,8 @@
   case T_IO_GETTIMEMILLI: fprintf(f, "$IO.getTimeMilli"); break;
   case T_IO_PERFORMIO: fprintf(f, "$IO.performIO"); break;
   case T_IO_CCALL: fprintf(f, "#%s", ffi_table[GETVALUE(n)].ffi_name); break;
+  case T_ISINT: fprintf(f, "$isInt"); break;
+  case T_ISIO: fprintf(f, "$isIO"); break;
   default: ERR("print tag");
   }
 }
@@ -1492,6 +1497,19 @@
     case T_IO_GETTIMEMILLI:
     case T_IO_CCALL:
       RET;
+
+    case T_ISINT:
+      CHECK(1);
+      x = evali(ARG(TOP(0)));
+      POP(1);
+      GOIND(GETTAG(x) == T_INT ? comTrue : combFalse);
+
+    case T_ISIO:
+      CHECK(1);
+      x = evali(ARG(TOP(0)));
+      POP(1);
+      l = GETTAG(x);
+      GOIND(T_IO_BIND <= l && l <= T_IO_FLUSH ? comTrue : combFalse);
 
     default:
       fprintf(stderr, "bad tag %d\n", GETTAG(n));
--