diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -26,7 +26,25 @@
                , "TARGET=" ++ idir
                , "IDRIS=" ++ icmd
                ]
+         putStrLn $ "Installing run time system in " ++ idir ++ "/rts"
+         make verbosity
+               [ "-C", "rts", "install"
+               , "TARGET=" ++ idir ++ "/rts"
+               , "IDRIS=" ++ icmd
+               ]
 
+-- This is a hack. I don't know how to tell cabal that a data file needs
+-- installing but shouldn't be in the distribution. And it won't make the
+-- distribution if it's not there, so instead I just delete
+-- the file after configure.
+
+removeLibIdris local verbosity
+    = do let icmd = ".." </> buildDir local </> "idris" </> "idris"
+         make verbosity
+               [ "-C", "rts", "clean"
+               , "IDRIS=" ++ icmd
+               ]
+
 checkStdLib local verbosity
     = do let icmd = ".." </> buildDir local </> "idris" </> "idris"
          putStrLn $ "Building libraries..."
@@ -34,6 +52,10 @@
                [ "-C", "lib", "check"
                , "IDRIS=" ++ icmd
                ]
+         make verbosity
+               [ "-C", "rts", "check"
+               , "IDRIS=" ++ icmd
+               ]
 
 -- Install libraries during both copy and install
 -- See http://hackage.haskell.org/trac/hackage/ticket/718
@@ -44,6 +66,8 @@
         , postInst = \ _ flags pkg lbi -> do
               installStdLib pkg lbi (S.fromFlag $ S.installVerbosity flags)
                                     NoCopyDest
+        , postConf  = \ _ flags _ lbi -> do
+              removeLibIdris lbi (S.fromFlag $ S.configVerbosity flags)
         , postClean = \ _ flags _ _ -> do
               cleanStdLib (S.fromFlag $ S.cleanVerbosity flags)
         , postBuild = \ _ flags _ lbi -> do
diff --git a/idris.cabal b/idris.cabal
--- a/idris.cabal
+++ b/idris.cabal
@@ -1,5 +1,5 @@
 Name:           idris
-Version:        0.9.2.1
+Version:        0.9.3
 License:        BSD3
 License-file:   LICENSE
 Author:         Edwin Brady
@@ -40,8 +40,12 @@
 Cabal-Version:  >= 1.6
 Build-type:     Custom
 
+Data-files:            rts/libidris_rts.a rts/idris_rts.h rts/idris_gc.h
+                       rts/idris_stdfgn.h rts/idris_main.c rts/idris_gmp.h
 Extra-source-files:    lib/Makefile  lib/*.idr lib/prelude/*.idr lib/network/*.idr
-                       lib/control/monad/*.idr tutorial/examples/*.idr
+                       lib/control/monad/*.idr lib/language/*.idr
+                       tutorial/examples/*.idr
+                       rts/*.c rts/*.h rts/Makefile
 
 source-repository head
   type:     git
@@ -56,7 +60,8 @@
                               Core.ShellParser, Core.Unify, Core.Elaborate,
                               Core.CaseTree, Core.Constraints,
 
-                              Idris.AbsSyntax, Idris.Parser, Idris.REPL,
+                              Idris.AbsSyntax, Idris.AbsSyntaxTree,
+                              Idris.Parser, Idris.REPL,
                               Idris.REPLParser, Idris.ElabDecls, Idris.Error,
                               Idris.Delaborate, Idris.Primitives, Idris.Imports,
                               Idris.Compiler, Idris.Prover, Idris.ElabTerm,
@@ -65,13 +70,16 @@
 
                               Util.Pretty,
 
+                              IRTS.Lang, IRTS.LParser, IRTS.Bytecode, IRTS.Simplified,
+                              IRTS.CodegenC, IRTS.Defunctionalise, IRTS.Compiler,
+
                               Paths_idris
 
-               Build-depends:   base>=4 && <5, parsec, mtl, Cabal, haskeline,
+               Build-depends:   base>=4 && <5, parsec, mtl, Cabal, haskeline<0.7,
                                 containers, process, transformers, filepath, directory,
-                                binary, bytestring, epic>=0.9.3, pretty
+                                binary, bytestring, pretty
                                 
                Extensions:      MultiParamTypeClasses, FunctionalDependencies,
                                 FlexibleInstances, TemplateHaskell
-               ghc-prof-options: -auto-all
+               ghc-prof-options: -auto-all -caf-all
                ghc-options: -rtsopts
diff --git a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -7,19 +7,22 @@
 install: check
 	mkdir -p $(TARGET)/prelude
 	mkdir -p $(TARGET)/network
+	mkdir -p $(TARGET)/language
 	mkdir -p $(TARGET)/control/monad
 	install *.ibc $(TARGET)
 	install prelude/*.ibc $(TARGET)/prelude
 	install network/*.ibc $(TARGET)/network
+	install language/*.ibc $(TARGET)/language
 	install control/monad/*.ibc $(TARGET)/control/monad
 
 clean: .PHONY
 	rm -f *.ibc
 	rm -f prelude/*.ibc
 	rm -f network/*.ibc
+	rm -f language/*.ibc
 	rm -f control/monad/*.ibc
 
 linecount: .PHONY
-	wc -l *.idr network/*.idr prelude/*.idr control/monad/*.idr
+	wc -l *.idr network/*.idr language/*.idr prelude/*.idr control/monad/*.idr
 
 .PHONY:
diff --git a/lib/builtins.idr b/lib/builtins.idr
--- a/lib/builtins.idr
+++ b/lib/builtins.idr
@@ -85,11 +85,11 @@
 not True = False
 not False = True
 
-infixl 5 ==, /=, ==.
-infixl 6 <, <=, >, >=, <., <=., >., >=.
+infixl 5 ==, /=
+infixl 6 <, <=, >, >=
 infixl 7 <<, >>
-infixl 8 +,-,++,+.,-.
-infixl 9 *,/,*.,/.
+infixl 8 +,-,++
+infixl 9 *,/
 
 --- Numeric operators
 
@@ -127,6 +127,12 @@
 
 
 data Ordering = LT | EQ | GT
+
+instance Eq Ordering where
+    LT == LT = True
+    EQ == EQ = True
+    GT == GT = True
+    _  == _  = False
 
 class Eq a => Ord a where 
     compare : a -> a -> Ordering
diff --git a/lib/checkall.idr b/lib/checkall.idr
--- a/lib/checkall.idr
+++ b/lib/checkall.idr
@@ -25,5 +25,7 @@
 
 import network.cgi 
 
+import language.reflection
+
 import control.monad.identity
 import control.monad.state
diff --git a/lib/io.idr b/lib/io.idr
--- a/lib/io.idr
+++ b/lib/io.idr
@@ -8,6 +8,9 @@
 io_bind : IO a -> (a -> IO b) -> IO b
 io_bind (prim__IO v) k = k v
 
+unsafePerformIO : IO a -> a
+-- compiled as primitive
+
 abstract
 io_return : a -> IO a
 io_return x = prim__IO x
@@ -18,15 +21,16 @@
 run__IO : IO () -> IO ()
 run__IO v = io_bind v (\v' => io_return v')
 
-data FTy = FInt | FFloat | FChar | FString | FPtr | FUnit
+data FTy = FInt | FFloat | FChar | FString | FPtr | FAny Set | FUnit
 
 interpFTy : FTy -> Set
-interpFTy FInt    = Int
-interpFTy FFloat  = Float
-interpFTy FChar   = Char
-interpFTy FString = String
-interpFTy FPtr    = Ptr
-interpFTy FUnit   = ()
+interpFTy FInt     = Int
+interpFTy FFloat   = Float
+interpFTy FChar    = Char
+interpFTy FString  = String
+interpFTy FPtr     = Ptr
+interpFTy (FAny t) = t
+interpFTy FUnit    = ()
 
 ForeignTy : (xs:List FTy) -> (t:FTy) -> Set
 ForeignTy xs t = mkForeign' (reverse xs) (IO (interpFTy t)) where 
@@ -40,6 +44,7 @@
            Foreign (ForeignTy xs t)
 
 mkForeign : Foreign x -> x
--- mkForeign compiled as primitive
+mkLazyForeign : Foreign x -> x
+-- mkForeign and mkLazyForeign compiled as primitives
 
 
diff --git a/lib/language/reflection.idr b/lib/language/reflection.idr
new file mode 100644
--- /dev/null
+++ b/lib/language/reflection.idr
@@ -0,0 +1,11 @@
+module language.reflection
+
+TTName : Set
+TTName = String
+
+data TT = Var TTName
+        | Lam TTName TT TT
+        | Pi  TTName TT TT
+        | Let TTName TT TT TT
+        | App TTName TT TT
+
diff --git a/lib/network/sockets.idr b/lib/network/sockets.idr
new file mode 100644
--- /dev/null
+++ b/lib/network/sockets.idr
@@ -0,0 +1,78 @@
+%include "network.h"
+%lib "network.o"
+
+f_netTest = mkForeign (FFun "netTest" (Cons FStr (Cons FInt Nil)) FInt); 
+	  [%nocg]
+
+f_clientSocket = mkForeign (FFun "net_UDP_clientSocket"
+	                 (Cons FStr (Cons FInt Nil)) FPtr); [%eval]
+f_serverSocket = mkForeign (FFun "net_UDP_serverSocket"
+	                 (Cons FInt Nil) FPtr); [%eval]
+f_send = mkForeign (FFun "net_sendUDP"
+     (Cons FPtr (Cons FStr (Cons FInt (Cons FStr Nil)))) FInt); [%eval]
+f_recv = mkForeign (FFun "net_recvUDP"
+		   (Cons FPtr Nil) FPtr); [%eval]
+
+f_recvBuf = mkForeign (FFun "get_recvBuf"
+		   (Cons FPtr Nil) FStr); [%eval]
+f_recvServer = mkForeign (FFun "get_recvServer"
+		   (Cons FPtr Nil) FStr); [%eval]
+f_recvPort = mkForeign (FFun "get_recvPort"
+		   (Cons FPtr Nil) FInt); [%eval]
+
+f_nullPtr = mkForeign (FFun "nullPtr" (Cons FPtr Nil) FInt); [%eval]
+
+nullPtr : Ptr -> (IO Bool);
+nullPtr ptr = do { p <- f_nullPtr ptr;
+		   return (if_then_else (p==1) True False);
+};
+
+data Socket = mkCon Ptr;
+data Recv = mkRecv String String Int
+          | noRecv;
+
+clientSocket : String -> Int -> (IO Socket);
+clientSocket server port = do {
+	     sock <- f_clientSocket server port;
+	     return (mkCon sock); };
+
+serverSocket : Int -> (IO Socket);
+serverSocket port = do {
+	     sock <- f_serverSocket port;
+	     return (mkCon sock); };
+
+sendTo : Socket -> String -> Int -> String -> (IO ());
+sendTo (mkCon c) server port dat 
+       = do { v <- f_send c server port dat;
+	      return II; };
+
+doMkRecv : Bool -> Ptr -> (IO Recv);
+doMkRecv True _ = return noRecv;
+doMkRecv False rcv = do {
+	 buf <- f_recvBuf rcv;
+	 server <- f_recvServer rcv;
+	 port <- f_recvPort rcv;
+--	 putStrLn ("Port from connection is " ++ (__toString port));
+	 return (mkRecv buf server port);
+};
+
+recvFrom : Socket -> (IO Recv);
+recvFrom (mkCon c) = do {
+	 rcv <- f_recv c;
+	 nul <- nullPtr rcv;
+         doMkRecv nul rcv;
+};
+
+
+recvOK : Recv -> Bool;
+recvOK (mkRecv _ _ _) = True;
+recvOK noRecv = False;
+
+recvStr : Recv -> String;
+recvStr (mkRecv buf server port) = buf;
+
+recvServer : Recv -> String;
+recvServer (mkRecv buf server port) = server;
+
+recvPort : Recv -> Int;
+recvPort (mkRecv buf server port) = port;
diff --git a/lib/prelude.idr b/lib/prelude.idr
--- a/lib/prelude.idr
+++ b/lib/prelude.idr
@@ -194,7 +194,7 @@
 print x = putStrLn (show x)
 
 getLine : IO String
-getLine = mkForeign (FFun "readStr" Nil FString)
+getLine = return (prim__readString prim__stdin)
 
 putChar : Char -> IO ()
 putChar c = mkForeign (FFun "putchar" [FChar] FUnit) c
@@ -230,7 +230,7 @@
 closeFile (FHandle h) = do_fclose h
 
 do_fread : Ptr -> IO String
-do_fread h = mkForeign (FFun "freadStr" [FPtr] FString) h
+do_fread h = return (prim__readString h)
 
 fread : File -> IO String
 fread (FHandle h) = do_fread h
diff --git a/lib/prelude/complex.idr b/lib/prelude/complex.idr
--- a/lib/prelude/complex.idr
+++ b/lib/prelude/complex.idr
@@ -1,3 +1,8 @@
+{-
+  © 2012 Copyright Mekeor Melire
+-}
+
+
 module prelude.complex
 
 import builtins
diff --git a/lib/prelude/list.idr b/lib/prelude/list.idr
--- a/lib/prelude/list.idr
+++ b/lib/prelude/list.idr
@@ -88,6 +88,14 @@
 drop (S n) []      = []
 drop (S n) (x::xs) = drop n xs
 
+takeWhile : (a -> Bool) -> List a -> List a
+takeWhile p []      = []
+takeWhile p (x::xs) = if p x then x :: takeWhile p xs else []
+
+dropWhile : (a -> Bool) -> List a -> List a
+dropWhile p []      = []
+dropWhile p (x::xs) = if p x then dropWhile p xs else x::xs
+
 --------------------------------------------------------------------------------
 -- Misc.
 --------------------------------------------------------------------------------
@@ -101,12 +109,18 @@
 length (x::xs) = 1 + length xs
 
 --------------------------------------------------------------------------------
--- Building bigger lists
+-- Building (bigger) lists
 --------------------------------------------------------------------------------
 
 (++) : List a -> List a -> List a
 (++) [] right      = right
 (++) (x::xs) right = x :: (xs ++ right)
+
+repeat : a -> List a
+repeat x = x :: repeat x
+
+replicate : Nat -> a -> List a
+replicate n x = take n (repeat x)
 
 --------------------------------------------------------------------------------
 -- Instances
diff --git a/lib/prelude/nat.idr b/lib/prelude/nat.idr
--- a/lib/prelude/nat.idr
+++ b/lib/prelude/nat.idr
@@ -44,6 +44,14 @@
 power base O       = S O
 power base (S exp) = mult base $ power base exp
 
+hyper : Nat -> Nat -> Nat -> Nat
+hyper O        a b      = S b
+hyper (S O)    a O      = a
+hyper (S(S O)) a O      = O
+hyper n        a O      = S O
+hyper (S pn)   a (S pb) = hyper pn a (hyper (S pn) a pb)
+
+
 --------------------------------------------------------------------------------
 -- Comparisons
 --------------------------------------------------------------------------------
@@ -115,7 +123,7 @@
 
   abs x = x
 
-  fromInteger = fromInteger'
+  fromInteger x = fromInteger' x
     where
       %assert_total
       fromInteger' : Int -> Nat
@@ -805,7 +813,7 @@
 plusRightCancelStepCase = proof {
     intros;
     refine inductiveHypothesis;
-    refine succInjective;
+    refine succInjective _ _ ?;
     rewrite sym (plusSuccRightSucc left right);
     rewrite sym (plusSuccRightSucc left' right);
     rewrite p;
@@ -832,4 +840,3 @@
     rewrite p;
     trivial;
 }
-
diff --git a/lib/prelude/strings.idr b/lib/prelude/strings.idr
--- a/lib/prelude/strings.idr
+++ b/lib/prelude/strings.idr
@@ -62,3 +62,28 @@
 trim : String -> String
 trim xs = ltrim (reverse (ltrim (reverse xs)))
 
+words' : List Char -> List (List Char)
+words' s = case dropWhile isSpace s of
+            [] => []
+            s' => let (w, s'') = break isSpace s'
+                  in w :: words' s''
+
+words : String -> List String
+words s = map pack $ words' $ unpack s
+
+foldr1 : (a -> a -> a) -> List a -> a	
+foldr1 f [x] = x
+foldr1 f (x::xs) = f x (foldr1 f xs)
+
+
+unwords' : List (List Char) -> List Char
+unwords' [] = []                         
+unwords' ws = (foldr1 addSpace ws)
+        where
+            addSpace : List Char -> List Char -> List Char
+            addSpace w s = w ++ (' ' :: s) 
+          
+               
+unwords :  List String -> String
+unwords = pack . unwords' . map unpack
+
diff --git a/lib/prelude/vect.idr b/lib/prelude/vect.idr
--- a/lib/prelude/vect.idr
+++ b/lib/prelude/vect.idr
@@ -64,13 +64,17 @@
 fromList (x::xs) = x :: fromList xs
 
 --------------------------------------------------------------------------------
--- Building bigger vectors
+-- Building (bigger) vectors
 --------------------------------------------------------------------------------
 
 total
 (++) : Vect a m -> Vect a n -> Vect a (m + n)
 (++) []      ys = ys
 (++) (x::xs) ys = x :: xs ++ ys
+
+replicate : (n : Nat) -> a -> Vect a n
+replicate O     x = []
+replicate (S k) x = x :: replicate k x
 
 --------------------------------------------------------------------------------
 -- Maps
diff --git a/lib/system.idr b/lib/system.idr
--- a/lib/system.idr
+++ b/lib/system.idr
@@ -25,3 +25,6 @@
 exit : Int -> IO ()
 exit code = mkForeign (FFun "exit" [FInt] FUnit) code
 
+usleep : Int -> IO ()
+usleep i = mkForeign (FFun "usleep" [FInt] FUnit) i
+
diff --git a/rts/Makefile b/rts/Makefile
new file mode 100644
--- /dev/null
+++ b/rts/Makefile
@@ -0,0 +1,22 @@
+OBJS = idris_rts.o idris_gc.o idris_gmp.o idris_stdfgn.o
+HDRS = idris_rts.h idris_gc.h idris_gmp.h idris_stdfgn.h
+CFLAGS = -O2
+
+LIBTARGET = libidris_rts.a
+
+check : $(LIBTARGET)
+
+$(LIBTARGET) : $(OBJS)
+	ar r $(LIBTARGET) $(OBJS)
+	ranlib $(LIBTARGET)
+
+install : .PHONY
+	mkdir -p $(TARGET)
+	install $(LIBTARGET) $(HDRS) $(TARGET)
+
+clean : .PHONY
+	rm -f $(OBJS) $(LIBTARGET)
+
+idris_rts.o: idris_rts.h
+
+.PHONY:
diff --git a/rts/idris_gc.c b/rts/idris_gc.c
new file mode 100644
--- /dev/null
+++ b/rts/idris_gc.c
@@ -0,0 +1,113 @@
+#include "idris_rts.h"
+#include "idris_gc.h"
+#include <assert.h>
+
+VAL copy(VM* vm, VAL x) {
+    int i;
+    VAL* argptr;
+    Closure* cl;
+    if (x==NULL || ISINT(x)) {
+        return x;
+    }
+    switch(x->ty) {
+    case CON:
+        cl = allocCon(vm, x->info.c.arity);
+        cl->info.c.tag = x->info.c.tag;
+        cl->info.c.arity = x->info.c.arity;
+
+        argptr = (VAL*)(cl->info.c.args);
+        for(i = 0; i < x->info.c.arity; ++i) {
+//            *argptr = copy(vm, *((VAL*)(x->info.c.args)+i)); // recursive version
+            *argptr = *((VAL*)(x->info.c.args)+i);
+            argptr++;
+        }
+        break;
+    case FLOAT:
+        cl = MKFLOAT(vm, x->info.f);
+        break;
+    case STRING:
+        cl = MKSTR(vm, x->info.str);
+        break;
+    case BIGINT:
+        cl = MKBIGM(vm, x->info.ptr);
+        break;
+    case PTR:
+        cl = MKPTR(vm, x->info.ptr);
+        break;
+    case FWD:
+        return x->info.ptr;
+    }
+    x->ty = FWD;
+    x->info.ptr = cl;
+    return cl;
+}
+
+void cheney(VM *vm) {
+    VAL* argptr;
+    int i;
+    char* scan = vm->heap;
+  
+    while(scan < vm->heap_next) {
+       size_t inc = *((size_t*)scan);
+       VAL heap_item = (VAL)(scan+sizeof(size_t));
+       // If it's a CON, copy its arguments
+       switch(heap_item->ty) {
+       case CON:
+           argptr = (VAL*)(heap_item->info.c.args);
+           for(i = 0; i < heap_item->info.c.arity; ++i) {
+               // printf("Copying %d %p\n", heap_item->info.c.tag, *argptr);
+               VAL newptr = copy(vm, *argptr);
+               // printf("Got %p\t\t%p %p\n", newptr, scan, vm->heap_next);
+               *argptr = newptr;
+               argptr++;
+           }
+           break;
+       }
+       scan += inc;
+    }
+    assert(scan == vm->heap_next);
+}
+
+void gc(VM* vm) {
+    // printf("Collecting\n");
+
+    char* newheap = malloc(vm -> heap_size);
+    char* oldheap = vm -> heap;
+    if (vm->oldheap != NULL) free(vm->oldheap);
+
+    vm->heap = newheap;
+    vm->heap_next = newheap;
+    vm->heap_end = newheap + vm->heap_size;
+
+    vm->collections++;
+
+    VAL* root;
+
+    for(root = vm->valstack; root < vm->valstack_top; ++root) {
+        *root = copy(vm, *root);
+    }
+    vm->ret = copy(vm, vm->ret);
+    vm->reg1 = copy(vm, vm->reg1);
+
+    cheney(vm);
+
+    // After reallocation, if we've still more than half filled the new heap, grow the heap
+    // for next time.
+
+    if ((vm->heap_next - vm->heap) > vm->heap_size >> 1) {
+        vm->heap_size += vm->heap_growth;
+    } 
+    vm->oldheap = oldheap;
+
+    // gcInfo(vm, 0);
+}
+
+void gcInfo(VM* vm, int doGC) {
+    printf("\nStack: %p %p\n", vm->valstack, vm->valstack_top); 
+    printf("Total allocations: %d\n", vm->allocations);
+    printf("GCs: %d\n", vm->collections);
+    printf("Final heap size %d\n", (int)(vm->heap_size));
+    printf("Final heap use %d\n", (int)(vm->heap_next - vm->heap));
+    if (doGC) { gc(vm); }
+    printf("Final heap use after GC %d\n", (int)(vm->heap_next - vm->heap));
+}
diff --git a/rts/idris_gc.h b/rts/idris_gc.h
new file mode 100644
--- /dev/null
+++ b/rts/idris_gc.h
@@ -0,0 +1,9 @@
+#ifndef _IDRISGC_H
+#define _IDRISGC_H
+
+#include "idris_rts.h"
+
+void gc(VM* vm);
+void gcInfo(VM* vm, int doGC);
+
+#endif
diff --git a/rts/idris_gmp.c b/rts/idris_gmp.c
new file mode 100644
--- /dev/null
+++ b/rts/idris_gmp.c
@@ -0,0 +1,242 @@
+#include "idris_rts.h"
+#include <gmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+VAL MKBIGI(int val) {
+    return MKINT((i_int)val);
+}
+
+VAL MKBIGC(VM* vm, char* val) {
+    mpz_t* bigint;
+    VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+    bigint = allocate(vm, sizeof(mpz_t));
+
+    mpz_init(*bigint);
+    mpz_set_str(*bigint, val, 10);
+
+    cl -> ty = BIGINT;
+    cl -> info.ptr = (void*)bigint;
+
+    return cl;
+}
+
+VAL MKBIGM(VM* vm, void* big) {
+    mpz_t* bigint;
+    VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+    bigint = allocate(vm, sizeof(mpz_t));
+
+    mpz_init(*bigint);
+    mpz_set(*bigint, *((mpz_t*)big));
+
+    cl -> ty = BIGINT;
+    cl -> info.ptr = (void*)bigint;
+
+    return cl;
+}
+
+VAL GETBIG(VM * vm, VAL x) {
+    if (ISINT(x)) {
+        mpz_t* bigint;
+        VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+        bigint = allocate(vm, sizeof(mpz_t));
+
+        mpz_init(*bigint);
+        mpz_set_si(*bigint, GETINT(x));
+
+        cl -> ty = BIGINT;
+        cl -> info.ptr = (void*)bigint;
+
+        return cl;
+    } else {
+        return x;
+    }
+}
+
+VAL bigAdd(VM* vm, VAL x, VAL y) {
+    mpz_t* bigint;
+    VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+    bigint = allocate(vm, sizeof(mpz_t));
+    mpz_add(*bigint, GETMPZ(x), GETMPZ(y));
+    cl -> ty = BIGINT;
+    cl -> info.ptr = (void*)bigint;
+    return cl;
+}
+
+VAL bigSub(VM* vm, VAL x, VAL y) {
+    mpz_t* bigint;
+    VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+    bigint = allocate(vm, sizeof(mpz_t));
+    mpz_sub(*bigint, GETMPZ(x), GETMPZ(y));
+    cl -> ty = BIGINT;
+    cl -> info.ptr = (void*)bigint;
+    return cl;
+}
+
+VAL bigMul(VM* vm, VAL x, VAL y) {
+    mpz_t* bigint;
+    VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+    bigint = allocate(vm, sizeof(mpz_t));
+    mpz_mul(*bigint, GETMPZ(x), GETMPZ(y));
+    cl -> ty = BIGINT;
+    cl -> info.ptr = (void*)bigint;
+    return cl;
+}
+
+VAL bigDiv(VM* vm, VAL x, VAL y) {
+    mpz_t* bigint;
+    VAL cl = allocate(vm, sizeof(ClosureType) + sizeof(void*));
+    bigint = allocate(vm, sizeof(mpz_t));
+    mpz_div(*bigint, GETMPZ(x), GETMPZ(y));
+    cl -> ty = BIGINT;
+    cl -> info.ptr = (void*)bigint;
+    return cl;
+}
+
+VAL idris_bigPlus(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        i_int vx = GETINT(x);
+        i_int vy = GETINT(y);
+        if ((vx <= 0 && vy >=0) || (vx >=0 && vy <=0)) {
+            return ADD(x, y);
+        }
+        i_int res = vx + vy;
+        if (res >= 1<<30 || res <= -(1 << 30)) {
+            return bigAdd(vm, GETBIG(vm, x), GETBIG(vm, y));
+        } else {
+            return MKINT(res);
+        }
+    } else {
+        return bigAdd(vm, GETBIG(vm, x), GETBIG(vm, y));
+    }
+}
+
+VAL idris_bigMinus(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        i_int vx = GETINT(x);
+        i_int vy = GETINT(y);
+        if ((vx <= 0 && vy <=0) || (vx >=0 && vy <=0)) {
+            return INTOP(-, x, y);
+        }
+        i_int res = vx - vy;
+        if (res >= 1<<30 || res <= -(1 << 30)) {
+            return bigSub(vm, GETBIG(vm, x), GETBIG(vm, y));
+        } else {
+            return MKINT(res);
+        }
+    } else {
+        return bigSub(vm, GETBIG(vm, x), GETBIG(vm, y));
+    }
+}
+
+VAL idris_bigTimes(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        i_int vx = GETINT(x);
+        i_int vy = GETINT(y);
+	// we could work out likelihood of overflow by checking the number
+	// of necessary bits. Here's a quick conservative hack instead.
+	if ((vx < (1<<15) && vy < (1<16)) ||
+	    (vx < (1<<16) && vy < (1<15)) ||
+	    (vx < (1<<20) && vy < (1<11)) ||
+	    (vx < (1<<11) && vy < (1<20)) ||
+	    (vx < (1<<23) && vy < (1<<8)) ||
+	    (vx < (1<<8) && vy < (1<<23))) { // ultra-conservative!
+	    return INTOP(*,x,y);
+        } else {
+            return bigMul(vm, GETBIG(vm, x), GETBIG(vm, y));
+        }
+    } else {
+        return bigMul(vm, GETBIG(vm, x), GETBIG(vm, y));
+    }
+}
+
+VAL idris_bigDivide(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        return INTOP(/, x, y);
+    } else {
+        return bigDiv(vm, GETBIG(vm, x), GETBIG(vm, y));
+    }
+}
+
+VAL bigEq(VM* vm, VAL x, VAL y) {
+    return MKINT((i_int)(mpz_cmp(GETMPZ(x), GETMPZ(y)) == 0));
+}
+
+VAL bigLt(VM* vm, VAL x, VAL y) {
+    return MKINT((i_int)(mpz_cmp(GETMPZ(x), GETMPZ(y)) < 0));
+}
+
+VAL bigGt(VM* vm, VAL x, VAL y) {
+    return MKINT((i_int)(mpz_cmp(GETMPZ(x), GETMPZ(y)) > 0));
+}
+
+VAL bigLe(VM* vm, VAL x, VAL y) {
+    return MKINT((i_int)(mpz_cmp(GETMPZ(x), GETMPZ(y)) <= 0));
+}
+
+VAL bigGe(VM* vm, VAL x, VAL y) {
+    return MKINT((i_int)(mpz_cmp(GETMPZ(x), GETMPZ(y)) >= 0));
+}
+
+VAL idris_bigEq(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        return MKINT((i_int)(GETINT(x) == GETINT(y)));
+    } else {
+        return bigEq(vm, x, y);
+    }
+}
+
+VAL idris_bigLt(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        return MKINT((i_int)(GETINT(x) < GETINT(y)));
+    } else {
+        return bigLt(vm, x, y);
+    }
+}
+
+VAL idris_bigLe(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        return MKINT((i_int)(GETINT(x) <= GETINT(y)));
+    } else {
+        return bigLe(vm, x, y);
+    }
+}
+
+VAL idris_bigGt(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        return MKINT((i_int)(GETINT(x) > GETINT(y)));
+    } else {
+        return bigGt(vm, x, y);
+    }
+}
+
+VAL idris_bigGe(VM* vm, VAL x, VAL y) {
+    if (ISINT(x) && ISINT(y)) {
+        return MKINT((i_int)(GETINT(x) >= GETINT(y)));
+    } else {
+        return bigGe(vm, x, y);
+    }
+}
+
+
+VAL idris_castIntBig(VM* vm, VAL i) {
+    return i;
+}
+
+VAL idris_castBigInt(VM* vm, VAL i) {
+    if (ISINT(i)) {
+        return i;
+    } else {
+        return MKINT((i_int)(mpz_get_ui(GETMPZ(i))));
+    }
+}
+
+VAL idris_castStrBig(VM* vm, VAL i) {
+    return MKBIGC(vm, GETSTR(i));
+}
+
+VAL idris_castBigStr(VM* vm, VAL i) {
+    char* str = mpz_get_str(NULL, 10, GETMPZ(GETBIG(vm, i)));
+    return MKSTR(vm, str);
+}
+
diff --git a/rts/idris_gmp.h b/rts/idris_gmp.h
new file mode 100644
--- /dev/null
+++ b/rts/idris_gmp.h
@@ -0,0 +1,26 @@
+#ifndef _IDRISGMP_H
+#define _IDRISGMP_H
+
+VAL MKBIGI(int val);
+VAL MKBIGC(VM* vm, char* bigint);
+VAL MKBIGM(VM* vm, void* bigint);
+
+VAL idris_bigPlus(VM*, VAL x, VAL y);
+VAL idris_bigMinus(VM*, VAL x, VAL y);
+VAL idris_bigTimes(VM*, VAL x, VAL y);
+VAL idris_bigDivide(VM*, VAL x, VAL y);
+
+VAL idris_bigEq(VM*, VAL x, VAL y);
+VAL idris_bigLt(VM*, VAL x, VAL y);
+VAL idris_bigLe(VM*, VAL x, VAL y);
+VAL idris_bigGt(VM*, VAL x, VAL y);
+VAL idris_bigGe(VM*, VAL x, VAL y);
+
+VAL idris_castIntBig(VM* vm, VAL i);
+VAL idris_castBigInt(VM* vm, VAL i);
+VAL idris_castStrBig(VM* vm, VAL i);
+VAL idris_castBigStr(VM* vm, VAL i);
+
+#define GETMPZ(x) *((mpz_t*)((x)->info.ptr))
+
+#endif
diff --git a/rts/idris_main.c b/rts/idris_main.c
new file mode 100644
--- /dev/null
+++ b/rts/idris_main.c
@@ -0,0 +1,8 @@
+int main(int argc, char* argv[]) {
+    VM* vm = init_vm(4096000, 2048000); // 1024000);
+    _idris__123_runMain0_125_(vm, NULL);
+    //_idris_main(vm, NULL);
+#ifdef IDRIS_TRACE
+    gcInfo(vm, 1);
+#endif
+}
diff --git a/rts/idris_rts.c b/rts/idris_rts.c
new file mode 100644
--- /dev/null
+++ b/rts/idris_rts.c
@@ -0,0 +1,313 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "idris_rts.h"
+#include "idris_gc.h"
+
+VM* init_vm(int stack_size, size_t heap_size) {
+    VAL* valstack = malloc(stack_size*sizeof(VAL));
+    int* intstack = malloc(stack_size*sizeof(int));
+    double* floatstack = malloc(stack_size*sizeof(double));
+
+    VM* vm = malloc(sizeof(VM));
+    vm -> valstack = valstack;
+    vm -> valstack_top = valstack;
+    vm -> valstack_base = valstack;
+    vm -> intstack = intstack;
+    vm -> intstack_ptr = intstack;
+    vm -> floatstack = floatstack;
+    vm -> floatstack_ptr = floatstack;
+    vm -> stack_max = valstack + stack_size;
+    vm -> heap = malloc(heap_size);
+    vm -> oldheap = NULL;
+    vm -> heap_next = vm -> heap;
+    vm -> heap_end = vm -> heap + heap_size;
+    vm -> heap_size = heap_size;
+    vm -> collections = 0;
+    vm -> allocations = 0;
+    vm -> heap_growth = heap_size;
+    vm -> ret = NULL;
+    vm -> reg1 = NULL;
+    return vm;
+}
+
+void* allocate(VM* vm, size_t size) {
+//    return malloc(size);
+    if ((size & 7)!=0) {
+	size = 8 + ((size >> 3) << 3);
+    }
+    vm->allocations += size + sizeof(size_t);
+    if (vm -> heap_next + size < vm -> heap_end) {
+        void* ptr = (void*)(vm->heap_next + sizeof(size_t));
+        *((size_t*)(vm->heap_next)) = size + sizeof(size_t);
+        vm -> heap_next += size + sizeof(size_t);
+        bzero(ptr, size);
+        return ptr;
+    } else {
+        gc(vm);
+        return allocate(vm, size);
+    }
+}
+
+void* allocCon(VM* vm, int arity) {
+    Closure* cl = allocate(vm, sizeof(Closure) + sizeof(VAL)*arity);
+    cl -> ty = CON;
+    if (arity == 0) {
+       cl -> info.c.args = NULL;
+    } else {
+       cl -> info.c.args = (void*)((char*)cl + sizeof(Closure));
+    }
+    cl -> info.c.arity = arity;
+//    cl -> info.c.tag = 42424242;
+//    printf("%p\n", cl);
+    return (void*)cl;
+}
+
+VAL MKFLOAT(VM* vm, double val) {
+    Closure* cl = allocate(vm, sizeof(Closure));
+    cl -> ty = FLOAT;
+    cl -> info.f = val;
+    return cl;
+}
+
+VAL MKSTR(VM* vm, char* str) {
+    Closure* cl = allocate(vm, sizeof(Closure) + // Type) + sizeof(char*) +
+                               sizeof(char)*strlen(str)+1);
+    cl -> ty = STRING;
+    cl -> info.str = (char*)cl + sizeof(Closure);
+
+    strcpy(cl -> info.str, str);
+    return cl;
+}
+
+VAL MKPTR(VM* vm, void* ptr) {
+    Closure* cl = allocate(vm, sizeof(Closure));
+    cl -> ty = PTR;
+    cl -> info.ptr = ptr;
+    return cl;
+}
+
+VAL MKCON(VM* vm, VAL cl, int tag, int arity, ...) {
+    int i;
+    va_list args;
+
+    va_start(args, arity);
+
+//    Closure* cl = allocCon(vm, arity);
+    cl -> info.c.tag = tag;
+    cl -> info.c.arity = arity;
+    VAL* argptr = (VAL*)(cl -> info.c.args);
+    // printf("... %p %p\n", cl, argptr);
+
+    for (i = 0; i < arity; ++i) {
+       VAL v = va_arg(args, VAL);
+       *argptr = v;
+       argptr++;
+    }
+    va_end(args);
+    return cl;
+}
+
+void PROJECT(VM* vm, VAL r, int loc, int arity) {
+    int i;
+    VAL* argptr = (VAL*)(r -> info.c.args);
+    
+    for(i = 0; i < arity; ++i) {
+        LOC(i+loc) = *argptr++;
+    }
+}
+
+void SLIDE(VM* vm, int args) {
+    int i;
+    for(i = 0; i < args; ++i) {
+        LOC(i) = TOP(i);
+    }
+}
+
+void dumpStack(VM* vm) {
+    int i = 0;
+    VAL* root;
+
+    for (root = vm->valstack; root < vm->valstack_top; ++root, ++i) {
+        printf("%d: ", i);
+        dumpVal(*root);
+        if (*root >= (VAL)(vm->heap) && *root < (VAL)(vm->heap_end)) { printf("OK"); }
+        printf("\n");
+    }
+    printf("RET: ");
+    dumpVal(vm->ret);
+    printf("\n");
+}
+
+void dumpVal(VAL v) {
+    if (v==NULL) return;
+    int i;
+    if (ISINT(v)) { 
+        printf("%d ", (int)(GETINT(v)));
+        return;
+    }
+    switch(v->ty) {
+    case CON:
+        printf("%d[", v->info.c.tag);
+        for(i = 0; i < v->info.c.arity; ++i) {
+            VAL* args = (VAL*)v->info.c.args;
+            dumpVal(args[i]);
+        }
+        printf("] ");
+        break;
+    case FWD:
+        printf("FWD ");
+        dumpVal((VAL)(v->info.ptr));
+        break;
+    default:
+        printf("val");
+    }
+
+}
+
+VAL idris_castIntStr(VM* vm, VAL i) {
+    Closure* cl = allocate(vm, sizeof(Closure) + sizeof(char)*16);
+    cl -> ty = STRING;
+    cl -> info.str = (char*)cl + sizeof(Closure);
+    sprintf(cl -> info.str, "%d", (int)(GETINT(i)));
+    return cl;
+}
+
+VAL idris_castStrInt(VM* vm, VAL i) {
+    char *end;
+    i_int v = strtol(GETSTR(i), &end, 10);
+    if (*end == '\0' || *end == '\n' || *end == '\r') 
+        return MKINT(v);
+    else 
+        return MKINT(0); 
+}
+
+VAL idris_castFloatStr(VM* vm, VAL i) {
+    Closure* cl = allocate(vm, sizeof(Closure) + sizeof(char)*32);
+    cl -> ty = STRING;
+    cl -> info.str = (char*)cl + sizeof(Closure);
+    sprintf(cl -> info.str, "%g", GETFLOAT(i));
+    return cl;
+}
+
+VAL idris_castStrFloat(VM* vm, VAL i) {
+    return MKFLOAT(vm, strtod(GETSTR(i), NULL));
+}
+
+VAL idris_concat(VM* vm, VAL l, VAL r) {
+    char *rs = GETSTR(r);
+    char *ls = GETSTR(l);
+    // dumpVal(l);
+    // printf("\n");
+    Closure* cl = allocate(vm, sizeof(Closure) + strlen(ls) + strlen(rs) + 1);
+    cl -> ty = STRING;
+    cl -> info.str = (char*)cl + sizeof(Closure);
+    strcpy(cl -> info.str, ls);
+    strcat(cl -> info.str, rs); 
+    return cl;
+}
+
+VAL idris_strlt(VM* vm, VAL l, VAL r) {
+    char *ls = GETSTR(l);
+    char *rs = GETSTR(r);
+
+    return MKINT((i_int)(strcmp(ls, rs) < 0));
+}
+
+VAL idris_streq(VM* vm, VAL l, VAL r) {
+    char *ls = GETSTR(l);
+    char *rs = GETSTR(r);
+
+    return MKINT((i_int)(strcmp(ls, rs) == 0));
+}
+
+VAL idris_strlen(VM* vm, VAL l) {
+    return MKINT((i_int)(strlen(GETSTR(l))));
+}
+
+#define BUFSIZE 256
+
+VAL idris_readStr(VM* vm, FILE* h) {
+// Modified from 'safe-fgets.c' in the gdb distribution.
+// (see http://www.gnu.org/software/gdb/current/)
+    char *line_ptr;
+    char* line_buf = (char *) malloc (BUFSIZE);
+    int line_buf_size = BUFSIZE;
+
+    /* points to last byte */
+    line_ptr = line_buf + line_buf_size - 1;
+
+    /* so we can see if fgets put a 0 there */
+    *line_ptr = 1;
+    if (fgets (line_buf, line_buf_size, h) == 0)
+        return MKSTR(vm, "");
+
+    /* we filled the buffer? */
+    while (line_ptr[0] == 0 && line_ptr[-1] != '\n')
+    {
+        /* Make the buffer bigger and read more of the line */
+        line_buf_size += BUFSIZE;
+        line_buf = (char *) realloc (line_buf, line_buf_size);
+
+        /* points to last byte again */
+        line_ptr = line_buf + line_buf_size - 1;
+        /* so we can see if fgets put a 0 there */
+        *line_ptr = 1;
+
+        if (fgets (line_buf + line_buf_size - BUFSIZE - 1, BUFSIZE + 1, h) == 0)
+           return MKSTR(vm, "");
+    }
+
+    VAL str = MKSTR(vm, line_buf);
+    free(line_buf);
+    return str;
+}
+
+VAL idris_strHead(VM* vm, VAL str) {
+    return MKINT((i_int)(GETSTR(str)[0]));
+}
+
+VAL idris_strTail(VM* vm, VAL str) {
+    return MKSTR(vm, GETSTR(str)+1);
+}
+
+VAL idris_strCons(VM* vm, VAL x, VAL xs) {
+    char *xstr = GETSTR(xs);
+    Closure* cl = allocate(vm, sizeof(Closure) +
+                               strlen(xstr) + 2);
+    cl -> ty = STRING;
+    cl -> info.str = (char*)cl + sizeof(Closure);
+    cl -> info.str[0] = (char)(GETINT(x));
+    strcpy(cl -> info.str+1, xstr);
+    return cl;
+}
+
+VAL idris_strIndex(VM* vm, VAL str, VAL i) {
+    return MKINT((i_int)(GETSTR(str)[GETINT(i)]));
+}
+
+VAL idris_strRev(VM* vm, VAL str) {
+    char *xstr = GETSTR(str);
+    Closure* cl = allocate(vm, sizeof(Closure) +
+                               strlen(xstr) + 1);
+    cl -> ty = STRING;
+    cl -> info.str = (char*)cl + sizeof(Closure);
+    int y = 0;
+    int x = strlen(xstr);
+
+    cl-> info.str[x+1] = '\0';
+    while(x>0) {
+        cl -> info.str[y++] = xstr[--x];
+    }
+    return cl;
+}
+
+
+void stackOverflow() {
+  fprintf(stderr, "Stack overflow");
+  exit(-1);
+}
+
diff --git a/rts/idris_rts.h b/rts/idris_rts.h
new file mode 100644
--- /dev/null
+++ b/rts/idris_rts.h
@@ -0,0 +1,155 @@
+#ifndef _IDRISRTS_H
+#define _IDRISRTS_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+// Closures
+
+typedef enum {
+    CON, INT, BIGINT, FLOAT, STRING, UNIT, PTR, FWD
+} ClosureType;
+
+typedef struct {
+    int tag;
+    int arity;
+    void* args;
+} con;
+
+typedef struct {
+    ClosureType ty;
+    union {
+        con c;
+        int i;
+        double f;
+        char* str;
+        void* ptr;
+    } info;
+} Closure;
+
+typedef Closure* VAL;
+
+typedef struct {
+    VAL* valstack;
+    int* intstack;
+    double* floatstack;
+    VAL* valstack_top;
+    VAL* valstack_base;
+    int* intstack_ptr;
+    double* floatstack_ptr;
+    char* heap;
+    char* oldheap;
+    char* heap_next;
+    char* heap_end;
+    VAL* stack_max;
+    size_t heap_size;
+    size_t heap_growth;
+    int allocations;
+    int collections;
+    VAL ret;
+    VAL reg1;
+} VM;
+
+VM* init_vm(int stack_size, size_t heap_size);
+
+// Functions all take a pointer to their VM, and previous stack base, 
+// and return nothing.
+typedef void(*func)(VM*, VAL*);
+
+// Register access 
+
+#define RVAL (vm->ret)
+#define LOC(x) (*(vm->valstack_base + (x)))
+#define TOP(x) (*(vm->valstack_top + (x)))
+#define REG1 (vm->reg1)
+
+// Retrieving values
+
+#define GETSTR(x) (((VAL)(x))->info.str) 
+#define GETPTR(x) (((VAL)(x))->info.ptr) 
+#define GETFLOAT(x) (((VAL)(x))->info.f)
+
+#define TAG(x) (ISINT(x) ? (-1) : ( (x)->ty == CON ? (x)->info.c.tag : (-1)) )
+
+// Integers, floats and operators
+
+typedef intptr_t i_int;
+
+#define MKINT(x) ((void*)((x)<<1)+1)
+#define GETINT(x) ((i_int)(x)>>1)
+#define ISINT(x) ((((i_int)x)&1) == 1)
+
+#define INTOP(op,x,y) MKINT((i_int)((((i_int)x)>>1) op (((i_int)y)>>1)))
+#define FLOATOP(op,x,y) MKFLOAT(((GETFLOAT(x)) op (GETFLOAT(y))))
+#define FLOATBOP(op,x,y) MKINT((i_int)(((GETFLOAT(x)) op (GETFLOAT(y)))))
+#define ADD(x,y) (void*)(((i_int)x)+(((i_int)y)-1))
+#define MULT(x,y) (MKINT((((i_int)x)>>1) * (((i_int)y)>>1)))
+
+// Stack management
+
+#define INITFRAME VAL* myoldbase
+#define REBASE vm->valstack_base = oldbase
+#define RESERVE(x) if (vm->valstack_top+(x) > vm->stack_max) { stackOverflow(); } \
+                   else { bzero(vm->valstack_top, (x)*sizeof(VAL)); }
+#define ADDTOP(x) vm->valstack_top += (x)
+#define TOPBASE(x) vm->valstack_top = vm->valstack_base + (x)
+#define BASETOP(x) vm->valstack_base = vm->valstack_top + (x)
+#define STOREOLD myoldbase = vm->valstack_base
+
+#define CALL(f) f(vm, myoldbase);
+#define TAILCALL(f) f(vm, oldbase);
+
+// Creating new values (each value placed at the top of the stack)
+VAL MKFLOAT(VM* vm, double val);
+VAL MKSTR(VM* vm, char* str);
+VAL MKPTR(VM* vm, void* ptr);
+
+VAL MKCON(VM* vm, VAL cl, int tag, int arity, ...);
+
+#define SETTAG(x, a) (x)->info.c.tag = (a)
+#define SETARG(x, i, a) ((VAL*)((x)->info.c.args))[i] = ((VAL)(a))
+
+void PROJECT(VM* vm, VAL r, int loc, int arity); 
+void SLIDE(VM* vm, int args);
+
+void* allocate(VM* vm, size_t size);
+void* allocCon(VM* vm, int arity);
+
+void dumpVal(VAL r);
+void dumpStack(VM* vm);
+
+// Casts
+
+#define idris_castIntFloat(x) MKFLOAT(vm, (double)(GETINT(x)))
+#define idris_castFloatInt(x) MKINT((i_int)(GETFLOAT(x)))
+
+VAL idris_castIntStr(VM* vm, VAL i);
+VAL idris_castStrInt(VM* vm, VAL i);
+VAL idris_castFloatStr(VM* vm, VAL i);
+VAL idris_castStrFloat(VM* vm, VAL i);
+
+// String primitives
+
+VAL idris_concat(VM* vm, VAL l, VAL r);
+VAL idris_strlt(VM* vm, VAL l, VAL r);
+VAL idris_streq(VM* vm, VAL l, VAL r);
+VAL idris_strlen(VM* vm, VAL l);
+VAL idris_readStr(VM* vm, FILE* h);
+
+VAL idris_strHead(VM* vm, VAL str);
+VAL idris_strTail(VM* vm, VAL str);
+VAL idris_strCons(VM* vm, VAL x, VAL xs);
+VAL idris_strIndex(VM* vm, VAL str, VAL i);
+VAL idris_strRev(VM* vm, VAL str);
+
+// Handle stack overflow. 
+// Just reports an error and exits.
+
+void stackOverflow();
+
+#include "idris_gmp.h"
+
+#endif 
diff --git a/rts/idris_stdfgn.c b/rts/idris_stdfgn.c
new file mode 100644
--- /dev/null
+++ b/rts/idris_stdfgn.c
@@ -0,0 +1,30 @@
+#include "idris_stdfgn.h"
+#include "idris_rts.h"
+
+void putStr(char* str) {
+    printf("%s", str);
+}
+
+void* fileOpen(char* name, char* mode) {
+    FILE* f = fopen(name, mode);
+    return (void*)f;
+}
+
+void fileClose(void* h) {
+    FILE* f = (FILE*)h;
+    fclose(f);
+}
+
+void fputStr(void* h, char* str) {
+    FILE* f = (FILE*)h;
+    fputs(str, f);
+}
+
+int isNull(void* ptr) {
+    return ptr==NULL;
+}
+
+void* idris_stdin() {
+    return (void*)stdin;
+}
+
diff --git a/rts/idris_stdfgn.h b/rts/idris_stdfgn.h
new file mode 100644
--- /dev/null
+++ b/rts/idris_stdfgn.h
@@ -0,0 +1,17 @@
+#ifndef _IDRISSTDFGN_H
+#define _IDRISSTDFGN_H
+
+// A collection of useful standard functions to be used by the prelude.
+
+void putStr(char* str);
+//char* readStr();
+
+void* fileOpen(char* f, char* mode);
+void fileClose(void* h);
+//char* freadStr(void* h);
+void fputStr(void*h, char* str);
+
+int isNull(void* ptr);
+void* idris_stdin();
+
+#endif
diff --git a/rts/libidris_rts.a b/rts/libidris_rts.a
new file mode 100644
Binary files /dev/null and b/rts/libidris_rts.a differ
diff --git a/src/Core/CaseTree.hs b/src/Core/CaseTree.hs
--- a/src/Core/CaseTree.hs
+++ b/src/Core/CaseTree.hs
@@ -11,10 +11,10 @@
 data CaseDef = CaseDef [Name] SC [Term]
     deriving Show
 
-data SC = Case Name [CaseAlt]
+data SC = Case Name [CaseAlt] -- invariant: lowest tags first
         | STerm Term
         | UnmatchedCase String -- error message
-    deriving Show
+    deriving (Show, Eq, Ord)
 {-! 
 deriving instance Binary SC 
 !-}
@@ -22,7 +22,7 @@
 data CaseAlt = ConCase Name Int [Name] SC
              | ConstCase Const         SC
              | DefaultCase             SC
-    deriving Show
+    deriving (Show, Eq, Ord)
 {-! 
 deriving instance Binary CaseAlt 
 !-}
@@ -53,19 +53,32 @@
     nut ps (Bind n b sc) = nut (n:ps) sc
     nut ps _ = []
 
-simpleCase :: Bool -> Bool -> [(Term, Term)] -> CaseDef
-simpleCase tc cover [] 
-                 = CaseDef [] (UnmatchedCase "No pattern clauses") []
-simpleCase tc cover cs 
-      = let pats       = map (\ (l, r) -> (toPats tc l, (l, r))) cs
-            numargs    = length (fst (head pats)) 
-            ns         = take numargs args
-            (tree, st) = runState (match ns pats (defaultCase cover)) ([], numargs) in
-            CaseDef ns (prune tree) (fst st)
+simpleCase :: Bool -> Bool -> FC -> [([Name], Term, Term)] -> TC CaseDef
+simpleCase tc cover fc [] 
+                 = return $ CaseDef [] (UnmatchedCase "No pattern clauses") []
+simpleCase tc cover fc cs 
+      = let pats       = map (\ (avs, l, r) -> (avs, toPats tc l, (l, r))) cs
+            chkPats    = mapM chkAccessible pats in
+            case chkPats of
+                OK pats ->
+                    let numargs    = length (fst (head pats)) 
+                        ns         = take numargs args
+                        (tree, st) = runState 
+                                         (match ns pats (defaultCase cover)) ([], numargs) in
+                        return $ CaseDef ns (prune tree) (fst st)
+                Error err -> Error (At fc err)
     where args = map (\i -> MN i "e") [0..]
           defaultCase True = STerm Erased
           defaultCase False = UnmatchedCase "Error"
 
+          chkAccessible (avs, l, c) = do mapM_ (acc l) avs
+                                         return (l, c)
+
+          acc [] n = Error (Inaccessible n) 
+          acc (PV x : xs) n | x == n = OK ()
+          acc (PCon _ _ ps : xs) n = acc (ps ++ xs) n
+          acc (_ : xs) n = acc xs n
+
 data Pat = PCon Name Int [Pat]
          | PConst Const
          | PV Name
@@ -154,7 +167,7 @@
 
 caseGroups :: [Name] -> [Group] -> SC -> State CS SC
 caseGroups (v:vs) gs err = do g <- altGroups gs
-                              return $ Case v g
+                              return $ Case v (sort g)
   where
     altGroups [] = return [DefaultCase err]
     altGroups (ConGroup (CName n i) args : cs)
diff --git a/src/Core/CoreParser.hs b/src/Core/CoreParser.hs
--- a/src/Core/CoreParser.hs
+++ b/src/Core/CoreParser.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
 
-module Core.CoreParser(parseTerm, parseFile, parseDef, pTerm, iName, idrisDef) where
+module Core.CoreParser(parseTerm, parseFile, parseDef, pTerm, iName, idrisDef,
+                       maybeWithNS) where
 
 import Core.TT
 
@@ -22,10 +23,10 @@
               reservedNames = ["let", "in", "data", "record", "Set", 
                                "do", "dsl", "import", "impossible", 
                                "case", "of", "total",
-                               "infix", "infixl", "infixr", "prefix",
-                               "where", "with", "forall", "syntax", "proof",
-                               "using", "params", "namespace", "class", "instance",
-                               "public", "private", "abstract",
+                               "infix", "infixl", "infixr", 
+                               "where", "with", "syntax", "proof", "postulate",
+                               "using", "namespace", "class", "instance",
+                               "public", "private", "abstract", 
                                "Int", "Integer", "Float", "Char", "String", "Ptr"]
            } 
 
@@ -60,15 +61,40 @@
                return p
 
 iName :: [String] -> CParser a Name
-iName bad = do x <- identifier
-               when (x `elem` bad) $ fail "Reserved identifier"
-               return $ mkNS (reverse (parseName x))
+iName bad = maybeWithNS identifier False bad
+
+-- Enhances a given parser to accept an optional namespace.  All possible
+-- namespace prefixes are tried in ascending / descending order, and
+-- identifiers of a given list fail.
+maybeWithNS :: CParser a String -> Bool -> [String] -> CParser a Name
+maybeWithNS parser ascend bad = do
+  i <- option "" (lookAhead identifier)
+  when (i `elem` bad) $ fail "Reserved identifier"
+  let transf = if ascend then id else reverse
+  (x, xs) <- choice $ transf (parserNoNS : parsersNS i)
+  return $ mkName (x, xs)
   where
-    mkNS [x] = UN x
-    mkNS (x:xs) = NS (UN x) xs 
-    parseName x = case span (/= '.') x of
-                       (x, "") -> [x]
-                       (x, '.':y) -> x : parseName y
+    parserNoNS = do x <- parser; return (x, "")
+    parserNS ns = do xs <- string ns; lchar '.'; x <- parser; return (x, xs)
+    parsersNS i = [try (parserNS ns) | ns <- (initsEndAt (=='.') i)]
+
+-- List of all initial segments in ascending order of a list.  Every such
+-- initial segment ends right before an element satisfying the given
+-- condition.
+initsEndAt :: (a -> Bool) -> [a] -> [[a]]
+initsEndAt p [] = []
+initsEndAt p (x:xs) | p x = [] : x_inits_xs
+                    | otherwise = x_inits_xs
+  where x_inits_xs = [x : cs | cs <- initsEndAt p xs]
+
+-- Create a `Name' from a pair of strings representing a base name and its
+-- namespace.
+mkName :: (String, String) -> Name
+mkName (n, "") = UN n 
+mkName (n, ns) = NS (UN n) (reverse (parseNS ns))
+  where parseNS x = case span (/= '.') x of
+                      (x, "")    -> [x]
+                      (x, '.':y) -> x : parseNS y
 
 pDef :: CParser a (Name, RDef)
 pDef = try (do x <- iName []; lchar ':'; ty <- pTerm
diff --git a/src/Core/Elaborate.hs b/src/Core/Elaborate.hs
--- a/src/Core/Elaborate.hs
+++ b/src/Core/Elaborate.hs
@@ -169,6 +169,10 @@
 elog str = do ES p logs prev <- get
               put (ES p (logs ++ str ++ "\n") prev)
 
+getLog :: Elab' aux String
+getLog = do ES p logs _ <- get
+            return logs
+
 -- The primitives, from ProofState
 
 attack :: Elab' aux ()
@@ -313,16 +317,24 @@
        -- HMMM: Actually, if we get it wrong, the typechecker will complain!
        -- so do nothing
        ptm <- get_term
-       let dontunify = [] -- map fst (filter (not.snd) (zip args (map fst imps)))
+       let dontunify = if null imps then [] -- do all we can 
+                          else
+                          map fst (filter (not.snd) (zip args (map fst imps)))
        ES (p, a) s prev <- get
-       let (n, hs) = unified p
-       let unify = (n, filter (\ (n, t) -> not (n `elem` dontunify)) hs)
-       put (ES (p { unified = unify }, a) s prev)
+       let (n, hs) = -- trace ("AVOID UNIFY: " ++ show (fn, dontunify)) $ 
+                      unified p
+       let unify = dropGiven dontunify hs
+       put (ES (p { unified = (n, unify) }, a) s prev)
        end_unify
-       return (map (updateUnify hs) args)
+       return (map (updateUnify unify) args)
   where updateUnify hs n = case lookup n hs of
                                 Just (P _ t _) -> t
                                 _ -> n
+        dropGiven du [] = []
+        dropGiven du ((n, P a t ty) : us) | n `elem` du && not (t `elem` du)
+                                   = (t, P a n ty) : dropGiven du us
+        dropGiven du (u@(n, _) : us) | n `elem` du = dropGiven du us
+        dropGiven du (u : us) = u : dropGiven du us
 
 apply2 :: Raw -> [Maybe (Elab' aux ())] -> Elab' aux () 
 apply2 fn elabs = 
@@ -402,6 +414,12 @@
            (do focus f; fun
                focus s; arg)
        complete_fill
+       hs <- get_holes
+       -- We don't need a and b in the hole queue any more since they were just for
+       -- checking f, so discard them if they are still there. If they haven't been solved,
+       -- regret will fail
+       when (a `elem` hs) $ do focus a; regret 
+       when (b `elem` hs) $ do focus b; regret 
        end_unify
 
 -- Abstract over an argument of unknown type, giving a name for the hole
@@ -429,8 +447,7 @@
 tryAll xs = tryAll' [] (cantResolve, 0) (map fst xs)
   where
     cantResolve :: Elab' aux a
-    cantResolve = fail $ "Couldn't resolve alternative: " 
-                                  ++ showSep ", " (map snd xs)
+    cantResolve = lift $ tfail $ CantResolveAlts (map snd xs) 
 
     tryAll' :: [Elab' aux a] -> -- successes
                (Elab' aux a, Int) -> -- smallest failure
diff --git a/src/Core/Evaluate.hs b/src/Core/Evaluate.hs
--- a/src/Core/Evaluate.hs
+++ b/src/Core/Evaluate.hs
@@ -7,7 +7,7 @@
                 Context, initContext, ctxtAlist, uconstraints, next_tvar,
                 addToCtxt, setAccess, setTotal, addCtxtDef, addTyDecl, addDatatype, 
                 addCasedef, addOperator,
-                lookupTy, lookupP, lookupDef, lookupVal, lookupTotal,
+                lookupNames, lookupTy, lookupP, lookupDef, lookupVal, lookupTotal,
                 lookupTyEnv, isConName, isFnName,
                 Value(..)) where
 
@@ -216,7 +216,8 @@
 --         | spec = specApply ntimes stk env f args 
     apply ntimes_in stk top env f@(VP Ref n ty)        args
       | (True, ntimes) <- usable n ntimes_in
-        = do let val = lookupDefAcc Nothing n atRepl ctxt
+        = -- trace (show n) $
+          do let val = lookupDefAcc Nothing n atRepl ctxt
              case val of
                 [(CaseOp inl _ _ ns tree _ _, Public)]  ->
                   if simpl && (not inl || elem n stk) 
@@ -558,7 +559,7 @@
 data Def = Function Type Term
          | TyDecl NameType Type 
          | Operator Type Int ([Value] -> Maybe Value)
-         | CaseOp Bool Type [(Term, Term)] -- Bool for inlineable
+         | CaseOp Bool Type [([Name], Term, Term)] -- Bool for inlineable
                   [Name] SC -- Compile time case definition
                   [Name] SC -- Run time cae definitions
 {-! 
@@ -673,14 +674,15 @@
               addCons (tag+1) cons (addDef n
                   (TyDecl (DCon tag (arity ty')) ty, Public, Unchecked) ctxt)
 
-addCasedef :: Name -> Bool -> Bool -> Bool -> [(Term, Term)] -> [(Term, Term)] ->
+addCasedef :: Name -> Bool -> Bool -> Bool -> 
+              [([Name], Term, Term)] -> [([Name], Term, Term)] ->
               Type -> Context -> Context
 addCasedef n alwaysInline tcase covering ps psrt ty uctxt 
     = let ctxt = definitions uctxt
           ps' = ps -- simpl ps in
-          ctxt' = case (simpleCase tcase covering ps', 
-                        simpleCase tcase covering psrt) of
-                    (CaseDef args sc _, CaseDef args' sc' _) -> 
+          ctxt' = case (simpleCase tcase covering (FC "" 0) ps', 
+                        simpleCase tcase covering (FC "" 0) psrt) of
+                    (OK (CaseDef args sc _), OK (CaseDef args' sc' _)) -> 
                                        let inl = alwaysInline in
                                            addDef n (CaseOp inl ty ps args sc args' sc',
                                                      Public, Unchecked) ctxt in
@@ -695,6 +697,11 @@
           uctxt { definitions = ctxt' }
 
 tfst (a, _, _) = a
+
+lookupNames :: Maybe [String] -> Name -> Context -> [Name]
+lookupNames root n ctxt
+                = let ns = lookupCtxtName root n (definitions ctxt) in
+                      map fst ns
 
 lookupTy :: Maybe [String] -> Name -> Context -> [Type]
 lookupTy root n ctxt 
diff --git a/src/Core/ProofState.hs b/src/Core/ProofState.hs
--- a/src/Core/ProofState.hs
+++ b/src/Core/ProofState.hs
@@ -294,9 +294,12 @@
 
     getP (n, b) = P Bound n (binderTy b)
 
--- Hmmm. YAGNI?
 regret :: RunTactic
-regret = undefined
+regret ctxt env (Bind x (Hole t) sc) | noOccurrence x sc =
+    do action (\ps -> let hs = holes ps in
+                          ps { holes = hs \\ [x] })
+       return sc
+regret ctxt env (Bind x (Hole t) _) = fail $ show x ++ " : " ++ show t ++ " is not solved"
 
 addInj :: [(Term, Term, Term)] -> StateT TState TC ()
 addInj inj = do ps <- get
@@ -315,6 +318,8 @@
 fill guess ctxt env (Bind x (Hole ty) sc) =
     do (val, valty) <- lift $ check ctxt env guess
        s <- get
+--        let valtyn = normalise ctxt env valty
+--        let tyn = normalise ctxt env ty
        ns <- unify' ctxt env valty ty
        ps <- get
        let (uh, uns) = unified ps
@@ -407,7 +412,8 @@
 rewrite :: Raw -> RunTactic
 rewrite tm ctxt env (Bind x (Hole t) xp@(P _ x' _)) | x == x' =
     do (tmv, tmt) <- lift $ check ctxt env tm
-       case unApply tmt of
+       let tmt' = normalise ctxt env tmt
+       case unApply tmt' of
          (P _ (UN "=") _, [lt,rt,l,r]) ->
             do let p = Bind rname (Lam lt) (mkP (P Bound rname lt) r l t)
                let newt = mkP l r l t 
diff --git a/src/Core/TT.hs b/src/Core/TT.hs
--- a/src/Core/TT.hs
+++ b/src/Core/TT.hs
@@ -43,42 +43,50 @@
     show (FC f l) = f ++ ":" ++ show l
 
 data Err = Msg String
-         | CantUnify Term Term Err Int -- Int is 'score' - how much we did unify
+         | InternalMsg String
+         | CantUnify Term Term Err [(Name, Type)] Int -- Int is 'score' - how much we did unify
          | NoSuchVariable Name
          | NotInjective Term Term Term
          | CantResolve Term
+         | CantResolveAlts [String]
          | IncompleteTerm Term
          | UniverseError
          | ProgramLineComment
+         | Inaccessible Name
          | At FC Err
   deriving Eq
 
 instance Sized Err where
   size (Msg msg) = length msg
-  size (CantUnify left right err score) = size left + size right + size err
+  size (InternalMsg msg) = length msg
+  size (CantUnify left right err _ score) = size left + size right + size err
   size (NoSuchVariable name) = size name
   size (NotInjective l c r) = size l + size c + size r
   size (CantResolve trm) = size trm
+  size (CantResolveAlts _) = 1
   size (IncompleteTerm trm) = size trm
   size UniverseError = 1
   size ProgramLineComment = 1
   size (At fc err) = size fc + size err
+  size (Inaccessible _) = 1
 
 score :: Err -> Int
-score (CantUnify _ _ m s) = s + score m
+score (CantUnify _ _ m _ s) = s + score m
 score (CantResolve _) = 20
 score (NoSuchVariable _) = 1000
 score _ = 0
 
 instance Show Err where
     show (Msg s) = s
-    show (CantUnify l r e i) = "CantUnify " ++ show l ++ " " ++ show r ++ " "
-                               ++ show e ++ " " ++ show i
+    show (InternalMsg s) = "Internal error: " ++ show s
+    show (CantUnify l r e sc i) = "CantUnify " ++ show l ++ " " ++ show r ++ " "
+                                  ++ show e ++ " in " ++ show sc ++ " " ++ show i
+    show (Inaccessible n) = show n ++ " is not an accessible pattern variable"
     show _ = "Error"
 
 instance Pretty Err where
   pretty (Msg m) = text m
-  pretty (CantUnify l r e i) =
+  pretty (CantUnify l r e _ i) =
     if size l + size r > breakingSize then
       text "Cannot unify" <+> colon $$
         nest nestingSize (pretty l <+> text "and" <+> pretty r) $$
@@ -112,7 +120,7 @@
     x >>= k = case x of 
                 OK v -> k v
                 Error e -> Error e
-    fail e = Error (Msg e)
+    fail e = Error (InternalMsg e)
 
 tfail :: Err -> TC a
 tfail e = Error e
@@ -230,8 +238,8 @@
 
 data Const = I Int | BI Integer | Fl Double | Ch Char | Str String 
            | IType | BIType     | FlType    | ChType  | StrType    
-           | PtrType | Forgot
-  deriving Eq
+           | PtrType | VoidType | Forgot
+  deriving (Eq, Ord)
 {-! 
 deriving instance Binary Const 
 !-}
@@ -251,6 +259,7 @@
   pretty ChType = text "Char"
   pretty StrType = text "String"
   pretty PtrType = text "Ptr"
+  pretty VoidType = text "Void"
   pretty Forgot = text "Forgot"
 
 data Raw = Var Name
@@ -288,7 +297,7 @@
                         binderVal :: b }
               | PVar  { binderTy  :: b }
               | PVTy  { binderTy  :: b }
-  deriving (Show, Eq, Functor)
+  deriving (Show, Eq, Ord, Functor)
 {-! 
 deriving instance Binary Binder 
 !-}
@@ -373,7 +382,7 @@
 type UCs = (Int, [UConstraint])
 
 data NameType = Bound | Ref | DCon Int Int | TCon Int Int
-  deriving (Show)
+  deriving (Show, Ord)
 {-! 
 deriving instance Binary NameType 
 !-}
@@ -398,7 +407,7 @@
           | Constant Const
           | Erased
           | Set UExp
-  deriving Functor
+  deriving (Ord, Functor)
 {-! 
 deriving instance Binary TT 
 !-}
@@ -599,6 +608,7 @@
     show ChType = "Char"
     show StrType = "String"
     show PtrType = "Ptr"
+    show VoidType = "Void"
 
 showEnv env t = showEnv' env t False
 showEnvDbg env t = showEnv' env t True
diff --git a/src/Core/Unify.hs b/src/Core/Unify.hs
--- a/src/Core/Unify.hs
+++ b/src/Core/Unify.hs
@@ -25,12 +25,16 @@
 unify :: Context -> Env -> TT Name -> TT Name -> TC ([(Name, TT Name)], 
                                                      Injs, Fails)
 unify ctxt env topx topy 
-    = case runStateT 
-             (un' False [] (normalise ctxt env topx) (normalise ctxt env topy))
-             (UI 0 [] []) of
-              OK (v, UI _ inj fails) -> return (filter notTrivial v, inj, reverse fails)
---               OK (_, UI s _ ((_,_,f):fs)) -> tfail $ CantUnify topx topy f s
-              Error e -> tfail e
+    = -- case runStateT (un' False [] topx topy) (UI 0 [] []) of
+      --    OK (v, UI _ inj []) -> return (filter notTrivial v, inj, [])
+      --    _ -> 
+               let topxn = normalise ctxt env topx
+	           topyn = normalise ctxt env topy in
+		     case runStateT (un' False [] topxn topyn)
+		  	        (UI 0 [] []) of
+	               OK (v, UI _ inj fails) -> return (filter notTrivial v, inj, reverse fails)
+--                     OK (_, UI s _ ((_,_,f):fs)) -> tfail $ CantUnify topx topy f s
+		       Error e -> tfail e
   where
     notTrivial (x, P _ x' _) = x /= x'
     notTrivial _ = True
@@ -76,18 +80,19 @@
     un' fn bnames (App fx ax) (App fy ay)    
         = do uplus -- do the second one if the first adds any errors 
                 (do hf <- un' True bnames fx fy 
-                    let ax' = normalise ctxt env (substNames hf ax)
-                    let ay' = normalise ctxt env (substNames hf ay)
+                    let ax' = hnormalise hf ctxt env (substNames hf ax)
+                    let ay' = hnormalise hf ctxt env (substNames hf ay)
                     ha <- un' False bnames ax' ay'
                     sc 1
                     combine bnames hf ha)
                 (do ha <- un' False bnames ax ay
-                    let fx' = normalise ctxt env (substNames ha fx)
-                    let fy' = normalise ctxt env (substNames ha fy)
+                    let fx' = hnormalise ha ctxt env (substNames ha fx)
+                    let fy' = hnormalise ha ctxt env (substNames ha fy)
                     hf <- un' False bnames fx' fy'
                     sc 1
                     combine bnames hf ha)
-
+      where hnormalise [] _ _ t = t
+            hnormalise ns ctxt env t = normalise ctxt env t
     un' fn bnames x (Bind n (Lam t) (App y (P Bound n' _)))
         | n == n' = un' False bnames x y
     un' fn bnames (Bind n (Lam t) (App x (P Bound n' _))) y
@@ -99,7 +104,7 @@
     un' fn bnames x y 
         | OK True <- convEq' ctxt x y = do sc 1; return []
         | otherwise = do UI s i f <- get
-                         let err = CantUnify topx topy (CantUnify x y (Msg "") s) s
+                         let err = CantUnify topx topy (CantUnify x y (Msg "") [] s) (errEnv env) s
                          put (UI s i ((x, y, env, err) : f))
                          return [] -- lift $ tfail err
 
@@ -119,8 +124,8 @@
     uB bnames (PVar tx) (PVar ty) = un' False bnames tx ty
     uB bnames x y = do UI s i f <- get
                        let err = CantUnify topx topy
-                                  (CantUnify (binderTy x) (binderTy y) (Msg "") s)
-                                  s
+                                  (CantUnify (binderTy x) (binderTy y) (Msg "") [] s)
+                                  (errEnv env) s
                        put (UI s i ((binderTy x, binderTy y, env, err) : f))
                        return [] -- lift $ tfail err
 
@@ -131,6 +136,8 @@
             Just t' -> do un' False bnames t t'
                           sc 1
                           combine bnames as bs
+
+errEnv = map (\(x, b) -> (x, binderTy b))
 
 holeIn :: Env -> Name -> Bool
 holeIn env n = case lookup n env of
diff --git a/src/IRTS/Bytecode.hs b/src/IRTS/Bytecode.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/Bytecode.hs
@@ -0,0 +1,109 @@
+module IRTS.Bytecode where
+
+import IRTS.Lang
+import IRTS.Simplified
+import Core.TT
+import Data.Maybe
+
+{- We have: 
+
+BASE: Current stack frame's base
+TOP:  Top of stack
+OLDBASE: Passed in to each function, the previous stack frame's base
+
+L i refers to the stack item at BASE + i
+T i refers to the stack item at TOP + i
+
+RVal is a register in which computed values (essentially, what a function
+returns) are stored.
+
+-}
+
+data Reg = RVal | L Int | T Int | Tmp
+   deriving (Show, Eq)
+
+data BC = ASSIGN Reg Reg
+        | ASSIGNCONST Reg Const
+        | MKCON Reg Int [Reg]
+        | CASE Reg [(Int, [BC])] (Maybe [BC])
+        | PROJECT Reg Int Int -- get all args from reg, put them from Int onwards
+        | CONSTCASE Reg [(Const, [BC])] (Maybe [BC])
+        | CALL Name
+        | TAILCALL Name
+        | FOREIGNCALL Reg FLang FType String [(FType, Reg)] 
+        | SLIDE Int -- move this number from TOP to BASE 
+        | REBASE -- set BASE = OLDBASE
+        | RESERVE Int -- reserve n more stack items 
+                      -- (i.e. check there's space, grow if necessary)
+        | ADDTOP Int -- move the top of stack up
+        | TOPBASE Int -- set TOP = BASE + n
+        | BASETOP Int -- set BASE = TOP + n
+        | STOREOLD -- set OLDBASE = BASE
+        | OP Reg PrimFn [Reg]
+        | ERROR String
+    deriving Show
+
+toBC :: (Name, SDecl) -> (Name, [BC])
+toBC (n, SFun n' args locs exp) 
+   = (n, reserve locs ++ bc RVal exp True)
+  where reserve 0 = []
+        reserve n = [RESERVE n, ADDTOP n]
+
+clean True  = [TOPBASE 0, REBASE]
+clean False = []
+
+bc :: Reg -> SExp -> Bool -> -- returning
+      [BC]
+bc reg (SV (Glob n)) r = bc reg (SApp False n []) r
+bc reg (SV (Loc i))  r = assign reg (L i) ++ clean r
+bc reg (SApp False f vs) r
+    = RESERVE (length vs) : moveReg 0 vs
+      ++ [STOREOLD, BASETOP 0, ADDTOP (length vs), CALL f] ++ 
+         assign reg RVal ++ clean r
+bc reg (SApp True f vs) r
+    = RESERVE (length vs) : moveReg 0 vs
+      ++ [SLIDE (length vs), TOPBASE (length vs), TAILCALL f]
+bc reg (SForeign l t fname args) r
+    = FOREIGNCALL reg l t fname (map farg args) : clean r
+  where farg (ty, Loc i) = (ty, L i)
+bc reg (SLet (Loc i) e sc) r = bc (L i) e False ++ bc reg sc r
+bc reg (SCon i _ vs) r = MKCON reg i (map getL vs) : clean r
+    where getL (Loc x) = L x
+bc reg (SConst i) r = ASSIGNCONST reg i : clean r
+bc reg (SOp p vs) r = OP reg p (map getL vs) : clean r
+    where getL (Loc x) = L x
+bc reg (SError str) r = [ERROR str]
+bc reg (SCase (Loc l) alts) r 
+   | isConst alts = constCase reg (L l) alts r
+   | otherwise = conCase reg (L l) alts r
+
+isConst [] = False
+isConst (SConstCase _ _ : xs) = True
+isConst (SConCase _ _ _ _ _ : xs) = False
+isConst (_ : xs) = False
+
+moveReg off [] = []
+moveReg off (Loc x : xs) = assign (T off) (L x) ++ moveReg (off + 1) xs
+
+assign r1 r2 | r1 == r2 = []
+             | otherwise = [ASSIGN r1 r2]
+
+conCase reg l xs r = [CASE l (mapMaybe (caseAlt l reg r) xs)
+                             (defaultAlt reg xs r)]
+
+constCase reg l xs r = [CONSTCASE l (mapMaybe (constAlt l reg r) xs)
+                               (defaultAlt reg xs r)]
+
+caseAlt l reg r (SConCase lvar tag _ args e) 
+    = Just (tag, PROJECT l lvar (length args) : bc reg e r) 
+caseAlt l reg r _ = Nothing
+
+constAlt l reg r (SConstCase c e) 
+    = Just (c, bc reg e r) 
+constAlt l reg r _ = Nothing
+
+defaultAlt reg [] r = Nothing
+defaultAlt reg (SDefaultCase e : _) r = Just (bc reg e r)
+defaultAlt reg (_ : xs) r = defaultAlt reg xs r
+
+
diff --git a/src/IRTS/CodegenC.hs b/src/IRTS/CodegenC.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/CodegenC.hs
@@ -0,0 +1,257 @@
+{-# LANGUAGE CPP #-}
+
+module IRTS.CodegenC where
+
+import IRTS.Bytecode
+import IRTS.Lang
+import IRTS.Simplified
+import Core.TT
+import Paths_idris
+
+import Data.Char
+import System.Process
+import System.Exit
+import System.IO
+import System.Directory
+import System.Environment
+import Control.Monad
+
+data DbgLevel = NONE | DEBUG | TRACE
+
+codegenC :: [(Name, SDecl)] ->
+            String -> -- output file name
+            Bool ->   -- generate executable if True, only .o if False 
+            [FilePath] -> -- include files
+            String -> -- extra compiler flags
+            DbgLevel ->
+            IO ()
+codegenC defs out exec incs libs dbg
+    = do -- print defs
+         let bc = map toBC defs
+         let h = concatMap toDecl (map fst bc)
+         let cc = concatMap (uncurry toC) bc
+         d <- getDataDir
+         mprog <- readFile (d ++ "/rts/idris_main.c")
+         let cout = headers incs ++ debug dbg ++ h ++ cc ++ 
+                     (if exec then mprog else "")
+         (tmpn, tmph) <- tempfile
+         hPutStr tmph cout
+         hFlush tmph
+         hClose tmph
+         let gcc = "gcc -x c " ++ 
+                     (if exec then "" else " - c ") ++
+                     gccDbg dbg ++
+                     " " ++ tmpn ++
+                     " `idris --link` `idris --include` " ++ libs ++
+                     " -lidris_rts -lgmp -o " ++ out
+         -- putStrLn cout
+         exit <- system gcc
+         when (exit /= ExitSuccess) $
+             putStrLn ("FAILURE: " ++ gcc)
+
+headers [] = "#include <idris_rts.h>\n#include <idris_stdfgn.h>\n#include<assert.h>\n"
+headers (x : xs) = "#include <" ++ x ++ ">\n" ++ headers xs
+
+debug TRACE = "#define IDRIS_TRACE\n\n"
+debug _ = ""
+
+gccDbg DEBUG = "-g"
+gccDbg TRACE = "-O2"
+gccDbg _ = "-O2"
+
+cname :: Name -> String
+cname n = "_idris_" ++ concatMap cchar (show n)
+  where cchar x | isAlpha x || isDigit x = [x]
+                | otherwise = "_" ++ show (fromEnum x) ++ "_"
+
+indent i = take (i * 4) (repeat ' ')
+
+creg RVal = "RVAL"
+creg (L i) = "LOC(" ++ show i ++ ")"
+creg (T i) = "TOP(" ++ show i ++ ")"
+creg Tmp = "REG1"
+
+toDecl :: Name -> String
+toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n" 
+
+toC :: Name -> [BC] -> String
+toC f code 
+    = -- "/* " ++ show code ++ "*/\n\n" ++ 
+      "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n" ++
+                 indent 1 ++ "INITFRAME;\n" ++ 
+                 concatMap (bcc 1) code ++ "}\n\n"
+
+bcc :: Int -> BC -> String
+bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
+bcc i (ASSIGNCONST l c) 
+    = indent i ++ creg l ++ " = " ++ mkConst c ++ ";\n"
+  where
+    mkConst (I i) = "MKINT(" ++ show i ++ ")"
+    mkConst (BI i) | i < (2^30) = "MKINT(" ++ show i ++ ")"
+                   | otherwise = "MKBIGC(vm,\"" ++ show i ++ "\")"
+    mkConst (Fl f) = "MKFLOAT(vm, " ++ show f ++ ")"
+    mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
+    mkConst (Str s) = "MKSTR(vm, " ++ show s ++ ")"
+    mkConst _ = "MKINT(42424242)"
+bcc i (MKCON l tag args)
+    = indent i ++ creg Tmp ++ " = allocCon(vm, " ++ show (length args) ++ 
+         "); " ++ "SETTAG(" ++ creg Tmp ++ ", " ++ show tag ++ ");\n" ++
+      indent i ++ setArgs 0 args ++ "\n" ++ 
+      indent i ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
+         
+--         "MKCON(vm, " ++ creg l ++ ", " ++ show tag ++ ", " ++
+--         show (length args) ++ concatMap showArg args ++ ");\n"
+  where showArg r = ", " ++ creg r
+        setArgs i [] = ""
+        setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
+                             "); " ++ setArgs (i + 1) xs
+
+bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++ 
+                                      ", " ++ show a ++ ");\n"
+bcc i (CASE r code def) 
+    = indent i ++ "switch(TAG(" ++ creg r ++ ")) {\n" ++
+      concatMap (showCase i) code ++
+      showDef i def ++
+      indent i ++ "}\n"
+  where
+    showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
+                         ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
+    showDef i Nothing = ""
+    showDef i (Just c) = indent i ++ "default:\n" 
+                         ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
+bcc i (CONSTCASE r code def) 
+    = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
+      concatMap (showCase i) code ++
+      showDef i def ++
+      indent i ++ "}\n"
+  where
+    showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
+                         ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
+    showDef i Nothing = ""
+    showDef i (Just c) = indent i ++ "default:\n" 
+                         ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
+bcc i (CALL n) = indent i ++ "CALL(" ++ cname n ++ ");\n"
+bcc i (TAILCALL n) = indent i ++ "TAILCALL(" ++ cname n ++ ");\n"
+bcc i (SLIDE n) = indent i ++ "SLIDE(vm, " ++ show n ++ ");\n"
+bcc i REBASE = indent i ++ "REBASE;\n"
+bcc i (RESERVE n) = indent i ++ "RESERVE(" ++ show n ++ ");\n"
+bcc i (ADDTOP n) = indent i ++ "ADDTOP(" ++ show n ++ ");\n"
+bcc i (TOPBASE n) = indent i ++ "TOPBASE(" ++ show n ++ ");\n"
+bcc i (BASETOP n) = indent i ++ "BASETOP(" ++ show n ++ ");\n"
+bcc i STOREOLD = indent i ++ "STOREOLD;\n"
+bcc i (OP l fn args) = indent i ++ doOp (creg l ++ " = ") fn args ++ ";\n"
+bcc i (FOREIGNCALL l LANG_C rty fn args)
+      = indent i ++ 
+        c_irts rty (creg l ++ " = ") 
+                   (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
+    where fcall (t, arg) = irts_c t (creg arg)
+bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); assert(0); exit(-1);"
+-- bcc i _ = indent i ++ "// not done yet\n"
+
+c_irts FInt l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
+c_irts FChar l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
+c_irts FString l x = l ++ "MKSTR(" ++ x ++ ")"
+c_irts FUnit l x = x
+c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
+c_irts FDouble l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
+c_irts FAny l x = l ++ x
+
+irts_c FInt x = "GETINT(" ++ x ++ ")"
+irts_c FChar x = "GETINT(" ++ x ++ ")"
+irts_c FString x = "GETSTR(" ++ x ++ ")"
+irts_c FUnit x = x
+irts_c FPtr x = "GETPTR(" ++ x ++ ")"
+irts_c FDouble x = "GETFLOAT(" ++ x ++ ")"
+irts_c FAny x = x
+
+doOp v LPlus [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LMinus [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LTimes [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LDiv [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LEq [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LLt [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LLe [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LGt [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LGe [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
+
+doOp v LFPlus [l, r] = v ++ "FLOATOP(+" ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFMinus [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFTimes [l, r] = v ++ "FLOATOP(*" ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFDiv [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFEq [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFLt [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFLe [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFGt [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LFGe [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
+
+doOp v LBPlus [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBMinus [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBTimes [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBDiv [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBEq [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBLt [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBLe [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBGt [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LBGe [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+
+doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
+doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
+
+doOp v LIntFloat [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
+doOp v LFloatInt [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
+doOp v LIntStr [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
+doOp v LStrInt [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
+doOp v LIntBig [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
+doOp v LBigInt [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
+doOp v LStrBig [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
+doOp v LBigStr [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
+doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
+doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
+
+doOp v LReadStr [x] = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
+doOp _ LPrintNum [x] = "printf(\"%ld\\n\", GETINT(" ++ creg x ++ "))"
+doOp _ LPrintStr [x] = "fputs(GETSTR(" ++ creg x ++ "), stdout)"
+
+doOp v LFExp [x] = v ++ "MKFLOAT(exp(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFLog [x] = v ++ "MKFLOAT(log(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFSin [x] = v ++ "MKFLOAT(sin(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFCos [x] = v ++ "MKFLOAT(cos(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFTan [x] = v ++ "MKFLOAT(tan(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFASin [x] = v ++ "MKFLOAT(asin(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFACos [x] = v ++ "MKFLOAT(acos(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFATan [x] = v ++ "MKFLOAT(atan(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFSqrt [x] = v ++ "MKFLOAT(floor(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFFloor [x] = v ++ "MKFLOAT(ceil(GETFLOAT(" ++ creg x ++ ")))"
+doOp v LFCeil [x] = v ++ "MKFLOAT(sqrt(GETFLOAT(" ++ creg x ++ ")))"
+
+doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
+doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
+doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
+doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
+doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
+
+doOp v LStdIn [] = v ++ "MKPTR(vm, stdin)"
+doOp v LStdOut [] = v ++ "MKPTR(vm, stdout)"
+doOp v LStdErr [] = v ++ "MKPTR(vm, stderr)"
+
+doOp v LNoOp [x] = ""
+doOp _ _ _ = "FAIL"
+
+tempfile :: IO (FilePath, Handle)
+tempfile = do env <- environment "TMPDIR"
+              let dir = case env of
+                              Nothing -> "/tmp"
+                              (Just d) -> d
+              openTempFile dir "idris"
+
+environment :: String -> IO (Maybe String)
+environment x = catch (do e <- getEnv x
+                          return (Just e))
+#if MIN_VERSION_base(4,6,0)
+                          (\y-> do return (y::SomeException);  return Nothing)  
+#endif
+#if !MIN_VERSION_base(4,6,0)
+                          (\_->  return Nothing)  
+#endif  
diff --git a/src/IRTS/Compiler.hs b/src/IRTS/Compiler.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/Compiler.hs
@@ -0,0 +1,210 @@
+{-# LANGUAGE PatternGuards #-}
+
+module IRTS.Compiler where
+
+import IRTS.Lang
+import IRTS.Defunctionalise
+import IRTS.Simplified
+import IRTS.CodegenC
+
+import Idris.AbsSyntax
+import Core.TT
+import Core.Evaluate
+import Core.CaseTree
+
+import Control.Monad.State
+import Data.List
+import System.Process
+import System.IO
+import System.Directory
+import System.Environment
+
+import Paths_idris
+
+compileC :: FilePath -> Term -> Idris ()
+compileC f tm = do checkMVs
+                   let tmnames = namesUsed (STerm tm)
+                   used <- mapM (allNames []) tmnames
+                   defsIn <- mkDecls tm (concat used)
+                   maindef <- irMain tm
+                   let defs = defsIn ++ [(MN 0 "runMain", maindef)]
+                   -- iputStrLn $ showSep "\n" (map show defs)
+                   let (nexttag, tagged) = addTags 0 (liftAll defs)
+                   let ctxtIn = addAlist tagged emptyContext
+                   let defuns = defunctionalise nexttag ctxtIn
+                   -- iputStrLn $ showSep "\n" (map show (toAlist defuns))
+                   let checked = checkDefs defuns (toAlist defuns)
+                   case checked of
+                        OK c -> do -- iputStrLn $ showSep "\n" (map show c)
+                                   liftIO $ codegenC c f True [] "" NONE
+                        Error e -> fail $ show e 
+  where checkMVs = do i <- get
+                      case idris_metavars i \\ primDefs of
+                            [] -> return ()
+                            ms -> fail $ "There are undefined metavariables: " ++ show ms
+        inDir d h = do let f = d ++ "/" ++ h
+                       ex <- doesFileExist f
+                       if ex then return f else return h
+
+irMain :: TT Name -> Idris LDecl
+irMain tm = do i <- ir tm
+               return $ LFun (MN 0 "runMain") [] (LForce i)
+
+allNames :: [Name] -> Name -> Idris [Name]
+allNames ns n | n `elem` ns = return []
+allNames ns n = do i <- get
+                   case lookupCtxt Nothing n (idris_callgraph i) of
+                      [ns'] -> do more <- mapM (allNames (n:ns)) ns' 
+                                  return (nub (n : concat more))
+                      _ -> return [n]
+
+mkDecls :: Term -> [Name] -> Idris [(Name, LDecl)]
+mkDecls t used 
+    = do i <- getIState
+         let ds = filter (\ (n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
+         decls <- mapM build ds
+         return decls
+
+isCon (TyDecl _ _) = True
+isCon _ = False
+
+class ToIR a where
+    ir :: a -> Idris LExp
+
+build :: (Name, Def) -> Idris (Name, LDecl)
+build (n, d)
+    = do i <- getIState
+         case lookup n (idris_scprims i) of
+              Just (ar, op) -> 
+                  let args = map (\x -> MN x "op") [0..] in
+                      return (n, (LFun n (take ar args) 
+                                         (LOp op (map (LV . Glob) (take ar args)))))
+              _ -> do def <- mkLDecl n d
+                      logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
+                      return (n, def)
+
+declArgs args n (LLam xs x) = declArgs (args ++ xs) n x
+declArgs args n x = LFun n args x 
+
+mkLDecl n (Function tm _) = do e <- ir tm
+                               return (declArgs [] n e)
+mkLDecl n (CaseOp _ _ pats _ _ args sc) = do e <- ir (args, sc)
+                                             return (declArgs [] n e)
+mkLDecl n (TyDecl (DCon t a) _) = return $ LConstructor n (-1) a
+mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
+mkLDecl n _ = return (LFun n [] (LError ("Impossible declaration " ++ show n)))
+
+instance ToIR (TT Name) where 
+    ir tm = ir' [] tm where
+      ir' env tm@(App f a)
+          | (P _ (UN "mkForeign") _, args) <- unApply tm
+              = doForeign args
+          | (P _ (UN "unsafePerformIO") _, [_, arg]) <- unApply tm
+              = ir' env arg
+          | (P _ (UN "lazy") _, [_, arg]) <- unApply tm
+              = do arg' <- ir' env arg
+                   return $ LLazyExp arg'
+          | (P _ (UN "prim__IO") _, [v]) <- unApply tm
+              = do v' <- ir' env v
+                   return v'
+          | (P _ (UN "io_bind") _, [_,_,v,k]) <- unApply tm
+              = do v' <- ir' env v 
+                   k' <- ir' env k
+                   return (LApp False k' [LForce v'])
+          | (P _ (UN "malloc") _, [_,size,t]) <- unApply tm
+              = do size' <- ir' env size
+                   t' <- ir' env t
+                   return t' -- TODO $ malloc_ size' t'
+          | (P _ (UN "trace_malloc") _, [_,t]) <- unApply tm
+              = do t' <- ir' env t
+                   return t' -- TODO
+          | (P (DCon t a) n _, args) <- unApply tm
+              = irCon env t a n args
+          | (f, args) <- unApply tm
+              = do f' <- ir' env f
+                   args' <- mapM (ir' env) args
+                   return (LApp False f' args')
+      ir' env (P _ n _) = return $ LV (Glob n)
+      ir' env (V i)     = return $ LV (Glob (env!!i))
+      ir' env (Bind n (Lam _) sc)
+          = do sc' <- ir' (n : env) sc
+               return $ LLam [n] sc'
+      ir' env (Bind n (Let _ v) sc)
+          = do sc' <- ir' (n : env) sc
+               v' <- ir' env v
+               return $ LLet n v' sc'
+      ir' env (Bind _ _ _) = return $ LConst (I 424242)
+      ir' env (Constant c) = return $ LConst c
+      ir' env _ = return $ LError "Impossible"
+
+      irCon env t arity n args
+        | length args == arity = buildApp env (LV (Glob n)) args
+        | otherwise = let extra = satArgs (arity - length args) in
+                          do sc' <- irCon env t arity n 
+                                        (args ++ map (\n -> P Bound n undefined) extra)
+                             return $ LLam extra sc'
+        
+      satArgs n = map (\i -> MN i "sat") [1..n]
+
+      buildApp env e [] = return e
+      buildApp env e xs = do xs' <- mapM (ir' env) xs
+                             return $ LApp False e xs'
+
+doForeign :: [TT Name] -> Idris LExp
+doForeign (_ : fgn : args)
+   | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
+        = let tys = getFTypes fgnArgTys
+              rty = mkIty' ret in
+              do args' <- mapM ir args
+                 -- wrap it in a prim__IO
+                 -- return $ con_ 0 @@ impossible @@ 
+                 return $ LLazyExp $ LForeign LANG_C rty fgnName (zip tys args')
+   | otherwise = fail "Badly formed foreign function call"
+
+getFTypes :: TT Name -> [FType]
+getFTypes tm = case unApply tm of
+                 (nil, []) -> []
+                 (cons, [ty, xs]) -> 
+                    let rest = getFTypes xs in
+                        mkIty' ty : rest
+
+mkIty' (P _ (UN ty) _) = mkIty ty
+mkIty' _ = FAny
+
+mkIty "FInt"    = FInt
+mkIty "FFloat"  = FDouble
+mkIty "FChar"   = FChar
+mkIty "FString" = FString
+mkIty "FPtr"    = FPtr
+mkIty "FUnit"   = FUnit
+
+instance ToIR ([Name], SC) where
+    ir (args, tree) = do logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
+                         tree' <- ir tree
+                         return $ LLam args tree'
+
+instance ToIR SC where
+    ir (STerm t) = ir t
+    ir (UnmatchedCase str) = return $ LError str
+    ir (Case n alts) = do alts' <- mapM mkIRAlt alts
+                          return $ LCase (LV (Glob n)) alts'
+      where
+        mkIRAlt (ConCase n t args rhs) 
+             = do rhs' <- ir rhs
+                  return $ LConCase (-1) n args rhs'
+        mkIRAlt (ConstCase (I i) rhs)  
+             = do rhs' <- ir rhs
+                  return $ LConstCase (I i) rhs'
+        mkIRAlt (ConstCase IType rhs) 
+             = do rhs' <- ir rhs 
+                  return $ LDefaultCase rhs'
+        mkIRAlt (ConstCase c rhs)      
+           = fail $ "Can only pattern match on integer constants (" ++ show c ++ ")"
+        mkIRAlt (DefaultCase rhs)
+           = do rhs' <- ir rhs
+                return $ LDefaultCase rhs'
+
+
+
+
+
diff --git a/src/IRTS/Defunctionalise.hs b/src/IRTS/Defunctionalise.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/Defunctionalise.hs
@@ -0,0 +1,142 @@
+module IRTS.Defunctionalise where
+
+import IRTS.Lang
+import Core.TT
+
+import Debug.Trace
+import Data.Maybe
+import Data.List
+
+defunctionalise :: Int -> LDefs -> LDefs 
+defunctionalise nexttag defs 
+     = let all = toAlist defs
+           -- sort newcons so that EVAL and APPLY cons get sequential tags
+           newcons = sortBy conord $ concatMap toCons (getFn all)
+           eval = mkEval newcons
+           app = mkApply newcons
+           condecls = declare nexttag newcons in
+           addAlist (eval : app : condecls ++ (map (addApps defs) all)) emptyContext
+   where conord (n, _, _) (n', _, _) = compare n n'
+
+getFn :: [(Name, LDecl)] -> [(Name, Int)]
+getFn xs = mapMaybe fnData xs
+  where fnData (n, LFun _ args _) = Just (n, length args) 
+        fnData _ = Nothing
+
+-- To defunctionalise:
+--
+-- 1 Create a data constructor for each function
+-- 2 Create a data constructor for each underapplication of a function
+-- 3 Convert underapplications to their corresponding constructors
+-- 4 Create an EVAL function which calls the appropriate function for data constructors
+--   created as part of step 1
+-- 5 Create an APPLY function which adds an argument to each underapplication (or calls
+--   APPLY again for an exact application)
+-- 6 Wrap overapplications in chains of APPLY
+-- 7 Wrap unknown applications (i.e. applications of local variables) in chains of APPLY
+-- 8 Add explicit EVAL to case, primitives, and foreign calls
+
+addApps :: LDefs -> (Name, LDecl) -> (Name, LDecl)
+addApps defs o@(n, LConstructor _ _ _) = o
+addApps defs (n, LFun _ args e) = (n, LFun n args (aa args e))
+  where
+    aa env (LV (Glob n)) | n `elem` env = LV (Glob n)
+                         | otherwise = aa env (LApp False (LV (Glob n)) [])
+--     aa env e@(LApp tc (MN 0 "EVAL") [a]) = e
+    aa env (LApp tc (LV (Glob n)) args)
+       = let args' = map (aa env) args in
+             case lookupCtxt Nothing n defs of
+                [LConstructor _ i ar] -> LApp tc (LV (Glob n)) args'
+                [LFun _ as _] -> let arity = length as in
+                                     fixApply tc n args' arity
+                [] -> chainAPPLY (LV (Glob n)) args'
+    aa env (LLazyApp n args)
+       = let args' = map (aa env) args in
+             case lookupCtxt Nothing n defs of
+                [LConstructor _ i ar] -> LApp False (LV (Glob n)) args'
+                [LFun _ as _] -> let arity = length as in
+                                     fixLazyApply n args' arity
+                [] -> chainAPPLY (LV (Glob n)) args'
+    aa env (LForce e) = eEVAL (aa env e)
+    aa env (LLet n v sc) = LLet n (aa env v) (aa (n : env) sc)
+    aa env (LCon i n args) = LCon i n (map (aa env) args)
+    aa env (LCase e alts) = LCase (eEVAL (aa env e)) (map (aaAlt env) alts)
+    aa env (LConst c) = LConst c
+    aa env (LForeign l t n args) = LForeign l t n (map (aaF env) args)
+    aa env (LOp f args) = LOp f (map (eEVAL . (aa env)) args)
+    aa env (LError e) = LError e
+
+    aaF env (t, e) = (t, eEVAL (aa env e))
+
+    aaAlt env (LConCase i n args e) = LConCase i n args (aa (args ++ env) e)
+    aaAlt env (LConstCase c e) = LConstCase c (aa env e)
+    aaAlt env (LDefaultCase e) = LDefaultCase (aa env e)
+
+    fixApply tc n args ar 
+        | length args == ar = LApp tc (LV (Glob n)) args
+        | length args < ar = LApp tc (LV (Glob (mkUnderCon n (ar - length args)))) args
+        | length args > ar = chainAPPLY (LApp tc (LV (Glob n)) (take ar args)) (drop ar args)
+
+    fixLazyApply n args ar 
+        | length args == ar = LApp False (LV (Glob (mkFnCon n))) args
+        | length args < ar = LApp False (LV (Glob (mkUnderCon n (ar - length args)))) args
+        | length args > ar = chainAPPLY (LApp False (LV (Glob n)) (take ar args)) (drop ar args)
+                                    
+    chainAPPLY f [] = f
+    chainAPPLY f (a : as) = chainAPPLY (LApp False (LV (Glob (MN 0 "APPLY"))) [f, a]) as
+
+eEVAL x = LApp False (LV (Glob (MN 0 "EVAL"))) [x]
+
+data EvalApply a = EvalCase a
+                 | ApplyCase a
+    deriving Show
+
+-- For a function name, generate a list of
+-- data constuctors, and whether to handle them in EVAL or APPLY
+
+toCons :: (Name, Int) -> [(Name, Int, EvalApply LAlt)]
+toCons (n, i) 
+   = (mkFnCon n, i, 
+        EvalCase (LConCase (-1) (mkFnCon n) (take i (genArgs 0))
+                 (eEVAL (LApp False (LV (Glob n)) (map (LV . Glob) (take i (genArgs 0)))))))
+        : mkApplyCase n 0 i
+
+mkApplyCase fname n ar | n == ar = []
+mkApplyCase fname n ar 
+        = let nm = mkUnderCon fname (ar - n) in
+              (nm, n, ApplyCase (LConCase (-1) nm (take n (genArgs 0))
+                              (LApp False (LV (Glob (mkUnderCon fname (ar - (n + 1))))) 
+                                          (map (LV . Glob) (take n (genArgs 0) ++ 
+                                                                   [MN 0 "arg"])))))
+                            : mkApplyCase fname (n + 1) ar
+
+mkEval :: [(Name, Int, EvalApply LAlt)] -> (Name, LDecl)
+mkEval xs = (MN 0 "EVAL", LFun (MN 0 "EVAL") [MN 0 "arg"]
+                             (LCase (LV (Glob (MN 0 "arg")))
+                                 (mapMaybe evalCase xs ++
+                                   [LDefaultCase (LV (Glob (MN 0 "arg")))])))
+  where
+    evalCase (n, t, EvalCase x) = Just x
+    evalCase _ = Nothing
+
+mkApply :: [(Name, Int, EvalApply LAlt)] -> (Name, LDecl)
+mkApply xs = (MN 0 "APPLY", LFun (MN 0 "APPLY") [MN 0 "fn", MN 0 "arg"]
+                             (LCase (LApp False (LV (Glob (MN 0 "EVAL"))) 
+                                            [LV (Glob (MN 0 "fn"))])
+                                 (mapMaybe applyCase xs)))
+  where
+    applyCase (n, t, ApplyCase x) = Just x
+    applyCase _ = Nothing
+
+declare :: Int -> [(Name, Int, EvalApply LAlt)] -> [(Name, LDecl)]
+declare t xs = dec' t xs [] where
+   dec' t [] acc = reverse acc
+   dec' t ((n, ar, _) : xs) acc = dec' (t + 1) xs ((n, LConstructor n t ar) : acc)
+
+
+genArgs i = MN i "P_c" : genArgs (i + 1)
+
+mkFnCon    n = MN 0 ("P_" ++ show n)
+mkUnderCon n 0       = n
+mkUnderCon n missing = MN missing ("U_" ++ show n)
+
diff --git a/src/IRTS/LParser.hs b/src/IRTS/LParser.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/LParser.hs
@@ -0,0 +1,257 @@
+module IRTS.LParser where
+
+import Core.CoreParser
+import Core.TT
+import IRTS.Lang
+import IRTS.Simplified
+import IRTS.Bytecode
+import IRTS.CodegenC
+import IRTS.Defunctionalise
+import Paths_idris
+
+import Text.ParserCombinators.Parsec
+import Text.ParserCombinators.Parsec.Error
+import Text.ParserCombinators.Parsec.Expr
+import Text.ParserCombinators.Parsec.Language
+import qualified Text.ParserCombinators.Parsec.Token as PTok
+
+import Data.List
+import Control.Monad.State
+import Debug.Trace
+import Data.Maybe
+import System.FilePath
+
+type TokenParser a = PTok.TokenParser a
+
+type LParser = GenParser Char ()
+
+lexer :: TokenParser ()
+lexer  = PTok.makeTokenParser idrisDef
+
+whiteSpace= PTok.whiteSpace lexer
+lexeme    = PTok.lexeme lexer
+symbol    = PTok.symbol lexer
+natural   = PTok.natural lexer
+parens    = PTok.parens lexer
+semi      = PTok.semi lexer
+comma     = PTok.comma lexer
+identifier= PTok.identifier lexer
+reserved  = PTok.reserved lexer
+operator  = PTok.operator lexer
+reservedOp= PTok.reservedOp lexer
+integer   = PTok.integer lexer
+float     = PTok.float lexer
+strlit    = PTok.stringLiteral lexer
+chlit     = PTok.charLiteral lexer
+lchar = lexeme.char
+
+fovm :: FilePath -> IO ()
+fovm f = do defs <- parseFOVM f
+            let (nexttag, tagged) = addTags 0 (liftAll defs)
+            let ctxtIn = addAlist tagged emptyContext
+            let defuns = defunctionalise nexttag ctxtIn
+            putStrLn $ showSep "\n" (map show (toAlist defuns))
+            let checked = checkDefs defuns (toAlist defuns)
+--            print checked
+            case checked of
+                 OK c -> codegenC c "a.out" True ["math.h"] "" TRACE
+                 Error e -> fail $ show e 
+
+parseFOVM :: FilePath -> IO [(Name, LDecl)]
+parseFOVM fname = do -- putStrLn $ "Reading " ++ fname
+                     fp <- readFile fname
+                     case runParser pProgram () fname fp of
+                        Left err-> fail (show err)
+                        Right x -> return x
+
+pProgram :: LParser [(Name, LDecl)]
+pProgram = do fs <- many1 pLDecl
+              eof
+              return fs 
+
+pLDecl :: LParser (Name, LDecl)
+pLDecl = do reserved "data"
+            n <- iName []
+            ar <- natural
+            return (n, LConstructor n (-1) (fromInteger ar))
+     <|> do reserved "fun"
+            n <- iName []
+            lchar '('
+            args <- sepBy (iName []) (lchar ',')
+            lchar ')'
+            lchar '='
+            def <- pLExp
+            return (n, LFun n args def)
+
+pLExp = buildExpressionParser optable pLExp' 
+
+optable = [[binary "*" (\x y -> LOp LTimes [x,y]) AssocLeft,
+            binary "/" (\x y -> LOp LDiv [x,y]) AssocLeft,
+            binary "*." (\x y -> LOp LFTimes [x,y]) AssocLeft,
+            binary "/." (\x y -> LOp LFDiv [x,y]) AssocLeft,
+            binary "*:" (\x y -> LOp LBTimes [x,y]) AssocLeft,
+            binary "/:" (\x y -> LOp LBDiv [x,y]) AssocLeft
+            ],
+           [
+            binary "+" (\x y -> LOp LPlus [x,y]) AssocLeft,
+            binary "-" (\x y -> LOp LMinus [x,y]) AssocLeft,
+            binary "++" (\x y -> LOp LStrConcat [x,y]) AssocLeft,
+            binary "+." (\x y -> LOp LFPlus [x,y]) AssocLeft,
+            binary "-." (\x y -> LOp LFMinus [x,y]) AssocLeft,
+            binary "+:" (\x y -> LOp LBPlus [x,y]) AssocLeft,
+            binary "-:" (\x y -> LOp LBMinus [x,y]) AssocLeft
+            ],
+           [
+            binary "==" (\x y -> LOp LEq [x, y]) AssocNone,
+            binary "==." (\x y -> LOp LFEq [x, y]) AssocNone,
+            binary "<" (\x y -> LOp LLt [x, y]) AssocNone,
+            binary "<." (\x y -> LOp LFLt [x, y]) AssocNone,
+            binary ">" (\x y -> LOp LGt [x, y]) AssocNone,
+            binary ">." (\x y -> LOp LFGt [x, y]) AssocNone,
+            binary "<=" (\x y -> LOp LLe [x, y]) AssocNone,
+            binary "<=." (\x y -> LOp LFLe [x, y]) AssocNone,
+            binary ">=" (\x y -> LOp LGe [x, y]) AssocNone,
+            binary ">=." (\x y -> LOp LFGe [x, y]) AssocNone,
+
+            binary "==:" (\x y -> LOp LBEq [x, y]) AssocNone,
+            binary "<:" (\x y -> LOp LBLt [x, y]) AssocNone,
+            binary ">:" (\x y -> LOp LBGt [x, y]) AssocNone,
+            binary "<=:" (\x y -> LOp LBLe [x, y]) AssocNone,
+            binary ">=:" (\x y -> LOp LBGe [x, y]) AssocNone
+          ]]
+
+binary name f assoc = Infix (do reservedOp name; return f) assoc
+
+pLExp' :: LParser LExp
+pLExp' = try (do lchar '%'; pCast)
+     <|> try (do lchar '%'; pPrim)
+     <|> try (do tc <- option False (do lchar '%'; reserved "tc"; return True)
+                 x <- iName [];
+                 lazy <- option False (do lchar '@'; return True)
+                 lchar '('
+                 args <- sepBy pLExp (lchar ',')
+                 lchar ')'
+                 if null args 
+                    then if lazy then return (LLazyApp x [])
+                                 else return (LV (Glob x)) 
+                    else if lazy then return (LLazyApp x args)
+                                 else return (LApp tc (LV (Glob x)) args))
+     <|> do lchar '('; e <- pLExp; lchar ')'; return e
+     <|> pLConst
+     <|> do reserved "let"; x <- iName []; lchar '='; v <- pLExp
+            reserved "in"; e <- pLExp
+            return (LLet x v e)
+     <|> do lchar '\\'; xs <- sepBy (iName []) (lchar ',')
+            symbol "=>"
+            e <- pLExp
+            return (LLam xs e)
+     <|> do reserved "foreign"; l <- pLang; t <- pType
+            fname <- strlit
+            lchar '('
+            fargs <- sepBy (do t' <- pType; e <- pLExp; return (t', e)) (lchar ',')
+            lchar ')'
+            return (LForeign l t fname fargs)
+     <|> pCase
+     <|> do x <- iName []
+            return (LV (Glob x))
+     
+pLang = do reserved "C"; return LANG_C
+
+pType = do reserved "Int"; return FInt
+    <|> do reserved "Float"; return FDouble
+    <|> do reserved "String"; return FString
+    <|> do reserved "Unit"; return FUnit
+    <|> do reserved "Ptr"; return FPtr
+    <|> do reserved "Any"; return FAny
+
+pCase :: LParser LExp
+pCase = do reserved "case"; e <- pLExp; reserved "of"
+           lchar '{'
+           alts <- sepBy1 pAlt (lchar '|')
+           lchar '}'
+           return (LCase e alts)
+
+pCast :: LParser LExp
+pCast = do reserved "FloatString"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LFloatStr [e])
+    <|> do reserved "StringFloat"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LStrFloat [e])
+    <|> do reserved "FloatInt"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LFloatInt [e])
+    <|> do reserved "IntFloat"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LIntFloat [e])
+    <|> do reserved "StringInt"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LStrInt [e])
+    <|> do reserved "IntString"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LIntStr [e])
+    <|> do reserved "BigInt"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LBigInt [e])
+    <|> do reserved "IntBig"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LIntBig [e])
+    <|> do reserved "BigString"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LBigStr [e])
+    <|> do reserved "StringBig"; lchar '('; e <- pLExp; lchar ')'
+           return (LOp LStrBig [e])
+
+pPrim :: LParser LExp
+pPrim = do reserved "StrEq"; lchar '(';
+           e <- pLExp; lchar ',';
+           e' <- pLExp; lchar ')'; 
+           return (LOp LStrEq [e, e'])
+    <|> do reserved "StrLt"; lchar '('
+           e <- pLExp; lchar ','; e' <- pLExp; 
+           lchar ')'
+           return (LOp LStrLt [e, e'])
+    <|> do reserved "StrLen"; lchar '('; e <- pLExp; lchar ')';
+           return (LOp LStrLen [e])
+    <|> do reserved "ReadString"; lchar '('; e <- pLExp; lchar ')';
+           return (LOp LReadStr [e])
+    <|> do reserved "WriteString"; lchar '(';
+           e <- pLExp; lchar ')'
+           return (LOp LPrintStr [e])
+    <|> do reserved "WriteInt"; lchar '('; 
+           e <- pLExp; lchar ')';
+           return (LOp LPrintNum [e])
+    <|> do reserved "lazy"; lchar '(';
+           e <- pLExp; lchar ')';
+           return (LLazyExp e)
+    <|> do reserved "StrHead"; lchar '('; e <- pLExp; lchar ')';
+           return (LOp LStrHead [e])
+    <|> do reserved "StrTail"; lchar '('; e <- pLExp; lchar ')';
+           return (LOp LStrTail [e])
+    <|> do reserved "StrRev"; lchar '('; e <- pLExp; lchar ')';
+           return (LOp LStrRev [e])
+    <|> do reserved "StrCons"; lchar '('; x <- pLExp; lchar ','; 
+           xs <- pLExp; lchar ')';
+           return (LOp LStrCons [x, xs])
+    <|> do reserved "StrIndex"; lchar '('; x <- pLExp; lchar ','; 
+           i <- pLExp; lchar ')';
+           return (LOp LStrIndex [x, i])
+
+pAlt :: LParser LAlt
+pAlt = try (do x <- iName []
+               lchar '('; args <- sepBy1 (iName []) (lchar ','); lchar ')'
+               symbol "=>"
+               rhs <- pLExp
+               return (LConCase (-1) x args rhs))
+    <|> do x <- iName [];
+           symbol "=>"
+           rhs <- pLExp
+           return (LConCase (-1) x [] rhs)
+    <|> do c <- natural
+           symbol "=>"
+           rhs <- pLExp
+           return (LConstCase (I (fromInteger c)) rhs)
+    <|> do symbol "_"
+           symbol "=>"
+           rhs <- pLExp
+           return (LDefaultCase rhs)
+
+
+pLConst :: LParser LExp
+pLConst = try (do f <- float; return $ LConst (Fl f))
+      <|> try (do i <- natural; lchar ':'; return $ LConst (BI i))     
+      <|> try (do i <- natural; return $ LConst (I (fromInteger i)))     
+      <|> try (do s <- strlit; return $ LConst (Str s))
+      <|> try (do c <- chlit; return $ LConst (Ch c))
+
diff --git a/src/IRTS/Lang.hs b/src/IRTS/Lang.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/Lang.hs
@@ -0,0 +1,193 @@
+module IRTS.Lang where
+
+import Core.TT
+import Control.Monad.State hiding(lift)
+import Data.List
+import Debug.Trace
+
+data LVar = Loc Int | Glob Name
+  deriving (Show, Eq)
+
+data LExp = LV LVar
+          | LApp Bool LExp [LExp] -- True = tail call
+          | LLazyApp Name [LExp] -- True = tail call
+          | LLazyExp LExp
+          | LForce LExp -- make sure Exp is evaluted
+          | LLet Name LExp LExp -- name just for pretty printing
+          | LLam [Name] LExp -- lambda, lifted out before compiling
+          | LCon Int Name [LExp]
+          | LCase LExp [LAlt]
+          | LConst Const
+          | LForeign FLang FType String [(FType, LExp)]
+          | LOp PrimFn [LExp]
+          | LError String
+  deriving Eq
+
+data PrimFn = LPlus | LMinus | LTimes | LDiv | LEq | LLt | LLe | LGt | LGe
+            | LFPlus | LFMinus | LFTimes | LFDiv | LFEq | LFLt | LFLe | LFGt | LFGe
+            | LBPlus | LBMinus | LBTimes | LBDiv | LBEq | LBLt | LBLe | LBGt | LBGe
+            | LStrConcat | LStrLt | LStrEq | LStrLen
+            | LIntFloat | LFloatInt | LIntStr | LStrInt | LFloatStr | LStrFloat
+            | LIntBig | LBigInt | LStrBig | LBigStr
+            | LPrintNum | LPrintStr | LReadStr
+
+            | LFExp | LFLog | LFSin | LFCos | LFTan | LFASin | LFACos | LFATan
+            | LFSqrt | LFFloor | LFCeil
+
+            | LStrHead | LStrTail | LStrCons | LStrIndex | LStrRev
+            | LStdIn | LStdOut | LStdErr
+            | LNoOp
+  deriving (Show, Eq)
+
+-- Supported target languages for foreign calls
+
+data FLang = LANG_C
+  deriving (Show, Eq)
+
+data FType = FInt | FChar | FString | FUnit | FPtr | FDouble | FAny
+  deriving (Show, Eq)
+
+data LAlt = LConCase Int Name [Name] LExp
+          | LConstCase Const LExp
+          | LDefaultCase LExp
+  deriving (Show, Eq)
+
+data LDecl = LFun Name [Name] LExp -- name, arg names, definition
+           | LConstructor Name Int Int -- constructor name, tag, arity
+  deriving (Show, Eq)
+
+type LDefs = Ctxt LDecl
+
+addTags :: Int -> [(Name, LDecl)] -> (Int, [(Name, LDecl)])
+addTags i ds = tag i ds []
+  where tag i ((n, LConstructor n' t a) : as) acc
+            = tag (i + 1) as ((n, LConstructor n' i a) : acc) 
+        tag i (x : as) acc = tag i as (x : acc)
+        tag i [] acc  = (i, reverse acc)
+
+data LiftState = LS Name Int [(Name, LDecl)]
+
+lname (NS n x) i = NS (lname n i) x
+lname (UN n) i = MN i n
+lname x i = MN i (show x)
+
+liftAll :: [(Name, LDecl)] -> [(Name, LDecl)]
+liftAll xs = concatMap (\ (x, d) -> lambdaLift x d) xs
+
+lambdaLift :: Name -> LDecl -> [(Name, LDecl)]
+lambdaLift n (LFun _ args e) 
+      = let (e', (LS _ _ decls)) = runState (lift args e) (LS n 0 []) in
+            (n, LFun n args e') : decls
+lambdaLift n x = [(n, x)]
+
+getNextName :: State LiftState Name
+getNextName = do LS n i ds <- get
+                 put (LS n (i + 1) ds)
+                 return (lname n i)
+
+addFn :: Name -> LDecl -> State LiftState ()
+addFn fn d = do LS n i ds <- get
+                put (LS n i ((fn, d) : ds))
+
+lift :: [Name] -> LExp -> State LiftState LExp
+lift env (LV v) = return (LV v) -- Lifting happens before these can exist...
+lift env (LApp tc (LV (Glob n)) args) = do args' <- mapM (lift env) args
+                                           return (LApp tc (LV (Glob n)) args')
+lift env (LApp tc f args) = do f' <- lift env f
+                               fn <- getNextName
+                               addFn fn (LFun fn env f')
+                               args' <- mapM (lift env) args
+                               return (LApp tc (LV (Glob fn)) (map (LV . Glob) env ++ args'))
+lift env (LLazyApp n args) = do args' <- mapM (lift env) args
+                                return (LLazyApp n args')
+lift env (LLazyExp (LConst c)) = return (LConst c)
+lift env (LLazyExp e) = do e' <- lift env e
+                           let usedArgs = nub $ usedIn env e'
+                           fn <- getNextName
+                           addFn fn (LFun fn usedArgs e')
+                           return (LLazyApp fn (map (LV . Glob) usedArgs))
+lift env (LForce e) = do e' <- lift env e
+                         return (LForce e') 
+lift env (LLet n v e) = do v' <- lift env v
+                           e' <- lift (env ++ [n]) e
+                           return (LLet n v' e')
+lift env (LLam args e) = do e' <- lift (env ++ args) e
+                            let usedArgs = nub $ usedIn env e'
+                            fn <- getNextName
+                            addFn fn (LFun fn (usedArgs ++ args) e')
+                            return (LApp False (LV (Glob fn)) (map (LV . Glob) usedArgs))
+lift env (LCon i n args) = do args' <- mapM (lift env) args
+                              return (LCon i n args')
+lift env (LCase e alts) = do alts' <- mapM liftA alts
+                             e' <- lift env e
+                             return (LCase e' alts')
+  where
+    liftA (LConCase i n args e) = do e' <- lift (env ++ args) e
+                                     return (LConCase i n args e')
+    liftA (LConstCase c e) = do e' <- lift env e
+                                return (LConstCase c e')
+    liftA (LDefaultCase e) = do e' <- lift env e
+                                return (LDefaultCase e')
+lift env (LConst c) = return (LConst c)
+lift env (LForeign l t s args) = do args' <- mapM (liftF env) args
+                                    return (LForeign l t s args')
+  where
+    liftF env (t, e) = do e' <- lift env e
+                          return (t, e')
+lift env (LOp f args) = do args' <- mapM (lift env) args
+                           return (LOp f args')
+lift env (LError str) = return $ LError str
+
+
+-- Return variables in list which are used in the expression
+
+usedArg env n | n `elem` env = [n]
+              | otherwise = []
+
+usedIn :: [Name] -> LExp -> [Name]
+usedIn env (LV (Glob n)) = usedArg env n 
+usedIn env (LApp _ e args) = usedIn env e ++ concatMap (usedIn env) args 
+usedIn env (LLazyApp n args) = concatMap (usedIn env) args ++ usedArg env n
+usedIn env (LLazyExp e) = usedIn env e
+usedIn env (LForce e) = usedIn env e
+usedIn env (LLet n v e) = usedIn env v ++ usedIn (env \\ [n]) e
+usedIn env (LLam ns e) = usedIn (env \\ ns) e
+usedIn env (LCon i n args) = concatMap (usedIn env) args
+usedIn env (LCase e alts) = concatMap (usedInA env) alts
+  where usedInA env (LConCase i n ns e) = usedIn env e
+        usedInA env (LConstCase c e) = usedIn env e
+        usedInA env (LDefaultCase e) = usedIn env e
+usedIn env (LForeign _ _ _ args) = concatMap (usedIn env) (map snd args)
+usedIn env (LOp f args) = concatMap (usedIn env) args
+usedIn env _ = []
+
+instance Show LExp where
+   show e = show' [] e where
+     show' env (LV (Loc i)) = env!!i
+     show' env (LV (Glob n)) = show n
+     show' env (LApp _ e args) = show' env e ++ "(" ++
+                                   showSep ", " (map (show' env) args) ++")"
+     show' env (LLazyExp e) = "%lazy(" ++ show' env e ++ ")" 
+     show' env (LForce e) = "%force(" ++ show' env e ++ ")"
+     show' env (LLet n v e) = "let " ++ show n ++ " = " ++ show' env v ++ " in " ++
+                               show' (env ++ [show n]) e
+     show' env (LLam args e) = "\\ " ++ showSep "," (map show args) ++ " => " ++
+                                 show' (env ++ (map show args)) e
+     show' env (LCon i n args) = show n ++ ")" ++ showSep ", " (map (show' env) args) ++ ")"
+     show' env (LCase e alts) = "case " ++ show' env e ++ " of {\n\t" ++
+                                    showSep "\n\t| " (map (showAlt env) alts)
+     show' env (LConst c) = show c
+     show' env (LForeign lang ty n args)
+           = "foreign " ++ n ++ "(" ++ showSep ", " (map (show' env) (map snd args)) ++ ")"
+     show' env (LOp f args) = show f ++ "(" ++ showSep ", " (map (show' env) args) ++ ")"
+     show' env (LError str) = "error " ++ show str
+
+     showAlt env (LConCase _ n args e) 
+          = show n ++ "(" ++ showSep ", " (map show args) ++ ") => "
+             ++ show' env e
+     showAlt env (LConstCase c e) = show c ++ " => " ++ show' env e
+     showAlt env (LDefaultCase e) = "_ => " ++ show' env e
+
+
+
+
diff --git a/src/IRTS/Simplified.hs b/src/IRTS/Simplified.hs
new file mode 100644
--- /dev/null
+++ b/src/IRTS/Simplified.hs
@@ -0,0 +1,190 @@
+module IRTS.Simplified where
+
+import IRTS.Lang
+import Core.TT
+import Data.Maybe
+import Control.Monad.State
+
+-- Simplified expressions, where functions/constructors can only be applied 
+-- to variables
+
+data SExp = SV LVar
+          | SApp Bool Name [LVar]
+          | SLet LVar SExp SExp
+          | SCon Int Name [LVar]
+          | SCase LVar [SAlt]
+          | SConst Const
+          | SForeign FLang FType String [(FType, LVar)]
+          | SOp PrimFn [LVar]
+          | SError String
+  deriving Show
+
+data SAlt = SConCase Int Int Name [Name] SExp
+          | SConstCase Const SExp
+          | SDefaultCase SExp
+  deriving Show
+
+data SDecl = SFun Name [Name] Int SExp
+  deriving Show
+
+hvar :: State (LDefs, Int) Int
+hvar = do (l, h) <- get
+          put (l, h + 1)
+          return h
+
+ldefs :: State (LDefs, Int) LDefs
+ldefs = do (l, h) <- get
+           return l
+
+simplify :: Bool -> LExp -> State (LDefs, Int) SExp
+simplify tl (LV (Loc i)) = return (SV (Loc i))
+simplify tl (LV (Glob x)) 
+    = do ctxt <- ldefs
+         case lookupCtxt Nothing x ctxt of
+              [LConstructor _ t 0] -> return $ SCon t x []
+              _ -> return $ SV (Glob x)
+simplify tl (LApp tc (LV (Glob n)) args) 
+                             = do args' <- mapM sVar args
+                                  mkapp (SApp (tl || tc) n) args'
+simplify tl (LForeign lang ty fn args) 
+                            = do args' <- mapM sVar (map snd args)
+                                 let fargs = zip (map fst args) args'
+                                 mkfapp (SForeign lang ty fn) fargs
+simplify tl (LLet n v e) = do v' <- simplify False v
+                              e' <- simplify tl e
+                              return (SLet (Glob n) v' e')
+simplify tl (LCon i n args) = do args' <- mapM sVar args
+                                 mkapp (SCon i n) args'
+simplify tl (LCase e alts) = do v <- sVar e
+                                alts' <- mapM (sAlt tl) alts
+                                case v of 
+                                    (x, Nothing) -> return (SCase x alts')
+                                    (Glob x, Just e) -> 
+                                        return (SLet (Glob x) e (SCase (Glob x) alts'))
+simplify tl (LConst c) = return (SConst c)
+simplify tl (LOp p args) = do args' <- mapM sVar args
+                              mkapp (SOp p) args'
+simplify tl (LError str) = return $ SError str
+
+sVar (LV (Glob x))
+    = do ctxt <- ldefs
+         case lookupCtxt Nothing x ctxt of
+              [LConstructor _ t 0] -> sVar (LCon t x [])
+              _ -> return (Glob x, Nothing)
+sVar (LV x) = return (x, Nothing)
+sVar e = do e' <- simplify False e
+            i <- hvar
+            return (Glob (MN i "R"), Just e')
+
+mkapp f args = mkapp' f args [] where
+   mkapp' f [] args = return $ f (reverse args)
+   mkapp' f ((x, Nothing) : xs) args = mkapp' f xs (x : args)
+   mkapp' f ((x, Just e) : xs) args 
+       = do sc <- mkapp' f xs (x : args)
+            return (SLet x e sc)
+
+mkfapp f args = mkapp' f args [] where
+   mkapp' f [] args = return $ f (reverse args)
+   mkapp' f ((ty, (x, Nothing)) : xs) args = mkapp' f xs ((ty, x) : args)
+   mkapp' f ((ty, (x, Just e)) : xs) args 
+       = do sc <- mkapp' f xs ((ty, x) : args)
+            return (SLet x e sc)
+
+sAlt tl (LConCase i n args e) = do e' <- simplify tl e
+                                   return (SConCase (-1) i n args e')
+sAlt tl (LConstCase c e) = do e' <- simplify tl e
+                              return (SConstCase c e')
+sAlt tl (LDefaultCase e) = do e' <- simplify tl e
+                              return (SDefaultCase e')
+
+checkDefs :: LDefs -> [(Name, LDecl)] -> TC [(Name, SDecl)]
+checkDefs ctxt [] = return []
+checkDefs ctxt (con@(n, LConstructor _ _ _) : xs) 
+    = do xs' <- checkDefs ctxt xs
+         return xs'
+checkDefs ctxt ((n, LFun n' args exp) : xs) 
+    = do let sexp = evalState (simplify True exp) (ctxt, 0)
+         (exp', locs) <- runStateT (scopecheck ctxt (zip args [0..]) sexp) (length args)
+         xs' <- checkDefs ctxt xs
+         return ((n, SFun n' args ((locs + 1) - length args) exp') : xs')
+
+lvar v = do i <- get
+            put (max i v)
+
+scopecheck :: LDefs -> [(Name, Int)] -> SExp -> StateT Int TC SExp 
+scopecheck ctxt env tm = sc env tm where
+    sc env (SV (Glob n)) =
+       case lookup n (reverse env) of -- most recent first
+              Just i -> do lvar i; return (SV (Loc i))
+              Nothing -> case lookupCtxt Nothing n ctxt of
+                              [LConstructor _ i ar] ->
+                                  if True -- ar == 0 
+                                     then return (SCon i n [])
+                                     else fail $ "Codegen error: Constructor " ++ show n ++
+                                                 " has arity " ++ show ar
+                              [_] -> return (SV (Glob n))
+                              [] -> fail $ "Codegen error: No such variable " ++ show n
+    sc env (SApp tc f args)
+       = do args' <- mapM (scVar env) args
+            case lookupCtxt Nothing f ctxt of
+                [LConstructor n tag ar] ->
+                    if True -- (ar == length args)
+                       then return $ SCon tag n args'
+                       else fail $ "Codegen error: Constructor " ++ show f ++ 
+                                   " has arity " ++ show ar
+                [_] -> return $ SApp tc f args'
+                [] -> fail $ "Codegen error: No such variable " ++ show f
+    sc env (SForeign l ty f args)
+       = do args' <- mapM (\ (t, a) -> do a' <- scVar env a
+                                          return (t, a')) args
+            return $ SForeign l ty f args'
+    sc env (SCon tag f args)
+       = do args' <- mapM (scVar env) args
+            case lookupCtxt Nothing f ctxt of
+                [LConstructor n tag ar] ->
+                    if True -- (ar == length args)
+                       then return $ SCon tag n args'
+                       else fail $ "Codegen error: Constructor " ++ show f ++ 
+                                   " has arity " ++ show ar
+                _ -> fail $ "Codegen error: No such constructor " ++ show f
+    sc env (SCase e alts)
+       = do e' <- scVar env e
+            alts' <- mapM (scalt env) alts
+            return (SCase e' alts')
+    sc env (SLet (Glob n) v e)
+       = do let env' = env ++ [(n, length env)]
+            v' <- sc env v
+            n' <- scVar env' (Glob n)
+            e' <- sc env' e
+            return (SLet n' v' e')
+    sc env (SOp prim args)
+       = do args' <- mapM (scVar env) args
+            return (SOp prim args')
+    sc env x = return x
+
+    scVar env (Glob n) =
+       case lookup n (reverse env) of -- most recent first
+              Just i -> do lvar i; return (Loc i)
+              Nothing -> case lookupCtxt Nothing n ctxt of
+                              [LConstructor _ i ar] ->
+                                  fail $ "Codegen error : can't pass constructor here"
+                              [_] -> return (Glob n)
+                              [] -> fail $ "Codegen error: No such variable " ++ show n
+    scVar _ x = return x
+
+    scalt env (SConCase _ i n args e)
+       = do let env' = env ++ zip args [length env..]
+            tag <- case lookupCtxt Nothing n ctxt of
+                        [LConstructor _ i ar] -> 
+                             if True -- (length args == ar) 
+                                then return i
+                                else fail $ "Codegen error: Constructor " ++ show n ++
+                                            " has arity " ++ show ar
+                        _ -> fail $ "Codegen error: No constructor " ++ show n
+            e' <- sc env' e
+            return (SConCase (length env) tag n args e')
+    scalt env (SConstCase c e) = do e' <- sc env e
+                                    return (SConstCase c e')
+    scalt env (SDefaultCase e) = do e' <- sc env e
+                                    return (SDefaultCase e')
+
diff --git a/src/Idris/AbsSyntax.hs b/src/Idris/AbsSyntax.hs
--- a/src/Idris/AbsSyntax.hs
+++ b/src/Idris/AbsSyntax.hs
@@ -1,13 +1,16 @@
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
              TypeSynonymInstances, PatternGuards #-}
 
-module Idris.AbsSyntax where
+module Idris.AbsSyntax(module Idris.AbsSyntax, module Idris.AbsSyntaxTree) where
 
 import Core.TT
 import Core.Evaluate
 import Core.Elaborate hiding (Tactic(..))
 import Core.Typecheck
+import Idris.AbsSyntaxTree
 
+import Paths_idris
+
 import System.Console.Haskeline
 
 import Control.Monad.State
@@ -18,94 +21,9 @@
 
 import Debug.Trace
 
-import qualified Epic.Epic as E
-
 import Util.Pretty
 
-data IOption = IOption { opt_logLevel :: Int,
-                         opt_typecase :: Bool,
-                         opt_typeintype :: Bool,
-                         opt_coverage :: Bool,
-                         opt_showimp  :: Bool,
-                         opt_repl     :: Bool,
-                         opt_verbose  :: Bool
-                       }
-    deriving (Show, Eq)
 
-defaultOpts = IOption 0 False False True False True True
-
--- TODO: Add 'module data' to IState, which can be saved out and reloaded quickly (i.e
--- without typechecking).
--- This will include all the functions and data declarations, plus fixity declarations
--- and syntax macros.
-
-data IState = IState { tt_ctxt :: Context,
-                       idris_constraints :: [(UConstraint, FC)],
-                       idris_infixes :: [FixDecl],
-                       idris_implicits :: Ctxt [PArg],
-                       idris_statics :: Ctxt [Bool],
-                       idris_classes :: Ctxt ClassInfo,
-                       idris_dsls :: Ctxt DSL,
-                       idris_optimisation :: Ctxt OptInfo, 
-                       idris_datatypes :: Ctxt TypeInfo,
-                       idris_patdefs :: Ctxt [(Term, Term)], -- not exported
-                       idris_flags :: Ctxt [FnOpt],
-                       idris_callgraph :: Ctxt [Name],
-                       idris_totcheck :: [(FC, Name)],
-                       idris_log :: String,
-                       idris_options :: IOption,
-                       idris_name :: Int,
-                       idris_metavars :: [Name],
-                       syntax_rules :: [Syntax],
-                       syntax_keywords :: [String],
-                       imported :: [FilePath],
-                       idris_prims :: [(Name, ([E.Name], E.Term))],
-                       idris_objs :: [FilePath],
-                       idris_libs :: [String],
-                       idris_hdrs :: [String],
-                       last_proof :: Maybe (Name, [String]),
-                       errLine :: Maybe Int,
-                       lastParse :: Maybe Name, 
-                       indent_stack :: [Int],
-                       brace_stack :: [Maybe Int],
-                       hide_list :: [(Name, Maybe Accessibility)],
-                       default_access :: Accessibility,
-                       ibc_write :: [IBCWrite],
-                       compiled_so :: Maybe String
-                     }
-             
--- information that needs writing for the current module's .ibc file
-data IBCWrite = IBCFix FixDecl
-              | IBCImp Name
-              | IBCStatic Name
-              | IBCClass Name
-              | IBCInstance Bool Name Name
-              | IBCDSL Name
-              | IBCData Name
-              | IBCOpt Name
-              | IBCSyntax Syntax
-              | IBCKeyword String
-              | IBCImport FilePath
-              | IBCObj FilePath
-              | IBCLib String
-              | IBCHeader String
-              | IBCAccess Name Accessibility
-              | IBCTotal Name Totality
-              | IBCFlags Name [FnOpt]
-              | IBCCG Name
-              | IBCDef Name -- i.e. main context
-  deriving Show
-
-idrisInit = IState initContext [] [] emptyContext emptyContext emptyContext
-                   emptyContext emptyContext emptyContext emptyContext 
-                   emptyContext emptyContext
-                   [] "" defaultOpts 6 [] [] [] [] [] [] [] [] 
-                   Nothing Nothing Nothing [] [] [] Hidden [] Nothing
-
--- The monad for the main REPL - reading and processing files and updating 
--- global state (hence the IO inner monad).
-type Idris = StateT IState (InputT IO)
-
 getContext :: Idris Context
 getContext = do i <- get; return (tt_ctxt i)
 
@@ -153,6 +71,9 @@
 addToCG n ns = do i <- get
                   put (i { idris_callgraph = addDef n ns (idris_callgraph i) })
 
+addToCalledG :: Name -> [Name] -> Idris ()
+addToCalledG n ns = return () -- TODO
+
 -- Add a class instance function. Dodgy hack: Put integer instances first in the
 -- list so they are resolved by default.
 
@@ -277,6 +198,16 @@
 logLevel = do i <- get
               return (opt_logLevel (idris_options i))
 
+setErrContext :: Bool -> Idris ()
+setErrContext t = do i <- get
+                     let opts = idris_options i
+                     let opt' = opts { opt_errContext = t }
+                     put (i { idris_options = opt' })
+
+errContext :: Idris Bool
+errContext = do i <- get
+                return (opt_errContext (idris_options i))
+
 useREPL :: Idris Bool
 useREPL = do i <- get
              return (opt_repl (idris_options i))
@@ -317,6 +248,26 @@
                    let opt' = opts { opt_coverage = t }
                    put (i { idris_options = opt' })
 
+setIBCSubDir :: FilePath -> Idris ()
+setIBCSubDir fp = do i <- get
+                     let opts = idris_options i
+                     let opt' = opts { opt_ibcsubdir = fp }
+                     put (i { idris_options = opt' })
+
+valIBCSubDir :: IState -> Idris FilePath
+valIBCSubDir i = return (opt_ibcsubdir (idris_options i))
+
+setImportDirs :: [FilePath] -> Idris ()
+setImportDirs fps = do i <- get
+                       let opts = idris_options i
+                       let opt' = opts { opt_importdirs = fps }
+                       put (i { idris_options = opt' })
+
+allImportDirs :: IState -> Idris [FilePath]
+allImportDirs i = do datadir <- liftIO $ getDataDir
+                     let optdirs = opt_importdirs (idris_options i)
+                     return ("." : (optdirs ++ [datadir]))
+
 impShow :: Idris Bool
 impShow = do i <- get
              return (opt_showimp (idris_options i))
@@ -349,826 +300,7 @@
                    let opt' = opts { opt_typecase = t }
                    put (i { idris_options = opt' })
 
--- Commands in the REPL
 
-data Command = Quit | Help | Eval PTerm | Check PTerm | TotCheck Name
-             | Reload | Edit
-             | Compile String | Execute | ExecVal PTerm
-             | Metavars | Prove Name | AddProof | Universes
-             | TTShell 
-             | LogLvl Int | Spec PTerm | HNF PTerm | Defn Name | Info Name
-             | NOP
-
--- Parsed declarations
-
-data Fixity = Infixl { prec :: Int } 
-            | Infixr { prec :: Int }
-            | InfixN { prec :: Int } 
-            | PrefixN { prec :: Int }
-    deriving Eq
-{-! 
-deriving instance Binary Fixity 
-!-}
-
-instance Show Fixity where
-    show (Infixl i) = "infixl " ++ show i
-    show (Infixr i) = "infixr " ++ show i
-    show (InfixN i) = "infix " ++ show i
-    show (PrefixN i) = "prefix " ++ show i
-
-data FixDecl = Fix Fixity String 
-    deriving (Show, Eq)
-{-! 
-deriving instance Binary FixDecl 
-!-}
-
-instance Ord FixDecl where
-    compare (Fix x _) (Fix y _) = compare (prec x) (prec y)
-
-
-data Static = Static | Dynamic
-  deriving (Show, Eq)
-{-! 
-deriving instance Binary Static 
-!-}
-
--- Mark bindings with their explicitness, and laziness
-data Plicity = Imp { plazy :: Bool,
-                     pstatic :: Static }
-             | Exp { plazy :: Bool,
-                     pstatic :: Static }
-             | Constraint { plazy :: Bool,
-                            pstatic :: Static }
-             | TacImp { plazy :: Bool,
-                        pstatic :: Static,
-                        pscript :: PTerm }
-  deriving (Show, Eq)
-
-{-!
-deriving instance Binary Plicity 
-!-}
-
-impl = Imp False Dynamic
-expl = Exp False Dynamic
-constraint = Constraint False Dynamic
-tacimpl = TacImp False Dynamic
-
-data FnOpt = Inlinable | TotalFn | AssertTotal | TCGen
-           | Specialise [Name] -- specialise it, freeze these names
-    deriving (Show, Eq)
-{-!
-deriving instance Binary FnOpt
-!-}
-
-type FnOpts = [FnOpt]
-
-inlinable :: FnOpts -> Bool
-inlinable = elem Inlinable
-
-data PDecl' t = PFix     FC Fixity [String] -- fixity declaration
-              | PTy      SyntaxInfo FC FnOpts Name t   -- type declaration
-              | PClauses FC FnOpts Name [PClause' t]   -- pattern clause
-              | PData    SyntaxInfo FC (PData' t)      -- data declaration
-              | PParams  FC [(Name, t)] [PDecl' t] -- params block
-              | PNamespace String [PDecl' t] -- new namespace
-              | PRecord  SyntaxInfo FC Name t Name t     -- record declaration
-              | PClass   SyntaxInfo FC 
-                         [t] -- constraints
-                         Name
-                         [(Name, t)] -- parameters
-                         [PDecl' t] -- declarations
-              | PInstance SyntaxInfo FC [t] -- constraints
-                                        Name -- class
-                                        [t] -- parameters
-                                        t -- full instance type
-                                        [PDecl' t]
-              | PDSL     Name (DSL' t)
-              | PSyntax  FC Syntax
-              | PDirective (Idris ())
-    deriving Functor
-
-data PClause' t = PClause  FC Name t [t] t [PDecl' t]
-                | PWith    FC Name t [t] t [PDecl' t]
-                | PClauseR FC        [t] t [PDecl' t]
-                | PWithR   FC        [t] t [PDecl' t]
-    deriving Functor
-
-data PData' t  = PDatadecl { d_name :: Name,
-                             d_tcon :: t,
-                             d_cons :: [(Name, t, FC)] }
-    deriving Functor
-
--- Handy to get a free function for applying PTerm -> PTerm functions
--- across a program, by deriving Functor
-
-type PDecl   = PDecl' PTerm
-type PData   = PData' PTerm
-type PClause = PClause' PTerm 
-
--- get all the names declared in a decl
-
-declared :: PDecl -> [Name]
-declared (PFix _ _ _) = []
-declared (PTy _ _ _ n t) = [n]
-declared (PClauses _ _ n _) = [] -- not a declaration
-declared (PData _ _ (PDatadecl n _ ts)) = n : map fstt ts
-   where fstt (a, _, _) = a
-declared (PParams _ _ ds) = concatMap declared ds
-declared (PNamespace _ ds) = concatMap declared ds
--- declared (PImport _) = []
-
-defined :: PDecl -> [Name]
-defined (PFix _ _ _) = []
-defined (PTy _ _ _ n t) = []
-defined (PClauses _ _ n _) = [n] -- not a declaration
-defined (PData _ _ (PDatadecl n _ ts)) = n : map fstt ts
-   where fstt (a, _, _) = a
-defined (PParams _ _ ds) = concatMap defined ds
-defined (PNamespace _ ds) = concatMap defined ds
--- declared (PImport _) = []
-
-updateN :: [(Name, Name)] -> Name -> Name
-updateN ns n | Just n' <- lookup n ns = n'
-updateN _  n = n
-
-updateNs :: [(Name, Name)] -> PTerm -> PTerm
-updateNs [] t = t
-updateNs ns t = mapPT updateRef t
-  where updateRef (PRef fc f) = PRef fc (updateN ns f) 
-        updateRef t = t
-
--- updateDNs :: [(Name, Name)] -> PDecl -> PDecl
--- updateDNs [] t = t
--- updateDNs ns (PTy s f n t)    | Just n' <- lookup n ns = PTy s f n' t
--- updateDNs ns (PClauses f n c) | Just n' <- lookup n ns = PClauses f n' (map updateCNs c)
---   where updateCNs ns (PClause n l ts r ds) 
---             = PClause (updateN ns n) (fmap (updateNs ns) l)
---                                      (map (fmap (updateNs ns)) ts)
---                                      (fmap (updateNs ns) r)
---                                      (map (updateDNs ns) ds)
--- updateDNs ns c = c
-
--- High level language terms
-
-data PTerm = PQuote Raw
-           | PRef FC Name
-           | PLam Name PTerm PTerm
-           | PPi  Plicity Name PTerm PTerm
-           | PLet Name PTerm PTerm PTerm 
-           | PTyped PTerm PTerm -- term with explicit type
-           | PApp FC PTerm [PArg]
-           | PCase FC PTerm [(PTerm, PTerm)]
-           | PTrue FC
-           | PFalse FC
-           | PRefl FC
-           | PResolveTC FC
-           | PEq FC PTerm PTerm
-           | PPair FC PTerm PTerm
-           | PDPair FC PTerm PTerm PTerm
-           | PAlternative [PTerm]
-           | PHidden PTerm -- irrelevant or hidden pattern
-           | PSet
-           | PConstant Const
-           | Placeholder
-           | PDoBlock [PDo]
-           | PIdiom FC PTerm
-           | PReturn FC
-           | PMetavar Name
-           | PProof [PTactic]
-           | PTactics [PTactic] -- as PProof, but no auto solving
-           | PElabError Err -- error to report on elaboration
-           | PImpossible -- special case for declaring when an LHS can't typecheck
-    deriving Eq
-{-! 
-deriving instance Binary PTerm 
-!-}
-
-mapPT :: (PTerm -> PTerm) -> PTerm -> PTerm
-mapPT f t = f (mpt t) where
-  mpt (PLam n t s) = PLam n (mapPT f t) (mapPT f s)
-  mpt (PPi p n t s) = PPi p n (mapPT f t) (mapPT f s)
-  mpt (PLet n ty v s) = PLet n (mapPT f ty) (mapPT f v) (mapPT f s)
-  mpt (PApp fc t as) = PApp fc (mapPT f t) (map (fmap (mapPT f)) as)
-  mpt (PCase fc c os) = PCase fc (mapPT f c) (map (pmap (mapPT f)) os)
-  mpt (PEq fc l r) = PEq fc (mapPT f l) (mapPT f r)
-  mpt (PTyped l r) = PTyped (mapPT f l) (mapPT f r)
-  mpt (PPair fc l r) = PPair fc (mapPT f l) (mapPT f r)
-  mpt (PDPair fc l t r) = PDPair fc (mapPT f l) (mapPT f t) (mapPT f r)
-  mpt (PAlternative as) = PAlternative (map (mapPT f) as)
-  mpt (PHidden t) = PHidden (mapPT f t)
-  mpt (PDoBlock ds) = PDoBlock (map (fmap (mapPT f)) ds)
-  mpt (PProof ts) = PProof (map (fmap (mapPT f)) ts)
-  mpt (PTactics ts) = PTactics (map (fmap (mapPT f)) ts)
-  mpt x = x
-
-
-data PTactic' t = Intro [Name] | Intros | Focus Name
-                | Refine Name [Bool] | Rewrite t | LetTac Name t
-                | Exact t | Compute | Trivial
-                | Solve
-                | Attack
-                | ProofState | ProofTerm | Undo
-                | Try (PTactic' t) (PTactic' t)
-                | TSeq (PTactic' t) (PTactic' t)
-                | Qed | Abandon
-    deriving (Show, Eq, Functor)
-{-! 
-deriving instance Binary PTactic' 
-!-}
-
-instance Sized a => Sized (PTactic' a) where
-  size (Intro nms) = 1 + size nms
-  size Intros = 1
-  size (Focus nm) = 1 + size nm
-  size (Refine nm bs) = 1 + size nm + length bs
-  size (Rewrite t) = 1 + size t
-  size (LetTac nm t) = 1 + size nm + size t
-  size (Exact t) = 1 + size t
-  size Compute = 1
-  size Trivial = 1
-  size Solve = 1
-  size Attack = 1
-  size ProofState = 1
-  size ProofTerm = 1
-  size Undo = 1
-  size (Try l r) = 1 + size l + size r
-  size (TSeq l r) = 1 + size l + size r
-  size Qed = 1
-  size Abandon = 1
-
-type PTactic = PTactic' PTerm
-
-data PDo' t = DoExp  FC t
-            | DoBind FC Name t
-            | DoBindP FC t t
-            | DoLet  FC Name t t
-            | DoLetP FC t t
-    deriving (Eq, Functor)
-{-! 
-deriving instance Binary PDo' 
-!-}
-
-instance Sized a => Sized (PDo' a) where
-  size (DoExp fc t) = 1 + size fc + size t
-  size (DoBind fc nm t) = 1 + size fc + size nm + size t
-  size (DoBindP fc l r) = 1 + size fc + size l + size r
-  size (DoLet fc nm l r) = 1 + size fc + size nm + size l + size r
-  size (DoLetP fc l r) = 1 + size fc + size l + size r
-
-type PDo = PDo' PTerm
-
--- The priority gives a hint as to elaboration order. Best to elaborate
--- things early which will help give a more concrete type to other
--- variables, e.g. a before (interpTy a).
-
-data PArg' t = PImp { priority :: Int, 
-                      lazyarg :: Bool, pname :: Name, getTm :: t }
-             | PExp { priority :: Int,
-                      lazyarg :: Bool, getTm :: t }
-             | PConstraint { priority :: Int,
-                             lazyarg :: Bool, getTm :: t }
-             | PTacImplicit { priority :: Int,
-                              lazyarg :: Bool, pname :: Name, 
-                              getScript :: t,
-                              getTm :: t }
-    deriving (Show, Eq, Functor)
-
-instance Sized a => Sized (PArg' a) where
-  size (PImp p l nm trm) = 1 + size nm + size trm
-  size (PExp p l trm) = 1 + size trm
-  size (PConstraint p l trm) = 1 + size trm
-  size (PTacImplicit p l nm scr trm) = 1 + size nm + size scr + size trm
-
-{-! 
-deriving instance Binary PArg' 
-!-}
-
-pimp = PImp 0 True
-pexp = PExp 0 False
-pconst = PConstraint 0 False
-ptacimp = PTacImplicit 0 True
-
-type PArg = PArg' PTerm
-
--- Type class data
-
-data ClassInfo = CI { instanceName :: Name,
-                      class_methods :: [(Name, (FnOpts, PTerm))],
-                      class_defaults :: [(Name, Name)], -- method name -> default impl
-                      class_params :: [Name],
-                      class_instances :: [Name] }
-    deriving Show
-{-! 
-deriving instance Binary ClassInfo 
-!-}
-
-data OptInfo = Optimise { collapsible :: Bool,
-                          forceable :: [Int], -- argument positions
-                          recursive :: [Int] }
-    deriving Show
-{-! 
-deriving instance Binary OptInfo 
-!-}
-
-
-data TypeInfo = TI { con_names :: [Name] }
-    deriving Show
-{-!
-deriving instance Binary TypeInfo
-!-}
-
--- Syntactic sugar info 
-
-data DSL' t = DSL { dsl_bind    :: t,
-                    dsl_return  :: t,
-                    dsl_apply   :: t,
-                    dsl_pure    :: t,
-                    dsl_var     :: Maybe t,
-                    index_first :: Maybe t,
-                    index_next  :: Maybe t,
-                    dsl_lambda  :: Maybe t,
-                    dsl_let     :: Maybe t
-                  }
-    deriving (Show, Functor)
-{-!
-deriving instance Binary DSL'
-!-}
-
-type DSL = DSL' PTerm
-
-data SynContext = PatternSyntax | TermSyntax | AnySyntax
-    deriving Show
-{-! 
-deriving instance Binary SynContext 
-!-}
-
-data Syntax = Rule [SSymbol] PTerm SynContext
-    deriving Show
-{-! 
-deriving instance Binary Syntax 
-!-}
-
-data SSymbol = Keyword Name
-             | Symbol String
-             | Expr Name
-             | SimpleExpr Name
-    deriving Show
-{-! 
-deriving instance Binary SSymbol 
-!-}
-
-initDSL = DSL (PRef f (UN ">>=")) 
-              (PRef f (UN "return"))
-              (PRef f (UN "<$>"))
-              (PRef f (UN "pure"))
-              Nothing
-              Nothing
-              Nothing
-              Nothing
-              Nothing
-  where f = FC "(builtin)" 0
-
-data SyntaxInfo = Syn { using :: [(Name, PTerm)],
-                        syn_params :: [(Name, PTerm)],
-                        syn_namespace :: [String],
-                        no_imp :: [Name],
-                        decoration :: Name -> Name,
-                        inPattern :: Bool,
-                        dsl_info :: DSL }
-    deriving Show
-
-defaultSyntax = Syn [] [] [] [] id False initDSL
-
-expandNS :: SyntaxInfo -> Name -> Name
-expandNS syn n@(NS _ _) = n
-expandNS syn n = case syn_namespace syn of
-                        [] -> n
-                        xs -> NS n xs
-
-
---- Pretty printing declarations and terms
-
-instance Show PTerm where
-    show tm = showImp False tm
-
-instance Pretty PTerm where
-  pretty = prettyImp False
-
-instance Show PDecl where
-    show d = showDeclImp False d
-
-instance Show PClause where
-    show c = showCImp True c
-
-instance Show PData where
-    show d = showDImp False d
-
-showDeclImp _ (PFix _ f ops) = show f ++ " " ++ showSep ", " ops
-showDeclImp t (PTy _ _ _ n ty) = show n ++ " : " ++ showImp t ty
-showDeclImp _ (PClauses _ _ n c) = showSep "\n" (map show c)
-showDeclImp _ (PData _ _ d) = show d
-
-showCImp :: Bool -> PClause -> String
-showCImp impl (PClause _ n l ws r w) 
-   = showImp impl l ++ showWs ws ++ " = " ++ showImp impl r
-             ++ " where " ++ show w 
-  where
-    showWs [] = ""
-    showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
-showCImp impl (PWith _ n l ws r w) 
-   = showImp impl l ++ showWs ws ++ " with " ++ showImp impl r
-             ++ " { " ++ show w ++ " } " 
-  where
-    showWs [] = ""
-    showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
-
-
-showDImp :: Bool -> PData -> String
-showDImp impl (PDatadecl n ty cons) 
-   = "data " ++ show n ++ " : " ++ showImp impl ty ++ " where\n\t"
-     ++ showSep "\n\t| " 
-            (map (\ (n, t, _) -> show n ++ " : " ++ showImp impl t) cons)
-
-getImps :: [PArg] -> [(Name, PTerm)]
-getImps [] = []
-getImps (PImp _ _ n tm : xs) = (n, tm) : getImps xs
-getImps (_ : xs) = getImps xs
-
-getExps :: [PArg] -> [PTerm]
-getExps [] = []
-getExps (PExp _ _ tm : xs) = tm : getExps xs
-getExps (_ : xs) = getExps xs
-
-getConsts :: [PArg] -> [PTerm]
-getConsts [] = []
-getConsts (PConstraint _ _ tm : xs) = tm : getConsts xs
-getConsts (_ : xs) = getConsts xs
-
-getAll :: [PArg] -> [PTerm]
-getAll = map getTm 
-
-prettyImp :: Bool -> PTerm -> Doc
-prettyImp impl = prettySe 10
-  where
-    prettySe p (PQuote r) =
-      if size r > breakingSize then
-        text "![" $$ pretty r <> text "]"
-      else
-        text "![" <> pretty r <> text "]"
-    prettySe p (PRef fc n) =
-      if impl then
-        pretty n
-      else
-        prettyBasic n
-      where
-        prettyBasic n@(UN _) = pretty n
-        prettyBasic (MN _ s) = text s
-        prettyBasic (NS n s) = (foldr (<>) empty (intersperse (text ".") (map text $ reverse s))) <> prettyBasic n
-    prettySe p (PLam n ty sc) =
-      bracket p 2 $
-        if size sc > breakingSize then
-          text "λ" <> pretty n <+> text "=>" $+$ pretty sc
-        else
-          text "λ" <> pretty n <+> text "=>" <+> pretty sc
-    prettySe p (PLet n ty v sc) =
-      bracket p 2 $
-        if size sc > breakingSize then
-          text "let" <+> pretty n <+> text "=" <+> prettySe 10 v <+> text "in" $+$
-            nest nestingSize (prettySe 10 sc)
-        else
-          text "let" <+> pretty n <+> text "=" <+> prettySe 10 v <+> text "in" <+>
-            prettySe 10 sc
-    prettySe p (PPi (Exp l s) n ty sc)
-      | n `elem` allNamesIn sc || impl =
-          let open = if l then text "|" <> lparen else lparen in
-            bracket p 2 $
-              if size sc > breakingSize then
-                open <> pretty n <+> colon <+> prettySe 10 ty <> rparen <+>
-                  st <+> text "->" $+$ prettySe 10 sc
-              else
-                open <> pretty n <+> colon <+> prettySe 10 ty <> rparen <+>
-                  st <+> text "->" <+> prettySe 10 sc
-      | otherwise                      =
-          bracket p 2 $
-            if size sc > breakingSize then
-              prettySe 0 ty <+> st <+> text "->" $+$ prettySe 10 sc
-            else
-              prettySe 0 ty <+> st <+> text "->" <+> prettySe 10 sc
-      where
-        st =
-          case s of
-            Static -> text "[static]"
-            _      -> empty
-    prettySe p (PPi (Imp l s) n ty sc)
-      | impl =
-          let open = if l then text "|" <> lbrace else lbrace in
-            bracket p 2 $
-              if size sc > breakingSize then
-                open <> pretty n <+> colon <+> prettySe 10 ty <> rbrace <+>
-                  st <+> text "->" <+> prettySe 10 sc
-              else
-                open <> pretty n <+> colon <+> prettySe 10 ty <> rbrace <+>
-                  st <+> text "->" <+> prettySe 10 sc
-      | otherwise = prettySe 10 sc
-      where
-        st =
-          case s of
-            Static -> text $ "[static]"
-            _      -> empty
-    prettySe p (PPi (Constraint _ _) n ty sc) =
-      bracket p 2 $
-        if size sc > breakingSize then
-          prettySe 10 ty <+> text "=>" <+> prettySe 10 sc
-        else
-          prettySe 10 ty <+> text "=>" $+$ prettySe 10 sc
-    prettySe p (PPi (TacImp _ _ s) n ty sc) =
-      bracket p 2 $
-        if size sc > breakingSize then
-          lbrace <> text "tacimp" <+> pretty n <+> colon <+> prettySe 10 ty <>
-            rbrace <+> text "->" $+$ prettySe 10 sc
-        else
-          lbrace <> text "tacimp" <+> pretty n <+> colon <+> prettySe 10 ty <>
-            rbrace <+> text "->" <+> prettySe 10 sc
-    prettySe p (PApp _ (PRef _ f) [])
-      | not impl = pretty f
-    prettySe p (PApp _ (PRef _ op@(UN (f:_))) args)
-      | length (getExps args) == 2 && (not impl) && (not $ isAlpha f) =
-          let [l, r] = getExps args in
-            bracket p 1 $
-              if size r > breakingSize then
-                prettySe 1 l <+> pretty op $+$ prettySe 0 r
-              else
-                prettySe 1 l <+> pretty op <+> prettySe 0 r
-    prettySe p (PApp _ f as) =
-      let args = getExps as in
-        bracket p 1 $
-          prettySe 1 f <+>
-            if impl then
-              foldl fS empty as
-              -- foldr (<+>) empty $ map prettyArgS as
-            else
-              foldl fSe empty args
-              -- foldr (<+>) empty $ map prettyArgSe args
-      where
-        fS l r =
-          if size r > breakingSize then
-            l $+$ nest nestingSize (prettyArgS r)
-          else
-            l <+> prettyArgS r
-
-        fSe l r =
-          if size r > breakingSize then
-            l $+$ nest nestingSize (prettyArgSe r)
-          else
-            l <+> prettyArgSe r
-    prettySe p (PCase _ scr opts) =
-      text "case" <+> prettySe 10 scr <+> text "of" $+$ nest nestingSize prettyBody
-      where
-        prettyBody = foldr ($$) empty $ intersperse (text "|") $ map sc opts
-
-        sc (l, r) = prettySe 10 l <+> text "=>" <+> prettySe 10 r
-    prettySe p (PHidden tm) = text "." <> prettySe 0 tm
-    prettySe p (PRefl _) = text "refl"
-    prettySe p (PResolveTC _) = text "resolvetc"
-    prettySe p (PTrue _) = text "()"
-    prettySe p (PFalse _) = text "_|_"
-    prettySe p (PEq _ l r) =
-      bracket p 2 $
-        if size r > breakingSize then
-          prettySe 10 l <+> text "=" $$ nest nestingSize (prettySe 10 r)
-        else
-          prettySe 10 l <+> text "=" <+> prettySe 10 r
-    prettySe p (PTyped l r) =
-      lparen <> prettySe 10 l <+> colon <+> prettySe 10 r <> rparen
-    prettySe p (PPair _ l r) =
-      if size r > breakingSize then
-        lparen <> prettySe 10 l <> text "," $+$
-          prettySe 10 r <> rparen
-      else
-        lparen <> prettySe 10 l <> text "," <+> prettySe 10 r <> rparen
-    prettySe p (PDPair _ l t r) =
-      if size r > breakingSize then
-        lparen <> prettySe 10 l <+> text "**" $+$
-          prettySe 10 r <> rparen
-      else
-        lparen <> prettySe 10 l <+> text "**" <+> prettySe 10 r <> rparen
-    prettySe p (PAlternative as) =
-      lparen <> text "|" <> prettyAs <> text "|" <> rparen
-        where
-          prettyAs =
-            foldr (\l -> \r -> l <+> text "," <+> r) empty $ map (prettySe 10) as
-    prettySe p PSet = text "Set"
-    prettySe p (PConstant c) = pretty c
-    -- XXX: add pretty for tactics
-    prettySe p (PProof ts) =
-      text "proof" <+> lbrace $+$ nest nestingSize (text . show $ ts) $+$ rbrace
-    prettySe p (PTactics ts) =
-      text "tactics" <+> lbrace $+$ nest nestingSize (text . show $ ts) $+$ rbrace
-    prettySe p (PMetavar n) = text "?" <> pretty n
-    prettySe p (PReturn f) = text "return"
-    prettySe p PImpossible = text "impossible"
-    prettySe p Placeholder = text "_"
-    prettySe p (PDoBlock _) = text "do block pretty not implemented"
-    prettySe p (PElabError s) = pretty s
-
-    prettySe p _ = text "test"
-
-    prettyArgS (PImp _ _ n tm) = prettyArgSi (n, tm)
-    prettyArgS (PExp _ _ tm)   = prettyArgSe tm
-    prettyArgS (PConstraint _ _ tm) = prettyArgSc tm
-    prettyArgS (PTacImplicit _ _ n _ tm) = prettyArgSti (n, tm)
-
-    prettyArgSe arg = prettySe 0 arg
-    prettyArgSi (n, val) = lbrace <> pretty n <+> text "=" <+> prettySe 10 val <> rbrace
-    prettyArgSc val = lbrace <> lbrace <> prettySe 10 val <> rbrace <> rbrace
-    prettyArgSti (n, val) = lbrace <> text "auto" <+> pretty n <+> text "=" <+> prettySe 10 val <> rbrace
-
-    bracket outer inner doc
-      | inner > outer = lparen <> doc <> rparen
-      | otherwise     = doc
-        
-showImp :: Bool -> PTerm -> String
-showImp impl tm = se 10 tm where
-    se p (PQuote r) = "![" ++ show r ++ "]"
-    se p (PRef fc n) = if impl then show n -- ++ "[" ++ show fc ++ "]"
-                               else showbasic n
-      where showbasic n@(UN _) = show n
-            showbasic (MN _ s) = s
-            showbasic (NS n s) = showSep "." (reverse s) ++ "." ++ showbasic n
-    se p (PLam n ty sc) = bracket p 2 $ "\\ " ++ show n ++ 
-                            (if impl then " : " ++ se 10 ty else "") ++ " => " 
-                            ++ se 10 sc
-    se p (PLet n ty v sc) = bracket p 2 $ "let " ++ show n ++ " = " ++ se 10 v ++
-                            " in " ++ se 10 sc 
-    se p (PPi (Exp l s) n ty sc)
-        | n `elem` allNamesIn sc || impl
-                                  = bracket p 2 $
-                                    if l then "|(" else "(" ++ 
-                                    show n ++ " : " ++ se 10 ty ++ 
-                                    ") " ++ st ++
-                                    "-> " ++ se 10 sc
-        | otherwise = bracket p 2 $ se 0 ty ++ " " ++ st ++ "-> " ++ se 10 sc
-      where st = case s of
-                    Static -> "[static] "
-                    _ -> ""
-    se p (PPi (Imp l s) n ty sc)
-        | impl = bracket p 2 $ if l then "|{" else "{" ++ 
-                               show n ++ " : " ++ se 10 ty ++ 
-                               "} " ++ st ++ "-> " ++ se 10 sc
-        | otherwise = se 10 sc
-      where st = case s of
-                    Static -> "[static] "
-                    _ -> ""
-    se p (PPi (Constraint _ _) n ty sc)
-        = bracket p 2 $ se 10 ty ++ " => " ++ se 10 sc
-    se p (PPi (TacImp _ _ s) n ty sc)
-        = bracket p 2 $ "{tacimp " ++ show n ++ " : " ++ se 10 ty ++ "} -> " ++ se 10 sc
-    se p (PApp _ (PRef _ f) [])
-        | not impl = show f
-    se p (PApp _ (PRef _ op@(UN (f:_))) args)
-        | length (getExps args) == 2 && not impl && not (isAlpha f) 
-            = let [l, r] = getExps args in
-              bracket p 1 $ se 1 l ++ " " ++ show op ++ " " ++ se 0 r
-    se p (PApp _ f as) 
-        = let args = getExps as in
-              bracket p 1 $ se 1 f ++ if impl then concatMap sArg as
-                                              else concatMap seArg args
-    se p (PCase _ scr opts) = "case " ++ se 10 scr ++ " of " ++ showSep " | " (map sc opts)
-       where sc (l, r) = se 10 l ++ " => " ++ se 10 r
-    se p (PHidden tm) = "." ++ se 0 tm
-    se p (PRefl _) = "refl"
-    se p (PResolveTC _) = "resolvetc"
-    se p (PTrue _) = "()"
-    se p (PFalse _) = "_|_"
-    se p (PEq _ l r) = bracket p 2 $ se 10 l ++ " = " ++ se 10 r
-    se p (PTyped l r) = "(" ++ se 10 l ++ " : " ++ se 10 r ++ ")"
-    se p (PPair _ l r) = "(" ++ se 10 l ++ ", " ++ se 10 r ++ ")"
-    se p (PDPair _ l t r) = "(" ++ se 10 l ++ " ** " ++ se 10 r ++ ")"
-    se p (PAlternative as) = "(|" ++ showSep " , " (map (se 10) as) ++ "|)"
-    se p PSet = "Set"
-    se p (PConstant c) = show c
-    se p (PProof ts) = "proof { " ++ show ts ++ "}"
-    se p (PTactics ts) = "tactics { " ++ show ts ++ "}"
-    se p (PMetavar n) = "?" ++ show n
-    se p (PReturn f) = "return"
-    se p PImpossible = "impossible"
-    se p Placeholder = "_"
-    se p (PDoBlock _) = "do block show not implemented"
-    se p (PElabError s) = show s
---     se p x = "Not implemented"
-
-    sArg (PImp _ _ n tm) = siArg (n, tm)
-    sArg (PExp _ _ tm) = seArg tm
-    sArg (PConstraint _ _ tm) = scArg tm
-    sArg (PTacImplicit _ _ n _ tm) = stiArg (n, tm)
-
-    seArg arg      = " " ++ se 0 arg
-    siArg (n, val) = " {" ++ show n ++ " = " ++ se 10 val ++ "}"
-    scArg val = " {{" ++ se 10 val ++ "}}"
-    stiArg (n, val) = " {auto " ++ show n ++ " = " ++ se 10 val ++ "}"
-
-    bracket outer inner str | inner > outer = "(" ++ str ++ ")"
-                            | otherwise = str
-
-{-
- PQuote Raw
-           | PRef FC Name
-           | PLam Name PTerm PTerm
-           | PPi  Plicity Name PTerm PTerm
-           | PLet Name PTerm PTerm PTerm 
-           | PTyped PTerm PTerm -- term with explicit type
-           | PApp FC PTerm [PArg]
-           | PCase FC PTerm [(PTerm, PTerm)]
-           | PTrue FC
-           | PFalse FC
-           | PRefl FC
-           | PResolveTC FC
-           | PEq FC PTerm PTerm
-           | PPair FC PTerm PTerm
-           | PDPair FC PTerm PTerm PTerm
-           | PAlternative [PTerm]
-           | PHidden PTerm -- irrelevant or hidden pattern
-           | PSet
-           | PConstant Const
-           | Placeholder
-           | PDoBlock [PDo]
-           | PIdiom FC PTerm
-           | PReturn FC
-           | PMetavar Name
-           | PProof [PTactic]
-           | PTactics [PTactic] -- as PProof, but no auto solving
-           | PElabError Err -- error to report on elaboration
-           | PImpossible -- special case for declaring when an LHS can't typecheck
--}
-
-instance Sized PTerm where
-  size (PQuote rawTerm) = size rawTerm
-  size (PRef fc name) = size name
-  size (PLam name ty bdy) = 1 + size ty + size bdy
-  size (PPi plicity name ty bdy) = 1 + size ty + size bdy
-  size (PLet name ty def bdy) = 1 + size ty + size def + size bdy
-  size (PTyped trm ty) = 1 + size trm + size ty
-  size (PApp fc name args) = 1 + size args
-  size (PCase fc trm bdy) = 1 + size trm + size bdy
-  size (PTrue fc) = 1
-  size (PFalse fc) = 1
-  size (PRefl fc) = 1
-  size (PResolveTC fc) = 1
-  size (PEq fc left right) = 1 + size left + size right
-  size (PPair fc left right) = 1 + size left + size right
-  size (PDPair fs left ty right) = 1 + size left + size ty + size right
-  size (PAlternative alts) = 1 + size alts
-  size (PHidden hidden) = size hidden
-  size PSet = 1
-  size (PConstant const) = 1 + size const
-  size Placeholder = 1
-  size (PDoBlock dos) = 1 + size dos
-  size (PIdiom fc term) = 1 + size term
-  size (PReturn fc) = 1
-  size (PMetavar name) = 1
-  size (PProof tactics) = size tactics
-  size (PElabError err) = size err
-  size PImpossible = 1
-
-allNamesIn :: PTerm -> [Name]
-allNamesIn tm = nub $ ni [] tm 
-  where
-    ni env (PRef _ n)        
-        | not (n `elem` env) = [n]
-    ni env (PApp _ f as)   = ni env f ++ concatMap (ni env) (map getTm as)
-    ni env (PCase _ c os)  = ni env c ++ concatMap (ni env) (map snd os)
-    ni env (PLam n ty sc)  = ni env ty ++ ni (n:env) sc
-    ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
-    ni env (PHidden tm)    = ni env tm
-    ni env (PEq _ l r)     = ni env l ++ ni env r
-    ni env (PTyped l r)    = ni env l ++ ni env r
-    ni env (PPair _ l r)   = ni env l ++ ni env r
-    ni env (PDPair _ (PRef _ n) t r)  = ni env t ++ ni (n:env) r
-    ni env (PDPair _ l t r)  = ni env l ++ ni env t ++ ni env r
-    ni env (PAlternative ls) = concatMap (ni env) ls
-    ni env _               = []
-
-namesIn :: [(Name, PTerm)] -> IState -> PTerm -> [Name]
-namesIn uvars ist tm = nub $ ni [] tm 
-  where
-    ni env (PRef _ n)        
-        | not (n `elem` env) 
-            = case lookupTy Nothing n (tt_ctxt ist) of
-                [] -> [n]
-                _ -> if n `elem` (map fst uvars) then [n] else []
-    ni env (PApp _ f as)   = ni env f ++ concatMap (ni env) (map getTm as)
-    ni env (PCase _ c os)  = ni env c ++ concatMap (ni env) (map snd os)
-    ni env (PLam n ty sc)  = ni env ty ++ ni (n:env) sc
-    ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
-    ni env (PEq _ l r)     = ni env l ++ ni env r
-    ni env (PTyped l r)    = ni env l ++ ni env r
-    ni env (PPair _ l r)   = ni env l ++ ni env r
-    ni env (PDPair _ (PRef _ n) t r) = ni env t ++ ni (n:env) r
-    ni env (PDPair _ l t r) = ni env l ++ ni env t ++ ni env r
-    ni env (PAlternative as) = concatMap (ni env) as
-    ni env (PHidden tm)    = ni env tm
-    ni env _               = []
-
 -- For inferring types of things
 
 bi = FC "builtin" 0
@@ -1276,7 +408,7 @@
     en (PTyped l r) = PTyped (en l) (en r)
     en (PPair f l r) = PPair f (en l) (en r)
     en (PDPair f l t r) = PDPair f (en l) (en t) (en r)
-    en (PAlternative as) = PAlternative (map en as)
+    en (PAlternative a as) = PAlternative a (map en as)
     en (PHidden t) = PHidden (en t)
     en (PDoBlock ds) = PDoBlock (map (fmap en) ds)
     en (PProof ts)   = PProof (map (fmap en) ts)
@@ -1352,7 +484,7 @@
     pri (PTyped l r) = pri l
     pri (PPair _ l r) = max 1 (max (pri l) (pri r))
     pri (PDPair _ l t r) = max 1 (max (pri l) (max (pri t) (pri r)))
-    pri (PAlternative as) = maximum (map pri as)
+    pri (PAlternative a as) = maximum (map pri as)
     pri (PConstant _) = 0
     pri Placeholder = 1
     pri _ = 3
@@ -1468,7 +600,7 @@
              let isn = namesIn uvars ist l ++ namesIn uvars ist t ++ 
                        namesIn uvars ist r
              put (decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
-    imps top env (PAlternative as)
+    imps top env (PAlternative a as)
         = do (decls, ns) <- get
              let isn = concatMap (namesIn uvars ist) as
              put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
@@ -1501,9 +633,9 @@
 addImpl' inpat env ist ptm = ai env ptm
   where
     ai env (PRef fc f)    
-        | not (f `elem` env) = handleErr $ aiFn inpat ist fc f []
+        | not (f `elem` env) = handleErr $ aiFn inpat inpat ist fc f []
     ai env (PHidden (PRef fc f))
-        | not (f `elem` env) = handleErr $ aiFn False ist fc f []
+        | not (f `elem` env) = handleErr $ aiFn inpat False ist fc f []
     ai env (PEq fc l r)   = let l' = ai env l
                                 r' = ai env r in
                                 PEq fc l' r'
@@ -1517,12 +649,12 @@
                                    t' = ai env t
                                    r' = ai env r in
                                    PDPair fc l' t' r'
-    ai env (PAlternative as) = let as' = map (ai env) as in
-                                   PAlternative as'
+    ai env (PAlternative a as) = let as' = map (ai env) as in
+                                     PAlternative a as'
     ai env (PApp fc (PRef _ f) as) 
         | not (f `elem` env)
                           = let as' = map (fmap (ai env)) as in
-                                handleErr $ aiFn False ist fc f as'
+                                handleErr $ aiFn inpat False ist fc f as'
     ai env (PApp fc f as) = let f' = ai env f
                                 as' = map (fmap (ai env)) as in
                                 mkPApp fc 1 f' as'
@@ -1551,18 +683,18 @@
 -- if in a pattern, and there are no arguments, and there's no possible
 -- names with zero explicit arguments, don't add implicits.
 
-aiFn :: Bool -> IState -> FC -> Name -> [PArg] -> Either Err PTerm
-aiFn True ist fc f []
+aiFn :: Bool -> Bool -> IState -> FC -> Name -> [PArg] -> Either Err PTerm
+aiFn inpat True ist fc f []
   = case lookupCtxt Nothing f (idris_implicits ist) of
         [] -> Right $ PRef fc f
         alts -> if (any (all imp) alts)
-                        then aiFn False ist fc f [] -- use it as a constructor
+                        then aiFn inpat False ist fc f [] -- use it as a constructor
                         else Right $ PRef fc f
     where imp (PExp _ _ _) = False
           imp _ = True
-aiFn inpat ist fc f as
+aiFn inpat expat ist fc f as
     | f `elem` primNames = Right $ PApp fc (PRef fc f) as
-aiFn inpat ist fc f as
+aiFn inpat expat ist fc f as
           -- This is where namespaces get resolved by adding PAlternative
         = case lookupCtxtName Nothing f (idris_implicits ist) of
             [(f',ns)] -> Right $ mkPApp fc (length ns) (PRef fc f') (insertImpl ns as)
@@ -1570,7 +702,7 @@
                     then Right $ PApp fc (PRef fc f) as
                     else Right $ mkPApp fc (length as) (PRef fc f) as
             alts -> Right $
-                     PAlternative $
+                     PAlternative True $
                        map (\(f', ns) -> mkPApp fc (length ns) (PRef fc f') 
                                                    (insertImpl ns as)) alts
   where
@@ -1588,14 +720,17 @@
     insertImpl (PTacImplicit p l n sc ty : ps) given =
         case find n given [] of
             Just (tm, given') -> PTacImplicit p l n sc tm : insertImpl ps given'
-            Nothing ->           PTacImplicit p l n sc sc
-                                    : insertImpl ps given
+            Nothing -> if inpat 
+                          then PTacImplicit p l n sc Placeholder : insertImpl ps given
+                          else PTacImplicit p l n sc sc : insertImpl ps given
     insertImpl expected [] = []
     insertImpl _        given  = given
 
     find n []               acc = Nothing
     find n (PImp _ _ n' t : gs) acc 
          | n == n' = Just (t, reverse acc ++ gs)
+    find n (PTacImplicit _ _ n' _ t : gs) acc 
+         | n == n' = Just (t, reverse acc ++ gs)
     find n (g : gs) acc = find n gs (g : acc)
 
 mkPApp fc a f [] = f
@@ -1650,7 +785,7 @@
 dumpDecl (PSyntax _ syn) = "syntax " ++ show syn
 dumpDecl (PClass _ _ cs n ps ds) 
     = "class " ++ show cs ++ " " ++ show n ++ " " ++ show ps ++ "\n" ++ dumpDecls ds
-dumpDecl (PInstance _ _ cs n _ t ds) 
+dumpDecl (PInstance _ _ cs n _ t _ ds) 
     = "instance " ++ show cs ++ " " ++ show n ++ " " ++ show t ++ "\n" ++ dumpDecls ds
 dumpDecl _ = "..."
 -- dumpDecl (PImport i) = "import " ++ i
@@ -1715,10 +850,10 @@
                                                     mt <- match' t t'
                                                     mr <- match' r r'
                                                     return (ml ++ mt ++ mr)
-    match (PAlternative as) (PAlternative as') 
+    match (PAlternative a as) (PAlternative a' as') 
         = do ms <- zipWithM match' as as' 
              return (concat ms)
-    match a@(PAlternative as) b
+    match a@(PAlternative _ as) b
         = do let ms = zipWith match' as (repeat b)
              case (rights (map toEither ms)) of
                 (x: _) -> return x
@@ -1774,7 +909,7 @@
     sm (PTyped x y) = PTyped (sm x) (sm y)
     sm (PPair f x y) = PPair f (sm x) (sm y)
     sm (PDPair f x t y) = PDPair f (sm x) (sm t) (sm y)
-    sm (PAlternative as) = PAlternative (map sm as)
+    sm (PAlternative a as) = PAlternative a (map sm as)
     sm (PHidden x) = PHidden (sm x)
     sm x = x
 
@@ -1789,7 +924,7 @@
     sm (PTyped x y) = PTyped (sm x) (sm y)
     sm (PPair f x y) = PPair f (sm x) (sm y)
     sm (PDPair f x t y) = PDPair f (sm x) (sm t) (sm y)
-    sm (PAlternative as) = PAlternative (map sm as)
+    sm (PAlternative a as) = PAlternative a (map sm as)
     sm (PHidden x) = PHidden (sm x)
     sm x = x
 
diff --git a/src/Idris/AbsSyntaxTree.hs b/src/Idris/AbsSyntaxTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Idris/AbsSyntaxTree.hs
@@ -0,0 +1,976 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
+             TypeSynonymInstances, PatternGuards #-}
+
+module Idris.AbsSyntaxTree where
+
+import Core.TT
+import Core.Evaluate
+import Core.Elaborate hiding (Tactic(..))
+import Core.Typecheck
+import IRTS.Lang
+import Util.Pretty
+
+import Paths_idris
+
+import System.Console.Haskeline
+
+import Control.Monad.State
+
+import Data.List
+import Data.Char
+import Data.Either
+
+import Debug.Trace
+
+data IOption = IOption { opt_logLevel :: Int,
+                         opt_typecase :: Bool,
+                         opt_typeintype :: Bool,
+                         opt_coverage :: Bool,
+                         opt_showimp  :: Bool,
+                         opt_errContext :: Bool,
+                         opt_repl     :: Bool,
+                         opt_verbose  :: Bool,
+                         opt_ibcsubdir :: FilePath,
+                         opt_importdirs :: [FilePath]
+                       }
+    deriving (Show, Eq)
+
+defaultOpts = IOption 0 False False True False False True True "" []
+
+-- TODO: Add 'module data' to IState, which can be saved out and reloaded quickly (i.e
+-- without typechecking).
+-- This will include all the functions and data declarations, plus fixity declarations
+-- and syntax macros.
+
+data IState = IState { tt_ctxt :: Context,
+                       idris_constraints :: [(UConstraint, FC)],
+                       idris_infixes :: [FixDecl],
+                       idris_implicits :: Ctxt [PArg],
+                       idris_statics :: Ctxt [Bool],
+                       idris_classes :: Ctxt ClassInfo,
+                       idris_dsls :: Ctxt DSL,
+                       idris_optimisation :: Ctxt OptInfo, 
+                       idris_datatypes :: Ctxt TypeInfo,
+                       idris_patdefs :: Ctxt [([Name], Term, Term)], -- not exported
+                       idris_flags :: Ctxt [FnOpt],
+                       idris_callgraph :: Ctxt [Name],
+                       idris_calledgraph :: Ctxt [Name],
+                       idris_totcheck :: [(FC, Name)],
+                       idris_log :: String,
+                       idris_options :: IOption,
+                       idris_name :: Int,
+                       idris_metavars :: [Name],
+                       syntax_rules :: [Syntax],
+                       syntax_keywords :: [String],
+                       imported :: [FilePath],
+                       idris_scprims :: [(Name, (Int, PrimFn))],
+                       idris_objs :: [FilePath],
+                       idris_libs :: [String],
+                       idris_hdrs :: [String],
+                       proof_list :: [(Name, [String])],
+                       errLine :: Maybe Int,
+                       lastParse :: Maybe Name, 
+                       indent_stack :: [Int],
+                       brace_stack :: [Maybe Int],
+                       hide_list :: [(Name, Maybe Accessibility)],
+                       default_access :: Accessibility,
+                       ibc_write :: [IBCWrite],
+                       compiled_so :: Maybe String
+                     }
+
+primDefs = [UN "unsafePerformIO", UN "mkLazyForeign", UN "mkForeign", UN "FalseElim"]
+             
+-- information that needs writing for the current module's .ibc file
+data IBCWrite = IBCFix FixDecl
+              | IBCImp Name
+              | IBCStatic Name
+              | IBCClass Name
+              | IBCInstance Bool Name Name
+              | IBCDSL Name
+              | IBCData Name
+              | IBCOpt Name
+              | IBCSyntax Syntax
+              | IBCKeyword String
+              | IBCImport FilePath
+              | IBCObj FilePath
+              | IBCLib String
+              | IBCHeader String
+              | IBCAccess Name Accessibility
+              | IBCTotal Name Totality
+              | IBCFlags Name [FnOpt]
+              | IBCCG Name
+              | IBCDef Name -- i.e. main context
+  deriving Show
+
+idrisInit = IState initContext [] [] emptyContext emptyContext emptyContext
+                   emptyContext emptyContext emptyContext emptyContext 
+                   emptyContext emptyContext emptyContext
+                   [] "" defaultOpts 6 [] [] [] [] [] [] [] []
+                   [] Nothing Nothing [] [] [] Hidden [] Nothing
+
+-- The monad for the main REPL - reading and processing files and updating 
+-- global state (hence the IO inner monad).
+type Idris = StateT IState (InputT IO)
+
+-- Commands in the REPL
+
+data Command = Quit   | Help | Eval PTerm | Check PTerm | TotCheck Name
+             | Reload | Edit
+             | Compile String | Execute | ExecVal PTerm
+             | NewCompile String
+             | Metavars    | Prove Name | AddProof | RmProof | Proofs | Universes
+             | TTShell 
+             | LogLvl Int | Spec PTerm | HNF PTerm | Defn Name 
+             | Info Name  | DebugInfo Name
+             | Search PTerm
+             | SetOpt Opt | UnsetOpt Opt
+             | NOP
+
+data Opt = Filename String
+         | Ver
+         | Usage
+         | ShowLibs
+         | ShowIncs
+         | NoPrelude
+         | NoREPL
+         | OLogging Int
+         | Output String
+         | NewOutput String
+         | TypeCase
+         | TypeInType
+         | NoCoverage 
+         | ErrContext 
+         | ShowImpl
+         | Verbose
+         | IBCSubDir String
+         | ImportDir String
+         | BCAsm String
+         | FOVM String
+    deriving Eq
+
+
+-- Parsed declarations
+
+data Fixity = Infixl { prec :: Int } 
+            | Infixr { prec :: Int }
+            | InfixN { prec :: Int } 
+            | PrefixN { prec :: Int }
+    deriving Eq
+{-! 
+deriving instance Binary Fixity 
+!-}
+
+instance Show Fixity where
+    show (Infixl i) = "infixl " ++ show i
+    show (Infixr i) = "infixr " ++ show i
+    show (InfixN i) = "infix " ++ show i
+    show (PrefixN i) = "prefix " ++ show i
+
+data FixDecl = Fix Fixity String 
+    deriving (Show, Eq)
+{-! 
+deriving instance Binary FixDecl 
+!-}
+
+instance Ord FixDecl where
+    compare (Fix x _) (Fix y _) = compare (prec x) (prec y)
+
+
+data Static = Static | Dynamic
+  deriving (Show, Eq)
+{-! 
+deriving instance Binary Static 
+!-}
+
+-- Mark bindings with their explicitness, and laziness
+data Plicity = Imp { plazy :: Bool,
+                     pstatic :: Static }
+             | Exp { plazy :: Bool,
+                     pstatic :: Static }
+             | Constraint { plazy :: Bool,
+                            pstatic :: Static }
+             | TacImp { plazy :: Bool,
+                        pstatic :: Static,
+                        pscript :: PTerm }
+  deriving (Show, Eq)
+
+{-!
+deriving instance Binary Plicity 
+!-}
+
+impl = Imp False Dynamic
+expl = Exp False Dynamic
+constraint = Constraint False Dynamic
+tacimpl = TacImp False Dynamic
+
+data FnOpt = Inlinable | TotalFn | AssertTotal | TCGen
+           | CExport String    -- export, with a C name
+           | Specialise [Name] -- specialise it, freeze these names
+    deriving (Show, Eq)
+{-!
+deriving instance Binary FnOpt
+!-}
+
+type FnOpts = [FnOpt]
+
+inlinable :: FnOpts -> Bool
+inlinable = elem Inlinable
+
+data PDecl' t = PFix     FC Fixity [String] -- fixity declaration
+              | PTy      SyntaxInfo FC FnOpts Name t   -- type declaration
+              | PClauses FC FnOpts Name [PClause' t]   -- pattern clause
+              | PData    SyntaxInfo FC (PData' t)      -- data declaration
+              | PParams  FC [(Name, t)] [PDecl' t] -- params block
+              | PNamespace String [PDecl' t] -- new namespace
+              | PRecord  SyntaxInfo FC Name t Name t     -- record declaration
+              | PClass   SyntaxInfo FC 
+                         [t] -- constraints
+                         Name
+                         [(Name, t)] -- parameters
+                         [PDecl' t] -- declarations
+              | PInstance SyntaxInfo FC [t] -- constraints
+                                        Name -- class
+                                        [t] -- parameters
+                                        t -- full instance type
+                                        (Maybe Name) -- explicit name
+                                        [PDecl' t]
+              | PDSL     Name (DSL' t)
+              | PSyntax  FC Syntax
+              | PDirective (Idris ())
+    deriving Functor
+{-!
+deriving instance Binary PDecl'
+!-}
+
+data PClause' t = PClause  FC Name t [t] t [PDecl' t]
+                | PWith    FC Name t [t] t [PDecl' t]
+                | PClauseR FC        [t] t [PDecl' t]
+                | PWithR   FC        [t] t [PDecl' t]
+    deriving Functor
+{-!
+deriving instance Binary PClause'
+!-}
+
+data PData' t  = PDatadecl { d_name :: Name,
+                             d_tcon :: t,
+                             d_cons :: [(Name, t, FC)] }
+    deriving Functor
+{-!
+deriving instance Binary PData'
+!-}
+
+-- Handy to get a free function for applying PTerm -> PTerm functions
+-- across a program, by deriving Functor
+
+type PDecl   = PDecl' PTerm
+type PData   = PData' PTerm
+type PClause = PClause' PTerm 
+
+-- get all the names declared in a decl
+
+declared :: PDecl -> [Name]
+declared (PFix _ _ _) = []
+declared (PTy _ _ _ n t) = [n]
+declared (PClauses _ _ n _) = [] -- not a declaration
+declared (PData _ _ (PDatadecl n _ ts)) = n : map fstt ts
+   where fstt (a, _, _) = a
+declared (PParams _ _ ds) = concatMap declared ds
+declared (PNamespace _ ds) = concatMap declared ds
+-- declared (PImport _) = []
+
+defined :: PDecl -> [Name]
+defined (PFix _ _ _) = []
+defined (PTy _ _ _ n t) = []
+defined (PClauses _ _ n _) = [n] -- not a declaration
+defined (PData _ _ (PDatadecl n _ ts)) = n : map fstt ts
+   where fstt (a, _, _) = a
+defined (PParams _ _ ds) = concatMap defined ds
+defined (PNamespace _ ds) = concatMap defined ds
+-- declared (PImport _) = []
+
+updateN :: [(Name, Name)] -> Name -> Name
+updateN ns n | Just n' <- lookup n ns = n'
+updateN _  n = n
+
+updateNs :: [(Name, Name)] -> PTerm -> PTerm
+updateNs [] t = t
+updateNs ns t = mapPT updateRef t
+  where updateRef (PRef fc f) = PRef fc (updateN ns f) 
+        updateRef t = t
+
+-- updateDNs :: [(Name, Name)] -> PDecl -> PDecl
+-- updateDNs [] t = t
+-- updateDNs ns (PTy s f n t)    | Just n' <- lookup n ns = PTy s f n' t
+-- updateDNs ns (PClauses f n c) | Just n' <- lookup n ns = PClauses f n' (map updateCNs c)
+--   where updateCNs ns (PClause n l ts r ds) 
+--             = PClause (updateN ns n) (fmap (updateNs ns) l)
+--                                      (map (fmap (updateNs ns)) ts)
+--                                      (fmap (updateNs ns) r)
+--                                      (map (updateDNs ns) ds)
+-- updateDNs ns c = c
+
+-- High level language terms
+
+data PTerm = PQuote Raw
+           | PRef FC Name
+           | PLam Name PTerm PTerm
+           | PPi  Plicity Name PTerm PTerm
+           | PLet Name PTerm PTerm PTerm 
+           | PTyped PTerm PTerm -- term with explicit type
+           | PApp FC PTerm [PArg]
+           | PCase FC PTerm [(PTerm, PTerm)]
+           | PTrue FC
+           | PFalse FC
+           | PRefl FC
+           | PResolveTC FC
+           | PEq FC PTerm PTerm
+           | PPair FC PTerm PTerm
+           | PDPair FC PTerm PTerm PTerm
+           | PAlternative Bool [PTerm] -- True if only one may work
+           | PHidden PTerm -- irrelevant or hidden pattern
+           | PSet
+           | PConstant Const
+           | Placeholder
+           | PDoBlock [PDo]
+           | PIdiom FC PTerm
+           | PReturn FC
+           | PMetavar Name
+           | PProof [PTactic]
+           | PTactics [PTactic] -- as PProof, but no auto solving
+           | PElabError Err -- error to report on elaboration
+           | PImpossible -- special case for declaring when an LHS can't typecheck
+    deriving Eq
+{-! 
+deriving instance Binary PTerm 
+!-}
+
+mapPT :: (PTerm -> PTerm) -> PTerm -> PTerm
+mapPT f t = f (mpt t) where
+  mpt (PLam n t s) = PLam n (mapPT f t) (mapPT f s)
+  mpt (PPi p n t s) = PPi p n (mapPT f t) (mapPT f s)
+  mpt (PLet n ty v s) = PLet n (mapPT f ty) (mapPT f v) (mapPT f s)
+  mpt (PApp fc t as) = PApp fc (mapPT f t) (map (fmap (mapPT f)) as)
+  mpt (PCase fc c os) = PCase fc (mapPT f c) (map (pmap (mapPT f)) os)
+  mpt (PEq fc l r) = PEq fc (mapPT f l) (mapPT f r)
+  mpt (PTyped l r) = PTyped (mapPT f l) (mapPT f r)
+  mpt (PPair fc l r) = PPair fc (mapPT f l) (mapPT f r)
+  mpt (PDPair fc l t r) = PDPair fc (mapPT f l) (mapPT f t) (mapPT f r)
+  mpt (PAlternative a as) = PAlternative a (map (mapPT f) as)
+  mpt (PHidden t) = PHidden (mapPT f t)
+  mpt (PDoBlock ds) = PDoBlock (map (fmap (mapPT f)) ds)
+  mpt (PProof ts) = PProof (map (fmap (mapPT f)) ts)
+  mpt (PTactics ts) = PTactics (map (fmap (mapPT f)) ts)
+  mpt x = x
+
+
+data PTactic' t = Intro [Name] | Intros | Focus Name
+                | Refine Name [Bool] | Rewrite t | LetTac Name t
+                | Exact t | Compute | Trivial
+                | Solve
+                | Attack
+                | ProofState | ProofTerm | Undo
+                | Try (PTactic' t) (PTactic' t)
+                | TSeq (PTactic' t) (PTactic' t)
+                | Qed | Abandon
+    deriving (Show, Eq, Functor)
+{-! 
+deriving instance Binary PTactic' 
+!-}
+
+instance Sized a => Sized (PTactic' a) where
+  size (Intro nms) = 1 + size nms
+  size Intros = 1
+  size (Focus nm) = 1 + size nm
+  size (Refine nm bs) = 1 + size nm + length bs
+  size (Rewrite t) = 1 + size t
+  size (LetTac nm t) = 1 + size nm + size t
+  size (Exact t) = 1 + size t
+  size Compute = 1
+  size Trivial = 1
+  size Solve = 1
+  size Attack = 1
+  size ProofState = 1
+  size ProofTerm = 1
+  size Undo = 1
+  size (Try l r) = 1 + size l + size r
+  size (TSeq l r) = 1 + size l + size r
+  size Qed = 1
+  size Abandon = 1
+
+type PTactic = PTactic' PTerm
+
+data PDo' t = DoExp  FC t
+            | DoBind FC Name t
+            | DoBindP FC t t
+            | DoLet  FC Name t t
+            | DoLetP FC t t
+    deriving (Eq, Functor)
+{-! 
+deriving instance Binary PDo' 
+!-}
+
+instance Sized a => Sized (PDo' a) where
+  size (DoExp fc t) = 1 + size fc + size t
+  size (DoBind fc nm t) = 1 + size fc + size nm + size t
+  size (DoBindP fc l r) = 1 + size fc + size l + size r
+  size (DoLet fc nm l r) = 1 + size fc + size nm + size l + size r
+  size (DoLetP fc l r) = 1 + size fc + size l + size r
+
+type PDo = PDo' PTerm
+
+-- The priority gives a hint as to elaboration order. Best to elaborate
+-- things early which will help give a more concrete type to other
+-- variables, e.g. a before (interpTy a).
+
+data PArg' t = PImp { priority :: Int, 
+                      lazyarg :: Bool, pname :: Name, getTm :: t }
+             | PExp { priority :: Int,
+                      lazyarg :: Bool, getTm :: t }
+             | PConstraint { priority :: Int,
+                             lazyarg :: Bool, getTm :: t }
+             | PTacImplicit { priority :: Int,
+                              lazyarg :: Bool, pname :: Name, 
+                              getScript :: t,
+                              getTm :: t }
+    deriving (Show, Eq, Functor)
+
+instance Sized a => Sized (PArg' a) where
+  size (PImp p l nm trm) = 1 + size nm + size trm
+  size (PExp p l trm) = 1 + size trm
+  size (PConstraint p l trm) = 1 + size trm
+  size (PTacImplicit p l nm scr trm) = 1 + size nm + size scr + size trm
+
+{-! 
+deriving instance Binary PArg' 
+!-}
+
+pimp = PImp 0 True
+pexp = PExp 0 False
+pconst = PConstraint 0 False
+ptacimp = PTacImplicit 0 True
+
+type PArg = PArg' PTerm
+
+-- Type class data
+
+data ClassInfo = CI { instanceName :: Name,
+                      class_methods :: [(Name, (FnOpts, PTerm))],
+                      class_defaults :: [(Name, (Name, PDecl))], -- method name -> default impl
+                      class_params :: [Name],
+                      class_instances :: [Name] }
+    deriving Show
+{-! 
+deriving instance Binary ClassInfo 
+!-}
+
+data OptInfo = Optimise { collapsible :: Bool,
+                          forceable :: [Int], -- argument positions
+                          recursive :: [Int] }
+    deriving Show
+{-! 
+deriving instance Binary OptInfo 
+!-}
+
+
+data TypeInfo = TI { con_names :: [Name] }
+    deriving Show
+{-!
+deriving instance Binary TypeInfo
+!-}
+
+-- Syntactic sugar info 
+
+data DSL' t = DSL { dsl_bind    :: t,
+                    dsl_return  :: t,
+                    dsl_apply   :: t,
+                    dsl_pure    :: t,
+                    dsl_var     :: Maybe t,
+                    index_first :: Maybe t,
+                    index_next  :: Maybe t,
+                    dsl_lambda  :: Maybe t,
+                    dsl_let     :: Maybe t
+                  }
+    deriving (Show, Functor)
+{-!
+deriving instance Binary DSL'
+!-}
+
+type DSL = DSL' PTerm
+
+data SynContext = PatternSyntax | TermSyntax | AnySyntax
+    deriving Show
+{-! 
+deriving instance Binary SynContext 
+!-}
+
+data Syntax = Rule [SSymbol] PTerm SynContext
+    deriving Show
+{-! 
+deriving instance Binary Syntax 
+!-}
+
+data SSymbol = Keyword Name
+             | Symbol String
+             | Binding Name
+             | Expr Name
+             | SimpleExpr Name
+    deriving Show
+{-! 
+deriving instance Binary SSymbol 
+!-}
+
+initDSL = DSL (PRef f (UN ">>=")) 
+              (PRef f (UN "return"))
+              (PRef f (UN "<$>"))
+              (PRef f (UN "pure"))
+              Nothing
+              Nothing
+              Nothing
+              Nothing
+              Nothing
+  where f = FC "(builtin)" 0
+
+data SyntaxInfo = Syn { using :: [(Name, PTerm)],
+                        syn_params :: [(Name, PTerm)],
+                        syn_namespace :: [String],
+                        no_imp :: [Name],
+                        decoration :: Name -> Name,
+                        inPattern :: Bool,
+                        implicitAllowed :: Bool,
+                        dsl_info :: DSL }
+    deriving Show
+{-!
+deriving instance Binary SyntaxInfo
+!-}
+
+defaultSyntax = Syn [] [] [] [] id False False initDSL
+
+expandNS :: SyntaxInfo -> Name -> Name
+expandNS syn n@(NS _ _) = n
+expandNS syn n = case syn_namespace syn of
+                        [] -> n
+                        xs -> NS n xs
+
+
+--- Pretty printing declarations and terms
+
+instance Show PTerm where
+    show tm = showImp False tm
+
+instance Pretty PTerm where
+  pretty = prettyImp False
+
+instance Show PDecl where
+    show d = showDeclImp False d
+
+instance Show PClause where
+    show c = showCImp True c
+
+instance Show PData where
+    show d = showDImp False d
+
+showDeclImp _ (PFix _ f ops) = show f ++ " " ++ showSep ", " ops
+showDeclImp t (PTy _ _ _ n ty) = show n ++ " : " ++ showImp t ty
+showDeclImp _ (PClauses _ _ n c) = showSep "\n" (map show c)
+showDeclImp _ (PData _ _ d) = show d
+
+showCImp :: Bool -> PClause -> String
+showCImp impl (PClause _ n l ws r w) 
+   = showImp impl l ++ showWs ws ++ " = " ++ showImp impl r
+             ++ " where " ++ show w 
+  where
+    showWs [] = ""
+    showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
+showCImp impl (PWith _ n l ws r w) 
+   = showImp impl l ++ showWs ws ++ " with " ++ showImp impl r
+             ++ " { " ++ show w ++ " } " 
+  where
+    showWs [] = ""
+    showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
+
+
+showDImp :: Bool -> PData -> String
+showDImp impl (PDatadecl n ty cons) 
+   = "data " ++ show n ++ " : " ++ showImp impl ty ++ " where\n\t"
+     ++ showSep "\n\t| " 
+            (map (\ (n, t, _) -> show n ++ " : " ++ showImp impl t) cons)
+
+getImps :: [PArg] -> [(Name, PTerm)]
+getImps [] = []
+getImps (PImp _ _ n tm : xs) = (n, tm) : getImps xs
+getImps (_ : xs) = getImps xs
+
+getExps :: [PArg] -> [PTerm]
+getExps [] = []
+getExps (PExp _ _ tm : xs) = tm : getExps xs
+getExps (_ : xs) = getExps xs
+
+getConsts :: [PArg] -> [PTerm]
+getConsts [] = []
+getConsts (PConstraint _ _ tm : xs) = tm : getConsts xs
+getConsts (_ : xs) = getConsts xs
+
+getAll :: [PArg] -> [PTerm]
+getAll = map getTm 
+
+prettyImp :: Bool -> PTerm -> Doc
+prettyImp impl = prettySe 10
+  where
+    prettySe p (PQuote r) =
+      if size r > breakingSize then
+        text "![" $$ pretty r <> text "]"
+      else
+        text "![" <> pretty r <> text "]"
+    prettySe p (PRef fc n) =
+      if impl then
+        pretty n
+      else
+        prettyBasic n
+      where
+        prettyBasic n@(UN _) = pretty n
+        prettyBasic (MN _ s) = text s
+        prettyBasic (NS n s) = (foldr (<>) empty (intersperse (text ".") (map text $ reverse s))) <> prettyBasic n
+    prettySe p (PLam n ty sc) =
+      bracket p 2 $
+        if size sc > breakingSize then
+          text "λ" <> pretty n <+> text "=>" $+$ pretty sc
+        else
+          text "λ" <> pretty n <+> text "=>" <+> pretty sc
+    prettySe p (PLet n ty v sc) =
+      bracket p 2 $
+        if size sc > breakingSize then
+          text "let" <+> pretty n <+> text "=" <+> prettySe 10 v <+> text "in" $+$
+            nest nestingSize (prettySe 10 sc)
+        else
+          text "let" <+> pretty n <+> text "=" <+> prettySe 10 v <+> text "in" <+>
+            prettySe 10 sc
+    prettySe p (PPi (Exp l s) n ty sc)
+      | n `elem` allNamesIn sc || impl =
+          let open = if l then text "|" <> lparen else lparen in
+            bracket p 2 $
+              if size sc > breakingSize then
+                open <> pretty n <+> colon <+> prettySe 10 ty <> rparen <+>
+                  st <+> text "->" $+$ prettySe 10 sc
+              else
+                open <> pretty n <+> colon <+> prettySe 10 ty <> rparen <+>
+                  st <+> text "->" <+> prettySe 10 sc
+      | otherwise                      =
+          bracket p 2 $
+            if size sc > breakingSize then
+              prettySe 0 ty <+> st <+> text "->" $+$ prettySe 10 sc
+            else
+              prettySe 0 ty <+> st <+> text "->" <+> prettySe 10 sc
+      where
+        st =
+          case s of
+            Static -> text "[static]"
+            _      -> empty
+    prettySe p (PPi (Imp l s) n ty sc)
+      | impl =
+          let open = if l then text "|" <> lbrace else lbrace in
+            bracket p 2 $
+              if size sc > breakingSize then
+                open <> pretty n <+> colon <+> prettySe 10 ty <> rbrace <+>
+                  st <+> text "->" <+> prettySe 10 sc
+              else
+                open <> pretty n <+> colon <+> prettySe 10 ty <> rbrace <+>
+                  st <+> text "->" <+> prettySe 10 sc
+      | otherwise = prettySe 10 sc
+      where
+        st =
+          case s of
+            Static -> text $ "[static]"
+            _      -> empty
+    prettySe p (PPi (Constraint _ _) n ty sc) =
+      bracket p 2 $
+        if size sc > breakingSize then
+          prettySe 10 ty <+> text "=>" <+> prettySe 10 sc
+        else
+          prettySe 10 ty <+> text "=>" $+$ prettySe 10 sc
+    prettySe p (PPi (TacImp _ _ s) n ty sc) =
+      bracket p 2 $
+        if size sc > breakingSize then
+          lbrace <> text "tacimp" <+> pretty n <+> colon <+> prettySe 10 ty <>
+            rbrace <+> text "->" $+$ prettySe 10 sc
+        else
+          lbrace <> text "tacimp" <+> pretty n <+> colon <+> prettySe 10 ty <>
+            rbrace <+> text "->" <+> prettySe 10 sc
+    prettySe p (PApp _ (PRef _ f) [])
+      | not impl = pretty f
+    prettySe p (PApp _ (PRef _ op@(UN (f:_))) args)
+      | length (getExps args) == 2 && (not impl) && (not $ isAlpha f) =
+          let [l, r] = getExps args in
+            bracket p 1 $
+              if size r > breakingSize then
+                prettySe 1 l <+> pretty op $+$ prettySe 0 r
+              else
+                prettySe 1 l <+> pretty op <+> prettySe 0 r
+    prettySe p (PApp _ f as) =
+      let args = getExps as in
+        bracket p 1 $
+          prettySe 1 f <+>
+            if impl then
+              foldl fS empty as
+              -- foldr (<+>) empty $ map prettyArgS as
+            else
+              foldl fSe empty args
+              -- foldr (<+>) empty $ map prettyArgSe args
+      where
+        fS l r =
+          if size r > breakingSize then
+            l $+$ nest nestingSize (prettyArgS r)
+          else
+            l <+> prettyArgS r
+
+        fSe l r =
+          if size r > breakingSize then
+            l $+$ nest nestingSize (prettyArgSe r)
+          else
+            l <+> prettyArgSe r
+    prettySe p (PCase _ scr opts) =
+      text "case" <+> prettySe 10 scr <+> text "of" $+$ nest nestingSize prettyBody
+      where
+        prettyBody = foldr ($$) empty $ intersperse (text "|") $ map sc opts
+
+        sc (l, r) = prettySe 10 l <+> text "=>" <+> prettySe 10 r
+    prettySe p (PHidden tm) = text "." <> prettySe 0 tm
+    prettySe p (PRefl _) = text "refl"
+    prettySe p (PResolveTC _) = text "resolvetc"
+    prettySe p (PTrue _) = text "()"
+    prettySe p (PFalse _) = text "_|_"
+    prettySe p (PEq _ l r) =
+      bracket p 2 $
+        if size r > breakingSize then
+          prettySe 10 l <+> text "=" $$ nest nestingSize (prettySe 10 r)
+        else
+          prettySe 10 l <+> text "=" <+> prettySe 10 r
+    prettySe p (PTyped l r) =
+      lparen <> prettySe 10 l <+> colon <+> prettySe 10 r <> rparen
+    prettySe p (PPair _ l r) =
+      if size r > breakingSize then
+        lparen <> prettySe 10 l <> text "," $+$
+          prettySe 10 r <> rparen
+      else
+        lparen <> prettySe 10 l <> text "," <+> prettySe 10 r <> rparen
+    prettySe p (PDPair _ l t r) =
+      if size r > breakingSize then
+        lparen <> prettySe 10 l <+> text "**" $+$
+          prettySe 10 r <> rparen
+      else
+        lparen <> prettySe 10 l <+> text "**" <+> prettySe 10 r <> rparen
+    prettySe p (PAlternative a as) =
+      lparen <> text "|" <> prettyAs <> text "|" <> rparen
+        where
+          prettyAs =
+            foldr (\l -> \r -> l <+> text "," <+> r) empty $ map (prettySe 10) as
+    prettySe p PSet = text "Set"
+    prettySe p (PConstant c) = pretty c
+    -- XXX: add pretty for tactics
+    prettySe p (PProof ts) =
+      text "proof" <+> lbrace $+$ nest nestingSize (text . show $ ts) $+$ rbrace
+    prettySe p (PTactics ts) =
+      text "tactics" <+> lbrace $+$ nest nestingSize (text . show $ ts) $+$ rbrace
+    prettySe p (PMetavar n) = text "?" <> pretty n
+    prettySe p (PReturn f) = text "return"
+    prettySe p PImpossible = text "impossible"
+    prettySe p Placeholder = text "_"
+    prettySe p (PDoBlock _) = text "do block pretty not implemented"
+    prettySe p (PElabError s) = pretty s
+
+    prettySe p _ = text "test"
+
+    prettyArgS (PImp _ _ n tm) = prettyArgSi (n, tm)
+    prettyArgS (PExp _ _ tm)   = prettyArgSe tm
+    prettyArgS (PConstraint _ _ tm) = prettyArgSc tm
+    prettyArgS (PTacImplicit _ _ n _ tm) = prettyArgSti (n, tm)
+
+    prettyArgSe arg = prettySe 0 arg
+    prettyArgSi (n, val) = lbrace <> pretty n <+> text "=" <+> prettySe 10 val <> rbrace
+    prettyArgSc val = lbrace <> lbrace <> prettySe 10 val <> rbrace <> rbrace
+    prettyArgSti (n, val) = lbrace <> text "auto" <+> pretty n <+> text "=" <+> prettySe 10 val <> rbrace
+
+    bracket outer inner doc
+      | inner > outer = lparen <> doc <> rparen
+      | otherwise     = doc
+        
+showImp :: Bool -> PTerm -> String
+showImp impl tm = se 10 tm where
+    se p (PQuote r) = "![" ++ show r ++ "]"
+    se p (PRef fc n) = if impl then show n -- ++ "[" ++ show fc ++ "]"
+                               else showbasic n
+      where showbasic n@(UN _) = show n
+            showbasic (MN _ s) = s
+            showbasic (NS n s) = showSep "." (reverse s) ++ "." ++ showbasic n
+    se p (PLam n ty sc) = bracket p 2 $ "\\ " ++ show n ++ 
+                            (if impl then " : " ++ se 10 ty else "") ++ " => " 
+                            ++ se 10 sc
+    se p (PLet n ty v sc) = bracket p 2 $ "let " ++ show n ++ " = " ++ se 10 v ++
+                            " in " ++ se 10 sc 
+    se p (PPi (Exp l s) n ty sc)
+        | n `elem` allNamesIn sc || impl
+                                  = bracket p 2 $
+                                    if l then "|(" else "(" ++ 
+                                    show n ++ " : " ++ se 10 ty ++ 
+                                    ") " ++ st ++
+                                    "-> " ++ se 10 sc
+        | otherwise = bracket p 2 $ se 0 ty ++ " " ++ st ++ "-> " ++ se 10 sc
+      where st = case s of
+                    Static -> "[static] "
+                    _ -> ""
+    se p (PPi (Imp l s) n ty sc)
+        | impl = bracket p 2 $ if l then "|{" else "{" ++ 
+                               show n ++ " : " ++ se 10 ty ++ 
+                               "} " ++ st ++ "-> " ++ se 10 sc
+        | otherwise = se 10 sc
+      where st = case s of
+                    Static -> "[static] "
+                    _ -> ""
+    se p (PPi (Constraint _ _) n ty sc)
+        = bracket p 2 $ se 10 ty ++ " => " ++ se 10 sc
+    se p (PPi (TacImp _ _ s) n ty sc)
+        = bracket p 2 $ "{tacimp " ++ show n ++ " : " ++ se 10 ty ++ "} -> " ++ se 10 sc
+    se p (PApp _ (PRef _ f) [])
+        | not impl = show f
+    se p (PApp _ (PRef _ op@(UN (f:_))) args)
+        | length (getExps args) == 2 && not impl && not (isAlpha f) 
+            = let [l, r] = getExps args in
+              bracket p 1 $ se 1 l ++ " " ++ show op ++ " " ++ se 0 r
+    se p (PApp _ f as) 
+        = let args = getExps as in
+              bracket p 1 $ se 1 f ++ if impl then concatMap sArg as
+                                              else concatMap seArg args
+    se p (PCase _ scr opts) = "case " ++ se 10 scr ++ " of " ++ showSep " | " (map sc opts)
+       where sc (l, r) = se 10 l ++ " => " ++ se 10 r
+    se p (PHidden tm) = "." ++ se 0 tm
+    se p (PRefl _) = "refl"
+    se p (PResolveTC _) = "resolvetc"
+    se p (PTrue _) = "()"
+    se p (PFalse _) = "_|_"
+    se p (PEq _ l r) = bracket p 2 $ se 10 l ++ " = " ++ se 10 r
+    se p (PTyped l r) = "(" ++ se 10 l ++ " : " ++ se 10 r ++ ")"
+    se p (PPair _ l r) = "(" ++ se 10 l ++ ", " ++ se 10 r ++ ")"
+    se p (PDPair _ l t r) = "(" ++ se 10 l ++ " ** " ++ se 10 r ++ ")"
+    se p (PAlternative a as) = "(|" ++ showSep " , " (map (se 10) as) ++ "|)"
+    se p PSet = "Set"
+    se p (PConstant c) = show c
+    se p (PProof ts) = "proof { " ++ show ts ++ "}"
+    se p (PTactics ts) = "tactics { " ++ show ts ++ "}"
+    se p (PMetavar n) = "?" ++ show n
+    se p (PReturn f) = "return"
+    se p PImpossible = "impossible"
+    se p Placeholder = "_"
+    se p (PDoBlock _) = "do block show not implemented"
+    se p (PElabError s) = show s
+--     se p x = "Not implemented"
+
+    sArg (PImp _ _ n tm) = siArg (n, tm)
+    sArg (PExp _ _ tm) = seArg tm
+    sArg (PConstraint _ _ tm) = scArg tm
+    sArg (PTacImplicit _ _ n _ tm) = stiArg (n, tm)
+
+    seArg arg      = " " ++ se 0 arg
+    siArg (n, val) = " {" ++ show n ++ " = " ++ se 10 val ++ "}"
+    scArg val = " {{" ++ se 10 val ++ "}}"
+    stiArg (n, val) = " {auto " ++ show n ++ " = " ++ se 10 val ++ "}"
+
+    bracket outer inner str | inner > outer = "(" ++ str ++ ")"
+                            | otherwise = str
+
+{-
+ PQuote Raw
+           | PRef FC Name
+           | PLam Name PTerm PTerm
+           | PPi  Plicity Name PTerm PTerm
+           | PLet Name PTerm PTerm PTerm 
+           | PTyped PTerm PTerm -- term with explicit type
+           | PApp FC PTerm [PArg]
+           | PCase FC PTerm [(PTerm, PTerm)]
+           | PTrue FC
+           | PFalse FC
+           | PRefl FC
+           | PResolveTC FC
+           | PEq FC PTerm PTerm
+           | PPair FC PTerm PTerm
+           | PDPair FC PTerm PTerm PTerm
+           | PAlternative [PTerm]
+           | PHidden PTerm -- irrelevant or hidden pattern
+           | PSet
+           | PConstant Const
+           | Placeholder
+           | PDoBlock [PDo]
+           | PIdiom FC PTerm
+           | PReturn FC
+           | PMetavar Name
+           | PProof [PTactic]
+           | PTactics [PTactic] -- as PProof, but no auto solving
+           | PElabError Err -- error to report on elaboration
+           | PImpossible -- special case for declaring when an LHS can't typecheck
+-}
+
+instance Sized PTerm where
+  size (PQuote rawTerm) = size rawTerm
+  size (PRef fc name) = size name
+  size (PLam name ty bdy) = 1 + size ty + size bdy
+  size (PPi plicity name ty bdy) = 1 + size ty + size bdy
+  size (PLet name ty def bdy) = 1 + size ty + size def + size bdy
+  size (PTyped trm ty) = 1 + size trm + size ty
+  size (PApp fc name args) = 1 + size args
+  size (PCase fc trm bdy) = 1 + size trm + size bdy
+  size (PTrue fc) = 1
+  size (PFalse fc) = 1
+  size (PRefl fc) = 1
+  size (PResolveTC fc) = 1
+  size (PEq fc left right) = 1 + size left + size right
+  size (PPair fc left right) = 1 + size left + size right
+  size (PDPair fs left ty right) = 1 + size left + size ty + size right
+  size (PAlternative a alts) = 1 + size alts
+  size (PHidden hidden) = size hidden
+  size PSet = 1
+  size (PConstant const) = 1 + size const
+  size Placeholder = 1
+  size (PDoBlock dos) = 1 + size dos
+  size (PIdiom fc term) = 1 + size term
+  size (PReturn fc) = 1
+  size (PMetavar name) = 1
+  size (PProof tactics) = size tactics
+  size (PElabError err) = size err
+  size PImpossible = 1
+
+allNamesIn :: PTerm -> [Name]
+allNamesIn tm = nub $ ni [] tm 
+  where
+    ni env (PRef _ n)        
+        | not (n `elem` env) = [n]
+    ni env (PApp _ f as)   = ni env f ++ concatMap (ni env) (map getTm as)
+    ni env (PCase _ c os)  = ni env c ++ concatMap (ni env) (map snd os)
+    ni env (PLam n ty sc)  = ni env ty ++ ni (n:env) sc
+    ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
+    ni env (PHidden tm)    = ni env tm
+    ni env (PEq _ l r)     = ni env l ++ ni env r
+    ni env (PTyped l r)    = ni env l ++ ni env r
+    ni env (PPair _ l r)   = ni env l ++ ni env r
+    ni env (PDPair _ (PRef _ n) t r)  = ni env t ++ ni (n:env) r
+    ni env (PDPair _ l t r)  = ni env l ++ ni env t ++ ni env r
+    ni env (PAlternative a ls) = concatMap (ni env) ls
+    ni env _               = []
+
+namesIn :: [(Name, PTerm)] -> IState -> PTerm -> [Name]
+namesIn uvars ist tm = nub $ ni [] tm 
+  where
+    ni env (PRef _ n)        
+        | not (n `elem` env) 
+            = case lookupTy Nothing n (tt_ctxt ist) of
+                [] -> [n]
+                _ -> if n `elem` (map fst uvars) then [n] else []
+    ni env (PApp _ f as)   = ni env f ++ concatMap (ni env) (map getTm as)
+    ni env (PCase _ c os)  = ni env c ++ concatMap (ni env) (map snd os)
+    ni env (PLam n ty sc)  = ni env ty ++ ni (n:env) sc
+    ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
+    ni env (PEq _ l r)     = ni env l ++ ni env r
+    ni env (PTyped l r)    = ni env l ++ ni env r
+    ni env (PPair _ l r)   = ni env l ++ ni env r
+    ni env (PDPair _ (PRef _ n) t r) = ni env t ++ ni (n:env) r
+    ni env (PDPair _ l t r) = ni env l ++ ni env t ++ ni env r
+    ni env (PAlternative a as) = concatMap (ni env) as
+    ni env (PHidden tm)    = ni env tm
+    ni env _               = []
diff --git a/src/Idris/Compiler.hs b/src/Idris/Compiler.hs
--- a/src/Idris/Compiler.hs
+++ b/src/Idris/Compiler.hs
@@ -3,9 +3,11 @@
 module Idris.Compiler where
 
 import Idris.AbsSyntax
+import Core.TT
+
+{-
 import Idris.Transforms
 
-import Core.TT
 import Core.Evaluate
 import Core.CaseTree
 
@@ -16,12 +18,16 @@
 import System.Directory
 import System.Environment
 
+import Paths_idris
+
 import Epic.Epic hiding (Term, Type, Name, fn, compile)
 import qualified Epic.Epic as E
-
-primDefs = [UN "mkForeign", UN "FalseElim"]
+-}
 
 compile :: FilePath -> Term -> Idris ()
+compile f t = fail "Epic backend disabled"
+
+{-
 compile f tm
     = do checkMVs
          let tmnames = namesUsed (STerm tm)
@@ -30,8 +36,12 @@
          objs <- getObjectFiles
          libs <- getLibs
          hdrs <- getHdrs
-         let incs = map Include hdrs
+         ddir <- liftIO $ getDataDir
+         -- if any includes exist in the data directory, use that
+         hdrs' <- liftIO $ mapM (inDir ddir) hdrs
+         let incs = map Include hdrs'
          so <- getSO
+--          let ilib = ddir ++ "/libidris.a"
          case so of
             Nothing ->
                 do m <- epicMain tm
@@ -43,7 +53,11 @@
                       case idris_metavars i \\ primDefs of
                             [] -> return ()
                             ms -> fail $ "There are undefined metavariables: " ++ show ms
+        inDir d h = do let f = d ++ "/" ++ h
+                       ex <- doesFileExist f
+                       if ex then return f else return h
 
+
 allNames :: [Name] -> Name -> Idris [Name]
 allNames ns n | n `elem` ns = return []
 allNames ns n = do i <- get
@@ -92,16 +106,21 @@
     epic tm = epic' [] tm where
       epic' env tm@(App f a)
           | (P _ (UN "mkForeign") _, args) <- unApply tm
-              = doForeign args
+              = doForeign False args
+          | (P _ (UN "mkLazyForeign") _, args) <- unApply tm
+              = doForeign True args
+          | (P _ (UN "unsafePerformIO") _, [_, arg]) <- unApply tm
+              = epic' env arg
           | (P _ (UN "lazy") _, [_,arg]) <- unApply tm
               = do arg' <- epic' env arg
                    return $ lazy_ arg'
           | (P _ (UN "prim__IO") _, [v]) <- unApply tm
-              = epic' env v
+              = do v' <- epic' env v
+                   return (effect_ v')
           | (P _ (UN "io_bind") _, [_,_,v,k]) <- unApply tm
               = do v' <- epic' env v 
                    k' <- epic' env k
-                   return (k' @@ (effect_ v'))
+                   return (effect_ (k' @@ (effect_ v')))
           | (P _ (UN "malloc") _, [_,size,t]) <- unApply tm
               = do size' <- epic' env size
                    t' <- epic' env t
@@ -144,24 +163,29 @@
                                  buildApp env (e @@ x') xs
                                     
 
-doForeign :: [TT Name] -> Idris E.Term
-doForeign (_ : fgn : args)
-   | (_, (Constant (Str fgnName) : fgnArgTys : P _ (UN ret) _ : [])) <- unApply fgn
+doForeign :: Bool -> [TT Name] -> Idris E.Term
+doForeign lazy (_ : fgn : args)
+   | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
         = let tys = getFTypes fgnArgTys
-              rty = mkEty ret in
+              rty = mkEty' ret in
               do args' <- mapM epic args
                  -- wrap it in a prim__IO
                  -- return $ con_ 0 @@ impossible @@ 
-                 return $ lazy_ $ foreign_ rty fgnName (zip args' tys)
+                 if lazy 
+                   then return $ lazy_ $ foreignL_ rty fgnName (zip args' tys)
+                   else return $ lazy_ $ foreign_ rty fgnName (zip args' tys)
    | otherwise = fail "Badly formed foreign function call"
 
 getFTypes :: TT Name -> [E.Type]
 getFTypes tm = case unApply tm of
                  (nil, []) -> []
-                 (cons, [(P _ (UN ty) _), xs]) -> 
+                 (cons, [ty, xs]) -> 
                     let rest = getFTypes xs in
-                        mkEty ty : rest                        
+                        mkEty' ty : rest
 
+mkEty' (P _ (UN ty) _) = mkEty ty
+mkEty' _ = tyAny
+
 mkEty "FInt"    = tyInt
 mkEty "FFloat"  = tyFloat
 mkEty "FChar"   = tyChar
@@ -212,15 +236,4 @@
         mkEpicAlt (DefaultCase rhs)      = do rhs' <- epic rhs
                                               return $ defaultcase rhs'
 
-tempfile :: IO (FilePath, Handle)
-tempfile = do env <- environment "TMPDIR"
-              let dir = case env of
-                              Nothing -> "/tmp"
-                              (Just d) -> d
-              openTempFile dir "esc"
-
-environment :: String -> IO (Maybe String)
-environment x = catch (do e <- getEnv x
-                          return (Just e))
-                      (\_ -> return Nothing)
-
+-}
diff --git a/src/Idris/Coverage.hs b/src/Idris/Coverage.hs
--- a/src/Idris/Coverage.hs
+++ b/src/Idris/Coverage.hs
@@ -140,7 +140,7 @@
 data LexOrder = LexXX | LexEQ | LexLT
     deriving (Show, Eq, Ord)
 
-calcTotality :: [Name] -> FC -> Name -> [(Term, Term)] -> Idris Totality
+calcTotality :: [Name] -> FC -> Name -> [([Name], Term, Term)] -> Idris Totality
 calcTotality path fc n pats 
     = do orders <- mapM ctot pats 
          let order = sortBy cmpOrd $ concat orders
@@ -177,7 +177,7 @@
                         [] -> [[]] -- recursive calls are all useless...
                         xs -> xs
 
-    ctot (lhs, rhs) 
+    ctot (_, lhs, rhs) 
         | (_, args) <- unApply lhs
             = do -- check lhs doesn't use any dodgy names
                     lhsOK <- mapM (chkOrd [] []) args
diff --git a/src/Idris/DSL.hs b/src/Idris/DSL.hs
--- a/src/Idris/DSL.hs
+++ b/src/Idris/DSL.hs
@@ -34,7 +34,7 @@
 expandDo dsl (PPair fc l r) = PPair fc (expandDo dsl l) (expandDo dsl r)
 expandDo dsl (PDPair fc l t r) = PDPair fc (expandDo dsl l) (expandDo dsl t) 
                                            (expandDo dsl r)
-expandDo dsl (PAlternative as) = PAlternative (map (expandDo dsl) as)
+expandDo dsl (PAlternative a as) = PAlternative a (map (expandDo dsl) as)
 expandDo dsl (PHidden t) = PHidden (expandDo dsl t)
 expandDo dsl (PReturn fc) = dsl_return dsl
 expandDo dsl (PDoBlock ds) = expandDo dsl $ block (dsl_bind dsl) ds 
@@ -81,7 +81,7 @@
     v' i (PEq f l r)     = PEq f (v' i l) (v' i r)
     v' i (PPair f l r)   = PPair f (v' i l) (v' i r)
     v' i (PDPair f l t r) = PDPair f (v' i l) (v' i t) (v' i r)
-    v' i (PAlternative as) = PAlternative $ map (v' i) as
+    v' i (PAlternative a as) = PAlternative a $ map (v' i) as
     v' i (PHidden t)     = PHidden (v' i t)
     v' i (PIdiom f t)    = PIdiom f (v' i t)
     v' i (PDoBlock ds)   = PDoBlock (map (fmap (v' i)) ds)
diff --git a/src/Idris/DataOpts.hs b/src/Idris/DataOpts.hs
--- a/src/Idris/DataOpts.hs
+++ b/src/Idris/DataOpts.hs
@@ -60,6 +60,11 @@
                           y' <- applyOpts y
                           return (x', y')
 
+instance (Optimisable a, Optimisable b) => Optimisable (vs, a, b) where
+    applyOpts (v, x, y) = do x' <- applyOpts x
+                             y' <- applyOpts y
+                             return (v, x', y')
+
 instance Optimisable a => Optimisable [a] where
     applyOpts = mapM applyOpts
 
diff --git a/src/Idris/Delaborate.hs b/src/Idris/Delaborate.hs
--- a/src/Idris/Delaborate.hs
+++ b/src/Idris/Delaborate.hs
@@ -10,6 +10,8 @@
 
 import Debug.Trace
 
+bugaddr = "https://github.com/edwinb/Idris-dev/issues"
+
 delab :: IState -> Term -> PTerm
 delab i tm = delab' i tm False
 
@@ -50,7 +52,7 @@
     deFn env (P _ n _) [ty, Bind x (Lam _) r]
                                  | n == UN "Exists" 
                                        = PDPair un (PRef un x) (de env ty)
-                                                   (de env (instantiate (P Bound x ty) r))
+                                                   (de ((x,x):env) (instantiate (P Bound x ty) r))
     deFn env (P _ n _) [_,_,l,r] | n == pairCon = PPair un (de env l) (de env r)
                                  | n == eqTy    = PEq un (de env l) (de env r)
                                  | n == UN "Ex_intro" = PDPair un (de env l) Placeholder
@@ -70,20 +72,32 @@
 
 pshow :: IState -> Err -> String
 pshow i (Msg s) = s
-pshow i (CantUnify x y e s) 
+pshow i (InternalMsg s) = "INTERNAL ERROR: " ++ show s ++ 
+   "\nThis is probably a bug, or a missing error message.\n" ++
+   "Please consider reporting at " ++ bugaddr
+pshow i (CantUnify x y e sc s) 
     = "Can't unify " ++ show (delab i x)
         ++ " with " ++ show (delab i y) ++
 --         " (" ++ show x ++ " and " ++ show y ++ ") " ++
         case e of
             Msg "" -> ""
-            _ -> "\n\nSpecifically:\n\t " ++ pshow i e 
+            _ -> "\n\nSpecifically:\n\t" ++ pshow i e ++ 
+                 if (opt_errContext (idris_options i)) then showSc sc else ""
+    where showSc [] = ""
+          showSc xs = "\n\nIn context:\n" ++ showSep "\n" (map showVar (reverse xs))
+          showVar (x, y) = "\t" ++ showbasic x ++ " : " ++ show (delab i y)
+          showbasic n@(UN _) = show n
+          showbasic (MN _ s) = s
+          showbasic (NS n s) = showSep "." (reverse s) ++ "." ++ showbasic n
 pshow i (NotInjective p x y) = "Can't verify injectivity of " ++ show (delab i p) ++
                                " when unifying " ++ show (delab i x) ++ " and " ++ 
                                                     show (delab i y)
 pshow i (CantResolve c) = "Can't resolve type class " ++ show (delab i c)
+pshow i (CantResolveAlts as) = "Can't disambiguate name: " ++ showSep ", " as
 pshow i (NoSuchVariable n) = "No such variable " ++ show n
 pshow i (IncompleteTerm t) = "Incomplete term " ++ show (delab i t)
 pshow i UniverseError = "Universe inconsistency"
 pshow i ProgramLineComment = "Program line next to comment"
+pshow i (Inaccessible n) = show n ++ " is not an accessible pattern variable"
 pshow i (At f e) = show f ++ ":" ++ pshow i e
 
diff --git a/src/Idris/ElabDecls.hs b/src/Idris/ElabDecls.hs
--- a/src/Idris/ElabDecls.hs
+++ b/src/Idris/ElabDecls.hs
@@ -25,7 +25,6 @@
 import Data.Maybe
 import Debug.Trace
 
-
 recheckC fc env t 
     = do -- t' <- applyOpts (forget t) (doesn't work, or speed things up...)
          ctxt <- getContext 
@@ -58,7 +57,7 @@
          (cty, _)   <- recheckC fc [] tyT
          addStatics n cty ty'
          logLvl 2 $ "---> " ++ show cty
-         let nty = normalise ctxt [] cty
+         let nty = cty -- normalise ctxt [] cty
          ds <- checkDef fc [(n, nty)]
          addIBC (IBCDef n)
          addDeferred ds
@@ -230,11 +229,11 @@
                                         show r) pats))
          ist <- get
          let tcase = opt_typecase (idris_options ist)
-         let pdef = map debind (map (simpl (tt_ctxt ist)) pats)
+         let pdef = map debind $ map (simpl (tt_ctxt ist)) pats
          cov <- coverage
          pcover <-
                  if cov  
-                    then do missing <- genClauses fc n (map fst pdef) cs
+                    then do missing <- genClauses fc n (map getLHS pdef) cs
                             missing' <- filterM (checkPossible info fc True n) missing
 --                             let missing' = mapMaybe (\x -> case x of
 --                                                                 Nothing -> Nothing
@@ -243,7 +242,7 @@
                             logLvl 3 $ "Must be unreachable:\n" ++ 
                                         showSep "\n" (map (showImp True) missing') ++
                                        "\nAgainst: " ++
-                                        showSep "\n" (map (\t -> showImp True (delab ist t)) (map fst pdef))
+                                        showSep "\n" (map (\t -> showImp True (delab ist t)) (map getLHS pdef))
                             if null missing'
                               then return True
                               else return False 
@@ -260,7 +259,7 @@
 --                                   return False
                     else return False
          pdef' <- applyOpts pdef 
-         let tree@(CaseDef _ sc _) = simpleCase tcase pcover pdef
+         tree@(CaseDef _ sc _) <- tclift $ simpleCase tcase pcover fc pdef
          ist <- get
 --          let wf = wellFounded ist n sc
          let tot = if pcover || AssertTotal `elem` opts
@@ -279,7 +278,7 @@
                                         iputStrLn $ show fc ++
                                                     ":warning - Unreachable case: " ++ 
                                                     show (delab ist x)) xs
-         let tree' = simpleCase tcase pcover pdef'
+         tree' <- tclift $ simpleCase tcase pcover fc pdef'
          tclift $ sameLength pdef
          logLvl 3 (show tree)
          logLvl 3 $ "Optimised: " ++ show tree'
@@ -299,18 +298,23 @@
                                 do let ns = namesUsed sc \\ scargs
                                    logLvl 2 $ "Called names: " ++ show ns
                                    addToCG n ns
+                                   addToCalledG n ns -- plus names in type!
                                    addIBC (IBCCG n)
                             _ -> return ()
 --                         addIBC (IBCTotal n tot)
              [] -> return ()
   where
-    debind (x, y) = (depat x, depat y)
-    depat (Bind n (PVar t) sc) = depat (instantiate (P Bound n t) sc)
-    depat x = x
+    debind (x, y) = let (vs, x') = depat [] x 
+                        (_, y') = depat [] y in
+                        (vs, x', y')
+    depat acc (Bind n (PVar t) sc) = depat (n : acc) (instantiate (P Bound n t) sc)
+    depat acc x = (acc, x)
+    
+    getLHS (_, l, _) = l
 
     simpl ctxt (x, y) = (x, simplify ctxt [] y)
 
-    sameLength ((x, _) : xs) 
+    sameLength ((_, x, _) : xs) 
         = do l <- sameLength xs
              let (f, as) = unApply x
              if (null xs || l == length as) then return (length as)
@@ -376,7 +380,7 @@
         let decls = concatMap declared whereblock
         let newargs = pvars ist lhs_tm
         let wb = map (expandParamsD ist decorate newargs decls) whereblock
-        logLvl 5 $ show wb
+        logLvl 5 $ "Where block: " ++ show wb
         mapM_ (elabDecl' info) wb
         -- Now build the RHS, using the type of the LHS as the goal.
         i <- get -- new implicits from where block
@@ -385,6 +389,7 @@
                                  (expandParams decorate newargs decls rhs_in)
         logLvl 2 (showImp True rhs)
         ctxt <- getContext -- new context with where block added
+        logLvl 5 "STARTING CHECK"
         ((rhs', defer, is), _) <- 
            tclift $ elaborate ctxt (MN 0 "patRHS") clhsty []
                     (do pbinds lhs_tm
@@ -393,6 +398,7 @@
                         tt <- get_term
                         let (tm, ds) = runState (collectDeferred tt) []
                         return (tm, ds, is))
+        logLvl 5 "DONE CHECK"
         logLvl 2 $ "---> " ++ show rhs'
         when (not (null defer)) $ iLOG $ "DEFERRED " ++ show defer
         def' <- checkDef fc defer
@@ -582,7 +588,7 @@
                                                  [PTy syn fc [] n ty', 
                                                   PClauses fc (TCGen:o ++ opts) n cs]
                                     iLOG (show ds)
-                                    return (n, (defaultdec n, ds))
+                                    return (n, ((defaultdec n, ds!!1), ds))
             _ -> fail $ show n ++ " is not a method"
     defdecl _ _ _ = fail "Can't happen (defdecl)"
 
@@ -664,17 +670,22 @@
                 Name -> -- the class 
                 [PTerm] -> -- class parameters (i.e. instance) 
                 PTerm -> -- full instance type
+                Maybe Name -> -- explicit name
                 [PDecl] -> Idris ()
-elabInstance info syn fc cs n ps t ds
+elabInstance info syn fc cs n ps t expn ds
     = do i <- get 
          (n, ci) <- case lookupCtxtName (namespace info) n (idris_classes i) of
                        [c] -> return c
                        _ -> fail $ show fc ++ ":" ++ show n ++ " is not a type class"
-         let iname = UN ('@':show n ++ "$" ++ show ps)
+         let iname = case expn of
+                         Nothing -> UN ('@':show n ++ "$" ++ show ps)
+                         Just nm -> nm
          -- if the instance type matches any of the instances we have already,
-         -- then it's overlapping, so report an error
-         mapM_ (checkNotOverlapping i t) (class_instances ci) 
-         addInstance intInst n iname
+         -- and it's not a named instance, then it's overlapping, so report an error
+         case expn of
+            Nothing -> do mapM_ (checkNotOverlapping i t) (class_instances ci) 
+                          addInstance intInst n iname
+            Just _ -> addInstance intInst n iname 
          elabType info syn fc [] iname t
          let ips = zip (class_params ci) ps
          let ns = case n of
@@ -685,7 +696,7 @@
                                     (decorate ns n, op, coninsert cs t', t'))
                         (class_methods ci)
          logLvl 3 (show (mtys, ips))
-         let ds' = insertDefaults (class_defaults ci) ns ds
+         let ds' = insertDefaults i (class_defaults ci) ns ds
          iLOG ("Defaults inserted: " ++ show ds' ++ "\n" ++ show ci)
          mapM_ (warnMissing ds' ns) (map fst (class_methods ci))
          mapM_ (checkInClass (map fst (class_methods ci))) (concatMap defined ds')
@@ -766,16 +777,16 @@
     coninsert cs (PPi p@(Imp _ _) n t sc) = PPi p n t (coninsert cs sc)
     coninsert cs sc = conbind cs sc
 
-    insertDefaults :: [(Name, Name)] -> [String] -> [PDecl] -> [PDecl]
-    insertDefaults [] ns ds = ds
-    insertDefaults ((n,dn) : defs) ns ds 
-       = insertDefaults defs ns (insertDef n dn ns ds)
+    insertDefaults :: IState -> [(Name, (Name, PDecl))] -> [String] -> [PDecl] -> [PDecl]
+    insertDefaults i [] ns ds = ds
+    insertDefaults i ((n,(dn, clauses)) : defs) ns ds 
+       = insertDefaults i defs ns (insertDef i n dn clauses ns ds)
 
-    insertDef meth def ns decls
+    insertDef i meth def clauses ns decls
         | null $ filter (clauseFor meth ns) decls
-            = decls ++ [PClauses fc [Inlinable,TCGen] meth 
-                        [PClause fc meth (PApp fc (PRef fc meth) []) [] 
-                                         (PApp fc (PRef fc def) []) []]]
+            = let newd = expandParamsD i (\n -> meth) [] [def] clauses in
+                  -- trace (show newd) $ 
+                  decls ++ [newd]
         | otherwise = decls
 
     warnMissing decls ns meth
@@ -854,9 +865,9 @@
                 Just ns -> info { namespace = Just (n:ns) } 
 elabDecl' info (PClass s f cs n ps ds) = do iLOG $ "Elaborating class " ++ show n
                                             elabClass info s f cs n ps ds
-elabDecl' info (PInstance s f cs n ps t ds) 
+elabDecl' info (PInstance s f cs n ps t expn ds) 
     = do iLOG $ "Elaborating instance " ++ show n
-         elabInstance info s f cs n ps t ds
+         elabInstance info s f cs n ps t expn ds
 elabDecl' info (PRecord s f tyn ty cn cty)
     = do iLOG $ "Elaborating record " ++ show tyn
          elabRecord info s f tyn ty cn cty
@@ -879,14 +890,16 @@
 
 checkInferred :: FC -> PTerm -> PTerm -> Idris ()
 checkInferred fc inf user =
-     do logLvl 6 $ "Checked to\n" ++ showImp True inf ++ "\n" ++
+     do logLvl 6 $ "Checked to\n" ++ showImp True inf ++ "\n\nFROM\n\n" ++
                                      showImp True user
+        logLvl 10 $ "Checking match"
         i <- get
         tclift $ case matchClause' True i user inf of 
             Right vs -> return ()
             Left (x, y) -> tfail $ At fc 
                                     (Msg $ "The type-checked term and given term do not match: "
                                            ++ show x ++ " and " ++ show y)
+        logLvl 10 $ "Checked match"
 --                           ++ "\n" ++ showImp True inf ++ "\n" ++ showImp True user)
 
 -- Return whether inferred term is different from given term
diff --git a/src/Idris/ElabTerm.hs b/src/Idris/ElabTerm.hs
--- a/src/Idris/ElabTerm.hs
+++ b/src/Idris/ElabTerm.hs
@@ -42,7 +42,9 @@
          is <- getAux
          tt <- get_term
          let (tm, ds) = runState (collectDeferred tt) []
-         return (tm, ds, is)
+         log <- getLog
+         if (log /= "") then trace log $ return (tm, ds, is)
+            else return (tm, ds, is)
 
 -- Build a term autogenerated as a typeclass method definition
 -- (Separate, so we don't go overboard resolving things that we don't
@@ -55,7 +57,9 @@
          is <- getAux
          tt <- get_term
          let (tm, ds) = runState (collectDeferred tt) []
-         return (tm, ds, is)
+         log <- getLog
+         if (log /= "") then trace log $ return (tm, ds, is)
+            else return (tm, ds, is)
 
 -- Returns the set of declarations we need to add to complete the definition
 -- (most likely case blocks to elaborate)
@@ -135,12 +139,20 @@
                                             [pimp (MN 0 "a") t,
                                              pimp (MN 0 "P") Placeholder,
                                              pexp l, pexp r])
-    elab' ina (PAlternative as) 
-        = let as' = pruneAlt as in
-              try (tryAll (zip (map (elab' ina) as') (map showHd as')))
-                  (tryAll (zip (map (elab' ina) as) (map showHd as)))
+    elab' ina (PAlternative True as) 
+        = do ty <- goal
+             ctxt <- get_context
+             let (tc, _) = unApply ty
+             let as' = pruneByType tc ctxt as
+             let as'' = as' -- pruneAlt as'
+             try (tryAll (zip (map (elab' ina) as'') (map showHd as'')))
+                 (tryAll (zip (map (elab' ina) as') (map showHd as')))
         where showHd (PApp _ h _) = show h
               showHd x = show x
+    elab' ina (PAlternative False as) 
+        = trySeq as
+        where trySeq [] = fail "All alternatives fail to elaborate"
+              trySeq (x : xs) = try (elab' ina x) (trySeq xs)
     elab' (ina, guarded) (PRef fc n) | pattern && not (inparamBlock n)
                          = do ctxt <- get_context
                               let iscon = isConName Nothing n ctxt
@@ -222,7 +234,9 @@
             let isinf = f == inferCon || tcname f
             ctxt <- get_context
             let guarded = isConName Nothing f ctxt
-            try (do ns <- apply (Var f) (map isph args)
+--             when True
+            try
+                (do ns <- apply (Var f) (map isph args)
                     let (ns', eargs) 
                          = unzip $
                              sortBy (\(_,x) (_,y) -> compare (priority x) (priority y))
@@ -335,12 +349,12 @@
         = PApp fc1 (PRef fc2 f) (fmap (fmap (choose f)) as)
     prune t = t
 
-    choose f (PAlternative as)
+    choose f (PAlternative a as)
         = let as' = fmap (choose f) as
               fs = filter (headIs f) as' in
               case fs of
                  [a] -> a
-                 _ -> PAlternative as'
+                 _ -> PAlternative a as'
     choose f (PApp fc f' as) = PApp fc (choose f f') (fmap (fmap (choose f)) as)
     choose f t = t
 
@@ -348,6 +362,29 @@
     headIs f (PApp _ f' _) = headIs f f'
     headIs f _ = True -- keep if it's not an application
 
+-- Rule out alternatives that don't return the same type as the head of the goal
+-- (If there are none left as a result, do nothing)
+
+pruneByType :: Term -> Context -> [PTerm] -> [PTerm]
+pruneByType (P _ n _) c as 
+    = let as' = filter (headIs n) as in
+          case as' of
+            [] -> as
+            _ -> as'
+  where
+    headIs f (PApp _ (PRef _ f') _) = typeHead f f'
+    headIs f (PApp _ f' _) = headIs f f'
+    headIs f (PPi _ _ _ sc) = headIs f sc
+    headIs _ _ = True -- keep if it's not an application
+
+    typeHead f f' = case lookupTy Nothing f' c of
+                       [ty] -> case unApply (getRetTy ty) of
+                                    (P _ ftyn _, _) -> ftyn == f
+                                    _ -> False
+                       _ -> False
+
+pruneByType t _ as = as
+
 trivial :: IState -> ElabD ()
 trivial ist = try (do elab ist toplevel False False (MN 0 "tac") (PRefl (FC "prf" 0))
                       return ())
@@ -416,7 +453,7 @@
                                 [] -> []
                                 [args] -> map isImp (snd args) -- won't be overloaded!
                 args <- apply (Var n) imps
---                 traceWhen (all boundVar ttypes) ("Progress: " ++ show t ++ " with " ++ show n) $
+                --                 traceWhen (all boundVar ttypes) ("Progress: " ++ show t ++ " with " ++ show n) $
                 mapM_ (\ (_,n) -> do focus n
                                      t' <- goal
                                      let (tc', ttype) = unApply t'
@@ -469,7 +506,7 @@
                                              return (fn, a)
                                     -- FIXME: resolve ambiguities
                                     [(n, args)] -> return $ (n, map isImp args)
-             ns <- apply (Var fn') (map (\x -> (x,0)) imps)
+             ns <- apply (Var fn') (map (\x -> (x, 0)) imps)
              when autoSolve solveAll
        where isImp (PImp _ _ _ _) = True
              isImp _ = False
diff --git a/src/Idris/Error.hs b/src/Idris/Error.hs
--- a/src/Idris/Error.hs
+++ b/src/Idris/Error.hs
@@ -11,6 +11,7 @@
 import Core.Constraints
 
 import System.Console.Haskeline
+import System.Console.Haskeline.MonadException
 import Control.Monad.State
 import System.IO.Error(isUserError, ioeGetErrorString)
 import Data.Char
diff --git a/src/Idris/IBC.hs b/src/Idris/IBC.hs
--- a/src/Idris/IBC.hs
+++ b/src/Idris/IBC.hs
@@ -21,7 +21,7 @@
 import Paths_idris
 
 ibcVersion :: Word8
-ibcVersion = 17
+ibcVersion = 19
 
 data IBCFile = IBCFile { ver :: Word8,
                          sourcefile :: FilePath,
@@ -64,7 +64,8 @@
                 (_:_) -> fail "Can't write ibc when there are unsolved metavariables"
                 [] -> return ()
          ibcf <- mkIBC (ibc_write i) (initIBC { sourcefile = src }) 
-         idrisCatch (do liftIO $ encodeFile f ibcf
+         idrisCatch (do liftIO $ createDirectoryIfMissing True (dropFileName f)
+                        liftIO $ encodeFile f ibcf
                         iLOG "Written")
             (\c -> do iLOG $ "Failed " ++ show c)
          return ()
@@ -154,9 +155,10 @@
 
 pImports :: [FilePath] -> Idris ()
 pImports fs 
-  = do datadir <- liftIO $ getDataDir
-       mapM_ (\f -> do fp <- liftIO $ findImport [".", datadir] f
-                       i <- getIState
+  = do mapM_ (\f -> do i <- getIState
+                       ibcsd <- valIBCSubDir i
+                       ids <- allImportDirs i
+                       fp <- liftIO $ findImport ids ibcsd f
                        if (f `elem` imported i)
                         then iLOG $ "Already read " ++ f
                         else do putIState (i { imported = f : imported i })
@@ -800,6 +802,206 @@
                    _ -> error "Corrupted binary data for Plicity"
 
  
+instance (Binary t) => Binary (PDecl' t) where
+        put x
+          = case x of
+                PFix x1 x2 x3 -> do putWord8 0
+                                    put x1
+                                    put x2
+                                    put x3
+                PTy x1 x2 x3 x4 x5 -> do putWord8 1
+                                         put x1
+                                         put x2
+                                         put x3
+                                         put x4
+                                         put x5
+                PClauses x1 x2 x3 x4 -> do putWord8 2
+                                           put x1
+                                           put x2
+                                           put x3
+                                           put x4
+                PData x1 x2 x3 -> do putWord8 3
+                                     put x1
+                                     put x2
+                                     put x3
+                PParams x1 x2 x3 -> do putWord8 4
+                                       put x1
+                                       put x2
+                                       put x3
+                PNamespace x1 x2 -> do putWord8 5
+                                       put x1
+                                       put x2
+                PRecord x1 x2 x3 x4 x5 x6 -> do putWord8 6
+                                                put x1
+                                                put x2
+                                                put x3
+                                                put x4
+                                                put x5
+                                                put x6
+                PClass x1 x2 x3 x4 x5 x6 -> do putWord8 7
+                                               put x1
+                                               put x2
+                                               put x3
+                                               put x4
+                                               put x5
+                                               put x6
+                PInstance x1 x2 x3 x4 x5 x6 x7 x8 -> do putWord8 8
+                                                        put x1
+                                                        put x2
+                                                        put x3
+                                                        put x4
+                                                        put x5
+                                                        put x6
+                                                        put x7
+                                                        put x8
+                PDSL x1 x2 -> do putWord8 9
+                                 put x1
+                                 put x2
+        get
+          = do i <- getWord8
+               case i of
+                   0 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           return (PFix x1 x2 x3)
+                   1 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           x5 <- get
+                           return (PTy x1 x2 x3 x4 x5)
+                   2 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           return (PClauses x1 x2 x3 x4)
+                   3 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           return (PData x1 x2 x3)
+                   4 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           return (PParams x1 x2 x3)
+                   5 -> do x1 <- get
+                           x2 <- get
+                           return (PNamespace x1 x2)
+                   6 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           x5 <- get
+                           x6 <- get
+                           return (PRecord x1 x2 x3 x4 x5 x6)
+                   7 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           x5 <- get
+                           x6 <- get
+                           return (PClass x1 x2 x3 x4 x5 x6)
+                   8 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           x5 <- get
+                           x6 <- get
+                           x7 <- get
+                           x8 <- get
+                           return (PInstance x1 x2 x3 x4 x5 x6 x7 x8)
+                   9 -> do x1 <- get
+                           x2 <- get
+                           return (PDSL x1 x2)
+                   _ -> error "Corrupted binary data for PDecl'"
+
+instance Binary SyntaxInfo where
+        put (Syn x1 x2 x3 x4 x5 x6 x7 x8)
+          = do put x1
+               put x2
+               put x3
+               put x4
+               put x5
+               put x6
+               put x7
+               put x8
+        get
+          = do x1 <- get
+               x2 <- get
+               x3 <- get
+               x4 <- get
+               x5 <- get
+               x6 <- get
+               x7 <- get
+               x8 <- get
+               return (Syn x1 x2 x3 x4 x5 x6 x7 x8)
+
+instance (Binary t) => Binary (PClause' t) where
+        put x
+          = case x of
+                PClause x1 x2 x3 x4 x5 x6 -> do putWord8 0
+                                                put x1
+                                                put x2
+                                                put x3
+                                                put x4
+                                                put x5
+                                                put x6
+                PWith x1 x2 x3 x4 x5 x6 -> do putWord8 1
+                                              put x1
+                                              put x2
+                                              put x3
+                                              put x4
+                                              put x5
+                                              put x6
+                PClauseR x1 x2 x3 x4 -> do putWord8 2
+                                           put x1
+                                           put x2
+                                           put x3
+                                           put x4
+                PWithR x1 x2 x3 x4 -> do putWord8 3
+                                         put x1
+                                         put x2
+                                         put x3
+                                         put x4
+        get
+          = do i <- getWord8
+               case i of
+                   0 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           x5 <- get
+                           x6 <- get
+                           return (PClause x1 x2 x3 x4 x5 x6)
+                   1 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           x5 <- get
+                           x6 <- get
+                           return (PWith x1 x2 x3 x4 x5 x6)
+                   2 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           return (PClauseR x1 x2 x3 x4)
+                   3 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           x4 <- get
+                           return (PWithR x1 x2 x3 x4)
+                   _ -> error "Corrupted binary data for PClause'"
+
+instance (Binary t) => Binary (PData' t) where
+        put (PDatadecl x1 x2 x3)
+          = do put x1
+               put x2
+               put x3
+        get
+          = do x1 <- get
+               x2 <- get
+               x3 <- get
+               return (PDatadecl x1 x2 x3)
+
 instance Binary PTerm where
         put x
           = case x of
@@ -822,52 +1024,61 @@
                                        put x2
                                        put x3
                                        put x4
-                PApp x1 x2 x3 -> do putWord8 5
+                PTyped x1 x2 -> do putWord8 5
+                                   put x1
+                                   put x2
+                PApp x1 x2 x3 -> do putWord8 6
                                     put x1
                                     put x2
                                     put x3
-                PTrue x1 -> do putWord8 6
+                PCase x1 x2 x3 -> do putWord8 7
+                                     put x1
+                                     put x2
+                                     put x3
+                PTrue x1 -> do putWord8 8
                                put x1
-                PFalse x1 -> do putWord8 7
+                PFalse x1 -> do putWord8 9
                                 put x1
-                PRefl x1 -> do putWord8 8
+                PRefl x1 -> do putWord8 10
                                put x1
-                PResolveTC x1 -> do putWord8 9
+                PResolveTC x1 -> do putWord8 11
                                     put x1
-                PEq x1 x2 x3 -> do putWord8 10
+                PEq x1 x2 x3 -> do putWord8 12
                                    put x1
                                    put x2
                                    put x3
-                PPair x1 x2 x3 -> do putWord8 11
+                PPair x1 x2 x3 -> do putWord8 13
                                      put x1
                                      put x2
                                      put x3
-                PDPair x1 x2 x3 x4 -> do putWord8 12
+                PDPair x1 x2 x3 x4 -> do putWord8 14
                                          put x1
                                          put x2
                                          put x3
                                          put x4
-                PAlternative x1 -> do putWord8 13
-                                      put x1
-                PHidden x1 -> do putWord8 14
+                PAlternative x1 x2 -> do putWord8 15
+                                         put x1
+                                         put x2
+                PHidden x1 -> do putWord8 16
                                  put x1
-                PSet -> putWord8 15
-                PConstant x1 -> do putWord8 16
+                PSet -> putWord8 17
+                PConstant x1 -> do putWord8 18
                                    put x1
-                Placeholder -> putWord8 17
-                PDoBlock x1 -> do putWord8 18
+                Placeholder -> putWord8 19
+                PDoBlock x1 -> do putWord8 20
                                   put x1
-                PReturn x1 -> do putWord8 19
+                PIdiom x1 x2 -> do putWord8 21
+                                   put x1
+                                   put x2
+                PReturn x1 -> do putWord8 22
                                  put x1
-                PMetavar x1 -> do putWord8 20
+                PMetavar x1 -> do putWord8 23
                                   put x1
-                PProof x1 -> do putWord8 21
+                PProof x1 -> do putWord8 24
                                 put x1
-                PTactics x1 -> do putWord8 22
+                PTactics x1 -> do putWord8 25
                                   put x1
---                 PElabError x1 -> do putWord8 23
---                                     put x1
-                PImpossible -> putWord8 24
+                PImpossible -> putWord8 27
         get
           = do i <- getWord8
                case i of
@@ -892,52 +1103,60 @@
                            return (PLet x1 x2 x3 x4)
                    5 -> do x1 <- get
                            x2 <- get
+                           return (PTyped x1 x2)
+                   6 -> do x1 <- get
+                           x2 <- get
                            x3 <- get
                            return (PApp x1 x2 x3)
-                   6 -> do x1 <- get
-                           return (PTrue x1)
                    7 -> do x1 <- get
-                           return (PFalse x1)
+                           x2 <- get
+                           x3 <- get
+                           return (PCase x1 x2 x3)
                    8 -> do x1 <- get
-                           return (PRefl x1)
+                           return (PTrue x1)
                    9 -> do x1 <- get
-                           return (PResolveTC x1)
+                           return (PFalse x1)
                    10 -> do x1 <- get
+                            return (PRefl x1)
+                   11 -> do x1 <- get
+                            return (PResolveTC x1)
+                   12 -> do x1 <- get
                             x2 <- get
                             x3 <- get
                             return (PEq x1 x2 x3)
-                   11 -> do x1 <- get
+                   13 -> do x1 <- get
                             x2 <- get
                             x3 <- get
                             return (PPair x1 x2 x3)
-                   12 -> do x1 <- get
+                   14 -> do x1 <- get
                             x2 <- get
                             x3 <- get
                             x4 <- get
                             return (PDPair x1 x2 x3 x4)
-                   13 -> do x1 <- get
-                            return (PAlternative x1)
-                   14 -> do x1 <- get
-                            return (PHidden x1)
-                   15 -> return PSet
+                   15 -> do x1 <- get
+                            x2 <- get
+                            return (PAlternative x1 x2)
                    16 -> do x1 <- get
-                            return (PConstant x1)
-                   17 -> return Placeholder
+                            return (PHidden x1)
+                   17 -> return PSet
                    18 -> do x1 <- get
+                            return (PConstant x1)
+                   19 -> return Placeholder
+                   20 -> do x1 <- get
                             return (PDoBlock x1)
-                   19 -> do x1 <- get
+                   21 -> do x1 <- get
+                            x2 <- get
+                            return (PIdiom x1 x2)
+                   22 -> do x1 <- get
                             return (PReturn x1)
-                   20 -> do x1 <- get
+                   23 -> do x1 <- get
                             return (PMetavar x1)
-                   21 -> do x1 <- get
+                   24 -> do x1 <- get
                             return (PProof x1)
-                   22 -> do x1 <- get
+                   25 -> do x1 <- get
                             return (PTactics x1)
---                    23 -> do x1 <- get
---                             return (PElabError x1)
-                   24 -> return PImpossible
+                   27 -> return PImpossible
                    _ -> error "Corrupted binary data for PTerm"
-
  
 instance (Binary t) => Binary (PTactic' t) where
         put x
@@ -1189,6 +1408,8 @@
                               put x1
                 SimpleExpr x1 -> do putWord8 3
                                     put x1
+                Binding x1 -> do putWord8 4
+                                 put x1
         get
           = do i <- getWord8
                case i of
@@ -1200,4 +1421,6 @@
                            return (Expr x1)
                    3 -> do x1 <- get
                            return (SimpleExpr x1)
+                   4 -> do x1 <- get
+                           return (Binding x1)
                    _ -> error "Corrupted binary data for SSymbol"
diff --git a/src/Idris/Imports.hs b/src/Idris/Imports.hs
--- a/src/Idris/Imports.hs
+++ b/src/Idris/Imports.hs
@@ -25,28 +25,44 @@
                      _ -> fp ++ ".lidr"
 
 -- Get name of byte compiled version of an import
-ibcPath :: FilePath -> FilePath
-ibcPath fp = let (n, ext) = splitExtension fp in
-                 n ++ ".ibc"
+ibcPath :: FilePath -> Bool -> FilePath -> FilePath
+ibcPath ibcsd use_ibcsd fp = let (d_fp, n_fp) = splitFileName fp
+                                 d = if (not use_ibcsd) || ibcsd == ""
+                                     then d_fp
+                                     else d_fp ++ ibcsd ++ "/"
+                                 n = dropExtension n_fp
+                             in d ++ n ++ ".ibc"
 
-findImport :: [FilePath] -> FilePath -> IO IFileType
-findImport []     fp = fail $ "Can't find import " ++ fp
-findImport (d:ds) fp = do let ibcp = ibcPath (d ++ "/" ++ fp)
-                          let idrp = srcPath (d ++ "/" ++ fp)
-                          let lidrp = lsrcPath (d ++ "/" ++ fp)
-                          ibc  <- doesFileExist ibcp
-                          idr  <- doesFileExist idrp
-                          lidr <- doesFileExist lidrp
---                           when idr $ putStrLn $ idrp ++ " ok"
---                           when lidr $ putStrLn $ lidrp ++ " ok"
---                           when ibc $ putStrLn $ ibcp ++ " ok"
-                          let isrc = if lidr then LIDR lidrp
-                                             else IDR idrp
-                          if ibc 
-                             then return (IBC ibcp isrc)
-                             else if (idr || lidr) 
-                                     then return isrc
-                                     else findImport ds fp
+ibcPathWithFallback :: FilePath -> FilePath -> IO FilePath
+ibcPathWithFallback ibcsd fp = do let ibcp = ibcPath ibcsd True fp
+                                  ibc <- doesFileExist ibcp
+                                  return (if ibc
+                                          then ibcp
+                                          else ibcPath ibcsd False fp)
+
+ibcPathNoFallback :: FilePath -> FilePath -> FilePath
+ibcPathNoFallback ibcsd fp = ibcPath ibcsd True fp
+
+findImport :: [FilePath] -> FilePath -> FilePath -> IO IFileType
+findImport []     ibcsd fp = fail $ "Can't find import " ++ fp
+findImport (d:ds) ibcsd fp = do let fp_full = d ++ "/" ++ fp
+                                ibcp <- ibcPathWithFallback ibcsd fp_full
+                                let idrp = srcPath fp_full
+                                let lidrp = lsrcPath fp_full
+                                ibc <- doesFileExist ibcp
+                                idr  <- doesFileExist idrp
+                                lidr <- doesFileExist lidrp
+--                              when idr $ putStrLn $ idrp ++ " ok"
+--                              when lidr $ putStrLn $ lidrp ++ " ok"
+--                              when ibc $ putStrLn $ ibcp ++ " ok"
+                                let isrc = if lidr
+                                           then LIDR lidrp
+                                           else IDR idrp
+                                if ibc
+                                  then return (IBC ibcp isrc)
+                                  else if (idr || lidr) 
+                                       then return isrc
+                                       else findImport ds ibcsd fp
 
 -- find a specific filename somewhere in a path
 
diff --git a/src/Idris/Parser.hs b/src/Idris/Parser.hs
--- a/src/Idris/Parser.hs
+++ b/src/Idris/Parser.hs
@@ -57,9 +57,10 @@
 
 loadModule :: FilePath -> Idris String
 loadModule f 
-   = idrisCatch (do datadir <- liftIO $ getDataDir
-                    fp <- liftIO $ findImport [".", datadir] f
-                    i <- getIState
+   = idrisCatch (do i <- getIState
+                    ibcsd <- valIBCSubDir i
+                    ids <- allImportDirs i
+                    fp <- liftIO $ findImport ids ibcsd f
                     if (f `elem` imported i)
                        then iLOG $ "Already read " ++ f
                        else do putIState (i { imported = f : imported i })
@@ -104,7 +105,8 @@
                   i <- get
                   mapM_ checkDeclTotality (idris_totcheck i)
                   iLOG ("Finished " ++ f)
-                  let ibc = dropExtension f ++ ".ibc"
+                  ibcsd <- valIBCSubDir i
+                  let ibc = ibcPathNoFallback ibcsd f
                   iucheck
                   i <- getIState
                   addHides (hide_list i)
@@ -294,8 +296,8 @@
 collect (PParams f ns ps : ds) = PParams f ns (collect ps) : collect ds
 collect (PNamespace ns ps : ds) = PNamespace ns (collect ps) : collect ds
 collect (PClass f s cs n ps ds : ds') = PClass f s cs n ps (collect ds) : collect ds'
-collect (PInstance f s cs n ps t ds : ds') 
-    = PInstance f s cs n ps t (collect ds) : collect ds'
+collect (PInstance f s cs n ps t en ds : ds') 
+    = PInstance f s cs n ps t en (collect ds) : collect ds'
 collect (d : ds) = d : collect ds
 collect [] = []
 
@@ -373,7 +375,7 @@
          when (length ns /= length (nub ns)) 
             $ fail "Repeated variable in syntax rule"
          lchar '='
-         tm <- pExpr syn
+         tm <- pExpr (impOK syn)
          pTerminator
          return (Rule (mkSimple syms) tm sty)
   where
@@ -395,6 +397,8 @@
 pSynSym :: IParser SSymbol
 pSynSym = try (do lchar '['; n <- pName; lchar ']'
                   return (Expr n))
+      <|> try (do lchar '{'; n <- pName; lchar '}'
+                  return (Binding n))
       <|> do n <- iName []
              return (Keyword n)
       <|> do sym <- strlit
@@ -407,7 +411,7 @@
                         opts' <- pFnOpts
                         n_in <- pfName
                         let n = expandNS syn n_in
-                        ty <- pTSig syn
+                        ty <- pTSig (impOK syn)
                         fc <- pfc
                         pTerminator 
 --                         ty' <- implicit syn n ty
@@ -470,7 +474,7 @@
      <|> try (do reserved "infix";  return InfixN)
      <|> try (do reserved "prefix"; return PrefixN)
 
---------- Tyoe classes ---------
+--------- Type classes ---------
 
 pClass :: SyntaxInfo -> IParser [PDecl]
 pClass syn = do acc <- pAccessibility
@@ -494,6 +498,10 @@
 pInstance :: SyntaxInfo -> IParser [PDecl]
 pInstance syn = do reserved "instance"
                    fc <- pfc
+                   en <- option Nothing
+                            (do lchar '['; n_in <- pfName; lchar ']'
+                                let n = expandNS syn n_in
+                                return (Just n))
                    cs <- pConstList syn
                    cn <- pName
                    args <- many1 (pSimpleExpr syn)
@@ -502,7 +510,7 @@
                    reserved "where"; open_block 
                    ds <- many $ pFunDecl syn
                    close_block
-                   return [PInstance syn fc cs cn args t (concat ds)]
+                   return [PInstance syn fc cs cn args t en (concat ds)]
 
 --------- Expressions ---------
 
@@ -550,6 +558,8 @@
     valid (Rule _ _ TermSyntax) = not (inPattern syn)
 
 
+data SynMatch = SynTm PTerm | SynBind Name
+
 pExt :: SyntaxInfo -> Syntax -> IParser PTerm
 pExt syn (Rule ssym ptm _)
     = do smap <- mapM pSymbol ssym
@@ -558,27 +568,33 @@
   where
     pSymbol (Keyword n)    = do reserved (show n); return Nothing
     pSymbol (Expr n)       = do tm <- pExpr syn
-                                return $ Just (n, tm)
+                                return $ Just (n, SynTm tm)
     pSymbol (SimpleExpr n) = do tm <- pSimpleExpr syn
-                                return $ Just (n, tm)
+                                return $ Just (n, SynTm tm)
+    pSymbol (Binding n)    = do b <- pName
+                                return $ Just (n, SynBind b)
     pSymbol (Symbol s)     = do symbol s
                                 return Nothing
     dropn n [] = []
     dropn n ((x,t) : xs) | n == x = xs
                          | otherwise = (x,t):dropn n xs
 
+    updateB ns n = case lookup n ns of
+                     Just (SynBind t) -> t
+                     _ -> n
+
     update ns (PRef fc n) = case lookup n ns of
-                              Just t -> t
+                              Just (SynTm t) -> t
                               _ -> PRef fc n
-    update ns (PLam n ty sc) = PLam n (update ns ty) (update (dropn n ns) sc)
-    update ns (PPi p n ty sc) = PPi p n (update ns ty) (update (dropn n ns) sc) 
-    update ns (PLet n ty val sc) = PLet n (update ns ty) (update ns val)
+    update ns (PLam n ty sc) = PLam (updateB ns n) (update ns ty) (update (dropn n ns) sc)
+    update ns (PPi p n ty sc) = PPi p (updateB ns n) (update ns ty) (update (dropn n ns) sc) 
+    update ns (PLet n ty val sc) = PLet (updateB ns n) (update ns ty) (update ns val)
                                           (update (dropn n ns) sc)
     update ns (PApp fc t args) = PApp fc (update ns t) (map (fmap (update ns)) args)
     update ns (PCase fc c opts) = PCase fc (update ns c) (map (pmap (update ns)) opts) 
     update ns (PPair fc l r) = PPair fc (update ns l) (update ns r)
     update ns (PDPair fc l t r) = PDPair fc (update ns l) (update ns t) (update ns r)
-    update ns (PAlternative as) = PAlternative (map (update ns) as)
+    update ns (PAlternative a as) = PAlternative a (map (update ns) as)
     update ns (PHidden t) = PHidden (update ns t)
     update ns (PDoBlock ds) = PDoBlock $ upd ns ds
       where upd ns (DoExp fc t : ds) = DoExp fc (update ns t) : upd ns ds
@@ -597,11 +613,15 @@
            i <- getState
            UN n <- iName (syntax_keywords i)
            return (UN ('@':n))
-    
 
-pfName = try pName
-     <|> do lchar '('; o <- operator; lchar ')'; return (UN o)
+-- Parser for an operator in function position, i.e. enclosed by `()', with an
+-- optional namespace.
+pOpFront = maybeWithNS pOpFrontNoNS False []
+  where pOpFrontNoNS = do lchar '('; o <- operator; lchar ')'; return o
 
+pfName = try pOpFront
+         <|> pName
+
 pAccessibility' :: IParser Accessibility
 pAccessibility'
         = do reserved "public";   return Public
@@ -615,6 +635,8 @@
 
 pFnOpts :: IParser [FnOpt]
 pFnOpts = do reserved "total"; xs <- pFnOpts; return (TotalFn : xs)
+      <|> try (do lchar '%'; reserved "export"; c <- strlit; xs <- pFnOpts
+                  return (CExport c : xs))
       <|> do lchar '%'; reserved "assert_total"; xs <- pFnOpts; return (AssertTotal : xs)
       <|> do lchar '%'; reserved "specialise"; 
              lchar '['; ns <- sepBy pfName (lchar ','); lchar ']'
@@ -654,10 +676,11 @@
         <|> try (pList syn)
         <|> try (pAlt syn)
         <|> try (pIdiom syn)
-        <|> try (do lchar '('; bracketed syn)
+        <|> try (do lchar '('; bracketed (noImp syn))
         <|> try (do c <- pConstant; fc <- pfc
                     return (modifyConst syn fc (PConstant c)))
         <|> do reserved "Set"; return PSet
+--         <|> do symbol "*"; return PSet
         <|> try (do symbol "()"; fc <- pfc; return (PTrue fc))
         <|> try (do symbol "_|_"; fc <- pfc; return (PFalse fc))
         <|> do lchar '_'; return Placeholder
@@ -732,7 +755,7 @@
 pAlt syn = do symbol "(|"; 
               alts <- sepBy1 (pExpr' syn) (lchar ',')
               symbol "|)"
-              return (PAlternative alts)
+              return (PAlternative False alts)
 
 pHSimpleExpr syn
              = do lchar '.'
@@ -790,9 +813,12 @@
 mkSet (MN 0 n) = MN 0 ("set_" ++ n)
 mkSet (NS n s) = NS (mkSet n) s
 
+noImp syn = syn { implicitAllowed = False }
+impOK syn = syn { implicitAllowed = True }
+
 pTSig syn = do lchar ':'
-               cs <- pConstList syn
-               sc <- pExpr syn
+               cs <- if implicitAllowed syn then pConstList syn else return []
+               sc <- pExpr syn 
                return (bindList (PPi constraint) (map (\x -> (MN 0 "c", x)) cs) sc)
 
 pLambda syn = do lchar '\\'
@@ -829,12 +855,14 @@
              symbol "->"
              sc <- pExpr syn
              return (bindList (PPi (Exp lazy st)) xt sc))
- <|> try (do lazy <- option False (do lchar '|'; return True)
-             st <- pStatic
-             lchar '{'; xt <- tyDeclList syn; lchar '}'
-             symbol "->"
-             sc <- pExpr syn
-             return (bindList (PPi (Imp lazy st)) xt sc))
+ <|> try (if implicitAllowed syn then
+             do lazy <- option False (do lchar '|'; return True)
+                st <- pStatic
+                lchar '{'; xt <- tyDeclList syn; lchar '}'
+                symbol "->"
+                sc <- pExpr syn
+                return (bindList (PPi (Imp lazy st)) xt sc)
+             else fail "No implicit arguments allowed here")
  <|> try (do lchar '{'; reserved "auto"
              xt <- tyDeclList syn; lchar '}'
              symbol "->"
@@ -855,19 +883,19 @@
 
 pConstList :: SyntaxInfo -> IParser [PTerm]
 pConstList syn = try (do lchar '(' 
-                         tys <- sepBy1 (pExpr' syn) (lchar ',')
+                         tys <- sepBy1 (pExpr' (noImp syn)) (lchar ',')
                          lchar ')'
                          reservedOp "=>"
                          return tys)
-             <|> try (do t <- pExpr syn
+             <|> try (do t <- pExpr (noImp syn)
                          reservedOp "=>"
                          return [t])
              <|> return []
 
-tyDeclList syn = try (sepBy1 (do x <- pfName; t <- pTSig syn; return (x,t))
+tyDeclList syn = try (sepBy1 (do x <- pfName; t <- pTSig (noImp syn); return (x,t))
                          (lchar ','))
              <|> do ns <- sepBy1 pName (lchar ',')
-                    t <- pTSig syn
+                    t <- pTSig (noImp syn)
                     return (map (\x -> (x, t)) ns)
 
 tyOptDeclList syn = sepBy1 (do x <- pfName; 
@@ -975,7 +1003,7 @@
 pRecord :: SyntaxInfo -> IParser PDecl
 pRecord syn = do acc <- pAccessibility
                  reserved "record"; fc <- pfc
-                 tyn_in <- pfName; ty <- pTSig syn
+                 tyn_in <- pfName; ty <- pTSig (impOK syn)
                  let tyn = expandNS syn tyn_in
                  reserved "where"
                  open_block
@@ -1001,7 +1029,7 @@
 pData :: SyntaxInfo -> IParser PDecl
 pData syn = try (do acc <- pAccessibility
                     reserved "data"; fc <- pfc
-                    tyn_in <- pfName; ty <- pTSig syn
+                    tyn_in <- pfName; ty <- pTSig (impOK syn)
                     let tyn = expandNS syn tyn_in
                     reserved "where"
                     open_block
@@ -1041,7 +1069,7 @@
 pConstructor syn 
     = do cn_in <- pfName; fc <- pfc
          let cn = expandNS syn cn_in
-         ty <- pTSig syn
+         ty <- pTSig (impOK syn)
 --          ty' <- implicit syn cn ty
          return (cn, ty, fc)
  
diff --git a/src/Idris/Primitives.hs b/src/Idris/Primitives.hs
--- a/src/Idris/Primitives.hs
+++ b/src/Idris/Primitives.hs
@@ -6,17 +6,16 @@
 import Idris.ElabTerm
 import Idris.AbsSyntax
 
+import IRTS.Lang
+
 import Core.TT
 import Core.Evaluate
 
-import Epic.Epic hiding (Term, Type, Name, fn)
-import qualified Epic.Epic as E
-
 data Prim = Prim { p_name  :: Name,
                    p_type  :: Type,
                    p_arity :: Int,
                    p_def   :: [Value] -> Maybe Value,
-                   p_epic  :: ([E.Name], E.Term),
+		   p_lexp  :: (Int, PrimFn),
                    p_total :: Totality
                  }
 
@@ -27,189 +26,148 @@
             (Bind (UN "b") (Pi (Set (UVar (-2))))
             (Bind (UN "x") (Pi (V 1)) (V 1)))
 
-type ETm = E.Term
-type EOp = E.Op
-
-fun = E.fn
-ref = E.ref
-
-eOp :: EOp -> ([E.Name], ETm)
-eOp op = ([E.name "x", E.name "y"], E.op_ op (E.fn "x") (E.fn "y")) 
-
-eOpFn :: E.Type -> E.Type -> String -> ([E.Name], ETm)
-eOpFn ty rty op = ([E.name "x", E.name "y"], 
-                    foreign_ rty op [(E.fn "x", ty), (E.fn "y", ty)])
-
-strToInt x = foreign_ tyInt "strToInt" [(x, tyString)]
-intToStr x = foreign_ tyString "intToStr" [(x, tyInt)]
-charToInt x = x
-intToChar x = x
-intToBigInt x = foreign_ tyBigInt "intToBigInt" [(x, tyInt)]
-bigIntToInt x = foreign_ tyInt "bigIntToInt" [(x, tyBigInt)]
-strToBigInt x = foreign_ tyBigInt "strToBig" [(x, tyString)]
-bigIntToStr x = foreign_ tyString "bigToStr" [(x, tyBigInt)]
-strToFloat x = foreign_ tyFloat "strToFloat" [(x, tyString)]
-floatToStr x = foreign_ tyString "floatToStr" [(x, tyFloat)]
-intToFloat x = foreign_ tyFloat "intToFloat" [(x, tyInt)]
-floatToInt x = foreign_ tyInt "floatToInt" [(x, tyFloat)]
-
-floatExp x = foreign_ tyFloat "exp" [(x, tyFloat)]
-floatLog x = foreign_ tyFloat "log" [(x, tyFloat)]
-floatSin x = foreign_ tyFloat "sin" [(x, tyFloat)]
-floatCos x = foreign_ tyFloat "cos" [(x, tyFloat)]
-floatTan x = foreign_ tyFloat "tan" [(x, tyFloat)]
-floatASin x = foreign_ tyFloat "asin" [(x, tyFloat)]
-floatACos x = foreign_ tyFloat "acos" [(x, tyFloat)]
-floatATan x = foreign_ tyFloat "atan" [(x, tyFloat)]
-floatFloor x = foreign_ tyFloat "floor" [(x, tyFloat)]
-floatCeil x = foreign_ tyFloat "ceil" [(x, tyFloat)]
-floatSqrt x = foreign_ tyFloat "sqrt" [(x, tyFloat)]
-
-strIndex x i = foreign_ tyChar "strIndex" [(x, tyString), (i, tyInt)]
-strHead x = foreign_ tyChar "strHead" [(x, tyString)]
-strTail x = foreign_ tyString "strTail" [(x, tyString)]
-strCons x xs = foreign_ tyString "strCons" [(x, tyChar), (xs, tyString)]
-strRev x = foreign_ tyString "strrev" [(x, tyString)]
-strEq x y = foreign_ tyInt "streq" [(x, tyString), (y, tyString)]
-strLt x y = foreign_ tyInt "strlt" [(x, tyString), (y, tyString)]
-
 total = Total []
 partial = Partial NotCovering 
 
 primitives =
    -- operators
   [Prim (UN "prim__addInt") (ty [IType, IType] IType) 2 (iBin (+))
-   (eOp E.plus_) total,
+    (2, LPlus) total,
    Prim (UN "prim__subInt") (ty [IType, IType] IType) 2 (iBin (-))
-    (eOp E.minus_) total,
+     (2, LMinus) total,
    Prim (UN "prim__mulInt") (ty [IType, IType] IType) 2 (iBin (*))
-    (eOp E.times_) total,
+     (2, LTimes) total,
    Prim (UN "prim__divInt") (ty [IType, IType] IType) 2 (iBin (div))
-    (eOp E.divide_) partial,
+     (2, LDiv) partial,
    Prim (UN "prim__eqInt")  (ty [IType, IType] IType) 2 (biBin (==))
-    (eOp E.eq_) total,
+     (2, LEq) total,
    Prim (UN "prim__ltInt")  (ty [IType, IType] IType) 2 (biBin (<))
-    (eOp E.lt_) total,
+     (2, LLt) total,
    Prim (UN "prim__lteInt") (ty [IType, IType] IType) 2 (biBin (<=))
-    (eOp E.lte_) total,
+     (2, LLe) total,
    Prim (UN "prim__gtInt")  (ty [IType, IType] IType) 2 (biBin (>))
-    (eOp E.gt_) total,
+     (2, LGt) total,
    Prim (UN "prim__gteInt") (ty [IType, IType] IType) 2 (biBin (>=))
-    (eOp E.gte_) total,
+     (2, LGe) total,
    Prim (UN "prim__eqChar")  (ty [ChType, ChType] IType) 2 (bcBin (==))
-    (eOp E.eq_) total,
+     (2, LEq) total,
    Prim (UN "prim__ltChar")  (ty [ChType, ChType] IType) 2 (bcBin (<))
-    (eOp E.lt_) total,
+     (2, LLt) total,
    Prim (UN "prim__lteChar") (ty [ChType, ChType] IType) 2 (bcBin (<=))
-    (eOp E.lte_) total,
+     (2, LLe) total,
    Prim (UN "prim__gtChar")  (ty [ChType, ChType] IType) 2 (bcBin (>))
-    (eOp E.gt_) total,
+     (2, LGt) total,
    Prim (UN "prim__gteChar") (ty [ChType, ChType] IType) 2 (bcBin (>=))
-    (eOp E.gte_) total,
+     (2, LGe) total,
    Prim (UN "prim__addBigInt") (ty [BIType, BIType] BIType) 2 (bBin (+))
-    (eOpFn tyBigInt tyBigInt "addBig") total,
+     
+    (2, LBPlus) total,
    Prim (UN "prim__subBigInt") (ty [BIType, BIType] BIType) 2 (bBin (-))
-    (eOpFn tyBigInt tyBigInt "subBig") total,
+     (2, LBMinus) total,
    Prim (UN "prim__mulBigInt") (ty [BIType, BIType] BIType) 2 (bBin (*))
-    (eOpFn tyBigInt tyBigInt "mulBig") total,
+     (2, LBTimes) total,
    Prim (UN "prim__divBigInt") (ty [BIType, BIType] BIType) 2 (bBin (div))
-    (eOpFn tyBigInt tyBigInt "divBig") partial,
+     (2, LBDiv) partial,
    Prim (UN "prim__eqBigInt")  (ty [BIType, BIType] IType) 2 (bbBin (==))
-    (eOpFn tyBigInt tyInt "eqBig") total,
+     (2, LBEq) total,
    Prim (UN "prim__ltBigInt")  (ty [BIType, BIType] IType) 2 (bbBin (<))
-    (eOpFn tyBigInt tyInt "ltBig") total,
+     (2, LBLt) total,
    Prim (UN "prim__lteBigInt")  (ty [BIType, BIType] IType) 2 (bbBin (<=))
-    (eOpFn tyBigInt tyInt "leBig") total,
+     (2, LBLe) total,
    Prim (UN "prim__gtBigInt")  (ty [BIType, BIType] IType) 2 (bbBin (>))
-    (eOpFn tyBigInt tyInt "gtBig") total,
+     (2, LBGt) total,
    Prim (UN "prim__gtBigInt")  (ty [BIType, BIType] IType) 2 (bbBin (>=))
-    (eOpFn tyBigInt tyInt "geBig") total,
+     (2, LBGe) total,
    Prim (UN "prim__addFloat") (ty [FlType, FlType] FlType) 2 (fBin (+))
-    (eOp E.plusF_) total,
+     (2, LFPlus) total,
    Prim (UN "prim__subFloat") (ty [FlType, FlType] FlType) 2 (fBin (-))
-    (eOp E.minusF_) total,
+     (2, LFMinus) total,
    Prim (UN "prim__mulFloat") (ty [FlType, FlType] FlType) 2 (fBin (*))
-    (eOp E.timesF_) total,
+     (2, LFTimes) total,
    Prim (UN "prim__divFloat") (ty [FlType, FlType] FlType) 2 (fBin (/))
-    (eOp E.divideF_) total,
+     (2, LFDiv) total,
    Prim (UN "prim__eqFloat")  (ty [FlType, FlType] IType) 2 (bfBin (==))
-    (eOp E.eqF_) total,
+     (2, LFEq) total,
    Prim (UN "prim__ltFloat")  (ty [FlType, FlType] IType) 2 (bfBin (<))
-    (eOp E.ltF_) total,
+     (2, LFLt) total,
    Prim (UN "prim__lteFloat") (ty [FlType, FlType] IType) 2 (bfBin (<=))
-    (eOp E.lteF_) total,
+     (2, LFLe) total,
    Prim (UN "prim__gtFloat")  (ty [FlType, FlType] IType) 2 (bfBin (>))
-    (eOp E.gtF_) total,
+     (2, LFGt) total,
    Prim (UN "prim__gteFloat") (ty [FlType, FlType] IType) 2 (bfBin (>=))
-    (eOp E.gteF_) total,
+     (2, LFGe) total,
    Prim (UN "prim__concat") (ty [StrType, StrType] StrType) 2 (sBin (++))
-    ([E.name "x", E.name "y"], (fun "append") @@ fun "x" @@ fun "y") total,
+    (2, LStrConcat) total,
    Prim (UN "prim__eqString") (ty [StrType, StrType] IType) 2 (bsBin (==))
-    ([E.name "x", E.name "y"], strEq (fun "x") (fun "y")) total,
+    (2, LStrEq) total,
    Prim (UN "prim__ltString") (ty [StrType, StrType] IType) 2 (bsBin (<))
-    ([E.name "x", E.name "y"], strLt (fun "x") (fun "y")) total,
+    (2, LStrLt) total,
     -- Conversions
    Prim (UN "prim__strToInt") (ty [StrType] IType) 1 (c_strToInt)
-    ([E.name "x"], strToInt (fun "x")) total,
+     (1, LStrInt) total,
    Prim (UN "prim__intToStr") (ty [IType] StrType) 1 (c_intToStr)
-    ([E.name "x"], intToStr (fun "x")) total,
+     (1, LIntStr) total,
    Prim (UN "prim__charToInt") (ty [ChType] IType) 1 (c_charToInt)
-    ([E.name "x"], charToInt (fun "x")) total,
+     (1, LNoOp) total,
    Prim (UN "prim__intToChar") (ty [IType] ChType) 1 (c_intToChar)
-    ([E.name "x"], intToChar (fun "x")) total,
+     (1, LNoOp) total,
    Prim (UN "prim__intToBigInt") (ty [IType] BIType) 1 (c_intToBigInt)
-    ([E.name "x"], intToBigInt (fun "x")) total,
+     (1, LIntBig) total,
    Prim (UN "prim__bigIntToInt") (ty [BIType] IType) 1 (c_bigIntToInt)
-    ([E.name "x"], bigIntToInt (fun "x")) total,
+     (1, LBigInt) total,
    Prim (UN "prim__strToBigInt") (ty [StrType] BIType) 1 (c_strToBigInt)
-    ([E.name "x"], strToBigInt (fun "x")) total,
+     (1, LStrBig) total,
    Prim (UN "prim__bigIntToStr") (ty [BIType] StrType) 1 (c_bigIntToStr)
-    ([E.name "x"], bigIntToStr (fun "x")) total,
+     (1, LBigStr) total,
    Prim (UN "prim__strToFloat") (ty [StrType] FlType) 1 (c_strToFloat)
-    ([E.name "x"], strToFloat (fun "x")) total,
+     (1, LStrFloat) total,
    Prim (UN "prim__floatToStr") (ty [FlType] StrType) 1 (c_floatToStr)
-    ([E.name "x"], floatToStr (fun "x")) total,
+     (1, LFloatStr) total,
    Prim (UN "prim__intToFloat") (ty [IType] FlType) 1 (c_intToFloat)
-    ([E.name "x"], intToFloat (fun "x")) total,
+     (1, LIntFloat) total,
    Prim (UN "prim__floatToInt") (ty [FlType] IType) 1 (c_floatToInt)
-    ([E.name "x"], floatToInt (fun "x")) total,
+     (1, LFloatInt) total,
 
    Prim (UN "prim__floatExp") (ty [FlType] FlType) 1 (p_floatExp)
-    ([E.name "x"], floatExp (fun "x")) total, 
+     (1, LFExp) total, 
    Prim (UN "prim__floatLog") (ty [FlType] FlType) 1 (p_floatLog)
-    ([E.name "x"], floatLog (fun "x")) total,
+     (1, LFLog) total,
    Prim (UN "prim__floatSin") (ty [FlType] FlType) 1 (p_floatSin)
-    ([E.name "x"], floatSin (fun "x")) total,
+     (1, LFSin) total,
    Prim (UN "prim__floatCos") (ty [FlType] FlType) 1 (p_floatCos)
-    ([E.name "x"], floatCos (fun "x")) total,
+     (1, LFCos) total,
    Prim (UN "prim__floatTan") (ty [FlType] FlType) 1 (p_floatTan)
-    ([E.name "x"], floatTan (fun "x")) total,
+     (1, LFTan) total,
    Prim (UN "prim__floatASin") (ty [FlType] FlType) 1 (p_floatASin)
-    ([E.name "x"], floatASin (fun "x")) total,
+     (1, LFASin) total,
    Prim (UN "prim__floatACos") (ty [FlType] FlType) 1 (p_floatACos)
-    ([E.name "x"], floatACos (fun "x")) total,
+     (1, LFACos) total,
    Prim (UN "prim__floatATan") (ty [FlType] FlType) 1 (p_floatATan)
-    ([E.name "x"], floatATan (fun "x")) total,
+     (1, LFATan) total,
    Prim (UN "prim__floatSqrt") (ty [FlType] FlType) 1 (p_floatSqrt)
-    ([E.name "x"], floatSqrt (fun "x")) total,
+     (1, LFSqrt) total,
    Prim (UN "prim__floatFloor") (ty [FlType] FlType) 1 (p_floatFloor)
-    ([E.name "x"], floatFloor (fun "x")) total,
+     (1, LFFloor) total,
    Prim (UN "prim__floatCeil") (ty [FlType] FlType) 1 (p_floatCeil)
-    ([E.name "x"], floatCeil (fun "x")) total,
+     (1, LFCeil) total,
 
    Prim (UN "prim__strHead") (ty [StrType] ChType) 1 (p_strHead)
-    ([E.name "x"], strHead (fun "x")) partial,
+     (1, LStrHead) partial,
    Prim (UN "prim__strTail") (ty [StrType] StrType) 1 (p_strTail)
-    ([E.name "x"], strTail (fun "x")) partial,
+     (1, LStrTail) partial,
    Prim (UN "prim__strCons") (ty [ChType, StrType] StrType) 2 (p_strCons)
-    ([E.name "x", E.name "xs"], strCons (fun "x") (fun "xs")) total,
+    (2, LStrCons) total,
    Prim (UN "prim__strIndex") (ty [StrType, IType] ChType) 2 (p_strIndex)
-    ([E.name "x", E.name "i"], strIndex (fun "x") (fun "i")) partial,
+    (2, LStrIndex) partial,
    Prim (UN "prim__strRev") (ty [StrType] StrType) 1 (p_strRev)
-    ([E.name "x"], strRev (fun "x")) total,
-
+    (1, LStrRev) total,
+   Prim (UN "prim__readString") (ty [PtrType] StrType) 1 (p_cantreduce)
+     (1, LReadStr) partial,
+   -- Streams
+   Prim (UN "prim__stdin") (ty [] PtrType) 0 (p_cantreduce)
+    (0, LStdIn) partial,
    Prim (UN "prim__believe_me") believeTy 3 (p_believeMe)
-    ([E.name "a", E.name "b", E.name "x"], fun "x") total -- ahem
+    (1, LNoOp) total -- ahem
   ]
 
 p_believeMe [_,_,x] = Just x
@@ -310,12 +268,14 @@
 p_strRev [VConstant (Str xs)] = Just $ VConstant (Str (reverse xs))
 p_strRev _ = Nothing
 
+p_cantreduce _ = Nothing
+
 elabPrim :: Prim -> Idris ()
-elabPrim (Prim n ty i def epic tot) 
+elabPrim (Prim n ty i def sc tot) 
     = do updateContext (addOperator n ty i def)
          setTotality n tot
          i <- getIState
-         putIState i { idris_prims = (n, epic) : idris_prims i }
+         putIState i { idris_scprims = (n, sc) : idris_scprims i }
 
 elabPrims :: Idris ()
 elabPrims = do mapM_ (elabDecl toplevel) 
diff --git a/src/Idris/Prover.hs b/src/Idris/Prover.hs
--- a/src/Idris/Prover.hs
+++ b/src/Idris/Prover.hs
@@ -44,13 +44,14 @@
          iLOG $ "Adding " ++ show tm
          iputStrLn $ showProof lit n prf
          i <- get
-         put (i { last_proof = Just (n, prf) })
-         let tree = simpleCase False True [(P Ref n ty, tm)]
+         let proofs = proof_list i
+         put (i { proof_list = (n, prf) : proofs })
+         let tree = simpleCase False True (FC "proof" 0) [([], P Ref n ty, tm)]
          logLvl 3 (show tree)
          (ptm, pty) <- recheckC (FC "proof" 0) [] tm
          ptm' <- applyOpts ptm
-         updateContext (addCasedef n True False True [(P Ref n ty, ptm)] 
-                                                [(P Ref n ty, ptm')] ty)
+         updateContext (addCasedef n True False True [([], P Ref n ty, ptm)] 
+                                                [([], P Ref n ty, ptm')] ty)
          solveDeferred n
 elabStep :: ElabState [PDecl] -> ElabD a -> Idris (a, ElabState [PDecl])
 elabStep st e = do case runStateT e st of
diff --git a/src/Idris/REPL.hs b/src/Idris/REPL.hs
--- a/src/Idris/REPL.hs
+++ b/src/Idris/REPL.hs
@@ -20,6 +20,13 @@
 import Core.TT
 import Core.Constraints
 
+import IRTS.Compiler
+
+-- import RTS.SC
+-- import RTS.Bytecode
+-- import RTS.PreC
+-- import RTS.CodegenC
+
 import System.Console.Haskeline as H
 import System.FilePath
 import System.Environment
@@ -77,6 +84,10 @@
                 Right AddProof -> do idrisCatch (addProof fn orig)
                                                 (\e -> iputStrLn (show e))
                                      return (Just inputs)
+                Right RmProof -> do rmProof orig
+                                    return (Just inputs)
+                Right Proofs -> do proofs orig
+                                   return (Just inputs)
                 Right Quit -> do iputStrLn "Bye bye"
                                  return Nothing
                 Right cmd  -> do idrisCatch (process fn cmd)
@@ -110,14 +121,32 @@
          liftIO $ copyFile f fb -- make a backup in case something goes wrong!
          prog <- liftIO $ readFile fb
          i <- get
-         case last_proof i of
-            Nothing -> iputStrLn "No proof to add"
-            Just (n, p) -> do let prog' = insertScript (showProof (lit f) n p) (lines prog)
-                              liftIO $ writeFile f (unlines prog')
-                              iputStrLn $ "Added proof " ++ show n
-                              put (i { last_proof = Nothing })
-                              -- lift $ removeFile fb -- uncomment when less scared :)
+         case proof_list i of
+            [] -> iputStrLn "No proof to add"
+            (n, p) : proofs -> do let prog' = insertScript (showProof (lit f) n p) (lines prog)
+                                  liftIO $ writeFile f (unlines prog')
+                                  iputStrLn $ "Added proof " ++ show n
+                                  put (i { proof_list = proofs })
+                                  -- lift $ removeFile fb -- uncomment when less scared :)
 
+rmProof :: IState -> Idris ()
+rmProof orig
+  = do i <- get
+       case proof_list i of
+            [] -> iputStrLn "Nothing to remove"
+            (n, p) : ps -> do iputStrLn $ "Removed proof " ++ show n
+                              let metavars = idris_metavars i
+                              put (i { proof_list     = ps
+                                     , idris_metavars = n : metavars
+                                     })
+
+proofs :: IState -> Idris ()
+proofs orig
+  = do i <- get
+       case proof_list i of
+            [] -> iputStrLn "No proofs"
+            ps -> mapM_ (\(n, p) -> iputStrLn $ showProof False n p) ps
+
 insertScript :: String -> [String] -> [String]
 insertScript prf [] = "\n---------- Proofs ----------" : "" : [prf]
 insertScript prf (p@"---------- Proofs ----------" : "" : xs) 
@@ -142,7 +171,7 @@
 --                                                           [pexp t])
                          (tmpn, tmph) <- liftIO tempfile
                          liftIO $ hClose tmph
-                         compile tmpn tm
+                         compileC tmpn tm
                          liftIO $ system tmpn
                          return ()
     where fc = FC "(input)" 0 
@@ -180,29 +209,45 @@
                          case lookupTotal n (tt_ctxt i) of
                             [t] -> iputStrLn (showTotal t i)
                             _ -> return ()
-    where printCase i (lhs, rhs) = do liftIO $ putStr $ showImp True (delab i lhs)
-                                      liftIO $ putStr " = "
-                                      liftIO $ putStrLn $ showImp True (delab i rhs)
+    where printCase i (_, lhs, rhs) = do liftIO $ putStr $ showImp True (delab i lhs)
+                                         liftIO $ putStr " = "
+                                         liftIO $ putStrLn $ showImp True (delab i rhs)
 process fn (TotCheck n) = do i <- get
                              case lookupTotal n (tt_ctxt i) of
                                 [t] -> iputStrLn (showTotal t i)
                                 _ -> return ()
-process fn (Info n) = do i <- get
+process fn (DebugInfo n) 
+                    = do i <- get
                          let oi = lookupCtxtName Nothing n (idris_optimisation i)
                          when (not (null oi)) $ iputStrLn (show oi)
                          let si = lookupCtxt Nothing n (idris_statics i)
                          when (not (null si)) $ iputStrLn (show si)
+                         let d = lookupDef Nothing n (tt_ctxt i)
+                         when (not (null d)) $ liftIO $
+                            do print (head d)
+process fn (Info n) = do i <- get
+                         case lookupCtxt Nothing n (idris_classes i) of
+                              [c] -> classInfo c
+                              _ -> iputStrLn "Not a class"
+process fn (Search t) = iputStrLn "Not implemented"
 process fn (Spec t) = do (tm, ty) <- elabVal toplevel False t
                          ctxt <- getContext
                          ist <- get
                          let tm' = specialise ctxt [] [] {- (idris_statics ist) -} tm
                          iputStrLn (show (delab ist tm'))
-process fn (Prove n) = do prover (lit fn) n
-                          -- recheck totality
-                          i <- get
-                          totcheck (FC "(input)" 0, n)
-                          mapM_ (\ (f,n) -> setTotality n Unchecked) (idris_totcheck i)
-                          mapM_ checkDeclTotality (idris_totcheck i)
+process fn (Prove n') 
+     = do ctxt <- getContext
+          ist <- get
+          n <- case lookupNames Nothing n' ctxt of
+                    [x] -> return x
+                    [] -> return n'
+                    ns -> fail $ pshow ist (CantResolveAlts (map show ns)) 
+          prover (lit fn) n
+          -- recheck totality
+          i <- get
+          totcheck (FC "(input)" 0, n)
+          mapM_ (\ (f,n) -> setTotality n Unchecked) (idris_totcheck i)
+          mapM_ checkDeclTotality (idris_totcheck i)
 process fn (HNF t)  = do (tm, ty) <- elabVal toplevel False t
                          ctxt <- getContext
                          ist <- get
@@ -219,16 +264,22 @@
 --                                      (PRef (FC "main" 0) (NS (UN "main") ["main"]))
                         (tmpn, tmph) <- liftIO tempfile
                         liftIO $ hClose tmph
-                        compile tmpn m
+                        compileC tmpn m
                         liftIO $ system tmpn
                         return ()
   where fc = FC "main" 0                     
-process fn (Compile f) = do (m, _) <- elabVal toplevel False
-                                        (PApp fc 
-                                           (PRef fc (UN "run__IO"))
-                                           [pexp $ PRef fc (NS (UN "main") ["main"])])
-                            compile f m
+process fn (NewCompile f) 
+     = do (m, _) <- elabVal toplevel False
+                      (PApp fc (PRef fc (UN "run__IO"))
+                          [pexp $ PRef fc (NS (UN "main") ["main"])])
+          compile f m
   where fc = FC "main" 0                     
+process fn (Compile f) 
+      = do (m, _) <- elabVal toplevel False
+                       (PApp fc (PRef fc (UN "run__IO"))
+                       [pexp $ PRef fc (NS (UN "main") ["main"])])
+           compileC f m
+  where fc = FC "main" 0                     
 process fn (LogLvl i) = setLogLevel i 
 process fn Metavars 
                  = do ist <- get
@@ -238,6 +289,32 @@
                         _ -> iputStrLn $ "Global metavariables:\n\t" ++ show mvs
 process fn NOP      = return ()
 
+process fn (SetOpt   ErrContext) = setErrContext True
+process fn (UnsetOpt ErrContext) = setErrContext False
+process fn (SetOpt ShowImpl)     = setImpShow True
+process fn (UnsetOpt ShowImpl)   = setImpShow False
+
+process fn (SetOpt _) = iputStrLn "Not a valid option"
+process fn (UnsetOpt _) = iputStrLn "Not a valid option"
+
+
+classInfo :: ClassInfo -> Idris ()
+classInfo ci = do iputStrLn "Methods:\n"
+                  mapM_ dumpMethod (class_methods ci)
+                  iputStrLn ""
+                  iputStrLn "Instances:\n"
+                  mapM_ dumpInstance (class_instances ci)
+
+dumpMethod :: (Name, (FnOpts, PTerm)) -> Idris ()
+dumpMethod (n, (_, t)) = iputStrLn $ show n ++ " : " ++ show t
+
+dumpInstance :: Name -> Idris ()
+dumpInstance n = do i <- get
+                    ctxt <- getContext
+                    imp <- impShow
+                    case lookupTy Nothing n ctxt of
+                         ts -> mapM_ (\t -> iputStrLn $ showImp imp (delab i t)) ts
+
 showTotal t@(Partial (Other ns)) i
    = show t ++ "\n\t" ++ showSep "\n\t" (map (showTotalN i) ns)
 showTotal t i = show t
@@ -245,6 +322,18 @@
                         [t] -> showTotal t i
                         _ -> ""
 
+tempfile :: IO (FilePath, Handle)
+tempfile = do env <- environment "TMPDIR"
+              let dir = case env of
+                              Nothing -> "/tmp"
+                              (Just d) -> d
+              openTempFile dir "esc"
+
+environment :: String -> IO (Maybe String)
+environment x = Prelude.catch (do e <- getEnv x
+                                  return (Just e))
+                              (\_ -> return Nothing)
+
 displayHelp = let vstr = showVersion version in
               "\nIdris version " ++ vstr ++ "\n" ++
               "--------------" ++ map (\x -> '-') vstr ++ "\n\n" ++
@@ -259,15 +348,20 @@
     ([""], "", ""),
     (["<expr>"], "", "Evaluate an expression"),
     ([":t"], "<expr>", "Check the type of an expression"),
+    ([":i", ":info"], "<name>", "Display information about a type class"),
     ([":total"], "<name>", "Check the totality of a name"),
     ([":r",":reload"], "", "Reload current file"),
     ([":e",":edit"], "", "Edit current file using $EDITOR or $VISUAL"),
     ([":m",":metavars"], "", "Show remaining proof obligations (metavariables)"),
     ([":p",":prove"], "<name>", "Prove a metavariable"),
     ([":a",":addproof"], "", "Add last proof to source file"),
+    ([":rmproof"], "", "Remove last proof from proof stack"),
+    ([":proofs"], "", "Show proof stack"),
     ([":c",":compile"], "<filename>", "Compile to an executable <filename>"),
     ([":exec",":execute"], "", "Compile to an executable and run"),
     ([":?",":h",":help"], "", "Display this help text"),
+    ([":set"], "<option>", "Set an option (errorcontext, showimplicits)"),
+    ([":unset"], "<option>", "Unset an option"),
     ([":q",":quit"], "", "Exit the Idris system")
   ]
 
diff --git a/src/Idris/REPLParser.hs b/src/Idris/REPLParser.hs
--- a/src/Idris/REPLParser.hs
+++ b/src/Idris/REPLParser.hs
@@ -27,9 +27,12 @@
    <|> try (do cmd ["exec", "execute"]; eof; return Execute)
    <|> try (do cmd ["ttshell"]; eof; return TTShell)
    <|> try (do cmd ["c", "compile"]; f <- identifier; eof; return (Compile f))
+   <|> try (do cmd ["nc", "newcompile"]; f <- identifier; eof; return (NewCompile f))
    <|> try (do cmd ["m", "metavars"]; eof; return Metavars)
-   <|> try (do cmd ["p", "prove"]; n <- pName; eof; return (Prove n)) 
+   <|> try (do cmd ["proofs"]; eof; return Proofs)
+   <|> try (do cmd ["p", "prove"]; n <- pName; eof; return (Prove n))
    <|> try (do cmd ["a", "addproof"]; eof; return AddProof)
+   <|> try (do cmd ["rmproof"]; eof; return RmProof)
    <|> try (do cmd ["log"]; i <- natural; eof; return (LogLvl (fromIntegral i)))
    <|> try (do cmd ["spec"]; t <- pFullExpr defaultSyntax; return (Spec t))
    <|> try (do cmd ["hnf"]; t <- pFullExpr defaultSyntax; return (HNF t))
@@ -37,8 +40,16 @@
    <|> try (do cmd ["total"]; do n <- pName; eof; return (TotCheck n))
    <|> try (do cmd ["t", "type"]; do t <- pFullExpr defaultSyntax; return (Check t))
    <|> try (do cmd ["u", "universes"]; eof; return Universes)
+   <|> try (do cmd ["di", "dbginfo"]; n <- pfName; eof; return (DebugInfo n))
    <|> try (do cmd ["i", "info"]; n <- pfName; eof; return (Info n))
+   <|> try (do cmd ["set"]; o <-pOption; return (SetOpt o))
+   <|> try (do cmd ["unset"]; o <-pOption; return (UnsetOpt o))
+   <|> try (do cmd ["s", "search"]; t <- pFullExpr defaultSyntax; return (Search t))
    <|> try (do cmd ["x"]; t <- pFullExpr defaultSyntax; return (ExecVal t))
    <|> do t <- pFullExpr defaultSyntax; return (Eval t)
    <|> do eof; return NOP
+
+pOption :: IParser Opt
+pOption = do discard (symbol "errorcontext"); return ErrContext
+      <|> do discard (symbol "showimplicits"); return ShowImpl
 
diff --git a/src/Idris/Transforms.hs b/src/Idris/Transforms.hs
--- a/src/Idris/Transforms.hs
+++ b/src/Idris/Transforms.hs
@@ -6,39 +6,52 @@
 import Core.CaseTree
 import Core.TT
 
+data TTOpt = TermTrans (TT Name -> TT Name) -- term transform
+           | CaseTrans (SC -> SC) -- case expression transform
+
 class Transform a where
-    transform :: (a -> a) -> a -> a
+     transform :: TTOpt -> a -> a
 
 instance Transform (TT Name) where
-    transform t x = t (trans' x) where
-        trans' (Bind n b sc) = Bind n (fmap (transform t) b) (transform t sc)
-        trans' (App f a) = App (transform t f) (transform t a)
-        trans' x = x
-
-type TTOpt = TT Name -> TT Name
+    transform o@(TermTrans t) tm = trans t tm where
+      trans t (Bind n b tm) = t $ Bind n (transform o b) (trans t tm)
+      trans t (App f a)     = t $ App (trans t f) (trans t a)
+      trans t tm            = t tm
+    transform _ tm = tm
 
-optimisations :: [TTOpt]
-optimisations = [zero, suc]
+instance Transform a => Transform (Binder a) where
+    transform t (Let ty v) = Let (transform t ty) (transform t v)
+    transform t b = b { binderTy = transform t (binderTy b) }
 
 instance Transform SC where
-    transform t x = t (trans' x) where
-        trans' (Case n alts) = Case n (map transAlt alts)
-        trans' t = t
+    transform o@(CaseTrans t) sc = trans t sc where
+      trans t (Case n alts) = t (Case n (map (transform o) alts))
+      trans t x = t x
+    transform o@(TermTrans t) sc = trans t sc where
+      trans t (Case n alts) = Case n (map (transform o) alts)
+      trans t (STerm tm) = STerm (t tm)
+      trans t x = x
 
-        transAlt (ConCase n i as sc) = ConCase n i as (trans' sc)
-        transAlt (ConstCase c sc) = ConstCase c (trans' sc)
-        transAlt (DefaultCase sc) = DefaultCase (trans' sc)
+instance Transform CaseAlt where
+   transform o (ConCase n i ns sc) = ConCase n i ns (transform o sc)
+   transform o (ConstCase c sc)    = ConstCase c (transform o sc)
+   transform o (DefaultCase sc)    = DefaultCase (transform o sc)
 
-type CaseOpt = SC -> SC
+natTrans = [TermTrans zero, TermTrans suc, CaseTrans natcase]
 
-zero :: TTOpt
-zero (P _ n _) | n == NS (UN "O") ["nat","prelude"] 
+zname = NS (UN "O") ["nat","prelude"] 
+sname = NS (UN "S") ["nat","prelude"] 
+
+zero :: TT Name -> TT Name
+zero (P _ n _) | n == zname
     = Constant (BI 0)
 zero x = x
 
-suc :: TTOpt
-suc (App (P _ s _) a) | s == NS (UN "S") ["nat","prelude"] 
+suc :: TT Name -> TT Name
+suc (App (P _ s _) a) | s == sname
     = mkApp (P Ref (UN "prim__addBigInt") Erased) [Constant (BI 1), a]
 suc x = x
 
+natcase :: SC -> SC
+natcase = undefined 
 
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -24,24 +24,15 @@
 import Idris.Primitives
 import Idris.Imports
 import Idris.Error
+
+import IRTS.Lang
+import IRTS.LParser
+
 import Paths_idris
 
 -- Main program reads command line options, parses the main program, and gets
 -- on with the REPL.
 
-data Opt = Filename String
-         | Ver
-         | Usage
-         | NoPrelude
-         | NoREPL
-         | OLogging Int
-         | Output String
-         | TypeCase
-         | TypeInType
-         | NoCoverage 
-         | Verbose
-    deriving Eq
-
 main = do xs <- getArgs
           opts <- parseArgs xs
           runInputT defaultSettings $ execStateT (runIdris opts) idrisInit
@@ -51,12 +42,32 @@
     do let inputs = opt getFile opts
        let runrepl = not (NoREPL `elem` opts)
        let output = opt getOutput opts
+       let newoutput = opt getNewOutput opts
+       let ibcsubdir = opt getIBCSubDir opts
+       let importdirs = opt getImportDir opts
+       let bcs = opt getBC opts
+       let vm = opt getFOVM opts
+
        when (Ver `elem` opts) $ liftIO showver
        when (Usage `elem` opts) $ liftIO usage
+       when (ShowIncs `elem` opts) $ liftIO showIncs
+       when (ShowLibs `elem` opts) $ liftIO showLibs
        setREPL runrepl
        setVerbose runrepl
        when (Verbose `elem` opts) $ setVerbose True
        mapM_ makeOption opts
+       -- if we have the --fovm flag, drop into the first order VM testing
+       case vm of
+	    [] -> return ()
+	    xs -> liftIO $ mapM_ fovm xs 
+       -- if we have the --bytecode flag, drop into the bytecode assembler
+       case bcs of
+	    [] -> return ()
+	    xs -> return () -- liftIO $ mapM_ bcAsm xs 
+       case ibcsubdir of
+         [] -> setIBCSubDir ""
+         (d:_) -> setIBCSubDir d
+       setImportDirs importdirs
        elabPrims
        when (not (NoPrelude `elem` opts)) $ do x <- loadModule "prelude"
                                                return ()
@@ -67,6 +78,9 @@
        when ok $ case output of
                     [] -> return ()
                     (o:_) -> process "" (Compile o)  
+       when ok $ case newoutput of
+                    [] -> return ()
+                    (o:_) -> process "" (NewCompile o)  
        when runrepl $ repl ist inputs
        ok <- noErrors
        when (not ok) $ liftIO (exitWith (ExitFailure 1))
@@ -75,16 +89,37 @@
     makeOption TypeCase = setTypeCase True
     makeOption TypeInType = setTypeInType True
     makeOption NoCoverage = setCoverage False
+    makeOption ErrContext = setErrContext True
     makeOption _ = return ()
 
 getFile :: Opt -> Maybe String
 getFile (Filename str) = Just str
 getFile _ = Nothing
 
+getBC :: Opt -> Maybe String
+getBC (BCAsm str) = Just str
+getBC _ = Nothing
+
+getFOVM :: Opt -> Maybe String
+getFOVM (FOVM str) = Just str
+getFOVM _ = Nothing
+
 getOutput :: Opt -> Maybe String
 getOutput (Output str) = Just str
 getOutput _ = Nothing
 
+getNewOutput :: Opt -> Maybe String
+getNewOutput (NewOutput str) = Just str
+getNewOutput _ = Nothing
+
+getIBCSubDir :: Opt -> Maybe String
+getIBCSubDir (IBCSubDir str) = Just str
+getIBCSubDir _ = Nothing
+
+getImportDir :: Opt -> Maybe String
+getImportDir (ImportDir str) = Just str
+getImportDir _ = Nothing
+
 opt :: (Opt -> Maybe a) -> [Opt] -> [a]
 opt = mapMaybe 
 
@@ -94,19 +129,35 @@
 showver = do putStrLn $ "Idris version " ++ ver
              exitWith ExitSuccess
 
+showLibs = do dir <- getDataDir
+              putStrLn $ "-L" ++ dir ++ "/rts -lidris_rts"
+              exitWith ExitSuccess
+
+showIncs = do dir <- getDataDir
+              putStrLn $ "-I" ++ dir ++ "/rts"
+              exitWith ExitSuccess
+
 parseArgs :: [String] -> IO [Opt]
 parseArgs [] = return []
-parseArgs ("--log":lvl:ns)   = liftM (OLogging (read lvl) : ) (parseArgs ns)
-parseArgs ("--noprelude":ns) = liftM (NoPrelude : ) (parseArgs ns)
-parseArgs ("--check":ns)     = liftM (NoREPL : ) (parseArgs ns)
-parseArgs ("-o":n:ns)        = liftM (\x -> NoREPL : Output n : x) (parseArgs ns)
-parseArgs ("--typecase":ns)  = liftM (TypeCase : ) (parseArgs ns)
-parseArgs ("--typeintype":ns) = liftM (TypeInType : ) (parseArgs ns)
-parseArgs ("--nocoverage":ns) = liftM (NoCoverage : ) (parseArgs ns)
-parseArgs ("--help":ns)      = liftM (Usage : ) (parseArgs ns)
-parseArgs ("--version":ns)   = liftM (Ver : ) (parseArgs ns)
-parseArgs ("--verbose":ns)   = liftM (Verbose : ) (parseArgs ns)
-parseArgs (n:ns)             = liftM (Filename n : ) (parseArgs ns)
+parseArgs ("--log":lvl:ns)      = liftM (OLogging (read lvl) : ) (parseArgs ns)
+parseArgs ("--noprelude":ns)    = liftM (NoPrelude : ) (parseArgs ns)
+parseArgs ("--check":ns)        = liftM (NoREPL : ) (parseArgs ns)
+parseArgs ("-o":n:ns)           = liftM (\x -> NoREPL : Output n : x) (parseArgs ns)
+parseArgs ("-no":n:ns)          = liftM (\x -> NoREPL : NewOutput n : x) (parseArgs ns)
+parseArgs ("--typecase":ns)     = liftM (TypeCase : ) (parseArgs ns)
+parseArgs ("--typeintype":ns)   = liftM (TypeInType : ) (parseArgs ns)
+parseArgs ("--nocoverage":ns)   = liftM (NoCoverage : ) (parseArgs ns)
+parseArgs ("--errorcontext":ns) = liftM (ErrContext : ) (parseArgs ns)
+parseArgs ("--help":ns)         = liftM (Usage : ) (parseArgs ns)
+parseArgs ("--link":ns)         = liftM (ShowLibs : ) (parseArgs ns)
+parseArgs ("--include":ns)      = liftM (ShowIncs : ) (parseArgs ns)
+parseArgs ("--version":ns)      = liftM (Ver : ) (parseArgs ns)
+parseArgs ("--verbose":ns)      = liftM (Verbose : ) (parseArgs ns)
+parseArgs ("--ibcsubdir":n:ns)  = liftM (IBCSubDir n : ) (parseArgs ns)
+parseArgs ("-i":n:ns)           = liftM (ImportDir n : ) (parseArgs ns)
+parseArgs ("--bytecode":n:ns)   = liftM (\x -> NoREPL : BCAsm n : x) (parseArgs ns)
+parseArgs ("--fovm":n:ns)       = liftM (\x -> NoREPL : FOVM n : x) (parseArgs ns)
+parseArgs (n:ns)                = liftM (Filename n : ) (parseArgs ns)
 
 ver = showVersion version
 
@@ -120,9 +171,13 @@
            "--------------" ++ map (\x -> '-') ver ++ "\n" ++
            "Usage: idris [input file] [options]\n" ++
            "Options:\n" ++
-           "\t--check       Type check only\n" ++
-           "\t-o [file]     Generate executable\n" ++
-           "\t--noprelude   Don't import the prelude\n" ++
-           "\t--typeintype  Disable universe checking\n" ++
-           "\t--log [level] Set debugging log level\n"
+           "\t--check           Type check only\n" ++
+           "\t-o [file]         Generate executable\n" ++
+           "\t-i [dir]          Add directory to the list of import paths\n" ++
+           "\t--ibcsubdir [dir] Write IBC files into sub directory\n" ++
+           "\t--noprelude       Don't import the prelude\n" ++
+           "\t--typeintype      Disable universe checking\n" ++
+           "\t--log [level]     Set debugging log level\n" ++
+	   "\t--link            Show library directories and exit (for C linking)\n" ++
+	   "\t--include         Show include directories and exit (for C linking)\n"
 
